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 */ 017package org.apache.commons.scxml2; 018 019import java.util.HashMap; 020import java.util.LinkedHashSet; 021import java.util.Map; 022import java.util.Set; 023 024import org.apache.commons.scxml2.model.EnterableState; 025import org.apache.commons.scxml2.model.Observable; 026import org.apache.commons.scxml2.model.Transition; 027import org.apache.commons.scxml2.model.TransitionTarget; 028 029/** 030 * The registry where SCXML listeners are recorded for nodes of 031 * interest such as the <code>SCXML</code> root, 032 * <code>EnterableState</code>s and <code>Transition</code>s. 033 * The notification registry keeps track of all 034 * <code>SCXMLListener</code>s attached and notifies relevant 035 * listeners of the events that interest them. 036 * 037 */ 038public final class NotificationRegistry { 039 040 /** 041 * The Map of all listeners keyed by {@link Observable#getObservableId()}. 042 */ 043 private final Map<Integer, Set<SCXMLListener>> regs; 044 045 /** 046 * Constructor. 047 */ 048 public NotificationRegistry() { 049 this.regs = new HashMap<Integer, Set<SCXMLListener>>(); 050 } 051 052 /** 053 * Register this SCXMLListener for this Observable. 054 * 055 * @param source The observable this listener wants to listen to 056 * @param lst The listener 057 */ 058 synchronized void addListener(final Observable source, final SCXMLListener lst) { 059 if (source != null && source.getObservableId() != null) { 060 Set<SCXMLListener> entries = regs.get(source.getObservableId()); 061 if (entries == null) { 062 entries = new LinkedHashSet<SCXMLListener>(); 063 regs.put(source.getObservableId(), entries); 064 } 065 entries.add(lst); 066 } 067 } 068 069 /** 070 * Deregister this SCXMLListener for this Observable. 071 * 072 * @param source The observable this listener wants to stop listening to 073 * @param lst The listener 074 */ 075 synchronized void removeListener(final Observable source, final SCXMLListener lst) { 076 if (source != null && source.getObservableId() != null) { 077 Set<SCXMLListener> entries = regs.get(source.getObservableId()); 078 if (entries != null) { 079 entries.remove(lst); 080 if (entries.size() == 0) { 081 regs.remove(source.getObservableId()); 082 } 083 } 084 } 085 } 086 087 /** 088 * Inform all relevant listeners that a EnterableState has been 089 * entered. 090 * 091 * @param source The Observable 092 * @param state The EnterableState that was entered 093 */ 094 public synchronized void fireOnEntry(final Observable source, 095 final EnterableState state) { 096 if (source != null && source.getObservableId() != null) { 097 Set<SCXMLListener> entries = regs.get(source.getObservableId()); 098 if (entries != null) { 099 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