jakarta.faces.FactoryFinderInstance Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jakarta.faces Show documentation
Show all versions of jakarta.faces Show documentation
EE4J Compatible Implementation for Jakarta Faces API
The newest version!
/*
* Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/
package jakarta.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 jakarta.faces.FactoryFinder.APPLICATION_FACTORY;
import static jakarta.faces.FactoryFinder.CLIENT_WINDOW_FACTORY;
import static jakarta.faces.FactoryFinder.EXCEPTION_HANDLER_FACTORY;
import static jakarta.faces.FactoryFinder.EXTERNAL_CONTEXT_FACTORY;
import static jakarta.faces.FactoryFinder.FACELET_CACHE_FACTORY;
import static jakarta.faces.FactoryFinder.FACES_CONTEXT_FACTORY;
import static jakarta.faces.FactoryFinder.FACTORIES_CACHE;
import static jakarta.faces.FactoryFinder.FLASH_FACTORY;
import static jakarta.faces.FactoryFinder.FLOW_HANDLER_FACTORY;
import static jakarta.faces.FactoryFinder.LIFECYCLE_FACTORY;
import static jakarta.faces.FactoryFinder.PARTIAL_VIEW_CONTEXT_FACTORY;
import static jakarta.faces.FactoryFinder.RENDER_KIT_FACTORY;
import static jakarta.faces.FactoryFinder.SEARCH_EXPRESSION_CONTEXT_FACTORY;
import static jakarta.faces.FactoryFinder.TAG_HANDLER_DELEGATE_FACTORY;
import static jakarta.faces.FactoryFinder.VIEW_DECLARATION_LANGUAGE_FACTORY;
import static jakarta.faces.FactoryFinder.VISIT_CONTEXT_FACTORY;
import static jakarta.faces.ServletContextFacesContextFactory.SERVLET_CONTEXT_FINDER_NAME;
import static jakarta.faces.ServletContextFacesContextFactory.SERVLET_CONTEXT_FINDER_REMOVAL_NAME;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.text.MessageFormat.format;
import static java.util.Collections.binarySearch;
import static java.util.Map.entry;
import static java.util.logging.Level.SEVERE;
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.Enumeration;
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 java.util.stream.Collectors;
import com.sun.faces.config.ConfigManager;
import com.sun.faces.spi.InjectionProvider;
import jakarta.faces.context.FacesContext;
final class FactoryFinderInstance {
private static final Logger LOGGER = Logger.getLogger("jakarta.faces", "jakarta.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 Jakarta 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 static 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 static 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