| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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.apache.webbeans.config; |
| |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Properties; |
| import java.util.Set; |
| import java.util.logging.Level; |
| import java.util.stream.Stream; |
| |
| import org.apache.webbeans.exception.WebBeansConfigurationException; |
| import org.apache.webbeans.logger.WebBeansLoggerFacade; |
| import org.apache.webbeans.spi.BeanArchiveService; |
| |
| import static java.util.Arrays.asList; |
| import static java.util.stream.Collectors.toList; |
| |
| /** |
| * Defines configuration for OpenWebBeans. |
| * |
| * The algorithm is easy: |
| * <ul> |
| * <li>Load all properties you can find with the name (META-INF/openwebbeans/openwebbeans.properties),</li> |
| * <li>Sort the property files via their configuration.ordinal in ascending order,</li> |
| * <li>Overload them in a loop,</li> |
| * <li><Overload them via System.getProperties/li> |
| * <li><Overload them via System.getenv/li> |
| * <li>Use the final list of properties.</li> |
| * </ul> |
| */ |
| public class OpenWebBeansConfiguration |
| { |
| /**Timeout interval in ms*/ |
| public static final String CONVERSATION_TIMEOUT_INTERVAL = "org.apache.webbeans.conversation.Conversation.timeoutInterval"; |
| |
| /** |
| * Environment property which comma separated list of classes which |
| * should NOT fail with UnproxyableResolutionException |
| */ |
| public static final String ALLOW_PROXYING_PARAM = "jakarta.enterprise.inject.allowProxying.classes"; |
| |
| /** |
| * Lifycycle methods like {@link jakarta.annotation.PostConstruct} and |
| * {@link jakarta.annotation.PreDestroy} must not define a checked Exception |
| * regarding to the spec. But this is often unnecessary restrictive so we |
| * allow to disable this check application wide. |
| */ |
| public static final String INTERCEPTOR_FORCE_NO_CHECKED_EXCEPTIONS = "org.apache.webbeans.forceNoCheckedExceptions"; |
| |
| /** |
| * Enable that calls to various methods get strictly validated. |
| * Defaults to 'false' for more performance. |
| */ |
| public static final String STRICT_DYNAMIC_VALIDATION = "org.apache.webbeans.strictDynamicValidation"; |
| |
| /**If generics should be taken into account for the matching*/ |
| public static final String FAST_MATCHING = "org.apache.webbeans.container.InjectionResolver.fastMatching"; |
| |
| /**Use EJB Discovery or not*/ |
| public static final String USE_EJB_DISCOVERY = "org.apache.webbeans.spi.deployer.useEjbMetaDataDiscoveryService"; |
| |
| /** |
| * The maximum number of threads to use for BeansDeployer validation of our beans. |
| * We detect how many CPU cores we do have and then for each 500 or so beans, we use a new thread. |
| * But we will always stay below the max number of CPU cores and configured maxThreads. |
| */ |
| public static final String BEANS_DEPLOYER_MAX_THREADS = "org.apache.webbeans.deployer.maxThreads"; |
| |
| /** |
| * The maximum number of threads to use for the ScannerService. |
| * We detect how many CPU cores we do have and use that as maximum threads or the configured maxThreads. |
| */ |
| public static final String SCANNER_SERVICE_MAX_THREADS = "org.apache.webbeans.scanner.maxThreads"; |
| |
| /**Container lifecycle*/ |
| public static final String CONTAINER_LIFECYCLE = "org.apache.webbeans.spi.ContainerLifecycle"; |
| |
| /**JNDI Service SPI*/ |
| public static final String JNDI_SERVICE = "org.apache.webbeans.spi.JNDIService"; |
| |
| /**Scanner Service*/ |
| public static final String SCANNER_SERVICE = "org.apache.webbeans.spi.ScannerService"; |
| |
| /**Contexts Service*/ |
| public static final String CONTEXTS_SERVICE = "org.apache.webbeans.spi.ContextsService"; |
| |
| /**Conversation Service*/ |
| public static final String CONVERSATION_SERVICE = "org.apache.webbeans.spi.ConversationService"; |
| |
| /**Resource Injection Service*/ |
| public static final String RESOURCE_INJECTION_SERVICE = "org.apache.webbeans.spi.ResourceInjectionService"; |
| |
| /**Security Service*/ |
| public static final String SECURITY_SERVICE = "org.apache.webbeans.spi.SecurityService"; |
| |
| /**Validator Service*/ |
| public static final String VALIDATOR_SERVICE = "org.apache.webbeans.spi.ValidatorService"; |
| |
| /**Transaction Service*/ |
| public static final String TRANSACTION_SERVICE = "org.apache.webbeans.spi.TransactionService"; |
| |
| /**Application is core JSP*/ |
| public static final String APPLICATION_IS_JSP = "org.apache.webbeans.application.jsp"; |
| |
| /** @Produces with interceptor/decorator support */ |
| public static final String PRODUCER_INTERCEPTION_SUPPORT = "org.apache.webbeans.application.supportsProducerInterception"; |
| |
| /**EL Adaptor*/ |
| public static final String EL_ADAPTOR_SERVICE = "org.apache.webbeans.spi.adaptor.ELAdaptor"; |
| |
| /** |
| * prefix followed by the fully qualified scope name, for configuring NormalScopedBeanInterceptorHandler |
| * for our proxies. |
| * |
| * The format is like the following: |
| * 'org.apache.webbeans.proxy.mapping.' followed by the scope annotation = a subclass of a NormalScopedBeanInterceptorHandler |
| * |
| * Example: |
| * <pre> |
| * org.apache.webbeans.proxy.mapping.jakarta.enterprise.context.ApplicationScoped=org.apache.webbeans.intercept.ApplicationScopedBeanInterceptorHandler |
| * org.apache.webbeans.proxy.mapping.jakarta.enterprise.context.RequestScoped=org.apache.webbeans.intercept.RequestScopedBeanInterceptorHandler |
| * org.apache.webbeans.proxy.mapping.jakarta.enterprise.context.SessionScoped=org.apache.webbeans.intercept.SessionScopedBeanInterceptorHandler |
| * </pre> |
| * |
| */ |
| public static final String PROXY_MAPPING_PREFIX = "org.apache.webbeans.proxy.mapping."; |
| |
| /** |
| * Use BDABeansXmlScanner to determine if interceptors, decorators, and |
| * alternatives are enabled in the beans.xml of a given BDA. For an |
| * application containing jar1 and jar2, this implies that an interceptor |
| * enabled in the beans.xml of jar1 is not automatically enabled in jar2 |
| * @deprecated as spec section 5 and 12 contradict each other and the BDA per jar handling is broken anyway |
| **/ |
| @Deprecated |
| public static final String USE_BDA_BEANSXML_SCANNER = "org.apache.webbeans.useBDABeansXMLScanner"; |
| |
| /** A list of known JARs/paths which should not be scanned for beans */ |
| public static final String SCAN_EXCLUSION_PATHS = "org.apache.webbeans.scanExclusionPaths"; |
| |
| /** |
| * Flag which indicates that only jars with an explicit META-INF/beans.xml marker file shall get parsed. |
| * Default is {@code false}. |
| * |
| * This might be switched on to improve boot time in cases where you always have beans.xml in |
| * your jars or classpath entries. |
| */ |
| public static final String SCAN_ONLY_BEANS_XML_JARS = "org.apache.webbeans.scanBeansXmlOnly"; |
| |
| /** |
| * a comma-separated list of fully qualified class names that should be ignored |
| * when determining if a decorator matches its delegate. These are typically added by |
| * weaving or bytecode modification. |
| */ |
| public static final String IGNORED_INTERFACES = "org.apache.webbeans.ignoredDecoratorInterfaces"; |
| |
| /** |
| * A comma-separated list of fully qualified class names of CDI Extensions that should be ignored. |
| * |
| * |
| */ |
| public static final String IGNORED_EXTENSIONS = "org.apache.webbeans.ignoredExtensions"; |
| |
| /** |
| * A boolean to enable CDI 1.1 behavior to not scan "extension JARs". |
| * "extensions JARs" are JARs, without a beans.xml but with CDI extensions. |
| * |
| * IMPORTANT: this can break CDI 1.0 extensions. |
| */ |
| public static final String SCAN_EXTENSION_JARS = "org.apache.webbeans.scanExtensionJars"; |
| |
| /** |
| * By default we do _not_ force session creation in our WebBeansConfigurationListener. We only create the |
| * Session if we really need the SessionContext. E.g. when we create a Contextual Instance in it. |
| * Sometimes this creates a problem as the HttpSession can only be created BEFORE anything got written back |
| * to the client. |
| * With this configuration you can choose between 3 settings |
| * <ul> |
| * <li>"true" the Session will <u>always</u> eagerly be created at the begin of a request</li> |
| * <li>"false" the Session will <u>never</u> eagerly be created but only lazily when the first @SessionScoped bean gets used</li> |
| * <li>any other value will be interpreted as Java regular expression for request URIs which need eager Session initialization</li> |
| * </ul> |
| */ |
| public static final String EAGER_SESSION_INITIALISATION = "org.apache.webbeans.web.eagerSessionInitialisation"; |
| |
| /** |
| * The Java Version to use for the generated proxy classes. |
| * If "auto" then we will pick the version of the current JVM. |
| * The default is set to "1.6" as some tools in jetty/tomcat/etc still |
| * cannot properly handle Java8 (mostly due to older Eclipse JDT versions). |
| */ |
| public static final String GENERATOR_JAVA_VERSION = "org.apache.webbeans.generator.javaVersion"; |
| |
| |
| /** |
| * Default bean discovery mode for empty beans.xml |
| * There was a really wicked change in the CDI-4.0 specification which will break many applications. |
| * They switched the bean-discovery-mode of an empty beans.xml file (or a beans.xml without any version) |
| * from ALL to ANNOTATED (Despite warnings that his is totally backward incompatible and could easily have been avoided). |
| * |
| * The default in OWB is still ALL, but it can be configured to any other bean-discovery-mode with this config switch |
| */ |
| public static final String DEFAULT_BEAN_DISCOVERY_MODE = "org.apache.webbeans.defaultBeanDiscoveryMode"; |
| |
| |
| |
| /**Default configuration files*/ |
| private static final String DEFAULT_CONFIG_PROPERTIES_NAME = "META-INF/openwebbeans/openwebbeans.properties"; |
| |
| /** |
| * A value which indicates an 'automatic' behaviour. |
| */ |
| private static final String AUTO_CONFIG = "auto"; |
| |
| /**Property of application*/ |
| private final Properties configProperties = new Properties(); |
| |
| |
| /** |
| * @see #IGNORED_INTERFACES |
| */ |
| private Set<String> ignoredInterfaces; |
| |
| /** |
| * @see #IGNORED_EXTENSIONS |
| */ |
| private Set<String> ignoredExtensions; |
| |
| /** |
| * @see #SCAN_EXTENSION_JARS |
| */ |
| private Boolean scanExtensionJars; |
| |
| /** |
| * All configured lists per key. |
| * |
| * For a single key the following configuration sources will get parsed: |
| * <ul> |
| * <li>all {@link #DEFAULT_CONFIG_PROPERTIES_NAME} files</li> |
| * <li>{@code System.getProperties()}</li> |
| * <li>{@code System.env()}</li> |
| * </ul> |
| * |
| * All the found values will get split by comma (',') and all trimmed values |
| * will get stored in a Set. |
| * |
| */ |
| private Map<String, Set<String>> configuredLists = new HashMap<>(); |
| |
| /** |
| * List of packages which can't be used to generate a proxy. |
| * |
| * Important: changing this default has runtime impacts on proxies name. |
| * It is recommended to not tune it until really needed. |
| * Also ensure it is consistent between generation and runtime if you use stable proxy names. |
| */ |
| private volatile List<String> proxyReservedPackages; |
| |
| |
| /** |
| * you can configure this externally as well. |
| * |
| * @param properties |
| */ |
| public OpenWebBeansConfiguration(Properties properties) |
| { |
| this(); |
| |
| // and override all settings with the given properties |
| configProperties.putAll(properties); |
| } |
| |
| /** |
| * Parse configuration. |
| */ |
| public OpenWebBeansConfiguration() |
| { |
| parseConfiguration(); |
| } |
| |
| |
| |
| /** |
| * (re)read the configuration from the resources in the classpath. |
| * @see #DEFAULT_CONFIG_PROPERTIES_NAME |
| * @see #DEFAULT_CONFIG_PROPERTIES_NAME |
| */ |
| public synchronized void parseConfiguration() throws WebBeansConfigurationException |
| { |
| Properties newConfigProperties = PropertyLoader.getProperties(DEFAULT_CONFIG_PROPERTIES_NAME); |
| |
| configProperties.clear(); |
| |
| // set the new one as perfect fit. |
| if(newConfigProperties != null) |
| { |
| overrideWithGlobalSettings(newConfigProperties); |
| |
| configProperties.putAll(newConfigProperties); |
| } |
| } |
| |
| /** |
| * Take the given commaSeparatedVals and spit them by ',' and trim them. |
| * @return all trimmed values or an empty list |
| */ |
| public List<String> splitValues(String commaSeparatedVals) |
| { |
| ArrayList<String> values = new ArrayList<>(); |
| if (commaSeparatedVals != null) |
| { |
| for (String value : commaSeparatedVals.split(",")) |
| { |
| value = value.trim(); |
| if (!value.isEmpty()) |
| { |
| values.add(value); |
| } |
| } |
| } |
| return values; |
| } |
| |
| private void overrideWithGlobalSettings(Properties configProperties) |
| { |
| Properties systemProperties = System.getProperties(); |
| |
| Map<String, String> systemEnvironment = System.getenv(); |
| |
| for (Map.Entry property : configProperties.entrySet()) |
| { |
| String key = (String) property.getKey(); |
| String value = (String) property.getValue(); |
| |
| value = systemProperties.getProperty(key) != null ? systemProperties.getProperty(key) : value; |
| |
| String envKey = key.replace('.', '_'); |
| value = systemEnvironment.get(envKey) != null ? systemEnvironment.get(envKey) : value; |
| |
| if (value != null) |
| { |
| configProperties.put(key, value); |
| } |
| } |
| } |
| |
| /** |
| * Gets property. |
| * @param key |
| * @return String with the property value or <code>null</code> |
| */ |
| public String getProperty(String key) |
| { |
| return configProperties.getProperty(key); |
| } |
| |
| /** |
| * Gets property value. |
| * @param key |
| * @param defaultValue |
| * @return String with the property value or <code>null</code> |
| */ |
| public String getProperty(String key,String defaultValue) |
| { |
| return configProperties.getProperty(key, defaultValue); |
| } |
| |
| |
| /** |
| * Sets given property. |
| * @param key property name |
| * @param value property value |
| */ |
| public synchronized void setProperty(String key, Object value) |
| { |
| configProperties.put(key, value); |
| } |
| |
| |
| /** |
| * Gets jsp property. |
| * @return true if jsp |
| */ |
| public boolean isJspApplication() |
| { |
| String value = getProperty(APPLICATION_IS_JSP); |
| |
| return Boolean.valueOf(value); |
| } |
| |
| /** |
| * Flag which indicates that only jars with an explicit META-INF/beans.xml marker file shall get paresed. |
| * Default is {@code false} |
| */ |
| public boolean scanOnlyBeansXmlJars() |
| { |
| String value = getProperty(SCAN_ONLY_BEANS_XML_JARS); |
| return "true".equalsIgnoreCase(value); |
| } |
| |
| /** |
| * Flag which indicates that programmatic invocations to vaious BeanManager methods |
| * should get strictly validated. |
| * E.g. whether qualifier parameters are really qualifiers, etc. |
| * Default is {@code false} |
| */ |
| public boolean strictDynamicValidation() |
| { |
| String value = getProperty(STRICT_DYNAMIC_VALIDATION); |
| return "true".equalsIgnoreCase(value); |
| } |
| |
| public synchronized Set<String> getIgnoredInterfaces() |
| { |
| if (ignoredInterfaces == null) |
| { |
| ignoredInterfaces = getPropertyList(IGNORED_INTERFACES); |
| } |
| return ignoredInterfaces; |
| } |
| |
| public synchronized Set<String> getIgnoredExtensions() |
| { |
| if (ignoredExtensions == null) |
| { |
| ignoredExtensions = getPropertyList(IGNORED_EXTENSIONS); |
| } |
| return ignoredExtensions; |
| } |
| |
| public synchronized boolean getScanExtensionJars() |
| { |
| if (scanExtensionJars == null) |
| { |
| final String property = getProperty(SCAN_EXTENSION_JARS); |
| // default must stay true for backward compatibility |
| scanExtensionJars = property == null || Boolean.parseBoolean(property.trim()); |
| } |
| return scanExtensionJars; |
| } |
| |
| private Set<String> getPropertyList(String configKey) |
| { |
| String configValue = getProperty(configKey); |
| if (configValue != null) |
| { |
| return new HashSet<>(Arrays.asList(configValue.split("[,\\p{javaWhitespace}]"))); |
| } |
| return Collections.emptySet(); |
| } |
| |
| /** |
| * Scan all openwebbeans.properties files + system properties + |
| * syste.env for the given key. |
| * If the key is comma separated then use the separate tokens. |
| * All the values get put into a big set. |
| */ |
| public synchronized Set<String> getConfigListValues(String keyName) |
| { |
| Set<String> allValues = configuredLists.get(keyName); |
| if (allValues != null) |
| { |
| return allValues; |
| } |
| |
| allValues = new HashSet<>(); |
| try |
| { |
| List<Properties> properties = PropertyLoader.loadAllProperties(DEFAULT_CONFIG_PROPERTIES_NAME); |
| if (properties != null) |
| { |
| for (Properties property : properties) |
| { |
| String values = (String) property.get(keyName); |
| allValues.addAll(splitValues(values)); |
| } |
| } |
| } |
| catch (IOException e) |
| { |
| WebBeansLoggerFacade.getLogger(OpenWebBeansConfiguration.class) |
| .log(Level.SEVERE, "Error while loading the propertyFile " + DEFAULT_CONFIG_PROPERTIES_NAME, e); |
| return Collections.EMPTY_SET; |
| } |
| |
| // search for the key in the properties |
| String value = System.getProperty(keyName); |
| allValues.addAll(splitValues(value)); |
| |
| // search for the key in the environment |
| String envKeyName = keyName.toUpperCase().replace(".", "_"); |
| value = System.getenv(envKeyName); |
| allValues.addAll(splitValues(value)); |
| |
| configuredLists.put(keyName, allValues); |
| |
| return allValues; |
| } |
| |
| /** |
| * Add a configuration value to the Set of configured values registered |
| * under the keyName. |
| * |
| * Calling this method ensures that all the configured values are first |
| * read from the environment and configuration properties. |
| * |
| * @see #getConfigListValues(String) get's called internally to insure the list is initialised |
| */ |
| public synchronized void addConfigListValue(String keyName, String value) |
| { |
| Set<String> configListValues = getConfigListValues(keyName); |
| configListValues.add(value); |
| } |
| |
| public boolean supportsInterceptionOnProducers() |
| { |
| return Boolean.parseBoolean(getProperty(PRODUCER_INTERCEPTION_SUPPORT, "true")); |
| } |
| |
| public String getGeneratorJavaVersion() |
| { |
| String generatorJavaVersion = getProperty(GENERATOR_JAVA_VERSION); |
| if (generatorJavaVersion == null || AUTO_CONFIG.equals(generatorJavaVersion)) |
| { |
| return System.getProperty("java.version"); |
| } |
| |
| return generatorJavaVersion; |
| } |
| |
| public boolean isSkipNoClassDefFoundErrorTriggers() |
| { |
| return Boolean.parseBoolean(getProperty( |
| "org.apache.webbeans.spi.deployer.skipNoClassDefFoundTriggers")); |
| } |
| |
| public List<String> getProxyReservedPackages() |
| { |
| if (proxyReservedPackages == null) |
| { |
| synchronized (this) |
| { |
| if (proxyReservedPackages == null) |
| { |
| final String conf = getProperty("org.apache.webbeans.generator.proxyReservedPackages"); |
| if (conf == null) |
| { |
| proxyReservedPackages = asList("java.", "javax.", "jakarta.", "sun.misc."); |
| } |
| else |
| { |
| proxyReservedPackages = Stream.concat( |
| Stream.of("java.", "javax.", "jakarta.", "sun.misc."), |
| Stream.of(conf.split(",")) |
| .map(String::trim) |
| .filter(it -> !it.isEmpty())) |
| .distinct() |
| .collect(toList()); |
| } |
| } |
| } |
| } |
| return proxyReservedPackages; |
| } |
| |
| /** |
| * @see #DEFAULT_BEAN_DISCOVERY_MODE |
| */ |
| public BeanArchiveService.BeanDiscoveryMode getDefaultBeanDiscoveryMode() |
| { |
| return BeanArchiveService.BeanDiscoveryMode.valueOf(getProperty(OpenWebBeansConfiguration.DEFAULT_BEAN_DISCOVERY_MODE)); |
| } |
| |
| public int getBeanDeployerMaxThreads() |
| { |
| final String maxThreadsStr = getProperty(OpenWebBeansConfiguration.BEANS_DEPLOYER_MAX_THREADS); |
| return maxThreadsStr == null ? Integer.MAX_VALUE : Integer.parseInt(maxThreadsStr.trim()); |
| } |
| |
| public int getScannerServiceMaxThreads() |
| { |
| final String maxThreadsStr = getProperty(OpenWebBeansConfiguration.SCANNER_SERVICE_MAX_THREADS); |
| return maxThreadsStr == null ? Integer.MAX_VALUE : Integer.parseInt(maxThreadsStr.trim()); |
| } |
| } |