/*
* JBoss, Home of Professional Open Source.
* Copyright 2011, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This 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 software 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 software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.as.ee.component;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jboss.as.ee.logging.EeLogger;
import org.jboss.as.ee.component.interceptors.OrderedItemContainer;
import org.jboss.as.ee.concurrent.ConcurrentContext;
import org.jboss.as.naming.context.NamespaceContextSelector;
import org.jboss.as.server.deployment.reflect.ClassReflectionIndex;
import org.jboss.invocation.InterceptorFactory;
import org.jboss.modules.ModuleLoader;
import org.jboss.msc.service.Service;
/**
* The construction parameter set passed in to an abstract component.
* <p/>
* <h4>Interceptors</h4>
* The interceptor factories provided herein are assembled from the component's EE module class as well as the EE
* module classes of the declared interceptor classes for this component by way of a configurator.
*
* @author <a href="mailto:david.lloyd@redhat.com">David M. Lloyd</a>
*/
public class ComponentConfiguration {
private final ComponentDescription componentDescription;
// Core component config
private final ClassReflectionIndex classIndex;
private final ModuleLoader moduleLoader;
private final ClassLoader moduleClassLoader;
private final ConcurrentContext concurrentContext;
private ComponentCreateServiceFactory componentCreateServiceFactory = ComponentCreateServiceFactory.BASIC;
// Interceptor config
private final OrderedItemContainer<List<InterceptorFactory>> aroundConstructInterceptors = new OrderedItemContainer<>();
private final OrderedItemContainer<List<InterceptorFactory>> postConstructInterceptors = new OrderedItemContainer<>();
private final OrderedItemContainer<List<InterceptorFactory>> preDestroyInterceptors = new OrderedItemContainer<>();
private final OrderedItemContainer<List<InterceptorFactory>> prePassivateInterceptors = new OrderedItemContainer<>();
private final OrderedItemContainer<List<InterceptorFactory>> postActivateInterceptors = new OrderedItemContainer<>();
private final Map<Method, OrderedItemContainer<List<InterceptorFactory>>> componentInterceptors = new IdentityHashMap<>();
//TODO: move this into an EJB specific configuration
private final Map<Method, OrderedItemContainer<InterceptorFactory>> timeoutInterceptors = new IdentityHashMap<>();
// Component instance management
private ComponentFactory instanceFactory;
private final List<DependencyConfigurator<? extends Service<Component>>> createDependencies = new ArrayList<DependencyConfigurator<? extends Service<Component>>>();
private final List<DependencyConfigurator<ComponentStartService>> startDependencies = new ArrayList<DependencyConfigurator<ComponentStartService>>();
// Views
private final List<ViewConfiguration> views = new ArrayList<ViewConfiguration>();
private InterceptorFactory namespaceContextInterceptorFactory;
private NamespaceContextSelector namespaceContextSelector;
private final Set<Object> interceptorContextKeys = new HashSet<Object>();
/**
* Contains a set of all lifecycle methods defined by the bean
*/
private final Set<Method> lifecycleMethods = new HashSet<>();
public ComponentConfiguration(final ComponentDescription componentDescription, final ClassReflectionIndex classIndex, final ClassLoader moduleClassLoader, final ModuleLoader moduleLoader) {
this.componentDescription = componentDescription;
this.classIndex = classIndex;
this.moduleClassLoader = moduleClassLoader;
this.moduleLoader = moduleLoader;
this.concurrentContext = new ConcurrentContext();
}
/**
* Get the component description.
*
* @return the component description
*/
public ComponentDescription getComponentDescription() {
return componentDescription;
}
/**
* Get the component class.
*
* @return the component class
*/
public Class<?> getComponentClass() {
return classIndex.getIndexedClass();
}
/**
* Get the component name.
*
* @return the component name
*/
public String getComponentName() {
return componentDescription.getComponentName();
}
/**
* Get the set of currently known component methods. This is an identity set.
*
* @return the set of methods
*/
public Set<Method> getDefinedComponentMethods() {
return classIndex.getClassMethods();
}
/**
* Gets the interceptor list for a given method. This should not be called until
* all interceptors have been added.
*
* @param method the component method
* @return the deque
*/
public List<InterceptorFactory> getComponentInterceptors(Method method) {
Map<Method, OrderedItemContainer<List<InterceptorFactory>>> map = componentInterceptors;
OrderedItemContainer<List<InterceptorFactory>> interceptors = map.get(method);
if (interceptors == null) {
return Collections.emptyList();
}
List<List<InterceptorFactory>> sortedItems = interceptors.getSortedItems();
List<InterceptorFactory> ret = new ArrayList<>();
for(List<InterceptorFactory> item : sortedItems) {
ret.addAll(item);
}
return ret;
}
/**
* Gets the around timeout interceptor list for a given method. This should not be called until
* all interceptors have been added.
*
* @param method the component method
* @return the deque
*/
public List<InterceptorFactory> getAroundTimeoutInterceptors(Method method) {
Map<Method, OrderedItemContainer<InterceptorFactory>> map = timeoutInterceptors;
OrderedItemContainer<InterceptorFactory> interceptors = map.get(method);
if (interceptors == null) {
return Collections.emptyList();
}
return interceptors.getSortedItems();
}
/**
* Adds an interceptor factory to every method on the component.
*
* @param factory The interceptor factory to add
* @param priority The interceptors relative order
* @param publicOnly If true then then interceptor is only added to public methods
*/
public void addComponentInterceptor(InterceptorFactory factory, int priority, boolean publicOnly) {
addComponentInterceptors(Collections.singletonList(factory), priority, publicOnly);
}
/**
* Adds an interceptor factory to every method on the component.
*
* @param factory The interceptor factory to add
* @param priority The interceptors relative order
* @param publicOnly If true then then interceptor is only added to public methods
*/
public void addComponentInterceptors(List<InterceptorFactory> factory, int priority, boolean publicOnly) {
for (Method method : (Iterable<Method>)classIndex.getClassMethods()) {
if (publicOnly && !Modifier.isPublic(method.getModifiers())) {
continue;
}
OrderedItemContainer<List<InterceptorFactory>> interceptors = componentInterceptors.get(method);
if (interceptors == null) {
componentInterceptors.put(method, interceptors = new OrderedItemContainer<List<InterceptorFactory>>());
}
interceptors.add(factory, priority);
}
}
/**
* Adds an interceptor factory to a given method. The method parameter *must* be retrived from either the
* {@link org.jboss.as.server.deployment.reflect.DeploymentReflectionIndex} or from {@link #getDefinedComponentMethods()},
* as the methods are stored in an identity hash map
*
* @param method The method to add the interceptor to
* @param factory The interceptor factory to add
* @param priority The interceptors relative order
*/
public void addComponentInterceptor(Method method, InterceptorFactory factory, int priority) {
addComponentInterceptors(method, Collections.singletonList(factory), priority);
}
/**
* Adds an interceptor factory to a given method. The method parameter *must* be retrived from either the
* {@link org.jboss.as.server.deployment.reflect.DeploymentReflectionIndex} or from {@link #getDefinedComponentMethods()},
* as the methods are stored in an identity hash map
*
* @param method The method to add the interceptor to
* @param factory The interceptor factory to add
* @param priority The interceptors relative order
*/
public void addComponentInterceptors(Method method, List<InterceptorFactory> factory, int priority) {
OrderedItemContainer<List<InterceptorFactory>> interceptors = componentInterceptors.get(method);
if (interceptors == null) {
componentInterceptors.put(method, interceptors = new OrderedItemContainer<List<InterceptorFactory>>());
}
interceptors.add(factory, priority);
}
/**
* Adds a timeout interceptor factory to every method on the component.
*
* @param factory The interceptor factory to add
* @param priority The interceptors relative order
*/
public void addTimeoutViewInterceptor(InterceptorFactory factory, int priority) {
for (Method method : (Iterable<Method>)classIndex.getClassMethods()) {
OrderedItemContainer<InterceptorFactory> interceptors = timeoutInterceptors.get(method);
if (interceptors == null) {
timeoutInterceptors.put(method, interceptors = new OrderedItemContainer<InterceptorFactory>());
}
interceptors.add(factory, priority);
}
}
/**
* Adds a timeout interceptor factory to every method on the component.
*
* @param method The method to add it to
* @param factory The interceptor factory to add
* @param priority The interceptors relative order
*/
public void addTimeoutViewInterceptor(final Method method, InterceptorFactory factory, int priority) {
OrderedItemContainer<InterceptorFactory> interceptors = timeoutInterceptors.get(method);
if (interceptors == null) {
timeoutInterceptors.put(method, interceptors = new OrderedItemContainer<InterceptorFactory>());
}
interceptors.add(factory, priority);
}
/**
* Get the create dependencies list.
*
* @return the create dependencies list
*/
public List<DependencyConfigurator<? extends Service<Component>>> getCreateDependencies() {
return createDependencies;
}
/**
* Get the start dependencies list.
*
* @return the start dependencies list
*/
public List<DependencyConfigurator<ComponentStartService>> getStartDependencies() {
return startDependencies;
}
/**
* Get the list of views for this component.
*
* @return the list of views
*/
public List<ViewConfiguration> getViews() {
return views;
}
/**
* Get the around-construct interceptors.
* <p/>
* This method should only be called after all interceptors have been added
*
* @return the sorted interceptors
*/
public List<InterceptorFactory> getAroundConstructInterceptors() {
List<List<InterceptorFactory>> sortedItems = aroundConstructInterceptors.getSortedItems();
List<InterceptorFactory> interceptorFactories = new ArrayList<>();
for(List<InterceptorFactory> i : sortedItems) {
interceptorFactories.addAll(i);
}
return interceptorFactories;
}
/**
* Adds an around-construct interceptor
*
* @param factories The interceptors to add
* @param priority The priority
*/
public void addAroundConstructInterceptors(List<InterceptorFactory> factories, int priority) {
aroundConstructInterceptors.add(factories, priority);
}
/**
* Adds an around-construct interceptor
*
* @param interceptorFactory The interceptor to add
* @param priority The priority
*/
public void addAroundConstructInterceptor(InterceptorFactory interceptorFactory, int priority) {
aroundConstructInterceptors.add(Collections.singletonList(interceptorFactory), priority);
}
/**
* Get the post-construct interceptors.
* <p/>
* This method should only be called after all interceptors have been added
*
* @return the sorted interceptors
*/
public List<InterceptorFactory> getPostConstructInterceptors() {
List<List<InterceptorFactory>> sortedItems = postConstructInterceptors.getSortedItems();
List<InterceptorFactory> interceptorFactories = new ArrayList<>();
for(List<InterceptorFactory> i : sortedItems) {
interceptorFactories.addAll(i);
}
return interceptorFactories;
}
/**
* Adds a post construct interceptor
*
* @param interceptorFactory The interceptor to add
* @param priority The priority
*/
public void addPostConstructInterceptors(List<InterceptorFactory> interceptorFactory, int priority) {
postConstructInterceptors.add(interceptorFactory, priority);
}
/**
* Adds a post construct interceptor
*
* @param interceptorFactory The interceptor to add
* @param priority The priority
*/
public void addPostConstructInterceptor(InterceptorFactory interceptorFactory, int priority) {
postConstructInterceptors.add(Collections.singletonList(interceptorFactory), priority);
}
/**
* Get the pre-destroy interceptors.
* <p/>
* This method should only be called after all interceptors have been added
*
* @return the sorted interceptor
*/
public List<InterceptorFactory> getPreDestroyInterceptors() {
List<List<InterceptorFactory>> sortedItems = preDestroyInterceptors.getSortedItems();
List<InterceptorFactory> interceptorFactories = new ArrayList<>();
for(List<InterceptorFactory> i : sortedItems) {
interceptorFactories.addAll(i);
}
return interceptorFactories;
}
/**
* Adds a pre destroy interceptor
*
* @param factories The interceptor factory to add
* @param priority The factories priority
*/
public void addPreDestroyInterceptors(List<InterceptorFactory> factories, int priority) {
preDestroyInterceptors.add(factories, priority);
}
/**
* Adds a pre destroy interceptor
*
* @param interceptorFactory The interceptor factory to add
* @param priority The factories priority
*/
public void addPreDestroyInterceptor(InterceptorFactory interceptorFactory, int priority) {
preDestroyInterceptors.add(Collections.singletonList(interceptorFactory), priority);
}
/**
* Get the pre-passivate interceptors.
* <p/>
* This method should only be called after all interceptors have been added
*
* @return the sorted interceptors
*/
public List<InterceptorFactory> getPrePassivateInterceptors() {
List<List<InterceptorFactory>> sortedItems = prePassivateInterceptors.getSortedItems();
List<InterceptorFactory> interceptorFactories = new ArrayList<>();
for(List<InterceptorFactory> i : sortedItems) {
interceptorFactories.addAll(i);
}
return interceptorFactories;
}
/**
* Adds a pre passivate interceptor
*
* @param factories The interceptor to add
* @param priority The priority
*/
public void addPrePassivateInterceptors(List<InterceptorFactory> factories, int priority) {
prePassivateInterceptors.add(factories, priority);
}
/**
* Adds a pre passivate interceptor
*
* @param interceptorFactory The interceptor to add
* @param priority The priority
*/
public void addPrePassivateInterceptor(InterceptorFactory interceptorFactory, int priority) {
prePassivateInterceptors.add(Collections.singletonList(interceptorFactory), priority);
}
/**
* Get the post-activate interceptors.
* <p/>
* This method should only be called after all interceptors have been added
*
* @return the sorted interceptors
*/
public List<InterceptorFactory> getPostActivateInterceptors() {
List<List<InterceptorFactory>> sortedItems = postActivateInterceptors.getSortedItems();
List<InterceptorFactory> interceptorFactories = new ArrayList<>();
for(List<InterceptorFactory> i : sortedItems) {
interceptorFactories.addAll(i);
}
return interceptorFactories;
}
/**
* Adds a post activate interceptor
*
* @param interceptorFactory The interceptor to add
* @param priority The priority
*/
public void addPostActivateInterceptors(List<InterceptorFactory> interceptorFactory, int priority) {
postActivateInterceptors.add(interceptorFactory, priority);
}
/**
* Adds a post activate interceptor
*
* @param interceptorFactory The interceptor to add
* @param priority The priority
*/
public void addPostActivateInterceptor(InterceptorFactory interceptorFactory, int priority) {
postActivateInterceptors.add(Collections.singletonList(interceptorFactory), priority);
}
/**
* Get the application name.
*
* @return the application name
*/
public String getApplicationName() {
return componentDescription.getApplicationName();
}
/**
* Get the module name.
*
* @return the module name
*/
public String getModuleName() {
return componentDescription.getModuleName();
}
/**
* Get the instance factory for this component.
*
* @return the instance factory
*/
public ComponentFactory getInstanceFactory() {
return instanceFactory;
}
/**
* Set the instance factory for this component.
*
* @param instanceFactory the instance factory
*/
public void setInstanceFactory(final ComponentFactory instanceFactory) {
this.instanceFactory = instanceFactory;
}
public ClassReflectionIndex getClassIndex() {
return classIndex;
}
/**
* Get the component create service factory for this component.
*
* @return the component create service factory
*/
public ComponentCreateServiceFactory getComponentCreateServiceFactory() {
return componentCreateServiceFactory;
}
/**
* Set the component create service factory for this component.
*
* @param componentCreateServiceFactory the component create service factory
*/
public void setComponentCreateServiceFactory(final ComponentCreateServiceFactory componentCreateServiceFactory) {
if (componentCreateServiceFactory == null) {
throw EeLogger.ROOT_LOGGER.nullVar("componentCreateServiceFactory");
}
this.componentCreateServiceFactory = componentCreateServiceFactory;
}
public String toString() {
return getClass().getName() + "[name=" + componentDescription.getComponentName() + " class=" + componentDescription.getComponentClassName() + "]";
}
public InterceptorFactory getNamespaceContextInterceptorFactory() {
return namespaceContextInterceptorFactory;
}
public void setNamespaceContextInterceptorFactory(InterceptorFactory interceptorFactory) {
this.namespaceContextInterceptorFactory = interceptorFactory;
}
public ClassLoader getModuleClassLoader() {
return moduleClassLoader;
}
public ModuleLoader getModuleLoader() {
return moduleLoader;
}
/**
* @return The components namespace context selector, if any
*/
public NamespaceContextSelector getNamespaceContextSelector() {
return namespaceContextSelector;
}
public void setNamespaceContextSelector(final NamespaceContextSelector namespaceContextSelector) {
this.namespaceContextSelector = namespaceContextSelector;
}
public Set<Object> getInterceptorContextKeys() {
return interceptorContextKeys;
}
public ConcurrentContext getConcurrentContext() {
return concurrentContext;
}
/**
* Adds a lifecycle method to the lifecycle methods set
*
* @param method The lifecycle method
*/
public void addLifecycleMethod(Method method) {
lifecycleMethods.add(method);
}
/**
* Returns a set of all lifecycle methods defined on the bean
*
* @return All lifecycle methods defined on the component class and its superclasses
*/
public Set<Method> getLifecycleMethods() {
return Collections.unmodifiableSet(lifecycleMethods);
}
}