WW-4875 Add ability to use Java based configuration

This commit is contained in:
Aleksandr Mashchenko
2017-10-24 22:27:51 +03:00
parent e9fe38608a
commit 0a86e4fe16
5 changed files with 1616 additions and 0 deletions
@@ -0,0 +1,32 @@
/*
* 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.struts2.config;
import java.util.List;
import org.apache.struts2.config.entities.BeanConfig;
import org.apache.struts2.config.entities.ConstantConfig;
public interface StrutsJavaConfiguration {
List<BeanConfig> beans();
List<ConstantConfig> constants();
List<String> unknownHandlerStack();
}
@@ -0,0 +1,174 @@
/*
* 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.struts2.config;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.config.entities.BeanConfig;
import org.apache.struts2.config.entities.ConstantConfig;
import com.opensymphony.xwork2.config.Configuration;
import com.opensymphony.xwork2.config.ConfigurationException;
import com.opensymphony.xwork2.config.ConfigurationProvider;
import com.opensymphony.xwork2.config.entities.UnknownHandlerConfig;
import com.opensymphony.xwork2.config.impl.LocatableFactory;
import com.opensymphony.xwork2.config.providers.ValueSubstitutor;
import com.opensymphony.xwork2.inject.ContainerBuilder;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.util.location.LocatableProperties;
import com.opensymphony.xwork2.util.location.Location;
import com.opensymphony.xwork2.util.location.LocationUtils;
public class StrutsJavaConfigurationProvider implements ConfigurationProvider {
private static final Logger LOG = LogManager.getLogger(StrutsJavaConfigurationProvider.class);
private final StrutsJavaConfiguration javaConfig;
private Configuration configuration;
private boolean throwExceptionOnDuplicateBeans = true;
private ValueSubstitutor valueSubstitutor;
public StrutsJavaConfigurationProvider(StrutsJavaConfiguration javaConfig) {
this.javaConfig = javaConfig;
}
public void setThrowExceptionOnDuplicateBeans(boolean val) {
this.throwExceptionOnDuplicateBeans = val;
}
@Inject(required = false)
public void setValueSubstitutor(ValueSubstitutor valueSubstitutor) {
this.valueSubstitutor = valueSubstitutor;
}
@Override
public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException {
Map<String, Object> loadedBeans = new HashMap<>();
// bean
List<BeanConfig> beanConfigs = javaConfig.beans();
if (beanConfigs != null) {
for (BeanConfig bc : beanConfigs) {
if (bc != null) {
registerBean(loadedBeans, builder, bc);
}
}
}
// constant
List<ConstantConfig> constantConfigList = javaConfig.constants();
if (constantConfigList != null) {
for (ConstantConfig constantConf : constantConfigList) {
if (constantConf != null) {
Map<String, String> constantMap = constantConf.getAllAsStringsMap();
for (Entry<String, String> entr : constantMap.entrySet()) {
if (entr.getKey() != null && entr.getValue() != null) {
registerConstant(props, entr.getKey(), entr.getValue());
}
}
}
}
}
// unknown-handler-stack
List<String> unknownHandlers = javaConfig.unknownHandlerStack();
if (unknownHandlers != null) {
List<UnknownHandlerConfig> unknownHandlerStack = new ArrayList<>();
for (String unknownHandler : unknownHandlers) {
Location location = LocationUtils.getLocation(unknownHandler);
unknownHandlerStack.add(new UnknownHandlerConfig(unknownHandler, location));
}
if (!unknownHandlerStack.isEmpty()) {
configuration.setUnknownHandlerStack(unknownHandlerStack);
}
}
}
private void registerConstant(LocatableProperties props, String key, String value) {
if (valueSubstitutor != null) {
LOG.debug("Substituting value [{}] using [{}]", value, valueSubstitutor.getClass().getName());
value = valueSubstitutor.substitute(value);
}
props.setProperty(key, value, javaConfig);
}
private void registerBean(Map<String, Object> loadedBeans, ContainerBuilder containerBuilder, BeanConfig beanConf) {
try {
if (beanConf.isOnlyStatic()) {
// Force loading of class to detect no class def found
// exceptions
beanConf.getClazz().getDeclaredClasses();
containerBuilder.injectStatics(beanConf.getClazz());
} else {
if (containerBuilder.contains(beanConf.getType(), beanConf.getName())) {
Location loc = LocationUtils
.getLocation(loadedBeans.get(beanConf.getType().getName() + beanConf.getName()));
if (throwExceptionOnDuplicateBeans) {
throw new ConfigurationException("Bean type " + beanConf.getType() + " with the name "
+ beanConf.getName() + " has already been loaded by " + loc);
}
}
// Force loading of class to detect no class def found
// exceptions
beanConf.getClazz().getDeclaredConstructors();
LOG.debug("Loaded type: {} name: {} clazz: {}", beanConf.getType(), beanConf.getName(),
beanConf.getClazz());
containerBuilder.factory(
beanConf.getType(), beanConf.getName(), new LocatableFactory(beanConf.getName(),
beanConf.getType(), beanConf.getClazz(), beanConf.getScope(), javaConfig),
beanConf.getScope());
}
loadedBeans.put(beanConf.getType().getName() + beanConf.getName(), javaConfig);
} catch (Throwable ex) {
if (!beanConf.isOptional()) {
throw new ConfigurationException(
"Unable to load bean: type:" + beanConf.getType() + " class:" + beanConf.getClazz(), ex);
} else {
LOG.debug("Unable to load optional class: {}", beanConf.getClazz());
}
}
}
@Override
public void init(Configuration configuration) throws ConfigurationException {
this.configuration = configuration;
}
@Override
public boolean needsReload() {
return false;
}
@Override
public void loadPackages() throws ConfigurationException {
}
@Override
public void destroy() {
}
}
@@ -0,0 +1,76 @@
/*
* 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.struts2.config.entities;
import com.opensymphony.xwork2.inject.Container;
import com.opensymphony.xwork2.inject.Scope;
public class BeanConfig {
private final Class<?> clazz;
private final String name;
private final Class<?> type;
private final Scope scope;
private final boolean onlyStatic;
private final boolean optional;
public BeanConfig(Class<?> clazz) {
this(clazz, Container.DEFAULT_NAME);
}
public BeanConfig(Class<?> clazz, String name) {
this(clazz, name, clazz);
}
public BeanConfig(Class<?> clazz, String name, Class<?> type) {
this(clazz, name, type, Scope.SINGLETON, false, false);
}
public BeanConfig(Class<?> clazz, String name, Class<?> type, Scope scope, boolean onlyStatic, boolean optional) {
this.clazz = clazz;
this.name = name;
this.type = type;
this.scope = scope;
this.onlyStatic = onlyStatic;
this.optional = optional;
}
public Class<?> getClazz() {
return clazz;
}
public String getName() {
return name;
}
public Class<?> getType() {
return type;
}
public Scope getScope() {
return scope;
}
public boolean isOnlyStatic() {
return onlyStatic;
}
public boolean isOptional() {
return optional;
}
}
File diff suppressed because it is too large Load Diff
@@ -48,6 +48,8 @@ import org.apache.struts2.StrutsStatics;
import org.apache.struts2.config.DefaultBeanSelectionProvider;
import org.apache.struts2.config.DefaultPropertiesProvider;
import org.apache.struts2.config.PropertiesConfigurationProvider;
import org.apache.struts2.config.StrutsJavaConfiguration;
import org.apache.struts2.config.StrutsJavaConfigurationProvider;
import org.apache.struts2.config.StrutsXmlConfigurationProvider;
import org.apache.struts2.dispatcher.mapper.ActionMapping;
import org.apache.struts2.dispatcher.multipart.MultiPartRequest;
@@ -411,6 +413,30 @@ public class Dispatcher {
return new StrutsXmlConfigurationProvider(filename, errorIfMissing, ctx);
}
private void init_JavaConfigurations() {
String configClasses = initParams.get("javaConfigClasses");
if (configClasses != null) {
String[] classes = configClasses.split("\\s*[,]\\s*");
for (String cname : classes) {
try {
Class cls = ClassLoaderUtil.loadClass(cname, this.getClass());
StrutsJavaConfiguration config = (StrutsJavaConfiguration) cls.newInstance();
configurationManager.addContainerProvider(createJavaConfigurationProvider(config));
} catch (InstantiationException e) {
throw new ConfigurationException("Unable to instantiate java configuration: " + cname, e);
} catch (IllegalAccessException e) {
throw new ConfigurationException("Unable to access java configuration: " + cname, e);
} catch (ClassNotFoundException e) {
throw new ConfigurationException("Unable to locate java configuration class: " + cname, e);
}
}
}
}
protected StrutsJavaConfigurationProvider createJavaConfigurationProvider(StrutsJavaConfiguration config) {
return new StrutsJavaConfigurationProvider(config);
}
private void init_CustomConfigurationProviders() {
String configProvs = initParams.get("configProviders");
if (configProvs != null) {
@@ -488,6 +514,7 @@ public class Dispatcher {
init_FileManager();
init_DefaultProperties(); // [1]
init_TraditionalXmlConfigurations(); // [2]
init_JavaConfigurations();
init_LegacyStrutsProperties(); // [3]
init_CustomConfigurationProviders(); // [5]
init_FilterInitParameters() ; // [6]