source code formatting.
[utils] / support / general / src / main / java / org / wamblee / observer / Observable.java
1 /*
2  * Copyright 2005 the original author or authors.
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 package org.wamblee.observer;
17
18 import org.apache.log4j.Logger;
19
20 import java.util.ArrayList;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.TreeMap;
24
25
26 /**
27  * Implements subscription and notification logic for an observer pattern. This
28  * class is thread safe.
29  */
30 public class Observable<ObservableType, Event> {
31     private static final Logger LOGGER = Logger.getLogger(Observable.class);
32
33     /**
34      * Observable.
35      */
36     private ObservableType observable;
37
38     /**
39      * Used to notify observers.
40      */
41     private ObserverNotifier<ObservableType, Event> notifier;
42
43     /**
44      * Map of subscription to observer.
45      */
46     private Map<Long, Observer<ObservableType, Event>> observers;
47
48     /**
49      * Counter for subscriptions. Holds the next subscription.
50      */
51     private long counter;
52
53     /**
54      * Constructs the observable.
55      *
56      * @param aObservable
57      *            Observable this instance is used for.
58      * @param aNotifier
59      *            Object used for implementing notification of listeners.
60      */
61     public Observable(ObservableType aObservable,
62         ObserverNotifier<ObservableType, Event> aNotifier) {
63         observable = aObservable;
64         notifier = aNotifier;
65         observers = new TreeMap<Long, Observer<ObservableType, Event>>();
66         counter = 0;
67     }
68
69     /**
70      * Subscribe an obvers.
71      *
72      * @param aObserver
73      *            Observer to subscribe.
74      * @return Event Event to send.
75      */
76     public synchronized long subscribe(
77         Observer<ObservableType, Event> aObserver) {
78         long subscription = counter++; // integer rage is so large it will
79                                        // never roll over.
80
81         observers.put(subscription, aObserver);
82
83         return subscription;
84     }
85
86     /**
87      * Unsubscribe an observer.
88      *
89      * @param aSubscription
90      *            Subscription which is used
91      * @throws IllegalArgumentException
92      *             In case the subscription is not known.
93      */
94     public synchronized void unsubscribe(long aSubscription) {
95         Object obj = observers.remove(aSubscription);
96
97         if (obj == null) {
98             throw new IllegalArgumentException("Subscription '" +
99                 aSubscription + "'");
100         }
101     }
102
103     /**
104      * Gets the number of subscribed observers.
105      *
106      * @return Number of subscribed observers.
107      */
108     public int getObserverCount() {
109         return observers.size();
110     }
111
112     /**
113      * Notifies all subscribed observers.
114      *
115      * @param aEvent
116      *            Event to send.
117      */
118     public void send(Event aEvent) {
119         // Make sure we do the notification while not holding the lock to avoid
120         // potential deadlock
121         // situations.
122         List<Observer<ObservableType, Event>> myObservers = new ArrayList<Observer<ObservableType, Event>>();
123
124         synchronized (this) {
125             myObservers.addAll(observers.values());
126         }
127
128         for (Observer<ObservableType, Event> observer : myObservers) {
129             notifier.update(observer, observable, aEvent);
130         }
131     }
132
133     /*
134      * (non-Javadoc)
135      *
136      * @see java.lang.Object#finalize()
137      */
138     @Override
139     protected void finalize() throws Throwable {
140         if (observers.size() > 0) {
141             LOGGER.error(
142                 "Still observers registered at finalization of observer!");
143
144             for (Observer observer : observers.values()) {
145                 LOGGER.error("  observer: " + observer);
146             }
147         }
148
149         super.finalize();
150     }
151 }