Coverage Report - org.apache.commons.configuration.event.EventSource
 
Classes in this File Line Coverage Branch Coverage Complexity
EventSource
92%
34/37
100%
6/6
1,667
 
 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.configuration.event;
 18  
 
 19  
 import java.util.ArrayList;
 20  
 import java.util.Collection;
 21  
 import java.util.Collections;
 22  
 import java.util.Iterator;
 23  
 import java.util.LinkedList;
 24  
 
 25  
 /**
 26  
  * <p>
 27  
  * A base class for objects that can generate configuration events.
 28  
  * </p>
 29  
  * <p>
 30  
  * This class implements functionality for managing a set of event listeners
 31  
  * that can be notified when an event occurs. It can be extended by
 32  
  * configuration classes that support the event machanism. In this case these
 33  
  * classes only need to call the <code>fireEvent()</code> method when an event
 34  
  * is to be delivered to the registered listeners.
 35  
  * </p>
 36  
  * <p>
 37  
  * Adding and removing event listeners can happen concurrently to manipulations
 38  
  * on a configuration that cause events. The operations are synchronized.
 39  
  * </p>
 40  
  * <p>
 41  
  * With the <code>detailEvents</code> property the number of detail events can
 42  
  * be controlled. Some methods in configuration classes are implemented in a way
 43  
  * that they call other methods that can generate their own events. One example
 44  
  * is the <code>setProperty()</code> method that can be implemented as a
 45  
  * combination of <code>clearProperty()</code> and <code>addProperty()</code>.
 46  
  * With <code>detailEvents</code> set to <b>true</b>, all involved methods
 47  
  * will generate events (i.e. listeners will receive property set events,
 48  
  * property clear events, and property add events). If this mode is turned off
 49  
  * (which is the default), detail events are suppressed, so only property set
 50  
  * events will be received. Note that the number of received detail events may
 51  
  * differ for different configuration implementations.
 52  
  * <code>{@link org.apache.commons.configuration.HierarchicalConfiguration HierarchicalConfiguration}</code>
 53  
  * for instance has a custom implementation of <code>setProperty()</code>, which
 54  
  * does not generate any detail events.
 55  
  * </p>
 56  
  *
 57  
  * @author <a
 58  
  * href="http://jakarta.apache.org/commons/configuration/team-list.html">Commons
 59  
  * Configuration team</a>
 60  
  * @version $Id: EventSource.java 439648 2006-09-02 20:42:10Z oheger $
 61  
  * @since 1.3
 62  
  */
 63  
 public class EventSource
 64  
 {
 65  
     /** A collection for the registered event listeners. */
 66  
     private Collection listeners;
 67  
 
 68  
     /** A counter for the detail events. */
 69  
     private int detailEvents;
 70  
 
 71  
     /**
 72  
      * Creates a new instance of <code>EventSource</code>.
 73  
      */
 74  
     public EventSource()
 75  2258
     {
 76  2258
         clearConfigurationListeners();
 77  2258
     }
 78  
 
 79  
     /**
 80  
      * Adds a configuration listener to this object.
 81  
      *
 82  
      * @param l the listener to add
 83  
      */
 84  
     public void addConfigurationListener(ConfigurationListener l)
 85  
     {
 86  1317
         if (l == null)
 87  
         {
 88  1
             throw new IllegalArgumentException("Listener must not be null!");
 89  
         }
 90  1316
         synchronized (listeners)
 91  
         {
 92  1316
             listeners.add(l);
 93  1316
         }
 94  1316
     }
 95  
 
 96  
     /**
 97  
      * Removes the specified event listener so that it does not receive any
 98  
      * further events caused by this object.
 99  
      *
 100  
      * @param l the listener to be removed
 101  
      * @return a flag whether the event listener was found
 102  
      */
 103  
     public boolean removeConfigurationListener(ConfigurationListener l)
 104  
     {
 105  380
         synchronized (listeners)
 106  
         {
 107  380
             return listeners.remove(l);
 108  0
         }
 109  
     }
 110  
 
 111  
     /**
 112  
      * Returns a collection with all configuration event listeners that are
 113  
      * currently registered at this object.
 114  
      *
 115  
      * @return a collection with the registered
 116  
      * <code>ConfigurationListener</code>s (this collection cannot be
 117  
      * changed)
 118  
      */
 119  
     public Collection getConfigurationListeners()
 120  
     {
 121  26
         synchronized (listeners)
 122  
         {
 123  26
             return Collections.unmodifiableCollection(listeners);
 124  0
         }
 125  
     }
 126  
 
 127  
     /**
 128  
      * Removes all registered configuration listeners.
 129  
      */
 130  
     public void clearConfigurationListeners()
 131  
     {
 132  2281
         listeners = new LinkedList();
 133  2281
     }
 134  
 
 135  
     /**
 136  
      * Returns a flag whether detail events are enabled.
 137  
      *
 138  
      * @return a flag if detail events are generated
 139  
      */
 140  
     public boolean isDetailEvents()
 141  
     {
 142  4
         synchronized (listeners)
 143  
         {
 144  4
             return detailEvents > 0;
 145  0
         }
 146  
     }
 147  
 
 148  
     /**
 149  
      * Determines whether detail events should be generated. If enabled, some
 150  
      * methods can generate multiple update events. Note that this method
 151  
      * records the number of calls, i.e. if for instance
 152  
      * <code>setDetailEvents(false)</code> was called three times, you will
 153  
      * have to invoke the method as often to enable the details.
 154  
      *
 155  
      * @param enable a flag if detail events should be enabled or disabled
 156  
      */
 157  
     public void setDetailEvents(boolean enable)
 158  
     {
 159  4491
         synchronized (listeners)
 160  
         {
 161  4491
             if (enable)
 162  
             {
 163  2254
                 detailEvents++;
 164  
             }
 165  
             else
 166  
             {
 167  2237
                 detailEvents--;
 168  
             }
 169  4491
         }
 170  4491
     }
 171  
 
 172  
     /**
 173  
      * Creates an event object and delivers it to all registered event
 174  
      * listeners. The method will check first if sending an event is allowed
 175  
      * (making use of the <code>detailEvents</code> property), and if
 176  
      * listeners are registered.
 177  
      *
 178  
      * @param type the event's type
 179  
      * @param propName the name of the affected property (can be <b>null</b>)
 180  
      * @param propValue the value of the affected property (can be <b>null</b>)
 181  
      * @param before the before update flag
 182  
      */
 183  
     protected void fireEvent(int type, String propName, Object propValue,
 184  
             boolean before)
 185  
     {
 186  79475
         Collection listenersToCall = null;
 187  
 
 188  79475
         synchronized (listeners)
 189  
         {
 190  79475
             if (detailEvents >= 0 && listeners.size() > 0)
 191  
             {
 192  
                 // Copy listeners to another collection so that manipulating
 193  
                 // the listener list during event delivery won't cause problems
 194  469
                 listenersToCall = new ArrayList(listeners);
 195  
             }
 196  79475
         }
 197  
 
 198  79475
         if (listenersToCall != null)
 199  
         {
 200  469
             ConfigurationEvent event = createEvent(type, propName, propValue,
 201  
                     before);
 202  1440
             for (Iterator it = listenersToCall.iterator(); it.hasNext();)
 203  
             {
 204  502
                 ((ConfigurationListener) it.next()).configurationChanged(event);
 205  
             }
 206  
         }
 207  79475
     }
 208  
 
 209  
     /**
 210  
      * Creates a <code>ConfigurationEvent</code> object based on the passed in
 211  
      * parameters. This is called by <code>fireEvent()</code> if it decides
 212  
      * that an event needs to be generated.
 213  
      *
 214  
      * @param type the event's type
 215  
      * @param propName the name of the affected property (can be <b>null</b>)
 216  
      * @param propValue the value of the affected property (can be <b>null</b>)
 217  
      * @param before the before update flag
 218  
      * @return the newly created event object
 219  
      */
 220  
     protected ConfigurationEvent createEvent(int type, String propName,
 221  
             Object propValue, boolean before)
 222  
     {
 223  469
         return new ConfigurationEvent(this, type, propName, propValue, before);
 224  
     }
 225  
 }