View Javadoc

    1   package org.apache.turbine.services.assemblerbroker;
    2
    3
    4   /*
    5    * Licensed to the Apache Software Foundation (ASF) under one
    6    * or more contributor license agreements.  See the NOTICE file
    7    * distributed with this work for additional information
    8    * regarding copyright ownership.  The ASF licenses this file
    9    * to you under the Apache License, Version 2.0 (the
    10   * "License"); you may not use this file except in compliance
    11   * with the License.  You may obtain a copy of the License at
    12   *
    13   *   http://www.apache.org/licenses/LICENSE-2.0
    14   *
    15   * Unless required by applicable law or agreed to in writing,
    16   * software distributed under the License is distributed on an
    17   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    18   * KIND, either express or implied.  See the License for the
    19   * specific language governing permissions and limitations
    20   * under the License.
    21   */
    22
    23
    24  import java.util.HashMap;
    25  import java.util.Iterator;
    26  import java.util.List;
    27  import java.util.Map;
    28  import java.util.Vector;
    29
    30  import org.apache.commons.collections.map.LRUMap;
    31  import org.apache.commons.configuration.Configuration;
    32  import org.apache.commons.logging.Log;
    33  import org.apache.commons.logging.LogFactory;
    34  import org.apache.turbine.Turbine;
    35  import org.apache.turbine.TurbineConstants;
    36  import org.apache.turbine.modules.Assembler;
    37  import org.apache.turbine.modules.Loader;
    38  import org.apache.turbine.services.InitializationException;
    39  import org.apache.turbine.services.TurbineBaseService;
    40  import org.apache.turbine.services.assemblerbroker.util.AssemblerFactory;
    41  import org.apache.turbine.util.TurbineException;
    42
    43  /**
    44   * TurbineAssemblerBrokerService allows assemblers (like screens,
    45   * actions and layouts) to be loaded from one or more AssemblerFactory
    46   * classes.  AssemblerFactory classes are registered with this broker
    47   * by adding them to the TurbineResources.properties file.
    48   *
    49   * @author <a href="mailto:leon@opticode.co.za">Leon Messerschmidt</a>
    50   * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
    51   * @version $Id: TurbineAssemblerBrokerService.java 1078552 2011-03-06 19:58:46Z tv $
    52   */
    53  public class TurbineAssemblerBrokerService
    54          extends TurbineBaseService
    55          implements AssemblerBrokerService
    56  {
    57      /** Logging */
    58      private static Log log
    59              = LogFactory.getLog(TurbineAssemblerBrokerService.class);
    60
    61      /** A structure that holds the registered AssemblerFactories */
    62      private Map<String, List<AssemblerFactory>> factories = null;
    63
    64      /** A cache that holds the generated Assemblers */
    65      private Map<String, Assembler> assemblerCache = null;
    66
    67      /** A cache that holds the Loaders */
    68      private Map<String, Loader> loaderCache = null;
    69
    70      /** Caching on/off */
    71      private boolean isCaching;
    72
    73      /**
    74       * Get a list of AssemblerFactories of a certain type
    75       *
    76       * @param type type of Assembler
    77       * @return list of AssemblerFactories
    78       */
    79      private List<AssemblerFactory> getFactoryGroup(String type)
    80      {
    81          if (!factories.containsKey(type))
    82          {
    83              factories.put(type, new Vector<AssemblerFactory>());
    84          }
    85          return factories.get(type);
    86      }
    87
    88      /**
    89       * Utiltiy method to register all factories for a given type.
    90       *
    91       * @param type type of Assembler
    92       * @throws TurbineException
    93       */
    94      private void registerFactories(String type)
    95          throws TurbineException
    96      {
    97          List names = getConfiguration().getList(type);
    98
    99          log.info("Registering " + names.size() + " " + type + " factories.");
    100
    101         for (Iterator it = names.iterator(); it.hasNext(); )
    102         {
    103             String factory = (String) it.next();
    104             try
    105             {
    106                 Object o = Class.forName(factory).newInstance();
    107                 registerFactory(type, (AssemblerFactory) o);
    108             }
    109             // these must be passed to the VM
    110             catch (ThreadDeath e)
    111             {
    112                 throw e;
    113             }
    114             catch (OutOfMemoryError e)
    115             {
    116                 throw e;
    117             }
    118             // when using Class.forName(), NoClassDefFoundErrors are likely
    119             // to happen (missing jar files)
    120             catch (Throwable t)
    121             {
    122                 throw new TurbineException("Failed registering " + type
    123                         + " factory: " + factory, t);
    124             }
    125         }
    126     }
    127
    128     /**
    129      * Initializes the AssemblerBroker and loads the AssemblerFactory
    130      * classes registered in TurbineResources.Properties.
    131      *
    132      * @throws InitializationException
    133      */
    134     @SuppressWarnings("unchecked") // as long as commons-collections does not use generics
    135     @Override
    136     public void init()
    137         throws InitializationException
    138     {
    139         factories = new HashMap<String, List<AssemblerFactory>>();
    140
    141         try
    142         {
    143             Configuration conf = getConfiguration();
    144
    145             for (Iterator i = conf.getKeys(); i.hasNext();)
    146             {
    147                 String type = (String)i.next();
    148
    149                 if (!"classname".equalsIgnoreCase(type))
    150                 {
    151                     registerFactories(type);
    152                 }
    153             }
    154         }
    155         catch (TurbineException e)
    156         {
    157             throw new InitializationException(
    158                     "AssemblerBrokerService failed to initialize", e);
    159         }
    160
    161         isCaching = Turbine.getConfiguration()
    162             .getBoolean(TurbineConstants.MODULE_CACHE_KEY,
    163                         TurbineConstants.MODULE_CACHE_DEFAULT);
    164
    165         if (isCaching)
    166         {
    167             int cacheSize = Turbine.getConfiguration()
    168                 .getInt(TurbineConstants.MODULE_CACHE_SIZE_KEY,
    169                         TurbineConstants.MODULE_CACHE_SIZE_DEFAULT);
    170
    171             assemblerCache = new LRUMap(cacheSize);
    172             loaderCache = new LRUMap(cacheSize);
    173         }
    174
    175         setInit(true);
    176     }
    177
    178     /**
    179      * Register a new AssemblerFactory under a certain type
    180      *
    181      * @param type type of Assembler
    182      * @param factory factory to register
    183      */
    184     public void registerFactory(String type, AssemblerFactory factory)
    185     {
    186         getFactoryGroup(type).add(factory);
    187     }
    188
    189     /**
    190      * Attempt to retrieve an Assembler of a given type with
    191      * a name.  Cycle through all the registered AssemblerFactory
    192      * classes of type and return the first non-null assembly
    193      * found.  If an assembly was not found return null.
    194      *
    195      * @param type type of Assembler
    196      * @param name name of the requested Assembler
    197      * @return an Assembler or null
    198      * @throws TurbineException
    199      */
    200     public Assembler getAssembler(String type, String name)
    201         throws TurbineException
    202     {
    203         String key = type + ":" + name;
    204         Assembler assembler = null;
    205
    206         if (isCaching && assemblerCache.containsKey(key))
    207         {
    208             assembler = assemblerCache.get(key);
    209             log.debug("Found " + key + " in the cache!");
    210         }
    211         else
    212         {
    213             log.debug("Loading " + key);
    214             List<AssemblerFactory> facs = getFactoryGroup(type);
    215
    216             for (Iterator<AssemblerFactory> it = facs.iterator(); (assembler == null) && it.hasNext();)
    217             {
    218                 AssemblerFactory fac = it.next();
    219
    220                 try
    221                 {
    222                     assembler = fac.getAssembler(name);
    223                 }
    224                 catch (Exception e)
    225                 {
    226                     throw new TurbineException("Failed to load an assembler for "
    227                                                + name + " from the "
    228                                                + type + " factory "
    229                                                + fac.getClass().getName(), e);
    230                 }
    231
    232                 if (isCaching && assembler != null)
    233                 {
    234                     assemblerCache.put(key, assembler);
    235                 }
    236             }
    237         }
    238
    239         return assembler;
    240     }
    241
    242     /**
    243      * Get a Loader for the given assembler type
    244      *
    245      * @param type The Type of the Assembler
    246      * @return A Loader instance for the requested type
    247      */
    248     public Loader getLoader(String type)
    249     {
    250         Loader loader = null;
    251
    252         if (isCaching && loaderCache.containsKey(type))
    253         {
    254             loader = loaderCache.get(type);
    255             log.debug("Found " + type + " loader in the cache!");
    256         }
    257         else
    258         {
    259             log.debug("Getting Loader for " + type);
    260             List facs = getFactoryGroup(type);
    261
    262             for (Iterator it = facs.iterator(); (loader == null) && it.hasNext();)
    263             {
    264                 AssemblerFactory fac = (AssemblerFactory) it.next();
    265
    266                 loader = fac.getLoader();
    267             }
    268
    269             if (isCaching && loader != null)
    270             {
    271                 loaderCache.put(type, loader);
    272             }
    273         }
    274
    275         if (loader == null)
    276         {
    277             log.warn("Loader for " + type + " is null.");
    278         }
    279
    280         return loader;
    281     }
    282 }