com.sun.faces.util.Util Maven / Gradle / Ivy
Show all versions of jakarta.faces Show documentation
/*
* Copyright (c) 2021, 2023 Contributors to Eclipse Foundation.
* Copyright (c) 1997, 2021 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
*/
// Util.java
package com.sun.faces.util;
import static com.sun.faces.RIConstants.CDI_BEAN_MANAGER;
import static com.sun.faces.RIConstants.FACELETS_ENCODING_KEY;
import static com.sun.faces.RIConstants.FACES_SERVLET_MAPPINGS;
import static com.sun.faces.RIConstants.FACES_SERVLET_REGISTRATION;
import static com.sun.faces.RIConstants.NO_VALUE;
import static com.sun.faces.util.MessageUtils.ILLEGAL_ATTEMPT_SETTING_APPLICATION_ARTIFACT_ID;
import static com.sun.faces.util.MessageUtils.NAMED_OBJECT_NOT_FOUND_ERROR_MESSAGE_ID;
import static com.sun.faces.util.MessageUtils.NULL_PARAMETERS_ERROR_MESSAGE_ID;
import static com.sun.faces.util.MessageUtils.NULL_VIEW_ID_ERROR_MESSAGE_ID;
import static com.sun.faces.util.MessageUtils.getExceptionMessageString;
import static jakarta.faces.application.ViewHandler.CHARACTER_ENCODING_KEY;
import static java.lang.Character.isDigit;
import static java.util.Collections.emptyList;
import static java.util.logging.Level.FINE;
import static java.util.logging.Level.FINEST;
import static java.util.logging.Level.SEVERE;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.JarURLConnection;
import java.net.MalformedURLException;
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.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.xml.XMLConstants;
import javax.xml.namespace.NamespaceContext;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.TransformerFactory;
import javax.xml.validation.SchemaFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import com.sun.faces.RIConstants;
import com.sun.faces.application.ApplicationAssociate;
import com.sun.faces.config.WebConfiguration;
import com.sun.faces.config.manager.FacesSchema;
import com.sun.faces.facelets.component.UIRepeat;
import com.sun.faces.io.FastStringWriter;
import jakarta.el.ValueExpression;
import jakarta.enterprise.inject.spi.BeanManager;
import jakarta.enterprise.inject.spi.CDI;
import jakarta.enterprise.inject.spi.el.ELAwareBeanManager;
import jakarta.faces.FacesException;
import jakarta.faces.application.Application;
import jakarta.faces.application.ProjectStage;
import jakarta.faces.application.StateManager;
import jakarta.faces.application.ViewHandler;
import jakarta.faces.component.Doctype;
import jakarta.faces.component.NamingContainer;
import jakarta.faces.component.UIComponent;
import jakarta.faces.component.UIData;
import jakarta.faces.component.UINamingContainer;
import jakarta.faces.component.UIViewRoot;
import jakarta.faces.context.ExternalContext;
import jakarta.faces.context.FacesContext;
import jakarta.faces.convert.Converter;
import jakarta.faces.event.AbortProcessingException;
import jakarta.faces.render.ResponseStateManager;
import jakarta.faces.webapp.FacesServlet;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletRegistration;
import jakarta.servlet.http.HttpServletMapping;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.MappingMatch;
/**
* Util is a class ...
*
* Lifetime And Scope
*
*/
public class Util {
// Log instance for this class
private static final Logger LOGGER = FacesLogger.APPLICATION.getLogger();
// README - make sure to add the message identifier constant
// (ex: Util.CONVERSION_ERROR_MESSAGE_ID) and the number of substitution
// parameters to test/com/sun/faces/util/TestUtil_messages (see comment there).
/**
* Flag that, when true, enables special behavior in Mojarra to enable unit testing.
*/
private static boolean unitTestModeEnabled = false;
/**
* RegEx patterns
*/
private static final String PATTERN_CACHE_KEY = RIConstants.FACES_PREFIX + "patternCache";
private static final String CLIENT_ID_NESTED_IN_ITERATOR_PATTERN = "CLIENT_ID_NESTED_IN_ITERATOR_PATTERN";
private static final String FACES_SERVLET_CLASS = FacesServlet.class.getName();
private Util() {
throw new IllegalStateException();
}
private static Map getPatternCache(Map appMap) {
@SuppressWarnings("unchecked")
Map result = (Map) appMap.get(PATTERN_CACHE_KEY);
if (result == null) {
result = Collections.synchronizedMap(new LRUMap<>(15));
appMap.put(PATTERN_CACHE_KEY, result);
}
return result;
}
private static Map getPatternCache(ServletContext sc) {
@SuppressWarnings("unchecked")
Map result = (Map) sc.getAttribute(PATTERN_CACHE_KEY);
if (result == null) {
result = Collections.synchronizedMap(new LRUMap<>(15));
sc.setAttribute(PATTERN_CACHE_KEY, result);
}
return result;
}
private static Collection getFacesServletMappings(ServletContext servletContext) {
// check servlet context during initialization to avoid ConfigureListener to call the servlet registration
@SuppressWarnings("unchecked")
Collection mappings = (Collection) servletContext.getAttribute(FACES_SERVLET_MAPPINGS);
if (mappings != null) {
return mappings;
}
ServletRegistration facesRegistration = getExistingFacesServletRegistration(servletContext);
if (facesRegistration != null) {
return facesRegistration.getMappings();
}
return emptyList();
}
private static ServletRegistration getExistingFacesServletRegistration(ServletContext servletContext) {
Map existing = servletContext.getServletRegistrations();
for (ServletRegistration registration : existing.values()) {
if (FACES_SERVLET_CLASS.equals(registration.getClassName())) {
return registration;
}
}
return null;
}
public static Optional getFacesServletRegistration(FacesContext context) {
Object unKnownContext = context.getExternalContext().getContext();
if (unKnownContext instanceof ServletContext) {
return Optional.of((ServletRegistration) ((ServletContext) unKnownContext).getAttribute(FACES_SERVLET_REGISTRATION));
}
return Optional.empty();
}
/**
*
* Convenience method for determining if the request associated with the specified FacesContext
is a
* PortletRequest submitted by the JSR-301 bridge.
*
*
* @param context the FacesContext
associated with the request.
*/
public static boolean isPortletRequest(FacesContext context) {
return context.getExternalContext().getRequestMap().get("javax.portlet.faces.phase") != null;
}
public static String generateCreatedBy(FacesContext facesContext) {
String applicationContextPath = "unitTest";
try {
applicationContextPath = facesContext.getExternalContext().getApplicationContextPath();
} catch (Throwable e) {
// ignore
}
return applicationContextPath + " " + Thread.currentThread().toString() + " " + System.currentTimeMillis();
}
/**
*
* Factory method for creating the various Faces listener instances that may be referenced by type
or
* binding
.
*
*
* If binding
is not null
and the evaluation result is not null
return that
* instance. Otherwise try to instantiate an instances based on type
.
*
*
* @param type the Listener
type
* @param binding a ValueExpression
which resolves to a Listener
instance
* @return a Listener
instance based off the provided type
and binding
*/
public static Object getListenerInstance(ValueExpression type, ValueExpression binding) {
FacesContext faces = FacesContext.getCurrentInstance();
Object instance = null;
if (faces == null) {
return null;
}
if (binding != null) {
instance = binding.getValue(faces.getELContext());
}
if (instance == null && type != null) {
try {
instance = ReflectionUtils.newInstance((String) type.getValue(faces.getELContext()));
} catch (IllegalArgumentException | ReflectiveOperationException | SecurityException e) {
throw new AbortProcessingException(e.getMessage(), e);
}
if (binding != null) {
binding.setValue(faces.getELContext(), instance);
}
}
return instance;
}
public static void setUnitTestModeEnabled(boolean enabled) {
unitTestModeEnabled = enabled;
}
public static boolean isUnitTestModeEnabled() {
return unitTestModeEnabled;
}
public static interface ThrowingBiConsumer {
void accept(T t, U u) throws Exception;
}
private static void setFeature(ThrowingBiConsumer setter, F feature, Boolean flag) {
try {
setter.accept(feature, flag);
} catch (Exception e) {
throw new IllegalArgumentException("The feature '" + feature + "' is not supported by your XML processor.", e);
}
}
private static void setPossiblyUnsupportedFeature(ThrowingBiConsumer setter, F feature, Boolean flag) {
try {
setFeature(setter, feature, flag);
} catch (IllegalArgumentException e) {
LOGGER.log(Level.FINE, e.getMessage(), e);
}
}
public static TransformerFactory createTransformerFactory() {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
TransformerFactory factory;
try {
Thread.currentThread().setContextClassLoader(Util.class.getClassLoader());
factory = TransformerFactory.newInstance();
factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, NO_VALUE);
factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, NO_VALUE);
setFeature(factory::setFeature, XMLConstants.FEATURE_SECURE_PROCESSING, true);
} finally {
Thread.currentThread().setContextClassLoader(cl);
}
return factory;
}
public static SAXParserFactory createSAXParserFactory() {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
SAXParserFactory factory;
try {
Thread.currentThread().setContextClassLoader(Util.class.getClassLoader());
factory = SAXParserFactory.newInstance();
} finally {
Thread.currentThread().setContextClassLoader(cl);
}
return factory;
}
public static DocumentBuilderFactory createDocumentBuilderFactory() {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
DocumentBuilderFactory factory;
try {
Thread.currentThread().setContextClassLoader(Util.class.getClassLoader());
factory = createLocalDocumentBuilderFactory();
} finally {
Thread.currentThread().setContextClassLoader(cl);
}
return factory;
}
public static DocumentBuilderFactory createLocalDocumentBuilderFactory() {
DocumentBuilderFactory factory;
factory = DocumentBuilderFactory.newInstance();
factory.setXIncludeAware(false);
factory.setExpandEntityReferences(false);
setFeature(factory::setFeature, XMLConstants.FEATURE_SECURE_PROCESSING, true);
setPossiblyUnsupportedFeature(factory::setFeature, "http://xml.org/sax/features/external-general-entities", false);
setPossiblyUnsupportedFeature(factory::setFeature, "http://xml.org/sax/features/external-parameter-entities", false);
setPossiblyUnsupportedFeature(factory::setFeature, "http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
return factory;
}
public static SchemaFactory createSchemaFactory(String uri) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
SchemaFactory factory;
try {
Thread.currentThread().setContextClassLoader(Util.class.getClassLoader());
factory = SchemaFactory.newInstance(uri);
} finally {
Thread.currentThread().setContextClassLoader(cl);
}
return factory;
}
public static final Map> primitiveTypes = Map.of(
"byte" , byte.class ,
"short" , short.class ,
"int" , int.class ,
"long" , long.class ,
"float" , float.class ,
"double" , double.class ,
"boolean" , boolean.class ,
"char" , char.class
);
public static Class loadClass(String name, Object fallbackClass) throws ClassNotFoundException {
ClassLoader loader = Util.getCurrentLoader(fallbackClass);
return primitiveTypes.getOrDefault(name, Class.forName(name, true, loader));
}
public static Class> loadClass2(String name, Object fallbackClass) {
try {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
if (loader == null) {
loader = fallbackClass.getClass().getClassLoader();
}
return Class.forName(name, true, loader);
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
@SuppressWarnings("unchecked")
public static T newInstance(Class> clazz) {
try {
return (T) clazz.getDeclaredConstructor().newInstance();
} catch (IllegalArgumentException | ReflectiveOperationException | SecurityException e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
public static ClassLoader getCurrentLoader(Object fallbackClass) {
ClassLoader loader = getContextClassLoader();
if (loader == null) {
loader = fallbackClass.getClass().getClassLoader();
}
return loader;
}
private static ClassLoader getContextClassLoader() {
return Thread.currentThread().getContextClassLoader();
}
/**
*
* Identify and return the class loader that is associated with the calling web application.
*
*
* @throws FacesException if the web application class loader cannot be identified
*/
public static ClassLoader getContextClassLoader2() throws FacesException {
// J2EE 1.3 (and later) containers are required to make the
// web application class loader visible through the context
// class loader of the current thread.
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
throw new FacesException("getContextClassLoader");
}
return classLoader;
}
public static String removeAllButLastSlashPathSegment(String input) {
// Trim the leading lastSlash, if any.
if (input.charAt(0) == '/') {
input = input.substring(1);
}
int len = input.length();
// Trim the trailing lastSlash, if any.
if (input.charAt(len - 1) == '/') {
input = input.substring(0, len - 1);
}
// Trim any path segments that remain, leaving only the
// last path segment.
int slash = input.lastIndexOf("/");
// Do we have a "/"?
if (-1 != slash) {
input = input.substring(slash + 1);
}
return input;
}
/**
* @return the filename extension or null. the method is null-safe
*/
public static String fileExtension(String filename) {
final String notBlankFilename = nullIfBlank(filename);
if ( notBlankFilename == null ) return null;
int idx = notBlankFilename.lastIndexOf('.');
return idx == -1 ? null : notBlankFilename.substring(idx+1);
}
public static String removeAllButNextToLastSlashPathSegment(String input) {
// Trim the leading lastSlash, if any.
if (input.charAt(0) == '/') {
input = input.substring(1);
}
int len = input.length();
// Trim the trailing lastSlash, if any.
if (input.charAt(len - 1) == '/') {
input = input.substring(0, len - 1);
}
// Trim any path segments that remain, leaving only the
// last path segment.
int lastSlash = input.lastIndexOf("/");
// Do we have a "/"?
if (-1 != lastSlash) {
int startOrPreviousSlash = input.lastIndexOf("/", lastSlash - 1);
startOrPreviousSlash = -1 == startOrPreviousSlash ? 0 : startOrPreviousSlash;
input = input.substring(startOrPreviousSlash, lastSlash);
}
return input;
}
public static String removeLastPathSegment(String input) {
int slash = input.lastIndexOf("/");
// Do we have a "/"?
if (-1 != slash) {
input = input.substring(0, slash);
}
return input;
}
public static void notNegative(String varname, long number) {
if (number < 0) {
throw new IllegalArgumentException("\"" + varname + "\" is negative");
}
}
public static void notNull(String varname, Object var) {
if (var == null) {
throw new NullPointerException(getExceptionMessageString(NULL_PARAMETERS_ERROR_MESSAGE_ID, varname));
}
}
public static void notNullViewId(String viewId) {
if (viewId == null) {
throw new IllegalArgumentException(getExceptionMessageString(NULL_VIEW_ID_ERROR_MESSAGE_ID));
}
}
public static void notNullNamedObject(Object object, String objectId, String logMsg) {
if (object == null) {
Object[] params = { objectId };
if (LOGGER.isLoggable(SEVERE)) {
LOGGER.log(SEVERE, logMsg, params);
}
throw new FacesException(getExceptionMessageString(NAMED_OBJECT_NOT_FOUND_ERROR_MESSAGE_ID, params));
}
}
public static void canSetAppArtifact(ApplicationAssociate applicationAssociate, String artifactName) {
if (applicationAssociate.hasRequestBeenServiced()) {
throw new IllegalStateException(getExceptionMessageString(ILLEGAL_ATTEMPT_SETTING_APPLICATION_ARTIFACT_ID, artifactName));
}
}
public static void notNullAttribute(String attributeName, Object attribute) {
if (attribute == null) {
throw new FacesException("The \"" + attributeName + "\" attribute is required");
}
}
public static ValueExpression getValueExpressionNullSafe(UIComponent component, String name) {
ValueExpression valueExpression = component.getValueExpression(name);
notNullAttribute(name, valueExpression);
return valueExpression;
}
/**
* Returns true if the given string is null or is empty.
*
* @param string The string to be checked on emptiness.
* @return True if the given string is null or is empty.
*/
public static boolean isEmpty(String string) {
return string == null || string.isEmpty();
}
/**
* Returns true if the given string is null or is blank.
*
* @param string The string to be checked.
* @return True if the given string is null or is blank.
*/
public static boolean isBlank(String string) {
return string == null || string.isBlank();
}
/**
* @return null if the passed String is null or blank, s otherwise
*/
public static String nullIfBlank(String s) {
return isBlank(s) ? null : s;
}
/**
* Returns true
if the given array is null or is empty.
*
* @param array The array to be checked on emptiness.
* @return true
if the given array is null or is empty.
*/
public static boolean isEmpty(Object[] array) {
return array == null || array.length == 0;
}
/**
* Returns true
if the given collection is null or is empty.
*
* @param collection The collection to be checked on emptiness.
* @return true
if the given collection is null or is empty.
*/
public static boolean isEmpty(Collection> collection) {
return collection == null || collection.isEmpty();
}
/**
* Returns true
if the given value is null or is empty. Types of String, Collection, Map, Optional and
* Array are recognized. If none is recognized, then examine the emptiness of the toString() representation instead.
*
* @param value The value to be checked on emptiness.
* @return true
if the given value is null or is empty.
*/
public static boolean isEmpty(Object value) {
if (value == null) {
return true;
} else if (value instanceof String) {
return ((String) value).isEmpty();
} else if (value instanceof Collection>) {
return ((Collection>) value).isEmpty();
} else if (value instanceof Map, ?>) {
return ((Map, ?>) value).isEmpty();
} else if (value instanceof Optional>) {
return ((Optional>) value).isEmpty();
} else if (value.getClass().isArray()) {
return Array.getLength(value) == 0;
} else {
return value.toString() == null || value.toString().isEmpty();
}
}
/**
* Returns true if all values are empty, false if at least one value is not empty.
*
* @param values the values to be checked on emptiness
* @return True if all values are empty, false otherwise
*/
public static boolean isAllEmpty(Object... values) {
for (Object value : values) {
if (!isEmpty(value)) {
return false;
}
}
return true;
}
/**
* Returns true
if at least one value is empty.
*
* @param values the values to be checked on emptiness
* @return true
if any value is empty and false
if no values are empty
*/
public static boolean isAnyEmpty(Object... values) {
for (Object value : values) {
if (isEmpty(value)) {
return true;
}
}
return false;
}
public static boolean isAllNull(Object... values) {
for (Object value : values) {
if (value != null) {
return false;
}
}
return true;
}
public static boolean isAnyNull(Object... values) {
for (Object value : values) {
if (value == null) {
return true;
}
}
return false;
}
/**
* Returns true
if the given object equals one of the given objects.
*
* @param The generic object type.
* @param object The object to be checked if it equals one of the given objects.
* @param objects The argument list of objects to be tested for equality.
* @return true
if the given object equals one of the given objects.
*/
@SafeVarargs
public static boolean isOneOf(T object, T... objects) {
for (Object other : objects) {
if (object == null ? other == null : object.equals(other)) {
return true;
}
}
return false;
}
/**
* Returns the first non-null
object of the argument list, or null
if there is no such
* element.
*
* @param The generic object type.
* @param objects The argument list of objects to be tested for non-null
.
* @return The first non-null
object of the argument list, or null
if there is no such
* element.
*/
@SafeVarargs
public static T coalesce(T... objects) {
for (T object : objects) {
if (object != null) {
return object;
}
}
return null;
}
public static List reverse(List list) {
int length = list.size();
List result = new ArrayList<>(length);
for (int i = length - 1; i >= 0; i--) {
result.add(list.get(i));
}
return result;
}
/**
* Returns true
if the given string starts with one of the given prefixes.
*
* @param string The object to be checked if it starts with one of the given prefixes.
* @param prefixes The argument list of prefixes to be checked
*
* @return true
if the given string starts with one of the given prefixes.
*/
public static boolean startsWithOneOf(String string, String... prefixes) {
if (prefixes == null) {
return false;
}
for (String prefix : prefixes) {
if (string.startsWith(prefix)) {
return true;
}
}
return false;
}
/**
* @param context the FacesContext
for the current request
* @return the Locale from the UIViewRoot, the the value of Locale.getDefault()
*/
public static Locale getLocaleFromContextOrSystem(FacesContext context) {
Locale result, temp = Locale.getDefault();
UIViewRoot root;
result = temp;
if (null != context && null != (root = context.getViewRoot()) && null == (result = root.getLocale())) {
result = temp;
}
return result;
}
public static Converter getConverterForClass(Class converterClass, FacesContext context) {
if (converterClass == null) {
return null;
}
try {
Application application = context.getApplication();
return application.createConverter(converterClass);
} catch (Exception e) {
return null;
}
}
public static Converter getConverterForIdentifer(String converterId, FacesContext context) {
if (converterId == null) {
return null;
}
try {
Application application = context.getApplication();
return application.createConverter(converterId);
} catch (Exception e) {
return null;
}
}
public static StateManager getStateManager(FacesContext context) throws FacesException {
return context.getApplication().getStateManager();
}
public static Class getTypeFromString(String type) throws ClassNotFoundException {
Class result;
switch (type) {
case "byte":
result = Byte.TYPE;
break;
case "short":
result = Short.TYPE;
break;
case "int":
result = Integer.TYPE;
break;
case "long":
result = Long.TYPE;
break;
case "float":
result = Float.TYPE;
break;
case "double":
result = Double.TYPE;
break;
case "boolean":
result = Boolean.TYPE;
break;
case "char":
result = Character.TYPE;
break;
case "void":
result = Void.TYPE;
break;
default:
if (type.indexOf('.') == -1) {
type = "java.lang." + type;
}
result = Util.loadClass(type, Void.TYPE);
break;
}
return result;
}
public static ViewHandler getViewHandler(FacesContext context) throws FacesException {
// Get Application instance
Application application = context.getApplication();
assert application != null;
// Get the ViewHandler
ViewHandler viewHandler = application.getViewHandler();
assert viewHandler != null;
return viewHandler;
}
public static boolean componentIsDisabled(UIComponent component) {
return Boolean.parseBoolean(String.valueOf(component.getAttributes().get("disabled")));
}
public static boolean componentIsDisabledOrReadonly(UIComponent component) {
return Boolean.parseBoolean(String.valueOf(component.getAttributes().get("disabled")))
|| Boolean.parseBoolean(String.valueOf(component.getAttributes().get("readonly")));
}
// W3C XML specification refers to IETF RFC 1766 for language code
// structure, therefore the value for the xml:lang attribute should
// be in the form of language or language-country or
// language-country-variant.
public static Locale getLocaleFromString(String localeStr) throws IllegalArgumentException {
// length must be at least 2.
if (null == localeStr || localeStr.length() < 2) {
throw new IllegalArgumentException("Illegal locale String: " + localeStr);
}
Locale result = null;
try {
Method method = Locale.class.getMethod("forLanguageTag", String.class);
if (method != null) {
result = (Locale) method.invoke(null, localeStr);
}
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException throwable) {
// if we are NOT running JavaSE 7 we end up here and we will
// default to the previous way of determining the Locale below.
}
if (result == null || result.getLanguage().equals("")) {
String lang = null;
String country = null;
String variant = null;
char[] seps = { '-', '_' };
int inputLength = localeStr.length();
int i = 0;
int j = 0;
// to have a language, the length must be >= 2
if (inputLength >= 2 && (i = indexOfSet(localeStr, seps, 0)) == -1) {
// we have only Language, no country or variant
if (2 != localeStr.length()) {
throw new IllegalArgumentException("Illegal locale String: " + localeStr);
}
lang = localeStr.toLowerCase();
}
// we have a separator, it must be either '-' or '_'
if (i != -1) {
lang = localeStr.substring(0, i);
// look for the country sep.
// to have a country, the length must be >= 5
if (inputLength >= 5 && (j = indexOfSet(localeStr, seps, i + 1)) == -1) {
// no further separators, length must be 5
if (inputLength != 5) {
throw new IllegalArgumentException("Illegal locale String: " + localeStr);
}
country = localeStr.substring(i + 1);
}
if (j != -1) {
country = localeStr.substring(i + 1, j);
// if we have enough separators for language, locale,
// and variant, the length must be >= 8.
if (inputLength >= 8) {
variant = localeStr.substring(j + 1);
} else {
throw new IllegalArgumentException("Illegal locale String: " + localeStr);
}
}
}
if (variant != null && country != null && lang != null) {
result = new Locale(lang, country, variant);
} else if (lang != null && country != null) {
result = new Locale(lang, country);
} else if (lang != null) {
result = new Locale(lang, "");
}
}
return result;
}
/**
* @param str local string
* @param set the substring
* @param fromIndex starting index
* @return starting at fromIndex
, the index of the first occurrence of any substring from set
* in toSearch
, or -1 if no such match is found
*/
public static int indexOfSet(String str, char[] set, int fromIndex) {
int result = -1;
for (int i = fromIndex, len = str.length(); i < len; i++) {
for (int j = 0, innerLen = set.length; j < innerLen; j++) {
if (str.charAt(i) == set[j]) {
result = i;
break;
}
}
if (-1 != result) {
break;
}
}
return result;
}
/**
*
* Leverage the Throwable.getStackTrace() method to produce a String version of the stack trace, with a "\n" before each
* line.
*
*
* @param e the Throwable to obtain the stacktrace from
*
* @return the String representation ofthe stack trace obtained by calling getStackTrace() on the passed in exception.
* If null is passed in, we return the empty String.
*/
public static String getStackTraceString(Throwable e) {
if (null == e) {
return "";
}
StackTraceElement[] stacks = e.getStackTrace();
StringBuilder sb = new StringBuilder();
for (StackTraceElement stack : stacks) {
sb.append(stack.toString()).append('\n');
}
return sb.toString();
}
/**
*
* PRECONDITION: argument response
is non-null and has a method called getContentType
that
* takes no arguments and returns a String, with no side-effects.
*
*
*
* This method allows us to get the contentType in both the servlet and portlet cases, without introducing a
* compile-time dependency on the portlet api.
*
*
* @param response the current response
* @return the content type of the response
*/
public static String getContentTypeFromResponse(Object response) {
String result = null;
if (null != response) {
try {
Method method = ReflectionUtils.lookupMethod(response.getClass(), "getContentType", RIConstants.EMPTY_CLASS_ARGS);
if (null != method) {
Object obj = method.invoke(response, RIConstants.EMPTY_METH_ARGS);
if (null != obj) {
result = obj.toString();
}
}
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
throw new FacesException(e);
}
}
return result;
}
/**
*
* A slightly more efficient version of String.split()
which caches the Pattern
s in an LRUMap
* instead of creating a new Pattern
on each invocation.
*
*
* @param appMap the Application Map
* @param toSplit the string to split
* @param regex the regex used for splitting
* @return the result of Pattern.spit(String, int)
*/
public static String[] split(Map appMap, String toSplit, String regex) {
return split(appMap, toSplit, regex, 0);
}
/**
* A slightly more efficient version of
* String.split()
which caches
* the Pattern
s in an LRUMap instead of
* creating a new Pattern
on each
* invocation. Limited by splitLimit.
* @param appMap the Application Map
* @param toSplit the string to split
* @param regex the regex used for splitting
* @param splitLimit split result threshold
* @return the result of Pattern.spit(String, int)
*/
public static String[] split(Map appMap, String toSplit, String regex, int splitLimit) {
Map patternCache = getPatternCache(appMap);
Pattern pattern = patternCache.computeIfAbsent(regex, Pattern::compile);
return pattern.split(toSplit, splitLimit);
}
public static String[] split(ServletContext sc, String toSplit, String regex) {
Map patternCache = getPatternCache(sc);
Pattern pattern = patternCache.computeIfAbsent(regex, Pattern::compile);
return pattern.split(toSplit, 0);
}
/**
*
* Returns the URL pattern of the {@link jakarta.faces.webapp.FacesServlet} that is executing the current request. If
* there are multiple URL patterns, the value returned by HttpServletRequest.getServletPath()
and
* HttpServletRequest.getPathInfo()
is used to determine which mapping to return.
*
* If no mapping can be determined, it most likely means that this particular request wasn't dispatched through the
* {@link jakarta.faces.webapp.FacesServlet}.
*
*
* @param context the {@link FacesContext} of the current request
*
* @return the URL pattern of the {@link jakarta.faces.webapp.FacesServlet} or null
if no mapping can be
* determined
*
* @throws NullPointerException if context
is null
*/
public static HttpServletMapping getFacesMapping(FacesContext context) {
notNull("context", context);
return ((HttpServletRequest) context.getExternalContext().getRequest()).getHttpServletMapping();
}
/**
* Checks if the FacesServlet is exact mapped to the given resource.
*
* Not to be confused with isExactMapped(String)
, which checks if a string representing a mapping, not a
* resource, is an exact mapping.
*
* @param viewId the view id to test
* @return true if the FacesServlet is exact mapped to the given viewId, false otherwise
*/
public static boolean isViewIdExactMappedToFacesServlet(String viewId) {
return isResourceExactMappedToFacesServlet(FacesContext.getCurrentInstance().getExternalContext(), viewId);
}
/**
* Checks if the FacesServlet is exact mapped to the given resource.
*
* Not to be confused with isExactMapped(String)
, which checks if a string representing a mapping, not a
* resource, is an exact mapping.
*
* @param externalContext the external context for this request
* @param resource the resource to test
* @return true if the FacesServlet is exact mapped to the given resource, false otherwise
*/
public static boolean isResourceExactMappedToFacesServlet(ExternalContext externalContext, String resource) {
Object context = externalContext.getContext();
if (context instanceof ServletContext) {
return getFacesServletMappings((ServletContext) context).contains(resource);
}
return false;
}
public static HttpServletMapping getFirstWildCardMappingToFacesServlet(ExternalContext externalContext) {
// If needed, cache this after initialization of Faces
Object context = externalContext.getContext();
if (context instanceof ServletContext) {
return getFacesServletMappings((ServletContext) context).stream()
.filter(mapping -> mapping.contains("*"))
.map(mapping -> new HttpServletMapping() {
@Override
public String getServletName() {
return "";
}
@Override
public String getPattern() {
return mapping;
}
@Override
public String getMatchValue() {
return null;
}
@Override
public MappingMatch getMappingMatch() {
return isPrefixMapped(mapping)? MappingMatch.PATH : MappingMatch.EXTENSION;
}
})
.findFirst()
.orElse(null);
}
return null;
}
/**
*
* Returns true if the provided url-mapping
is a prefix path mapping (starts with /
).
*
*
* @param mapping a url-pattern
* @return true if the mapping starts with /
*/
public static boolean isPrefixMapped(String mapping) {
return mapping.charAt(0) == '/';
}
public static boolean isSpecialAttributeName(String name) {
boolean isSpecialAttributeName = name.equals("action") || name.equals("actionListener") || name.equals("validator")
|| name.equals("valueChangeListener");
return isSpecialAttributeName;
}
/**
* @param ctx the {@link FacesContext} for the current request
* @param viewToRender the {@link UIViewRoot} to check
* @return true
if the {@link FacesContext} attributes map contains a reference to the {@link UIViewRoot}'s
* view ID
*/
public static boolean isViewPopulated(FacesContext ctx, UIViewRoot viewToRender) {
return ctx.getAttributes().containsKey(viewToRender);
}
/**
*
* Flag the specified {@link UIViewRoot} as populated.
*
*
* @param ctx the {@link FacesContext} for the current request
* @param viewToRender the {@link UIViewRoot} to mark as populated
*/
public static void setViewPopulated(FacesContext ctx, UIViewRoot viewToRender) {
ctx.getAttributes().put(viewToRender, Boolean.TRUE);
}
/**
* Utility method to validate ID uniqueness for the tree represented by component
.
*/
public static void checkIdUniqueness(FacesContext context, UIComponent component, Set componentIds) {
boolean uniquenessCheckDisabled = false;
if (context.isProjectStage(ProjectStage.Production)) {
WebConfiguration config = WebConfiguration.getInstance(context.getExternalContext());
uniquenessCheckDisabled = config.isOptionEnabled(WebConfiguration.BooleanWebContextInitParameter.DisableIdUniquenessCheck);
}
if (!uniquenessCheckDisabled) {
// deal with children/facets that are marked transient.
for (Iterator kids = component.getFacetsAndChildren(); kids.hasNext();) {
UIComponent kid = kids.next();
// check for id uniqueness
String id = kid.getClientId(context);
if (componentIds.add(id)) {
checkIdUniqueness(context, kid, componentIds);
} else {
if (LOGGER.isLoggable(Level.SEVERE)) {
LOGGER.log(Level.SEVERE, "faces.duplicate_component_id_error", id);
FastStringWriter writer = new FastStringWriter(128);
DebugUtil.simplePrintTree(context.getViewRoot(), id, writer);
LOGGER.severe(writer.toString());
}
String message = MessageUtils.getExceptionMessageString(MessageUtils.DUPLICATE_COMPONENT_ID_ERROR_ID, id);
throw new IllegalStateException(message);
}
}
}
}
static public boolean classHasAnnotations(Class> clazz) {
if (clazz != null) {
while (clazz != Object.class) {
try {
Field[] fields = clazz.getDeclaredFields();
if (fields != null) {
for (Field field : fields) {
if (field.getAnnotations().length > 0) {
return true;
}
}
}
Method[] methods = clazz.getDeclaredMethods();
if (methods != null) {
for (Method method : methods) {
if (method.getDeclaredAnnotations().length > 0) {
return true;
}
}
}
}
catch (NoClassDefFoundError e) {
if (LOGGER.isLoggable(FINE)) {
LOGGER.log(FINE, "Cannot inspect " + clazz + " because of missing dependency " + e.getMessage());
}
return false;
}
clazz = clazz.getSuperclass();
}
}
return false;
}
/**
* If view root is instance of naming container, return its container client id, suffixed with separator character.
*
* @param context Involved faces context.
* @return The naming container prefix, or an empty string if the view root is not an instance of naming container.
*/
public static String getNamingContainerPrefix(FacesContext context) {
UIViewRoot viewRoot = context.getViewRoot();
if (viewRoot == null) {
Application application = context.getApplication();
viewRoot = (UIViewRoot) application.createComponent(UIViewRoot.COMPONENT_TYPE);
}
if (viewRoot instanceof NamingContainer) {
return viewRoot.getContainerClientId(context) + UINamingContainer.getSeparatorChar(context);
} else {
return "";
}
}
public static String getViewStateId(FacesContext context) {
String result = null;
final String viewStateCounterKey = "com.sun.faces.util.ViewStateCounterKey";
Map