0001: /*
0002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
0003: *
0004: * This file is part of Resin(R) Open Source
0005: *
0006: * Each copy or derived work must preserve the copyright notice and this
0007: * notice unmodified.
0008: *
0009: * Resin Open Source is free software; you can redistribute it and/or modify
0010: * it under the terms of the GNU General Public License as published by
0011: * the Free Software Foundation; either version 2 of the License, or
0012: * (at your option) any later version.
0013: *
0014: * Resin Open Source is distributed in the hope that it will be useful,
0015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
0017: * of NON-INFRINGEMENT. See the GNU General Public License for more
0018: * details.
0019: *
0020: * You should have received a copy of the GNU General Public License
0021: * along with Resin Open Source; if not, write to the
0022: *
0023: * Free Software Foundation, Inc.
0024: * 59 Temple Place, Suite 330
0025: * Boston, MA 02111-1307 USA
0026: *
0027: * @author Scott Ferguson
0028: */
0029:
0030: package com.caucho.webbeans.manager;
0031:
0032: import com.caucho.config.program.MethodComponentProgram;
0033: import com.caucho.config.*;
0034: import com.caucho.config.j2ee.*;
0035: import com.caucho.config.program.ConfigProgram;
0036: import com.caucho.loader.*;
0037: import com.caucho.loader.enhancer.*;
0038: import com.caucho.util.*;
0039: import com.caucho.vfs.*;
0040: import com.caucho.server.util.*;
0041: import com.caucho.webbeans.*;
0042: import com.caucho.webbeans.cfg.*;
0043: import com.caucho.webbeans.component.*;
0044: import com.caucho.webbeans.context.*;
0045: import com.caucho.webbeans.event.*;
0046:
0047: import java.io.*;
0048: import java.util.*;
0049: import java.util.logging.*;
0050: import java.lang.annotation.*;
0051: import java.lang.reflect.*;
0052:
0053: import javax.webbeans.*;
0054:
0055: /**
0056: * The web beans container for a given environment.
0057: */
0058: public class WebBeansContainer implements ScanListener,
0059: EnvironmentListener, Container, java.io.Serializable {
0060: private static final L10N L = new L10N(WebBeansContainer.class);
0061: private static final Logger log = Logger
0062: .getLogger(WebBeansContainer.class.getName());
0063:
0064: private static final String SCHEMA = "com/caucho/webbeans/cfg/webbeans.rnc";
0065:
0066: private static final EnvironmentLocal<WebBeansContainer> _localContainer = new EnvironmentLocal<WebBeansContainer>();
0067:
0068: private static final Annotation[] NULL_ANN = new Annotation[0];
0069:
0070: private WebBeansContainer _parent;
0071:
0072: private EnvironmentClassLoader _classLoader;
0073: private ClassLoader _tempClassLoader;
0074:
0075: private WbWebBeans _wbWebBeans;
0076:
0077: private HashMap<Path, WbWebBeans> _webBeansMap = new HashMap<Path, WbWebBeans>();
0078:
0079: private HashMap<Type, WebComponent> _componentMap = new HashMap<Type, WebComponent>();
0080:
0081: private HashMap<String, ComponentImpl> _namedComponentMap = new HashMap<String, ComponentImpl>();
0082:
0083: private HashMap<Path, WebBeansRootContext> _rootContextMap = new HashMap<Path, WebBeansRootContext>();
0084:
0085: private HashMap<Class, Context> _contextMap = new HashMap<Class, Context>();
0086:
0087: private HashMap<Class, ObserverMap> _observerMap = new HashMap<Class, ObserverMap>();
0088:
0089: private HashMap<Class, ArrayList<ObserverMap>> _observerListCache = new HashMap<Class, ArrayList<ObserverMap>>();
0090:
0091: private HashMap<Class, ClassComponent> _transientMap = new HashMap<Class, ClassComponent>();
0092:
0093: private HashMap<FactoryBinding, ComponentFactory> _objectFactoryMap = new HashMap<FactoryBinding, ComponentFactory>();
0094:
0095: private ArrayList<WebBeansRootContext> _pendingRootContextList = new ArrayList<WebBeansRootContext>();
0096:
0097: private ArrayList<WebBeansRootContext> _pendingBindList = new ArrayList<WebBeansRootContext>();
0098:
0099: private ArrayList<ComponentImpl> _pendingSingletonList = new ArrayList<ComponentImpl>();
0100:
0101: private HashMap<Class, InjectProgram> _injectMap = new HashMap<Class, InjectProgram>();
0102:
0103: private RuntimeException _configException;
0104:
0105: private WebBeansContainer(ClassLoader loader) {
0106: _classLoader = Environment.getEnvironmentClassLoader(loader);
0107:
0108: if (_classLoader != null) {
0109: _parent = WebBeansContainer
0110: .create(_classLoader.getParent());
0111: }
0112:
0113: _localContainer.set(this , _classLoader);
0114:
0115: if (_classLoader != null)
0116: _tempClassLoader = _classLoader.getNewTempClassLoader();
0117: else
0118: _tempClassLoader = new DynamicClassLoader(null);
0119:
0120: _wbWebBeans = new WbWebBeans(this , Vfs.lookup());
0121:
0122: _contextMap.put(RequestScoped.class, new RequestScope());
0123: _contextMap.put(SessionScoped.class, new SessionScope());
0124: _contextMap.put(ConversationScoped.class,
0125: new ConversationScope());
0126: _contextMap
0127: .put(ApplicationScoped.class, new ApplicationScope());
0128: _contextMap.put(Singleton.class, new SingletonScope());
0129:
0130: if (_classLoader != null)
0131: _classLoader.addScanListener(this );
0132:
0133: Environment.addEnvironmentListener(this , _classLoader);
0134: }
0135:
0136: /**
0137: * Returns the local container.
0138: */
0139: public static WebBeansContainer getCurrent() {
0140: return getCurrent(Thread.currentThread()
0141: .getContextClassLoader());
0142: }
0143:
0144: /**
0145: * Returns the current environment container.
0146: */
0147: public static WebBeansContainer getCurrent(ClassLoader loader) {
0148: synchronized (_localContainer) {
0149: return _localContainer.get(loader);
0150: }
0151: }
0152:
0153: /**
0154: * Returns the current active container.
0155: */
0156: public static WebBeansContainer create() {
0157: return create(Thread.currentThread().getContextClassLoader());
0158: }
0159:
0160: /**
0161: * Returns the current active container.
0162: */
0163: public static WebBeansContainer create(ClassLoader loader) {
0164: WebBeansContainer webBeans = null;
0165:
0166: synchronized (_localContainer) {
0167: webBeans = _localContainer.getLevel(loader);
0168:
0169: if (webBeans != null)
0170: return webBeans;
0171:
0172: webBeans = new WebBeansContainer(loader);
0173:
0174: _localContainer.set(webBeans);
0175: }
0176:
0177: return webBeans;
0178: }
0179:
0180: public WbWebBeans getWbWebBeans() {
0181: return _wbWebBeans;
0182: }
0183:
0184: public ClassLoader getClassLoader() {
0185: return _classLoader;
0186: }
0187:
0188: private void init() {
0189: try {
0190: update();
0191: } catch (RuntimeException e) {
0192: _configException = e;
0193:
0194: throw _configException;
0195: } catch (Exception e) {
0196: _configException = ConfigException.create(e);
0197:
0198: throw _configException;
0199: }
0200:
0201: Environment.addEnvironmentListener(this );
0202: }
0203:
0204: public WbComponentType createComponentType(Class cl) {
0205: return _wbWebBeans.createComponentType(cl);
0206: }
0207:
0208: public void addComponent(ComponentImpl comp) {
0209: addComponentByType(comp.getTargetType(), comp);
0210:
0211: String name = comp.getName();
0212:
0213: if (name != null && comp.getScope() != null)
0214: _namedComponentMap.put(name, comp);
0215:
0216: if (comp.getScope() instanceof SingletonScope) {
0217: _pendingSingletonList.add(comp);
0218: }
0219: }
0220:
0221: public void addComponentByName(String name, ComponentImpl comp) {
0222: _namedComponentMap.put(name, comp);
0223: }
0224:
0225: /**
0226: * Adds a component by the interface type
0227: *
0228: * @param type the interface type to expose the component
0229: * @param comp the component to register
0230: */
0231: public void addComponentByType(Type type, ComponentImpl comp) {
0232: if (type == null)
0233: return;
0234:
0235: if (log.isLoggable(Level.FINE)) {
0236: log.fine(comp.toDebugString() + " added to " + this );
0237: }
0238:
0239: addComponentRec(type, comp);
0240: }
0241:
0242: private void addComponentRec(Type type, ComponentImpl comp) {
0243: if (type == null || Object.class.equals(type))
0244: return;
0245:
0246: WebComponent webComponent = _componentMap.get(type);
0247:
0248: if (webComponent == null) {
0249: webComponent = new WebComponent(type);
0250: _componentMap.put(type, webComponent);
0251: }
0252:
0253: webComponent.addComponent(comp);
0254:
0255: Class cl;
0256:
0257: if (type instanceof Class)
0258: cl = (Class) type;
0259: else if (type instanceof ParameterizedType) {
0260: cl = (Class) ((ParameterizedType) type).getRawType();
0261: addComponentRec(cl, comp);
0262: return;
0263: } else {
0264: return;
0265: }
0266:
0267: addComponentRec(cl.getSuperclass(), comp);
0268:
0269: for (Class subClass : cl.getInterfaces()) {
0270: addComponentRec(subClass, comp);
0271: }
0272: }
0273:
0274: public void addSingleton(Object object) {
0275: SingletonComponent comp = new SingletonComponent(_wbWebBeans,
0276: object);
0277:
0278: comp.init();
0279:
0280: addComponent(comp);
0281: }
0282:
0283: public void addSingleton(Object object, String name) {
0284: SingletonComponent comp = new SingletonComponent(_wbWebBeans,
0285: object);
0286:
0287: comp.setName(name);
0288:
0289: WbBinding binding = new WbBinding();
0290: binding.setClass(Named.class);
0291: binding.addValue("value", name);
0292:
0293: ArrayList<WbBinding> bindingList = new ArrayList<WbBinding>();
0294: bindingList.add(binding);
0295:
0296: comp.setBindingList(bindingList);
0297:
0298: comp.init();
0299:
0300: addComponent(comp);
0301: }
0302:
0303: public void addSingleton(Object object, String name,
0304: Class componentType) {
0305: SingletonComponent comp = new SingletonComponent(_wbWebBeans,
0306: object);
0307:
0308: comp.setName(name);
0309: comp.setType(_wbWebBeans.createComponentType(componentType));
0310:
0311: WbBinding binding = new WbBinding();
0312: binding.setClass(Named.class);
0313: binding.addValue("value", name);
0314:
0315: ArrayList<WbBinding> bindingList = new ArrayList<WbBinding>();
0316: bindingList.add(binding);
0317:
0318: comp.setBindingList(bindingList);
0319:
0320: comp.init();
0321:
0322: addComponent(comp);
0323: }
0324:
0325: /**
0326: * Adds a singleton only to the name map
0327: *
0328: * @param object the singleton value
0329: * @param name the singleton's name
0330: */
0331: public void addSingletonByName(Object object, String name) {
0332: SingletonComponent comp = new SingletonComponent(_wbWebBeans,
0333: object);
0334:
0335: comp.setName(name);
0336: comp.init();
0337:
0338: _namedComponentMap.put(name, comp);
0339: }
0340:
0341: public void addEnabledInterceptor(Class cl) {
0342: _wbWebBeans.addEnabledInterceptor(cl);
0343: }
0344:
0345: public ArrayList<Class> findInterceptors(
0346: ArrayList<Annotation> annList) {
0347: ArrayList<Class> list = new ArrayList<Class>();
0348:
0349: ArrayList<WbInterceptor> interceptors = _wbWebBeans
0350: .findInterceptors(annList);
0351:
0352: // root interceptors take priority
0353: if (interceptors != null) {
0354: addInterceptorClasses(list, interceptors);
0355:
0356: return list;
0357: }
0358:
0359: for (WbWebBeans wbWebBeans : _webBeansMap.values()) {
0360: interceptors = wbWebBeans.findInterceptors(annList);
0361:
0362: if (interceptors != null)
0363: addInterceptorClasses(list, interceptors);
0364: }
0365:
0366: return list;
0367: }
0368:
0369: private void addInterceptorClasses(ArrayList<Class> classes,
0370: ArrayList<WbInterceptor> interceptors) {
0371: for (WbInterceptor interceptor : interceptors) {
0372: classes.add(interceptor.getInterceptorClass());
0373: }
0374: }
0375:
0376: /**
0377: * Returns the scope context corresponding to the scope annotation type.
0378: *
0379: * @param scope the scope annotation type identifying the scope
0380: */
0381: public ScopeContext getScopeContext(Class scope) {
0382: if (scope == null)
0383: throw new NullPointerException();
0384: else if (Dependent.class.equals(scope))
0385: return null;
0386:
0387: Context context = _contextMap.get(scope);
0388:
0389: if (context != null)
0390: return (ScopeContext) context;
0391: else
0392: throw new IllegalArgumentException(L.l(
0393: "'{0}' is an unknown scope.", scope.getName()));
0394: }
0395:
0396: /**
0397: * Creates an injection program for the given field
0398: */
0399: public void createProgram(ArrayList<ConfigProgram> injectList,
0400: Field field) throws ConfigException {
0401: ComponentImpl component;
0402:
0403: component = bind(location(field), field.getGenericType(), field
0404: .getAnnotations());
0405:
0406: if (component == null)
0407: throw injectError(field, L.l(
0408: "Can't find a component for '{0}'", field.getType()
0409: .getName()));
0410:
0411: component.createProgram(injectList, field);
0412: }
0413:
0414: /**
0415: * Creates an injection program for the given method
0416: */
0417: public void createProgram(ArrayList<ConfigProgram> injectList,
0418: Method method) throws ConfigException {
0419: if (method.isAnnotationPresent(Produces.class))
0420: throw error(method,
0421: "An injection method may not have the @Produces annotation.");
0422:
0423: // XXX: lazy binding
0424: try {
0425: Type[] paramTypes = method.getGenericParameterTypes();
0426: Annotation[][] paramAnn = method.getParameterAnnotations();
0427:
0428: ComponentImpl[] args = new ComponentImpl[paramTypes.length];
0429:
0430: for (int i = 0; i < args.length; i++) {
0431: args[i] = bind(location(method), paramTypes[i],
0432: paramAnn[i]);
0433:
0434: if (args[i] == null) {
0435: throw error(
0436: method,
0437: L
0438: .l(
0439: "Injection for type '{0}' of method parameter #{1} has no matching component.",
0440: getSimpleName(paramTypes[i]),
0441: i));
0442: }
0443: }
0444:
0445: injectList.add(new MethodComponentProgram(method, args));
0446: } catch (ConfigException e) {
0447: throw e;
0448: } catch (Exception e) {
0449: throw LineConfigException.create(method, e);
0450: }
0451: }
0452:
0453: /**
0454: * Returns the web beans component corresponding to a method
0455: * and a @Named value
0456: */
0457: public ComponentImpl bind(String location, Type type, String name) {
0458: ArrayList<Binding> bindingList = new ArrayList<Binding>();
0459:
0460: Binding binding = new Binding(Named.class);
0461: binding.put("value", name);
0462:
0463: bindingList.add(binding);
0464:
0465: return bindByBindings(location, type, bindingList);
0466: }
0467:
0468: /**
0469: * Returns the web beans component corresponding to the return type.
0470: */
0471: public ComponentImpl bind(String location, Type type) {
0472: ArrayList<Binding> bindingList = new ArrayList<Binding>();
0473:
0474: return bindByBindings(location, type, bindingList);
0475: }
0476:
0477: /**
0478: * Returns the web beans component corresponding to a method
0479: * parameter.
0480: */
0481: public ComponentImpl bind(String location, Type type,
0482: Annotation[] paramAnn) {
0483: ArrayList<Annotation> bindingList = new ArrayList<Annotation>();
0484:
0485: boolean isNew = false;
0486: for (Annotation ann : paramAnn) {
0487: if (ann instanceof New)
0488: isNew = true;
0489: else if (ann.annotationType().isAnnotationPresent(
0490: BindingType.class))
0491: bindingList.add(ann);
0492: }
0493:
0494: if (isNew)
0495: return bindNew(location, (Class) type);
0496: else
0497: return bind(location, type, bindingList);
0498: }
0499:
0500: /**
0501: * Binds for the @New expression
0502: */
0503: private ComponentImpl bindNew(String location, Class type) {
0504: ComponentImpl component = bind(location, type,
0505: new Annotation[0]);
0506:
0507: if (component == null) {
0508: ClassComponent newComp = new ClassComponent(_wbWebBeans);
0509: newComp.setInstanceClass(type);
0510: newComp.setTargetType(type);
0511: newComp.init();
0512:
0513: addComponent(newComp);
0514:
0515: component = newComp;
0516: }
0517:
0518: return component;
0519: }
0520:
0521: /**
0522: * Returns the web beans component with a given binding list.
0523: */
0524: public ComponentImpl bind(String location, Type type,
0525: ArrayList<Annotation> bindingList) {
0526: _wbWebBeans.init();
0527:
0528: WebComponent component = _componentMap.get(type);
0529:
0530: if (component != null) {
0531: ComponentImpl comp = component.bind(location, bindingList);
0532:
0533: if (log.isLoggable(Level.FINER))
0534: log.finer(this + " bind(" + getSimpleName(type)
0535: + ") returns " + comp);
0536:
0537: return comp;
0538: } else if (_parent != null) {
0539: return _parent.bind(location, type, bindingList);
0540: } else {
0541: return null;
0542: }
0543: }
0544:
0545: /**
0546: * Returns the web beans component with a given binding list.
0547: */
0548: public ComponentImpl bindByBindings(String location, Type type,
0549: ArrayList<Binding> bindingList) {
0550: _wbWebBeans.init();
0551:
0552: WebComponent component = _componentMap.get(type);
0553:
0554: if (component != null)
0555: return component
0556: .bindByBindings(location, type, bindingList);
0557: else if (_parent != null)
0558: return _parent.bindByBindings(location, type, bindingList);
0559: else
0560: return null;
0561: }
0562:
0563: /**
0564: * Finds a component by its component name.
0565: */
0566: public ComponentImpl findByName(String name) {
0567: ComponentImpl comp = _namedComponentMap.get(name);
0568: if (comp != null)
0569: return comp;
0570: else if (_parent != null)
0571: return _parent.findByName(name);
0572: else
0573: return null;
0574: }
0575:
0576: /**
0577: * Finds a component by its component name.
0578: */
0579: public Object getObjectByName(String name) {
0580: ComponentImpl comp = _namedComponentMap.get(name);
0581: if (comp != null)
0582: return comp.get();
0583: else if (_parent != null)
0584: return _parent.getObjectByName(name);
0585: else
0586: return null;
0587: }
0588:
0589: /**
0590: * Injects an object
0591: */
0592: public void injectObject(Object obj) {
0593: if (obj == null)
0594: return;
0595:
0596: Class cl = obj.getClass();
0597: InjectProgram program;
0598:
0599: synchronized (_injectMap) {
0600: program = _injectMap.get(cl);
0601:
0602: if (program == null) {
0603: program = InjectIntrospector.introspectProgram(cl);
0604: _injectMap.put(cl, program);
0605: }
0606: }
0607:
0608: program.configure(obj);
0609: }
0610:
0611: //
0612: // events
0613: //
0614:
0615: public void addObserver(ObserverImpl observer) {
0616: synchronized (_observerMap) {
0617: ObserverMap map = _observerMap.get(observer.getType());
0618:
0619: if (map == null) {
0620: map = new ObserverMap(observer.getType());
0621: _observerMap.put(observer.getType(), map);
0622: }
0623:
0624: map.addObserver(observer);
0625: }
0626: }
0627:
0628: //
0629: // javax.webbeans.Container
0630: //
0631:
0632: /**
0633: * Returns the component which matches the apiType and binding types
0634: */
0635: public <T> ComponentFactory<T> resolveByType(Class<T> apiType,
0636: Annotation... bindingTypes) {
0637: return bind("", apiType, bindingTypes);
0638: }
0639:
0640: public void addContext(Class<Annotation> scopeType, Context context) {
0641: _contextMap.put(scopeType, context);
0642: }
0643:
0644: public Context getContext(Class<Annotation> scopeType) {
0645: return _contextMap.get(scopeType);
0646: }
0647:
0648: /**
0649: * Sends the specified event to any observer instances in the scope
0650: */
0651: public void raiseEvent(Object event, Annotation... bindings) {
0652: if (_parent != null)
0653: _parent.raiseEvent(event, bindings);
0654:
0655: ArrayList<ObserverMap> observerList;
0656:
0657: synchronized (_observerListCache) {
0658: observerList = _observerListCache.get(event.getClass());
0659:
0660: if (observerList == null) {
0661: observerList = new ArrayList<ObserverMap>();
0662:
0663: fillObserverList(observerList, event.getClass());
0664: _observerListCache.put(event.getClass(), observerList);
0665: }
0666: }
0667:
0668: int size = observerList.size();
0669: for (int i = 0; i < size; i++) {
0670: observerList.get(i).raiseEvent(event, bindings);
0671: }
0672: }
0673:
0674: public Conversation createConversation() {
0675: return (Conversation) _contextMap.get(ConversationScoped.class);
0676: }
0677:
0678: private void fillObserverList(ArrayList<ObserverMap> list, Class cl) {
0679: if (cl == null)
0680: return;
0681:
0682: fillObserverList(list, cl.getSuperclass());
0683:
0684: for (Class iface : cl.getInterfaces())
0685: fillObserverList(list, iface);
0686:
0687: ObserverMap map = _observerMap.get(cl);
0688:
0689: if (map != null)
0690: list.add(map);
0691: }
0692:
0693: /**
0694: * Returns a ComponentFactory for a class, but does not register the
0695: * component with webbeans.
0696: */
0697: public <T> ComponentFactory<T> createTransient(Class<T> type) {
0698: synchronized (_transientMap) {
0699: ClassComponent comp = _transientMap.get(type);
0700:
0701: if (comp == null) {
0702: if (type.isInterface())
0703: throw new ConfigException(
0704: L
0705: .l(
0706: "'{0}' cannot be an interface. createTransient requires a concrete type.",
0707: type.getName()));
0708: else if (Modifier.isAbstract(type.getModifiers()))
0709: throw new ConfigException(
0710: L
0711: .l(
0712: "'{0}' cannot be an abstract. createTransient requires a concrete type.",
0713: type.getName()));
0714:
0715: comp = new ClassComponent(_wbWebBeans);
0716: comp.setInstanceClass(type);
0717:
0718: try {
0719: Constructor nullCtor = type
0720: .getConstructor(new Class[0]);
0721:
0722: if (nullCtor != null)
0723: comp.setConstructor(nullCtor);
0724: } catch (NoSuchMethodException e) {
0725: // if the type doesn't have a null-arg constructor
0726: }
0727:
0728: comp.init();
0729:
0730: _transientMap.put(type, comp);
0731:
0732: // XXX: QA
0733: comp.bind();
0734: }
0735:
0736: return comp;
0737: }
0738: }
0739:
0740: /**
0741: * Returns a new instance for a class, but does not register the
0742: * component with webbeans.
0743: */
0744: public <T> T getObject(Class<T> type, Annotation... ann) {
0745: return (T) createFactory(type, ann).get();
0746: }
0747:
0748: /**
0749: * Returns a new instance for a class, but does not register the
0750: * component with webbeans.
0751: */
0752: public <T> T getObject(Class<T> type, String name) {
0753: Annotation[] ann = new Annotation[] { Names.create(name) };
0754:
0755: return (T) createFactory(type, ann).get();
0756: }
0757:
0758: /**
0759: * Returns a new instance for a class, but does not register the
0760: * component with webbeans.
0761: */
0762: public <T> T createFactory(Class<T> type, String name) {
0763: Annotation[] ann = new Annotation[] { Names.create(name) };
0764:
0765: return (T) createFactory(type, ann);
0766: }
0767:
0768: /**
0769: * Returns a new instance for a class, but does not register the
0770: * component with webbeans.
0771: */
0772: public <T> T getEnvironmentObject(Class<T> type, Annotation... ann) {
0773: ComponentImpl comp = (ComponentImpl) createFactory(type, ann);
0774:
0775: Object value = comp.get();
0776:
0777: if (comp.isDestroyPresent())
0778: Environment.addClassLoaderListener(new ComponentClose(
0779: value, comp));
0780:
0781: return (T) value;
0782: }
0783:
0784: /**
0785: * Returns a new instance for a class, but does not register the
0786: * component with webbeans.
0787: */
0788: public ComponentFactory createFactory(Class type, Annotation... ann) {
0789: FactoryBinding binding = new FactoryBinding(type, ann);
0790:
0791: synchronized (_objectFactoryMap) {
0792: ComponentFactory factory = _objectFactoryMap.get(binding);
0793:
0794: if (factory != null)
0795: return factory;
0796:
0797: if (ann == null)
0798: ann = NULL_ANN;
0799:
0800: factory = resolveByType(type, ann);
0801:
0802: if (factory != null) {
0803: _objectFactoryMap.put(binding, factory);
0804:
0805: return factory;
0806: }
0807:
0808: if (type.isInterface())
0809: throw new ConfigException(
0810: L
0811: .l(
0812: "'{0}' cannot be an interface. createTransient requires a concrete type.",
0813: type.getName()));
0814: else if (Modifier.isAbstract(type.getModifiers()))
0815: throw new ConfigException(
0816: L
0817: .l(
0818: "'{0}' cannot be an abstract. createTransient requires a concrete type.",
0819: type.getName()));
0820:
0821: ClassComponent comp = new ClassComponent(_wbWebBeans);
0822: comp.setInstanceClass(type);
0823:
0824: try {
0825: Constructor nullCtor = type
0826: .getConstructor(new Class[0]);
0827:
0828: if (nullCtor != null)
0829: comp.setConstructor(nullCtor);
0830: } catch (NoSuchMethodException e) {
0831: // if the type doesn't have a null-arg constructor
0832: }
0833:
0834: comp.init();
0835:
0836: _objectFactoryMap.put(binding, comp);
0837:
0838: return comp;
0839: }
0840: }
0841:
0842: //
0843: // class loader updates
0844: //
0845:
0846: public void update() {
0847: Thread thread = Thread.currentThread();
0848: ClassLoader oldLoader = thread.getContextClassLoader();
0849:
0850: try {
0851: thread.setContextClassLoader(_classLoader);
0852:
0853: ArrayList<WebBeansRootContext> rootContextList = new ArrayList<WebBeansRootContext>(
0854: _pendingRootContextList);
0855:
0856: _pendingRootContextList.clear();
0857:
0858: for (WebBeansRootContext context : rootContextList) {
0859: Path root = context.getRoot();
0860:
0861: WbWebBeans webBeans = _webBeansMap.get(root);
0862:
0863: if (webBeans == null) {
0864: webBeans = new WbWebBeans(this , root);
0865: _webBeansMap.put(root, webBeans);
0866:
0867: Path path = root.lookup("META-INF/web-beans.xml");
0868:
0869: if (path.canRead()) {
0870: path.setUserPath(path.getURL());
0871:
0872: new Config().configure(webBeans, path, SCHEMA);
0873: }
0874: }
0875:
0876: for (String className : context.getClassNameList()) {
0877: try {
0878: Class cl = Class.forName(className, false,
0879: _classLoader);
0880:
0881: webBeans.addScannedClass(cl);
0882: } catch (ClassNotFoundException e) {
0883: log.log(Level.FINER, e.toString(), e);
0884: }
0885: }
0886:
0887: webBeans.update();
0888:
0889: webBeans.init();
0890:
0891: _pendingBindList.add(context);
0892: }
0893:
0894: _wbWebBeans.init();
0895: } catch (ConfigException e) {
0896: if (_configException == null)
0897: _configException = e;
0898:
0899: throw e;
0900: } finally {
0901: thread.setContextClassLoader(oldLoader);
0902: }
0903: }
0904:
0905: /**
0906: * Starts the bind phase
0907: */
0908: public void bind() {
0909: Thread thread = Thread.currentThread();
0910: ClassLoader oldLoader = thread.getContextClassLoader();
0911:
0912: try {
0913: thread.setContextClassLoader(_classLoader);
0914:
0915: ArrayList<WebBeansRootContext> rootContextList = new ArrayList<WebBeansRootContext>(
0916: _pendingBindList);
0917:
0918: _pendingBindList.clear();
0919:
0920: for (WebBeansRootContext context : rootContextList) {
0921: WbWebBeans webBeans = _webBeansMap.get(context
0922: .getRoot());
0923:
0924: webBeans.bind();
0925: }
0926:
0927: _wbWebBeans.bind();
0928: } catch (ConfigException e) {
0929: if (_configException == null)
0930: _configException = e;
0931:
0932: throw e;
0933: } finally {
0934: thread.setContextClassLoader(oldLoader);
0935: }
0936: }
0937:
0938: public Class loadClass(String className) {
0939: try {
0940: return Class.forName(className, false, _classLoader);
0941: } catch (ClassNotFoundException e) {
0942: throw new RuntimeException(e);
0943: }
0944: }
0945:
0946: /**
0947: * Handles the case the environment config phase
0948: */
0949: public void environmentConfig(EnvironmentClassLoader loader) {
0950: update();
0951: }
0952:
0953: /**
0954: * Handles the case where the environment is starting (after init).
0955: */
0956: public void environmentStart(EnvironmentClassLoader loader) {
0957: update();
0958: bind();
0959:
0960: _wbWebBeans.init();
0961:
0962: startSingletons();
0963: }
0964:
0965: /**
0966: * Initialize all the singletons
0967: */
0968: private void startSingletons() {
0969: ArrayList<ComponentImpl> singletons;
0970:
0971: synchronized (_pendingSingletonList) {
0972: if (_pendingSingletonList.size() == 0)
0973: return;
0974:
0975: singletons = new ArrayList<ComponentImpl>();
0976: singletons.addAll(_pendingSingletonList);
0977: _pendingSingletonList.clear();
0978: }
0979:
0980: for (ComponentImpl singleton : singletons)
0981: singleton.get();
0982: }
0983:
0984: /**
0985: * Handles the case where the environment is stopping
0986: */
0987: public void environmentStop(EnvironmentClassLoader loader) {
0988: _componentMap = null;
0989: _namedComponentMap = null;
0990: }
0991:
0992: public static ConfigException injectError(AccessibleObject prop,
0993: String msg) {
0994: String location = "";
0995:
0996: if (prop instanceof Field) {
0997: Field field = (Field) prop;
0998: String className = field.getDeclaringClass().getName();
0999:
1000: location = className + "." + field.getName() + ": ";
1001: } else if (prop instanceof Method) {
1002: Method method = (Method) prop;
1003: String className = method.getDeclaringClass().getName();
1004:
1005: location = className + "." + method.getName() + ": ";
1006: }
1007:
1008: return new ConfigException(location + msg);
1009: }
1010:
1011: public static String location(Field field) {
1012: return field.getDeclaringClass().getName() + "."
1013: + field.getName() + ": ";
1014: }
1015:
1016: public static String location(Method method) {
1017: return LineConfigException.loc(method);
1018: }
1019:
1020: public static ConfigException error(Method method, String msg) {
1021: return new ConfigException(location(method) + msg);
1022: }
1023:
1024: //
1025: // ScanListener
1026: //
1027:
1028: /**
1029: * Returns true if the root is a valid scannable root.
1030: */
1031: public boolean isRootScannable(Path root) {
1032: if (!root.lookup("META-INF/web-beans.xml").canRead())
1033: return false;
1034:
1035: WebBeansRootContext context = _rootContextMap.get(root);
1036:
1037: if (context == null) {
1038: context = new WebBeansRootContext(root);
1039: _rootContextMap.put(root, context);
1040: _pendingRootContextList.add(context);
1041: }
1042:
1043: if (context.isScanComplete())
1044: return false;
1045: else {
1046: if (log.isLoggable(Level.FINER))
1047: log.finer("WebBeans scanning " + root.getURL());
1048:
1049: context.setScanComplete(true);
1050: return true;
1051: }
1052: }
1053:
1054: public boolean isScanMatch(CharBuffer annotationName) {
1055: try {
1056: String className = annotationName.toString();
1057:
1058: Class cl = Class
1059: .forName(className, false, _tempClassLoader);
1060:
1061: return cl.isAnnotationPresent(ComponentType.class);
1062: } catch (ClassNotFoundException e) {
1063: }
1064:
1065: return false;
1066: }
1067:
1068: /**
1069: * Callback to note the class matches
1070: */
1071: public void classMatchEvent(EnvironmentClassLoader loader,
1072: Path root, String className) {
1073: WebBeansRootContext context = _rootContextMap.get(root);
1074:
1075: if (context == null) {
1076: context = new WebBeansRootContext(root);
1077: _rootContextMap.put(root, context);
1078: _pendingRootContextList.add(context);
1079: }
1080:
1081: context.addClassName(className);
1082: }
1083:
1084: /**
1085: * Serialization rewriting
1086: */
1087: public Object writeReplace() {
1088: return new WebBeansHandle(Container.class);
1089: }
1090:
1091: public String toString() {
1092: if (_classLoader != null && _classLoader.getId() != null)
1093: return "WebBeansContainer[" + _classLoader.getId() + "]";
1094: else
1095: return "WebBeansContainer[]";
1096: }
1097:
1098: static String getSimpleName(Type type) {
1099: if (type instanceof Class)
1100: return ((Class) type).getSimpleName();
1101: else
1102: return String.valueOf(type);
1103: }
1104:
1105: static class FactoryBinding {
1106: private static final Annotation[] NULL = new Annotation[0];
1107:
1108: private final Type _type;
1109: private final Annotation[] _ann;
1110:
1111: FactoryBinding(Type type, Annotation[] ann) {
1112: _type = type;
1113:
1114: if (ann != null)
1115: _ann = ann;
1116: else
1117: _ann = NULL;
1118: }
1119:
1120: @Override
1121: public int hashCode() {
1122: int hash = _type.hashCode();
1123:
1124: for (Annotation ann : _ann)
1125: hash = 65521 * hash + ann.hashCode();
1126:
1127: return hash;
1128: }
1129:
1130: @Override
1131: public boolean equals(Object obj) {
1132: if (!(obj instanceof FactoryBinding))
1133: return false;
1134:
1135: FactoryBinding binding = (FactoryBinding) obj;
1136:
1137: if (_type != binding._type)
1138: return false;
1139:
1140: if (_ann.length != binding._ann.length)
1141: return false;
1142:
1143: for (int i = 0; i < _ann.length; i++) {
1144: if (!_ann[i].equals(binding._ann[i]))
1145: return false;
1146: }
1147:
1148: return true;
1149: }
1150: }
1151: }
|