/* * JBoss, Home of Professional Open Source * Copyright 2010, Red Hat Middleware LLC, and individual contributors * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * * 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 org.jboss.shrinkwrap.api; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.concurrent.ExecutorService; import java.util.logging.Level; import java.util.logging.Logger; /** * Mutable construction object for new instances of {@link Configuration}. Provides defaults for each property if not * specified (null) according to the following: * * <ul> * <li><code>executorService</code> - Stay null, none is required and ShrinkWrap will create its own and destroy it when * done as needed</li> * <li><code>extensionLoader</code> - A new instance of the service extension loader from shrinkwrap-impl</li> * </ul> * * Not thread-safe. When done altering properties here, a new configuration may be constructed by calling upon * {@link ConfigurationBuilder#build()}. * * @author <a href="mailto:andrew.rubinger@jboss.org">ALR</a> * @author <a href="mailto:ken@glxn.net">Ken Gullaksen</a> * @version $Revision: $ */ public class ConfigurationBuilder { // -------------------------------------------------------------------------------------|| // Class Members ----------------------------------------------------------------------|| // -------------------------------------------------------------------------------------|| /** * Logger */ private static final Logger log = Logger.getLogger(ConfigurationBuilder.class.getName()); /** * Implementation class name of the default {@link ExtensionLoader} to be used */ private static final String EXTENSION_LOADER_IMPL = "org.jboss.shrinkwrap.impl.base.ServiceExtensionLoader"; // -------------------------------------------------------------------------------------|| // Instance Members -------------------------------------------------------------------|| // -------------------------------------------------------------------------------------|| /** * Loader mapping archive types to the appropriate underlying implementation */ private ExtensionLoader extensionLoader; /** * {@link ExecutorService} used for all asynchronous operations */ private ExecutorService executorService; /** * {@link ClassLoader}s used for extension loading, adding resources, etc */ private Iterable<ClassLoader> classLoaders; // -------------------------------------------------------------------------------------|| // Constructor ------------------------------------------------------------------------|| // -------------------------------------------------------------------------------------|| /** * Creates a new builder initialized to defaults (null) values. Any properties not explicitly provided by the user * will be defaulted during {@link ConfigurationBuilder#build()}. */ public ConfigurationBuilder() { } // -------------------------------------------------------------------------------------|| // Functional Methods ----------------------------------------------------------------|| // -------------------------------------------------------------------------------------|| /** * @return the extensionLoader */ public ExtensionLoader getExtensionLoader() { return extensionLoader; } /** * @return the executorService */ public ExecutorService getExecutorService() { return executorService; } /** * @return */ public Iterable<ClassLoader> getClassLoaders() { return classLoaders; } /** * Sets the {@link ExtensionLoader} to be used, returning this instance * * @param extensionLoader * @return */ public ConfigurationBuilder extensionLoader(final ExtensionLoader extensionLoader) { this.extensionLoader = extensionLoader; return this; } /** * Sets the {@link ExecutorService} to be used, returning this instance * * @param executorService * @return */ public ConfigurationBuilder executorService(final ExecutorService executorService) { this.executorService = executorService; return this; } /** * Sets the {@link ClassLoader} used in resolving extension implementations by the {@link ExtensionLoader}; other * tasks requiring a CL by the {@link Archive} * * @param classLoaders * @return */ public ConfigurationBuilder classLoaders(final Iterable<ClassLoader> classLoaders) { this.classLoaders = classLoaders; return this; } /** * Builds a new {@link Configuration} using the properties contained in this builder. In the case a property has not * been specified, it will be defaulted according to the rules set forth in this {@link ConfigurationBuilder}'s * contract. * * @return */ public Configuration build() { // Make a new configuration and return it. return new Configuration(this); } // -------------------------------------------------------------------------------------|| // Internal Helper Methods -----------------------------------------------------------|| // -------------------------------------------------------------------------------------|| /** * Sets properties to their default values if they haven't been explicitly provided by the user. If no ClassLoaders * are specified, use the TCCL. */ void setDefaults() { // If no ClassLoaders are specified, use the TCCL // Ensure we default this BEFORE defaulting the extension loader, as // the loader needs a CL to be created if (this.getClassLoaders() == null) { final ClassLoader tccl = SecurityActions.getThreadContextClassLoader(); if (log.isLoggable(Level.FINER)) { log.finer("User has not defined an explicit " + ClassLoader.class.getSimpleName() + "; defaulting to the TCCL: " + tccl); } final Collection<ClassLoader> tcclCollection = new ArrayList<ClassLoader>(1); // Adjust for the bootstrap CL, which may be denoted as null in some JVM impls if (tccl != null) { tcclCollection.add(tccl); } else { tcclCollection.add(ClassLoader.getSystemClassLoader()); } this.classLoaders = tcclCollection; } // Adjust the CLs to be sure of no duplicate or null references (which may indicate // the bootstrap CL, so get to the system CL) final Collection<ClassLoader> adjustedCls = new HashSet<ClassLoader>(); for (ClassLoader cl : this.classLoaders) { // Adjust for null references if (cl == null) { cl = ClassLoader.getSystemClassLoader(); } // Add to the set, which will restrict duplicates adjustedCls.add(cl); } this.classLoaders = adjustedCls; // If no extension loader is present, create one if (getExtensionLoader() == null) { final ExtensionLoader loader = createDefaultExtensionLoader(); if (log.isLoggable(Level.FINER)) { log.finer("User has not defined an explicit " + ExtensionLoader.class.getSimpleName() + "; defaulting to " + loader); } this.extensionLoader(loader); } } /** * Obtains the default {@link ExtensionLoader} to be used if none is specified * * @return */ ExtensionLoader createDefaultExtensionLoader() { // First find the right Class/ClassLoader final Class<?> extensionLoaderImplClass; try { extensionLoaderImplClass = ClassLoaderSearchUtil.findClassFromClassLoaders(EXTENSION_LOADER_IMPL, getClassLoaders()); } catch (final ClassNotFoundException cnfe) { throw new IllegalStateException( "Could not find extension loader impl class in any of the configured ClassLoaders", cnfe); } // Return return SecurityActions.newInstance(extensionLoaderImplClass, new Class<?>[] { Iterable.class }, new Object[] { this.getClassLoaders() }, ExtensionLoader.class); } }