/* * ============================================================================ * GNU Lesser General Public License * ============================================================================ * * Beanlet - JSE Application Container. * Copyright (C) 2006 Leon van Zantvoort * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. * * Leon van Zantvoort * 243 Acalanes Drive #11 * Sunnyvale, CA 94086 * USA * * zantvoort@users.sourceforge.net * http://beanlet.org */ package org.beanlet; import java.io.BufferedReader; import java.io.InputStreamReader; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; import java.net.URL; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.Enumeration; import java.util.Map; import java.util.Set; /** * <p>Bootstrap class for the application container. An instance of the * {@code BeanletApplicationContext} can be obtained through the static * {@code instance} method. If the container isn't already running, the * first call to this method automatically starts and initializes the container. * </p> * * <p>During initialization, the container registers the beanlets listed in all * the {@code beanlet.xml} and {@code META-INF/beanlet.xml} files that are * available from the container's classpath.</p> * * <p>The beanlet application context providess access to all registered * beanlets. All methods of this class are thread-safe. They can be called at * all time. That includes during initialization of the application container. * </p> * * @author Leon van Zantvoort */ public abstract class BeanletApplicationContext { /** * The LazyHolder class is responsible for looking up the Beanlet container * implementation using Jar service discovery. Furthermore, this static * class provides a solution for the flawed double-checked locking idiom, */ private static class LazyHolder { static final BeanletApplicationContext ctx; static { try { try { Constructor constructor = AccessController.doPrivileged( new PrivilegedExceptionAction<Constructor>() { public Constructor run() throws Exception { String path = "META-INF/services/" + BeanletApplicationContext.class.getName(); // PERMISSION: java.lang.RuntimePermission getClassLoader ClassLoader loader = Thread.currentThread(). getContextClassLoader(); final Enumeration<URL> urls; if (loader == null) { urls = BeanletApplicationContext.class. getClassLoader().getResources(path); } else { urls = loader.getResources(path); } while (urls.hasMoreElements()) { URL url = urls.nextElement(); BufferedReader reader = new BufferedReader(new InputStreamReader( url.openStream())); try { String className; while ((className = reader.readLine()) != null) { final String name = className.trim(); if (!name.startsWith("#") && !name.startsWith(";") && !name.startsWith("//")) { final Class<?> cls; if (loader == null) { cls = Class.forName(name); } else { cls = Class.forName(name, true, loader); } int m = cls.getModifiers(); if (BeanletApplicationContext.class.isAssignableFrom(cls) && !Modifier.isAbstract(m) && !Modifier.isInterface(m)) { // PERMISSION: java.lang.RuntimePermission accessDeclaredMembers Constructor constructor = cls.getDeclaredConstructor(); // PERMISSION: java.lang.reflect.ReflectPermission suppressAccessChecks if (!Modifier.isPublic(constructor.getModifiers())) { constructor.setAccessible(true); } return constructor; } else { throw new ClassCastException(cls.getName()); } } } } finally { reader.close(); } } throw new BeanletApplicationException("No " + "BeanletApplicationContext implementation " + "found."); } }); ctx = (BeanletApplicationContext) constructor.newInstance(); } catch (PrivilegedActionException e) { throw e.getException(); } catch (InvocationTargetException e) { throw e.getTargetException(); } } catch (BeanletApplicationException e) { throw e; } catch (Error e) { throw e; } catch (Throwable t) { throw new BeanletApplicationException(t); } } } /** * Bootstraps the Beanlet container by obtaining a {@code BeanletApplicationContext} instance. * * @param args no arguments required. */ public static void main(String... args) { BeanletApplicationContext.instance(); } /** * <p>Returns a {@code BeanletApplicationContext} instance. If the container * isn't already running, the first call to this method automatically starts * and initializes the container.</p> * * <p>It is not specified whether multiple calls to this method results in * a single or multiple instances of the {@code BeanletApplicationContext}. * However, as the container only starts once, invoking this method multiple * times is valid and does not consume any additional resources.</p> * * @return a {@code BeanletApplicationContext} instance. * @throws BeanletApplicationException indicates an error during container * initialization. */ public static BeanletApplicationContext instance() throws BeanletApplicationException { try { try { return LazyHolder.ctx.resolveInstance(); } catch (ExceptionInInitializerError e) { try { throw e.getException(); } catch (BeanletApplicationException e2) { throw e2; } catch (Error e2) { throw e2; } catch (Throwable t) { throw new BeanletApplicationException(t); } } } catch (BeanletApplicationException e) { // Don't catch Errors and RuntimeExceptions. throw e; } } /** * Subclasses of this class can implement this method to control which * instance is returned to the caller of the static {@code instance} method. * The default implementation of this method simply returns {@code this}. * * @return a beanlet application context reference. * @throws BeanletApplicationException indicates an error during container * initialization. */ protected BeanletApplicationContext resolveInstance() throws BeanletApplicationException { return this; } /** * Undeploys all components and stops all internal container threads. * @throws BeanletApplicationContext indicates an error during container * shutdown. */ public abstract void shutdown() throws BeanletApplicationException; /** * Factory method for the specified {@code eventType}. * * @return a concrete implementation of the specified {@code eventType}. */ public abstract <T extends Event> T getEvent(Class<T> eventType); /** * <p>Returns a beanlet instance for the specified {@code beanletName}.</p> * * <p>If his beanlet instance implements the {@code FactoryBeanlet} * interface, the result of {@link FactoryBeanlet#getObject} is returned. * Prefix the {@code beanletName} with {@code "&"} to obtain an instance to * the {@code FactoryBeanlet} itself.</p> * * @param beanletName name of the beanlet. * @return a beanlet. * @throws BeanletNotFoundException if beanlet does not exist. * @throws BeanletCreationException if beanlet could not be created for any * reason. */ public abstract Object getBeanlet(String beanletName) throws BeanletNotFoundException, BeanletCreationException; /** * <p>Returns a beanlet instance for the specified {@code beanletName}. If * no beanlet exists for the specied {@code beanletName} a * {@code BeanletNotFoundException} is thrown. A * {@code BeanletNotOfRequiredTypeException} is thrown if the beanlet * instance cannot be assigned to the {@code requiredType}.</p> * * <p>If his beanlet instance implements the {@code FactoryBeanlet} * interface, the result of {@link FactoryBeanlet#getObject} is returned. * Prefix the {@code beanletName} with {@code "&"} to obtain an instance to * the {@code FactoryBeanlet} itself.</p> * * <p>The entries of the {@code info} argument can be used to wire members * of the beanlet instance. This does not apply to singleton and stateless * beanlets.</p> * * @param beanletName name of the beanlet. * @param requiredType type to mached the beanlet type. * @return a beanlet. * @throws BeanletNotFoundException if beanlet does not exist. * @throws BeanletCreationException if beanlet could not be created for * any reason. * @throws BeanletNotOfRequiredTypeException if beanlet cannot be assigned * to the {@code requiredType}. * @see Inject * @see Wiring */ public abstract <T> T getBeanlet(String beanletName, Class<T> requiredType) throws BeanletNotFoundException, BeanletCreationException, BeanletNotOfRequiredTypeException; /** * <p>Returns a beanlet for the specified {@code beanletName}.</p> * * <p>If this beanlet implements the {@code FactoryBeanlet} * interface, the result of {@link FactoryBeanlet#getObject} is returned. * Prefix the {@code beanletName} with {@code "&"} to obtain an instance to * the {@code FactoryBeanlet} itself.</p> * * <p>The entries of the {@code info} argument can be used to wire members * of the beanlet instance. This does not apply to static beanlets.</p> * * @param beanletName name of the beanlet. * @param info map that contains parameters that can be injected into * the beanlet instance. * @return a beanlet. * @throws BeanletNotFoundException if beanlet does not exist. * @throws BeanletCreationException if beanlet could not be * created for any reason. * @see Inject * @see Wiring */ public abstract Object getBeanlet(String beanletName, Map<String, ?> info) throws BeanletNotFoundException, BeanletCreationException; /** * <p>Returns a {@code BeanletFactory} for the specified {@code beanletName}. * If no beanlet exists for the specified {@code beanletName} a * {@code BeanletNotFoundException} is thrown. If the beanlet definition * type is either the same as, or a subclass of the specified * {@code requiredType}, a generified {@code BeanletFactory} is returned * with the {@code requiredType} as upper bound.</p> * * <p>This method ignores the {@code "&"} prefix.</p> * * <p>The entries of the {@code info} argument can be used to wire members * of the beanlet instance. This does not apply to static beanlets.</p> * * @param beanletName name of the beanlet. * @param requiredType type to mached the beanlet type. * @param info map that contains parameters that can be injected into * the beanlet instance. * @return a {@code BeanletFactory} for the specified {@code beanletName}. * @throws BeanletNotFoundException if beanlet does not exist. * @throws BeanletCreationException if beanlet could not be created for any * reason. * @throws BeanletNotOfRequiredTypeException if beanlet cannot be assigned * to the {@code requiredType}. * @see Inject * @see Wiring */ public abstract <T> T getBeanlet(String beanletName, Class<T> requiredType, Map<String, ?> info) throws BeanletNotFoundException, BeanletCreationException, BeanletNotOfRequiredTypeException; /** * Returns an immutable set of beanlet names of all registered beanlets. */ public abstract Set<String> getBeanletNames(); /** * Returns an immutable set of beanlet names of all registered beanlets, * which the beanlet instance type is the same as, or a subclass of the * specified {@code type}. * * @param type type to mached the beanlet type. */ public abstract Set<String> getBeanletNamesForType(Class<?> type); /** * Returns an immutable set of beanlet names of all registered beanlets, * which the beanlet instance type is the same as, or a subclass of the * specified {@code type}. Additionally, beanlet factories, which return * type match the specified {@code type} can be added as well, if * {@code factoryAware} is set to {@code true}. Set {@code usePrefix} to * {@code true} if these beanlet names must be prepended with "&". * * @param type type to mached the beanlet type, or factory * beanlet return type (optional). * @param factoryAware specify {@code true} to include factory beanlets, * which return type match the given type. * @param usePrefix specify {@code true} to prefix factory beanlet names. */ public abstract Set<String> getBeanletNamesForType(Class<?> type, boolean factoryAware, boolean usePrefix); /** * <p>Returns a {@code BeanletFactory} for the specified {@code beanletName}, * or throws a {@code BeanletNotFoundException} if beanlet does not exist.</p> * * <p>This method ignores the {@code "&"} prefix.</p> * * @param beanletName name of the beanlet. * @return a {@code BeanletFactory} for the specified {@code beanletName}. * @throws BeanletNotFoundException if beanlet does not exist. */ public abstract BeanletFactory<?> getBeanletFactory(String beanletName) throws BeanletNotFoundException; /** * <p>Returns a {@code BeanletFactory} for the specified {@code beanletName}. * If no beanlet exists for the specified {@code beanletName} a * {@code BeanletNotFoundException} is thrown. If the beanlet definition * type is either the same as, or a subclass of the specified * {@code requiredType}, a generified {@code BeanletFactory} is returned * with the {@code requiredType} as upper bound.</p> * * <p>This method ignores the {@code "&"} prefix.</p> * * @param beanletName name of the beanlet. * @param requiredType type to mached the beanlet type. * @return a {@code BeanletFactory} for the specified {@code beanletName}. * @throws BeanletNotFoundException if beanlet does not exist. * @throws BeanletNotOfRequiredTypeException if beanlet's type * is not the same as, or a subtype of {@code requiredType}. */ public abstract <T> BeanletFactory<? extends T> getBeanletFactory( String beanletName, Class<T> requiredType) throws BeanletNotFoundException, BeanletNotOfRequiredTypeException; /** * <p>Returns {@code true} if a beanlet exists for the specified * {@code beanletName}.</p> * * <p>This method ignores the {@code "&"} prefix.</p> * * @param beanletName name of the beanlet. * @return {@code true} if beanlet exists, or {@code false} otherwise. */ public abstract boolean exists(String beanletName); }