All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hisrc.jsonix.definition.Mapping Maven / Gradle / Ivy

There is a newer version: 2.3.9
Show newest version
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