Project Report: fawkez

Packagesummary org.jcoderz.commons.config

org.jcoderz.commons.config.ConfigurationCacheByDbReadOnlyImpl

LineHitsNoteSource
1  /*
2   * $Id: ConfigurationCacheByDbReadOnlyImpl.java 1011 2008-06-16 17:57:36Z amandel $
3   *
4   * Copyright 2006, The jCoderZ.org Project. All rights reserved.
5   *
6   * Redistribution and use in source and binary forms, with or without
7   * modification, are permitted provided that the following conditions are
8   * met:
9   *
10   *    * Redistributions of source code must retain the above copyright
11   *      notice, this list of conditions and the following disclaimer.
12   *    * Redistributions in binary form must reproduce the above
13   *      copyright notice, this list of conditions and the following
14   *      disclaimer in the documentation and/or other materials
15   *      provided with the distribution.
16   *    * Neither the name of the jCoderZ.org Project nor the names of
17   *      its contributors may be used to endorse or promote products
18   *      derived from this software without specific prior written
19   *      permission.
20   *
21   * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND
22   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24   * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS
25   * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28   * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30   * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32   */
33  package org.jcoderz.commons.config;
34  
35  import java.lang.ref.WeakReference;
36  import java.rmi.RemoteException;
37  import java.util.ArrayList;
38  import java.util.Collection;
39  import java.util.Collections;
40  import java.util.HashSet;
41  import java.util.Iterator;
42  import java.util.List;
43  import java.util.Set;
44  import java.util.logging.Level;
45  import java.util.logging.Logger;
46  
47  import org.jcoderz.commons.EntityNotFoundException;
48  
49  /**
50   * This ConfigurationCache implementation is based on a ReadOnly EntityBean
51   * that stores its data within a database table.
52   *
53   */
54 (1)public final class ConfigurationCacheByDbReadOnlyImpl
55        implements ConfigurationCacheInterface
56  {
57     /** Name of this class. */
580    private static final String CLASSNAME
59             = ConfigurationCacheByDbReadOnlyImpl.class.getName();
60  
61     /** Logger for this class. */
620    private static final Logger logger = Logger.getLogger(CLASSNAME);
63  
64     /** The mutex object to synchronize the config keys map. */
650    private static final Object MUTEX_KEYS = new Object();
66  
67     /** The mutex object to synchronize the services set. */
680    private static final Object MUTEX_SERVICES = new Object();
69  
70  
71     /**
72      * cache the configuration keys also, to prevent set creation for every
73      * {@link #getKeys()} call
74      */
750    private Set mConfigurationKeys = null;
76  
77     /**
78      * This Set contains the Services that have been registered to receive
79      * notifications when the cache has been changed.
80      * The Set contains objects that implement the ConfigurationListener
81      * interface.
82      */
830    private final Set mRegisteredServices = new HashSet();
84  
85     private boolean mIsInitialized;
86     private Exception mInitException;
87  
88     /**
89      * Singleton has no public constructor
90      *
91      * @see ConfigurationCacheByDbReadOnlyImpl#current()
92      */
93     private ConfigurationCacheByDbReadOnlyImpl ()
940    {
95        try
96        {
970          init();
980          mIsInitialized = true;
990          mInitException = null;
100        }
1010       catch (Exception x)
102        {
1030          mIsInitialized = false;
1040          mInitException = x;
1050          final ConfigurationInitializationFailedException sysEvt
106                 = new ConfigurationInitializationFailedException(x);
1070          sysEvt.log();
1080       }
1090    }
110  
111  
112     /**
113      * Returns a reference to the one and only object instance of this
114      * class. Use this method to access the object's methods.
115      *
116      * @return a reference to the one and only object instance of this class.
117      */
118     public static ConfigurationCacheByDbReadOnlyImpl current ()
119     {
1200       final ConfigurationCacheByDbReadOnlyImpl result
121              = ConfigurationCacheHolder.INSTANCE;
1220       if (! result.mIsInitialized)
123        {
1240          throw new ConfigurationInitializationFailedException(
125                 result.mInitException);
126        }
1270       return result;
128     }
129  
130  
131     /**
132      * Setup configuration cache as MBean and initialize cache.
133      */
134     private void init ()
135     {
1360       final String method = "init";
137  
1380       if (logger.isLoggable(Level.FINER))
139        {
1400          logger.entering(CLASSNAME, method);
141        }
142  
1430       reloadCache();
144  
1450       if (logger.isLoggable(Level.FINER))
146        {
1470          logger.exiting(CLASSNAME, method);
148        }
1490    }
150  
151     /**
152      * {@inheritDoc}
153      * Returns the String value set for the given configuration key.
154      * @param key the key to look up.
155      * @return the value as string.
156      * @throws ConfigurationValueNotFoundException if the key is not set or
157      *       the resource was not found.
158      */
159     public String getString (String key)
160           throws ConfigurationValueNotFoundException
161     {
1620       final String methodName = "getString";
1630       if (logger.isLoggable(Level.FINER))
164        {
1650          logger.entering(CLASSNAME, methodName, key);
166        }
167        final String result;
168        try
169        {
170           // No caching in this class is used for the config entry,
171           // because EntityBean is defined with ReadOnly and timeout=0.
1720          final ConfigEntity entity
173                 = ConfigEntityHelper.findReadOnlyByPrimaryKey(key);
1740          result = entity.getValue();
1750          CfgLogMessage.ConfigurationValueRead.log(key, result);
176        }
1770       catch (EntityNotFoundException e)
178        {
1790          throw new ConfigurationValueNotFoundException(key, e);
180        }
1810       catch (RemoteException re)
182        {
1830          throw new ConfigurationValueNotFoundException(key, re);
1840       }
185  
1860       if (logger.isLoggable(Level.FINER))
187        {
1880          logger.exiting(CLASSNAME, methodName, result);
189        }
1900       return result;
191     }
192  
193     /** {@inheritDoc} */
194     public Set getKeys ()
195     {
196        final Set result;
197  
1980       synchronized (MUTEX_KEYS)
199        {
2000          result = Collections.unmodifiableSet(mConfigurationKeys);
2010       }
202  
2030       return result;
204     }
205  
206  
207     /** {@inheritDoc} */
208     public void addConfigurationListener (ConfigurationListener newListener)
209     {
2100       synchronized (MUTEX_SERVICES)
211        {
2120          mRegisteredServices.add(new WeakReference(newListener));
2130       }
2140    }
215  
216  
217     /**
218      * Reloads the internal configuration cache from resource bundle.
219      * If an exception occurs during, the old cached properties are
220      * returned.
221      */
222     public void reloadCache ()
223     {
2240       final String method = "reloadCache";
2250       if (logger.isLoggable(Level.FINER))
226        {
2270          logger.entering(CLASSNAME, method);
228        }
229  
230        try
231        {
2320          final Collection all = ConfigEntityHelper.findAllReadOnly();
2330          final Set keys = new HashSet(all.size());
2340          for (final Iterator iter = all.iterator(); iter.hasNext();)
235           {
2360             final ConfigEntity element = (ConfigEntity) iter.next();
2370             keys.add(element.getConfigKey());
2380          }
239           // This block violates the j2ee spec.
2400          synchronized (MUTEX_KEYS)
241           {
2420             mConfigurationKeys = keys;
2430          }
244        }
2450       catch (Exception e)
246        {
2470          final ConfigurationInitializationFailedException cife
248                 = new ConfigurationInitializationFailedException(e);
249 (2)         // CHECKME: create special config cache reload exception
2500          cife.addParameter("DETAIL",
251                 "Exception while updating ConfigurationCache.");
2520          throw cife;
2530       }
254  
2550       notifyServices();
256  
2570       if (logger.isLoggable(Level.FINER))
258        {
2590          logger.exiting(CLASSNAME, method);
260        }
2610    }
262  
263     /**
264      * Notifies all registered services about the cache update.
265      */
266     private void notifyServices ()
267     {
2680       final ConfigUpdateEvent event = new ConfigUpdateEvent(this,
269              ConfigUpdateEvent.CACHE_UPDATED);
270  
2710       final List alive_listeners = new ArrayList();
2720       final List dead_listeners = new ArrayList();
273  
2740       synchronized (MUTEX_SERVICES)
275        {
2760          final Iterator it = mRegisteredServices.iterator();
2770          while (it.hasNext())
278           {
2790             final WeakReference wk = (WeakReference) it.next();
2800             final ConfigurationListener cl = (ConfigurationListener) wk.get();
2810             if (cl == null)
282              {
2830                dead_listeners.add(wk);
284              }
285              else
286              {
2870                alive_listeners.add(cl);
288              }
2890          }
2900          mRegisteredServices.removeAll(dead_listeners);
2910       }
292  
2930(3)      for (int i = 0; i < alive_listeners.size(); i++)
294        {
2950          ((ConfigurationListener) alive_listeners.get(i))
296                 .updateConfiguration(event);
297        }
2980    }
299  
300     /**
301      * Local helper class holding a member initialized by calling
302      * the private constructor of the singleton.
303      */
3040(4)   private static final class ConfigurationCacheHolder
305     {
3060       private static final ConfigurationCacheByDbReadOnlyImpl INSTANCE
307           = new ConfigurationCacheByDbReadOnlyImpl();
308     }
309  }

Findings in this File

c (1) 54 : 0 Type Javadoc comment is missing an @author tag.
i (2) 249 : 0 Comment matches to-do format '(TODO|FIXME|CHECKME)'.
w (3) 293 : 0 method org.jcoderz.commons.config.ConfigurationCacheByDbReadOnlyImpl.notifyServices() uses integer based for loops to iterate over a List
c (4) 304 : 4 Utility classes should not have a public or default constructor.