001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.scxml;
018
019 import java.io.Serializable;
020 import java.util.HashMap;
021 import java.util.Iterator;
022 import java.util.LinkedHashSet;
023 import java.util.Map;
024 import java.util.Set;
025
026 import org.apache.commons.scxml.model.SCXML;
027 import org.apache.commons.scxml.model.Transition;
028 import org.apache.commons.scxml.model.TransitionTarget;
029
030 /**
031 * The registry where SCXML listeners are recorded for nodes of
032 * interest such as the <code>SCXML</code> root,
033 * <code>TransitionTarget</code>s and <code>Transition</code>s.
034 * The notification registry keeps track of all
035 * <code>SCXMLListener</code>s attached and notifies relevant
036 * listeners of the events that interest them.
037 *
038 */
039 public final class NotificationRegistry implements Serializable {
040
041 /**
042 * Serial version UID.
043 */
044 private static final long serialVersionUID = 1L;
045
046 /**
047 * The Map of all listeners keyed by Observable.
048 */
049 private Map regs = new HashMap();
050
051 /**
052 * Constructor.
053 */
054 public NotificationRegistry() {
055 super();
056 }
057
058 /**
059 * Register this SCXMLListener for this Observable.
060 *
061 * @param source The observable this listener wants to listen to
062 * @param lst The listener
063 */
064 synchronized void addListener(final Object source,
065 final SCXMLListener lst) {
066 Set entries = (Set) regs.get(source);
067 if (entries == null) {
068 entries = new LinkedHashSet();
069 regs.put(source, entries);
070 }
071 entries.add(lst);
072 }
073
074 /**
075 * Deregister this SCXMLListener for this Observable.
076 *
077 * @param source The observable this listener wants to stop listening to
078 * @param lst The listener
079 */
080 synchronized void removeListener(final Object source,
081 final SCXMLListener lst) {
082 Set entries = (Set) regs.get(source);
083 if (entries != null) {
084 entries.remove(lst);
085 if (entries.size() == 0) {
086 regs.remove(source);
087 }
088 }
089 }
090
091 /**
092 * Inform all relevant listeners that a TransitionTarget has been
093 * entered.
094 *
095 * @param observable The Observable
096 * @param state The TransitionTarget that was entered
097 */
098 public void fireOnEntry(final TransitionTarget observable,
099 final TransitionTarget state) {
100 Object source = observable;
101 fireOnEntry(source, state);
102 }
103
104 /**
105 * Inform all relevant listeners that a TransitionTarget has been
106 * entered.
107 *
108 * @param observable The Observable
109 * @param state The TransitionTarget that was entered
110 */
111 public void fireOnEntry(final SCXML observable,
112 final TransitionTarget state) {
113 Object source = observable;
114 fireOnEntry(source, state);
115 }
116
117 /**
118 * Inform all relevant listeners that a TransitionTarget has been
119 * entered.
120 *
121 * @param source The Observable
122 * @param state The TransitionTarget that was entered
123 */
124 private synchronized void fireOnEntry(final Object source,
125 final TransitionTarget state) {
126 Set entries = (Set) regs.get(source);
127 if (entries != null) {
128 for (Iterator iter = entries.iterator(); iter.hasNext();) {
129 SCXMLListener lst = (SCXMLListener) iter.next();
130 lst.onEntry(state);
131 }
132 }
133 }
134
135 /**
136 * Inform all relevant listeners that a TransitionTarget has been
137 * exited.
138 *
139 * @param observable The Observable
140 * @param state The TransitionTarget that was exited
141 */
142 public void fireOnExit(final TransitionTarget observable,
143 final TransitionTarget state) {
144 Object source = observable;
145 fireOnExit(source, state);
146 }
147
148 /**
149 * Inform all relevant listeners that a TransitionTarget has been
150 * exited.
151 *
152 * @param observable The Observable
153 * @param state The TransitionTarget that was exited
154 */
155 public void fireOnExit(final SCXML observable,
156 final TransitionTarget state) {
157 Object source = observable;
158 fireOnExit(source, state);
159 }
160
161 /**
162 * Inform all relevant listeners that a TransitionTarget has been
163 * exited.
164 *
165 * @param source The Observable
166 * @param state The TransitionTarget that was exited
167 */
168 private synchronized void fireOnExit(final Object source,
169 final TransitionTarget state) {
170 Set entries = (Set) regs.get(source);
171 if (entries != null) {
172 for (Iterator iter = entries.iterator(); iter.hasNext();) {
173 SCXMLListener lst = (SCXMLListener) iter.next();
174 lst.onExit(state);
175 }
176 }
177 }
178
179 /**
180 * Inform all relevant listeners of a transition that has occured.
181 *
182 * @param observable The Observable
183 * @param from The source TransitionTarget
184 * @param to The destination TransitionTarget
185 * @param transition The Transition that was taken
186 */
187 public void fireOnTransition(final Transition observable,
188 final TransitionTarget from, final TransitionTarget to,
189 final Transition transition) {
190 Object source = observable;
191 fireOnTransition(source, from, to, transition);
192 }
193
194 /**
195 * Inform all relevant listeners of a transition that has occured.
196 *
197 * @param observable The Observable
198 * @param from The source TransitionTarget
199 * @param to The destination TransitionTarget
200 * @param transition The Transition that was taken
201 */
202 public void fireOnTransition(final SCXML observable,
203 final TransitionTarget from, final TransitionTarget to,
204 final Transition transition) {
205 Object source = observable;
206 fireOnTransition(source, from, to, transition);
207 }
208
209 /**
210 * Inform all relevant listeners of a transition that has occured.
211 *
212 * @param source The Observable
213 * @param from The source TransitionTarget
214 * @param to The destination TransitionTarget
215 * @param transition The Transition that was taken
216 */
217 private synchronized void fireOnTransition(final Object source,
218 final TransitionTarget from, final TransitionTarget to,
219 final Transition transition) {
220 Set entries = (Set) regs.get(source);
221 if (entries != null) {
222 for (Iterator iter = entries.iterator(); iter.hasNext();) {
223 SCXMLListener lst = (SCXMLListener) iter.next();
224 lst.onTransition(from, to, transition);
225 }
226 }
227 }
228
229 }
230