org.hisrc.jsonix.definition.Mapping Maven / Gradle / Ivy
package org.hisrc.jsonix.definition;
import java.text.MessageFormat;
import java.util.Collection;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import org.apache.commons.lang3.Validate;
import org.hisrc.jsonix.analysis.DefaultInfoVertexVisitor;
import org.hisrc.jsonix.analysis.DependencyEdge;
import org.hisrc.jsonix.analysis.DependencyType;
import org.hisrc.jsonix.analysis.ElementInfoVertex;
import org.hisrc.jsonix.analysis.InfoVertex;
import org.hisrc.jsonix.analysis.InfoVertexVisitor;
import org.hisrc.jsonix.analysis.ModelInfoGraphAnalyzer;
import org.hisrc.jsonix.analysis.PackageInfoVertex;
import org.hisrc.jsonix.analysis.PropertyInfoVertex;
import org.hisrc.jsonix.analysis.TypeInfoVertex;
import org.hisrc.jsonix.context.JsonixContext;
import org.jgrapht.DirectedGraph;
import org.jvnet.jaxb2_commons.xml.bind.model.MClassInfo;
import org.jvnet.jaxb2_commons.xml.bind.model.MElementInfo;
import org.jvnet.jaxb2_commons.xml.bind.model.MEnumLeafInfo;
import org.jvnet.jaxb2_commons.xml.bind.model.MPackageInfo;
import org.jvnet.jaxb2_commons.xml.bind.model.MPropertyInfo;
import org.jvnet.jaxb2_commons.xml.bind.model.MTypeInfo;
import org.jvnet.jaxb2_commons.xml.bind.model.MTypeInfoVisitor;
import org.jvnet.jaxb2_commons.xml.bind.model.util.DefaultTypeInfoVisitor;
import org.slf4j.Logger;
public class Mapping {
private final Logger logger;
private final ModelInfoGraphAnalyzer analyzer;
private final MPackageInfo packageInfo;
private final Collection> classInfos = new HashSet>();
private final Collection> propertyInfos = new HashSet>();
private final Collection> enumLeafInfos = new HashSet>();
private final Collection> elementInfos = new HashSet>();
private final Collection> infoVertices = new HashSet>();
private final String packageName;
private final String mappingName;
private final String schemaId;
private final String targetNamespaceURI;
private final String defaultElementNamespaceURI;
private final String defaultAttributeNamespaceURI;
private final Map, ContainmentType> verticesContainmentMap = new HashMap, ContainmentType>();
public Mapping(JsonixContext context,
ModelInfoGraphAnalyzer analyzer, MPackageInfo packageInfo,
String mappingName, String schemaId, String targetNamespaceURI,
String defaultElementNamespaceURI,
String defaultAttributeNamespaceURI) {
this.logger = Validate.notNull(context).getLoggerFactory()
.getLogger(Mapping.class.getName());
Validate.notNull(analyzer);
Validate.notNull(packageInfo);
Validate.notNull(mappingName);
Validate.notNull(schemaId);
Validate.notNull(defaultElementNamespaceURI);
Validate.notNull(defaultAttributeNamespaceURI);
this.analyzer = analyzer;
this.packageInfo = packageInfo;
this.packageName = packageInfo.getPackageName();
this.mappingName = mappingName;
this.schemaId = schemaId;
this.targetNamespaceURI = targetNamespaceURI;
this.defaultElementNamespaceURI = defaultElementNamespaceURI;
this.defaultAttributeNamespaceURI = defaultAttributeNamespaceURI;
}
public boolean isEmpty() {
return this.elementInfos.isEmpty() && this.classInfos.isEmpty()
&& this.enumLeafInfos.isEmpty();
}
public void includePackage(MPackageInfo packageInfo) {
Validate.notNull(packageInfo);
final PackageInfoVertex vertex = new PackageInfoVertex(
packageInfo);
includeInfoVertex(vertex);
}
public void includePropertyInfo(MPropertyInfo propertyInfo) {
Validate.notNull(propertyInfo);
final PropertyInfoVertex vertex = new PropertyInfoVertex(
propertyInfo);
includeInfoVertex(vertex);
}
public void includeElementInfo(MElementInfo elementInfo) {
Validate.notNull(elementInfo);
final ElementInfoVertex vertex = new ElementInfoVertex(
elementInfo);
includeInfoVertex(vertex);
}
public void includeTypeInfo(MTypeInfo typeInfo) {
Validate.notNull(typeInfo);
final TypeInfoVertex vertex = new TypeInfoVertex(
this.packageInfo, typeInfo);
includeInfoVertex(vertex);
}
public void includeDependenciesOfMapping(Mapping mapping) {
Validate.notNull(mapping);
final Map, ContainmentType> dependendMappingVerticesContainmentMap = mapping.verticesContainmentMap;
for (Map.Entry, ContainmentType> entry : dependendMappingVerticesContainmentMap
.entrySet()) {
final ContainmentType dependendMappingVertexContainmentType = entry
.getValue();
// If a given vertex is excluded in the dependend mapping
if (!dependendMappingVertexContainmentType.isIncluded()) {
// Check if this vertex is included in the given map
final InfoVertex dependendMappingVertex = entry.getKey();
final ContainmentType containmentType = this.verticesContainmentMap
.get(dependendMappingVertex);
final ContainmentType newContainmentType = dependendMappingVertexContainmentType
.combineWith(containmentType);
if (newContainmentType != containmentType) {
this.verticesContainmentMap.put(dependendMappingVertex,
newContainmentType);
}
}
}
for (Map.Entry, ContainmentType> entry : dependendMappingVerticesContainmentMap
.entrySet()) {
final ContainmentType dependendMappingVertexContainmentType = entry
.getValue();
// If a given vertex is excluded in the dependend mapping
if (dependendMappingVertexContainmentType.isIncluded()) {
final InfoVertex dependendMappingVertex = entry.getKey();
includeInfoVertex(dependendMappingVertex);
}
}
}
public Collection> getDirectDependencies() {
final Map> dependencies = new HashMap>();
final DirectedGraph, DependencyEdge> graph = analyzer
.getGraph();
final Collection> vertices = new HashSet>(
getInfoVertices());
for (InfoVertex sourceVertex : vertices) {
final Set edges = graph
.outgoingEdgesOf(sourceVertex);
for (DependencyEdge edge : edges) {
if (edge.getType() == DependencyType.HARD) {
final InfoVertex targetVertex = graph
.getEdgeTarget(edge);
final MPackageInfo packageInfo = targetVertex
.getPackageInfo();
// If this another package (not this package and not the
// built-in package)
if (packageInfo != null
&& !this.packageInfo.equals(packageInfo)) {
MappingDependency dependency = dependencies
.get(packageInfo);
if (dependency == null) {
dependency = new MappingDependency(
packageInfo);
dependencies.put(packageInfo, dependency);
}
dependency.addInfoVertex(targetVertex);
}
}
}
}
return dependencies.values();
}
public void excludePropertyInfo(MPropertyInfo propertyInfo) {
Validate.notNull(propertyInfo);
final PropertyInfoVertex vertex = new PropertyInfoVertex(
propertyInfo);
excludeInfoVertex(vertex);
}
public void excludeElementInfo(MElementInfo elementInfo) {
Validate.notNull(elementInfo);
final ElementInfoVertex vertex = new ElementInfoVertex(
elementInfo);
excludeInfoVertex(vertex);
}
public void excludeTypeInfo(MTypeInfo typeInfo) {
Validate.notNull(typeInfo);
final TypeInfoVertex vertex = new TypeInfoVertex(
this.packageInfo, typeInfo);
excludeInfoVertex(vertex);
}
private void includeInfoVertex(final InfoVertex initialVertex) {
logger.trace(MessageFormat.format("Including the vertex [{0}].",
initialVertex));
final DirectedGraph, DependencyEdge> graph = analyzer
.getGraph();
final SortedMap>> deques = new TreeMap>>();
deques.put(ContainmentType.INCLUDED_EXPLICITLY,
new LinkedList>());
deques.put(ContainmentType.INCLUDED_AS_HARD_DEPENDENCY,
new LinkedList>());
deques.put(ContainmentType.INCLUDED_AS_SOFT_DEPENDENCY,
new LinkedList>());
deques.get(ContainmentType.INCLUDED_EXPLICITLY).add(initialVertex);
for (Map.Entry>> dequeEntry : deques
.entrySet()) {
final ContainmentType dequeContainmentType = dequeEntry.getKey();
final Deque> deque = dequeEntry.getValue();
while (!deque.isEmpty()) {
final InfoVertex sourceVertex = deque.removeFirst();
final ContainmentType currentSourceContainmentType = getInfoVertexContainmentType(sourceVertex);
final ContainmentType sourceContainmentType = dequeContainmentType
.combineWith(currentSourceContainmentType);
if (currentSourceContainmentType == null
|| currentSourceContainmentType
.compareTo(sourceContainmentType) > 0) {
if (currentSourceContainmentType != null
&& !currentSourceContainmentType.isIncluded()) {
logger.warn(MessageFormat
.format("The vertex [{0}] was excluded with the containment type [{1}], but it must be included with containment type [{2}], otherwise mappings will not be consistent.",
sourceVertex,
currentSourceContainmentType,
sourceContainmentType));
} else {
logger.trace(MessageFormat
.format("Including the vertex [{0}] with the containment type [{1}].",
sourceVertex, dequeContainmentType));
}
setInfoVertexContainmentType(sourceVertex,
sourceContainmentType);
final Set edges = graph
.outgoingEdgesOf(sourceVertex);
for (DependencyEdge edge : edges) {
final InfoVertex targetVertex = graph
.getEdgeTarget(edge);
final DependencyType dependencyType = edge.getType();
final ContainmentType targetContainmentType = dependencyType
.combineWith(sourceContainmentType);
if (targetContainmentType != null) {
final Deque> targetDeque = deques
.get(targetContainmentType);
if (targetDeque != null) {
logger.trace(MessageFormat
.format("Queueing the inclusion of the vertex [{0}] with the containment type [{1}].",
targetVertex,
targetContainmentType));
targetDeque.add(targetVertex);
}
}
}
} else {
logger.trace(MessageFormat
.format("Vertex [{0}] is already included with the containment type [{1}].",
sourceVertex, currentSourceContainmentType));
}
}
}
}
private ContainmentType getInfoVertexContainmentType(
final InfoVertex sourceVertex) {
ContainmentType sourceContainmentType = verticesContainmentMap
.get(sourceVertex);
return sourceContainmentType;
}
private void excludeInfoVertex(final InfoVertex vertex) {
Validate.notNull(vertex);
logger.trace(MessageFormat.format("Excluding [{0}].", vertex));
final DirectedGraph, DependencyEdge> graph = analyzer
.getGraph();
final SortedMap>> deques = new TreeMap>>();
deques.put(ContainmentType.EXCLUDED_EXPLICITLY,
new LinkedList>());
deques.put(ContainmentType.EXCLUDED_AS_HARD_DEPENDENCY,
new LinkedList>());
deques.get(ContainmentType.EXCLUDED_EXPLICITLY).add(vertex);
for (Map.Entry>> dequeEntry : deques
.entrySet()) {
final ContainmentType dequeContainmentType = dequeEntry.getKey();
final Deque> deque = dequeEntry.getValue();
while (!deque.isEmpty()) {
final InfoVertex targetVertex = deque.removeFirst();
final ContainmentType currentTargetContainmentType = getInfoVertexContainmentType(targetVertex);
final ContainmentType targetContainmentType = dequeContainmentType
.combineWith(currentTargetContainmentType);
if (currentTargetContainmentType == null
|| currentTargetContainmentType
.compareTo(targetContainmentType) > 0) {
logger.trace(MessageFormat
.format("Excluding the vertex [{0}] with the containment type [{1}].",
targetVertex, targetContainmentType));
setInfoVertexContainmentType(targetVertex,
targetContainmentType);
final Set edges = graph
.incomingEdgesOf(targetVertex);
for (DependencyEdge edge : edges) {
final InfoVertex sourceVertex = graph
.getEdgeSource(edge);
final DependencyType dependencyType = edge.getType();
final ContainmentType sourceContainmentType = dependencyType
.combineWith(targetContainmentType);
if (sourceContainmentType != null) {
final Deque> sourceDeque = deques
.get(sourceContainmentType);
if (sourceDeque != null) {
logger.trace(MessageFormat
.format("Queueing the exclusion of the vertex [{0}] with the containment type [{1}].",
sourceVertex,
sourceContainmentType));
sourceDeque.add(sourceVertex);
}
}
}
} else {
logger.trace(MessageFormat
.format("Vertex [{0}] is already excluded with the containment type [{1}].",
targetVertex, targetContainmentType));
}
}
}
}
private final InfoVertexVisitor infoVertexAdder = new DefaultInfoVertexVisitor() {
@Override
public Void visitTypeInfoVertex(TypeInfoVertex vertex) {
addTypeInfo(vertex.getTypeInfo());
return null;
}
@Override
public Void visitElementInfoVertex(ElementInfoVertex vertex) {
addElementInfo(vertex.getElementInfo());
return null;
}
@Override
public Void visitPropertyInfoVertex(PropertyInfoVertex vertex) {
addPropertyInfo(vertex.getPropertyInfo());
return null;
}
};
private void setInfoVertexContainmentType(InfoVertex vertex,
ContainmentType containmentType) {
Validate.notNull(vertex);
verticesContainmentMap.put(vertex, containmentType);
if (containmentType.isIncluded()) {
vertex.accept(infoVertexAdder);
}
}
private final MTypeInfoVisitor typeInfoAdder = new DefaultTypeInfoVisitor() {
@Override
public Void visitClassInfo(MClassInfo info) {
Mapping.this.addClassInfo(info);
return null;
}
@Override
public Void visitEnumLeafInfo(MEnumLeafInfo info) {
Mapping.this.addEnumLeafInfo(info);
return null;
}
};
private void addTypeInfo(MTypeInfo typeInfo) {
Validate.notNull(typeInfo);
typeInfo.acceptTypeInfoVisitor(typeInfoAdder);
}
private void addElementInfo(MElementInfo elementInfo) {
Validate.notNull(elementInfo);
if (this.packageInfo.equals(elementInfo.getPackageInfo())) {
this.elementInfos.add(elementInfo);
this.infoVertices.add(new ElementInfoVertex(elementInfo));
}
}
private void addClassInfo(MClassInfo classInfo) {
Validate.notNull(classInfo);
if (this.packageInfo.equals(classInfo.getPackageInfo())) {
this.classInfos.add(classInfo);
this.infoVertices.add(new TypeInfoVertex(classInfo
.getPackageInfo(), classInfo));
}
}
private void addEnumLeafInfo(MEnumLeafInfo enumLeafInfo) {
Validate.notNull(enumLeafInfo);
if (this.packageInfo.equals(enumLeafInfo.getPackageInfo())) {
this.enumLeafInfos.add(enumLeafInfo);
this.infoVertices.add(new TypeInfoVertex(enumLeafInfo
.getPackageInfo(), enumLeafInfo));
}
}
private void addPropertyInfo(MPropertyInfo propertyInfo) {
Validate.notNull(propertyInfo);
if (this.packageInfo.equals(propertyInfo.getClassInfo()
.getPackageInfo())) {
this.propertyInfos.add(propertyInfo);
this.infoVertices.add(new PropertyInfoVertex(propertyInfo));
}
}
private Collection> getInfoVertices() {
return infoVertices;
}
public MPackageInfo getPackageInfo() {
return packageInfo;
}
public String getPackageName() {
return packageName;
}
public String getMappingName() {
return mappingName;
}
public String getSchemaId() {
return this.schemaId;
}
public String getTargetNamespaceURI() {
return targetNamespaceURI;
}
public String getDefaultElementNamespaceURI() {
return defaultElementNamespaceURI;
}
public String getDefaultAttributeNamespaceURI() {
return defaultAttributeNamespaceURI;
}
public Collection> getClassInfos() {
return this.classInfos;
}
public Collection> getPropertyInfos() {
return propertyInfos;
}
public Collection> getEnumLeafInfos() {
return this.enumLeafInfos;
}
public Collection> getElementInfos() {
return this.elementInfos;
}
@Override
public String toString() {
return MessageFormat.format("Mapping [{0}]", this.mappingName);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy