Fast forward existing prototype work
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap;
|
||||
|
||||
import java.io.PrintStream;
|
||||
|
||||
/**
|
||||
* Writes the 'Spring Bootstrap' banner.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
abstract class Banner {
|
||||
|
||||
private static final String[] BANNER = {
|
||||
" . ____ _ ____ _ _ __ _ ",
|
||||
" /\\\\ / ___'_ __ _ _(_)_ __ __ _| __ ) ___ ___| |_ ___| |_ _ _ __ _ _ __\\ \\ \\ ",
|
||||
"( ( )\\___ | '_ | '_| | '_ \\/ _` | _ \\/ _ \\/ _ | __/ __| __| '_/ _` | '_ \\\\ \\ \\ ",
|
||||
" \\\\/ ___)| |_)| | | | | || (_| | |_)| (_)| (_)| |_\\__ | |_| || (_| | |_) |} } }",
|
||||
" ' |____| .__|_| |_|_| |_\\__, |____/\\___/\\___/\\__|___/\\__|_| \\__,_| .__// / / ",
|
||||
" =========|_|==============|___/====================================|_|==/_/_/ " };
|
||||
|
||||
/**
|
||||
* Write the banner to the specified print stream.
|
||||
* @param printStream the output print stream
|
||||
*/
|
||||
public static void write(PrintStream printStream) {
|
||||
System.out.println();
|
||||
for (String line : BANNER) {
|
||||
printStream.println(line);
|
||||
}
|
||||
System.out.println();
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.BeanNameGenerator;
|
||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
|
||||
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
|
||||
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.type.filter.AbstractTypeHierarchyTraversingFilter;
|
||||
import org.springframework.core.type.filter.TypeFilter;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Loads bean definitions from underlying sources, including XML and JavaConfig. Acts as a
|
||||
* simple facade over {@link AnnotatedBeanDefinitionReader},
|
||||
* {@link XmlBeanDefinitionReader} and {@link ClassPathBeanDefinitionScanner}. See
|
||||
* {@link SpringApplication} for the types of sources that are supported.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @see #setBeanNameGenerator(BeanNameGenerator)
|
||||
*/
|
||||
class BeanDefinitionLoader {
|
||||
|
||||
private static final ResourceLoader DEFAULT_RESOURCE_LOADER = new DefaultResourceLoader();
|
||||
|
||||
private Object[] sources;
|
||||
|
||||
private AnnotatedBeanDefinitionReader annotatedReader;
|
||||
|
||||
private XmlBeanDefinitionReader xmlReader;
|
||||
|
||||
private ClassPathBeanDefinitionScanner scanner;
|
||||
|
||||
private ResourceLoader resourceLoader;
|
||||
|
||||
/**
|
||||
* Create a new {@link BeanDefinitionLoader} that will load beans into the specified
|
||||
* {@link BeanDefinitionRegistry}.
|
||||
* @param registry the bean definition registry that will contain the loaded beans
|
||||
* @param sources the bean sources
|
||||
*/
|
||||
public BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
|
||||
Assert.notNull(registry, "Registry must not be null");
|
||||
Assert.notEmpty(sources, "Sources must not be empty");
|
||||
this.sources = sources;
|
||||
this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
|
||||
this.xmlReader = new XmlBeanDefinitionReader(registry);
|
||||
this.scanner = new ClassPathBeanDefinitionScanner(registry);
|
||||
this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bean name generator to be used by the underlying readers and scanner.
|
||||
* @param beanNameGenerator the bean name generator
|
||||
*/
|
||||
public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
|
||||
this.annotatedReader.setBeanNameGenerator(beanNameGenerator);
|
||||
this.xmlReader.setBeanNameGenerator(beanNameGenerator);
|
||||
this.scanner.setBeanNameGenerator(beanNameGenerator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the resource loader to be used by the underlying readers and scanner.
|
||||
* @param resourceLoader the resource loader
|
||||
*/
|
||||
public void setResourceLoader(ResourceLoader resourceLoader) {
|
||||
this.resourceLoader = resourceLoader;
|
||||
this.xmlReader.setResourceLoader(resourceLoader);
|
||||
this.scanner.setResourceLoader(resourceLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the environment to be used by the underlying readers and scanner.
|
||||
* @param environment
|
||||
*/
|
||||
public void setEnvironment(ConfigurableEnvironment environment) {
|
||||
this.annotatedReader.setEnvironment(environment);
|
||||
this.xmlReader.setEnvironment(environment);
|
||||
this.scanner.setEnvironment(environment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the sources into the reader.
|
||||
* @return the number of loaded beans
|
||||
*/
|
||||
public int load() {
|
||||
int count = 0;
|
||||
for (Object source : this.sources) {
|
||||
count += load(source);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private int load(Object source) {
|
||||
Assert.notNull(source, "Source must not be null");
|
||||
if (source instanceof Class<?>) {
|
||||
this.annotatedReader.register((Class<?>) source);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (source instanceof Resource) {
|
||||
return this.xmlReader.loadBeanDefinitions((Resource) source);
|
||||
}
|
||||
|
||||
if (source instanceof Package) {
|
||||
// FIXME register the scanned package for data to pick up
|
||||
return this.scanner.scan(((Package) source).getName());
|
||||
}
|
||||
|
||||
if (source instanceof CharSequence) {
|
||||
try {
|
||||
return load(Class.forName(source.toString()));
|
||||
} catch (ClassNotFoundException e) {
|
||||
}
|
||||
|
||||
Resource loadedResource = (this.resourceLoader != null ? this.resourceLoader
|
||||
: DEFAULT_RESOURCE_LOADER).getResource(source.toString());
|
||||
if (loadedResource != null && loadedResource.exists()) {
|
||||
return load(loadedResource);
|
||||
}
|
||||
Package packageResource = Package.getPackage(source.toString());
|
||||
if (packageResource != null) {
|
||||
return load(packageResource);
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Invalid source '" + source + "'");
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple {@link TypeFilter} used to ensure that specified {@link Class} sources are
|
||||
* not accidentally re-added during scanning.
|
||||
*/
|
||||
private static class ClassExcludeFilter extends AbstractTypeHierarchyTraversingFilter {
|
||||
|
||||
private Set<String> classNames = new HashSet<String>();
|
||||
|
||||
public ClassExcludeFilter(Object... sources) {
|
||||
super(false, false);
|
||||
for (Object source : sources) {
|
||||
if (source instanceof Class<?>) {
|
||||
this.classNames.add(((Class<?>) source).getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean matchClassName(String className) {
|
||||
return this.classNames.contains(className);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap;
|
||||
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
||||
/**
|
||||
* Interface used to indicate that a bean should <em>run</em> when it is contained within
|
||||
* a {@link SpringApplication}. Multiple {@link CommandLineRunner} beans can be defined
|
||||
* within the same application context and can be ordered using the {@link Ordered}
|
||||
* interface or {@link Order @Order} annotation.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public interface CommandLineRunner {
|
||||
|
||||
/**
|
||||
* Callback used to run the bean.
|
||||
* @param args incoming main method arguments
|
||||
*/
|
||||
void run(String... args);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,266 @@
|
||||
/*
|
||||
* Copyright 2010-2012 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.bootstrap.config.YamlProcessor.ArrayDocumentMatcher;
|
||||
import org.springframework.bootstrap.config.YamlProcessor.DocumentMatcher;
|
||||
import org.springframework.bootstrap.config.YamlPropertiesFactoryBean;
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.env.CommandLinePropertySource;
|
||||
import org.springframework.core.env.MutablePropertySources;
|
||||
import org.springframework.core.env.PropertiesPropertySource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.PropertiesLoaderUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link ApplicationContextInitializer} that configures the context environment by
|
||||
* loading properties from well known file locations. By default properties will be loaded
|
||||
* from 'application.properties' and/or 'application.yaml' files in the following
|
||||
* locations:
|
||||
* <ul>
|
||||
* <li>classpath:</li>
|
||||
* <li>file:./</li>
|
||||
* <li>classpath:config/</li>
|
||||
* <li>file:./config/:</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Alternative locations and names can be specified using
|
||||
* {@link #setSearchLocations(String[])} and {@link #setName(String)}.
|
||||
*
|
||||
* <p>
|
||||
* Additional files will also be loaded based on active profiles. For example if a 'web'
|
||||
* profile is active 'application-web.properties' and 'application-web.yaml' will be
|
||||
* considered.
|
||||
*
|
||||
* <p>
|
||||
* The 'spring.config.name' property can be used to specify an alternative name to load or
|
||||
* alternatively the 'spring.config.location' property can be used to specify an exact
|
||||
* resource location.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class ConfigFileApplicationContextInitializer implements
|
||||
ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
|
||||
|
||||
private static final Loader[] LOADERS = { new PropertiesLoader(), new YamlLoader() };
|
||||
|
||||
private static final String LOCATION_VARIABLE = "${spring.config.location}";
|
||||
|
||||
private String[] searchLocations = new String[] { "classpath:", "file:./",
|
||||
"classpath:config/", "file:./config/" };
|
||||
|
||||
private String name = "${spring.config.name:application}";
|
||||
|
||||
private int order = Integer.MIN_VALUE;
|
||||
|
||||
@Override
|
||||
public void initialize(ConfigurableApplicationContext applicationContext) {
|
||||
List<String> candidates = getCandidateLocations(applicationContext);
|
||||
|
||||
// Initial load allows profiles to be activated
|
||||
for (String candidate : candidates) {
|
||||
load(applicationContext, candidate, null);
|
||||
}
|
||||
|
||||
// Second load for specific profiles
|
||||
for (String profile : applicationContext.getEnvironment().getActiveProfiles()) {
|
||||
for (String candidate : candidates) {
|
||||
load(applicationContext, candidate, profile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> getCandidateLocations(
|
||||
ConfigurableApplicationContext applicationContext) {
|
||||
List<String> candidates = new ArrayList<String>();
|
||||
for (String searchLocation : this.searchLocations) {
|
||||
for (Loader loader : LOADERS) {
|
||||
for (String extension : loader.getExtensions()) {
|
||||
String location = searchLocation + this.name + extension;
|
||||
candidates.add(location);
|
||||
}
|
||||
}
|
||||
}
|
||||
candidates.add(LOCATION_VARIABLE);
|
||||
return candidates;
|
||||
}
|
||||
|
||||
private void load(ConfigurableApplicationContext applicationContext, String location,
|
||||
String profile) {
|
||||
location = applicationContext.getEnvironment().resolvePlaceholders(location);
|
||||
String suffix = "." + StringUtils.getFilenameExtension(location);
|
||||
if (StringUtils.hasLength(profile)) {
|
||||
location = location.replace(suffix, "-" + profile + suffix);
|
||||
}
|
||||
for (Loader loader : LOADERS) {
|
||||
if (loader.getExtensions().contains(suffix.toLowerCase())) {
|
||||
Resource resource = applicationContext.getResource(location);
|
||||
if (resource != null && resource.exists()) {
|
||||
loader.load(resource, applicationContext);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setOrder(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return this.order;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the file that should be loaded (excluding any file extension).
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the search locations that will be considered.
|
||||
*/
|
||||
public void setSearchLocations(String[] searchLocations) {
|
||||
this.searchLocations = searchLocations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strategy interface used to load a {@link PropertySource}.
|
||||
*/
|
||||
private static interface Loader {
|
||||
|
||||
/**
|
||||
* @return The supported extensions (including '.' and in lowercase)
|
||||
*/
|
||||
public Set<String> getExtensions();
|
||||
|
||||
/**
|
||||
* Load the resource into the destination application context.
|
||||
*/
|
||||
void load(Resource resource, ConfigurableApplicationContext applicationContext);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Strategy to load '.properties' files.
|
||||
*/
|
||||
private static class PropertiesLoader implements Loader {
|
||||
|
||||
@Override
|
||||
public Set<String> getExtensions() {
|
||||
return Collections.singleton(".properties");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(Resource resource,
|
||||
ConfigurableApplicationContext applicationContext) {
|
||||
try {
|
||||
Properties properties = loadProperties(resource, applicationContext);
|
||||
MutablePropertySources propertySources = applicationContext
|
||||
.getEnvironment().getPropertySources();
|
||||
if (propertySources
|
||||
.contains(CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME)) {
|
||||
propertySources.addAfter(
|
||||
CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME,
|
||||
new PropertiesPropertySource(resource.getDescription(),
|
||||
properties));
|
||||
|
||||
} else {
|
||||
propertySources.addFirst(new PropertiesPropertySource(resource
|
||||
.getDescription(), properties));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("Could not load properties file from "
|
||||
+ resource, e);
|
||||
}
|
||||
}
|
||||
|
||||
protected Properties loadProperties(Resource resource,
|
||||
ConfigurableApplicationContext applicationContext) throws IOException {
|
||||
return PropertiesLoaderUtils.loadProperties(resource);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Strategy to load '.yml' files.
|
||||
*/
|
||||
private static class YamlLoader extends PropertiesLoader {
|
||||
|
||||
@Override
|
||||
public Set<String> getExtensions() {
|
||||
return Collections.singleton(".yml");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Properties loadProperties(final Resource resource,
|
||||
final ConfigurableApplicationContext applicationContext)
|
||||
throws IOException {
|
||||
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
|
||||
List<DocumentMatcher> matchers = new ArrayList<DocumentMatcher>();
|
||||
matchers.add(new DocumentMatcher() {
|
||||
@Override
|
||||
public boolean matches(Properties properties) {
|
||||
String[] profiles = applicationContext.getEnvironment()
|
||||
.getActiveProfiles();
|
||||
if (profiles.length > 0) {
|
||||
return new ArrayDocumentMatcher("spring.profiles", profiles)
|
||||
.matches(properties);
|
||||
} else {
|
||||
return properties.getProperty("spring.profiles", "NONE")
|
||||
.contains("default");
|
||||
}
|
||||
}
|
||||
});
|
||||
matchers.add(new DocumentMatcher() {
|
||||
@Override
|
||||
public boolean matches(Properties properties) {
|
||||
if (!properties.containsKey("spring.profiles")) {
|
||||
Set<String> profiles = StringUtils
|
||||
.commaDelimitedListToSet(properties.getProperty(
|
||||
"spring.profiles.active", ""));
|
||||
for (String profile : profiles) {
|
||||
// allow document with no profile to set the active one
|
||||
applicationContext.getEnvironment().addActiveProfile(profile);
|
||||
}
|
||||
// matches default profile
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
factory.setMatchDefault(false);
|
||||
factory.setDocumentMatchers(matchers);
|
||||
factory.setResources(new Resource[] { resource });
|
||||
return factory.getObject();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.context.ApplicationContextException;
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.GenericTypeResolver;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link ApplicationContextInitializer} that delegates to other initializers that are
|
||||
* specified under a {@literal context.initializer.classes} environment property.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class EnvironmentDelegateApplicationContextInitializer implements
|
||||
ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
|
||||
|
||||
// NOTE: Similar to org.springframework.web.context.ContextLoader
|
||||
|
||||
private static final String PROPERTY_NAME = "context.initializer.classes";
|
||||
private int order = 0;
|
||||
|
||||
@Override
|
||||
public void initialize(ConfigurableApplicationContext applicationContext) {
|
||||
ConfigurableEnvironment env = applicationContext.getEnvironment();
|
||||
List<Class<ApplicationContextInitializer<ConfigurableApplicationContext>>> initializerClasses = determineContextInitializerClasses(env);
|
||||
|
||||
if (initializerClasses.size() == 0) {
|
||||
// no ApplicationContextInitializers have been declared -> nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
Class<?> contextClass = applicationContext.getClass();
|
||||
ArrayList<ApplicationContextInitializer<ConfigurableApplicationContext>> initializerInstances = new ArrayList<ApplicationContextInitializer<ConfigurableApplicationContext>>();
|
||||
|
||||
for (Class<ApplicationContextInitializer<ConfigurableApplicationContext>> initializerClass : initializerClasses) {
|
||||
Class<?> initializerContextClass = GenericTypeResolver.resolveTypeArgument(
|
||||
initializerClass, ApplicationContextInitializer.class);
|
||||
Assert.isAssignable(
|
||||
initializerContextClass,
|
||||
contextClass,
|
||||
String.format(
|
||||
"Could not add context initializer [%s] as its generic parameter [%s] "
|
||||
+ "is not assignable from the type of application context used by this "
|
||||
+ "context loader [%s]: ",
|
||||
initializerClass.getName(),
|
||||
initializerContextClass.getName(), contextClass.getName()));
|
||||
initializerInstances.add(BeanUtils.instantiateClass(initializerClass));
|
||||
}
|
||||
|
||||
Collections.sort(initializerInstances, new AnnotationAwareOrderComparator());
|
||||
for (ApplicationContextInitializer<ConfigurableApplicationContext> initializer : initializerInstances) {
|
||||
initializer.initialize(applicationContext);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private List<Class<ApplicationContextInitializer<ConfigurableApplicationContext>>> determineContextInitializerClasses(
|
||||
ConfigurableEnvironment env) {
|
||||
String classNames = env.getProperty(PROPERTY_NAME);
|
||||
List<Class<ApplicationContextInitializer<ConfigurableApplicationContext>>> classes = new ArrayList<Class<ApplicationContextInitializer<ConfigurableApplicationContext>>>();
|
||||
if (StringUtils.hasLength(classNames)) {
|
||||
for (String className : StringUtils.tokenizeToStringArray(classNames, ",")) {
|
||||
try {
|
||||
Class<?> clazz = ClassUtils.forName(className,
|
||||
ClassUtils.getDefaultClassLoader());
|
||||
Assert.isAssignable(ApplicationContextInitializer.class, clazz,
|
||||
"class [" + className
|
||||
+ "] must implement ApplicationContextInitializer");
|
||||
classes.add((Class<ApplicationContextInitializer<ConfigurableApplicationContext>>) clazz);
|
||||
} catch (ClassNotFoundException ex) {
|
||||
throw new ApplicationContextException(
|
||||
"Failed to load context initializer class [" + className
|
||||
+ "]", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
return classes;
|
||||
}
|
||||
|
||||
public void setOrder(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return this.order;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,507 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.BeanNameGenerator;
|
||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
|
||||
import org.springframework.bootstrap.context.embedded.AnnotationConfigEmbeddedWebApplicationContext;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigUtils;
|
||||
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.context.support.AbstractApplicationContext;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.core.GenericTypeResolver;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.core.env.CommandLinePropertySource;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.SimpleCommandLinePropertySource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||
import org.springframework.core.type.StandardAnnotationMetadata;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.web.context.ConfigurableWebApplicationContext;
|
||||
|
||||
/**
|
||||
* Classes that can be used to bootstrap and launch a Spring application from a Java main
|
||||
* method. By default class will perform the following steps to bootstrap your
|
||||
* application:
|
||||
*
|
||||
* <ul>
|
||||
* <li>Create an appropriate {@link ApplicationContext} instance (
|
||||
* {@link AnnotationConfigApplicationContext} or
|
||||
* {@link AnnotationConfigEmbeddedWebApplicationContext} depending on your classpath)</li>
|
||||
*
|
||||
* <li>Register a {@link CommandLinePropertySource} to expose command line arguments as
|
||||
* Spring properties</li>
|
||||
*
|
||||
* <li>Refresh the application context, loading all singleton beans</li>
|
||||
*
|
||||
* <li>Trigger any {@link CommandLineRunner} beans</li>
|
||||
* </ul>
|
||||
*
|
||||
* In most circumstances the static {@link #run(Object, String[])} method can be called
|
||||
* directly from your {@literal main} method to bootstrap your application:
|
||||
*
|
||||
* <pre class="code">
|
||||
* @Configuration
|
||||
* @EnableAutoConfiguration
|
||||
* public class MyApplication {
|
||||
*
|
||||
* // ... Bean definitions
|
||||
*
|
||||
* public static void main(String[] args) throws Exception {
|
||||
* SpringApplication.run(MyApplication.class, args);
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* For more advanced configuration a {@link SpringApplication} instance can be created and
|
||||
* customized before being run:
|
||||
*
|
||||
* <pre class="code">
|
||||
* public static void main(String[] args) throws Exception {
|
||||
* SpringApplication app = new SpringApplication(MyApplication.class);
|
||||
* // ... customize app settings here
|
||||
* app.run(args)
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* {@link SpringApplication}s can read beans from a variety of different sources. It is
|
||||
* generally recommended that a single {@code @Configuration} class is used to bootstrap
|
||||
* your application, however, any of the following sources can also be used:
|
||||
*
|
||||
* <p>
|
||||
* <ul>
|
||||
* <li>{@link Class} - A Java class to be loaded by {@link AnnotatedBeanDefinitionReader}</li>
|
||||
*
|
||||
* <li>{@link Resource} - A XML resource to be loaded by {@link XmlBeanDefinitionReader}</li>
|
||||
*
|
||||
* <li>{@link Package} - A Java package to be scanned by
|
||||
* {@link ClassPathBeanDefinitionScanner}</li>
|
||||
*
|
||||
* <li>{@link CharSequence} - A class name, resource handle or package name to loaded as
|
||||
* appropriate. If the {@link CharSequence} cannot be resolved to class and does not
|
||||
* resolve to a {@link Resource} that exists it will be considered a {@link Package}.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Dave Syer
|
||||
* @see #run(Object, String[])
|
||||
* @see #run(Object[], String[])
|
||||
* @see #SpringApplication(Object...)
|
||||
*/
|
||||
public class SpringApplication {
|
||||
|
||||
private static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
|
||||
+ "annotation.AnnotationConfigApplicationContext";
|
||||
|
||||
private static final String DEFAULT_WEB_CONTEXT_CLASS = "org.springframework.bootstrap."
|
||||
+ "context.embedded.AnnotationConfigEmbeddedWebApplicationContext";
|
||||
|
||||
private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
|
||||
"org.springframework.web.context.ConfigurableWebApplicationContext" };
|
||||
|
||||
private Object[] sources;
|
||||
|
||||
private boolean showBanner = true;
|
||||
|
||||
private boolean addCommandLineProperties = true;
|
||||
|
||||
private ResourceLoader resourceLoader;
|
||||
|
||||
private BeanNameGenerator beanNameGenerator;
|
||||
|
||||
private ConfigurableEnvironment environment;
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
private Class<? extends ApplicationContext> applicationContextClass;
|
||||
|
||||
private boolean webEnvironment;
|
||||
|
||||
private List<ApplicationContextInitializer<?>> initializers;
|
||||
|
||||
/**
|
||||
* Crate a new {@link SpringApplication} instance. The application context will load
|
||||
* beans from the specified sources (see {@link SpringApplication class-level}
|
||||
* documentation for details. The instance can be customized before calling
|
||||
* {@link #run(String...)}.
|
||||
* @param sources the bean sources
|
||||
* @see #run(Object, String[])
|
||||
* @see #SpringApplication(ResourceLoader, Object...)
|
||||
*/
|
||||
public SpringApplication(Object... sources) {
|
||||
Assert.notEmpty(sources, "Sources must not be empty");
|
||||
this.sources = sources;
|
||||
initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Crate a new {@link SpringApplication} instance. The application context will load
|
||||
* beans from the specified sources (see {@link SpringApplication class-level}
|
||||
* documentation for details. The instance can be customized before calling
|
||||
* {@link #run(String...)}.
|
||||
* @param resourceLoader the resource loader to use
|
||||
* @param sources the bean sources
|
||||
* @see #run(Object, String[])
|
||||
* @see #SpringApplication(ResourceLoader, Object...)
|
||||
*/
|
||||
public SpringApplication(ResourceLoader resourceLoader, Object... sources) {
|
||||
Assert.notEmpty(sources, "Sources must not be empty");
|
||||
this.resourceLoader = resourceLoader;
|
||||
this.sources = sources;
|
||||
initialize();
|
||||
}
|
||||
|
||||
protected void initialize() {
|
||||
this.webEnvironment = deduceWebEnvironment();
|
||||
this.initializers = new ArrayList<ApplicationContextInitializer<?>>();
|
||||
@SuppressWarnings("rawtypes")
|
||||
Collection<ApplicationContextInitializer> factories = SpringFactoriesLoader
|
||||
.loadFactories(ApplicationContextInitializer.class,
|
||||
SpringApplication.class.getClassLoader());
|
||||
for (ApplicationContextInitializer<?> initializer : factories) {
|
||||
this.initializers.add(initializer);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean deduceWebEnvironment() {
|
||||
for (String className : WEB_ENVIRONMENT_CLASSES) {
|
||||
if (!ClassUtils.isPresent(className, null)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the Spring application, creating and refreshing a new
|
||||
* {@link ApplicationContext}.
|
||||
* @param args the application arguments (usually passed from a Java main method)
|
||||
* @return a running {@link ApplicationContext}
|
||||
*/
|
||||
public ApplicationContext run(String... args) {
|
||||
if (this.showBanner) {
|
||||
printBanner();
|
||||
}
|
||||
ApplicationContext context = createApplicationContext();
|
||||
postProcessApplicationContext(context);
|
||||
addPropertySources(context, args);
|
||||
if (context instanceof ConfigurableApplicationContext) {
|
||||
applyInitializers((ConfigurableApplicationContext) context);
|
||||
}
|
||||
load(context, this.sources);
|
||||
refresh(context);
|
||||
runCommandLineRunners(context, args);
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print a simple banner message to the console. Subclasses can override this method
|
||||
* to provide additional or alternative banners.
|
||||
* @see #setShowBanner(boolean)
|
||||
*/
|
||||
protected void printBanner() {
|
||||
Banner.write(System.out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply any {@link ApplicationContextInitializer}s to the context before it is
|
||||
* refreshed.
|
||||
* @param context the configured ApplicationContext (not refreshed yet)
|
||||
* @see ConfigurableApplicationContext#refresh()
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
protected void applyInitializers(ConfigurableApplicationContext context) {
|
||||
for (ApplicationContextInitializer initializer : this.initializers) {
|
||||
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
|
||||
initializer.getClass(), ApplicationContextInitializer.class);
|
||||
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
|
||||
initializer.initialize(context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Strategy method used to create the {@link ApplicationContext}. By default this
|
||||
* method will respect any explicitly set application context or application context
|
||||
* class before falling back to a suitable default.
|
||||
* @return the application context (not yet refreshed)
|
||||
* @see #setApplicationContext(ApplicationContext)
|
||||
* @see #setApplicationContextClass(Class)
|
||||
*/
|
||||
protected ApplicationContext createApplicationContext() {
|
||||
if (this.applicationContext != null) {
|
||||
return this.applicationContext;
|
||||
}
|
||||
|
||||
Class<?> contextClass = this.applicationContextClass;
|
||||
if (contextClass == null) {
|
||||
try {
|
||||
contextClass = Class
|
||||
.forName(this.webEnvironment ? DEFAULT_WEB_CONTEXT_CLASS
|
||||
: DEFAULT_CONTEXT_CLASS);
|
||||
} catch (ClassNotFoundException ex) {
|
||||
throw new IllegalStateException(
|
||||
"Unable create a default ApplicationContext, "
|
||||
+ "please specify an ApplicationContextClass", ex);
|
||||
}
|
||||
}
|
||||
|
||||
return (ApplicationContext) BeanUtils.instantiate(contextClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply any relevant post processing the {@link ApplicationContext}. Subclasses can
|
||||
* apply additional processing as required.
|
||||
* @param context the application context
|
||||
*/
|
||||
protected void postProcessApplicationContext(ApplicationContext context) {
|
||||
if (this.webEnvironment) {
|
||||
if (context instanceof ConfigurableWebApplicationContext) {
|
||||
ConfigurableWebApplicationContext configurableContext = (ConfigurableWebApplicationContext) context;
|
||||
if (this.beanNameGenerator != null) {
|
||||
configurableContext.getBeanFactory().registerSingleton(
|
||||
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
|
||||
this.beanNameGenerator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (context instanceof AbstractApplicationContext) {
|
||||
((AbstractApplicationContext) context).setEnvironment(this.environment);
|
||||
}
|
||||
|
||||
if (context instanceof GenericApplicationContext) {
|
||||
((GenericApplicationContext) context).setResourceLoader(this.resourceLoader);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add any {@link PropertySource}s to the application context environment.
|
||||
* @param context the application context
|
||||
* @param args run arguments
|
||||
*/
|
||||
protected void addPropertySources(ApplicationContext context, String[] args) {
|
||||
Environment environment = context.getEnvironment();
|
||||
if (environment instanceof ConfigurableEnvironment) {
|
||||
ConfigurableEnvironment configurable = (ConfigurableEnvironment) environment;
|
||||
if (this.addCommandLineProperties) {
|
||||
CommandLinePropertySource<?> propertySource = new SimpleCommandLinePropertySource(
|
||||
args);
|
||||
configurable.getPropertySources().addFirst(propertySource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load beans into the application context.
|
||||
* @param context the context to load beans into
|
||||
*/
|
||||
protected void load(ApplicationContext context, Object[] sources) {
|
||||
Assert.isInstanceOf(BeanDefinitionRegistry.class, context);
|
||||
BeanDefinitionLoader loader = createBeanDefinitionLoader(
|
||||
(BeanDefinitionRegistry) context, sources);
|
||||
if (this.beanNameGenerator != null) {
|
||||
loader.setBeanNameGenerator(this.beanNameGenerator);
|
||||
}
|
||||
if (this.resourceLoader != null) {
|
||||
loader.setResourceLoader(this.resourceLoader);
|
||||
}
|
||||
if (this.environment != null) {
|
||||
loader.setEnvironment(this.environment);
|
||||
}
|
||||
loader.load();
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method used to create the {@link BeanDefinitionLoader}.
|
||||
*/
|
||||
protected BeanDefinitionLoader createBeanDefinitionLoader(
|
||||
BeanDefinitionRegistry registry, Object[] sources) {
|
||||
return new BeanDefinitionLoader(registry, sources);
|
||||
}
|
||||
|
||||
private void runCommandLineRunners(ApplicationContext context, String... args) {
|
||||
List<CommandLineRunner> runners = new ArrayList<CommandLineRunner>(context
|
||||
.getBeansOfType(CommandLineRunner.class).values());
|
||||
AnnotationAwareOrderComparator.sort(runners);
|
||||
for (CommandLineRunner runner : runners) {
|
||||
runner.run(args);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the underlying {@link ApplicationContext}.
|
||||
* @param applicationContext the application context to refresh
|
||||
*/
|
||||
protected void refresh(ApplicationContext applicationContext) {
|
||||
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
|
||||
((AbstractApplicationContext) applicationContext).refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if this application is running within a web environment. If not specified will
|
||||
* attempt to deduce the environment based on the classpath.
|
||||
*/
|
||||
public void setWebEnvironment(boolean webEnvironment) {
|
||||
this.webEnvironment = webEnvironment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if the Spring banner should be displayed when the application runs. Defaults
|
||||
* to {@code true}.
|
||||
* @see #printBanner()
|
||||
*/
|
||||
public void setShowBanner(boolean showBanner) {
|
||||
this.showBanner = showBanner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if a {@link CommandLinePropertySource} should be added to the application
|
||||
* context in order to expose arguments. Defaults to {@code true}.
|
||||
*/
|
||||
public void setAddCommandLineProperties(boolean addCommandLineProperties) {
|
||||
this.addCommandLineProperties = addCommandLineProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bean name generator that should be used when generating bean names.
|
||||
*/
|
||||
public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
|
||||
this.beanNameGenerator = beanNameGenerator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the underlying environment that should be used when loading.
|
||||
*/
|
||||
public void setEnvironment(ConfigurableEnvironment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link ResourceLoader} that should be used when loading resources.
|
||||
*/
|
||||
public void setResourceLoader(ResourceLoader resourceLoader) {
|
||||
Assert.notNull(resourceLoader, "ResourceLoader must not be null");
|
||||
this.resourceLoader = resourceLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the type of Spring {@link ApplicationContext} that will be created. If not
|
||||
* specified defaults to {@link AnnotationConfigEmbeddedWebApplicationContext} for web
|
||||
* based applications or {@link AnnotationConfigApplicationContext} for non web based
|
||||
* applications.
|
||||
* @param applicationContextClass the context class to set
|
||||
* @see #setApplicationContext(ApplicationContext)
|
||||
*/
|
||||
public void setApplicationContextClass(
|
||||
Class<? extends ApplicationContext> applicationContextClass) {
|
||||
this.applicationContextClass = applicationContextClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a Spring {@link ApplicationContext} that will be used for the application. If
|
||||
* not specified an {@link AnnotationConfigEmbeddedWebApplicationContext} will be
|
||||
* created for web based applications or an {@link AnnotationConfigApplicationContext}
|
||||
* for non web based applications.
|
||||
* @param applicationContext the spring application context.
|
||||
* @see #setApplicationContextClass(Class)
|
||||
*/
|
||||
public void setApplicationContext(ApplicationContext applicationContext) {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param initializers the initializers to set
|
||||
*/
|
||||
public void setInitializers(
|
||||
Collection<? extends ApplicationContextInitializer<?>> initializers) {
|
||||
this.initializers = new ArrayList<ApplicationContextInitializer<?>>(initializers);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param initializers
|
||||
*/
|
||||
public void addInitializers(ApplicationContextInitializer<?>... initializers) {
|
||||
this.initializers.addAll(Arrays.asList(initializers));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the initializers
|
||||
*/
|
||||
public List<ApplicationContextInitializer<?>> getInitializers() {
|
||||
return this.initializers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Static helper that can be used to run a {@link SpringApplication} from the
|
||||
* specified source using default settings.
|
||||
* @param source the source to load
|
||||
* @param args the application arguments (usually passed from a Java main method)
|
||||
* @return the running {@link ApplicationContext}
|
||||
*/
|
||||
public static ApplicationContext run(Object source, String... args) {
|
||||
return run(new Object[] { source }, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Static helper that can be used to run a {@link SpringApplication} from the
|
||||
* specified sources using default settings.
|
||||
* @param sources the sources to load
|
||||
* @param args the application arguments (usually passed from a Java main method)
|
||||
* @return the running {@link ApplicationContext}
|
||||
*/
|
||||
public static ApplicationContext run(Object[] sources, String[] args) {
|
||||
return new SpringApplication(sources).run(args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Static helper that can be used to run a {@link SpringApplication} from the
|
||||
* specified {@code @Component} sources. Any class not annotated or meta-annotated
|
||||
* with {@code @Component} will be ignored.
|
||||
* @param classes the source classes to consider loading
|
||||
* @param args the application arguments (usually passed from a Java main method)
|
||||
* @return the running {@link ApplicationContext}
|
||||
*/
|
||||
public static ApplicationContext runComponents(Class<?>[] classes, String... args) {
|
||||
List<Class<?>> componentClasses = new ArrayList<Class<?>>();
|
||||
for (Class<?> candidate : classes) {
|
||||
StandardAnnotationMetadata metadata = new StandardAnnotationMetadata(
|
||||
candidate);
|
||||
if (metadata.isAnnotated(Component.class.getName())) {
|
||||
componentClasses.add(candidate);
|
||||
}
|
||||
}
|
||||
return new SpringApplication(componentClasses.toArray()).run(args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.autoconfigure;
|
||||
|
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnMissingBean;
|
||||
import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for
|
||||
* {@link PropertySourcesPlaceholderConfigurer}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnMissingBean(PropertySourcesPlaceholderConfigurer.class)
|
||||
public class PropertyPlaceholderAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer(
|
||||
ApplicationContext context) {
|
||||
return new PropertySourcesPlaceholderConfigurer();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.autoconfigure.data;
|
||||
|
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnClass;
|
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnMissingBean;
|
||||
import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for Spring Data's JPA Repositories.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @see EnableJpaRepositories
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(JpaRepository.class)
|
||||
@ConditionalOnMissingBean(JpaRepositoryFactoryBean.class)
|
||||
@Import(JpaRepositoriesAutoConfigureRegistrar.class)
|
||||
public class JpaRepositoriesAutoConfiguration {
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.autoconfigure.data;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.bootstrap.context.annotation.AutoConfigurationUtils;
|
||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.core.type.StandardAnnotationMetadata;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
import org.springframework.data.jpa.repository.config.JpaRepositoryConfigExtension;
|
||||
import org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource;
|
||||
import org.springframework.data.repository.config.RepositoryBeanDefinitionBuilder;
|
||||
import org.springframework.data.repository.config.RepositoryBeanNameGenerator;
|
||||
import org.springframework.data.repository.config.RepositoryConfiguration;
|
||||
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link ImportBeanDefinitionRegistrar} used to auto-configure Spring Data JPA
|
||||
* Repositories.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class JpaRepositoriesAutoConfigureRegistrar implements ImportBeanDefinitionRegistrar,
|
||||
BeanFactoryAware, BeanClassLoaderAware {
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
private ClassLoader beanClassLoader;
|
||||
|
||||
@Override
|
||||
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
|
||||
final BeanDefinitionRegistry registry) {
|
||||
|
||||
final ResourceLoader resourceLoader = new DefaultResourceLoader();
|
||||
final AnnotationRepositoryConfigurationSource configurationSource = getConfigurationSource();
|
||||
final RepositoryConfigurationExtension extension = new JpaRepositoryConfigExtension();
|
||||
extension.registerBeansForRoot(registry, configurationSource);
|
||||
|
||||
final RepositoryBeanNameGenerator generator = new RepositoryBeanNameGenerator();
|
||||
generator.setBeanClassLoader(this.beanClassLoader);
|
||||
|
||||
Collection<RepositoryConfiguration<AnnotationRepositoryConfigurationSource>> repositoryConfigurations = extension
|
||||
.getRepositoryConfigurations(configurationSource, resourceLoader);
|
||||
|
||||
for (final RepositoryConfiguration<AnnotationRepositoryConfigurationSource> repositoryConfiguration : repositoryConfigurations) {
|
||||
RepositoryBeanDefinitionBuilder builder = new RepositoryBeanDefinitionBuilder(
|
||||
repositoryConfiguration, extension);
|
||||
BeanDefinitionBuilder definitionBuilder = builder.build(registry,
|
||||
resourceLoader);
|
||||
extension.postProcess(definitionBuilder, configurationSource);
|
||||
|
||||
String beanName = generator.generateBeanName(
|
||||
definitionBuilder.getBeanDefinition(), registry);
|
||||
registry.registerBeanDefinition(beanName,
|
||||
definitionBuilder.getBeanDefinition());
|
||||
}
|
||||
}
|
||||
|
||||
private AnnotationRepositoryConfigurationSource getConfigurationSource() {
|
||||
StandardAnnotationMetadata metadata = new StandardAnnotationMetadata(
|
||||
EnableJpaRepositoriesConfiguration.class, true);
|
||||
AnnotationRepositoryConfigurationSource configurationSource = new AnnotationRepositoryConfigurationSource(
|
||||
metadata, EnableJpaRepositories.class) {
|
||||
|
||||
@Override
|
||||
public java.lang.Iterable<String> getBasePackages() {
|
||||
return JpaRepositoriesAutoConfigureRegistrar.this.getBasePackages();
|
||||
};
|
||||
};
|
||||
return configurationSource;
|
||||
}
|
||||
|
||||
protected Iterable<String> getBasePackages() {
|
||||
List<String> basePackages = AutoConfigurationUtils
|
||||
.getBasePackages(this.beanFactory);
|
||||
Assert.notEmpty(
|
||||
basePackages,
|
||||
"Unable to find JPA repository base packages, please define "
|
||||
+ "a @ComponentScan annotation or disable JpaRepositoriesAutoConfigure");
|
||||
return basePackages;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
this.beanClassLoader = classLoader;
|
||||
}
|
||||
|
||||
@EnableJpaRepositories
|
||||
private static class EnableJpaRepositoriesConfiguration {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.autoconfigure.jdbc;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnMissingBean;
|
||||
import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.task.AsyncUtils;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
|
||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for embedded databases.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@Configuration
|
||||
@Conditional(EmbeddedDatabaseAutoConfiguration.EmbeddedDatabaseCondition.class)
|
||||
@ConditionalOnMissingBean(DataSource.class)
|
||||
public class EmbeddedDatabaseAutoConfiguration {
|
||||
|
||||
private static final Map<EmbeddedDatabaseType, String> EMBEDDED_DATABASE_TYPE_CLASSES;
|
||||
static {
|
||||
EMBEDDED_DATABASE_TYPE_CLASSES = new LinkedHashMap<EmbeddedDatabaseType, String>();
|
||||
EMBEDDED_DATABASE_TYPE_CLASSES.put(EmbeddedDatabaseType.HSQL,
|
||||
"org.hsqldb.Database");
|
||||
}
|
||||
|
||||
private ExecutorService executorService;
|
||||
|
||||
@Bean
|
||||
public DataSource dataSource() {
|
||||
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
|
||||
.setType(getEmbeddedDatabaseType());
|
||||
return AsyncUtils.submitVia(this.executorService, builder).build();
|
||||
}
|
||||
|
||||
public static EmbeddedDatabaseType getEmbeddedDatabaseType() {
|
||||
for (Map.Entry<EmbeddedDatabaseType, String> entry : EMBEDDED_DATABASE_TYPE_CLASSES
|
||||
.entrySet()) {
|
||||
if (ClassUtils.isPresent(entry.getValue(),
|
||||
EmbeddedDatabaseAutoConfiguration.class.getClassLoader())) {
|
||||
return entry.getKey();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static class EmbeddedDatabaseCondition implements Condition {
|
||||
|
||||
@Override
|
||||
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
if (!ClassUtils.isPresent(
|
||||
"org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType",
|
||||
context.getClassLoader())) {
|
||||
return false;
|
||||
}
|
||||
return getEmbeddedDatabaseType() != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.autoconfigure.orm.jpa;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.bootstrap.autoconfigure.jdbc.EmbeddedDatabaseAutoConfiguration;
|
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnClass;
|
||||
import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
|
||||
import org.springframework.orm.jpa.JpaVendorAdapter;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for Hibernate JPA.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(name = "org.hibernate.ejb.HibernateEntityManager")
|
||||
@EnableTransactionManagement
|
||||
public class HibernateJpaAutoConfiguration extends JpaAutoConfiguration {
|
||||
|
||||
private static final Map<EmbeddedDatabaseType, String> EMBEDDED_DATABASE_DIALECTS;
|
||||
static {
|
||||
EMBEDDED_DATABASE_DIALECTS = new LinkedHashMap<EmbeddedDatabaseType, String>();
|
||||
EMBEDDED_DATABASE_DIALECTS.put(EmbeddedDatabaseType.HSQL,
|
||||
"org.hibernate.dialect.HSQLDialect");
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Override
|
||||
public JpaVendorAdapter jpaVendorAdapter() {
|
||||
return new HibernateJpaVendorAdapter();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(
|
||||
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean) {
|
||||
Map<String, Object> properties = entityManagerFactoryBean.getJpaPropertyMap();
|
||||
if (isAutoConfiguredDataSource()) {
|
||||
properties.put("hibernate.hbm2ddl.auto", "create-drop");
|
||||
String dialect = EMBEDDED_DATABASE_DIALECTS
|
||||
.get(EmbeddedDatabaseAutoConfiguration.getEmbeddedDatabaseType());
|
||||
if (dialect != null) {
|
||||
properties.put("hibernate.dialect", dialect);
|
||||
}
|
||||
}
|
||||
properties.put("hibernate.cache.provider_class",
|
||||
"org.hibernate.cache.HashtableCacheProvider");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.autoconfigure.orm.jpa;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.bootstrap.autoconfigure.jdbc.EmbeddedDatabaseAutoConfiguration;
|
||||
import org.springframework.bootstrap.context.annotation.AutoConfigurationUtils;
|
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnBean;
|
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnClass;
|
||||
import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.orm.jpa.JpaVendorAdapter;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Base {@link EnableAutoConfiguration Auto-configuration} for JPA.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@ConditionalOnClass({ LocalContainerEntityManagerFactoryBean.class,
|
||||
EnableTransactionManagement.class, EntityManager.class })
|
||||
@ConditionalOnBean(DataSource.class)
|
||||
public abstract class JpaAutoConfiguration implements BeanFactoryAware {
|
||||
|
||||
private ConfigurableListableBeanFactory beanFactory;
|
||||
|
||||
@Bean
|
||||
public PlatformTransactionManager txManager() {
|
||||
return new JpaTransactionManager(entityManagerFactory().getObject());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
|
||||
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
|
||||
entityManagerFactoryBean.setJpaVendorAdapter(jpaVendorAdapter());
|
||||
entityManagerFactoryBean.setDataSource(getDataSource());
|
||||
entityManagerFactoryBean.setPackagesToScan(getPackagesToScan());
|
||||
configure(entityManagerFactoryBean);
|
||||
return entityManagerFactoryBean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the {@code dataSource} being used by Spring was created from
|
||||
* {@link EmbeddedDatabaseAutoConfiguration}.
|
||||
* @return true if the data source was auto-configured.
|
||||
*/
|
||||
protected boolean isAutoConfiguredDataSource() {
|
||||
try {
|
||||
BeanDefinition beanDefinition = this.beanFactory
|
||||
.getBeanDefinition("dataSource");
|
||||
return EmbeddedDatabaseAutoConfiguration.class.getName().equals(
|
||||
beanDefinition.getFactoryBeanName());
|
||||
} catch (NoSuchBeanDefinitionException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
public abstract JpaVendorAdapter jpaVendorAdapter();
|
||||
|
||||
protected DataSource getDataSource() {
|
||||
try {
|
||||
return this.beanFactory.getBean("dataSource", DataSource.class);
|
||||
} catch (RuntimeException e) {
|
||||
return this.beanFactory.getBean(DataSource.class);
|
||||
}
|
||||
}
|
||||
|
||||
protected String[] getPackagesToScan() {
|
||||
List<String> basePackages = AutoConfigurationUtils
|
||||
.getBasePackages(this.beanFactory);
|
||||
Assert.notEmpty(basePackages,
|
||||
"Unable to find JPA packages to scan, please define "
|
||||
+ "a @ComponentScan annotation or disable JpaAutoConfiguration");
|
||||
return basePackages.toArray(new String[basePackages.size()]);
|
||||
}
|
||||
|
||||
protected void configure(
|
||||
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.autoconfigure.web;
|
||||
|
||||
import javax.servlet.Servlet;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.util.Loader;
|
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnClass;
|
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnMissingBean;
|
||||
import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration;
|
||||
import org.springframework.bootstrap.context.embedded.EmbeddedServletContainerFactory;
|
||||
import org.springframework.bootstrap.context.embedded.jetty.JettyEmbeddedServletContainerFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for
|
||||
* {@link JettyEmbeddedServletContainerFactory}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass({ Servlet.class, Server.class, Loader.class })
|
||||
@ConditionalOnMissingBean(EmbeddedServletContainerFactory.class)
|
||||
public class EmbeddedJettyAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public JettyEmbeddedServletContainerFactory jettyEmbeddedServletContainerFactory() {
|
||||
return new JettyEmbeddedServletContainerFactory();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.autoconfigure.web;
|
||||
|
||||
import javax.servlet.Servlet;
|
||||
|
||||
import org.apache.catalina.startup.Tomcat;
|
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnClass;
|
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnMissingBean;
|
||||
import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration;
|
||||
import org.springframework.bootstrap.context.embedded.EmbeddedServletContainerFactory;
|
||||
import org.springframework.bootstrap.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for
|
||||
* {@link TomcatEmbeddedServletContainerFactory}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass({ Servlet.class, Tomcat.class })
|
||||
@ConditionalOnMissingBean(EmbeddedServletContainerFactory.class)
|
||||
public class EmbeddedTomcatAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {
|
||||
return new TomcatEmbeddedServletContainerFactory();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.autoconfigure.web;
|
||||
|
||||
import javax.servlet.Servlet;
|
||||
|
||||
import org.springframework.bootstrap.autoconfigure.web.WebMvcAutoConfiguration.WebMvcConfiguration;
|
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnClass;
|
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnMissingBean;
|
||||
import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
import org.springframework.web.servlet.HandlerAdapter;
|
||||
import org.springframework.web.servlet.HandlerMapping;
|
||||
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for {@link EnableWebMvc Web MVC}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class })
|
||||
@ConditionalOnMissingBean({ HandlerAdapter.class, HandlerMapping.class })
|
||||
@Import(WebMvcConfiguration.class)
|
||||
public class WebMvcAutoConfiguration {
|
||||
|
||||
/**
|
||||
* Nested configuration used because {@code @EnableWebMvc} will add HandlerAdapter and
|
||||
* HandlerMapping, causing the condition to fail and the additional DispatcherServlet
|
||||
* bean never to be registered if it were declared directly.
|
||||
*/
|
||||
@EnableWebMvc
|
||||
public static class WebMvcConfiguration extends WebMvcConfigurerAdapter {
|
||||
|
||||
@Bean
|
||||
public DispatcherServlet dispatcherServlet() {
|
||||
return new DispatcherServlet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureDefaultServletHandling(
|
||||
DefaultServletHandlerConfigurer configurer) {
|
||||
configurer.enable();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.bind;
|
||||
|
||||
import java.beans.IntrospectionException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.yaml.snakeyaml.constructor.Constructor;
|
||||
import org.yaml.snakeyaml.introspector.Property;
|
||||
import org.yaml.snakeyaml.introspector.PropertyUtils;
|
||||
import org.yaml.snakeyaml.nodes.NodeId;
|
||||
|
||||
/**
|
||||
* Extended version of snakeyaml's Constructor class to facilitate mapping custom YAML
|
||||
* keys to Javabean property names.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class CustomPropertyConstructor extends Constructor {
|
||||
|
||||
private final Map<Class<?>, Map<String, Property>> properties = new HashMap<Class<?>, Map<String, Property>>();
|
||||
|
||||
private final PropertyUtils propertyUtils = new PropertyUtils();
|
||||
|
||||
public CustomPropertyConstructor(Class<?> theRoot) {
|
||||
super(theRoot);
|
||||
this.yamlClassConstructors.put(NodeId.mapping,
|
||||
new CustomPropertyConstructMapping());
|
||||
}
|
||||
|
||||
public CustomPropertyConstructor(Class<?> theRoot,
|
||||
Map<Class<?>, Map<String, String>> propertyAliases) {
|
||||
this(theRoot);
|
||||
|
||||
for (Class<?> key : propertyAliases.keySet()) {
|
||||
Map<String, String> map = propertyAliases.get(key);
|
||||
if (map != null) {
|
||||
for (String alias : map.keySet()) {
|
||||
addPropertyAlias(alias, key, map.get(alias));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an alias for a Javabean property name on a particular type. The values of YAML
|
||||
* keys with the alias name will be mapped to the Javabean property.
|
||||
*/
|
||||
protected final void addPropertyAlias(String alias, Class<?> type, String name) {
|
||||
Map<String, Property> typeMap = this.properties.get(type);
|
||||
|
||||
if (typeMap == null) {
|
||||
typeMap = new HashMap<String, Property>();
|
||||
this.properties.put(type, typeMap);
|
||||
}
|
||||
|
||||
try {
|
||||
typeMap.put(alias, this.propertyUtils.getProperty(type, name));
|
||||
} catch (IntrospectionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
class CustomPropertyConstructMapping extends ConstructMapping {
|
||||
|
||||
@Override
|
||||
protected Property getProperty(Class<?> type, String name)
|
||||
throws IntrospectionException {
|
||||
Property p = lookupProperty(type, name);
|
||||
|
||||
return p != null ? p : super.getProperty(type, name);
|
||||
}
|
||||
|
||||
private Property lookupProperty(Class<?> type, String name) {
|
||||
Map<String, Property> m = CustomPropertyConstructor.this.properties.get(type);
|
||||
|
||||
if (m != null) {
|
||||
return m.get(name);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.bind;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.beans.PropertyValues;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.MessageSourceAware;
|
||||
import org.springframework.core.env.PropertySources;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.validation.DataBinder;
|
||||
import org.springframework.validation.ObjectError;
|
||||
import org.springframework.validation.Validator;
|
||||
|
||||
/**
|
||||
* Validate some {@link Properties} by binding them to an object of a specified type and
|
||||
* then optionally running a {@link Validator} over it.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class PropertiesConfigurationFactory<T> implements FactoryBean<T>,
|
||||
MessageSourceAware, InitializingBean {
|
||||
|
||||
private static final Log logger = LogFactory
|
||||
.getLog(PropertiesConfigurationFactory.class);
|
||||
|
||||
private boolean ignoreUnknownFields = true;
|
||||
|
||||
private boolean ignoreInvalidFields = false;
|
||||
|
||||
private boolean exceptionIfInvalid;
|
||||
|
||||
private Properties properties;
|
||||
|
||||
private PropertySources propertySources;
|
||||
|
||||
private T configuration;
|
||||
|
||||
private Validator validator;
|
||||
|
||||
private MessageSource messageSource;
|
||||
|
||||
private boolean initialized = false;
|
||||
|
||||
private String targetName;
|
||||
|
||||
/**
|
||||
* @param target the target object to bind too
|
||||
* @see #PropertiesConfigurationFactory(Class)
|
||||
*/
|
||||
public PropertiesConfigurationFactory(T target) {
|
||||
Assert.notNull(target);
|
||||
this.configuration = target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new factory for an object of the given type.
|
||||
*
|
||||
* @see #PropertiesConfigurationFactory(Class)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public PropertiesConfigurationFactory(Class<?> type) {
|
||||
Assert.notNull(type);
|
||||
this.configuration = (T) BeanUtils.instantiate(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to ignore unknown fields, that is, whether to ignore bind parameters
|
||||
* that do not have corresponding fields in the target object.
|
||||
* <p>
|
||||
* Default is "true". Turn this off to enforce that all bind parameters must have a
|
||||
* matching field in the target object.
|
||||
* <p>
|
||||
*/
|
||||
public void setIgnoreUnknownFields(boolean ignoreUnknownFields) {
|
||||
this.ignoreUnknownFields = ignoreUnknownFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to ignore invalid fields, that is, whether to ignore bind parameters
|
||||
* that have corresponding fields in the target object which are not accessible (for
|
||||
* example because of null values in the nested path).
|
||||
* <p>
|
||||
* Default is "false". Turn this on to ignore bind parameters for nested objects in
|
||||
* non-existing parts of the target object graph.
|
||||
* <p>
|
||||
*/
|
||||
public void setIgnoreInvalidFields(boolean ignoreInvalidFields) {
|
||||
this.ignoreInvalidFields = ignoreInvalidFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param targetName
|
||||
*/
|
||||
public void setTargetName(String targetName) {
|
||||
this.targetName = targetName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param messageSource the messageSource to set
|
||||
*/
|
||||
@Override
|
||||
public void setMessageSource(MessageSource messageSource) {
|
||||
this.messageSource = messageSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param properties the properties to set
|
||||
*/
|
||||
public void setProperties(Properties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param propertySources the propertySources to set
|
||||
*/
|
||||
public void setPropertySources(PropertySources propertySources) {
|
||||
this.propertySources = propertySources;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param validator the validator to set
|
||||
*/
|
||||
public void setValidator(Validator validator) {
|
||||
this.validator = validator;
|
||||
}
|
||||
|
||||
public void setExceptionIfInvalid(boolean exceptionIfInvalid) {
|
||||
this.exceptionIfInvalid = exceptionIfInvalid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
|
||||
Assert.state(this.properties != null || this.propertySources != null,
|
||||
"Properties or propertySources should not be null");
|
||||
|
||||
try {
|
||||
if (this.properties != null) {
|
||||
logger.trace("Properties:\n" + this.properties);
|
||||
} else {
|
||||
logger.trace("Property Sources: " + this.propertySources);
|
||||
}
|
||||
this.initialized = true;
|
||||
|
||||
RelaxedDataBinder dataBinder;
|
||||
if (this.targetName != null) {
|
||||
dataBinder = new RelaxedDataBinder(this.configuration, this.targetName);
|
||||
} else {
|
||||
dataBinder = new RelaxedDataBinder(this.configuration);
|
||||
}
|
||||
if (this.validator != null) {
|
||||
dataBinder.setValidator(this.validator);
|
||||
}
|
||||
dataBinder.setIgnoreInvalidFields(this.ignoreInvalidFields);
|
||||
dataBinder.setIgnoreUnknownFields(this.ignoreUnknownFields);
|
||||
customizeBinder(dataBinder);
|
||||
PropertyValues pvs;
|
||||
if (this.properties != null) {
|
||||
pvs = new MutablePropertyValues(this.properties);
|
||||
} else {
|
||||
pvs = new PropertySourcesPropertyValues(this.propertySources);
|
||||
}
|
||||
dataBinder.bind(pvs);
|
||||
|
||||
if (this.validator != null) {
|
||||
dataBinder.validate();
|
||||
BindingResult errors = dataBinder.getBindingResult();
|
||||
|
||||
if (errors.hasErrors()) {
|
||||
logger.error("Properties configuration failed validation");
|
||||
for (ObjectError error : errors.getAllErrors()) {
|
||||
logger.error(this.messageSource != null ? this.messageSource
|
||||
.getMessage(error, Locale.getDefault())
|
||||
+ " ("
|
||||
+ error
|
||||
+ ")" : error);
|
||||
}
|
||||
if (this.exceptionIfInvalid) {
|
||||
BindException summary = new BindException(errors);
|
||||
throw summary;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (BindException e) {
|
||||
if (this.exceptionIfInvalid) {
|
||||
throw e;
|
||||
}
|
||||
logger.error(
|
||||
"Failed to load Properties validation bean. Your Properties may be invalid.",
|
||||
e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param dataBinder the data binder that will be used to bind and validate
|
||||
*/
|
||||
protected void customizeBinder(DataBinder dataBinder) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
if (this.configuration == null) {
|
||||
return Object.class;
|
||||
}
|
||||
return this.configuration.getClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getObject() throws Exception {
|
||||
if (!this.initialized) {
|
||||
afterPropertiesSet();
|
||||
}
|
||||
return this.configuration;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.bind;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.bootstrap.context.annotation.ConfigurationProperties;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.env.PropertySources;
|
||||
import org.springframework.validation.Validator;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class PropertySourcesBindingPostProcessor implements BeanPostProcessor {
|
||||
|
||||
private PropertySources propertySources;
|
||||
|
||||
private Validator validator;
|
||||
|
||||
/**
|
||||
* @param propertySources
|
||||
*/
|
||||
public void setPropertySources(PropertySources propertySources) {
|
||||
this.propertySources = propertySources;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param validator the validator to set
|
||||
*/
|
||||
public void setValidator(Validator validator) {
|
||||
this.validator = validator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
ConfigurationProperties annotation = AnnotationUtils.findAnnotation(
|
||||
bean.getClass(), ConfigurationProperties.class);
|
||||
if (annotation != null) {
|
||||
PropertiesConfigurationFactory<Object> factory = new PropertiesConfigurationFactory<Object>(
|
||||
bean);
|
||||
factory.setPropertySources(this.propertySources);
|
||||
factory.setValidator(this.validator);
|
||||
factory.setIgnoreInvalidFields(annotation.ignoreInvalidFields());
|
||||
factory.setIgnoreUnknownFields(annotation.ignoreUnknownFields());
|
||||
String targetName = "".equals(annotation.value()) ? ("".equals(annotation
|
||||
.name()) ? null : annotation.name()) : annotation.value();
|
||||
factory.setTargetName(targetName);
|
||||
try {
|
||||
bean = factory.getObject();
|
||||
} catch (BeansException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new BeanCreationException(beanName, "Could not bind", e);
|
||||
}
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.bind;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.beans.PropertyValue;
|
||||
import org.springframework.beans.PropertyValues;
|
||||
import org.springframework.core.env.EnumerablePropertySource;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.core.env.PropertySources;
|
||||
import org.springframework.core.env.PropertySourcesPropertyResolver;
|
||||
import org.springframework.validation.DataBinder;
|
||||
|
||||
/**
|
||||
* A {@link PropertyValues} implementation backed by a {@link PropertySources}, bridging
|
||||
* the two abstractions and allowing (for instance) a regular {@link DataBinder} to be
|
||||
* used with the latter.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class PropertySourcesPropertyValues implements PropertyValues {
|
||||
|
||||
private Map<String, PropertyValue> propertyValues = new ConcurrentHashMap<String, PropertyValue>();
|
||||
|
||||
private PropertySources propertySources;
|
||||
|
||||
/**
|
||||
* Create a new PropertyValues from the given PropertySources
|
||||
*
|
||||
* @param propertySources a PropertySources instance
|
||||
*/
|
||||
public PropertySourcesPropertyValues(PropertySources propertySources) {
|
||||
this.propertySources = propertySources;
|
||||
// TODO: maybe lazy initialization?
|
||||
PropertySourcesPropertyResolver resolver = new PropertySourcesPropertyResolver(
|
||||
propertySources);
|
||||
for (PropertySource<?> source : propertySources) {
|
||||
if (source instanceof EnumerablePropertySource) {
|
||||
EnumerablePropertySource<?> enumerable = (EnumerablePropertySource<?>) source;
|
||||
if (enumerable.getPropertyNames().length > 0) {
|
||||
for (String propertyName : enumerable.getPropertyNames()) {
|
||||
Object value = resolver.getProperty(propertyName);
|
||||
this.propertyValues.put(propertyName, new PropertyValue(
|
||||
propertyName, value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PropertyValue[] getPropertyValues() {
|
||||
Collection<PropertyValue> values = this.propertyValues.values();
|
||||
return values.toArray(new PropertyValue[values.size()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PropertyValue getPropertyValue(String propertyName) {
|
||||
PropertyValue propertyValue = this.propertyValues.get(propertyName);
|
||||
if (propertyValue != null) {
|
||||
return propertyValue;
|
||||
}
|
||||
for (PropertySource<?> source : this.propertySources) {
|
||||
Object value = source.getProperty(propertyName);
|
||||
if (value != null) {
|
||||
propertyValue = new PropertyValue(propertyName, value);
|
||||
this.propertyValues.put(propertyName, propertyValue);
|
||||
return propertyValue;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PropertyValues changesSince(PropertyValues old) {
|
||||
MutablePropertyValues changes = new MutablePropertyValues();
|
||||
// for each property value in the new set
|
||||
for (PropertyValue newPv : getPropertyValues()) {
|
||||
// if there wasn't an old one, add it
|
||||
PropertyValue pvOld = old.getPropertyValue(newPv.getName());
|
||||
if (pvOld == null) {
|
||||
changes.addPropertyValue(newPv);
|
||||
} else if (!pvOld.equals(newPv)) {
|
||||
// it's changed
|
||||
changes.addPropertyValue(newPv);
|
||||
}
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(String propertyName) {
|
||||
return getPropertyValue(propertyName) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return this.propertyValues.isEmpty();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.bind;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.BeanWrapper;
|
||||
import org.springframework.beans.BeanWrapperImpl;
|
||||
import org.springframework.beans.InvalidPropertyException;
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.beans.PropertyValue;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.DataBinder;
|
||||
|
||||
/**
|
||||
* Binder implementation that allows caller to bind to maps and also allows property names
|
||||
* to match a bit loosely (if underscores or dashes are removed and replaced with camel
|
||||
* case for example).
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class RelaxedDataBinder extends DataBinder {
|
||||
|
||||
private String namePrefix;
|
||||
|
||||
/**
|
||||
* @param target the target into which properties are bound
|
||||
*/
|
||||
public RelaxedDataBinder(Object target) {
|
||||
super(target);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param target the target into which properties are bound
|
||||
* @param namePrefix An optional prefix to be used when reading properties
|
||||
*/
|
||||
public RelaxedDataBinder(Object target, String namePrefix) {
|
||||
super(target, (StringUtils.hasLength(namePrefix) ? namePrefix
|
||||
: DEFAULT_OBJECT_NAME));
|
||||
this.namePrefix = (StringUtils.hasLength(namePrefix) ? namePrefix + "." : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doBind(MutablePropertyValues propertyValues) {
|
||||
propertyValues = modifyProperties(propertyValues, getTarget());
|
||||
super.doBind(propertyValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify the property values so that period separated property paths are valid for
|
||||
* map keys. Also creates new maps for properties of map type that are null (assuming
|
||||
* all maps are potentially nested). The standard bracket <code>[...]</code>
|
||||
* dereferencing is also accepted.
|
||||
*
|
||||
* @param propertyValues the property values
|
||||
* @param target the target object
|
||||
*/
|
||||
private MutablePropertyValues modifyProperties(MutablePropertyValues propertyValues,
|
||||
Object target) {
|
||||
|
||||
BeanWrapper targetWrapper = new BeanWrapperImpl(target);
|
||||
targetWrapper.setAutoGrowNestedPaths(true);
|
||||
|
||||
propertyValues = getProperyValuesForNamePrefix(propertyValues);
|
||||
|
||||
List<PropertyValue> list = propertyValues.getPropertyValueList();
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
modifyProperty(propertyValues, targetWrapper, list.get(i), i);
|
||||
}
|
||||
return propertyValues;
|
||||
}
|
||||
|
||||
private MutablePropertyValues getProperyValuesForNamePrefix(
|
||||
MutablePropertyValues propertyValues) {
|
||||
if (this.namePrefix == null) {
|
||||
return propertyValues;
|
||||
}
|
||||
MutablePropertyValues rtn = new MutablePropertyValues();
|
||||
for (PropertyValue pv : propertyValues.getPropertyValues()) {
|
||||
String name = pv.getName();
|
||||
if (name.startsWith(this.namePrefix)) {
|
||||
name = name.substring(this.namePrefix.length());
|
||||
rtn.add(name, pv.getValue());
|
||||
}
|
||||
}
|
||||
return rtn;
|
||||
}
|
||||
|
||||
private void modifyProperty(MutablePropertyValues propertyValues, BeanWrapper target,
|
||||
PropertyValue propertyValue, int index) {
|
||||
|
||||
String name = propertyValue.getName();
|
||||
StringBuilder builder = new StringBuilder();
|
||||
Class<?> type = target.getWrappedClass();
|
||||
|
||||
for (String key : StringUtils.delimitedListToStringArray(name, ".")) {
|
||||
if (builder.length() != 0) {
|
||||
builder.append(".");
|
||||
}
|
||||
String oldKey = key;
|
||||
key = getActualPropertyName(target, builder.toString(), oldKey);
|
||||
builder.append(key);
|
||||
String base = builder.toString();
|
||||
if (!oldKey.equals(key)) {
|
||||
propertyValues.setPropertyValueAt(
|
||||
new PropertyValue(base, propertyValue.getValue()), index);
|
||||
}
|
||||
type = target.getPropertyType(base);
|
||||
|
||||
// Any nested properties that are maps, are assumed to be simple nested
|
||||
// maps of maps...
|
||||
if (type != null && Map.class.isAssignableFrom(type)) {
|
||||
String suffix = name.substring(base.length());
|
||||
Map<String, Object> nested = new LinkedHashMap<String, Object>();
|
||||
if (target.getPropertyValue(base) != null) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> existing = (Map<String, Object>) target
|
||||
.getPropertyValue(base);
|
||||
nested = existing;
|
||||
} else {
|
||||
target.setPropertyValue(base, nested);
|
||||
}
|
||||
Map<String, Object> value = nested;
|
||||
nested = new LinkedHashMap<String, Object>();
|
||||
String[] tree = StringUtils.delimitedListToStringArray(suffix, ".");
|
||||
for (int j = 1; j < tree.length - 1; j++) {
|
||||
if (!value.containsKey(tree[j])) {
|
||||
value.put(tree[j], nested);
|
||||
}
|
||||
value = nested;
|
||||
nested = new LinkedHashMap<String, Object>();
|
||||
}
|
||||
String refName = base + suffix.replaceAll("\\.([a-zA-Z0-9]*)", "[$1]");
|
||||
propertyValues.setPropertyValueAt(new PropertyValue(refName,
|
||||
propertyValue.getValue()), index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getActualPropertyName(BeanWrapper target, String prefix, String name) {
|
||||
for (Variation variation : Variation.values()) {
|
||||
for (Manipulation manipulation : Manipulation.values()) {
|
||||
// Apply all manipulations before attempting variations
|
||||
String candidate = variation.apply(manipulation.apply(name));
|
||||
try {
|
||||
if (target.getPropertyType(prefix + candidate) != null) {
|
||||
return candidate;
|
||||
}
|
||||
} catch (InvalidPropertyException ex) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
static enum Variation {
|
||||
NONE {
|
||||
@Override
|
||||
public String apply(String value) {
|
||||
return value;
|
||||
}
|
||||
},
|
||||
UPPERCASE {
|
||||
@Override
|
||||
public String apply(String value) {
|
||||
return value.toUpperCase();
|
||||
}
|
||||
},
|
||||
|
||||
LOWERCASE {
|
||||
@Override
|
||||
public String apply(String value) {
|
||||
return value.toLowerCase();
|
||||
}
|
||||
};
|
||||
|
||||
public abstract String apply(String value);
|
||||
}
|
||||
|
||||
static enum Manipulation {
|
||||
NONE {
|
||||
@Override
|
||||
public String apply(String value) {
|
||||
return value;
|
||||
}
|
||||
},
|
||||
UNDERSCORE {
|
||||
@Override
|
||||
public String apply(String value) {
|
||||
return value.replace("-", "_");
|
||||
}
|
||||
},
|
||||
|
||||
CAMELCASE {
|
||||
@Override
|
||||
public String apply(String value) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (String field : UNDERSCORE.apply(value).split("_")) {
|
||||
builder.append(builder.length() == 0 ? field : StringUtils
|
||||
.capitalize(field));
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
};
|
||||
|
||||
public abstract String apply(String value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.bind;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.MessageSourceAware;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StreamUtils;
|
||||
import org.springframework.validation.BeanPropertyBindingResult;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.validation.ObjectError;
|
||||
import org.springframework.validation.Validator;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
import org.yaml.snakeyaml.constructor.Constructor;
|
||||
import org.yaml.snakeyaml.error.YAMLException;
|
||||
|
||||
/**
|
||||
* Validate some YAML by binding it to an object of a specified type and then optionally
|
||||
* running a {@link Validator} over it.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class YamlConfigurationFactory<T> implements FactoryBean<T>, MessageSourceAware,
|
||||
InitializingBean {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(YamlConfigurationFactory.class);
|
||||
|
||||
private Class<?> type;
|
||||
|
||||
private boolean exceptionIfInvalid;
|
||||
|
||||
private String yaml;
|
||||
|
||||
private Resource resource;
|
||||
|
||||
private T configuration;
|
||||
|
||||
private Validator validator;
|
||||
|
||||
private MessageSource messageSource;
|
||||
|
||||
private Map<Class<?>, Map<String, String>> propertyAliases = Collections.emptyMap();
|
||||
|
||||
/**
|
||||
* Sets a validation constructor which will be applied to the YAML doc to see whether
|
||||
* it matches the expected Javabean.
|
||||
*/
|
||||
public YamlConfigurationFactory(Class<?> type) {
|
||||
Assert.notNull(type);
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param messageSource the messageSource to set
|
||||
*/
|
||||
@Override
|
||||
public void setMessageSource(MessageSource messageSource) {
|
||||
this.messageSource = messageSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param propertyAliases the propertyAliases to set
|
||||
*/
|
||||
public void setPropertyAliases(Map<Class<?>, Map<String, String>> propertyAliases) {
|
||||
this.propertyAliases = new HashMap<Class<?>, Map<String, String>>(propertyAliases);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param yaml the yaml to set
|
||||
*/
|
||||
public void setYaml(String yaml) {
|
||||
this.yaml = yaml;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param resource the resource to set
|
||||
*/
|
||||
public void setResource(Resource resource) {
|
||||
this.resource = resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param validator the validator to set
|
||||
*/
|
||||
public void setValidator(Validator validator) {
|
||||
this.validator = validator;
|
||||
}
|
||||
|
||||
public void setExceptionIfInvalid(boolean exceptionIfInvalid) {
|
||||
this.exceptionIfInvalid = exceptionIfInvalid;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
|
||||
if (this.yaml == null) {
|
||||
Assert.state(this.resource != null, "Resource should not be null");
|
||||
this.yaml = StreamUtils.copyToString(this.resource.getInputStream(),
|
||||
Charset.defaultCharset());
|
||||
}
|
||||
|
||||
Assert.state(
|
||||
this.yaml != null,
|
||||
"Yaml document should not be null: either set it directly or set the resource to load it from");
|
||||
|
||||
try {
|
||||
logger.trace("Yaml document is\n" + this.yaml);
|
||||
Constructor constructor = new CustomPropertyConstructor(this.type,
|
||||
this.propertyAliases);
|
||||
this.configuration = (T) (new Yaml(constructor)).load(this.yaml);
|
||||
|
||||
if (this.validator != null) {
|
||||
BindingResult errors = new BeanPropertyBindingResult(this.configuration,
|
||||
"configuration");
|
||||
this.validator.validate(this.configuration, errors);
|
||||
|
||||
if (errors.hasErrors()) {
|
||||
logger.error("YAML configuration failed validation");
|
||||
for (ObjectError error : errors.getAllErrors()) {
|
||||
logger.error(this.messageSource != null ? this.messageSource
|
||||
.getMessage(error, Locale.getDefault())
|
||||
+ " ("
|
||||
+ error
|
||||
+ ")" : error);
|
||||
}
|
||||
if (this.exceptionIfInvalid) {
|
||||
BindException summary = new BindException(errors);
|
||||
throw summary;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (YAMLException e) {
|
||||
if (this.exceptionIfInvalid) {
|
||||
throw e;
|
||||
}
|
||||
logger.error(
|
||||
"Failed to load YAML validation bean. Your YAML file may be invalid.",
|
||||
e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
if (this.configuration == null) {
|
||||
return Object.class;
|
||||
}
|
||||
return this.configuration.getClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getObject() throws Exception {
|
||||
if (this.configuration == null) {
|
||||
afterPropertiesSet();
|
||||
}
|
||||
return this.configuration;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.config;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
|
||||
/**
|
||||
* Factory for Map that reads from a YAML source. YAML is a nice human-readable format for
|
||||
* configuration, and it has some useful hierarchical properties. It's more or less a
|
||||
* superset of JSON, so it has a lot of similar features. If multiple resources are
|
||||
* provided the later ones will override entries in the earlier ones hierarchically - that
|
||||
* is all entries with the same nested key of type Map at any depth are merged. For
|
||||
* example:
|
||||
*
|
||||
* <pre>
|
||||
* foo:
|
||||
* bar:
|
||||
* one: two
|
||||
* three: four
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* plus (later in the list)
|
||||
*
|
||||
* <pre>
|
||||
* foo:
|
||||
* bar:
|
||||
* one: 2
|
||||
* five: six
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* results in an effecive input of
|
||||
*
|
||||
* <pre>
|
||||
* foo:
|
||||
* bar:
|
||||
* one: 2
|
||||
* three: four
|
||||
* five: six
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* Note that the value of "foo" in the first document is not simply replaced with the value in the second, but its nested values are merged.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 3.2
|
||||
*
|
||||
*/
|
||||
public class YamlMapFactoryBean extends YamlProcessor implements
|
||||
FactoryBean<Map<String, Object>> {
|
||||
|
||||
private boolean singleton = true;
|
||||
|
||||
private Map<String, Object> instance;
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getObject() {
|
||||
if (!this.singleton || this.instance == null) {
|
||||
final Map<String, Object> result = new LinkedHashMap<String, Object>();
|
||||
MatchCallback callback = new MatchCallback() {
|
||||
@Override
|
||||
public void process(Properties properties, Map<String, Object> map) {
|
||||
merge(result, map);
|
||||
}
|
||||
};
|
||||
process(callback);
|
||||
this.instance = result;
|
||||
}
|
||||
return this.instance;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private void merge(Map<String, Object> output, Map<String, Object> map) {
|
||||
for (Entry<String, Object> entry : map.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
Object value = entry.getValue();
|
||||
Object existing = output.get(key);
|
||||
if (value instanceof Map && existing instanceof Map) {
|
||||
Map<String, Object> result = new LinkedHashMap<String, Object>(
|
||||
(Map) existing);
|
||||
merge(result, (Map) value);
|
||||
output.put(key, result);
|
||||
} else {
|
||||
output.put(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return Map.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if a singleton should be created, or a new object on each request otherwise.
|
||||
* Default is <code>true</code> (a singleton).
|
||||
*/
|
||||
public void setSingleton(boolean singleton) {
|
||||
this.singleton = singleton;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return this.singleton;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,317 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.config;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
|
||||
/**
|
||||
* Base class for Yaml factories.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 3.2
|
||||
*/
|
||||
public class YamlProcessor {
|
||||
|
||||
public interface MatchCallback {
|
||||
void process(Properties properties, Map<String, Object> map);
|
||||
}
|
||||
|
||||
public interface DocumentMatcher {
|
||||
boolean matches(Properties properties);
|
||||
}
|
||||
|
||||
private static final Log logger = LogFactory.getLog(YamlProcessor.class);
|
||||
|
||||
public static enum ResolutionMethod {
|
||||
OVERRIDE, OVERRIDE_AND_IGNORE, FIRST_FOUND
|
||||
}
|
||||
|
||||
private ResolutionMethod resolutionMethod = ResolutionMethod.OVERRIDE;
|
||||
|
||||
private Resource[] resources = new Resource[0];
|
||||
|
||||
private List<DocumentMatcher> documentMatchers = Collections.emptyList();
|
||||
|
||||
private boolean matchDefault = true;
|
||||
|
||||
/**
|
||||
* A map of document matchers allowing callers to selectively use only some of the
|
||||
* documents in a YAML resource. In YAML documents are separated by
|
||||
* <code>---<code> lines, and each document is converted to properties before the match is made. E.g.
|
||||
*
|
||||
* <pre>
|
||||
* environment: dev
|
||||
* url: http://dev.bar.com
|
||||
* name: Developer Setup
|
||||
* ---
|
||||
* environment: prod
|
||||
* url:http://foo.bar.com
|
||||
* name: My Cool App
|
||||
* </pre>
|
||||
*
|
||||
* when mapped with <code>documentMatchers = YamlProcessor.mapMatcher({"environment": "prod"})</code>
|
||||
* would end up as
|
||||
*
|
||||
* <pre>
|
||||
* environment=prod
|
||||
* url=http://foo.bar.com
|
||||
* name=My Cool App
|
||||
* url=http://dev.bar.com
|
||||
* </pre>
|
||||
*
|
||||
* @param matchers a map of keys to value patterns (regular expressions)
|
||||
*/
|
||||
public void setDocumentMatchers(List<? extends DocumentMatcher> matchers) {
|
||||
this.documentMatchers = Collections.unmodifiableList(matchers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag indicating that a document that contains none of the keys in the
|
||||
* {@link #setDocumentMatchers(List) document matchers} will nevertheless match.
|
||||
*
|
||||
* @param matchDefault the flag to set (default true)
|
||||
*/
|
||||
public void setMatchDefault(boolean matchDefault) {
|
||||
this.matchDefault = matchDefault;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to use for resolving resources. Each resource will be converted to a Map, so
|
||||
* this property is used to decide which map entries to keep in the final output from
|
||||
* this factory. Possible values:
|
||||
* <ul>
|
||||
* <li><code>OVERRIDE</code> for replacing values from earlier in the list</li>
|
||||
* <li><code>FIRST_FOUND</code> if you want to take the first resource in the list
|
||||
* that exists and use just that.</li>
|
||||
* </ul>
|
||||
*
|
||||
*
|
||||
* @param resolutionMethod the resolution method to set. Defaults to OVERRIDE.
|
||||
*/
|
||||
public void setResolutionMethod(ResolutionMethod resolutionMethod) {
|
||||
this.resolutionMethod = resolutionMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param resources the resources to set
|
||||
*/
|
||||
public void setResources(Resource[] resources) {
|
||||
this.resources = resources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides an opportunity for subclasses to process the Yaml parsed from the supplied
|
||||
* resources. Each resource is parsed in turn and the documents inside checked against
|
||||
* the {@link #setDocumentMatchers(List) matchers}. If a document matches it is passed
|
||||
* into the callback, along with its representation as Properties. Depending on the
|
||||
* {@link #setResolutionMethod(ResolutionMethod)} not all of the documents will be
|
||||
* parsed.
|
||||
*
|
||||
* @param callback a callback to delegate to once matching documents are found
|
||||
*/
|
||||
protected void process(MatchCallback callback) {
|
||||
Yaml yaml = new Yaml();
|
||||
boolean found = false;
|
||||
for (Resource resource : this.resources) {
|
||||
try {
|
||||
logger.info("Loading from YAML: " + resource);
|
||||
int count = 0;
|
||||
for (Object object : yaml.loadAll(resource.getInputStream())) {
|
||||
if (this.resolutionMethod != ResolutionMethod.FIRST_FOUND || !found) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> map = (Map<String, Object>) object;
|
||||
if (map != null) {
|
||||
found = process(map, callback);
|
||||
if (found) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Loaded " + count + " document" + (count > 1 ? "s" : "")
|
||||
+ " from YAML resource: " + resource);
|
||||
|
||||
if (this.resolutionMethod == ResolutionMethod.FIRST_FOUND && found) {
|
||||
// No need to load any more resources
|
||||
break;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
if (this.resolutionMethod == ResolutionMethod.FIRST_FOUND
|
||||
|| this.resolutionMethod == ResolutionMethod.OVERRIDE_AND_IGNORE) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Could not load map from " + resource + ": "
|
||||
+ e.getMessage());
|
||||
}
|
||||
} else {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean process(Map<String, Object> map, MatchCallback callback) {
|
||||
Properties properties = new Properties();
|
||||
assignProperties(properties, map, null);
|
||||
if (this.documentMatchers.isEmpty()) {
|
||||
logger.debug("Merging document (no matchers set)" + map);
|
||||
callback.process(properties, map);
|
||||
} else {
|
||||
boolean valueFound = false;
|
||||
for (DocumentMatcher matcher : this.documentMatchers) {
|
||||
if (matcher.matches(properties)) {
|
||||
callback.process(properties, map);
|
||||
valueFound = true;
|
||||
// No need to check for more matches
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!valueFound && this.matchDefault) {
|
||||
logger.debug("Matched document with default matcher: " + map);
|
||||
callback.process(properties, map);
|
||||
} else if (!valueFound) {
|
||||
logger.debug("Unmatched document");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void assignProperties(Properties properties, Map<String, Object> input,
|
||||
String path) {
|
||||
for (Entry<String, Object> entry : input.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
if (StringUtils.hasText(path)) {
|
||||
if (key.startsWith("[")) {
|
||||
key = path + key;
|
||||
} else {
|
||||
key = path + "." + key;
|
||||
}
|
||||
}
|
||||
Object value = entry.getValue();
|
||||
if (value instanceof String) {
|
||||
properties.put(key, value);
|
||||
} else if (value instanceof Map) {
|
||||
// Need a compound key
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> map = (Map<String, Object>) value;
|
||||
assignProperties(properties, map, key);
|
||||
} else if (value instanceof Collection) {
|
||||
// Need a compound key
|
||||
@SuppressWarnings("unchecked")
|
||||
Collection<Object> collection = (Collection<Object>) value;
|
||||
properties.put(key,
|
||||
StringUtils.collectionToCommaDelimitedString(collection));
|
||||
int count = 0;
|
||||
for (Object object : collection) {
|
||||
assignProperties(properties,
|
||||
Collections.singletonMap("[" + (count++) + "]", object), key);
|
||||
}
|
||||
} else {
|
||||
properties.put(key, value == null ? "" : value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches a document containing a given key and where the value of that key matches
|
||||
* one of the given values (interpreted as a regex).
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public static class SimpleDocumentMatcher implements DocumentMatcher {
|
||||
|
||||
private String key;
|
||||
|
||||
private String[] patterns;
|
||||
|
||||
public SimpleDocumentMatcher(final String key, final String... patterns) {
|
||||
this.key = key;
|
||||
this.patterns = patterns;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Properties properties) {
|
||||
if (!properties.containsKey(this.key)) {
|
||||
return false;
|
||||
}
|
||||
String value = properties.getProperty(this.key);
|
||||
for (String pattern : this.patterns) {
|
||||
if (value == null || value.matches(pattern)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches a document containing a given key and where the value of that key is an
|
||||
* array containing one of the given values, or where one of the values matches one of
|
||||
* the given values (interpreted as regexes).
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public static class ArrayDocumentMatcher implements DocumentMatcher {
|
||||
|
||||
private String key;
|
||||
|
||||
private String[] patterns;
|
||||
|
||||
public ArrayDocumentMatcher(final String key, final String... patterns) {
|
||||
this.key = key;
|
||||
this.patterns = patterns;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Properties properties) {
|
||||
if (!properties.containsKey(this.key)) {
|
||||
return false;
|
||||
}
|
||||
Set<String> values = StringUtils.commaDelimitedListToSet(properties
|
||||
.getProperty(this.key));
|
||||
for (String pattern : this.patterns) {
|
||||
for (String value : values) {
|
||||
if (value.matches(pattern)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.config;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
|
||||
/**
|
||||
* Factory for Java Properties that reads from a YAML source. YAML is a nice
|
||||
* human-readable format for configuration, and it has some useful hierarchical
|
||||
* properties. It's more or less a superset of JSON, so it has a lot of similar features.
|
||||
* The Properties created by this factory have nested paths for hierarchical objects, so
|
||||
* for instance this YAML
|
||||
*
|
||||
* <pre>
|
||||
* environments:
|
||||
* dev:
|
||||
* url: http://dev.bar.com
|
||||
* name: Developer Setup
|
||||
* prod:
|
||||
* url: http://foo.bar.com
|
||||
* name: My Cool App
|
||||
* </pre>
|
||||
*
|
||||
* is transformed into these Properties:
|
||||
*
|
||||
* <pre>
|
||||
* environments.dev.url=http://dev.bar.com
|
||||
* environments.dev.name=Developer Setup
|
||||
* environments.prod.url=http://foo.bar.com
|
||||
* environments.prod.name=My Cool App
|
||||
* </pre>
|
||||
*
|
||||
* Lists are represented as comma-separated values (useful for simple String values) and
|
||||
* also as property keys with <code>[]</code> dereferencers, for example this YAML:
|
||||
*
|
||||
* <pre>
|
||||
* servers:
|
||||
* - dev.bar.com
|
||||
* - foo.bar.com
|
||||
* </pre>
|
||||
*
|
||||
* becomes java Properties like this:
|
||||
*
|
||||
* <pre>
|
||||
* servers=dev.bar.com,foo.bar.com
|
||||
* servers[0]=dev.bar.com
|
||||
* servers[1]=foo.bar.com
|
||||
* </pre>
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 3.2
|
||||
*
|
||||
*/
|
||||
public class YamlPropertiesFactoryBean extends YamlProcessor implements
|
||||
FactoryBean<Properties> {
|
||||
|
||||
private boolean singleton = true;
|
||||
|
||||
private Properties instance;
|
||||
|
||||
@Override
|
||||
public Properties getObject() {
|
||||
if (!this.singleton || this.instance == null) {
|
||||
final Properties result = new Properties();
|
||||
MatchCallback callback = new MatchCallback() {
|
||||
@Override
|
||||
public void process(Properties properties, Map<String, Object> map) {
|
||||
result.putAll(properties);
|
||||
}
|
||||
};
|
||||
process(callback);
|
||||
this.instance = result;
|
||||
}
|
||||
return this.instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return Properties.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if a singleton should be created, or a new object on each request otherwise.
|
||||
* Default is <code>true</code> (a singleton).
|
||||
*/
|
||||
public void setSingleton(boolean singleton) {
|
||||
this.singleton = singleton;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return this.singleton;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.context.annotation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
* Base for {@link OnBeanCondition} and {@link OnMissingBeanCondition}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
abstract class AbstractOnBeanCondition implements Condition {
|
||||
|
||||
protected abstract Class<?> annotationClass();
|
||||
|
||||
@Override
|
||||
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
MultiValueMap<String, Object> attributes = metadata.getAllAnnotationAttributes(
|
||||
annotationClass().getName(), true);
|
||||
List<String> beanClasses = collect(attributes, "value");
|
||||
List<String> beanNames = collect(attributes, "value");
|
||||
Assert.isTrue(beanClasses.size() > 0 || beanNames.size() > 0,
|
||||
"@" + ClassUtils.getShortName(annotationClass())
|
||||
+ " annotations must specify at least one bean");
|
||||
|
||||
List<String> beanClassesFound = new ArrayList<String>();
|
||||
List<String> beanNamesFound = new ArrayList<String>();
|
||||
|
||||
for (String beanClass : beanClasses) {
|
||||
try {
|
||||
// eagerInit set to false to prevent early instantiation (some
|
||||
// factory beans will not be able to determine their object type at this
|
||||
// stage, so those are not eligible for matching this condition)
|
||||
String[] beans = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
|
||||
context.getBeanFactory(),
|
||||
ClassUtils.forName(beanClass, context.getClassLoader()), false,
|
||||
false);
|
||||
if (beans.length != 0) {
|
||||
beanClassesFound.add(beanClass);
|
||||
}
|
||||
} catch (ClassNotFoundException ex) {
|
||||
}
|
||||
}
|
||||
|
||||
for (String beanName : beanNames) {
|
||||
if (context.getBeanFactory().containsBeanDefinition(beanName)) {
|
||||
beanNamesFound.add(beanName);
|
||||
}
|
||||
}
|
||||
|
||||
return evaluate(beanClassesFound, beanNamesFound);
|
||||
}
|
||||
|
||||
protected boolean evaluate(List<String> beanClassesFound, List<String> beanNamesFound) {
|
||||
return !beanClassesFound.isEmpty() || !beanNamesFound.isEmpty();
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private List<String> collect(MultiValueMap<String, Object> attributes, String key) {
|
||||
List<String> collected = new ArrayList<String>();
|
||||
List<String[]> valueList = (List) attributes.get(key);
|
||||
for (String[] valueArray : valueList) {
|
||||
for (String value : valueArray) {
|
||||
collected.add(value);
|
||||
}
|
||||
}
|
||||
return collected;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.context.annotation;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
|
||||
/**
|
||||
* Convenience class for storing base packages during component scan, for reference later
|
||||
* (e.g. by JPA entity scanner).
|
||||
*
|
||||
* @author Phil Webb
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public abstract class AutoConfigurationUtils {
|
||||
|
||||
private static String BASE_PACKAGES_BEAN = AutoConfigurationUtils.class.getName()
|
||||
+ ".basePackages";
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static List<String> getBasePackages(BeanFactory beanFactory) {
|
||||
try {
|
||||
return beanFactory.getBean(BASE_PACKAGES_BEAN, List.class);
|
||||
} catch (NoSuchBeanDefinitionException e) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
public static void storeBasePackages(ConfigurableListableBeanFactory beanFactory,
|
||||
List<String> basePackages) {
|
||||
beanFactory.registerSingleton(BASE_PACKAGES_BEAN,
|
||||
Collections.unmodifiableList(basePackages));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.context.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
|
||||
/**
|
||||
* {@link Conditional} that only matches when the specified bean classes and/or names are
|
||||
* already contained in the {@link BeanFactory}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Conditional(OnBeanCondition.class)
|
||||
public @interface ConditionalOnBean {
|
||||
|
||||
/**
|
||||
* The class type of bean that should be checked. The condition matches when any of
|
||||
* the classes specified is contained in the {@link ApplicationContext}.
|
||||
* @return the class types of beans to check
|
||||
*/
|
||||
Class<?>[] value() default {};
|
||||
|
||||
/**
|
||||
* The names of beans to check. The condition matches when any of the bean names
|
||||
* specified is contained in the {@link ApplicationContext}.
|
||||
* @return the name of beans to check
|
||||
*/
|
||||
String[] name() default {};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.context.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
|
||||
/**
|
||||
* {@link Conditional} that only matches when the specified classes are on the classpath.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Conditional(OnClassCondition.class)
|
||||
public @interface ConditionalOnClass {
|
||||
|
||||
/**
|
||||
* The classes that must be present. Since this annotation parsed by loading class
|
||||
* bytecode it is safe to specify classes here that may ultimately not be on the
|
||||
* classpath.
|
||||
* @return the classes that must be present
|
||||
*/
|
||||
public Class<?>[] value() default {};
|
||||
|
||||
/**
|
||||
* The classes names that must be present. When possible {@link #value()} should be
|
||||
* used in preference to this property.
|
||||
* @return the class names that must be present.
|
||||
*/
|
||||
public String[] name() default {};
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.context.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
|
||||
/**
|
||||
* Configuration annotation for a conditional element that depends on teh value of a SpEL
|
||||
* expression.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
@Conditional(ExpressionCondition.class)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
public @interface ConditionalOnExpression {
|
||||
String value() default "true";
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.context.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
|
||||
/**
|
||||
* {@link Conditional} that only matches when the specified bean classes and/or names are
|
||||
* not already contained in the {@link BeanFactory}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Conditional(OnMissingBeanCondition.class)
|
||||
public @interface ConditionalOnMissingBean {
|
||||
|
||||
/**
|
||||
* The class type of bean that should be checked. The condition matches when each
|
||||
* class specified is missing in the {@link ApplicationContext}.
|
||||
* @return the class types of beans to check
|
||||
*/
|
||||
Class<?>[] value() default {};
|
||||
|
||||
/**
|
||||
* The names of beans to check. The condition matches when each bean name specified is
|
||||
* missing in the {@link ApplicationContext}.
|
||||
* @return the name of beans to check
|
||||
*/
|
||||
String[] name() default {};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.context.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.bootstrap.bind.PropertySourcesBindingPostProcessor;
|
||||
|
||||
/**
|
||||
* Annotation for externalized configuration. Add this to a class definition if you want
|
||||
* to bind and validate some external Properties (e.g. from a .properties file).
|
||||
*
|
||||
* @see PropertySourcesBindingPostProcessor
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface ConfigurationProperties {
|
||||
|
||||
/**
|
||||
* The (optional) name of the object to be bound. Properties to bind can have a name
|
||||
* prefix to select the properties that are valid to this object. Synonym for
|
||||
* {@link #name()}.
|
||||
*
|
||||
* @return the name prefix of the properties to bind
|
||||
*/
|
||||
String value() default "";
|
||||
|
||||
/**
|
||||
* The (optional) name of the object to be bound. Properties to bind can have a name
|
||||
* prefix to select the properties that are valid to this object. Synonym for
|
||||
* {@link #value()}.
|
||||
*
|
||||
* @return the name prefix of the properties to bind
|
||||
*/
|
||||
String name() default "";
|
||||
|
||||
/**
|
||||
* Flag to indicate that when binding to this object invalid fields should be ignored.
|
||||
* Invalid means invalid according to the binder that is used, and usually this means
|
||||
* fields of the wrong type (or that cannot be coerced into the correct type).
|
||||
*
|
||||
* @return the flag value (default false)
|
||||
*/
|
||||
boolean ignoreInvalidFields() default false;
|
||||
|
||||
/**
|
||||
* Flag to indicate that when binding to this object unknown fields should be ignored.
|
||||
* An unknown field could be a sign of a mistake in the Properties.
|
||||
*
|
||||
* @return the flag value (default true)
|
||||
*/
|
||||
boolean ignoreUnknownFields() default true;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.context.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.bootstrap.context.embedded.EmbeddedServletContainerFactory;
|
||||
import org.springframework.bootstrap.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||
|
||||
/**
|
||||
* Enable auto-configuration of the Spring Application Context, attempting to guess and
|
||||
* configure beans that you are likely to need.
|
||||
*
|
||||
* Auto-configuration classes are usually applied based on your classpath and what beans
|
||||
* you have defined. For example, If you have {@code tomat-embedded.jar} on your classpath
|
||||
* you are likely to want a {@link TomcatEmbeddedServletContainerFactory} (unless you have
|
||||
* defined your own {@link EmbeddedServletContainerFactory} bean).
|
||||
*
|
||||
* <p>
|
||||
* Auto-configuration tries to be as intelligent as possible and will back-away as you
|
||||
* define more of your own configuration. You can always manually {@link #exclude()} any
|
||||
* configuration that you never want to apply. Auto-configuration is always applied after
|
||||
* user-defined beans have been registered.
|
||||
*
|
||||
* <p>
|
||||
* Auto-configuration classes are regular Spring {@link Configuration} beans. They are
|
||||
* located using the {@link SpringFactoriesLoader} mechanism (keyed against this class).
|
||||
* Generally auto-configuration beans are {@link Conditional @Conditional} beans (most
|
||||
* often using {@link ConditionalOnClass @ConditionalOnClass} and
|
||||
* {@link ConditionalOnMissingBean @ConditionalOnMissingBean} annotations).
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @see ConditionalOnBean
|
||||
* @see ConditionalOnMissingBean
|
||||
* @see ConditionalOnClass
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Import(EnableAutoConfigurationImportSelector.class)
|
||||
public @interface EnableAutoConfiguration {
|
||||
|
||||
/**
|
||||
* Exclude a specific auto-configuration class such that it will never be applied.
|
||||
*/
|
||||
Class<?>[] exclude() default {};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.context.annotation;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.cglib.proxy.Enhancer;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.DeferredImportSelector;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.core.type.StandardAnnotationMetadata;
|
||||
import org.springframework.core.type.classreading.MetadataReader;
|
||||
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link DeferredImportSelector} to handle {@link EnableAutoConfiguration
|
||||
* auto-configuration}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @see EnableAutoConfiguration
|
||||
*/
|
||||
@Order(Ordered.LOWEST_PRECEDENCE)
|
||||
class EnableAutoConfigurationImportSelector implements DeferredImportSelector,
|
||||
BeanClassLoaderAware, BeanFactoryAware {
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private ClassLoader beanClassLoader;
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
private MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
|
||||
|
||||
@Override
|
||||
public String[] selectImports(AnnotationMetadata metadata) {
|
||||
storeComponentScanBasePackages();
|
||||
AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata
|
||||
.getAnnotationAttributes(EnableAutoConfiguration.class.getName(), true));
|
||||
List<String> factories = new ArrayList<String>(
|
||||
SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class,
|
||||
this.beanClassLoader));
|
||||
factories.removeAll(Arrays.asList(attributes.getStringArray("exclude")));
|
||||
return factories.toArray(new String[factories.size()]);
|
||||
}
|
||||
|
||||
private void storeComponentScanBasePackages() {
|
||||
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
|
||||
storeComponentScanBasePackages((ConfigurableListableBeanFactory) this.beanFactory);
|
||||
} else {
|
||||
if (this.logger.isWarnEnabled()) {
|
||||
this.logger
|
||||
.warn("Unable to read @ComponentScan annotations for auto-configure");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void storeComponentScanBasePackages(
|
||||
ConfigurableListableBeanFactory beanFactory) {
|
||||
List<String> basePackages = new ArrayList<String>();
|
||||
for (String beanName : beanFactory.getBeanDefinitionNames()) {
|
||||
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
|
||||
String[] basePackagesAttribute = (String[]) beanDefinition
|
||||
.getAttribute("componentScanBasePackages");
|
||||
if (basePackagesAttribute != null) {
|
||||
basePackages.addAll(Arrays.asList(basePackagesAttribute));
|
||||
}
|
||||
AnnotationMetadata metadata = getMetadata(beanDefinition);
|
||||
basePackages.addAll(getBasePackages(metadata));
|
||||
}
|
||||
AutoConfigurationUtils.storeBasePackages(beanFactory, basePackages);
|
||||
}
|
||||
|
||||
private AnnotationMetadata getMetadata(BeanDefinition beanDefinition) {
|
||||
if (beanDefinition instanceof AbstractBeanDefinition
|
||||
&& ((AbstractBeanDefinition) beanDefinition).hasBeanClass()) {
|
||||
Class<?> beanClass = ((AbstractBeanDefinition) beanDefinition).getBeanClass();
|
||||
if (Enhancer.isEnhanced(beanClass)) {
|
||||
beanClass = beanClass.getSuperclass();
|
||||
}
|
||||
return new StandardAnnotationMetadata(beanClass, true);
|
||||
}
|
||||
String className = beanDefinition.getBeanClassName();
|
||||
if (className != null) {
|
||||
try {
|
||||
MetadataReader metadataReader = this.metadataReaderFactory
|
||||
.getMetadataReader(className);
|
||||
return metadataReader.getAnnotationMetadata();
|
||||
} catch (IOException ex) {
|
||||
if (this.logger.isDebugEnabled()) {
|
||||
this.logger.debug(
|
||||
"Could not find class file for introspecting @ComponentScan classes: "
|
||||
+ className, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<String> getBasePackages(AnnotationMetadata metadata) {
|
||||
AnnotationAttributes attributes = AnnotationAttributes
|
||||
.fromMap((metadata == null ? null : metadata.getAnnotationAttributes(
|
||||
ComponentScan.class.getName(), true)));
|
||||
if (attributes != null) {
|
||||
List<String> basePackages = new ArrayList<String>();
|
||||
addAllHavingText(basePackages, attributes.getStringArray("value"));
|
||||
addAllHavingText(basePackages, attributes.getStringArray("basePackages"));
|
||||
for (String packageClass : attributes.getStringArray("basePackageClasses")) {
|
||||
basePackages.add(ClassUtils.getPackageName(packageClass));
|
||||
}
|
||||
if (basePackages.isEmpty()) {
|
||||
basePackages.add(ClassUtils.getPackageName(metadata.getClassName()));
|
||||
}
|
||||
return basePackages;
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private void addAllHavingText(List<String> list, String[] strings) {
|
||||
for (String s : strings) {
|
||||
if (StringUtils.hasText(s)) {
|
||||
list.add(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
this.beanClassLoader = classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.context.annotation;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanExpressionContext;
|
||||
import org.springframework.beans.factory.config.BeanExpressionResolver;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
|
||||
/**
|
||||
* A Condition that evaluates a SpEL expression.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class ExpressionCondition implements Condition {
|
||||
|
||||
@Override
|
||||
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
String value = (String) metadata.getAnnotationAttributes(
|
||||
ConditionalOnExpression.class.getName()).get("value");
|
||||
if (!value.startsWith("#{")) {
|
||||
// For convenience allow user to provide bare expression with no #{} wrapper
|
||||
value = "#{" + value + "}";
|
||||
}
|
||||
// Explicitly allow environment placeholders inside the expression
|
||||
value = context.getEnvironment().resolvePlaceholders(value);
|
||||
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
|
||||
BeanExpressionResolver resolver = beanFactory.getBeanExpressionResolver();
|
||||
BeanExpressionContext expressionContext = (beanFactory != null) ? new BeanExpressionContext(
|
||||
beanFactory, null) : null;
|
||||
return (Boolean) resolver.evaluate(value, expressionContext);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.context.annotation;
|
||||
|
||||
import org.springframework.context.annotation.Condition;
|
||||
|
||||
/**
|
||||
* {@link Condition} that checks that specific beans are present.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @see ConditionalOnBean
|
||||
*/
|
||||
class OnBeanCondition extends AbstractOnBeanCondition {
|
||||
|
||||
@Override
|
||||
protected Class<?> annotationClass() {
|
||||
return ConditionalOnBean.class;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.context.annotation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
* {@link Condition} that checks for the specific classes.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @see ConditionalOnClass
|
||||
*/
|
||||
class OnClassCondition implements Condition {
|
||||
|
||||
@Override
|
||||
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
MultiValueMap<String, Object> attributes = metadata.getAllAnnotationAttributes(
|
||||
ConditionalOnClass.class.getName(), true);
|
||||
if (attributes != null) {
|
||||
List<String> classNames = new ArrayList<String>();
|
||||
collectClassNames(classNames, attributes.get("value"));
|
||||
collectClassNames(classNames, attributes.get("name"));
|
||||
Assert.isTrue(classNames.size() > 0,
|
||||
"@ConditionalOnClass annotations must specify at least one class value");
|
||||
for (String className : classNames) {
|
||||
if (!ClassUtils.isPresent(className, context.getClassLoader())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void collectClassNames(List<String> classNames, List<Object> values) {
|
||||
for (Object value : values) {
|
||||
for (Object valueItem : (Object[]) value) {
|
||||
classNames.add(valueItem instanceof Class<?> ? ((Class<?>) valueItem)
|
||||
.getName() : valueItem.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.context.annotation;
|
||||
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
|
||||
/**
|
||||
* {@link Condition} that checks that specific beans are missing.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @see ConditionalOnMissingBean
|
||||
*/
|
||||
class OnMissingBeanCondition extends AbstractOnBeanCondition {
|
||||
|
||||
@Override
|
||||
protected Class<?> annotationClass() {
|
||||
return ConditionalOnMissingBean.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
return !super.matches(context, metadata);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,305 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.context.embedded;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.ServletContextInitializer;
|
||||
|
||||
/**
|
||||
* Abstract base class for {@link EmbeddedServletContainerFactory} implementations.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Dave Syer
|
||||
* @since 4.0
|
||||
*/
|
||||
public abstract class AbstractEmbeddedServletContainerFactory implements
|
||||
EmbeddedServletContainerFactory {
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private String contextPath = "";
|
||||
|
||||
private boolean registerDefaultServlet = true;
|
||||
|
||||
private boolean registerJspServlet = true;
|
||||
|
||||
private String jspServletClassName = "org.apache.jasper.servlet.JspServlet";
|
||||
|
||||
private int port = 8080;
|
||||
|
||||
private List<ServletContextInitializer> initializers = new ArrayList<ServletContextInitializer>();
|
||||
|
||||
private File documentRoot;
|
||||
|
||||
private Set<ErrorPage> errorPages = new LinkedHashSet<ErrorPage>();
|
||||
|
||||
/**
|
||||
* Create a new {@link AbstractEmbeddedServletContainerFactory} instance.
|
||||
*/
|
||||
public AbstractEmbeddedServletContainerFactory() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link AbstractEmbeddedServletContainerFactory} instance with the
|
||||
* specified port.
|
||||
* @param port the port number for the embedded servlet container
|
||||
*/
|
||||
public AbstractEmbeddedServletContainerFactory(int port) {
|
||||
setPort(port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link AbstractEmbeddedServletContainerFactory} instance with the
|
||||
* specified context path and port.
|
||||
* @param contextPath the context path for the embedded servlet container
|
||||
* @param port the port number for the embedded servlet container
|
||||
*/
|
||||
public AbstractEmbeddedServletContainerFactory(String contextPath, int port) {
|
||||
setContextPath(contextPath);
|
||||
setPort(port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the context path for the embedded servlet container. The context should start
|
||||
* with a "/" character but not end with a "/" character. The default context path can
|
||||
* be specified using an empty string.
|
||||
* @param contextPath the contextPath to set
|
||||
* @see #getContextPath
|
||||
*/
|
||||
public void setContextPath(String contextPath) {
|
||||
Assert.notNull(contextPath, "ContextPath must not be null");
|
||||
if (contextPath.length() > 0) {
|
||||
if ("/".equals(contextPath)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Root ContextPath must be specified using an empty string");
|
||||
}
|
||||
if (!contextPath.startsWith("/") || contextPath.endsWith("/")) {
|
||||
throw new IllegalArgumentException(
|
||||
"ContextPath must start with '/ and not end with '/'");
|
||||
}
|
||||
}
|
||||
this.contextPath = contextPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the context path for the embedded servlet container. The path will start
|
||||
* with "/" and not end with "/". The root context is represented by an empty string.
|
||||
*/
|
||||
public String getContextPath() {
|
||||
return this.contextPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the port that the embedded servlet container should listen on. If not
|
||||
* specified port '8080' will be used.
|
||||
* @param port the port to set
|
||||
*/
|
||||
public void setPort(int port) {
|
||||
if (port < 1 || port > 65535) {
|
||||
throw new IllegalArgumentException("Port must be between 1 and 65535");
|
||||
}
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the port that the embedded servlet container should listen on.
|
||||
*/
|
||||
public int getPort() {
|
||||
return this.port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets {@link ServletContextInitializer} that should be applied in addition to
|
||||
* {@link #getEmbdeddedServletContainer(ServletContextInitializer...)} parameters.
|
||||
* This method will replace any previously set or added initializers.
|
||||
* @param initializers the initializers to set
|
||||
* @see #addInitializers
|
||||
* @see #getInitializers
|
||||
*/
|
||||
public void setInitializers(List<? extends ServletContextInitializer> initializers) {
|
||||
Assert.notNull(initializers, "Initializers must not be null");
|
||||
this.initializers = new ArrayList<ServletContextInitializer>(initializers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add {@link ServletContextInitializer}s to those that should be applied in addition
|
||||
* to {@link #getEmbdeddedServletContainer(ServletContextInitializer...)} parameters.
|
||||
* @param initializers the initializers to add
|
||||
* @see #setInitializers
|
||||
* @see #getInitializers
|
||||
*/
|
||||
public void addInitializers(ServletContextInitializer... initializers) {
|
||||
Assert.notNull(initializers, "Initializers must not be null");
|
||||
this.initializers.addAll(Arrays.asList(initializers));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a mutable list of {@link ServletContextInitializer} that should be applied
|
||||
* in addition to {@link #getEmbdeddedServletContainer(ServletContextInitializer...)}
|
||||
* parameters.
|
||||
* @return the initializers
|
||||
*/
|
||||
public List<ServletContextInitializer> getInitializers() {
|
||||
return this.initializers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the document root folder which will be used by the web context to serve static
|
||||
* files.
|
||||
* @param documentRoot the document root or {@code null} if not required
|
||||
*/
|
||||
public void setDocumentRoot(File documentRoot) {
|
||||
this.documentRoot = documentRoot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the document root which will be used by the web context to serve static
|
||||
* files.
|
||||
*/
|
||||
public File getDocumentRoot() {
|
||||
return this.documentRoot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the error pages that will be used when handling exceptions.
|
||||
* @param errorPages the error pages
|
||||
*/
|
||||
public void setErrorPages(Set<ErrorPage> errorPages) {
|
||||
Assert.notNull(errorPages, "ErrorPages must not be null");
|
||||
this.errorPages = new LinkedHashSet<ErrorPage>(errorPages);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds error pages that will be used when handling exceptions.
|
||||
* @param errorPages the error pages
|
||||
*/
|
||||
public void addErrorPages(ErrorPage... errorPages) {
|
||||
Assert.notNull(this.initializers, "ErrorPages must not be null");
|
||||
this.errorPages.addAll(Arrays.asList(errorPages));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a mutable set of {@link ErrorPage}s that will be used when handling
|
||||
* exceptions.
|
||||
*/
|
||||
public Set<ErrorPage> getErrorPages() {
|
||||
return this.errorPages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if the DefaultServlet should be registered. Defaults to {@code true} so that
|
||||
* files from the {@link #setDocumentRoot(File) document root} will be served.
|
||||
* @param registerDefaultServlet if the default servlet should be registered
|
||||
*/
|
||||
public void setRegisterDefaultServlet(boolean registerDefaultServlet) {
|
||||
this.registerDefaultServlet = registerDefaultServlet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag to indicate that the JSP servlet should be registered if available on the
|
||||
* classpath.
|
||||
*
|
||||
* @return true if the JSP servlet is to be registered
|
||||
*/
|
||||
protected boolean getRegisterJspServlet() {
|
||||
return this.registerJspServlet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if the JspServlet should be registered if it is on the classpath. Defaults to
|
||||
* {@code true} so that files from the {@link #setDocumentRoot(File) document root}
|
||||
* will be served.
|
||||
* @param registerJspServlet if the JSP servlet should be registered
|
||||
*/
|
||||
public void setRegisterJspServlet(boolean registerJspServlet) {
|
||||
this.registerJspServlet = registerJspServlet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag to indicate that the default servlet should be registered.
|
||||
*
|
||||
* @return true if the default servlet is to be registered
|
||||
*/
|
||||
protected boolean getRegisterDefaultServlet() {
|
||||
return this.registerDefaultServlet;
|
||||
}
|
||||
|
||||
/**
|
||||
* The class name for the jsp servlet if used. If
|
||||
* {@link #setRegisterJspServlet(boolean) <code>registerJspServlet</code>} is true
|
||||
* <b>and</b> this class is on the classpath then it will be registered. Since both
|
||||
* Tomcat and Jetty use Jasper for their JSP implementation the default is
|
||||
* <code>org.apache.jasper.servlet.JspServlet</code>.
|
||||
*
|
||||
* @param jspServletClassName the class name for the JSP servlet if used
|
||||
*/
|
||||
public void setJspServletClassName(String jspServletClassName) {
|
||||
this.jspServletClassName = jspServletClassName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the JS{ servlet class name
|
||||
*/
|
||||
protected String getJspServletClassName() {
|
||||
return this.jspServletClassName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method that can be used by subclasses wishing to combine the specified
|
||||
* {@link ServletContextInitializer} parameters with those defined in this instance.
|
||||
* @param initializers the initializers to merge
|
||||
* @return a complete set of merged initializers (with the specified parameters
|
||||
* appearing first)
|
||||
*/
|
||||
protected final ServletContextInitializer[] mergeInitializers(
|
||||
ServletContextInitializer... initializers) {
|
||||
List<ServletContextInitializer> mergedInitializers = new ArrayList<ServletContextInitializer>();
|
||||
mergedInitializers.addAll(Arrays.asList(initializers));
|
||||
mergedInitializers.addAll(getInitializers());
|
||||
return mergedInitializers
|
||||
.toArray(new ServletContextInitializer[mergedInitializers.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute document root when it points to a valid folder, logging a
|
||||
* warning and returning {@code null} otherwise.
|
||||
*/
|
||||
protected final File getValidDocumentRoot() {
|
||||
File[] roots = new File[] { getDocumentRoot(), new File("src/main/webapp"),
|
||||
new File("public") };
|
||||
for (File root : roots) {
|
||||
if (root != null && root.exists() && root.isDirectory()) {
|
||||
return root.getAbsoluteFile();
|
||||
}
|
||||
}
|
||||
if (this.logger.isWarnEnabled()) {
|
||||
this.logger.warn("None of the document roots " + roots
|
||||
+ " point to a directory and will be ignored.");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.context.embedded;
|
||||
|
||||
import org.springframework.beans.factory.support.BeanNameGenerator;
|
||||
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
|
||||
import org.springframework.context.annotation.AnnotationConfigUtils;
|
||||
import org.springframework.context.annotation.AnnotationScopeMetadataResolver;
|
||||
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.ScopeMetadataResolver;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
|
||||
/**
|
||||
* {@link EmbeddedWebApplicationContext} that accepts annotated classes as input - in
|
||||
* particular {@link org.springframework.context.annotation.Configuration
|
||||
* <code>@Configuration</code>} -annotated classes, but also plain
|
||||
* {@link org.springframework.stereotype.Component <code>@Component</code>} classes and
|
||||
* JSR-330 compliant classes using {@code javax.inject} annotations. Allows for
|
||||
* registering classes one by one (specifying class names as config location) as well as
|
||||
* for classpath scanning (specifying base packages as config location).
|
||||
*
|
||||
* <p>
|
||||
* Note: In case of multiple {@code @Configuration} classes, later {@code @Bean}
|
||||
* definitions will override ones defined in earlier loaded files. This can be leveraged
|
||||
* to deliberately override certain bean definitions via an extra Configuration class.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 4.0
|
||||
* @see #register(Class...)
|
||||
* @see #scan(String...)
|
||||
* @see EmbeddedWebApplicationContext
|
||||
* @see AnnotationConfigWebApplicationContext
|
||||
*/
|
||||
public class AnnotationConfigEmbeddedWebApplicationContext extends
|
||||
EmbeddedWebApplicationContext {
|
||||
|
||||
private final AnnotatedBeanDefinitionReader reader;
|
||||
|
||||
private final ClassPathBeanDefinitionScanner scanner;
|
||||
|
||||
/**
|
||||
* Create a new {@link AnnotationConfigEmbeddedWebApplicationContext} that needs to be
|
||||
* populated through {@link #register} calls and then manually {@linkplain #refresh
|
||||
* refreshed}.
|
||||
*/
|
||||
public AnnotationConfigEmbeddedWebApplicationContext() {
|
||||
this.reader = new AnnotatedBeanDefinitionReader(this);
|
||||
this.scanner = new ClassPathBeanDefinitionScanner(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link AnnotationConfigEmbeddedWebApplicationContext}, deriving bean
|
||||
* definitions from the given annotated classes and automatically refreshing the
|
||||
* context.
|
||||
* @param annotatedClasses one or more annotated classes, e.g. {@link Configuration
|
||||
* <code>@Configuration</code>} classes
|
||||
*/
|
||||
public AnnotationConfigEmbeddedWebApplicationContext(Class<?>... annotatedClasses) {
|
||||
this();
|
||||
register(annotatedClasses);
|
||||
refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link AnnotationConfigEmbeddedWebApplicationContext}, scanning for
|
||||
* bean definitions in the given packages and automatically refreshing the context.
|
||||
* @param basePackages the packages to check for annotated classes
|
||||
*/
|
||||
public AnnotationConfigEmbeddedWebApplicationContext(String... basePackages) {
|
||||
this();
|
||||
scan(basePackages);
|
||||
refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>
|
||||
* Delegates given environment to underlying {@link AnnotatedBeanDefinitionReader} and
|
||||
* {@link ClassPathBeanDefinitionScanner} members.
|
||||
*/
|
||||
@Override
|
||||
public void setEnvironment(ConfigurableEnvironment environment) {
|
||||
super.setEnvironment(environment);
|
||||
this.reader.setEnvironment(environment);
|
||||
this.scanner.setEnvironment(environment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a custom {@link BeanNameGenerator} for use with
|
||||
* {@link AnnotatedBeanDefinitionReader} and/or {@link ClassPathBeanDefinitionScanner}
|
||||
* , if any.
|
||||
* <p>
|
||||
* Default is
|
||||
* {@link org.springframework.context.annotation.AnnotationBeanNameGenerator}.
|
||||
* <p>
|
||||
* Any call to this method must occur prior to calls to {@link #register(Class...)}
|
||||
* and/or {@link #scan(String...)}.
|
||||
* @see AnnotatedBeanDefinitionReader#setBeanNameGenerator
|
||||
* @see ClassPathBeanDefinitionScanner#setBeanNameGenerator
|
||||
*/
|
||||
public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
|
||||
this.reader.setBeanNameGenerator(beanNameGenerator);
|
||||
this.scanner.setBeanNameGenerator(beanNameGenerator);
|
||||
this.getBeanFactory().registerSingleton(
|
||||
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
|
||||
beanNameGenerator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link ScopeMetadataResolver} to use for detected bean classes.
|
||||
* <p>
|
||||
* The default is an {@link AnnotationScopeMetadataResolver}.
|
||||
* <p>
|
||||
* Any call to this method must occur prior to calls to {@link #register(Class...)}
|
||||
* and/or {@link #scan(String...)}.
|
||||
*/
|
||||
public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) {
|
||||
this.reader.setScopeMetadataResolver(scopeMetadataResolver);
|
||||
this.scanner.setScopeMetadataResolver(scopeMetadataResolver);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register one or more annotated classes to be processed. Note that
|
||||
* {@link #refresh()} must be called in order for the context to fully process the new
|
||||
* class.
|
||||
* <p>
|
||||
* Calls to {@link #register} are idempotent; adding the same annotated class more
|
||||
* than once has no additional effect.
|
||||
* @param annotatedClasses one or more annotated classes, e.g. {@link Configuration
|
||||
* <code>@Configuration</code>} classes
|
||||
* @see #scan(String...)
|
||||
* @see #refresh()
|
||||
*/
|
||||
public void register(Class<?>... annotatedClasses) {
|
||||
Assert.notEmpty(annotatedClasses,
|
||||
"At least one annotated class must be specified");
|
||||
this.reader.register(annotatedClasses);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a scan within the specified base packages. Note that {@link #refresh()}
|
||||
* must be called in order for the context to fully process the new class.
|
||||
* @param basePackages the packages to check for annotated classes
|
||||
* @see #register(Class...)
|
||||
* @see #refresh()
|
||||
*/
|
||||
public void scan(String... basePackages) {
|
||||
Assert.notEmpty(basePackages, "At least one base package must be specified");
|
||||
this.scanner.scan(basePackages);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void prepareRefresh() {
|
||||
this.scanner.clearCache();
|
||||
super.prepareRefresh();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.context.embedded;
|
||||
|
||||
/**
|
||||
* Simple interface that represents a fully configure embedded servlet container (for
|
||||
* example Tomcat or Jetty). Allows the container to be {@link #stop() stopped}.
|
||||
*
|
||||
* <p>
|
||||
* Instances of this class are usually obtained via a
|
||||
* {@link EmbeddedServletContainerFactory}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 4.0
|
||||
* @see EmbeddedServletContainerFactory
|
||||
*/
|
||||
public interface EmbeddedServletContainer {
|
||||
|
||||
/**
|
||||
* Stops the embedded servlet container. Calling this method on an already stopped
|
||||
* container has no effect.
|
||||
* @throws EmbeddedServletContainerException of the container cannot be stopped
|
||||
*/
|
||||
void stop() throws EmbeddedServletContainerException;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.context.embedded;
|
||||
|
||||
/**
|
||||
* Exceptions thrown by an embedded servlet container.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class EmbeddedServletContainerException extends RuntimeException {
|
||||
|
||||
public EmbeddedServletContainerException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.context.embedded;
|
||||
|
||||
import org.springframework.bootstrap.context.embedded.jetty.JettyEmbeddedServletContainerFactory;
|
||||
import org.springframework.bootstrap.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
|
||||
import org.springframework.web.ServletContextInitializer;
|
||||
|
||||
/**
|
||||
* Factory interface that can be used to create {@link EmbeddedServletContainer}s.
|
||||
* Implementations are encouraged to extends
|
||||
* {@link AbstractEmbeddedServletContainerFactory} when possible.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 4.0
|
||||
* @see EmbeddedServletContainer
|
||||
* @see AbstractEmbeddedServletContainerFactory
|
||||
* @see JettyEmbeddedServletContainerFactory
|
||||
* @see TomcatEmbeddedServletContainerFactory
|
||||
*/
|
||||
public interface EmbeddedServletContainerFactory {
|
||||
|
||||
/**
|
||||
* Gets a new fully configured and started {@link EmbeddedServletContainer}
|
||||
* instance,blocking until the point that clients can connect.
|
||||
* @param initializers {@link ServletContextInitializer}s that should be applied as
|
||||
* the container starts
|
||||
* @return a fully configured and started {@link EmbeddedServletContainer}
|
||||
* @see EmbeddedServletContainer#stop()
|
||||
*/
|
||||
EmbeddedServletContainer getEmbdeddedServletContainer(
|
||||
ServletContextInitializer... initializers);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,320 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.context.embedded;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.Servlet;
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextException;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.web.ServletContextInitializer;
|
||||
import org.springframework.web.context.ContextLoader;
|
||||
import org.springframework.web.context.ContextLoaderListener;
|
||||
import org.springframework.web.context.ServletContextAware;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.support.GenericWebApplicationContext;
|
||||
import org.springframework.web.context.support.ServletContextAwareProcessor;
|
||||
import org.springframework.web.context.support.ServletContextResource;
|
||||
import org.springframework.web.context.support.WebApplicationContextServletContextAwareProcessor;
|
||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||
|
||||
/**
|
||||
* A {@link WebApplicationContext} that can be used to bootstrap itself from a contained
|
||||
* {@link EmbeddedServletContainerFactory} bean.
|
||||
*
|
||||
* <p>
|
||||
* This context will create, initialize and run an {@link EmbeddedServletContainer} by
|
||||
* searching for a single {@link EmbeddedServletContainerFactory} bean within the
|
||||
* {@link ApplicationContext} itself. The {@link EmbeddedServletContainerFactory} is free
|
||||
* to use standard Spring concepts (such as dependency injection, lifecycle callbacks and
|
||||
* property placeholder variables).
|
||||
*
|
||||
* <p>
|
||||
* In addition, any {@link Servlet} or {@link Filter} beans defined in the context will be
|
||||
* automatically registered with the embedded Servlet container. In the case of a single
|
||||
* Servlet bean, the '/*' mapping will be used. If multiple Servlet beans are found then
|
||||
* the lowercase bean name will be used as a mapping prefix. Filter beans will be mapped
|
||||
* to all URLs ('/*').
|
||||
*
|
||||
* <p>
|
||||
* For more advanced configuration, the context can instead define beans that implement
|
||||
* the {@link ServletContextInitializer} interface (most often
|
||||
* {@link ServletRegistrationBean}s and/or {@link FilterRegistrationBean}s). To prevent
|
||||
* double registration, the use of {@link ServletContextInitializer} beans will disable
|
||||
* automatic Servlet and Filter bean registration.
|
||||
*
|
||||
* <p>
|
||||
* Although this context can be used directly, most developers should consider using the
|
||||
* {@link AnnotationConfigEmbeddedWebApplicationContext} or
|
||||
* {@link XmlEmbeddedWebApplicationContext} variants.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 4.0
|
||||
* @see AnnotationConfigEmbeddedWebApplicationContext
|
||||
* @see XmlEmbeddedWebApplicationContext
|
||||
* @see EmbeddedServletContainerFactory
|
||||
*/
|
||||
public class EmbeddedWebApplicationContext extends GenericWebApplicationContext {
|
||||
|
||||
private EmbeddedServletContainer embeddedServletContainer;
|
||||
|
||||
private ServletConfig servletConfig;
|
||||
|
||||
private String namespace;
|
||||
|
||||
/**
|
||||
* Register ServletContextAwareProcessor.
|
||||
* @see ServletContextAwareProcessor
|
||||
*/
|
||||
@Override
|
||||
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
|
||||
beanFactory
|
||||
.addBeanPostProcessor(new WebApplicationContextServletContextAwareProcessor(
|
||||
this));
|
||||
beanFactory.ignoreDependencyInterface(ServletContextAware.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRefresh() {
|
||||
super.onRefresh();
|
||||
registerShutdownHook();
|
||||
createAndStartEmbeddedServletContainer();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doClose() {
|
||||
super.doClose();
|
||||
stopAndReleaseEmbeddedServletContainer();
|
||||
}
|
||||
|
||||
private synchronized void createAndStartEmbeddedServletContainer() {
|
||||
if (this.embeddedServletContainer == null) {
|
||||
EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory();
|
||||
this.embeddedServletContainer = containerFactory
|
||||
.getEmbdeddedServletContainer(getServletContextInitializers());
|
||||
WebApplicationContextUtils.registerWebApplicationScopes(getBeanFactory(),
|
||||
getServletContext());
|
||||
WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(),
|
||||
getServletContext());
|
||||
initPropertySources();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link EmbeddedServletContainerFactory} that should be used to create
|
||||
* the embedded servlet container. By default this method searches for a suitable bean
|
||||
* in the context itself.
|
||||
* @return a {@link EmbeddedServletContainerFactory} (never {@code null})
|
||||
*/
|
||||
protected EmbeddedServletContainerFactory getEmbeddedServletContainerFactory() {
|
||||
try {
|
||||
return getBeanFactory().getBean(EmbeddedServletContainerFactory.class);
|
||||
} catch (NoUniqueBeanDefinitionException ex) {
|
||||
throw new ApplicationContextException(
|
||||
"Unable to start EmbeddedWebApplicationContext due to multiple "
|
||||
+ "EmbeddedServletContainerFactory beans.", ex);
|
||||
} catch (NoSuchBeanDefinitionException ex) {
|
||||
throw new ApplicationContextException(
|
||||
"Unable to start EmbeddedWebApplicationContext due to missing "
|
||||
+ "EmbeddedServletContainerFactory bean.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all {@link ServletContextInitializer}s that should be applied.
|
||||
*/
|
||||
private ServletContextInitializer[] getServletContextInitializers() {
|
||||
List<ServletContextInitializer> initializers = new ArrayList<ServletContextInitializer>();
|
||||
initializers.add(getSelfInitializer());
|
||||
initializers.addAll(getServletContextInitializerBeans());
|
||||
return initializers.toArray(new ServletContextInitializer[initializers.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link ServletContextInitializer} that will be used to complete the
|
||||
* setup of this {@link WebApplicationContext}.
|
||||
* @see #prepareEmbeddedWebApplicationContext(ServletContext)
|
||||
*/
|
||||
private ServletContextInitializer getSelfInitializer() {
|
||||
return new ServletContextInitializer() {
|
||||
@Override
|
||||
public void onStartup(ServletContext servletContext) throws ServletException {
|
||||
prepareEmbeddedWebApplicationContext(servletContext);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link ServletContextInitializer}s that should be used with the embedded
|
||||
* Servlet context. By default this method will first attempt to find
|
||||
* {@link ServletContextInitializer} beans, if none are found it will instead search
|
||||
* for {@link Servlet} and {@link Filter} beans.
|
||||
*/
|
||||
protected Collection<ServletContextInitializer> getServletContextInitializerBeans() {
|
||||
|
||||
Set<ServletContextInitializer> initializers = new LinkedHashSet<ServletContextInitializer>();
|
||||
|
||||
for (Entry<String, ServletContextInitializer> initializerBean : getOrderedBeansOfType(ServletContextInitializer.class)) {
|
||||
initializers.add(initializerBean.getValue());
|
||||
}
|
||||
|
||||
if (initializers.isEmpty()) {
|
||||
|
||||
SortedSet<Entry<String, Servlet>> servletBeans = getOrderedBeansOfType(Servlet.class);
|
||||
for (Entry<String, Servlet> servletBean : servletBeans) {
|
||||
String url = (servletBeans.size() == 1 ? "/" : "/"
|
||||
+ servletBean.getKey().toLowerCase() + "/*");
|
||||
ServletRegistrationBean registration = new ServletRegistrationBean(
|
||||
servletBean.getValue(), url);
|
||||
registration.setName(servletBean.getKey());
|
||||
initializers.add(registration);
|
||||
}
|
||||
|
||||
for (Entry<String, Filter> filterBean : getOrderedBeansOfType(Filter.class)) {
|
||||
FilterRegistrationBean registration = new FilterRegistrationBean(
|
||||
filterBean.getValue());
|
||||
registration.setName(filterBean.getKey());
|
||||
initializers.add(registration);
|
||||
}
|
||||
}
|
||||
|
||||
return initializers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the {@link WebApplicationContext} with the given fully loaded
|
||||
* {@link ServletContext}. This method is usually called from
|
||||
* {@link ServletContextInitializer#onStartup(ServletContext)} and is similar to the
|
||||
* functionality usually provided by a {@link ContextLoaderListener}.
|
||||
* @param servletContext the operational servlet context
|
||||
*/
|
||||
protected void prepareEmbeddedWebApplicationContext(ServletContext servletContext) {
|
||||
if (servletContext
|
||||
.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
|
||||
throw new IllegalStateException(
|
||||
"Cannot initialize context because there is already a root application context present - "
|
||||
+ "check whether you have multiple ServletContextInitializer!");
|
||||
}
|
||||
Log logger = LogFactory.getLog(ContextLoader.class);
|
||||
servletContext.log("Initializing Spring embedded WebApplicationContext");
|
||||
try {
|
||||
servletContext.setAttribute(
|
||||
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Published root WebApplicationContext as ServletContext attribute with name ["
|
||||
+ WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
|
||||
+ "]");
|
||||
}
|
||||
setServletContext(servletContext);
|
||||
if (logger.isInfoEnabled()) {
|
||||
long elapsedTime = System.currentTimeMillis() - getStartupDate();
|
||||
logger.info("Root WebApplicationContext: initialization completed in "
|
||||
+ elapsedTime + " ms");
|
||||
}
|
||||
} catch (RuntimeException ex) {
|
||||
logger.error("Context initialization failed", ex);
|
||||
servletContext.setAttribute(
|
||||
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
|
||||
throw ex;
|
||||
} catch (Error err) {
|
||||
logger.error("Context initialization failed", err);
|
||||
servletContext.setAttribute(
|
||||
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
private <T> SortedSet<Entry<String, T>> getOrderedBeansOfType(Class<T> type) {
|
||||
SortedSet<Entry<String, T>> beans = new TreeSet<Entry<String, T>>(
|
||||
new Comparator<Entry<String, T>>() {
|
||||
@Override
|
||||
public int compare(Entry<String, T> o1, Entry<String, T> o2) {
|
||||
return AnnotationAwareOrderComparator.INSTANCE.compare(
|
||||
o1.getValue(), o2.getValue());
|
||||
}
|
||||
});
|
||||
beans.addAll(getBeanFactory().getBeansOfType(type, true, true).entrySet());
|
||||
return beans;
|
||||
}
|
||||
|
||||
private synchronized void stopAndReleaseEmbeddedServletContainer() {
|
||||
if (this.embeddedServletContainer != null) {
|
||||
try {
|
||||
this.embeddedServletContainer.stop();
|
||||
this.embeddedServletContainer = null;
|
||||
} catch (Exception ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Resource getResourceByPath(String path) {
|
||||
if (getServletContext() == null) {
|
||||
return new ClassPathContextResource(path, getClassLoader());
|
||||
}
|
||||
return new ServletContextResource(getServletContext(), path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNamespace(String namespace) {
|
||||
this.namespace = namespace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNamespace() {
|
||||
return this.namespace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setServletConfig(ServletConfig servletConfig) {
|
||||
this.servletConfig = servletConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletConfig getServletConfig() {
|
||||
return this.servletConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link EmbeddedServletContainer} that was created by the context or
|
||||
* {@code null} if the container has not yet been created.
|
||||
*/
|
||||
public EmbeddedServletContainer getEmbeddedServletContainer() {
|
||||
return this.embeddedServletContainer;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.context.embedded;
|
||||
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Simple container-independent abstraction for servlet error pages. Roughly equivalent to
|
||||
* the {@literal <error-page>} element traditionally found in web.xml.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 4.0
|
||||
*/
|
||||
public class ErrorPage {
|
||||
|
||||
private String path;
|
||||
|
||||
private Class<? extends Throwable> exception = null;
|
||||
|
||||
private int status = 0;
|
||||
|
||||
public ErrorPage(String path) {
|
||||
super();
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public ErrorPage(int status, String path) {
|
||||
super();
|
||||
this.status = status;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public ErrorPage(Class<? extends Throwable> exception, String path) {
|
||||
super();
|
||||
this.exception = exception;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
/**
|
||||
* The path to render (usually implemented as a forward), starting with "/". A custom
|
||||
* controller or servlet path can be used, or if the container supports it, a template
|
||||
* path (e.g. "/error.jsp").
|
||||
*
|
||||
* @return the path that will be rendered for this error
|
||||
*/
|
||||
public String getPath() {
|
||||
return this.path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the exception type (or null for a page that matches by status)
|
||||
*/
|
||||
public Class<? extends Throwable> getException() {
|
||||
return this.exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP status value that this error page matches.
|
||||
*
|
||||
* @return the status value (or 0 for a page that matches any status)
|
||||
*/
|
||||
public int getStatus() {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
/**
|
||||
* The exception type name.
|
||||
*
|
||||
* @return the exception type name (or null if there is none)
|
||||
*/
|
||||
public String getExceptionName() {
|
||||
return this.exception == null ? null : this.exception.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return is this error page a global one (matches all unmatched status and exception
|
||||
* types)?
|
||||
*/
|
||||
public boolean isGlobal() {
|
||||
return this.status == 0 && this.exception == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ObjectUtils.nullSafeHashCode(getExceptionName());
|
||||
result = prime * result + ObjectUtils.nullSafeHashCode(this.path);
|
||||
result = prime * result + this.status;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
ErrorPage other = (ErrorPage) obj;
|
||||
boolean rtn = true;
|
||||
rtn &= ObjectUtils.nullSafeEquals(getExceptionName(), other.getExceptionName());
|
||||
rtn &= ObjectUtils.nullSafeEquals(this.path, other.path);
|
||||
rtn &= this.status == other.status;
|
||||
return rtn;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.context.embedded;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterRegistration;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.ServletContextInitializer;
|
||||
|
||||
/**
|
||||
* A {@link ServletContextInitializer} to register {@link Filter}s in a Servlet 3.0+
|
||||
* container. Similar to the {@link ServletContext#addFilter(String, Filter) registration}
|
||||
* features provided by {@link ServletContext} but with a Spring Bean friendly design.
|
||||
*
|
||||
* <p>
|
||||
* The {@link #setFilter(Filter) Filter} must be specified before calling
|
||||
* {@link #onStartup(ServletContext)}. Registrations can be associated with
|
||||
* {@link #setUrlPatterns URL patterns} and/or servlets (either by
|
||||
* {@link #setServletNames name} or via a {@link #setServletRegistrationBeans
|
||||
* ServletRegistrationBean}s. When no URL pattern or servlets are specified the filter
|
||||
* will be associated to '/*'. The filter name will be deduced if not specified.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 4.0
|
||||
* @see ServletContextInitializer
|
||||
* @see ServletContext#addFilter(String, Filter)
|
||||
*/
|
||||
public class FilterRegistrationBean extends RegistrationBean {
|
||||
|
||||
static final EnumSet<DispatcherType> ASYNC_DISPATCHER_TYPES = EnumSet.of(
|
||||
DispatcherType.FORWARD, DispatcherType.INCLUDE, DispatcherType.REQUEST,
|
||||
DispatcherType.ASYNC);
|
||||
|
||||
static final EnumSet<DispatcherType> NON_ASYNC_DISPATCHER_TYPES = EnumSet.of(
|
||||
DispatcherType.FORWARD, DispatcherType.INCLUDE, DispatcherType.REQUEST);
|
||||
|
||||
private static final String[] DEFAULT_URL_MAPPINGS = { "/*" };
|
||||
|
||||
private Filter filter;
|
||||
|
||||
private Set<ServletRegistrationBean> servletRegistrationBeans = new LinkedHashSet<ServletRegistrationBean>();
|
||||
|
||||
private Set<String> servletNames = new LinkedHashSet<String>();
|
||||
|
||||
private Set<String> urlPatterns = new LinkedHashSet<String>();
|
||||
|
||||
private EnumSet<DispatcherType> dispatcherTypes;
|
||||
|
||||
private boolean matchAfter = false;
|
||||
|
||||
/**
|
||||
* Create a new {@link FilterRegistrationBean} instance.
|
||||
*/
|
||||
public FilterRegistrationBean() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link FilterRegistrationBean} instance to be registered with the
|
||||
* specified {@link ServletRegistrationBean}s.
|
||||
* @param filter the filter to register
|
||||
* @param servletRegistrationBeans associate {@link ServletRegistrationBean}s
|
||||
*/
|
||||
public FilterRegistrationBean(Filter filter,
|
||||
ServletRegistrationBean... servletRegistrationBeans) {
|
||||
setFilter(filter);
|
||||
addServletRegistrationBeans(servletRegistrationBeans);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the filter to be registered.
|
||||
*/
|
||||
public void setFilter(Filter filter) {
|
||||
Assert.notNull(filter, "Filter must not be null");
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set {@link ServletRegistrationBean}s that the filter will be registered against.
|
||||
* @param servletRegistrationBeans the Servlet registration beans
|
||||
*/
|
||||
public void setServletRegistrationBeans(
|
||||
Collection<? extends ServletRegistrationBean> servletRegistrationBeans) {
|
||||
Assert.notNull(servletRegistrationBeans,
|
||||
"ServletRegistrationBeans must not be null");
|
||||
this.servletRegistrationBeans = new LinkedHashSet<ServletRegistrationBean>(
|
||||
servletRegistrationBeans);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a mutable collection of the {@link ServletRegistrationBean} that the filter
|
||||
* will be registered against. {@link ServletRegistrationBean}s.
|
||||
* @return the Servlet registration beans
|
||||
* @see #setServletNames
|
||||
* @see #setUrlPatterns
|
||||
*/
|
||||
public Collection<ServletRegistrationBean> getServletRegistrationBeans() {
|
||||
return this.servletRegistrationBeans;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add {@link ServletRegistrationBean}s for the filter.
|
||||
* @param servletRegistrationBeans the servlet registration beans to add
|
||||
* @see #setServletRegistrationBeans
|
||||
*/
|
||||
public void addServletRegistrationBeans(
|
||||
ServletRegistrationBean... servletRegistrationBeans) {
|
||||
Assert.notNull(servletRegistrationBeans,
|
||||
"ServletRegistrationBeans must not be null");
|
||||
for (ServletRegistrationBean servletRegistrationBean : servletRegistrationBeans) {
|
||||
this.servletRegistrationBeans.add(servletRegistrationBean);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set servlet names that the filter will be registered against. This will replace any
|
||||
* previously specified servlet names.
|
||||
* @param servletNames the servlet names
|
||||
* @see #setServletRegistrationBeans
|
||||
* @see #setUrlPatterns
|
||||
*/
|
||||
public void setServletNames(Collection<String> servletNames) {
|
||||
Assert.notNull(servletNames, "ServletNames must not be null");
|
||||
this.servletNames = new LinkedHashSet<String>(servletNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a mutable collection of servlet names that the filter will be registered
|
||||
* against.
|
||||
* @return the servlet names
|
||||
*/
|
||||
public Collection<String> getServletNames() {
|
||||
return this.servletNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add servlet names for the filter.
|
||||
* @param servletNames the servlet names to add
|
||||
*/
|
||||
public void addServletNames(String... servletNames) {
|
||||
Assert.notNull(servletNames, "ServletNames must not be null");
|
||||
this.servletNames.addAll(Arrays.asList(servletNames));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the URL patterns that the filter will be registered against. This will replace
|
||||
* any previously specified URL patterns.
|
||||
* @param urlPatterns the URL patterns
|
||||
* @see #setServletRegistrationBeans
|
||||
* @see #setServletNames
|
||||
*/
|
||||
public void setUrlPatterns(Collection<String> urlPatterns) {
|
||||
Assert.notNull(urlPatterns, "UrlPatterns must not be null");
|
||||
this.urlPatterns = new LinkedHashSet<String>(urlPatterns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a mutable collection of URL patterns that the filter will be registered
|
||||
* against.
|
||||
* @return the URL patterns
|
||||
*/
|
||||
public Collection<String> getUrlPatterns() {
|
||||
return this.urlPatterns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add URL patterns that the filter will be registered against.
|
||||
* @param urlPatterns the URL patterns
|
||||
*/
|
||||
public void addUrlPatterns(String... urlPatterns) {
|
||||
Assert.notNull(urlPatterns, "UrlPatterns must not be null");
|
||||
for (String urlPattern : urlPatterns) {
|
||||
this.urlPatterns.add(urlPattern);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if the filter mappings should be matched after any declared filter mappings of
|
||||
* the ServletContext. Defaults to {@code false} indicating the filters are supposed
|
||||
* to be matched before any declared filter mappings of the ServletContext.
|
||||
*/
|
||||
public void setMatchAfter(boolean matchAfter) {
|
||||
this.matchAfter = matchAfter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if filter mappings should be matched after any declared Filter mappings of
|
||||
* the ServletContext.
|
||||
*/
|
||||
public boolean isMatchAfter() {
|
||||
return this.matchAfter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartup(ServletContext servletContext) throws ServletException {
|
||||
Assert.notNull(this.filter, "Filter must not be null");
|
||||
configure(servletContext.addFilter(getOrDeduceName(this.filter), this.filter));
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure registration settings. Subclasses can override this method to perform
|
||||
* additional configuration if required.
|
||||
*/
|
||||
protected void configure(FilterRegistration.Dynamic registration) {
|
||||
super.configure(registration);
|
||||
EnumSet<DispatcherType> dispatcherTypes = this.dispatcherTypes;
|
||||
if (dispatcherTypes == null) {
|
||||
dispatcherTypes = (isAsyncSupported() ? ASYNC_DISPATCHER_TYPES
|
||||
: NON_ASYNC_DISPATCHER_TYPES);
|
||||
}
|
||||
|
||||
Set<String> servletNames = new LinkedHashSet<String>();
|
||||
for (ServletRegistrationBean servletRegistrationBean : this.servletRegistrationBeans) {
|
||||
servletNames.add(servletRegistrationBean.getServletName());
|
||||
}
|
||||
servletNames.addAll(this.servletNames);
|
||||
|
||||
if (servletNames.isEmpty() && this.urlPatterns.isEmpty()) {
|
||||
registration.addMappingForUrlPatterns(dispatcherTypes, this.matchAfter,
|
||||
DEFAULT_URL_MAPPINGS);
|
||||
} else {
|
||||
if (servletNames.size() > 0) {
|
||||
registration.addMappingForServletNames(dispatcherTypes, this.matchAfter,
|
||||
servletNames.toArray(new String[servletNames.size()]));
|
||||
}
|
||||
if (this.urlPatterns.size() > 0) {
|
||||
registration.addMappingForUrlPatterns(dispatcherTypes, this.matchAfter,
|
||||
this.urlPatterns.toArray(new String[this.urlPatterns.size()]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.context.embedded;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.Registration;
|
||||
|
||||
import org.springframework.core.Conventions;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.ServletContextInitializer;
|
||||
|
||||
/**
|
||||
* Base class for {@link ServletRegistrationBean servlet} and
|
||||
* {@link FilterRegistrationBean filter} registration beans.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 4.0
|
||||
* @see ServletRegistrationBean
|
||||
* @see FilterRegistrationBean
|
||||
*/
|
||||
public abstract class RegistrationBean implements ServletContextInitializer {
|
||||
|
||||
private String name;
|
||||
|
||||
private boolean asyncSupported = true;
|
||||
|
||||
private Map<String, String> initParameters = new LinkedHashMap<String, String>();
|
||||
|
||||
/**
|
||||
* Set the name of this registration. If not specified the bean name will be used.
|
||||
*/
|
||||
public void setName(String name) {
|
||||
Assert.hasLength(name, "Name must not be empty");
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if asynchronous operations are support for this registration. If not specified
|
||||
* defaults to {@code true}.
|
||||
*/
|
||||
public void setAsyncSupported(boolean asyncSupported) {
|
||||
this.asyncSupported = asyncSupported;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if asynchronous operations are support for this registration.
|
||||
*/
|
||||
public boolean isAsyncSupported() {
|
||||
return asyncSupported;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set init-parameters for this registration. Calling this method will replace any
|
||||
* existing init-parameters.
|
||||
* @see #getInitParameters
|
||||
* @see #addInitParameter
|
||||
*/
|
||||
public void setInitParameters(Map<String, String> initParameters) {
|
||||
Assert.notNull(initParameters, "InitParameters must not be null");
|
||||
this.initParameters = new LinkedHashMap<String, String>(initParameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a mutable Map of the registration init-parameters.
|
||||
*/
|
||||
public Map<String, String> getInitParameters() {
|
||||
return this.initParameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a single init-parameter, replacing any existing parameter with the same name.
|
||||
* @param name the init-parameter name
|
||||
* @param value the init-parameter value
|
||||
*/
|
||||
public void addInitParameter(String name, String value) {
|
||||
Assert.notNull(name, "Name must not be null");
|
||||
this.initParameters.put(name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deduces the name for this registration. Will return user specified name or fallback
|
||||
* to convention based naming.
|
||||
* @param value the object used for convention based names
|
||||
*/
|
||||
protected final String getOrDeduceName(Object value) {
|
||||
return (this.name != null ? this.name : Conventions.getVariableName(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure registration base settings.
|
||||
*/
|
||||
protected void configure(Registration.Dynamic registration) {
|
||||
registration.setAsyncSupported(this.asyncSupported);
|
||||
if (this.initParameters.size() > 0) {
|
||||
registration.setInitParameters(this.initParameters);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.context.embedded;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.Servlet;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRegistration;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.ServletContextInitializer;
|
||||
|
||||
/**
|
||||
* A {@link ServletContextInitializer} to register {@link Servlet}s in a Servlet 3.0+
|
||||
* container. Similar to the {@link ServletContext#addServlet(String, Servlet)
|
||||
* registration} features provided by {@link ServletContext} but with a Spring Bean
|
||||
* friendly design.
|
||||
*
|
||||
* <p>
|
||||
* The {@link #setServlet(Servlet) servlet} must be specified before calling
|
||||
* {@link #onStartup}. URL mapping can be configured used {@link #setUrlMappings} or
|
||||
* omitted when mapping to '/*'. The servlet name will be deduced if not specified.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 4.0
|
||||
* @see ServletContextInitializer
|
||||
* @see ServletContext#addServlet(String, Servlet)
|
||||
*/
|
||||
public class ServletRegistrationBean extends RegistrationBean {
|
||||
|
||||
private static final String[] DEFAULT_MAPPINGS = { "/*" };
|
||||
|
||||
private Servlet servlet;
|
||||
|
||||
private Set<String> urlMappings = new LinkedHashSet<String>();
|
||||
|
||||
private int loadOnStartup = 1;
|
||||
|
||||
private Set<Filter> filters = new LinkedHashSet<Filter>();
|
||||
|
||||
/**
|
||||
* Create a new {@link ServletRegistrationBean} instance.
|
||||
*/
|
||||
public ServletRegistrationBean() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link ServletRegistrationBean} instance with the specified
|
||||
* {@link Servlet} and URL mapping.
|
||||
* @param servlet the servlet being mapped
|
||||
* @param urlMappings the URLs being mapped
|
||||
*/
|
||||
public ServletRegistrationBean(Servlet servlet, String... urlMappings) {
|
||||
setServlet(servlet);
|
||||
addUrlMappings(urlMappings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the servlet to be registered.
|
||||
*/
|
||||
public void setServlet(Servlet servlet) {
|
||||
Assert.notNull(servlet, "Servlet must not be null");
|
||||
this.servlet = servlet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the URL mappings for the servlet. If not specified the mapping will default to
|
||||
* '/'. This will replace any previously specified mappings.
|
||||
* @param urlMappings the mappings to set
|
||||
* @see #addUrlMappings(String...)
|
||||
*/
|
||||
public void setUrlMappings(Collection<String> urlMappings) {
|
||||
Assert.notNull(urlMappings, "UrlMappings must not be null");
|
||||
this.urlMappings = new LinkedHashSet<String>(urlMappings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a mutable collection of the URL mappings for the servlet.
|
||||
* @return the urlMappings
|
||||
*/
|
||||
public Collection<String> getUrlMappings() {
|
||||
return this.urlMappings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add URL mappings for the servlet.
|
||||
* @param urlMappings the mappings to add
|
||||
* @see #setUrlMappings(Collection)
|
||||
*/
|
||||
public void addUrlMappings(String... urlMappings) {
|
||||
Assert.notNull(urlMappings, "UrlMappings must not be null");
|
||||
this.urlMappings.addAll(Arrays.asList(urlMappings));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the <code>loadOnStartup</code> priority. See
|
||||
* {@link ServletRegistration.Dynamic#setLoadOnStartup} for details.
|
||||
*/
|
||||
public void setLoadOnStartup(int loadOnStartup) {
|
||||
this.loadOnStartup = loadOnStartup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets any Filters that should be registered to this servlet. Any previously
|
||||
* specified Filters will be replaced.
|
||||
* @param filters the Filters to set
|
||||
*/
|
||||
public void setFilters(Collection<? extends Filter> filters) {
|
||||
Assert.notNull(filters, "Filters must not be null");
|
||||
this.filters = new LinkedHashSet<Filter>(filters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a mutable collection of the Filters being registered with this servlet.
|
||||
*/
|
||||
public Collection<Filter> getFilters() {
|
||||
return this.filters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Filters that will be registered with this servlet.
|
||||
* @param filters the Filters to add
|
||||
*/
|
||||
public void addFilters(Filter... filters) {
|
||||
Assert.notNull(filters, "Filters must not be null");
|
||||
this.filters.addAll(Arrays.asList(filters));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the servlet name that will be registered.
|
||||
*/
|
||||
public String getServletName() {
|
||||
return getOrDeduceName(this.servlet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartup(ServletContext servletContext) throws ServletException {
|
||||
Assert.notNull(this.servlet, "Servlet must not be null");
|
||||
configure(servletContext.addServlet(getServletName(), this.servlet));
|
||||
for (Filter filter : this.filters) {
|
||||
FilterRegistrationBean filterRegistration = new FilterRegistrationBean(
|
||||
filter, this);
|
||||
filterRegistration.setAsyncSupported(isAsyncSupported());
|
||||
filterRegistration.onStartup(servletContext);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure registration settings. Subclasses can override this method to perform
|
||||
* additional configuration if required.
|
||||
*/
|
||||
protected void configure(ServletRegistration.Dynamic registration) {
|
||||
super.configure(registration);
|
||||
String[] urlMapping = this.urlMappings
|
||||
.toArray(new String[this.urlMappings.size()]);
|
||||
if (urlMapping.length == 0) {
|
||||
urlMapping = DEFAULT_MAPPINGS;
|
||||
}
|
||||
registration.addMapping(urlMapping);
|
||||
registration.setLoadOnStartup(this.loadOnStartup);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.context.embedded;
|
||||
|
||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.web.context.support.XmlWebApplicationContext;
|
||||
|
||||
/**
|
||||
* {@link EmbeddedWebApplicationContext} which takes its configuration from XML documents,
|
||||
* understood by an {@link org.springframework.beans.factory.xml.XmlBeanDefinitionReader}.
|
||||
*
|
||||
* <p>
|
||||
* Note: In case of multiple config locations, later bean definitions will override ones
|
||||
* defined in earlier loaded files. This can be leveraged to deliberately override certain
|
||||
* bean definitions via an extra XML file.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @see #setNamespace
|
||||
* @see #setConfigLocations
|
||||
* @see EmbeddedWebApplicationContext
|
||||
* @see XmlWebApplicationContext
|
||||
*/
|
||||
public class XmlEmbeddedWebApplicationContext extends EmbeddedWebApplicationContext {
|
||||
|
||||
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
|
||||
|
||||
/**
|
||||
* Create a new {@link XmlEmbeddedWebApplicationContext} that needs to be
|
||||
* {@linkplain #load loaded} and then manually {@link #refresh refreshed}.
|
||||
*/
|
||||
public XmlEmbeddedWebApplicationContext() {
|
||||
reader.setEnvironment(this.getEnvironment());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link XmlEmbeddedWebApplicationContext}, loading bean definitions
|
||||
* from the given resources and automatically refreshing the context.
|
||||
* @param resources the resources to load from
|
||||
*/
|
||||
public XmlEmbeddedWebApplicationContext(Resource... resources) {
|
||||
load(resources);
|
||||
refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link XmlEmbeddedWebApplicationContext}, loading bean definitions
|
||||
* from the given resource locations and automatically refreshing the context.
|
||||
* @param resourceLocations the resources to load from
|
||||
*/
|
||||
public XmlEmbeddedWebApplicationContext(String... resourceLocations) {
|
||||
load(resourceLocations);
|
||||
refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link XmlEmbeddedWebApplicationContext}, loading bean definitions
|
||||
* from the given resource locations and automatically refreshing the context.
|
||||
* @param relativeClass class whose package will be used as a prefix when loading each
|
||||
* specified resource name
|
||||
* @param resourceNames relatively-qualified names of resources to load
|
||||
*/
|
||||
public XmlEmbeddedWebApplicationContext(Class<?> relativeClass,
|
||||
String... resourceNames) {
|
||||
load(relativeClass, resourceNames);
|
||||
refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to use XML validation. Default is {@code true}.
|
||||
*/
|
||||
public void setValidating(boolean validating) {
|
||||
this.reader.setValidating(validating);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>
|
||||
* Delegates the given environment to underlying {@link XmlBeanDefinitionReader}.
|
||||
* Should be called before any call to {@link #load}.
|
||||
*/
|
||||
@Override
|
||||
public void setEnvironment(ConfigurableEnvironment environment) {
|
||||
super.setEnvironment(environment);
|
||||
this.reader.setEnvironment(this.getEnvironment());
|
||||
}
|
||||
|
||||
/**
|
||||
* Load bean definitions from the given XML resources.
|
||||
* @param resources one or more resources to load from
|
||||
*/
|
||||
public void load(Resource... resources) {
|
||||
this.reader.loadBeanDefinitions(resources);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load bean definitions from the given XML resources.
|
||||
* @param resourceLocations one or more resource locations to load from
|
||||
*/
|
||||
public void load(String... resourceLocations) {
|
||||
this.reader.loadBeanDefinitions(resourceLocations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load bean definitions from the given XML resources.
|
||||
* @param relativeClass class whose package will be used as a prefix when loading each
|
||||
* specified resource name
|
||||
* @param resourceNames relatively-qualified names of resources to load
|
||||
*/
|
||||
public void load(Class<?> relativeClass, String... resourceNames) {
|
||||
Resource[] resources = new Resource[resourceNames.length];
|
||||
for (int i = 0; i < resourceNames.length; i++) {
|
||||
resources[i] = new ClassPathResource(resourceNames[i], relativeClass);
|
||||
}
|
||||
this.load(resources);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.context.embedded.jetty;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.springframework.bootstrap.context.embedded.EmbeddedServletContainer;
|
||||
import org.springframework.bootstrap.context.embedded.EmbeddedServletContainerException;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link EmbeddedServletContainer} that can be used to control an embedded Jetty server.
|
||||
* Usually this class should be created using the
|
||||
* {@link JettyEmbeddedServletContainerFactory} and not directly.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 4.0
|
||||
* @see JettyEmbeddedServletContainerFactory
|
||||
*/
|
||||
public class JettyEmbeddedServletContainer implements EmbeddedServletContainer {
|
||||
|
||||
private final Server server;
|
||||
|
||||
/**
|
||||
* Create a new {@link JettyEmbeddedServletContainer} instance.
|
||||
* @param server the underlying Jetty server
|
||||
*/
|
||||
public JettyEmbeddedServletContainer(Server server) {
|
||||
Assert.notNull(server, "Jetty Server must not be null");
|
||||
this.server = server;
|
||||
start();
|
||||
}
|
||||
|
||||
private synchronized void start() {
|
||||
try {
|
||||
this.server.start();
|
||||
} catch (Exception ex) {
|
||||
throw new EmbeddedServletContainerException(
|
||||
"Unable to start embedded Jetty servlet container", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void stop() {
|
||||
try {
|
||||
this.server.stop();
|
||||
} catch (Exception ex) {
|
||||
throw new EmbeddedServletContainerException(
|
||||
"Unable to stop embedded Jetty servlet container", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns access to the underlying Jetty Server.
|
||||
*/
|
||||
public Server getServer() {
|
||||
return this.server;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.context.embedded.jetty;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.ErrorHandler;
|
||||
import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.servlet.ServletMapping;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.webapp.AbstractConfiguration;
|
||||
import org.eclipse.jetty.webapp.Configuration;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.springframework.bootstrap.context.embedded.AbstractEmbeddedServletContainerFactory;
|
||||
import org.springframework.bootstrap.context.embedded.EmbeddedServletContainerFactory;
|
||||
import org.springframework.bootstrap.context.embedded.ErrorPage;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.ServletContextInitializer;
|
||||
|
||||
/**
|
||||
* {@link EmbeddedServletContainerFactory} that can be used to create
|
||||
* {@link JettyEmbeddedServletContainer}s. Can be initialized using Spring's
|
||||
* {@link ServletContextInitializer}s or Jetty {@link Configuration}s.
|
||||
*
|
||||
* <p>
|
||||
* Unless explicitly configured otherwise this factory will created containers that listen
|
||||
* for HTTP requests on port 8080.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Dave Syer
|
||||
* @since 4.0
|
||||
* @see #setPort(int)
|
||||
* @see #setConfigurations(Collection)
|
||||
* @see JettyEmbeddedServletContainer
|
||||
*/
|
||||
public class JettyEmbeddedServletContainerFactory extends
|
||||
AbstractEmbeddedServletContainerFactory implements ResourceLoaderAware {
|
||||
|
||||
private List<Configuration> configurations = new ArrayList<Configuration>();
|
||||
|
||||
private ResourceLoader resourceLoader;
|
||||
|
||||
/**
|
||||
* Create a new {@link JettyEmbeddedServletContainerFactory} instance.
|
||||
*/
|
||||
public JettyEmbeddedServletContainerFactory() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link JettyEmbeddedServletContainerFactory} that listens for requests
|
||||
* using the specified port.
|
||||
* @param port the port to listen on
|
||||
*/
|
||||
public JettyEmbeddedServletContainerFactory(int port) {
|
||||
super(port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link JettyEmbeddedServletContainerFactory} with the specified
|
||||
* context path and port.
|
||||
* @param contextPath root the context path
|
||||
* @param port the port to listen on
|
||||
*/
|
||||
public JettyEmbeddedServletContainerFactory(String contextPath, int port) {
|
||||
super(contextPath, port);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JettyEmbeddedServletContainer getEmbdeddedServletContainer(
|
||||
ServletContextInitializer... initializers) {
|
||||
Server server = new Server(getPort());
|
||||
|
||||
WebAppContext context = new WebAppContext();
|
||||
if (this.resourceLoader != null) {
|
||||
context.setClassLoader(this.resourceLoader.getClassLoader());
|
||||
}
|
||||
String contextPath = getContextPath();
|
||||
context.setContextPath(StringUtils.hasLength(contextPath) ? contextPath : "/");
|
||||
configureDocumentRoot(context);
|
||||
if (getRegisterDefaultServlet()) {
|
||||
addDefaultServlet(context);
|
||||
}
|
||||
if (getRegisterJspServlet()
|
||||
&& ClassUtils.isPresent(getJspServletClassName(), getClass()
|
||||
.getClassLoader())) {
|
||||
addJspServlet(context);
|
||||
}
|
||||
|
||||
ServletContextInitializer[] initializersToUse = mergeInitializers(initializers);
|
||||
Configuration[] configurations = getWebAppContextConfigurations(context,
|
||||
initializersToUse);
|
||||
context.setConfigurations(configurations);
|
||||
postProcessWebAppContext(context);
|
||||
|
||||
server.setHandler(context);
|
||||
return getJettyEmbeddedServletContainer(server);
|
||||
}
|
||||
|
||||
private void configureDocumentRoot(WebAppContext handler) {
|
||||
File root = getValidDocumentRoot();
|
||||
if (root != null) {
|
||||
try {
|
||||
handler.setBaseResource(Resource.newResource(root));
|
||||
} catch (Exception ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addDefaultServlet(WebAppContext context) {
|
||||
ServletHolder holder = new ServletHolder();
|
||||
holder.setName("default");
|
||||
holder.setClassName("org.eclipse.jetty.servlet.DefaultServlet");
|
||||
holder.setInitParameter("dirAllowed", "false");
|
||||
holder.setInitOrder(1);
|
||||
context.getServletHandler().addServletWithMapping(holder, "/");
|
||||
context.getServletHandler().getServletMapping("/").setDefault(true);
|
||||
}
|
||||
|
||||
private void addJspServlet(WebAppContext context) {
|
||||
ServletHolder holder = new ServletHolder();
|
||||
holder.setName("jsp");
|
||||
holder.setClassName(getJspServletClassName());
|
||||
holder.setInitParameter("fork", "false");
|
||||
holder.setInitOrder(3);
|
||||
context.getServletHandler().addServlet(holder);
|
||||
ServletMapping mapping = new ServletMapping();
|
||||
mapping.setServletName("jsp");
|
||||
mapping.setPathSpecs(new String[] { "*.jsp", "*.jspx" });
|
||||
context.getServletHandler().addServletMapping(mapping);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Jetty {@link Configuration}s that should be applied to the server.
|
||||
* @param webAppContext the Jetty {@link WebAppContext}
|
||||
* @param initializers the {@link ServletContextInitializer}s to apply
|
||||
* @return configurations to apply
|
||||
*/
|
||||
protected Configuration[] getWebAppContextConfigurations(WebAppContext webAppContext,
|
||||
ServletContextInitializer... initializers) {
|
||||
List<Configuration> configurations = new ArrayList<Configuration>();
|
||||
configurations.add(getServletContextInitializerConfiguration(webAppContext,
|
||||
initializers));
|
||||
configurations.addAll(getConfigurations());
|
||||
configurations.add(getErrorPageConfiguration());
|
||||
return configurations.toArray(new Configuration[configurations.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a configuration object that adds error handlers
|
||||
*
|
||||
* @return a configuration object for adding error pages
|
||||
*/
|
||||
private Configuration getErrorPageConfiguration() {
|
||||
return new AbstractConfiguration() {
|
||||
@Override
|
||||
public void configure(WebAppContext context) throws Exception {
|
||||
ErrorHandler errorHandler = context.getErrorHandler();
|
||||
if (errorHandler instanceof ErrorPageErrorHandler) {
|
||||
ErrorPageErrorHandler handler = (ErrorPageErrorHandler) errorHandler;
|
||||
for (ErrorPage errorPage : getErrorPages()) {
|
||||
if (errorPage.isGlobal()) {
|
||||
handler.addErrorPage(ErrorPageErrorHandler.GLOBAL_ERROR_PAGE,
|
||||
errorPage.getPath());
|
||||
} else {
|
||||
if (errorPage.getExceptionName() != null) {
|
||||
handler.addErrorPage(errorPage.getExceptionName(),
|
||||
errorPage.getPath());
|
||||
} else {
|
||||
handler.addErrorPage(errorPage.getStatus(),
|
||||
errorPage.getPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a Jetty {@link Configuration} that will invoke the specified
|
||||
* {@link ServletContextInitializer}s. By default this method will return a
|
||||
* {@link ServletContextInitializerConfiguration}.
|
||||
* @param webAppContext the Jetty {@link WebAppContext}
|
||||
* @param initializers the {@link ServletContextInitializer}s to apply
|
||||
* @return the {@link Configuration} instance
|
||||
*/
|
||||
protected Configuration getServletContextInitializerConfiguration(
|
||||
WebAppContext webAppContext, ServletContextInitializer... initializers) {
|
||||
return new ServletContextInitializerConfiguration(webAppContext, initializers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Post process the Jetty {@link WebAppContext} before it used with the Jetty Server.
|
||||
* Subclasses can override this method to apply additional processing to the
|
||||
* {@link WebAppContext}.
|
||||
* @param webAppContext the Jetty {@link WebAppContext}
|
||||
*/
|
||||
protected void postProcessWebAppContext(WebAppContext webAppContext) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method called to create the {@link JettyEmbeddedServletContainer}.
|
||||
* Subclasses can override this method to return a different
|
||||
* {@link JettyEmbeddedServletContainer} or apply additional processing to the Jetty
|
||||
* server.
|
||||
* @param server the Jetty server.
|
||||
* @return a new {@link JettyEmbeddedServletContainer} instance
|
||||
*/
|
||||
protected JettyEmbeddedServletContainer getJettyEmbeddedServletContainer(Server server) {
|
||||
return new JettyEmbeddedServletContainer(server);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResourceLoader(ResourceLoader resourceLoader) {
|
||||
this.resourceLoader = resourceLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets Jetty {@link Configuration}s that will be applied to the {@link WebAppContext}
|
||||
* before the server is created. Calling this method will replace any existing
|
||||
* configurations.
|
||||
* @param configurations the Jetty configurations to apply
|
||||
*/
|
||||
public void setConfigurations(Collection<? extends Configuration> configurations) {
|
||||
Assert.notNull(configurations, "Configurations must not be null");
|
||||
this.configurations = new ArrayList<Configuration>(configurations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a mutable collection of Jetty {@link Configuration}s that will be applied
|
||||
* to the {@link WebAppContext} before the server is created.
|
||||
* @return the Jetty {@link Configuration}s
|
||||
*/
|
||||
public Collection<Configuration> getConfigurations() {
|
||||
return this.configurations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add {@link Configuration}s that will be applied to the {@link WebAppContext} before
|
||||
* the server is create.
|
||||
* @param configurations the configurations to add
|
||||
*/
|
||||
public void addConfigurations(Configuration... configurations) {
|
||||
Assert.notNull(configurations, "Configurations must not be null");
|
||||
this.configurations.addAll(Arrays.asList(configurations));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.context.embedded.jetty;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||
import org.eclipse.jetty.webapp.AbstractConfiguration;
|
||||
import org.eclipse.jetty.webapp.Configuration;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.ServletContextInitializer;
|
||||
|
||||
/**
|
||||
* Jetty {@link Configuration} that calls {@link ServletContextInitializer}s.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 4.0
|
||||
*/
|
||||
public class ServletContextInitializerConfiguration extends AbstractConfiguration {
|
||||
|
||||
private ContextHandler contextHandler;
|
||||
|
||||
private ServletContextInitializer[] initializers;
|
||||
|
||||
/**
|
||||
* Create a new {@link ServletContextInitializerConfiguration}.
|
||||
* @param contextHandler the Jetty ContextHandler
|
||||
* @param initializers the initializers that should be invoked
|
||||
*/
|
||||
public ServletContextInitializerConfiguration(ContextHandler contextHandler,
|
||||
ServletContextInitializer... initializers) {
|
||||
Assert.notNull(contextHandler, "Jetty ContextHandler must not be null");
|
||||
Assert.notNull(initializers, "Initializers must not be null");
|
||||
this.contextHandler = contextHandler;
|
||||
this.initializers = initializers;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(WebAppContext context) throws Exception {
|
||||
context.addBean(new InitializerListener(), true);
|
||||
}
|
||||
|
||||
private class InitializerListener extends AbstractLifeCycle {
|
||||
|
||||
@Override
|
||||
protected void doStart() throws Exception {
|
||||
ServletContext servletContext = contextHandler.getServletContext();
|
||||
for (ServletContextInitializer initializer : initializers) {
|
||||
initializer.onStartup(servletContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Support for Jetty {@link org.springframework.bootstrap.context.embedded.EmbeddedServletContainer EmbeddedServletContainers}.
|
||||
*/
|
||||
package org.springframework.bootstrap.context.embedded.jetty;
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Support for embedded servlet containers.
|
||||
* @see org.springframework.bootstrap.context.embedded.EmbeddedServletContainerFactory
|
||||
* @see org.springframework.bootstrap.context.embedded.EmbeddedWebApplicationContext
|
||||
*/
|
||||
package org.springframework.bootstrap.context.embedded;
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.context.embedded.tomcat;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import org.apache.catalina.Lifecycle;
|
||||
import org.apache.catalina.LifecycleEvent;
|
||||
import org.apache.catalina.LifecycleListener;
|
||||
import org.apache.catalina.core.StandardContext;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.ServletContextInitializer;
|
||||
|
||||
/**
|
||||
* Tomcat {@link LifecycleListener} that calls {@link ServletContextInitializer}s.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 4.0
|
||||
*/
|
||||
public class ServletContextInitializerLifecycleListener implements LifecycleListener {
|
||||
|
||||
private ServletContextInitializer[] initializers;
|
||||
|
||||
/**
|
||||
* Create a new {@link ServletContextInitializerLifecycleListener} instance with the
|
||||
* specified initializers.
|
||||
* @param initializers the initializers to call
|
||||
*/
|
||||
public ServletContextInitializerLifecycleListener(
|
||||
ServletContextInitializer... initializers) {
|
||||
this.initializers = initializers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lifecycleEvent(LifecycleEvent event) {
|
||||
if (Lifecycle.CONFIGURE_START_EVENT.equals(event.getType())) {
|
||||
Assert.isInstanceOf(StandardContext.class, event.getSource());
|
||||
StandardContext standardContext = (StandardContext) event.getSource();
|
||||
for (ServletContextInitializer initializer : this.initializers) {
|
||||
try {
|
||||
initializer.onStartup(standardContext.getServletContext());
|
||||
} catch (ServletException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.context.embedded.tomcat;
|
||||
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.apache.catalina.startup.Tomcat;
|
||||
import org.springframework.bootstrap.context.embedded.EmbeddedServletContainer;
|
||||
import org.springframework.bootstrap.context.embedded.EmbeddedServletContainerException;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link EmbeddedServletContainer} that can be used to control an embedded Tomcat server.
|
||||
* Usually this class should be created using the
|
||||
* {@link TomcatEmbeddedServletContainerFactory} and not directly.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 4.0
|
||||
* @see TomcatEmbeddedServletContainerFactory
|
||||
*/
|
||||
public class TomcatEmbeddedServletContainer implements EmbeddedServletContainer {
|
||||
|
||||
private final Tomcat tomcat;
|
||||
|
||||
/**
|
||||
* Create a new {@link TomcatEmbeddedServletContainer} instance.
|
||||
* @param tomcat the underlying Tomcat server
|
||||
*/
|
||||
public TomcatEmbeddedServletContainer(Tomcat tomcat) {
|
||||
Assert.notNull(tomcat, "Tomcat Server must not be null");
|
||||
this.tomcat = tomcat;
|
||||
start();
|
||||
}
|
||||
|
||||
private synchronized void start() throws EmbeddedServletContainerException {
|
||||
try {
|
||||
this.tomcat.start();
|
||||
// Unlike Jetty, all Tomcat threads are daemon threads. We create a
|
||||
// blocking non-daemon to stop immediate shutdown
|
||||
Thread awaitThread = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
tomcat.getServer().await();
|
||||
};
|
||||
};
|
||||
awaitThread.setDaemon(false);
|
||||
awaitThread.start();
|
||||
} catch (Exception ex) {
|
||||
throw new EmbeddedServletContainerException(
|
||||
"Unable to start embdedded Tomcat", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void stop() throws EmbeddedServletContainerException {
|
||||
try {
|
||||
try {
|
||||
this.tomcat.stop();
|
||||
} catch (LifecycleException e) {
|
||||
}
|
||||
this.tomcat.destroy();
|
||||
} catch (Exception ex) {
|
||||
throw new EmbeddedServletContainerException(
|
||||
"Unable to stop embdedded Tomcat", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns access to the underlying Tomcat server.
|
||||
*/
|
||||
public Tomcat getTomcat() {
|
||||
return this.tomcat;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,360 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.context.embedded.tomcat;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.catalina.Context;
|
||||
import org.apache.catalina.Host;
|
||||
import org.apache.catalina.LifecycleListener;
|
||||
import org.apache.catalina.Server;
|
||||
import org.apache.catalina.Valve;
|
||||
import org.apache.catalina.Wrapper;
|
||||
import org.apache.catalina.connector.Connector;
|
||||
import org.apache.catalina.core.StandardContext;
|
||||
import org.apache.catalina.core.StandardEngine;
|
||||
import org.apache.catalina.core.StandardHost;
|
||||
import org.apache.catalina.core.StandardService;
|
||||
import org.apache.catalina.startup.Tomcat;
|
||||
import org.apache.catalina.startup.Tomcat.FixContextListener;
|
||||
import org.springframework.bootstrap.context.embedded.AbstractEmbeddedServletContainerFactory;
|
||||
import org.springframework.bootstrap.context.embedded.EmbeddedServletContainer;
|
||||
import org.springframework.bootstrap.context.embedded.EmbeddedServletContainerException;
|
||||
import org.springframework.bootstrap.context.embedded.EmbeddedServletContainerFactory;
|
||||
import org.springframework.bootstrap.context.embedded.ErrorPage;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.web.ServletContextInitializer;
|
||||
|
||||
/**
|
||||
* {@link EmbeddedServletContainerFactory} that can be used to create
|
||||
* {@link TomcatEmbeddedServletContainer}s. Can be initialized using Spring's
|
||||
* {@link ServletContextInitializer}s or Tomcat {@link LifecycleListener}s.
|
||||
*
|
||||
* <p>
|
||||
* Unless explicitly configured otherwise this factory will created containers that listen
|
||||
* for HTTP requests on port 8080.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Dave Syer
|
||||
* @since 4.0
|
||||
* @see #setPort(int)
|
||||
* @see #setContextLifecycleListeners(Collection)
|
||||
* @see TomcatEmbeddedServletContainer
|
||||
*/
|
||||
public class TomcatEmbeddedServletContainerFactory extends
|
||||
AbstractEmbeddedServletContainerFactory implements ResourceLoaderAware {
|
||||
|
||||
private File baseDirectory;
|
||||
|
||||
private List<Valve> contextValves = new ArrayList<Valve>();
|
||||
|
||||
private List<LifecycleListener> contextLifecycleListeners = new ArrayList<LifecycleListener>();
|
||||
|
||||
private ResourceLoader resourceLoader;
|
||||
|
||||
private Connector connector;
|
||||
|
||||
private Tomcat tomcat = new Tomcat();
|
||||
|
||||
/**
|
||||
* Create a new {@link TomcatEmbeddedServletContainerFactory} instance.
|
||||
*/
|
||||
public TomcatEmbeddedServletContainerFactory() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link TomcatEmbeddedServletContainerFactory} that listens for
|
||||
* requests using the specified port.
|
||||
* @param port the port to listen on
|
||||
*/
|
||||
public TomcatEmbeddedServletContainerFactory(int port) {
|
||||
super(port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link TomcatEmbeddedServletContainerFactory} with the specified
|
||||
* context path and port.
|
||||
* @param contextPath root the context path
|
||||
* @param port the port to listen on
|
||||
*/
|
||||
public TomcatEmbeddedServletContainerFactory(String contextPath, int port) {
|
||||
super(contextPath, port);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EmbeddedServletContainer getEmbdeddedServletContainer(
|
||||
ServletContextInitializer... initializers) {
|
||||
File baseDir = (this.baseDirectory != null ? this.baseDirectory
|
||||
: createTempDir("tomcat"));
|
||||
this.tomcat.setBaseDir(baseDir.getAbsolutePath());
|
||||
if (this.connector != null) {
|
||||
this.connector.setPort(getPort());
|
||||
this.tomcat.getService().addConnector(this.connector);
|
||||
this.tomcat.setConnector(this.connector);
|
||||
} else {
|
||||
Connector connector = new Connector(
|
||||
"org.apache.coyote.http11.Http11NioProtocol");
|
||||
connector.setPort(getPort());
|
||||
this.tomcat.getService().addConnector(connector);
|
||||
this.tomcat.setConnector(connector);
|
||||
}
|
||||
this.tomcat.getHost().setAutoDeploy(false);
|
||||
this.tomcat.getEngine().setBackgroundProcessorDelay(-1);
|
||||
|
||||
prepareContext(this.tomcat.getHost(), initializers);
|
||||
return getTomcatEmbeddedServletContainer(this.tomcat);
|
||||
}
|
||||
|
||||
protected void prepareContext(Host host, ServletContextInitializer[] initializers) {
|
||||
File docBase = getValidDocumentRoot();
|
||||
docBase = (docBase != null ? docBase : createTempDir("tomcat-docbase"));
|
||||
Context context = new StandardContext();
|
||||
context.setName(getContextPath());
|
||||
context.setPath(getContextPath());
|
||||
context.setDocBase(docBase.getAbsolutePath());
|
||||
context.addLifecycleListener(new FixContextListener());
|
||||
if (this.resourceLoader != null) {
|
||||
context.setParentClassLoader(this.resourceLoader.getClassLoader());
|
||||
}
|
||||
if (getRegisterDefaultServlet()) {
|
||||
addDefaultServlet(context);
|
||||
}
|
||||
if (getRegisterJspServlet()
|
||||
&& ClassUtils.isPresent(getJspServletClassName(), getClass()
|
||||
.getClassLoader())) {
|
||||
addJspServlet(context);
|
||||
}
|
||||
ServletContextInitializer[] initializersToUse = mergeInitializers(initializers);
|
||||
configureContext(context, initializersToUse);
|
||||
host.addChild(context);
|
||||
postProcessContext(context);
|
||||
}
|
||||
|
||||
private void addDefaultServlet(Context context) {
|
||||
Wrapper defaultServlet = context.createWrapper();
|
||||
defaultServlet.setName("default");
|
||||
defaultServlet.setServletClass("org.apache.catalina.servlets.DefaultServlet");
|
||||
defaultServlet.addInitParameter("debug", "0");
|
||||
defaultServlet.addInitParameter("listings", "false");
|
||||
defaultServlet.setLoadOnStartup(1);
|
||||
// Otherwise the default location of a Spring DispatcherServlet cannot be set
|
||||
defaultServlet.setOverridable(true);
|
||||
context.addChild(defaultServlet);
|
||||
context.addServletMapping("/", "default");
|
||||
}
|
||||
|
||||
private void addJspServlet(Context context) {
|
||||
Wrapper jspServlet = context.createWrapper();
|
||||
jspServlet.setName("jsp");
|
||||
jspServlet.setServletClass(getJspServletClassName());
|
||||
jspServlet.addInitParameter("fork", "false");
|
||||
jspServlet.setLoadOnStartup(3);
|
||||
context.addChild(jspServlet);
|
||||
context.addServletMapping("*.jsp", "jsp");
|
||||
context.addServletMapping("*.jspx", "jsp");
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the Tomcat {@link Context}.
|
||||
* @param context the Tomcat context
|
||||
* @param initializers initializers to apply
|
||||
*/
|
||||
protected void configureContext(Context context,
|
||||
ServletContextInitializer[] initializers) {
|
||||
context.addLifecycleListener(new ServletContextInitializerLifecycleListener(
|
||||
initializers));
|
||||
for (LifecycleListener lifecycleListener : this.contextLifecycleListeners) {
|
||||
context.addLifecycleListener(lifecycleListener);
|
||||
}
|
||||
for (Valve valve : this.contextValves) {
|
||||
context.getPipeline().addValve(valve);
|
||||
}
|
||||
for (ErrorPage errorPage : getErrorPages()) {
|
||||
org.apache.catalina.deploy.ErrorPage tomcatPage = new org.apache.catalina.deploy.ErrorPage();
|
||||
tomcatPage.setLocation(errorPage.getPath());
|
||||
tomcatPage.setExceptionType(errorPage.getExceptionName());
|
||||
tomcatPage.setErrorCode(errorPage.getStatus());
|
||||
context.addErrorPage(tomcatPage);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Post process the Tomcat {@link Context} before it used with the Tomcat Server.
|
||||
* Subclasses can override this method to apply additional processing to the
|
||||
* {@link Context}.
|
||||
* @param context the Tomcat {@link Context}
|
||||
*/
|
||||
protected void postProcessContext(Context context) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method called to create the {@link TomcatEmbeddedServletContainer}.
|
||||
* Subclasses can override this method to return a different
|
||||
* {@link TomcatEmbeddedServletContainer} or apply additional processing to the Tomcat
|
||||
* server.
|
||||
* @param tomcat the Tomcat server.
|
||||
* @return a new {@link TomcatEmbeddedServletContainer} instance
|
||||
*/
|
||||
protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(
|
||||
Tomcat tomcat) {
|
||||
return new TomcatEmbeddedServletContainer(tomcat);
|
||||
}
|
||||
|
||||
private File createTempDir(String prefix) {
|
||||
try {
|
||||
File tempFolder = File.createTempFile(prefix + ".", "." + getPort());
|
||||
tempFolder.delete();
|
||||
tempFolder.mkdir();
|
||||
tempFolder.deleteOnExit();
|
||||
return tempFolder;
|
||||
} catch (IOException ex) {
|
||||
throw new EmbeddedServletContainerException(
|
||||
"Unable to create Tomcat tempdir", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResourceLoader(ResourceLoader resourceLoader) {
|
||||
this.resourceLoader = resourceLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Tomcat base directory. If not specified a temporary directory will be used.
|
||||
* @param baseDirectory the tomcat base directory
|
||||
*/
|
||||
public void setBaseDirectory(File baseDirectory) {
|
||||
this.baseDirectory = baseDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* The tomcat connector to use (e.g. if you want to change the protocol handler).
|
||||
*
|
||||
* @param connector the connector to set
|
||||
*/
|
||||
public void setConnector(Connector connector) {
|
||||
this.connector = connector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set {@link Valve}s that should be applied to the Tomcat {@link Context}. Calling
|
||||
* this method will replace any existing listeners.
|
||||
* @param contextValves the valves to set
|
||||
*/
|
||||
public void setContextValves(Collection<? extends Valve> contextValves) {
|
||||
Assert.notNull(contextValves, "Valves must not be null");
|
||||
this.contextValves = new ArrayList<Valve>(contextValves);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a mutable collection of the {@link Valve}s that will be applied to the
|
||||
* Tomcat {@link Context}.
|
||||
* @return the contextValves the valves that will be applied
|
||||
*/
|
||||
public Collection<Valve> getValves() {
|
||||
return this.contextValves;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add {@link Valve}s that should be applied to the Tomcat {@link Context}.
|
||||
* @param contextValves the valves to add
|
||||
*/
|
||||
public void addContextValves(Valve... contextValves) {
|
||||
Assert.notNull(contextValves, "Valves must not be null");
|
||||
this.contextValves.addAll(Arrays.asList(contextValves));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set {@link LifecycleListener}s that should be applied to the Tomcat {@link Context}
|
||||
* . Calling this method will replace any existing listeners.
|
||||
* @param contextLifecycleListeners the listeners to set
|
||||
*/
|
||||
public void setContextLifecycleListeners(
|
||||
Collection<? extends LifecycleListener> contextLifecycleListeners) {
|
||||
Assert.notNull(contextLifecycleListeners,
|
||||
"ContextLifecycleListeners must not be null");
|
||||
this.contextLifecycleListeners = new ArrayList<LifecycleListener>(
|
||||
contextLifecycleListeners);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a mutable collection of the {@link LifecycleListener}s that will be applied
|
||||
* to the Tomcat {@link Context} .
|
||||
* @return the contextLifecycleListeners the listeners that will be applied
|
||||
*/
|
||||
public Collection<LifecycleListener> getContextLifecycleListeners() {
|
||||
return this.contextLifecycleListeners;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add {@link LifecycleListener}s that should be applied to the Tomcat {@link Context}
|
||||
* .
|
||||
* @param contextLifecycleListeners the listeners to add
|
||||
*/
|
||||
public void addContextLifecycleListeners(
|
||||
LifecycleListener... contextLifecycleListeners) {
|
||||
Assert.notNull(contextLifecycleListeners,
|
||||
"ContextLifecycleListeners must not be null");
|
||||
this.contextLifecycleListeners.addAll(Arrays.asList(contextLifecycleListeners));
|
||||
}
|
||||
|
||||
public TomcatEmbeddedServletContainerFactory getChildContextFactory(final String name) {
|
||||
|
||||
final Server server = this.tomcat.getServer();
|
||||
|
||||
return new TomcatEmbeddedServletContainerFactory() {
|
||||
|
||||
@Override
|
||||
public EmbeddedServletContainer getEmbdeddedServletContainer(
|
||||
ServletContextInitializer... initializers) {
|
||||
|
||||
StandardService service = new StandardService();
|
||||
service.setName(name);
|
||||
Connector connector = new Connector("HTTP/1.1");
|
||||
connector.setPort(getPort());
|
||||
service.addConnector(connector);
|
||||
StandardEngine engine = new StandardEngine();
|
||||
engine.setName(name);
|
||||
engine.setDefaultHost("localhost");
|
||||
service.setContainer(engine);
|
||||
server.addService(service);
|
||||
StandardHost host = new StandardHost();
|
||||
host.setName("localhost");
|
||||
engine.addChild(host);
|
||||
prepareContext(host, initializers);
|
||||
|
||||
return new EmbeddedServletContainer() {
|
||||
@Override
|
||||
public void stop() throws EmbeddedServletContainerException {
|
||||
// noop
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Support for Tomcat {@link org.springframework.bootstrap.context.embedded.EmbeddedServletContainer EmbeddedServletContainers}.
|
||||
*/
|
||||
package org.springframework.bootstrap.context.embedded.tomcat;
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.logging;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.logging.LogManager;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.springframework.util.ResourceUtils;
|
||||
import org.springframework.util.SystemPropertyUtils;
|
||||
|
||||
/**
|
||||
* Logging initializer for {@link Logger java.util.logging}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public abstract class JavaLoggerConfigurer {
|
||||
|
||||
/**
|
||||
* Configure the logging system from the specified location (a properties file).
|
||||
*
|
||||
* @param location the location to use to configure logging
|
||||
*/
|
||||
public static void initLogging(String location) throws FileNotFoundException {
|
||||
String resolvedLocation = SystemPropertyUtils.resolvePlaceholders(location);
|
||||
try {
|
||||
LogManager.getLogManager().readConfiguration(
|
||||
ResourceUtils.getURL(resolvedLocation).openStream());
|
||||
} catch (FileNotFoundException e) {
|
||||
throw e;
|
||||
} catch (RuntimeException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException("Could not initialize logging from "
|
||||
+ location, e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.logging;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.net.URL;
|
||||
|
||||
import org.slf4j.impl.StaticLoggerBinder;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
import org.springframework.util.SystemPropertyUtils;
|
||||
|
||||
import ch.qos.logback.classic.LoggerContext;
|
||||
import ch.qos.logback.classic.util.ContextInitializer;
|
||||
import ch.qos.logback.core.joran.spi.JoranException;
|
||||
|
||||
/**
|
||||
* Logging initializer for <a href="http://logback.qos.ch">logback</a>.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public abstract class LogbackConfigurer {
|
||||
|
||||
/**
|
||||
* Configure the logback system from the specified location.
|
||||
*
|
||||
* @param location the location to use to configure logback
|
||||
*/
|
||||
public static void initLogging(String location) throws FileNotFoundException {
|
||||
String resolvedLocation = SystemPropertyUtils.resolvePlaceholders(location);
|
||||
URL url = ResourceUtils.getURL(resolvedLocation);
|
||||
LoggerContext context = (LoggerContext) StaticLoggerBinder.getSingleton()
|
||||
.getLoggerFactory();
|
||||
context.stop();
|
||||
try {
|
||||
new ContextInitializer(context).configureByResource(url);
|
||||
} catch (JoranException e) {
|
||||
throw new IllegalArgumentException("Could not initialize logging from "
|
||||
+ location, e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.logging;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.Log4jConfigurer;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* An {@link ApplicationContextInitializer} that configures a logging framework depending
|
||||
* on what it finds on the classpath and in the {@link Environment}. If the environment
|
||||
* contains a property <code>logging.config</code> then that will be used to initialize
|
||||
* the logging system, otherwise a default location is used. The classpath is probed for
|
||||
* log4j and logback and if those are present they will be reconfigured, otherwise vanilla
|
||||
* <code>java.util.logging</code> will be used.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The default config locations are <code>classpath:log4j.properties</code> or
|
||||
* <code>classpath:log4j.xml</code> for log4j; <code>classpath:logback.xml</code> for
|
||||
* logback; and <code>classpath:logging.properties</code> for
|
||||
* <code>java.util.logging</code>. If the correct one of those files is not found then
|
||||
* some sensible defaults are adopted from files of the same name but in the package
|
||||
* containing {@link LoggingInitializer}.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Some system properties may be set as side effects, and these can be useful if the
|
||||
* logging configuration supports placeholders (i.e. log4j or logback):
|
||||
* <ul>
|
||||
* <li><code>LOG_FILE</code> is set to the value of <code>logging.file</code> if found in
|
||||
* the environment</li>
|
||||
* <li><code>LOG_PATH</code> is set to the value of <code>logging.path</code> if found in
|
||||
* the environment</li>
|
||||
* <li><code>PID</code> is set to the value of the current process ID if it can be
|
||||
* determined</li>
|
||||
* </ul>
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class LoggingInitializer implements
|
||||
ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
|
||||
|
||||
private int order = Integer.MIN_VALUE + 1;
|
||||
|
||||
/**
|
||||
* Initialize the logging system according to preferences expressed through the
|
||||
* {@link Environment} and the classpath.
|
||||
*/
|
||||
@Override
|
||||
public void initialize(ConfigurableApplicationContext applicationContext) {
|
||||
|
||||
String configLocation = getDefaultConfigLocation();
|
||||
|
||||
ConfigurableEnvironment environment = applicationContext.getEnvironment();
|
||||
|
||||
if (environment.containsProperty("logging.config")) {
|
||||
configLocation = environment.getProperty("logging.config");
|
||||
}
|
||||
|
||||
if (environment.containsProperty("logging.file")) {
|
||||
String location = environment.getProperty("logging.file");
|
||||
System.setProperty("LOG_FILE", location);
|
||||
}
|
||||
|
||||
if (environment.containsProperty("logging.path")) {
|
||||
String location = environment.getProperty("logging.path");
|
||||
System.setProperty("LOG_PATH", location);
|
||||
}
|
||||
|
||||
if (!environment.containsProperty("PID")) {
|
||||
System.setProperty("PID", getPid());
|
||||
}
|
||||
|
||||
initLogging(applicationContext, configLocation);
|
||||
|
||||
}
|
||||
|
||||
private void initLogging(ResourceLoader resourceLoader, String configLocation) {
|
||||
try {
|
||||
if (isLog4jPresent()) {
|
||||
Log4jConfigurer.initLogging(configLocation);
|
||||
} else {
|
||||
if (isLogbackPresent()) {
|
||||
LogbackConfigurer.initLogging(configLocation);
|
||||
} else {
|
||||
JavaLoggerConfigurer.initLogging(configLocation);
|
||||
}
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
throw e;
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("Cannot initialize logging from "
|
||||
+ configLocation, e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isLogbackPresent() {
|
||||
return ClassUtils.isPresent("ch.qos.logback.core.Appender",
|
||||
ClassUtils.getDefaultClassLoader());
|
||||
}
|
||||
|
||||
private boolean isLog4jPresent() {
|
||||
return ClassUtils.isPresent("org.apache.log4j.PropertyConfigurator",
|
||||
ClassUtils.getDefaultClassLoader());
|
||||
}
|
||||
|
||||
private String getDefaultConfigLocation() {
|
||||
|
||||
String defaultPath = ClassUtils.getPackageName(LoggingInitializer.class).replace(
|
||||
".", "/")
|
||||
+ "/";
|
||||
|
||||
if (isLog4jPresent()) {
|
||||
String path = "log4j.xml";
|
||||
if (!new ClassPathResource(path).exists()) {
|
||||
path = "log4j.properties";
|
||||
if (!new ClassPathResource(path).exists()) {
|
||||
path = defaultPath + path;
|
||||
}
|
||||
}
|
||||
return "classpath:" + path;
|
||||
}
|
||||
|
||||
if (isLogbackPresent()) {
|
||||
String path = "logback.xml";
|
||||
if (!new ClassPathResource(path).exists()) {
|
||||
path = defaultPath + path;
|
||||
}
|
||||
return "classpath:" + path;
|
||||
}
|
||||
|
||||
String path = "logging.properties";
|
||||
if (!new ClassPathResource(path).exists()) {
|
||||
path = defaultPath + path;
|
||||
}
|
||||
|
||||
return "classpath:" + path;
|
||||
|
||||
}
|
||||
|
||||
private String getPid() {
|
||||
String name = ManagementFactory.getRuntimeMXBean().getName();
|
||||
if (name != null) {
|
||||
return name.split("@")[0];
|
||||
}
|
||||
return "????";
|
||||
}
|
||||
|
||||
public void setOrder(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return this.order;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.bootstrap.maven;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarOutputStream;
|
||||
|
||||
import org.apache.maven.plugins.shade.relocation.Relocator;
|
||||
import org.apache.maven.plugins.shade.resource.ResourceTransformer;
|
||||
|
||||
/**
|
||||
* Extension for the <a href="http://maven.apache.org/plugins/maven-shade-plugin/">Maven
|
||||
* shade plugin</a> to allow properties files (e.g. <code>META-INF/spring.factories</code>
|
||||
* ) to be merged without losing any information.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class PropertiesMergingResourceTransformer implements ResourceTransformer {
|
||||
|
||||
String resource; // Set this in pom configuration with <resource>...</resource>
|
||||
|
||||
private Properties data = new Properties();
|
||||
|
||||
@Override
|
||||
public boolean canTransformResource(String resource) {
|
||||
if (this.resource != null && this.resource.equalsIgnoreCase(resource)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processResource(String resource, InputStream is,
|
||||
List<Relocator> relocators) throws IOException {
|
||||
Properties properties = new Properties();
|
||||
properties.load(is);
|
||||
is.close();
|
||||
for (Object key : properties.keySet()) {
|
||||
String name = (String) key;
|
||||
String value = properties.getProperty(name);
|
||||
String existing = this.data.getProperty(name);
|
||||
this.data
|
||||
.setProperty(name, existing == null ? value : existing + "," + value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasTransformedResource() {
|
||||
return this.data.size() > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void modifyOutputStream(JarOutputStream os) throws IOException {
|
||||
os.putNextEntry(new JarEntry(this.resource));
|
||||
this.data.store(os, "Merged by PropertiesMergingResourceTransformer");
|
||||
os.flush();
|
||||
this.data.clear();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user