import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.TreeMap;
import org.antlr.v4.runtime.tree.ParseTree;
import org.apache.commons.io.IOUtils;
+import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Belongs_to_stmtContext;
import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Module_header_stmtsContext;
import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Module_stmtContext;
import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Namespace_stmtContext;
import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Revision_stmtsContext;
+import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Submodule_header_stmtsContext;
+import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Submodule_stmtContext;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
import org.opendaylight.yangtools.yang.parser.builder.api.GroupingMember;
import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
+import org.opendaylight.yangtools.yang.parser.builder.api.UnknownSchemaNodeBuilder;
import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
import org.opendaylight.yangtools.yang.parser.impl.ParserListenerUtils;
import org.opendaylight.yangtools.yang.parser.impl.util.YangModelDependencyInfo;
public final class BuilderUtils {
- private static final DateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
private static final Logger LOG = LoggerFactory.getLogger(BuilderUtils.class);
- private static final Splitter SLASH_SPLITTER = Splitter.on('/').omitEmptyStrings();
private static final Splitter COLON_SPLITTER = Splitter.on(':');
private static final Date NULL_DATE = new Date(0L);
private static final String INPUT = "input";
}
}
- public static DataSchemaNodeBuilder findSchemaNode(final Iterable<QName> path, final SchemaNodeBuilder parentNode) {
- DataSchemaNodeBuilder node = null;
+ public static SchemaNodeBuilder findSchemaNode(final Iterable<QName> path, final SchemaNodeBuilder parentNode) {
+ SchemaNodeBuilder node = null;
SchemaNodeBuilder parent = parentNode;
int size = Iterables.size(path);
int i = 0;
String name = qname.getLocalName();
if (parent instanceof DataNodeContainerBuilder) {
node = ((DataNodeContainerBuilder) parent).getDataChildByName(name);
+ if (node == null) {
+ node = findUnknownNode(name, parent);
+ }
} else if (parent instanceof ChoiceBuilder) {
node = ((ChoiceBuilder) parent).getCaseNodeByName(name);
+ if (node == null) {
+ node = findUnknownNode(name, parent);
+ }
} else if (parent instanceof RpcDefinitionBuilder) {
if ("input".equals(name)) {
node = ((RpcDefinitionBuilder) parent).getInput();
} else if ("output".equals(name)) {
node = ((RpcDefinitionBuilder) parent).getOutput();
} else {
- return null;
+ if (node == null) {
+ node = findUnknownNode(name, parent);
+ }
}
} else {
- return null;
+ node = findUnknownNode(name, parent);
}
if (i < size - 1) {
return node;
}
+ private static UnknownSchemaNodeBuilder findUnknownNode(final String name, final Builder parent) {
+ for (UnknownSchemaNodeBuilder un : parent.getUnknownNodes()) {
+ if (un.getQName().getLocalName().equals(name)) {
+ return un;
+ }
+ }
+ return null;
+ }
+
/**
*
* Find a builder for node in data namespace of YANG module.
Optional<SchemaNodeBuilder> currentNode = getDataNamespaceChild(module, first);
while (currentNode.isPresent() && path.hasNext()) {
- currentNode = findDataChild(currentNode.get(), path.next());
+ SchemaNodeBuilder currentParent = currentNode.get();
+ QName currentPath = path.next();
+ currentNode = findDataChild(currentParent, currentPath);
+ if (!currentNode.isPresent()) {
+ for (SchemaNodeBuilder un : currentParent.getUnknownNodes()) {
+ if (un.getQName().equals(currentPath)) {
+ currentNode = Optional.of(un);
+ }
+ }
+ }
}
return currentNode;
}
* Class to be checked
* @param optional
* Original value
- * @return
+ * @return Optional object with type argument casted as cls
*/
private static <T> Optional<T> castOptional(final Class<T> cls, final Optional<?> optional) {
if (optional.isPresent()) {
return Optional.absent();
}
+ // FIXME: if rpc does not define input or output, this method creates it
/**
*
* Gets input / output container from {@link RpcDefinitionBuilder} if QName
* @return Optional of input/output if defined and QName is input/output.
* Otherwise {@link Optional#absent()}.
*/
- private static Optional<ContainerSchemaNodeBuilder> findContainerInRpc(final RpcDefinitionBuilder parent, final QName child) {
+ private static Optional<ContainerSchemaNodeBuilder> findContainerInRpc(final RpcDefinitionBuilder parent,
+ final QName child) {
if (INPUT.equals(child.getLocalName())) {
+ if (parent.getInput() == null) {
+ QName qname = QName.create(parent.getQName().getModule(), "input");
+ final ContainerSchemaNodeBuilder inputBuilder = new ContainerSchemaNodeBuilder(parent.getModuleName(),
+ parent.getLine(), qname, parent.getPath().createChild(qname));
+ inputBuilder.setParent(parent);
+ parent.setInput(inputBuilder);
+ return Optional.of(inputBuilder);
+ }
return Optional.of(parent.getInput());
} else if (OUTPUT.equals(child.getLocalName())) {
+ if (parent.getOutput() == null) {
+ QName qname = QName.create(parent.getQName().getModule(), "output");
+ final ContainerSchemaNodeBuilder outputBuilder = new ContainerSchemaNodeBuilder(parent.getModuleName(),
+ parent.getLine(), qname, parent.getPath().createChild(qname));
+ outputBuilder.setParent(parent);
+ parent.setOutput(outputBuilder);
+ return Optional.of(outputBuilder);
+ }
return Optional.of(parent.getOutput());
}
LOG.trace("Child {} not found in node {}", child, parent);
* Find augment target node and perform augmentation.
*
* @param augment
+ * augment builder to process
* @param firstNodeParent
* parent of first node in path
- * @param path
- * path to augment target
* @return true if augmentation process succeed, false otherwise
*/
public static boolean processAugmentation(final AugmentationSchemaBuilder augment,
firstNodeParent);
if (!potentialTargetNode.isPresent()) {
return false;
+ } else if (potentialTargetNode.get() instanceof UnknownSchemaNodeBuilder) {
+ LOG.warn("Error in augment parsing: unsupported augment target: {}", potentialTargetNode.get());
+ return true;
}
SchemaNodeBuilder targetNode = potentialTargetNode.get();
fillAugmentTarget(augment, targetNode);
public static Map<String, TreeMap<Date, URI>> createYangNamespaceContext(
final Collection<? extends ParseTree> modules, final Optional<SchemaContext> context) {
- Map<String, TreeMap<Date, URI>> map = new HashMap<>();
+ Map<String, TreeMap<Date, URI>> namespaceContext = new HashMap<>();
+ Set<Submodule_stmtContext> submodules = new HashSet<>();
+ // first read ParseTree collection and separate modules and submodules
for (ParseTree module : modules) {
for (int i = 0; i < module.getChildCount(); i++) {
ParseTree moduleTree = module.getChild(i);
- if (moduleTree instanceof Module_stmtContext) {
+ if (moduleTree instanceof Submodule_stmtContext) {
+ // put submodule context to separate collection
+ submodules.add((Submodule_stmtContext) moduleTree);
+ } else if (moduleTree instanceof Module_stmtContext) {
+ // get name, revision and namespace from module
Module_stmtContext moduleCtx = (Module_stmtContext) moduleTree;
final String moduleName = ParserListenerUtils.stringFromNode(moduleCtx);
Date rev = null;
}
}
}
- TreeMap<Date, URI> revToNs = map.get(moduleName);
+ // update namespaceContext
+ TreeMap<Date, URI> revToNs = namespaceContext.get(moduleName);
if (revToNs == null) {
revToNs = new TreeMap<>();
revToNs.put(rev, namespace);
- map.put(moduleName, revToNs);
+ namespaceContext.put(moduleName, revToNs);
}
revToNs.put(rev, namespace);
}
}
}
+ // after all ParseTree-s are parsed update namespaceContext with modules
+ // from SchemaContext
if (context.isPresent()) {
for (Module module : context.get().getModules()) {
- TreeMap<Date, URI> revToNs = map.get(module.getName());
+ TreeMap<Date, URI> revToNs = namespaceContext.get(module.getName());
if (revToNs == null) {
revToNs = new TreeMap<>();
revToNs.put(module.getRevision(), module.getNamespace());
- map.put(module.getName(), revToNs);
+ namespaceContext.put(module.getName(), revToNs);
}
revToNs.put(module.getRevision(), module.getNamespace());
}
}
- return map;
+ // when all modules are processed, traverse submodules and update
+ // namespaceContext with mapping for submodules
+ for (Submodule_stmtContext submodule : submodules) {
+ final String moduleName = ParserListenerUtils.stringFromNode(submodule);
+ for (int i = 0; i < submodule.getChildCount(); i++) {
+ ParseTree subHeaderCtx = submodule.getChild(i);
+ if (subHeaderCtx instanceof Submodule_header_stmtsContext) {
+ for (int j = 0; j < subHeaderCtx.getChildCount(); j++) {
+ ParseTree belongsCtx = subHeaderCtx.getChild(j);
+ if (belongsCtx instanceof Belongs_to_stmtContext) {
+ final String belongsTo = ParserListenerUtils.stringFromNode(belongsCtx);
+ TreeMap<Date, URI> ns = namespaceContext.get(belongsTo);
+ if (ns == null) {
+ throw new YangParseException(moduleName, submodule.getStart().getLine(), String.format(
+ "Unresolved belongs-to statement: %s", belongsTo));
+ }
+ // submodule get namespace and revision from module
+ TreeMap<Date, URI> subNs = new TreeMap<>();
+ subNs.put(ns.firstKey(), ns.firstEntry().getValue());
+ namespaceContext.put(moduleName, subNs);
+ }
+ }
+ }
+ }
+ }
+ return namespaceContext;
}
}