com.sun.faces.config.ConfigManager Maven / Gradle / Ivy
Show all versions of jsf-impl Show documentation
/* * $Id: ConfigManager.java,v 1.15.4.14 2009/12/07 23:08:47 rlubke Exp $ */ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development * and Distribution License("CDDL") (collectively, the "License"). You * may not use this file except in compliance with the License. You can obtain * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific * language governing permissions and limitations under the License. * * When distributing the software, include this License Header Notice in each * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt. * Sun designates this particular file as subject to the "Classpath" exception * as provided by Sun in the GPL Version 2 section of the License file that * accompanied this code. If applicable, add the following below the License * Header, with the fields enclosed by brackets [] replaced by your own * identifying information: "Portions Copyrighted [year] * [name of copyright owner]" * * Contributor(s): * * If you wish your version of this file to be governed by only the CDDL or * only the GPL Version 2, indicate your decision by adding "[Contributor] * elects to include this software in this distribution under the [CDDL or GPL * Version 2] license." If you don't indicate a single choice of license, a * recipient has the option to distribute your version of this file under * either the CDDL, the GPL Version 2 or to extend the choice of license to * its licensees as provided above. However, if you add GPL Version 2 code * and therefore, elected the GPL Version 2 license, then the option applies * only if the new code is made subject to such option by the copyright * holder. */ package com.sun.faces.config; import static com.sun.faces.config.WebConfiguration.BooleanWebContextInitParameter.EnableThreading; import static com.sun.faces.config.WebConfiguration.BooleanWebContextInitParameter.ValidateFacesConfigFiles; import com.sun.faces.config.configprovider.ConfigurationResourceProvider; import com.sun.faces.config.configprovider.MetaInfResourceProvider; import com.sun.faces.config.configprovider.RIConfigResourceProvider; import com.sun.faces.config.configprovider.WebResourceProvider; import com.sun.faces.config.processor.ApplicationConfigProcessor; import com.sun.faces.config.processor.ComponentConfigProcessor; import com.sun.faces.config.processor.ConfigProcessor; import com.sun.faces.config.processor.ConverterConfigProcessor; import com.sun.faces.config.processor.FactoryConfigProcessor; import com.sun.faces.config.processor.LifecycleConfigProcessor; import com.sun.faces.config.processor.ManagedBeanConfigProcessor; import com.sun.faces.config.processor.NavigationConfigProcessor; import com.sun.faces.config.processor.RenderKitConfigProcessor; import com.sun.faces.config.processor.ValidatorConfigProcessor; import com.sun.faces.util.FacesLogger; import com.sun.faces.util.Timer; import org.w3c.dom.Document; import org.xml.sax.InputSource; import javax.faces.FacesException; import javax.faces.FactoryFinder; import javax.servlet.ServletContext; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamSource; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.net.URLConnection; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Collection; import java.util.concurrent.Callable; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.FutureTask; import java.util.logging.Level; import java.util.logging.Logger; /** *
fase */ public boolean hasBeenInitialized(ServletContext sc) { return (initializedContexts.contains(sc)); } // --------------------------------------------------------- Private Methods /** ** This class manages the initialization of each web application that uses * JSF. *
*/ public class ConfigManager { private static final Logger LOGGER = FacesLogger.CONFIG.getLogger(); /** ** The list of resource providers. By default, this contains a provider * for the RI, and two providers to satisfy the requirements of the * specification. *
*/ private static final ListRESOURCE_PROVIDERS; /** * * The
*/ private static final int NUMBER_OF_TASK_THREADS = 5; /** *ConfigManager
will multithread the calls to the *ConfigurationResourceProvider
s as well as any calls * to parse a resources into a DOM. By default, we'll use only 5 threads * per web application. ** There is only once instance of
ConfigManager
. **/ private static final ConfigManager CONFIG_MANAGER = new ConfigManager(); /** *
* Contains each
*/ @SuppressWarnings({"CollectionWithoutInitialCapacity"}) private ListServletContext
that we've initialized. * TheServletContext
will be removed when the application * is destroyed. *initializedContexts = new CopyOnWriteArrayList (); /** * * The chain of {@link ConfigProcessor}, used to initialize JSF. *
*/ private static final ConfigProcessor CONFIG_PROCESSOR_CHAIN; private static final String XSL = "/com/sun/faces/jsf1_0-1_1toSchema.xsl"; static { Listl = new ArrayList (3); l.add(new RIConfigResourceProvider()); l.add(new MetaInfResourceProvider()); l.add(new WebResourceProvider()); RESOURCE_PROVIDERS = Collections.unmodifiableList(l); ConfigProcessor[] configProcessors = { new FactoryConfigProcessor(), new LifecycleConfigProcessor(), new ApplicationConfigProcessor(), new ComponentConfigProcessor(), new ConverterConfigProcessor(), new ValidatorConfigProcessor(), new ManagedBeanConfigProcessor(), new RenderKitConfigProcessor(), new NavigationConfigProcessor() }; for (int i = 0; i < configProcessors.length; i++) { ConfigProcessor p = configProcessors[i]; if ((i + 1) < configProcessors.length) { p.setNext(configProcessors[i + 1]); } } CONFIG_PROCESSOR_CHAIN = configProcessors[0]; } // ---------------------------------------------------------- Public Methods /** * @return a ConfigManager
instance */ public static ConfigManager getInstance() { return CONFIG_MANAGER; } /** ** This method bootstraps JSF based on the parsed configuration resources. *
* * @param sc theServletContext
for the application that * requires initialization */ public void initialize(ServletContext sc) { if (!hasBeenInitialized(sc)) { initializedContexts.add(sc); try { CONFIG_PROCESSOR_CHAIN.process(sc, getConfigDocuments(sc)); } catch (Exception e) { // clear out any configured factories releaseFactories(); if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, "Unsanitized stacktrace from failed start...", e); } Throwable t = unwind(e); throw new ConfigurationException("CONFIGURATION FAILED! " + t.getMessage(), t); } } } /** ** This method will remove any information about the application. *
* @param sc theServletContext
for the application that * needs to be removed */ public void destory(ServletContext sc) { releaseFactories(); initializedContexts.remove(sc); } /** * @param sc theServletContext
for the application in question * @returntrue
if this application has already been initialized, * otherwise returns* Obtains an array of
* * @param sc theDocument
s to be processed * by {@link ConfigManager#CONFIG_PROCESSOR_CHAIN}. *ServletContext
for the application to be * processed * @return an array ofDocument
s */ private static Document[] getConfigDocuments(ServletContext sc) { ExecutorService executor = null; if (useThreads(sc)) { executor = Executors.newFixedThreadPool(NUMBER_OF_TASK_THREADS); } List>> urlTasks = new ArrayList >>(RESOURCE_PROVIDERS.size()); for (ConfigurationResourceProvider p : RESOURCE_PROVIDERS) { FutureTask > t = new FutureTask >(new URLTask(p, sc)); urlTasks.add(t); if (executor != null) { executor.execute(t); } else { t.run(); } } List > docTasks = new ArrayList >(RESOURCE_PROVIDERS.size() << 1); boolean validating = WebConfiguration.getInstance(sc) .isOptionEnabled(ValidateFacesConfigFiles); for (FutureTask > t : urlTasks) { try { Collection l = t.get(); for (URL u : l) { FutureTask d = new FutureTask (new ParseTask(validating, u)); docTasks.add(d); if (executor != null) { executor.execute(d); } else { d.run(); } } } catch (InterruptedException ignored) { } catch (Exception e) { throw new ConfigurationException(e); } } List docs = new ArrayList (docTasks.size()); for (FutureTask t : docTasks) { try { docs.add(t.get()); } catch (ExecutionException e) { throw new ConfigurationException(e); } catch (InterruptedException ignored) { } } if (executor != null) { executor.shutdown(); } return docs.toArray(new Document[docs.size()]); } private static boolean useThreads(ServletContext ctx) { WebConfiguration config = WebConfiguration.getInstance(ctx); return config.isOptionEnabled(EnableThreading); } /** * @param throwable Throwable * @return the root cause of this error */ private Throwable unwind(Throwable throwable) { Throwable t = null; if (throwable != null) { t = unwind(throwable.getCause()); if (t == null) { t = throwable; } } return t; } /** * Calls through to {@link javax.faces.FactoryFinder#releaseFactories()} * ignoring any exceptions. */ private void releaseFactories() { try { FactoryFinder.releaseFactories(); } catch (FacesException ignored) { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, "Exception thrown from FactoryFinder.releaseFactories()", ignored); } } } // ----------------------------------------------------------- Inner Classes /** * * This
*/ private static class ParseTask implements CallableCallable
will be used by {@link ConfigManager#getConfigDocuments(javax.servlet.ServletContext)}. * It represents a single configuration resource to be parsed into a DOM. *{ private static final String FACES_SCHEMA_DEFAULT_NS = "http://java.sun.com/xml/ns/javaee"; private URL documentURL; private DocumentBuilderFactory factory; private boolean validating; // -------------------------------------------------------- Constructors /** * * Constructs a new ParseTask instance *
* @param validating whether or not we're validating * @param documentURL a URL to the configuration resource to be parsed * @throws Exception general error */ public ParseTask(boolean validating, URL documentURL) throws Exception { this.documentURL = documentURL; this.factory = DbfFactory.getFactory(); this.validating = validating; } // ----------------------------------------------- Methods from Callable /** * @return the result of the parse operation (a DOM) * @throws Exception if an error occurs during the parsing process */ public Document call() throws Exception { try { Timer timer = Timer.getInstance(); if (timer != null) { timer.startTiming(); } Document d = getDocument(); if (timer != null) { timer.stopTiming(); timer.logResult("Parse " + documentURL.toExternalForm()); } return d; } catch (Exception e) { throw new ConfigurationException(MessageFormat.format( "Unable to parse document ''{0}'': {1}", documentURL.toExternalForm(), e.getMessage()), e); } } // ----------------------------------------------------- Private Methods /** * @returnDocument
based ondocumentURL
. * @throws Exception if an error occurs during the process of building a *Document
*/ private Document getDocument() throws Exception { DocumentBuilder db = getNonValidatingBuilder(); InputSource is = new InputSource(getInputStream(documentURL)); is.setSystemId(documentURL.toExternalForm()); Document doc = db.parse(is); String documentNS = doc.getDocumentElement().getNamespaceURI(); if (validating && documentNS != null) { DOMSource domSource = new DOMSource(doc, documentURL.toExternalForm()); /* * If the Document in question is 1.2 (i.e. it has a namespace matching * FACES_SCHEMA_DEFAULT_NS, then perform validation using the cached schema * and return. Otherwise we assume a 1.0 or 1.1 faces-config in which case * we need to transform it to reference a special 1.1 schema before validating. */ if (FACES_SCHEMA_DEFAULT_NS.equals(documentNS)) { DocumentBuilder builder = getBuilderForSchema(DbfFactory.FacesSchema.FACES_12); if (builder.isValidating()) { builder.getSchema().newValidator().validate(domSource); return ((Document) domSource.getNode()); } else { return ((Document) domSource.getNode()); } } else { DOMResult domResult = new DOMResult(); Transformer transformer = getTransformer(); transformer.transform(domSource, domResult); DocumentBuilder builder = getBuilderForSchema(DbfFactory.FacesSchema.FACES_11); if (builder.isValidating()) { builder.getSchema().newValidator().validate(domSource); return ((Document) domSource.getNode()); } else { return ((Document) domSource.getNode()); } } } else { // validation isn't required, return the previously parsed document return doc; } } /** * Obtain aTransformer
using the style sheet * referenced by theXSL
constant. * * @return a new Tranformer instance * @throws Exception if a Tranformer instance could not be created */ private static Transformer getTransformer() throws Exception { TransformerFactory factory = TransformerFactory.newInstance(); return factory .newTransformer(new StreamSource(getInputStream(ConfigManager .class.getResource(XSL)))); } /** * @return anInputStream
to the resource referred to by *url
* @param url sourceURL
* @throws IOException if an error occurs */ private static InputStream getInputStream(URL url) throws IOException { URLConnection conn = url.openConnection(); conn.setUseCaches(false); return new BufferedInputStream(conn.getInputStream()); } private DocumentBuilder getNonValidatingBuilder() throws Exception { DocumentBuilderFactory tFactory = DbfFactory.getFactory(); tFactory.setValidating(false); DocumentBuilder tBuilder = tFactory.newDocumentBuilder(); tBuilder.setEntityResolver(DbfFactory.FACES_ENTITY_RESOLVER); tBuilder.setErrorHandler(DbfFactory.FACES_ERROR_HANDLER); return tBuilder; } private DocumentBuilder getBuilderForSchema(DbfFactory.FacesSchema schema) throws Exception { try { factory.setSchema(schema.getSchema()); } catch (UnsupportedOperationException upe) { return getNonValidatingBuilder(); } DocumentBuilder builder = factory.newDocumentBuilder(); builder.setEntityResolver(DbfFactory.FACES_ENTITY_RESOLVER); builder.setErrorHandler(DbfFactory.FACES_ERROR_HANDLER); return builder; } } // END ParseTask /** ** This
*/ private static class URLTask implements CallableCallable
will be used by {@link ConfigManager#getConfigDocuments(javax.servlet.ServletContext)}. * It represents one or more URLs to configuration resources that require * processing. *> { private ConfigurationResourceProvider provider; private ServletContext sc; // -------------------------------------------------------- Constructors /** * Constructs a new URLTask
instance. * @param provider theConfigurationResourceProvider
from * which zero or moreURL
s will be returned * @param sc theServletContext
of the current application */ public URLTask(ConfigurationResourceProvider provider, ServletContext sc) { this.provider = provider; this.sc = sc; } // ----------------------------------------------- Methods from Callable /** * @return zero or moreURL
instances * @throws Exception if an Exception is thrown by the underlying *ConfigurationResourceProvider
*/ public Collectioncall() throws Exception { return provider.getResources(sc); } } // END URLTask }