View Javadoc
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