    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