001 package org.apache.turbine.services.assemblerbroker; 002 003 004 /* 005 * Licensed to the Apache Software Foundation (ASF) under one 006 * or more contributor license agreements. See the NOTICE file 007 * distributed with this work for additional information 008 * regarding copyright ownership. The ASF licenses this file 009 * to you under the Apache License, Version 2.0 (the 010 * "License"); you may not use this file except in compliance 011 * with the License. You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, 016 * software distributed under the License is distributed on an 017 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 018 * KIND, either express or implied. See the License for the 019 * specific language governing permissions and limitations 020 * under the License. 021 */ 022 023 024 import java.util.HashMap; 025 import java.util.Iterator; 026 import java.util.List; 027 import java.util.Map; 028 import java.util.Vector; 029 030 import org.apache.commons.collections.map.LRUMap; 031 import org.apache.commons.configuration.Configuration; 032 import org.apache.commons.logging.Log; 033 import org.apache.commons.logging.LogFactory; 034 import org.apache.turbine.Turbine; 035 import org.apache.turbine.TurbineConstants; 036 import org.apache.turbine.modules.Assembler; 037 import org.apache.turbine.modules.Loader; 038 import org.apache.turbine.services.InitializationException; 039 import org.apache.turbine.services.TurbineBaseService; 040 import org.apache.turbine.services.assemblerbroker.util.AssemblerFactory; 041 import org.apache.turbine.util.TurbineException; 042 043 /** 044 * TurbineAssemblerBrokerService allows assemblers (like screens, 045 * actions and layouts) to be loaded from one or more AssemblerFactory 046 * classes. AssemblerFactory classes are registered with this broker 047 * by adding them to the TurbineResources.properties file. 048 * 049 * @author <a href="mailto:leon@opticode.co.za">Leon Messerschmidt</a> 050 * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a> 051 * @version $Id: TurbineAssemblerBrokerService.java 1078552 2011-03-06 19:58:46Z tv $ 052 */ 053 public class TurbineAssemblerBrokerService 054 extends TurbineBaseService 055 implements AssemblerBrokerService 056 { 057 /** Logging */ 058 private static Log log 059 = LogFactory.getLog(TurbineAssemblerBrokerService.class); 060 061 /** A structure that holds the registered AssemblerFactories */ 062 private Map<String, List<AssemblerFactory>> factories = null; 063 064 /** A cache that holds the generated Assemblers */ 065 private Map<String, Assembler> assemblerCache = null; 066 067 /** A cache that holds the Loaders */ 068 private Map<String, Loader> loaderCache = null; 069 070 /** Caching on/off */ 071 private boolean isCaching; 072 073 /** 074 * Get a list of AssemblerFactories of a certain type 075 * 076 * @param type type of Assembler 077 * @return list of AssemblerFactories 078 */ 079 private List<AssemblerFactory> getFactoryGroup(String type) 080 { 081 if (!factories.containsKey(type)) 082 { 083 factories.put(type, new Vector<AssemblerFactory>()); 084 } 085 return factories.get(type); 086 } 087 088 /** 089 * Utiltiy method to register all factories for a given type. 090 * 091 * @param type type of Assembler 092 * @throws TurbineException 093 */ 094 private void registerFactories(String type) 095 throws TurbineException 096 { 097 List names = getConfiguration().getList(type); 098 099 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 }