org.hisrc.jsonix.configuration.ModulesConfiguration Maven / Gradle / Ivy
package org.hisrc.jsonix.configuration;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import javax.xml.namespace.QName;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.hisrc.jsonix.analysis.ModelInfoGraphAnalyzer;
import org.hisrc.jsonix.context.JsonixContext;
import org.hisrc.jsonix.definition.Mapping;
import org.hisrc.jsonix.definition.Module;
import org.hisrc.jsonix.definition.Modules;
import org.hisrc.jsonix.naming.StandardNaming;
import org.jgrapht.DirectedGraph;
import org.jgrapht.EdgeFactory;
import org.jgrapht.alg.StrongConnectivityInspector;
import org.jgrapht.graph.DefaultDirectedGraph;
import org.jgrapht.traverse.TopologicalOrderIterator;
import org.jvnet.jaxb2_commons.xml.bind.model.MModelInfo;
import org.jvnet.jaxb2_commons.xml.bind.model.MPackageInfo;
import org.slf4j.Logger;
@XmlRootElement(name = ModulesConfiguration.LOCAL_ELEMENT_NAME)
@XmlType(propOrder = {})
public class ModulesConfiguration {
public static final String DEFAULT_PREFIX = "jsonix";
public static final String NAMESPACE_URI = "http://jsonix.highsource.org/customizations";
public static final String LOCAL_ELEMENT_NAME = "modules";
public static final QName ELEMENT_NAME = new QName(
ModulesConfiguration.NAMESPACE_URI, LOCAL_ELEMENT_NAME,
ModulesConfiguration.DEFAULT_PREFIX);
private List moduleConfigurations = new LinkedList();
private List mappingConfigurations = new LinkedList();
private List outputConfigurations = new LinkedList();
public List getModuleConfigurations() {
return moduleConfigurations;
}
public void setModuleConfigurations(
List moduleConfigurations) {
this.moduleConfigurations = moduleConfigurations;
}
public List getMappingConfigurations() {
return mappingConfigurations;
}
public void setMappingConfigurations(
List mappingConfigurations) {
this.mappingConfigurations = mappingConfigurations;
}
public List getOutputConfigurations() {
return outputConfigurations;
}
public void setOutputConfigurations(
List outputConfigurations) {
this.outputConfigurations = outputConfigurations;
}
public Modules build(JsonixContext context,
MModelInfo modelInfo) {
final ModelInfoGraphAnalyzer analyzer = new ModelInfoGraphAnalyzer(
context, modelInfo);
final List moduleConfigurations = new LinkedList(
getModuleConfigurations());
createModuleConfigurationsForMappingConfigurations(
moduleConfigurations, getMappingConfigurations());
createModuleConfigurationsForUnmappedPackages(analyzer,
moduleConfigurations);
assignDefaultOutputConfigurations(moduleConfigurations);
assignMappingNamesAndIds(context, moduleConfigurations);
return buildModules(context, modelInfo, analyzer, moduleConfigurations);
}
private void assignMappingNamesAndIds(JsonixContext context,
final List moduleConfigurations) {
// Generate ids where missing
final Map idToMappingConfiguration = new HashMap();
final Map> nameToMappingConfiguration = new HashMap>();
// Set mapping name and ids
for (final ModuleConfiguration moduleConfiguration : moduleConfigurations) {
for (final MappingConfiguration mappingConfiguration : moduleConfiguration
.getMappingConfigurations()) {
assignMappingName(mappingConfiguration);
assignMappingId(context, idToMappingConfiguration,
nameToMappingConfiguration, mappingConfiguration);
}
}
}
private void assignMappingId(
JsonixContext context,
final Map idToMappingConfiguration,
final Map> nameToMappingConfiguration,
final MappingConfiguration mappingConfiguration) {
final Logger logger = Validate.notNull(context).getLoggerFactory()
.getLogger(ModulesConfiguration.class.getName());
final String mappingName = mappingConfiguration.getName();
String mappingId = mappingConfiguration.getId();
if (mappingId != null) {
// TODO throw an exception, don't try to correct
if (idToMappingConfiguration.containsKey(mappingId)) {
logger.error(MessageFormat
.format("Mapping id [{0}] is already defined, generating a new mapping id.",
mappingId));
mappingId = null;
}
}
if (mappingId != null) {
idToMappingConfiguration.put(mappingId, mappingConfiguration);
} else {
List mappings = nameToMappingConfiguration
.get(mappingName);
if (mappings == null) {
mappings = new ArrayList(2);
logger.debug(MessageFormat.format(
"Assigning id [{0}] to the mapping with name [{1}].",
mappingName, mappingName));
mappingId = mappingName;
mappingConfiguration.setId(mappingId);
mappings.add(mappingConfiguration);
nameToMappingConfiguration.put(mappingName, mappings);
idToMappingConfiguration.put(mappingId, mappingConfiguration);
} else if (mappings.size() == 1) {
logger.debug(MessageFormat
.format("There are more than one mapping with the name [{0}] without id.",
mappingName));
final String mappingId0 = mappingName + "-0";
final MappingConfiguration mappingConfiguration0 = mappings
.get(0);
logger.debug(MessageFormat.format(
"Assigning id [{0}] to the mapping with name [{1}].",
mappingId0, mappingName));
mappingConfiguration0.setId(mappingId0);
mappingId = mappingName + "-1";
logger.debug(MessageFormat.format(
"Assigning id [{0}] to the mapping with name [{1}].",
mappingId, mappingName));
mappingConfiguration.setId(mappingId);
mappings.add(mappingConfiguration);
idToMappingConfiguration.remove(mappingName);
idToMappingConfiguration.put(mappingId0, mappingConfiguration0);
idToMappingConfiguration.put(mappingId, mappingConfiguration);
} else {
mappingId = mappingName + mappings.size();
logger.debug(MessageFormat.format(
"Assigning id [{0}] to the mapping with name [{1}].",
mappingId, mappingName));
mappingConfiguration.setId(mappingId);
mappings.add(mappingConfiguration);
idToMappingConfiguration.put(mappingId, mappingConfiguration);
}
}
}
private String assignMappingName(
final MappingConfiguration mappingConfiguration) {
String mappingName = mappingConfiguration.getName();
if (StringUtils.isBlank(mappingName)) {
final String packageName = mappingConfiguration.getPackage();
if (packageName != null) {
mappingName = StringUtils.isBlank(packageName) ? "Mapping"
: packageName.replace('.', '_');
}
mappingConfiguration.setName(mappingName);
}
return mappingName;
}
private void createModuleConfigurationsForUnmappedPackages(
final ModelInfoGraphAnalyzer analyzer,
final List moduleConfigurations) {
final Set packageNames = findUnmappedPackageNames(
analyzer.getPackageNames(), moduleConfigurations);
for (final String packageName : packageNames) {
final MappingConfiguration mappingConfiguration = new MappingConfiguration();
mappingConfiguration.setPackage(packageName);
final ModuleConfiguration moduleConfiguration = new ModuleConfiguration();
moduleConfiguration.getMappingConfigurations().add(
mappingConfiguration);
moduleConfigurations.add(moduleConfiguration);
}
}
private void assignDefaultOutputConfigurations(
final List moduleConfigurations) {
final List defaultOutputConfigurations = createDefaultOutputConfigurations();
for (final ModuleConfiguration moduleConfiguration : moduleConfigurations) {
if (moduleConfiguration.getOutputConfigurations().isEmpty()) {
moduleConfiguration.getOutputConfigurations().addAll(
defaultOutputConfigurations);
}
}
}
private Set findUnmappedPackageNames(
final Set allPackageNames,
final List moduleConfigurations) {
final Set packageNames = new HashSet(allPackageNames);
final Set mappedPackagesNames = new HashSet();
for (final ModuleConfiguration moduleConfiguration : moduleConfigurations) {
for (final MappingConfiguration mappingConfiguration : moduleConfiguration
.getMappingConfigurations()) {
mappedPackagesNames.add(mappingConfiguration.getPackage());
}
}
packageNames.removeAll(mappedPackagesNames);
return packageNames;
}
private void createModuleConfigurationsForMappingConfigurations(
final List moduleConfigurations,
final List mappingConfigurations) {
// Create one module configuration per mapping configuration
for (final MappingConfiguration mappingConfiguration : mappingConfigurations) {
final ModuleConfiguration moduleConfiguration = new ModuleConfiguration();
moduleConfiguration.getMappingConfigurations().add(
mappingConfiguration);
moduleConfigurations.add(moduleConfiguration);
}
}
private List createDefaultOutputConfigurations() {
final List defaultOutputConfigurations = getOutputConfigurations();
// If default output configurations are not configured, add the standard
// configuration
if (defaultOutputConfigurations.isEmpty()) {
defaultOutputConfigurations.add(new OutputConfiguration(
StandardNaming.NAMING_NAME));
}
return defaultOutputConfigurations;
}
private Modules buildModules(JsonixContext context,
MModelInfo modelInfo,
final ModelInfoGraphAnalyzer analyzer,
final List moduleConfigurations) {
final List mappingConfigurations = getTopologicallyOrderedMappingConfigurations(
context, moduleConfigurations);
final Map> mappings = buildMappings(context,
modelInfo, analyzer, mappingConfigurations);
final List> modules = new ArrayList>(
moduleConfigurations.size());
for (ModuleConfiguration moduleConfiguration : moduleConfigurations) {
final Module module = moduleConfiguration.build(analyzer,
modelInfo, mappings);
if (module != null) {
modules.add(module);
}
}
return new Modules(context, modelInfo, modules);
}
private Map> buildMappings(
JsonixContext context, MModelInfo modelInfo,
final ModelInfoGraphAnalyzer analyzer,
final List mappingConfigurations) {
final Logger logger = Validate.notNull(context).getLoggerFactory()
.getLogger(ModulesConfiguration.class.getName());
final Map> mappings = new HashMap>();
for (MappingConfiguration mappingConfiguration : mappingConfigurations) {
final String packageName = mappingConfiguration.getPackage();
final MPackageInfo packageInfo = analyzer.getPackageInfoMap().get(
packageName);
if (packageInfo == null) {
logger.warn(MessageFormat.format(
"Package name [{0}] could not be found.",
Validate.notNull(packageName)));
// throw new MissingPackageException(packageName);
} else {
final Mapping mapping = mappingConfiguration.build(
context, analyzer, modelInfo, packageInfo, mappings);
mappings.put(mappingConfiguration.getId(), mapping);
}
}
return mappings;
}
private List getTopologicallyOrderedMappingConfigurations(
JsonixContext context,
final List moduleConfigurations) {
final DirectedGraph mappingConfigurationDependencyGraph = buildMappingConfigurationDependencyGraph(
context, moduleConfigurations);
final StrongConnectivityInspector strongConnectivityInspector = new StrongConnectivityInspector(
mappingConfigurationDependencyGraph);
final List> stronglyConnectedSets = strongConnectivityInspector
.stronglyConnectedSets();
for (Set stronglyConnectedSet : stronglyConnectedSets) {
if (stronglyConnectedSet.size() > 1) {
throw new IllegalArgumentException(MessageFormat.format(
"Mappings have the following dependency cycle: {0}",
stronglyConnectedSet.toString()));
}
}
final List mappingConfigurations = new ArrayList(
mappingConfigurationDependencyGraph.vertexSet().size());
for (Iterator mappingConfigurationsInTopologicalOrderIterator = new TopologicalOrderIterator(
mappingConfigurationDependencyGraph); mappingConfigurationsInTopologicalOrderIterator
.hasNext();) {
mappingConfigurations
.add(mappingConfigurationsInTopologicalOrderIterator.next());
}
return mappingConfigurations;
}
private DirectedGraph buildMappingConfigurationDependencyGraph(
JsonixContext context,
final List moduleConfigurations) {
final Logger logger = Validate.notNull(context).getLoggerFactory()
.getLogger(ModulesConfiguration.class.getName());
final DirectedGraph mappingDependenciesGraph = new DefaultDirectedGraph(
new EdgeFactory() {
public Object createEdge(MappingConfiguration sourceVertex,
MappingConfiguration targetVertex) {
return new Object();
};
});
final Map idToMappingConfiguration = new HashMap();
final Map> nameToMappingConfiguration = new HashMap>();
for (ModuleConfiguration moduleConfiguration : moduleConfigurations) {
for (MappingConfiguration mappingConfiguration : moduleConfiguration
.getMappingConfigurations()) {
final String id = mappingConfiguration.getId();
final String name = mappingConfiguration.getName();
idToMappingConfiguration.put(id, mappingConfiguration);
List mappings = nameToMappingConfiguration
.get(name);
if (mappings == null) {
mappings = new ArrayList(2);
nameToMappingConfiguration.put(name, mappings);
}
mappings.add(mappingConfiguration);
}
}
for (ModuleConfiguration moduleConfiguration : moduleConfigurations) {
for (MappingConfiguration mappingConfiguration : moduleConfiguration
.getMappingConfigurations()) {
mappingDependenciesGraph.addVertex(mappingConfiguration);
final IncludesConfiguration includesConfiguration = mappingConfiguration
.getIncludesConfiguration();
if (includesConfiguration != null) {
for (DependenciesOfMappingConfiguration dependenciesOfMappingConfiguration : includesConfiguration
.getDependenciesOfMappingConfiguration()) {
final String id = dependenciesOfMappingConfiguration
.getId();
final String name = dependenciesOfMappingConfiguration
.getName();
MappingConfiguration dependingMappingConfiguration = null;
if (id != null) {
dependingMappingConfiguration = idToMappingConfiguration
.get(id);
if (dependingMappingConfiguration == null) {
throw new MissingMappingWithIdException(id);
}
mappingDependenciesGraph
.addVertex(dependingMappingConfiguration);
mappingDependenciesGraph.addEdge(
dependingMappingConfiguration,
mappingConfiguration);
} else if (name != null) {
final List dependingMappingConfigurations = nameToMappingConfiguration
.get(name);
if (dependingMappingConfigurations == null
|| dependingMappingConfigurations.isEmpty()) {
throw new MissingMappinWithNameException(name);
} else if (dependingMappingConfigurations.size() > 1) {
throw new AmbiguousMappingNameException(name);
} else {
// Ok, now the payload
dependingMappingConfiguration = dependingMappingConfigurations
.get(0);
dependenciesOfMappingConfiguration
.setId(dependingMappingConfiguration
.getId());
}
mappingDependenciesGraph
.addVertex(dependingMappingConfiguration);
mappingDependenciesGraph.addEdge(
dependingMappingConfiguration,
mappingConfiguration);
} else {
logger.warn(MessageFormat
.format("Either [id] or [name] must be defined in the [{0}] element.",
DependenciesOfMappingConfiguration.LOCAL_ELEMENT_NAME));
}
}
}
}
}
return mappingDependenciesGraph;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy