View Javadoc

1   package org.apache.jcs.engine.control;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.FileInputStream;
23  import java.io.IOException;
24  import java.util.ArrayList;
25  import java.util.Enumeration;
26  import java.util.List;
27  import java.util.Properties;
28  import java.util.StringTokenizer;
29  
30  import org.apache.commons.logging.Log;
31  import org.apache.commons.logging.LogFactory;
32  import org.apache.jcs.auxiliary.AuxiliaryCache;
33  import org.apache.jcs.auxiliary.AuxiliaryCacheAttributes;
34  import org.apache.jcs.auxiliary.AuxiliaryCacheFactory;
35  import org.apache.jcs.config.OptionConverter;
36  import org.apache.jcs.config.PropertySetter;
37  import org.apache.jcs.engine.behavior.ICache;
38  import org.apache.jcs.engine.behavior.ICompositeCacheAttributes;
39  import org.apache.jcs.engine.behavior.IElementAttributes;
40  
41  /***
42   * This class configures JCS based on a properties object.
43   * <p>
44   * This class is based on the log4j class org.apache.log4j.PropertyConfigurator
45   * which was made by: "Luke Blanshard" <Luke@quiq.com>"Mark DONSZELMANN"
46   * <Mark.Donszelmann@cern.ch>"Anders Kristensen" <akristensen@dynamicsoft.com>
47   *
48   */
49  public class CompositeCacheConfigurator
50  {
51      private final static Log log = LogFactory.getLog( CompositeCacheConfigurator.class );
52  
53      final static String DEFAULT_REGION = "jcs.default";
54  
55      final static String REGION_PREFIX = "jcs.region.";
56  
57      final static String SYSTEM_REGION_PREFIX = "jcs.system.";
58  
59      final static String AUXILIARY_PREFIX = "jcs.auxiliary.";
60  
61      final static String ATTRIBUTE_PREFIX = ".attributes";
62  
63      final static String CACHE_ATTRIBUTE_PREFIX = ".cacheattributes";
64  
65      final static String ELEMENT_ATTRIBUTE_PREFIX = ".elementattributes";
66  
67      private CompositeCacheManager compositeCacheManager;
68  
69      /***
70       * Constructor for the CompositeCacheConfigurator object
71       *
72       * @param ccMgr
73       */
74      public CompositeCacheConfigurator( CompositeCacheManager ccMgr )
75      {
76          this.compositeCacheManager = ccMgr;
77      }
78  
79      /***
80       * Configure cached for file name.
81       * <p>
82       * This is only used for testing. The manager handles the translation of a
83       * file into a properties object.
84       *
85       * @param configFileName
86       */
87      protected void doConfigure( String configFileName )
88      {
89          Properties props = new Properties();
90          try
91          {
92              FileInputStream istream = new FileInputStream( configFileName );
93              props.load( istream );
94              istream.close();
95          }
96          catch ( IOException e )
97          {
98              log.error( "Could not read configuration file, ignored: " + configFileName, e );
99              return;
100         }
101 
102         // If we reach here, then the config file is alright.
103         doConfigure( props );
104     }
105 
106     /***
107      * Configure cache for properties object.
108      * <p>
109      * This method proceeds in several steps:
110      * <ul>
111      * <li>Store props for use by non configured caches.
112      * <li>Set default value list
113      * <li>Set default cache attr
114      * <li>Set default element attr
115      * <li>Setup system caches to be used
116      * <li>Setup preconfigured caches
117      * </ul>
118      *
119      * @param properties
120      */
121     public void doConfigure( Properties properties )
122     {
123         long start = System.currentTimeMillis();
124 
125         // store props for use by non configured caches
126         compositeCacheManager.props = properties;
127         // set default value list
128         setDefaultAuxValues( properties );
129         // set default cache attr
130         setDefaultCompositeCacheAttributes( properties );
131         // set default element attr
132         setDefaultElementAttributes( properties );
133 
134         // set up ssytem caches to be used by non system caches
135         // need to make sure there is no circuarity of reference
136         parseSystemRegions( properties );
137 
138         // setup preconfigured caches
139         parseRegions( properties );
140 
141         long end = System.currentTimeMillis();
142         if ( log.isInfoEnabled() )
143         {
144             log.info( "Finished configuration in " + ( end - start ) + " ms." );
145         }
146 
147     }
148 
149     /***
150      * Set the default aux list for new caches.
151      *
152      * @param props
153      */
154     protected void setDefaultAuxValues( Properties props )
155     {
156         String value = OptionConverter.findAndSubst( DEFAULT_REGION, props );
157         compositeCacheManager.defaultAuxValues = value;
158 
159         if ( log.isInfoEnabled() )
160         {
161             log.info( "Setting default auxiliaries to " + value );
162         }
163     }
164 
165     /***
166      * Set the default CompositeCacheAttributes for new caches.
167      *
168      * @param props
169      */
170     protected void setDefaultCompositeCacheAttributes( Properties props )
171     {
172         ICompositeCacheAttributes icca = parseCompositeCacheAttributes( props, "",
173                                                                         CompositeCacheConfigurator.DEFAULT_REGION );
174         compositeCacheManager.setDefaultCacheAttributes( icca );
175 
176         log.info( "setting defaultCompositeCacheAttributes to " + icca );
177     }
178 
179     /***
180      * Set the default ElementAttributes for new caches.
181      *
182      * @param props
183      */
184     protected void setDefaultElementAttributes( Properties props )
185     {
186         IElementAttributes iea = parseElementAttributes( props, "", CompositeCacheConfigurator.DEFAULT_REGION );
187         compositeCacheManager.setDefaultElementAttributes( iea );
188 
189         log.info( "setting defaultElementAttributes to " + iea );
190     }
191 
192     /***
193      * Create caches used internally. System status gives them creation
194      * priority.
195      *
196      * @param props
197      */
198     protected void parseSystemRegions( Properties props )
199     {
200         Enumeration en = props.propertyNames();
201         while ( en.hasMoreElements() )
202         {
203             String key = (String) en.nextElement();
204             if ( key.startsWith( SYSTEM_REGION_PREFIX ) && ( key.indexOf( "attributes" ) == -1 ) )
205             {
206                 String regionName = key.substring( SYSTEM_REGION_PREFIX.length() );
207                 String value = OptionConverter.findAndSubst( key, props );
208                 ICache cache;
209                 synchronized ( regionName )
210                 {
211                     cache = parseRegion( props, regionName, value, null, SYSTEM_REGION_PREFIX );
212                 }
213                 compositeCacheManager.systemCaches.put( regionName, cache );
214                 // to be availiable for remote reference they need to be here as
215                 // well
216                 compositeCacheManager.caches.put( regionName, cache );
217             }
218         }
219     }
220 
221     /***
222      * Parse region elements.
223      *
224      * @param props
225      */
226     protected void parseRegions( Properties props )
227     {
228         List regionNames = new ArrayList();
229 
230         Enumeration en = props.propertyNames();
231         while ( en.hasMoreElements() )
232         {
233             String key = (String) en.nextElement();
234             if ( key.startsWith( REGION_PREFIX ) && ( key.indexOf( "attributes" ) == -1 ) )
235             {
236                 String regionName = key.substring( REGION_PREFIX.length() );
237 
238                 regionNames.add( regionName );
239 
240                 String value = OptionConverter.findAndSubst( key, props );
241                 ICache cache;
242                 synchronized ( regionName )
243                 {
244                     cache = parseRegion( props, regionName, value );
245                 }
246                 compositeCacheManager.caches.put( regionName, cache );
247             }
248         }
249 
250         if ( log.isInfoEnabled() )
251         {
252             log.info( "Parsed regions " + regionNames );
253         }
254 
255     }
256 
257     /***
258      * Create cache region.
259      *
260      * @param props
261      * @param regName
262      * @param value
263      * @return CompositeCache
264      */
265     protected CompositeCache parseRegion( Properties props, String regName, String value )
266     {
267         return parseRegion( props, regName, value, null, REGION_PREFIX );
268     }
269 
270     /***
271      * Get all the properties for a region and configure its cache.
272      * <p>
273      * This method tells the otehr parse method the name of the region prefix.
274      *
275      * @param props
276      * @param regName
277      * @param value
278      * @param cca
279      * @return CompositeCache
280      */
281     protected CompositeCache parseRegion( Properties props, String regName, String value, ICompositeCacheAttributes cca )
282     {
283         return parseRegion( props, regName, value, cca, REGION_PREFIX );
284     }
285 
286     /***
287      * Get all the properties for a region and configure its cache.
288      *
289      * @param props
290      * @param regName
291      * @param value
292      * @param cca
293      * @param regionPrefix
294      * @return CompositeCache
295      */
296     protected CompositeCache parseRegion( Properties props, String regName, String value,
297                                          ICompositeCacheAttributes cca, String regionPrefix )
298     {
299         // First, create or get the cache and element attributes, and create
300         // the cache.
301 
302         if ( cca == null )
303         {
304             cca = parseCompositeCacheAttributes( props, regName, regionPrefix );
305         }
306 
307         IElementAttributes ea = parseElementAttributes( props, regName, regionPrefix );
308 
309         CompositeCache cache = new CompositeCache( regName, cca, ea );
310 
311         // Next, create the auxiliaries for the new cache
312 
313         List auxList = new ArrayList();
314 
315         if ( log.isDebugEnabled() )
316         {
317             log.debug( "Parsing region name '" + regName + "', value '" + value + "'" );
318         }
319 
320         // We must skip over ',' but not white space
321         StringTokenizer st = new StringTokenizer( value, "," );
322 
323         // If value is not in the form ", appender.." or "", then we should set
324         // the priority of the category.
325 
326         if ( !( value.startsWith( "," ) || value.equals( "" ) ) )
327         {
328             // just to be on the safe side...
329             if ( !st.hasMoreTokens() )
330             {
331                 return null;
332             }
333         }
334 
335         AuxiliaryCache auxCache;
336         String auxName;
337         while ( st.hasMoreTokens() )
338         {
339             auxName = st.nextToken().trim();
340             if ( auxName == null || auxName.equals( "," ) )
341             {
342                 continue;
343             }
344             log.debug( "Parsing auxiliary named \"" + auxName + "\"." );
345 
346             auxCache = parseAuxiliary( cache, props, auxName, regName );
347 
348             if ( auxCache != null )
349             {
350                 auxList.add( auxCache );
351             }
352         }
353 
354         // Associate the auxiliaries with the cache
355 
356         cache.setAuxCaches( (AuxiliaryCache[]) auxList.toArray( new AuxiliaryCache[0] ) );
357 
358         // Return the new cache
359 
360         return cache;
361     }
362 
363     /***
364      * Get an compositecacheattributes for the listed region.
365      *
366      * @param props
367      * @param regName
368      * @return
369      */
370     protected ICompositeCacheAttributes parseCompositeCacheAttributes( Properties props, String regName )
371     {
372         return parseCompositeCacheAttributes( props, regName, REGION_PREFIX );
373     }
374 
375     /***
376      * Get the main attributes for a region.
377      *
378      * @param props
379      * @param regName
380      * @param regionPrefix
381      * @return ICompositeCacheAttributes
382      */
383     protected ICompositeCacheAttributes parseCompositeCacheAttributes( Properties props, String regName,
384                                                                       String regionPrefix )
385     {
386         ICompositeCacheAttributes ccAttr;
387 
388         String attrName = regionPrefix + regName + CACHE_ATTRIBUTE_PREFIX;
389 
390         // auxFactory was not previously initialized.
391         // String prefix = regionPrefix + regName + ATTRIBUTE_PREFIX;
392         ccAttr = (ICompositeCacheAttributes) OptionConverter
393             .instantiateByKey( props, attrName, org.apache.jcs.engine.behavior.ICompositeCacheAttributes.class, null );
394 
395         if ( ccAttr == null )
396         {
397             if ( log.isInfoEnabled() )
398             {
399                 log.info( "No special CompositeCacheAttributes class defined for key [" + attrName + "], using default class." );
400             }
401 
402             ICompositeCacheAttributes ccAttr2 = compositeCacheManager.getDefaultCacheAttributes();
403             ccAttr = ccAttr2.copy();
404         }
405 
406         if ( log.isDebugEnabled() )
407         {
408             log.debug( "Parsing options for '" + attrName + "'" );
409         }
410 
411         PropertySetter.setProperties( ccAttr, props, attrName + "." );
412         ccAttr.setCacheName( regName );
413 
414         if ( log.isDebugEnabled() )
415         {
416             log.debug( "End of parsing for \"" + attrName + "\"." );
417         }
418 
419         // GET CACHE FROM FACTORY WITH ATTRIBUTES
420         ccAttr.setCacheName( regName );
421         return ccAttr;
422     }
423 
424     /***
425      * Create the element attributes from the properties object for a cache
426      * region.
427      *
428      * @param props
429      * @param regName
430      * @param regionPrefix
431      * @return IElementAttributes
432      */
433     protected IElementAttributes parseElementAttributes( Properties props, String regName, String regionPrefix )
434     {
435         IElementAttributes eAttr;
436 
437         String attrName = regionPrefix + regName + CompositeCacheConfigurator.ELEMENT_ATTRIBUTE_PREFIX;
438 
439         // auxFactory was not previously initialized.
440         // String prefix = regionPrefix + regName + ATTRIBUTE_PREFIX;
441         eAttr = (IElementAttributes) OptionConverter
442             .instantiateByKey( props, attrName, org.apache.jcs.engine.behavior.IElementAttributes.class, null );
443         if ( eAttr == null )
444         {
445             if ( log.isInfoEnabled() )
446             {
447                 log.info( "No special ElementAttribute class defined for key [" + attrName + "], using default class." );
448             }
449 
450             IElementAttributes eAttr2 = compositeCacheManager.getDefaultElementAttributes();
451             eAttr = eAttr2.copy();
452         }
453 
454         if ( log.isDebugEnabled() )
455         {
456             log.debug( "Parsing options for '" + attrName + "'" );
457         }
458 
459         PropertySetter.setProperties( eAttr, props, attrName + "." );
460         // eAttr.setCacheName( regName );
461 
462         if ( log.isDebugEnabled() )
463         {
464             log.debug( "End of parsing for \"" + attrName + "\"." );
465         }
466 
467         // GET CACHE FROM FACTORY WITH ATTRIBUTES
468         // eAttr.setCacheName( regName );
469         return eAttr;
470     }
471 
472     /***
473      * Get an aux cache for the listed aux for a region.
474      *
475      * @param cache
476      *            the cache manager
477      * @param props
478      *            the configuration propeties
479      * @param auxName
480      *            the name of the auxiliary cache
481      * @param regName
482      *            the name of the region.
483      * @return AuxiliaryCache
484      */
485     protected AuxiliaryCache parseAuxiliary( CompositeCache cache, Properties props, String auxName, String regName )
486     {
487         AuxiliaryCache auxCache;
488 
489         if ( log.isDebugEnabled() )
490         {
491             // cache isn't used.
492             // TODO change method signature if is isn't needed.
493             log.debug( "parseAuxiliary, Cache = " + cache );
494         }
495 
496         // GET FACTORY
497         AuxiliaryCacheFactory auxFac = compositeCacheManager.registryFacGet( auxName );
498         if ( auxFac == null )
499         {
500             // auxFactory was not previously initialized.
501             String prefix = AUXILIARY_PREFIX + auxName;
502             auxFac = (AuxiliaryCacheFactory) OptionConverter
503                 .instantiateByKey( props, prefix, org.apache.jcs.auxiliary.AuxiliaryCacheFactory.class, null );
504             if ( auxFac == null )
505             {
506                 log.error( "Could not instantiate auxFactory named \"" + auxName + "\"." );
507                 return null;
508             }
509 
510             auxFac.setName( auxName );
511 
512             compositeCacheManager.registryFacPut( auxFac );
513         }
514 
515         // GET ATTRIBUTES
516         AuxiliaryCacheAttributes auxAttr = compositeCacheManager.registryAttrGet( auxName );
517         String attrName = AUXILIARY_PREFIX + auxName + ATTRIBUTE_PREFIX;
518         if ( auxAttr == null )
519         {
520             // auxFactory was not previously initialized.
521             String prefix = AUXILIARY_PREFIX + auxName + ATTRIBUTE_PREFIX;
522             auxAttr = (AuxiliaryCacheAttributes) OptionConverter
523                 .instantiateByKey( props, prefix, org.apache.jcs.auxiliary.AuxiliaryCacheAttributes.class, null );
524             if ( auxFac == null )
525             {
526                 log.error( "Could not instantiate auxAttr named '" + attrName + "'" );
527                 return null;
528             }
529             auxAttr.setName( auxName );
530             compositeCacheManager.registryAttrPut( auxAttr );
531         }
532 
533         auxAttr = auxAttr.copy();
534 
535         if ( log.isDebugEnabled() )
536         {
537             log.debug( "Parsing options for '" + attrName + "'" );
538         }
539 
540         PropertySetter.setProperties( auxAttr, props, attrName + "." );
541         auxAttr.setCacheName( regName );
542 
543         if ( log.isDebugEnabled() )
544         {
545             log.debug( "End of parsing for '" + attrName + "'" );
546         }
547 
548         // GET CACHE FROM FACTORY WITH ATTRIBUTES
549         auxAttr.setCacheName( regName );
550         // Consider putting the compositeCache back in the factory interface
551         // since the manager may not know about it at this point.
552         // need to make sure the maanger already has the cache
553         // before the auxiliary is created.
554         auxCache = auxFac.createCache( auxAttr, compositeCacheManager );
555         return auxCache;
556     }
557 }