javax.faces.FactoryFinderInstance Maven / Gradle / Ivy
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2017 Oracle and/or its affiliates. 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_1_1.html
* or packager/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 packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [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 javax.faces;
import static com.sun.faces.util.Util.generateCreatedBy;
import static com.sun.faces.util.Util.getContextClassLoader2;
import static com.sun.faces.util.Util.isAnyNull;
import static com.sun.faces.util.Util.isOneOf;
import static java.text.MessageFormat.format;
import static java.util.Collections.binarySearch;
import static java.util.Collections.unmodifiableMap;
import static java.util.logging.Level.SEVERE;
import static javax.faces.FactoryFinder.APPLICATION_FACTORY;
import static javax.faces.FactoryFinder.CLIENT_WINDOW_FACTORY;
import static javax.faces.FactoryFinder.EXCEPTION_HANDLER_FACTORY;
import static javax.faces.FactoryFinder.EXTERNAL_CONTEXT_FACTORY;
import static javax.faces.FactoryFinder.FACELET_CACHE_FACTORY;
import static javax.faces.FactoryFinder.FACES_CONTEXT_FACTORY;
import static javax.faces.FactoryFinder.FACTORIES_CACHE;
import static javax.faces.FactoryFinder.FLASH_FACTORY;
import static javax.faces.FactoryFinder.FLOW_HANDLER_FACTORY;
import static javax.faces.FactoryFinder.LIFECYCLE_FACTORY;
import static javax.faces.FactoryFinder.PARTIAL_VIEW_CONTEXT_FACTORY;
import static javax.faces.FactoryFinder.RENDER_KIT_FACTORY;
import static javax.faces.FactoryFinder.SEARCH_EXPRESSION_CONTEXT_FACTORY;
import static javax.faces.FactoryFinder.TAG_HANDLER_DELEGATE_FACTORY;
import static javax.faces.FactoryFinder.VIEW_DECLARATION_LANGUAGE_FACTORY;
import static javax.faces.FactoryFinder.VISIT_CONTEXT_FACTORY;
import static javax.faces.ServletContextFacesContextFactory.SERVLET_CONTEXT_FINDER_NAME;
import static javax.faces.ServletContextFacesContextFactory.SERVLET_CONTEXT_FINDER_REMOVAL_NAME;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.logging.Logger;
import javax.faces.context.FacesContext;
import com.sun.faces.config.ConfigManager;
import com.sun.faces.spi.InjectionProvider;
final class FactoryFinderInstance {
private static final Logger LOGGER = Logger.getLogger("javax.faces", "javax.faces.LogStrings");
private static final String INJECTION_PROVIDER_KEY = FactoryFinder.class.getPackage().getName() + "INJECTION_PROVIDER_KEY";
private final Map factories = new ConcurrentHashMap<>();
private final Map> savedFactoryNames = new ConcurrentHashMap<>();
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true);
private final String createdBy;
private ServletContextFacesContextFactory servletContextFinder = new ServletContextFacesContextFactory();
/**
*
* The set of JavaServer Faces factory classes for which the factory discovery mechanism is
* supported. The entries in this list must be alphabetically ordered according to the entire
* string of the *value* of each of the literals, not just the last part of the literal!
*
*/
private final List factoryNames = asSortedList(
APPLICATION_FACTORY,
VISIT_CONTEXT_FACTORY,
EXCEPTION_HANDLER_FACTORY,
EXTERNAL_CONTEXT_FACTORY,
FACES_CONTEXT_FACTORY,
FLASH_FACTORY,
FLOW_HANDLER_FACTORY,
PARTIAL_VIEW_CONTEXT_FACTORY,
CLIENT_WINDOW_FACTORY,
LIFECYCLE_FACTORY,
RENDER_KIT_FACTORY,
VIEW_DECLARATION_LANGUAGE_FACTORY,
FACELET_CACHE_FACTORY,
TAG_HANDLER_DELEGATE_FACTORY,
SEARCH_EXPRESSION_CONTEXT_FACTORY);
/**
*
* Map of Class instances for our factory names.
*
*/
private final Map> factoryClasses = buildFactoryClassesMap();
// -------------------------------------------------------- Constructors
FactoryFinderInstance(FacesContext facesContext) {
for (String name : factoryNames) {
factories.put(name, new ArrayList<>(4)); // NOPMD
}
copyInjectionProviderFromFacesContext(facesContext);
createdBy = generateCreatedBy(facesContext);
}
FactoryFinderInstance(FacesContext facesContext, FactoryFinderInstance toCopy) {
factories.putAll(toCopy.savedFactoryNames);
copyInjectionProviderFromFacesContext(facesContext);
createdBy = generateCreatedBy(facesContext);
}
@Override
public String toString() {
return super.toString() + " created by" + createdBy;
}
// ------------------------------------------------------ Package Private Methods
void addFactory(String factoryName, String implementationClassName) {
validateFactoryName(factoryName);
Object result = factories.get(factoryName);
lock.writeLock().lock();
try {
if (result instanceof List) {
TypedCollections.dynamicallyCastList((List) result, String.class).add(0, implementationClassName);
}
} finally {
lock.writeLock().unlock();
}
}
@SuppressWarnings("unchecked")
Object getFactory(String factoryName) {
validateFactoryName(factoryName);
if (factoryName.equals(SERVLET_CONTEXT_FINDER_NAME)) {
return servletContextFinder;
}
if (factoryName.equals(SERVLET_CONTEXT_FINDER_REMOVAL_NAME)) {
try {
lock.writeLock().lock();
servletContextFinder = null;
return null;
} finally {
lock.writeLock().unlock();
}
}
Object factoryOrList;
lock.readLock().lock();
try {
factoryOrList = factories.get(factoryName);
if (!(factoryOrList instanceof List)) {
return factoryOrList;
}
} finally {
lock.readLock().unlock();
}
// Factory hasn't been constructed
lock.writeLock().lock();
try {
// Double check the current value. Another thread
// may have completed the initialization by the time
// this thread entered this block
factoryOrList = factories.get(factoryName);
if (!(factoryOrList instanceof List)) {
return factoryOrList;
}
savedFactoryNames.put(factoryName, new ArrayList((List) factoryOrList));
Object factory = getImplementationInstance(getContextClassLoader2(), factoryName, (List) factoryOrList);
if (factory == null) {
logNoFactory(factoryName);
factory = FACTORIES_CACHE.getFallbackFactory(this, factoryName);
notNullFactory(factoryName, factory);
}
// Record and return the new instance
factories.put(factoryName, factory);
return factory;
} finally {
lock.writeLock().unlock();
}
}
InjectionProvider getInjectionProvider() {
return (InjectionProvider) factories.get(INJECTION_PROVIDER_KEY);
}
void clearInjectionProvider() {
factories.remove(INJECTION_PROVIDER_KEY);
}
void releaseFactories() {
InjectionProvider provider = getInjectionProvider();
if (provider != null) {
lock.writeLock().lock();
try {
for (Entry entry : factories.entrySet()) {
Object curFactory = entry.getValue();
// If the current entry is not the injectionProvider itself
// and the current entry has a non-null value
// and the value is not a string...
if (!INJECTION_PROVIDER_KEY.equals(entry.getKey()) && curFactory != null && !(curFactory instanceof String)) {
try {
provider.invokePreDestroy(curFactory);
} catch (Exception ex) {
logPreDestroyFail(entry.getValue(), ex);
}
}
}
} finally {
factories.clear();
lock.writeLock().unlock();
}
} else {
LOGGER.log(SEVERE,
"Unable to call @PreDestroy annotated methods because no InjectionProvider can be found. Does this container implement the Mojarra Injection SPI?");
}
}
Collection