BUG 1131: untangling package cyclic dependencies in yang-parser-impl
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / builder / impl / GroupingUtils.java
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/GroupingUtils.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/GroupingUtils.java
new file mode 100644 (file)
index 0000000..42957db
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * 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.yang.parser.builder.impl;
+
+import java.util.Comparator;
+import java.util.Date;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
+import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
+import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
+import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
+import org.opendaylight.yangtools.yang.parser.builder.api.RefineBuilder;
+import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
+import org.opendaylight.yangtools.yang.parser.util.YangParseException;
+
+public final class GroupingUtils {
+
+    private GroupingUtils() {
+    }
+
+    /**
+     * Search given modules for grouping by name defined in uses node.
+     *
+     * @param usesBuilder
+     *            builder of uses statement
+     * @param modules
+     *            all loaded modules
+     * @param module
+     *            current module
+     * @return grouping with given name if found, null otherwise
+     */
+    public static GroupingBuilder getTargetGroupingFromModules(final UsesNodeBuilder usesBuilder,
+            final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
+        final int line = usesBuilder.getLine();
+
+        final String groupingString = usesBuilder.getGroupingPathAsString();
+        String groupingPrefix;
+        String groupingName;
+
+        if (groupingString.contains(":")) {
+            String[] splitted = groupingString.split(":");
+            if (splitted.length != 2 || groupingString.contains("/")) {
+                throw new YangParseException(module.getName(), line, "Invalid name of target grouping");
+            }
+            groupingPrefix = splitted[0];
+            groupingName = splitted[1];
+        } else {
+            groupingPrefix = module.getPrefix();
+            groupingName = groupingString;
+        }
+
+        ModuleBuilder dependentModule;
+        if(groupingPrefix == null) {
+            dependentModule = module;
+        }
+        if (groupingPrefix.equals(module.getPrefix())) {
+            dependentModule = module;
+        } else {
+            dependentModule = BuilderUtils.findModuleFromBuilders(modules, module, groupingPrefix, line);
+        }
+
+        if (dependentModule == null) {
+            return null;
+        }
+
+        GroupingBuilder result;
+        Set<GroupingBuilder> groupings = dependentModule.getGroupingBuilders();
+        result = findGroupingBuilder(groupings, groupingName);
+        if (result != null) {
+            return result;
+        }
+
+        Builder parent = usesBuilder.getParent();
+
+        while (parent != null) {
+            if (parent instanceof DataNodeContainerBuilder) {
+                groupings = ((DataNodeContainerBuilder) parent).getGroupingBuilders();
+            } else if (parent instanceof RpcDefinitionBuilder) {
+                groupings = ((RpcDefinitionBuilder) parent).getGroupings();
+            }
+            result = findGroupingBuilder(groupings, groupingName);
+            if (result == null) {
+                parent = parent.getParent();
+            } else {
+                break;
+            }
+        }
+
+        if (result == null) {
+            throw new YangParseException(module.getName(), line, "Referenced grouping '" + groupingName
+                    + "' not found.");
+        }
+        return result;
+    }
+
+    /**
+     * Search context for grouping by name defined in uses node.
+     *
+     * @param usesBuilder
+     *            builder of uses statement
+     * @param module
+     *            current module
+     * @param context
+     *            SchemaContext containing already resolved modules
+     * @return grouping with given name if found, null otherwise
+     */
+    public static GroupingDefinition getTargetGroupingFromContext(final UsesNodeBuilder usesBuilder,
+            final ModuleBuilder module, final SchemaContext context) {
+        final int line = usesBuilder.getLine();
+        String groupingString = usesBuilder.getGroupingPathAsString();
+        String groupingPrefix;
+        String groupingName;
+
+        if (groupingString.contains(":")) {
+            String[] splitted = groupingString.split(":");
+            if (splitted.length != 2 || groupingString.contains("/")) {
+                throw new YangParseException(module.getName(), line, "Invalid name of target grouping");
+            }
+            groupingPrefix = splitted[0];
+            groupingName = splitted[1];
+        } else {
+            groupingPrefix = module.getPrefix();
+            groupingName = groupingString;
+        }
+
+        Module dependentModule = BuilderUtils.findModuleFromContext(context, module, groupingPrefix, line);
+        return findGroupingDefinition(dependentModule.getGroupings(), groupingName);
+    }
+
+    /**
+     * Find grouping by name.
+     *
+     * @param groupings
+     *            collection of grouping builders to search
+     * @param name
+     *            name of grouping
+     * @return grouping with given name if present in collection, null otherwise
+     */
+    public static GroupingBuilder findGroupingBuilder(final Set<GroupingBuilder> groupings, final String name) {
+        for (GroupingBuilder grouping : groupings) {
+            if (grouping.getQName().getLocalName().equals(name)) {
+                return grouping;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Find grouping by name.
+     *
+     * @param groupings
+     *            collection of grouping definitions to search
+     * @param name
+     *            name of grouping
+     * @return grouping with given name if present in collection, null otherwise
+     */
+    public static GroupingDefinition findGroupingDefinition(final Set<GroupingDefinition> groupings, final String name) {
+        for (GroupingDefinition grouping : groupings) {
+            if (grouping.getQName().getLocalName().equals(name)) {
+                return grouping;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Perform refinement of uses target grouping nodes. Uses process has to be
+     * already performed.
+     *
+     * @param usesNode
+     *            uses node containing refine statements
+     */
+    public static void performRefine(final UsesNodeBuilder usesNode) {
+        for (RefineBuilder refine : usesNode.getRefines()) {
+            String refineTargetPath = refine.getTargetPathString();
+
+            String[] splitted = refineTargetPath.split("/");
+            Builder currentNode = usesNode.getParent();
+            for (String pathElement : splitted) {
+                if (currentNode instanceof DataNodeContainerBuilder) {
+                    currentNode = ((DataNodeContainerBuilder) currentNode).getDataChildByName(pathElement);
+                } else if (currentNode instanceof ChoiceBuilder) {
+                    currentNode = ((ChoiceBuilder) currentNode).getCaseNodeByName(pathElement);
+                }
+            }
+
+            DataSchemaNodeBuilder nodeToRefine = (DataSchemaNodeBuilder) currentNode;
+            if (nodeToRefine == null) {
+                throw new YangParseException(refine.getModuleName(), refine.getLine(), "Refine target node '"
+                        + refine.getTargetPathString() + "' not found");
+            }
+            RefineUtils.performRefine(nodeToRefine, refine);
+            usesNode.addRefineNode(nodeToRefine);
+        }
+    }
+
+    public static class UsesComparator implements Comparator<UsesNodeBuilder> {
+        @Override
+        public int compare(final UsesNodeBuilder o1, final UsesNodeBuilder o2) {
+            return getElementPosition(o2) - getElementPosition(o1);
+        }
+    }
+
+    private static int getElementPosition(final UsesNodeBuilder usesNode) {
+        int i = 0;
+        Builder parent = usesNode.getParent();
+        while (!(parent instanceof ModuleBuilder)) {
+            parent = parent.getParent();
+            i++;
+        }
+        return i;
+    }
+
+}