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