1 /**
2  *  Copyright Terracotta, Inc.
3  *
4  *  Licensed under the Apache License, Version 2.0 (the "License");
5  *  you may not use this file except in compliance with the License.
6  *  You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License.
15  */

16
17 package net.sf.ehcache.event;
18
19 import java.util.Iterator;
20 import java.util.Set;
21 import java.util.concurrent.CopyOnWriteArraySet;
22
23 import net.sf.ehcache.Status;
24
25 /**
26  * Registered listeners for registering and unregistering CacheManagerEventListeners and sending notifications to registrants.
27  * <p/>
28  * There is one of these per CacheManager. It is a composite listener.
29  *
30  * @author Greg Luck
31  * @version $Id: CacheManagerEventListenerRegistry.java 5631 2012-05-10 08:31:33Z teck $
32  * @since 1.3
33  */

34 public class CacheManagerEventListenerRegistry implements CacheManagerEventListener {
35
36     private volatile Status status;
37
38     /**
39      * A Set of CacheEventListeners keyed by listener instance.
40      * CacheEventListener implementations that will be notified of this cache's events.
41      *
42      * @see CacheManagerEventListener
43      */

44     private Set listeners;
45
46     /**
47      * Construct a new registry
48      */

49     public CacheManagerEventListenerRegistry() {
50         status = Status.STATUS_UNINITIALISED;
51         listeners = new CopyOnWriteArraySet();
52     }
53
54     /**
55      * Adds a listener to the notification service. No guarantee is made that listeners will be
56      * notified in the order they were added.
57      *
58      * @param cacheManagerEventListener the listener to add. Can be null, in which case nothing happens
59      * @return true if the listener is being added and was not already added
60      */

61     public final boolean registerListener(CacheManagerEventListener cacheManagerEventListener) {
62         if (cacheManagerEventListener == null) {
63             return false;
64         }
65         return listeners.add(cacheManagerEventListener);
66     }
67
68     /**
69      * Removes a listener from the notification service.
70      *
71      * @param cacheManagerEventListener the listener to remove
72      * @return true if the listener was present
73      */

74     public final boolean unregisterListener(CacheManagerEventListener cacheManagerEventListener) {
75         return listeners.remove(cacheManagerEventListener);
76     }
77
78     /**
79      * Returns whether or not at least one cache manager event listeners has been registered.
80      *
81      * @return true if a one or more listeners have registered, otherwise false
82      */

83     public boolean hasRegisteredListeners() {
84         return listeners.size() > 0;
85     }
86
87     /**
88      * Gets a Set of the listeners registered to this class
89      *
90      * @return a set of type <code>CacheManagerEventListener</code>
91      */

92     public Set getRegisteredListeners() {
93         return listeners;
94     }
95
96     /**
97      * Initialises the listeners, ready to receive events.
98      */

99     public void init() {
100         //init once
101         Iterator iterator = listeners.iterator();
102         while (iterator.hasNext()) {
103             CacheManagerEventListener cacheManagerEventListener = (CacheManagerEventListener) iterator.next();
104             cacheManagerEventListener.init();
105         }
106         status = Status.STATUS_ALIVE;
107     }
108
109     /**
110      * Returns the listener status.
111      *
112      * @return the status at the point in time the method is called
113      */

114     public Status getStatus() {
115         return status;
116     }
117
118     /**
119      * Tell listeners to dispose themselves.
120      * Because this method is only ever called from a synchronized cache method, it does not itself need to be
121      * synchronized.
122      */

123     public void dispose() {
124         Iterator iterator = listeners.iterator();
125         while (iterator.hasNext()) {
126             CacheManagerEventListener cacheManagerEventListener = (CacheManagerEventListener) iterator.next();
127             cacheManagerEventListener.dispose();
128         }
129         listeners.clear();
130         status = Status.STATUS_SHUTDOWN;
131     }
132
133     /**
134      * Called immediately after a cache has been added and activated.
135      * <p/>
136      * Note that the CacheManager calls this method from a synchronized method. Any attempt to
137      * call a synchronized method on CacheManager from this method will cause a deadlock.
138      * <p/>
139      * Note that activation will also cause a CacheEventListener status change notification
140      * from {@link net.sf.ehcache.Status#STATUS_UNINITIALISED} to
141      * {@link net.sf.ehcache.Status#STATUS_ALIVE}. Care should be taken on processing that
142      * notification because:
143      * <ul>
144      * <li>the cache will not yet be accessible from the CacheManager.
145      * <li>the addCaches methods which cause this notification are synchronized on the
146      * CacheManager. An attempt to call {@link net.sf.ehcache.CacheManager#getEhcache(String)}
147      * will cause a deadlock.
148      * </ul>
149      * The calling method will block until this method returns.
150      * <p/>
151      *
152      * @param cacheName the name of the <code>Cache</code> the operation relates to
153      * @see CacheEventListener
154      */

155     public void notifyCacheAdded(String cacheName) {
156         Iterator iterator = listeners.iterator();
157         while (iterator.hasNext()) {
158             CacheManagerEventListener cacheManagerEventListener = (CacheManagerEventListener) iterator.next();
159             cacheManagerEventListener.notifyCacheAdded(cacheName);
160         }
161     }
162
163     /**
164      * Called immediately after a cache has been disposed and removed. The calling method will
165      * block until this method returns.
166      * <p/>
167      * Note that the CacheManager calls this method from a synchronized method. Any attempt to
168      * call a synchronized method on CacheManager from this method will cause a deadlock.
169      * <p/>
170      * Note that a {@link CacheEventListener} status changed will also be triggered. Any
171      * attempt from that notification to access CacheManager will also result in a deadlock.
172      *
173      * @param cacheName the name of the <code>Cache</code> the operation relates to
174      */

175     public void notifyCacheRemoved(String cacheName) {
176         Iterator iterator = listeners.iterator();
177         while (iterator.hasNext()) {
178             CacheManagerEventListener cacheManagerEventListener = (CacheManagerEventListener) iterator.next();
179             cacheManagerEventListener.notifyCacheRemoved(cacheName);
180         }
181     }
182
183     /**
184      * Returns a string representation of the object. In general, the
185      * <code>toString</code> method returns a string that
186      * "textually represents" this object. The result should
187      * be a concise but informative representation that is easy for a
188      * person to read.
189      *
190      * @return a string representation of the object.
191      */

192     @Override
193     public String toString() {
194         StringBuilder sb = new StringBuilder(" cacheManagerEventListeners: ");
195         for (Iterator iterator = listeners.iterator(); iterator.hasNext();) {
196             CacheManagerEventListener cacheManagerEventListener = (CacheManagerEventListener) iterator.next();
197             sb.append(cacheManagerEventListener.getClass().getName()).append(" ");
198         }
199         return sb.toString();
200     }
201 }
202