com.cisco.oss.foundation.configuration.xml.NamespaceDefinitionMessage Maven / Gradle / Ivy
/*
* Copyright 2014 Cisco Systems, Inc.
*
* 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 com.cisco.oss.foundation.configuration.xml;
import com.cisco.oss.foundation.configuration.xml.jaxb.NamespaceDefinition;
import com.cisco.oss.foundation.configuration.xml.jaxb.NamespaceDefinitions;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* This class is responsible for marshalling and unmarshalling NamespaceDefinition messages.
* @author dventura
*
*/
public class NamespaceDefinitionMessage {
private String xml = null;
private NamespaceDefinitions jaxb = null;
private XmlParser parser = null;
public NamespaceDefinitionMessage(String xml) throws XmlException {
parser = new XmlParser();
jaxb = unmarshall(xml);
this.xml = xml;
}
public NamespaceDefinitionMessage(NamespaceDefinitions jaxb) throws XmlException {
parser = new XmlParser();
xml = marshall(jaxb);
this.jaxb = jaxb;
}
public String toXml() {
return(xml);
}
public NamespaceDefinitions jaxb() {
return(jaxb);
}
protected String marshall(NamespaceDefinitions jaxb) throws XmlException {
return(parser.marshall(jaxb));
}
protected NamespaceDefinitions unmarshall(String xml) throws XmlException {
NamespaceDefinitions jaxb = null;
try {
jaxb = (NamespaceDefinitions)parser.unmarshall(xml);
} catch(ClassCastException e) {
throw new XmlException("The given message was not a NamespaceDefinitions Message - ClassCastException: " + e.getMessage(), e);
}
return(jaxb);
}
/**
* A NamespaceDefinition cannot be injected into the DB unless it's dependencies are injected first.
* This method will sort the given list of NamespaceDefinitions by dependency.
*
* If dependencies are missing, or circular dependencies exist such that there aren't any NamespaceDefinitions without dependencies
* a XmlException will be thrown.
*
* @return The list of NamespaceDefinition Object, sorted by dependencies
*
* @throws XmlException if dependencies are missing or circular dependencies exist such that there aren't any NamespaceDefinitions without dependencies
*/
public List sortByDependencies() throws XmlException {
ArrayList sorted = new ArrayList();
Map> namespaceMap = createNamespaceMap(jaxb.getNamespaceDefinitions());
NamespaceDefinition def = null;
do {
def = extractNamespaceWithLeastDependencies(namespaceMap);
if(def != null) {
sorted.add(def);
}
} while(def != null);
return(sorted);
}
protected NamespaceDefinition extractNamespaceWithLeastDependencies(Map> namespaceMap) {
if( (namespaceMap == null) || (namespaceMap.keySet().size() == 0) ) {
return(null);
}
Namespace lowest = null;
int lowestSize = Integer.MAX_VALUE;
for(Namespace current: namespaceMap.keySet()) {
int currentSize = namespaceMap.get(current).size();
if( (lowest == null) || (currentSize < lowestSize) ){
lowest = current;
lowestSize = currentSize;
}
}
namespaceMap.remove(lowest);
return(lowest.getNamespaceDefinition());
}
/**
* Checks that there aren't namespaces that depend on namespaces that don't exist in the list,
* and creates a list of all Namespace Objects in the list.
*
* @throws XmlException if there are any dependencies missing.
*/
protected Map> createNamespaceMap(List namespaceDefs) throws XmlException {
ArrayList namespaces = new ArrayList();
// add all root namespaces
for(NamespaceDefinition namespaceDef: namespaceDefs) {
Namespace node = new Namespace(namespaceDef);
if(namespaces.contains(node)) {
throw new XmlException("duplicate NamespaceDefinitions found: " + node.getId());
}
namespaces.add(node);
}
// go through each namespace's dependencies to see if any are missing
for(Namespace namespace: namespaces) {
List dependencyIds = namespace.getDirectDependencyIds();
for(String id: dependencyIds) {
if(find(namespaces, id) == null) {
throw new XmlException("Found missing dependency: " + id);
}
}
}
HashMap> namespaceFullDependencyMap = new HashMap>();
for(Namespace namespace: namespaces) {
ArrayList fullDependencies = new ArrayList();
for(String directDependencyId: namespace.getDirectDependencyIds()) {
addDependenciesRecursively(namespace, namespaces, directDependencyId, fullDependencies);
}
namespaceFullDependencyMap.put(namespace, fullDependencies);
}
return(namespaceFullDependencyMap);
}
/**
* Adds dependencyId, and all of it's depdencies recursively using namespaceList, to extendedDependencies for namespace.
* @throws XmlException
*/
protected void addDependenciesRecursively(Namespace namespace, List namespaceList, String dependencyId, List extendedDependencies) throws XmlException {
if(extendedDependencies.contains(dependencyId)) {
return;
}
if(namespace.getId().equals(dependencyId)) {
throw new XmlException("Circular dependency found in " + namespace.getId());
}
Namespace dependency = find(namespaceList, dependencyId);
extendedDependencies.add(dependency.getId());
for(String indirectDependencyId: dependency.getDirectDependencyIds()) {
addDependenciesRecursively(namespace, namespaceList, indirectDependencyId, extendedDependencies);
}
}
private Namespace find(List namespaces, String id) throws XmlException {
for(Namespace namespace: namespaces) {
if(namespace.getId().equals(id)) {
return(namespace);
}
}
return(null);
}
}