/*
* Copyright 2014 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.xd.module.core;
import java.util.Arrays;
import java.util.Map;
import java.util.Properties;
import org.springframework.boot.context.event.ApplicationPreparedEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.xd.module.ModuleDefinition;
import org.springframework.xd.module.ModuleDeploymentProperties;
import org.springframework.xd.module.ModuleDescriptor;
import org.springframework.xd.module.SimpleModuleDefinition;
import org.springframework.xd.module.options.ModuleOptions;
import org.springframework.xd.module.options.ModuleUtils;
/**
* A {@link SimpleModule} configured by an @Configuration class.
*
* @author David Turanski
*/
public class JavaConfiguredModule extends SimpleModule {
private static final String BASE_PACKAGES = "base_packages";
public JavaConfiguredModule(ModuleDescriptor descriptor, ModuleDeploymentProperties deploymentProperties) {
super(descriptor, deploymentProperties);
}
public JavaConfiguredModule(ModuleDescriptor descriptor, ModuleDeploymentProperties deploymentProperties,
ClassLoader classLoader, ModuleOptions moduleOptions) {
super(descriptor, deploymentProperties, classLoader, moduleOptions);
}
@Override
protected void configureModuleApplicationContext(SimpleModuleDefinition moduleDefinition) {
String[] basePackages = basePackages(moduleDefinition);
Assert.notEmpty(basePackages, String.format("%s property does not exist or does not contain a value for " +
"module" +
" %s.", BASE_PACKAGES, moduleDefinition.toString()));
addListener(new JavaConfigModuleListener(basePackages));
addListener(new JavaConfigValidationListener(moduleDefinition, basePackages));
}
public static String[] basePackages(SimpleModuleDefinition moduleDefinition) {
Properties properties = ModuleUtils.loadModuleProperties(moduleDefinition);
//Assert.notNull(propertiesFile, "required module properties not found.");
if (properties == null) {
return new String[0];
}
String basePackageNames = properties.getProperty(BASE_PACKAGES);
return StringUtils.commaDelimitedListToStringArray(basePackageNames);
}
static class JavaConfigModuleListener implements ApplicationListener<ApplicationPreparedEvent> {
private final String[] basePackages;
public JavaConfigModuleListener(String... basePackages) {
this.basePackages = basePackages;
}
@Override
public void onApplicationEvent(ApplicationPreparedEvent event) {
AnnotationConfigApplicationContext context = (AnnotationConfigApplicationContext) event
.getApplicationContext();
context.scan(basePackages);
}
}
static class JavaConfigValidationListener implements ApplicationListener<ContextRefreshedEvent> {
private final ModuleDefinition moduleDefinition;
private final String[] basePackages;
public JavaConfigValidationListener(SimpleModuleDefinition moduleDefinition, String[] basePackages) {
this.basePackages = Arrays.copyOf(basePackages, basePackages.length);
this.moduleDefinition = moduleDefinition;
}
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
ApplicationContext context = event.getApplicationContext();
Map<String, Object> moduleConfiguration = context.getBeansWithAnnotation(Configuration.class);
boolean found = false;
if (!CollectionUtils.isEmpty(moduleConfiguration)) {
for (String pkg : basePackages) {
if (found) {
break;
}
for (Object obj : moduleConfiguration.values()) {
if (obj.getClass().getName().startsWith(pkg)) {
found = true;
}
}
}
}
if (!found) {
throw new RuntimeException(String.format(
"Unable to find a module @Configuration class in base_packages: %s for module %s:%s",
StringUtils.arrayToCommaDelimitedString(basePackages),
moduleDefinition.getName(), moduleDefinition.getType()
));
}
}
}
}