root/trunk/src/java/org/jcoderz/commons/config/ConfigurationCacheByDbReadOnlyImpl.java

Revision 1011, 9.0 kB (checked in by amandel, 4 years ago)

Aligned svn keyword settings.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1/*
2 * $Id$
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 */
33package org.jcoderz.commons.config;
34
35import java.lang.ref.WeakReference;
36import java.rmi.RemoteException;
37import java.util.ArrayList;
38import java.util.Collection;
39import java.util.Collections;
40import java.util.HashSet;
41import java.util.Iterator;
42import java.util.List;
43import java.util.Set;
44import java.util.logging.Level;
45import java.util.logging.Logger;
46
47import 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 */
54public 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         // 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      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   private static final class ConfigurationCacheHolder
305   {
306      private static final ConfigurationCacheByDbReadOnlyImpl INSTANCE
307         = new ConfigurationCacheByDbReadOnlyImpl();
308   }
309}
Note: See TracBrowser for help on using the browser.