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. */
58     private static final String CLASSNAME 
59             = ConfigurationCacheByDbReadOnlyImpl.class.getName();
60   
61     /** Logger for this class. */
62     private static final Logger logger = Logger.getLogger(CLASSNAME);
63   
64     /** The mutex object to synchronize the config keys map. */
65     private static final Object MUTEX_KEYS = new Object();
66   
67     /** The mutex object to synchronize the services set. */
68     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      */
75     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      */
83     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 ()
94     {
95        try
96        {
97           init();
98           mIsInitialized = true;
99           mInitException = null;
100        }
101        catch (Exception x)
102        {
103           mIsInitialized = false;
104           mInitException = x;
105           final ConfigurationInitializationFailedException sysEvt
106                 = new ConfigurationInitializationFailedException(x);
107           sysEvt.log();
108        }
109     }
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     {
120        final ConfigurationCacheByDbReadOnlyImpl result
121              = ConfigurationCacheHolder.INSTANCE;
122        if (! result.mIsInitialized)
123        {
124           throw new ConfigurationInitializationFailedException(
125                 result.mInitException);
126        }
127        return result;
128     }
129   
130   
131     /**
132      * Setup configuration cache as MBean and initialize cache.
133      */
134     private void init ()
135     {
136        final String method = "init";
137   
138        if (logger.isLoggable(Level.FINER))
139        {
140           logger.entering(CLASSNAME, method);
141        }
142   
143        reloadCache();
144   
145        if (logger.isLoggable(Level.FINER))
146        {
147           logger.exiting(CLASSNAME, method);
148        }
149     }
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     {
162        final String methodName = "getString";
163        if (logger.isLoggable(Level.FINER))
164        {
165           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.
172           final ConfigEntity entity
173                 = ConfigEntityHelper.findReadOnlyByPrimaryKey(key);
174           result = entity.getValue();
175           CfgLogMessage.ConfigurationValueRead.log(key, result);
176        }
177        catch (EntityNotFoundException e)
178        {
179           throw new ConfigurationValueNotFoundException(key, e);
180        }
181        catch (RemoteException re)
182        {
183           throw new ConfigurationValueNotFoundException(key, re);
184        }
185   
186        if (logger.isLoggable(Level.FINER))
187        {
188           logger.exiting(CLASSNAME, methodName, result);
189        }
190        return result;
191     }
192   
193     /** {@inheritDoc} */
194     public Set getKeys ()
195     {
196        final Set result;
197   
198        synchronized (MUTEX_KEYS)
199        {
200           result = Collections.unmodifiableSet(mConfigurationKeys);
201        }
202   
203        return result;
204     }
205   
206   
207     /** {@inheritDoc} */
208     public void addConfigurationListener (ConfigurationListener newListener)
209     {
210        synchronized (MUTEX_SERVICES)
211        {
212           mRegisteredServices.add(new WeakReference(newListener));
213        }
214     }
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     {
224        final String method = "reloadCache";
225        if (logger.isLoggable(Level.FINER))
226        {
227           logger.entering(CLASSNAME, method);
228        }
229   
230        try
231        {
232           final Collection all = ConfigEntityHelper.findAllReadOnly();
233           final Set keys = new HashSet(all.size());
234           for (final Iterator iter = all.iterator(); iter.hasNext();)
235           {
236              final ConfigEntity element = (ConfigEntity) iter.next();
237              keys.add(element.getConfigKey());
238           }
239           // This block violates the j2ee spec.
240           synchronized (MUTEX_KEYS)
241           {
242              mConfigurationKeys = keys;
243           }
244        }
245        catch (Exception e)
246        {
247           final ConfigurationInitializationFailedException cife
248                 = new ConfigurationInitializationFailedException(e);
249 (2)         // CHECKME: create special config cache reload exception
250           cife.addParameter("DETAIL",
251                 "Exception while updating ConfigurationCache.");
252           throw cife;
253        }
254   
255        notifyServices();
256   
257        if (logger.isLoggable(Level.FINER))
258        {
259           logger.exiting(CLASSNAME, method);
260        }
261     }
262   
263     /**
264      * Notifies all registered services about the cache update.
265      */
266     private void notifyServices ()
267     {
268        final ConfigUpdateEvent event = new ConfigUpdateEvent(this,
269              ConfigUpdateEvent.CACHE_UPDATED);
270   
271        final List alive_listeners = new ArrayList();
272        final List dead_listeners = new ArrayList();
273   
274        synchronized (MUTEX_SERVICES)
275        {
276           final Iterator it = mRegisteredServices.iterator();
277           while (it.hasNext())
278           {
279              final WeakReference wk = (WeakReference) it.next();
280              final ConfigurationListener cl = (ConfigurationListener) wk.get();
281              if (cl == null)
282              {
283                 dead_listeners.add(wk);
284              }
285              else
286              {
287                 alive_listeners.add(cl);
288              }
289           }
290           mRegisteredServices.removeAll(dead_listeners);
291        }
292   
293 (3)      for (int i = 0; i < alive_listeners.size(); i++)
294        {
295           ((ConfigurationListener) alive_listeners.get(i))
296                 .updateConfiguration(event);
297        }
298     }
299   
300     /**
301      * Local helper class holding a member initialized by calling
302      * the private constructor of the singleton.
303      */
304 (4)   (4)private static final class ConfigurationCacheHolder
305     {
306        private static final ConfigurationCacheByDbReadOnlyImpl INSTANCE
307           = new ConfigurationCacheByDbReadOnlyImpl();
308     }
309  }
310   

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.