/* * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.yangtools.sal.binding.yang.types; import com.google.common.base.Function; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import java.util.List; import java.util.Map; import java.util.Set; import org.opendaylight.yangtools.yang.model.api.TypeDefinition; import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition; import org.opendaylight.yangtools.yang.model.util.ExtendedType; import org.opendaylight.yangtools.yang.parser.util.TopologicalSort; import org.opendaylight.yangtools.yang.parser.util.TopologicalSort.Node; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class UnionDependencySort { private static final Logger LOGGER = LoggerFactory.getLogger(UnionDependencySort.class); /** * Sorts union types by mutual dependencies. * * At the beginning the union types are selected from * typeDefinitions and wrapped to nodes. The nodes are sorted * and then the wrapped payload is extracted. * * @param typeDefinitions * set of type definitions. * @return list of extended type which are sorted by mutual dependencies * @throws IllegalArgumentException * if typeDefinitions equals null */ public List sort(final Set> typeDefinitions) { if (typeDefinitions == null) { LOGGER.error("Set of Type Definitions cannot be NULL!"); throw new IllegalArgumentException("Set of Type Definitions " + "cannot be NULL!"); } final Set extUnionTypes = unionsFromTypeDefinitions(typeDefinitions); final Set unsorted = unionTypesToNodes(extUnionTypes); final List sortedNodes = TopologicalSort.sort(unsorted); return Lists.transform(sortedNodes, new Function() { @Override public ExtendedType apply(final Node input) { return (ExtendedType) (((NodeWrappedType) input).getWrappedType()); } }); } /** * Extracts only union types from typeDefinitions set. * * @param typeDefinitions * set of all type definitions * @return set of extended type which are union type definition */ private static Set unionsFromTypeDefinitions(final Set> typeDefinitions) { final Set unions = Sets.newHashSet(); for (final TypeDefinition typedef : typeDefinitions) { if ((typedef != null) && (typedef.getBaseType() != null) && (typedef instanceof ExtendedType) && (typedef.getBaseType() instanceof UnionTypeDefinition)) { unions.add((ExtendedType) typedef); } } return unions; } /** * Wraps every extended type which represents union to node type and adds to * every node information about dependencies. * * The mapping from union type to node is created. For every created node * (next nodeFrom) is for its wrapped union type passed the list of * inner types through and only those inner types which represent union type * are next considered. For every inner union type is found its wrapping * node (next as nodeTo). This dependency relationship between * nodeFrom and all found nodesTo is modeled with creating of one edge from * nodeFrom to nodeTo. * * * @param extUnionTypes * set of extended types which represents union types * @return set of nodes which contains wrapped union types set of node where * each one contains wrapped one union type */ private static Set unionTypesToNodes(final Set extUnionTypes) { final Map nodeMap = Maps.newHashMap(); final Set resultNodes = Sets.newHashSet(); for (final ExtendedType unionType : extUnionTypes) { final Node node = new NodeWrappedType(unionType); nodeMap.put(unionType, node); resultNodes.add(node); } for (final Node node : resultNodes) { final NodeWrappedType nodeFrom = (NodeWrappedType) node; final ExtendedType extUnionType = (ExtendedType) nodeFrom.getWrappedType(); final UnionTypeDefinition unionType = (UnionTypeDefinition) extUnionType.getBaseType(); final List> innerTypes = unionType.getTypes(); for (final TypeDefinition typedef : innerTypes) { if (extUnionTypes.contains(typedef)) { final Node toNode = nodeMap.get(typedef); nodeFrom.addEdge(toNode); } } } return resultNodes; } }