1 package org.jadetower.dao.impl;
2
3 /*
4 Copyright (c) 2003, J Aaron Farr
5 All rights reserved.
6
7 This software is published under the terms of the JadeTower Software License,
8 a BSD derived license, a copy of which has been included with this
9 distribution in the LICENSE file. <http://www.jadetower.org>
10 */
11
12
13 import org.jadetower.dao.DaoManager;
14 import org.jadetower.dao.exception.DaoException;
15 import org.jadetower.resolver.Resolver;
16 import org.jadetower.resolver.ResolverUtils;
17
18 import org.apache.avalon.framework.container.ContainerUtil;
19 import org.apache.avalon.framework.configuration.Configurable;
20 import org.apache.avalon.framework.configuration.Configuration;
21 import org.apache.avalon.framework.configuration.ConfigurationException;
22 import org.apache.avalon.framework.parameters.Parameters;
23 import org.apache.avalon.framework.activity.Initializable;
24 import org.apache.avalon.framework.service.Serviceable;
25 import org.apache.avalon.framework.service.ServiceManager;
26 import org.apache.avalon.framework.service.ServiceException;
27 import org.apache.avalon.framework.logger.Logger;
28 import org.apache.avalon.framework.logger.AbstractLogEnabled;
29 import org.apache.avalon.framework.context.Contextualizable;
30 import org.apache.avalon.framework.context.Context;
31 import org.apache.avalon.framework.context.ContextException;
32 import org.apache.avalon.framework.context.DefaultContext;
33
34 import org.apache.commons.beanutils.BeanUtils;
35
36 import org.picocontainer.defaults.DefaultPicoContainer;
37 import org.picocontainer.defaults.DefaultComponentAdapterFactory;
38 import org.picocontainer.defaults.ConstantParameter;
39 import org.picocontainer.defaults.ComponentParameter;
40 import org.picocontainer.Parameter;
41
42 import java.util.HashMap;
43 import java.util.Set;
44 import java.util.Iterator;
45 import java.io.IOException;
46 import java.util.Map;
47 import java.lang.reflect.Constructor;
48 import java.util.ArrayList;
49 import bsh.Interpreter;
50 import bsh.EvalError;
51
52
53 /***
54 * The Default DAO Manager.
55 * Handles Bean, Pico, and Avalon lifecycles. Uses a PicoContainer as the
56 * basic internal DAO container.
57 *
58 * Part of this class was taken from org.apache.excalibur.configuration.ContextFactory
59 * and is copyrighted by the Apache Software Foundation
60 *
61 * @avalon.component name="dao-manager" lifestyle="singleton"
62 * @avalon.service type="org.jadetower.dao.DaoManager"
63 */
64 public class DefaultDaoManager
65 extends AbstractLogEnabled
66 implements DaoManager, Configurable, Initializable, Serviceable, Contextualizable
67 {
68
69 private DefaultPicoContainer m_lookup = null;
70 private DefaultComponentAdapterFactory m_factory = null;
71 private Resolver m_resolver = null;
72 private DaoServiceManager m_manager = null;
73 private Map m_context = new HashMap();
74 private Context m_parent = null;
75 private HashMap m_configurations = new HashMap();
76
77 public DefaultDaoManager(){
78 }
79
80 public DefaultDaoManager(Resolver resolver, Logger logger, Configuration config, Map context) throws InstantiationException {
81 m_resolver = resolver;
82 m_factory = new DefaultComponentAdapterFactory();
83 m_lookup = new DefaultPicoContainer( m_factory );
84 m_manager = new DaoServiceManager(null,m_lookup);
85 m_parent = new DefaultContext(context);
86 enableLogging(logger);
87 try {
88 configure(config);
89 initialize();
90 }
91 catch (Exception ex) {
92 throw new InstantiationException(ex.getMessage());
93 }
94 }
95
96 public Object getDao(String name) throws DaoException
97 {
98 if(getLogger().isDebugEnabled())
99 getLogger().debug("getting dao: "+name);
100 return m_lookup.getComponentInstance(name);
101 }
102
103 public void release(Object object){
104 /*** @todo work out release code */
105 }
106
107 public void contextualize(Context context) {
108 if(m_parent == null)
109 m_parent = context;
110 }
111
112 /***
113 * @avalon.dependency type="org.jadetower.resolver.Resolver"
114 */
115 public void service(ServiceManager serviceManager) throws ServiceException {
116 if(m_factory == null)
117 m_factory = new DefaultComponentAdapterFactory();
118
119 if(m_lookup == null)
120 m_lookup = new DefaultPicoContainer(m_factory);
121
122 if(m_manager == null)
123 m_manager = new DaoServiceManager(serviceManager,m_lookup);
124
125 if(m_resolver == null)
126 m_resolver = (Resolver) m_manager.lookup(Resolver.ROLE);
127
128 }
129
130 public void configure(Configuration configuration) throws ConfigurationException
131 {
132 m_context = createContextFromConfiguration(m_parent, configuration.getChild("context",true), getLogger());
133 Configuration d = configuration.getChild("daos",true);
134 Configuration[] daos = d.getChildren("dao");
135 for (int i = 0; i < daos.length; i++) {
136 String name = null;
137 try {
138 Configuration dao = daos[i];
139 name = dao.getAttribute("name", null);
140 String uri = dao.getAttribute("uri", null);
141 Object object = m_resolver.resolve(uri);
142 registerDAO(name, object);
143 m_configurations.put(name, dao);
144 }
145 catch (Exception ex) {
146 getLogger().error("Error configuring "+name,ex);
147 }
148 }
149 }
150
151 public void initialize() throws Exception {
152 Object proxy = m_lookup.getComponentMulticaster();
153 handleProxyLifecycle(proxy);
154 ArrayList keys = new ArrayList(m_lookup.getComponentKeys());
155 for(int i=0; i < keys.size(); i++){
156 String name = (String) keys.get(i);
157 Object component = m_lookup.getComponentInstance(name);
158 handleInstanceLifecycle(name,component);
159 }
160
161 handleStartup(proxy);
162 if(getLogger().isDebugEnabled()){
163 getLogger().debug("dao-manager successfully initialized");
164 }
165 }
166
167 protected void registerDAO(String name, Object dao) throws Exception {
168 if(dao instanceof Class){
169 Class daoClazz = (Class) dao;
170
171 // first get the largest constructor
172 Constructor[] cons = daoClazz.getConstructors();
173 Constructor c = null;
174 int maxParameters = 0;
175 for(int i=0; i < cons.length; i++){
176 if(cons[i].getParameterTypes().length >= maxParameters){
177 maxParameters = cons[i].getParameterTypes().length;
178 c = cons[i];
179 }
180 }
181 Class[] classes = c.getParameterTypes();
182 Parameter[] params = new Parameter[classes.length];
183 for (int j = 0; j < params.length; j++) {
184 if (classes[j].isAssignableFrom(Map.class)) {
185 params[j] = new ConstantParameter(m_context);
186 }
187 else {
188 params[j] = new ComponentParameter(classes[j]);
189 }
190 }
191
192 m_lookup.registerComponentImplementation(name,daoClazz,params);
193
194 }
195 else{
196 m_lookup.registerComponentInstance(name,dao);
197 }
198 if(getLogger().isDebugEnabled())
199 getLogger().debug("registered DAO: "+name);
200 }
201
202 protected void handleProxyLifecycle(Object dao) throws Exception {
203 ContainerUtil.enableLogging(dao,getLogger());
204 ContainerUtil.contextualize(dao, new DefaultContext(m_context));
205 ContainerUtil.service(dao,m_manager);
206 }
207
208 protected void handleInstanceLifecycle(String name, Object dao) throws Exception {
209 Configuration conf = (Configuration) m_configurations.get(name);
210 ContainerUtil.configure(dao,conf);
211 ContainerUtil.parameterize(dao,Parameters.fromConfiguration(conf));
212 BeanUtils.populate(dao,m_context);
213 }
214
215 protected void handleStartup(Object proxy) throws Exception {
216 ContainerUtil.initialize(proxy);
217 ContainerUtil.start(proxy);
218 }
219
220 /***
221 * Create context-attributes from entrys within <context/>-tag in config
222 * (Copyright ASF). Modified to handle URI's instead of types.
223 * @param parent the parent context
224 * @param config the configuration element describing the context parameters
225 * @param log a logging channel
226 * @return Context a context instance
227 * @exception ConfigurationException if a context related error occurs
228 */
229 protected Map createContextFromConfiguration(
230 Context parent, Configuration config, Logger log )
231 throws ConfigurationException
232 {
233
234 ClassLoader loader = Thread.currentThread().getContextClassLoader();
235 HashMap map = new HashMap();
236
237 Configuration[] scripts = config.getChildren("script");
238 Interpreter shell = new Interpreter();
239 for (int i = 0; i < scripts.length; i++) {
240 try {
241 Configuration script = scripts[i];
242 String scriptFile = script.getAttribute("file", null);
243 Object result = null;
244 if (scriptFile != null) {
245 result = shell.source(scriptFile);
246 }
247 else {
248 String bshScript = script.getValue(null);
249 if (bshScript != null) {
250 result = shell.eval(bshScript);
251 }
252 }
253 if (result != null && result instanceof Map) {
254 map.putAll( (Map) result);
255 }
256 }
257 catch (EvalError ex) {
258 if(getLogger().isErrorEnabled())
259 getLogger().error("Error during context script evaluation",ex);
260 }
261 catch (IOException ex) {
262 if(getLogger().isErrorEnabled())
263 getLogger().error("Error reading context script",ex);
264 }
265 }
266
267 final Configuration[] entrys = config.getChildren("entry");
268
269 for (int i = 0; i < entrys.length; i++) {
270 Configuration c = entrys[i];
271 final String paramName = entrys[i].getAttribute(
272 "name", null);
273 final String uri = entrys[i].getAttribute("uri",
274 "class://java.lang.String");
275
276 if (paramName == null) {
277 throw new ConfigurationException(
278 "missing name for context-entry");
279 }
280 try {
281
282 if (ResolverUtils.getScheme(uri).equalsIgnoreCase("parent")) {
283 String name = ResolverUtils.getPath(uri);
284 map.put(name, m_parent.get(name));
285
286 }
287 else {
288
289 Object object = m_resolver.resolve(uri);
290
291 if (object instanceof Class) {
292 final String className = ResolverUtils.getPath(uri);
293
294 Class[] params;
295 Object[] values;
296 Configuration entry = entrys[i];
297
298 if (entry.getAttribute("value", null) != null) {
299 // Single argument String-constructor
300 params = new Class[1];
301 params[0] = Class.forName("java.lang.String");
302 Class[] consObjects = {
303 Class.forName("java.lang.String")};
304 Constructor cons = params[0].getConstructor(consObjects);
305 values = new Object[1];
306 Object[] consValues = {
307 getContextValue(map, entry.getAttribute("value"))
308 };
309 values[0] = cons.newInstance(consValues);
310
311 if (log != null) {
312 log.debug("add context-attr '" + paramName
313 + "' class '" + className
314 + "' with value '" + consValues[0] + "'");
315 }
316 }
317 else {
318 // Multiple argument constructor
319 Configuration[] entryChilds = entry.getChildren("parameter");
320
321 params = new Class[entryChilds.length];
322 values = new Object[entryChilds.length];
323
324 if (log != null) {
325 log.debug("add context-attr '" + paramName
326 + "' class '" + className + "' with "
327 + entryChilds.length + " values");
328 }
329
330 for (int p = 0; p < entryChilds.length; p++) {
331 String paramClassName = entryChilds[p].getAttribute(
332 "type", "java.lang.String");
333 String paramValue = entryChilds[p].getAttribute("value", null);
334
335 if (paramValue == null) {
336 if (log != null) {
337 log.debug("value" + (p + 1) + ": class '"
338 + paramClassName + "' no value");
339 }
340 }
341 else {
342 paramValue = getContextValue(map, paramValue);
343 if (log != null) {
344 log.debug("value" + (p + 1) + ": class '"
345 + paramClassName + "' value '" + paramValue + "'");
346 }
347 }
348
349 try {
350 params[p] = loader.loadClass(paramClassName);
351
352 if (paramValue == null) {
353 values[p] = params[p].newInstance();
354 }
355 else {
356 Class[] consObjects = {
357 Class.forName("java.lang.String")};
358 Constructor cons = params[p].getConstructor(consObjects);
359 Object[] consValues = {
360 paramValue};
361 values[p] = cons.newInstance(consValues);
362 }
363 }
364 catch (ClassNotFoundException e) {
365 // Class not found
366 // -> perhaps a primitve class?
367 if (paramClassName.equals("int")) {
368 params[p] = int.class;
369 values[p] = new Integer(paramValue);
370 }
371 else if (paramClassName.equals("short")) {
372 params[p] = short.class;
373 values[p] = new Short(paramValue);
374 }
375 else if (paramClassName.equals("long")) {
376 params[p] = long.class;
377 values[p] = new Long(paramValue);
378 }
379 else if (paramClassName.equals("byte")) {
380 params[p] = byte.class;
381 values[p] = new Byte(paramValue);
382 }
383 else if (paramClassName.equals("double")) {
384 params[p] = double.class;
385 values[p] = new Double(paramValue);
386 }
387 else if (paramClassName.equals("float")) {
388 params[p] = float.class;
389 values[p] = new Float(paramValue);
390 }
391 else if (paramClassName.equals("char")) {
392 params[p] = char.class;
393 values[p] = new Character(paramValue.charAt(0));
394 }
395 else if (paramClassName.equals("boolean")) {
396 params[p] = boolean.class;
397 values[p] = new Boolean(paramValue);
398 }
399 else {
400 throw new ConfigurationException(
401 "incorrect type '" + paramClassName
402 + "' for context-attribute '" + paramName + "'", e);
403 }
404 }
405 }
406 }
407
408 Class paramClass;
409 try {
410 paramClass = loader.loadClass(className);
411 }
412 catch (final ClassNotFoundException e) {
413 throw new ConfigurationException(
414 "incorrect type '" + className
415 + "' for context-attribute '" + paramName + "'",
416 e);
417 }
418
419 Object paramInstance;
420
421 if (params.length > 0) {
422 // using param contructor
423 Constructor cons = paramClass.getConstructor(params);
424 paramInstance = cons.newInstance(values);
425 }
426 else {
427 // using default constructor
428 paramInstance = paramClass.newInstance();
429 }
430
431 map.put(paramName, paramInstance);
432 }
433 else {
434 map.put(paramName, object);
435 }
436 }
437 }
438 catch (ConfigurationException e) {
439 throw e;
440 }
441 catch (Exception e) {
442 throw new ConfigurationException(
443 "Error add context-attribute '" + paramName
444 + "' from Configuration", e);
445 }
446 }
447
448 return map;
449 }
450
451 /***
452 * Resolving an attribute value by replacing ${context-param} with
453 * the corresponding param out of current context.
454 * (Copyright AFS)
455 * @param map a map
456 * @param rawValue a raw value
457 * @return String the context attribute value
458 * @exception ConfigurationException if context-param does not exists
459 */
460 private static String getContextValue( Map map, String rawValue )
461 throws ConfigurationException
462 {
463 StringBuffer result = new StringBuffer( "" );
464 int i = 0;
465 int j = -1;
466 while( ( j = rawValue.indexOf( "${", i ) ) > -1 )
467 {
468 if( i < j )
469 {
470 result.append( rawValue.substring( i, j ) );
471 }
472 int k = rawValue.indexOf( '}', j );
473 final String ctxName = rawValue.substring( j + 2, k );
474 final Object ctx = map.get( ctxName );
475 if( ctx == null )
476 {
477 throw new ConfigurationException(
478 "missing entry '" + ctxName + "' in Context" );
479 }
480 result.append( ctx.toString() );
481 i = k + 1;
482 }
483 if( i < rawValue.length() )
484 {
485 result.append( rawValue.substring( i, rawValue.length() ) );
486 }
487 return result.toString();
488 }
489
490 }
This page was automatically generated by Maven