/* * Copyright 2003-2009 the original author or authors. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.jdon.container.pico; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; import org.picocontainer.ComponentMonitor; import org.picocontainer.Parameter; import org.picocontainer.PicoContainer; import org.picocontainer.PicoIntrospectionException; import org.picocontainer.PicoVisitor; import org.picocontainer.defaults.AbstractComponentAdapter; import org.picocontainer.defaults.AmbiguousComponentResolutionException; import org.picocontainer.defaults.AssignabilityRegistrationException; import org.picocontainer.defaults.ComponentParameter; import org.picocontainer.defaults.DefaultLifecycleStrategy; import org.picocontainer.defaults.DelegatingComponentMonitor; import org.picocontainer.defaults.LifecycleStrategy; import org.picocontainer.defaults.NotConcreteRegistrationException; import org.picocontainer.defaults.UnsatisfiableDependenciesException; public abstract class JdonInstantiatingComponentAdapter extends AbstractComponentAdapter implements LifecycleStrategy { /** * */ private static final long serialVersionUID = 1L; protected transient Guard verifyingGuard; protected static abstract class Guard extends JdonThreadLocalCyclicDependencyGuard { protected PicoContainer guardedContainer; protected void setArguments(PicoContainer container) { this.guardedContainer = container; } public void clearGuardedContainer() { if (guardedContainer != null) guardedContainer.stop(); guardedContainer = null; } } /** The parameters to use for initialization. */ protected transient Parameter[] parameters; /** Flag indicating instanciation of non-public classes. */ protected boolean allowNonPublicClasses; /** The strategy used to control the lifecycle */ protected LifecycleStrategy lifecycleStrategy; /** * Constructs a new ComponentAdapter for the given key and implementation. * * @param componentKey * the search key for this implementation * @param componentImplementation * the concrete implementation * @param parameters * the parameters to use for the initialization * @param allowNonPublicClasses * flag to allow instantiation of non-public classes * @param monitor * the component monitor used by this ComponentAdapter * @param lifecycleStrategy * the lifecycle strategy used by this ComponentAdapter * @throws AssignabilityRegistrationException * if the key is a type and the implementation cannot be * assigned to * @throws NotConcreteRegistrationException * if the implementation is not a concrete class * @throws NullPointerException * if one of the parameters is <code>null</code> */ protected JdonInstantiatingComponentAdapter(Object componentKey, Class componentImplementation, Parameter[] parameters, boolean allowNonPublicClasses, ComponentMonitor monitor, LifecycleStrategy lifecycleStrategy) { super(componentKey, componentImplementation, monitor); checkConcrete(); if (parameters != null) { for (int i = 0; i < parameters.length; i++) { if (parameters[i] == null) { throw new NullPointerException("Parameter " + i + " is null"); } } } this.parameters = parameters; this.allowNonPublicClasses = allowNonPublicClasses; this.lifecycleStrategy = lifecycleStrategy; } /** * Constructs a new ComponentAdapter for the given key and implementation. * * @param componentKey * the search key for this implementation * @param componentImplementation * the concrete implementation * @param parameters * the parameters to use for the initialization * @param allowNonPublicClasses * flag to allow instantiation of non-public classes * @param monitor * the component monitor used by this ComponentAdapter * @throws AssignabilityRegistrationException * if the key is a type and the implementation cannot be * assigned to * @throws NotConcreteRegistrationException * if the implementation is not a concrete class * @throws NullPointerException * if one of the parameters is <code>null</code> */ protected JdonInstantiatingComponentAdapter(Object componentKey, Class componentImplementation, Parameter[] parameters, boolean allowNonPublicClasses, ComponentMonitor monitor) { this(componentKey, componentImplementation, parameters, allowNonPublicClasses, monitor, new DefaultLifecycleStrategy(monitor)); } private void checkConcrete() throws NotConcreteRegistrationException { // Assert that the component class is concrete. boolean isAbstract = (getComponentImplementation().getModifiers() & Modifier.ABSTRACT) == Modifier.ABSTRACT; if (getComponentImplementation().isInterface() || isAbstract) { throw new NotConcreteRegistrationException(getComponentImplementation()); } } /** * Create default parameters for the given types. * * @param parameters * the parameter types * @return the array with the default parameters. */ protected Parameter[] createDefaultParameters(Class[] parameters) { Parameter[] componentParameters = new Parameter[parameters.length]; for (int i = 0; i < parameters.length; i++) { componentParameters[i] = ComponentParameter.DEFAULT; } return componentParameters; } public void verify(final PicoContainer container) throws PicoIntrospectionException { if (verifyingGuard == null) { verifyingGuard = new Guard() { public Object run() { final Constructor constructor = getGreediestSatisfiableConstructor(guardedContainer); final Class[] parameterTypes = constructor.getParameterTypes(); final Parameter[] currentParameters = parameters != null ? parameters : createDefaultParameters(parameterTypes); for (int i = 0; i < currentParameters.length; i++) { currentParameters[i].verify(container, JdonInstantiatingComponentAdapter.this, parameterTypes[i]); } return null; } }; } verifyingGuard.setArguments(container); verifyingGuard.observe(getComponentImplementation()); } public void accept(PicoVisitor visitor) { super.accept(visitor); if (parameters != null) { for (int i = 0; i < parameters.length; i++) { parameters[i].accept(visitor); } } } public void start(Object component) { lifecycleStrategy.start(component); } public void stop(Object component) { lifecycleStrategy.stop(component); } public void dispose(Object component) { lifecycleStrategy.dispose(component); } public boolean hasLifecycle(Class type) { return lifecycleStrategy.hasLifecycle(type); } /** * Instantiate an object with given parameters and respect the accessible * flag. * * @param constructor * the constructor to use * @param parameters * the parameters for the constructor * @return the new object. * @throws InstantiationException * @throws IllegalAccessException * @throws InvocationTargetException */ protected Object newInstance(Constructor constructor, Object[] parameters) throws InstantiationException, IllegalAccessException, InvocationTargetException { if (allowNonPublicClasses) { constructor.setAccessible(true); } return constructor.newInstance(parameters); } /** * Find and return the greediest satisfiable constructor. * * @param container * the PicoContainer to resolve dependencies. * @return the found constructor. * @throws PicoIntrospectionException * @throws UnsatisfiableDependenciesException * @throws AmbiguousComponentResolutionException * @throws AssignabilityRegistrationException * @throws NotConcreteRegistrationException */ protected abstract Constructor getGreediestSatisfiableConstructor(PicoContainer container) throws PicoIntrospectionException, UnsatisfiableDependenciesException, AmbiguousComponentResolutionException, AssignabilityRegistrationException, NotConcreteRegistrationException; protected JdonInstantiatingComponentAdapter(Object componentKey, Class componentImplementation, Parameter[] parameters, boolean allowNonPublicClasses) { this(componentKey, componentImplementation, parameters, allowNonPublicClasses, new DelegatingComponentMonitor()); } public void clear() { if (verifyingGuard != null) { verifyingGuard.clear(); } } }