1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.scxml2;
18
19 import java.util.HashMap;
20 import java.util.LinkedHashSet;
21 import java.util.Map;
22 import java.util.Set;
23
24 import org.apache.commons.scxml2.model.EnterableState;
25 import org.apache.commons.scxml2.model.Observable;
26 import org.apache.commons.scxml2.model.Transition;
27 import org.apache.commons.scxml2.model.TransitionTarget;
28
29 /**
30 * The registry where SCXML listeners are recorded for nodes of
31 * interest such as the <code>SCXML</code> root,
32 * <code>EnterableState</code>s and <code>Transition</code>s.
33 * The notification registry keeps track of all
34 * <code>SCXMLListener</code>s attached and notifies relevant
35 * listeners of the events that interest them.
36 *
37 */
38 public final class NotificationRegistry {
39
40 /**
41 * The Map of all listeners keyed by {@link Observable#getObservableId()}.
42 */
43 private final Map<Integer, Set<SCXMLListener>> regs;
44
45 /**
46 * Constructor.
47 */
48 public NotificationRegistry() {
49 this.regs = new HashMap<Integer, Set<SCXMLListener>>();
50 }
51
52 /**
53 * Register this SCXMLListener for this Observable.
54 *
55 * @param source The observable this listener wants to listen to
56 * @param lst The listener
57 */
58 synchronized void addListener(final Observable source, final SCXMLListener lst) {
59 if (source != null && source.getObservableId() != null) {
60 Set<SCXMLListener> entries = regs.get(source.getObservableId());
61 if (entries == null) {
62 entries = new LinkedHashSet<SCXMLListener>();
63 regs.put(source.getObservableId(), entries);
64 }
65 entries.add(lst);
66 }
67 }
68
69 /**
70 * Deregister this SCXMLListener for this Observable.
71 *
72 * @param source The observable this listener wants to stop listening to
73 * @param lst The listener
74 */
75 synchronized void removeListener(final Observable source, final SCXMLListener lst) {
76 if (source != null && source.getObservableId() != null) {
77 Set<SCXMLListener> entries = regs.get(source.getObservableId());
78 if (entries != null) {
79 entries.remove(lst);
80 if (entries.size() == 0) {
81 regs.remove(source.getObservableId());
82 }
83 }
84 }
85 }
86
87 /**
88 * Inform all relevant listeners that a EnterableState has been
89 * entered.
90 *
91 * @param source The Observable
92 * @param state The EnterableState that was entered
93 */
94 public synchronized void fireOnEntry(final Observable source,
95 final EnterableState state) {
96 if (source != null && source.getObservableId() != null) {
97 Set<SCXMLListener> entries = regs.get(source.getObservableId());
98 if (entries != null) {
99 for (SCXMLListener lst : entries) {
100 lst.onEntry(state);
101 }
102 }
103 }
104 }
105
106 /**
107 * Inform all relevant listeners that a EnterableState has been
108 * exited.
109 *
110 * @param source The Observable
111 * @param state The EnterableState that was exited
112 */
113 public synchronized void fireOnExit(final Observable source,
114 final EnterableState state) {
115 if (source != null && source.getObservableId() != null) {
116 Set<SCXMLListener> entries = regs.get(source.getObservableId());
117 if (entries != null) {
118 for (SCXMLListener lst : entries) {
119 lst.onExit(state);
120 }
121 }
122 }
123 }
124
125 /**
126 * Inform all relevant listeners of a transition that has occured.
127 *
128 * @param source The Observable
129 * @param from The source EnterableState
130 * @param to The destination EnterableState
131 * @param transition The Transition that was taken
132 * @param event The event name triggering the transition
133 */
134 public synchronized void fireOnTransition(final Observable source,
135 final TransitionTarget from, final TransitionTarget to,
136 final Transition transition, final String event) {
137 if (source != null && source.getObservableId() != null) {
138 Set<SCXMLListener> entries = regs.get(source.getObservableId());
139 if (entries != null) {
140 for (SCXMLListener lst : entries) {
141 lst.onTransition(from, to, transition, event);
142 }
143 }
144 }
145 }
146 }
147