import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.locks.Lock;
import javassist.ClassPool;
import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
-
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
-
import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil;
import org.opendaylight.yangtools.binding.generator.util.BindingTypes;
import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl;
*/
private final static String AUGMENT_IDENTIFIER_NAME = "augment-identifier";
+ private final char NEW_LINE = '\n';
+
+ private final char TAB = '\t';
+
/**
* Resolves generated types from <code>context</code> schema nodes of all
* modules.
final String packageName = packageNameForGeneratedType(basePackageName, node.getPath());
final GeneratedTypeBuilder genType = addDefaultInterfaceDefinition(packageName, node, childOf);
genType.addComment(node.getDescription());
+ genType.setDescription(createDescription(node, genType.getFullyQualifiedName()));
+ genType.setModuleName(module.getName());
+ genType.setReference(node.getReference());
+ genType.setSchemaPath(node.getPath().getPathFromRoot());
if (node instanceof DataNodeContainer) {
genCtx.get(module).addChildNodeType(node, genType);
groupingsToGenTypes(module, ((DataNodeContainer) node).getGroupings());
addImplementedInterfaceFromUses(module, moduleDataTypeBuilder);
moduleDataTypeBuilder.addImplementsType(DATA_ROOT);
moduleDataTypeBuilder.addComment(module.getDescription());
+ moduleDataTypeBuilder.setDescription(createDescription(module));
+ moduleDataTypeBuilder.setReference(module.getReference());
return moduleDataTypeBuilder;
}
final String basePackageName = BindingMapping.getRootPackageName(module.getQNameModule());
final GeneratedTypeBuilder interfaceBuilder = moduleTypeBuilder(module, "Service");
interfaceBuilder.addImplementsType(Types.typeForClass(RpcService.class));
+ interfaceBuilder.setDescription(createDescription(rpcDefinitions, module.getName(), module.getModuleSourcePath()));
+
for (RpcDefinition rpc : rpcDefinitions) {
if (rpc != null) {
final String rpcName = BindingMapping.getClassName(rpc.getQName());
listenerInterface.addImplementsType(BindingTypes.NOTIFICATION_LISTENER);
final String basePackageName = BindingMapping.getRootPackageName(module.getQNameModule());
+
+
for (NotificationDefinition notification : notifications) {
if (notification != null) {
processUsesAugments(notification, module);
.setComment(notification.getDescription()).setReturnType(Types.VOID);
}
}
+ listenerInterface.setDescription(createDescription(notifications, module.getName(), module.getModuleSourcePath()));
genCtx.get(module).addTopLevelNodeType(listenerInterface);
}
}
newType.setAbstract(true);
newType.addComment(identity.getDescription());
- newType.setDescription(identity.getDescription());
+ newType.setDescription(createDescription(identity, newType.getFullyQualifiedName()));
newType.setReference(identity.getReference());
newType.setModuleName(module.getName());
+ SchemaPath path = identity.getPath();
newType.setSchemaPath(identity.getPath().getPathFromRoot());
final QName qname = identity.getQName();
final String moduleName = BindingMapping.getClassName(module.getName()) + postfix;
final GeneratedTypeBuilderImpl moduleBuilder = new GeneratedTypeBuilderImpl(packageName, moduleName);
- moduleBuilder.setDescription(module.getDescription());
+ moduleBuilder.setDescription(createDescription(module));
moduleBuilder.setReference(module.getReference());
moduleBuilder.setModuleName(moduleName);
// FIXME: Validation of name conflict
final GeneratedTypeBuilderImpl newType = new GeneratedTypeBuilderImpl(packageName, genTypeName);
+ final Module module = findParentModule(schemaContext, schemaNode);
qnameConstant(newType, BindingMapping.QNAME_STATIC_FIELD_NAME, schemaNode.getQName());
newType.addComment(schemaNode.getDescription());
- newType.setDescription(schemaNode.getDescription());
+ newType.setDescription(createDescription(schemaNode, newType.getFullyQualifiedName()));
newType.setReference(schemaNode.getReference());
newType.setSchemaPath(schemaNode.getPath().getPathFromRoot());
-
- final Module module = findParentModule(schemaContext, schemaNode);
newType.setModuleName(module.getName());
if (!genTypeBuilders.containsKey(packageName)) {
throw new IllegalStateException("Grouping " + usesNode.getGroupingPath() + "is not resolved for "
+ builder.getName());
}
+
builder.addImplementsType(genType);
- builder.addComment(genType.getComment());
+ /*
+ builder.addComment(genType.getDescription());
+ builder.setDescription(genType.getDescription());
+ builder.setModuleName(genType.getModuleName());
+ builder.setReference(genType.getReference());
+ builder.setSchemaPath(genType.getSchemaPath());
+ */
}
}
return builder;
}
+ private boolean isNullOrEmpty(final Collection<?> list) {
+ return (list == null || list.isEmpty() ? true : false);
+ }
+
+ private String createDescription(final Set<? extends SchemaNode> schemaNodes, final String moduleName, final String moduleSourcePath) {
+ final StringBuilder sb = new StringBuilder();
+ final String yangSnipet = YangTemplate.generateYangSnipet(schemaNodes);
+
+ if (!isNullOrEmpty(schemaNodes)) {
+ final SchemaNode node = schemaNodes.iterator().next();
+
+ if (node instanceof RpcDefinition) {
+ sb.append("Interface for implementing the following YANG RPCs defined in module <b>" + moduleName + "</b>");
+ }
+ else if (node instanceof NotificationDefinition) {
+ sb.append("Interface for receiving the following YANG notifications defined in module <b>" + moduleName + "</b>");
+ }
+ }
+ sb.append(NEW_LINE);
+ sb.append("<br />(Source path: <i>");
+ sb.append(moduleSourcePath);
+ sb.append("</i>):");
+ sb.append(NEW_LINE);
+ sb.append("<pre>");
+ sb.append(NEW_LINE);
+ sb.append(yangSnipet);
+ sb.append("</pre>");
+ sb.append(NEW_LINE);
+
+ return sb.toString();
+ }
+
+ private String createDescription(final SchemaNode schemaNode, final String fullyQualifiedName) {
+ final StringBuilder sb = new StringBuilder();
+ final Module module = findParentModule(schemaContext, schemaNode);
+ final String yangSnipet = YangTemplate.generateYangSnipet(schemaNode);
+ final String formattedDescription = YangTemplate.formatToParagraph(schemaNode.getDescription(), 0);
+ final StringBuilder linkToBuilderClass = new StringBuilder();
+ final StringBuilder linkToKeyClass = new StringBuilder();
+ final Splitter splitter = Splitter.on("\\.");
+ final String[] namespace = Iterables.toArray(splitter.split(fullyQualifiedName), String.class);
+ String className = namespace[namespace.length - 1];
+
+ if (hasBuilderClass(schemaNode)) {
+ linkToBuilderClass.append(className);
+ linkToBuilderClass.append("Builder");
+
+ if (schemaNode instanceof ListSchemaNode) {
+ linkToKeyClass.append(className);
+ linkToKeyClass.append("Key");
+ }
+ }
+
+ if (!isNullOrEmpty(formattedDescription)) {
+ sb.append(formattedDescription);
+ sb.append(NEW_LINE);
+ }
+ sb.append("<p>");
+ sb.append("This class represents the following YANG schema fragment defined in module <b>");
+ sb.append(module.getName());
+ sb.append("</b>");
+ sb.append(NEW_LINE);
+ sb.append("<br />(Source path: <i>");
+ sb.append(module.getModuleSourcePath());
+ sb.append("</i>):");
+ sb.append(NEW_LINE);
+ sb.append("<pre>");
+ sb.append(NEW_LINE);
+ sb.append(yangSnipet);
+ sb.append("</pre>");
+ sb.append(NEW_LINE);
+ sb.append("The schema path to identify an instance is");
+ sb.append(NEW_LINE);
+ sb.append("<i>");
+ sb.append(YangTemplate.formatSchemaPath(module.getName(), schemaNode.getPath().getPathFromRoot()));
+ sb.append("</i>");
+ sb.append(NEW_LINE);
+
+ if (hasBuilderClass(schemaNode)) {
+ sb.append(NEW_LINE);
+ sb.append("<p>To create instances of this class use " + "{@link " + linkToBuilderClass + "}.");
+ sb.append(NEW_LINE);
+ sb.append("@see ");
+ sb.append(linkToBuilderClass);
+ if (schemaNode instanceof ListSchemaNode) {
+ sb.append("@see ");
+ sb.append(linkToKeyClass);
+ }
+ sb.append(NEW_LINE);
+ }
+
+ return sb.toString();
+ }
+
+ private boolean hasBuilderClass(final SchemaNode schemaNode) {
+ if (schemaNode instanceof ContainerSchemaNode || schemaNode instanceof ListSchemaNode ||
+ schemaNode instanceof RpcDefinition || schemaNode instanceof NotificationDefinition)
+ return true;
+ return false;
+ }
+
+ private boolean isNullOrEmpty(final String string) {
+ return (string == null || string.isEmpty() ? true : false);
+ }
+
+ private String createDescription(final Module module) {
+ final StringBuilder sb = new StringBuilder();
+ final String yangSnipet = YangTemplate.generateYangSnipet(module);
+ final String formattedDescription = YangTemplate.formatToParagraph(module.getDescription(), 0);
+
+ if (!isNullOrEmpty(formattedDescription)) {
+ sb.append(formattedDescription);
+ sb.append(NEW_LINE);
+ }
+ sb.append("<p>");
+ sb.append("This class represents the following YANG schema fragment defined in module <b>");
+ sb.append(module.getName());
+ sb.append("</b>");
+ sb.append(NEW_LINE);
+ sb.append("<br />Source path: <i>");
+ sb.append(module.getModuleSourcePath());
+ sb.append("</i>):");
+ sb.append(NEW_LINE);
+ sb.append("<pre>");
+ sb.append(NEW_LINE);
+ sb.append(yangSnipet);
+ sb.append("</pre>");
+
+ return sb.toString();
+ }
+
private GeneratedTypeBuilder findChildNodeByPath(final SchemaPath path) {
for (ModuleContext ctx : genCtx.values()) {
GeneratedTypeBuilder result = ctx.getChildNode(path);
binding.setListener(registry);
// if (ctx !== null) {
- // listenerRegistration = ctx.registerService(SchemaServiceListener,
+ // listenerRegistration = ctx.registerService(SchemaContextListener,
// this, new Hashtable<String, String>());
// }
}
import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl
import org.opendaylight.yangtools.binding.generator.util.Types
import org.opendaylight.yangtools.sal.binding.generator.util.CodeGenerationException
+import org.opendaylight.yangtools.sal.binding.generator.util.SourceCodeGenerator
+import org.opendaylight.yangtools.sal.binding.generator.util.SourceCodeGeneratorFactory
import org.opendaylight.yangtools.sal.binding.generator.util.XtendHelper
import org.opendaylight.yangtools.sal.binding.model.api.Enumeration
import org.opendaylight.yangtools.sal.binding.model.api.GeneratedProperty
import org.opendaylight.yangtools.yang.binding.BindingCodec
import org.opendaylight.yangtools.yang.binding.BindingDeserializer
import org.opendaylight.yangtools.yang.binding.BindingMapping
-import org.opendaylight.yangtools.yang.binding.DataObject
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
import org.opendaylight.yangtools.yang.common.QName
import org.opendaylight.yangtools.yang.model.api.AugmentationSchema
import static org.opendaylight.yangtools.sal.binding.generator.impl.CodecMapping.*
import static extension org.opendaylight.yangtools.sal.binding.generator.util.YangSchemaUtils.*
-import java.util.ArrayList
-import org.opendaylight.yangtools.sal.binding.generator.util.DefaultSourceCodeGenerator
-import org.opendaylight.yangtools.sal.binding.generator.util.SourceCodeGeneratorFactory
-import org.opendaylight.yangtools.sal.binding.generator.util.SourceCodeGenerator
class TransformerGenerator extends AbstractTransformerGenerator {
private static val LOG = LoggerFactory.getLogger(TransformerGenerator)
--- /dev/null
+/*
+ * Copyright (c) 2014 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.generator.impl
+
+import java.text.SimpleDateFormat
+import java.util.Collection
+import java.util.Date
+import java.util.List
+import java.util.Map
+import java.util.Set
+import java.util.StringTokenizer
+import org.opendaylight.yangtools.yang.common.QName
+import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode
+import org.opendaylight.yangtools.yang.model.api.Deviation
+import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition
+import org.opendaylight.yangtools.yang.model.api.FeatureDefinition
+import org.opendaylight.yangtools.yang.model.api.GroupingDefinition
+import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
+import org.opendaylight.yangtools.yang.model.api.Module
+import org.opendaylight.yangtools.yang.model.api.ModuleImport
+import org.opendaylight.yangtools.yang.model.api.NotificationDefinition
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition
+import org.opendaylight.yangtools.yang.model.api.SchemaNode
+import org.opendaylight.yangtools.yang.model.api.SchemaPath
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition
+import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode
+import org.opendaylight.yangtools.yang.model.api.UsesNode
+import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition
+import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition.EnumPair
+
+class YangTemplate {
+
+ private static var Module module = null
+
+ def static String generateYangSnipet(SchemaNode schemaNode) {
+ if (schemaNode == null)
+ return ''
+
+ '''
+ «IF schemaNode instanceof DataSchemaNode»
+ «writeDataSchemaNode(schemaNode as DataSchemaNode)»
+ «ENDIF»
+ «IF schemaNode instanceof EnumTypeDefinition.EnumPair»
+ «writeEnumPair(schemaNode as EnumTypeDefinition.EnumPair)»
+ «ENDIF»
+ «IF schemaNode instanceof ExtensionDefinition»
+ «writeExtension(schemaNode as ExtensionDefinition)»
+ «ENDIF»
+ «IF schemaNode instanceof FeatureDefinition»
+ «writeFeature(schemaNode as FeatureDefinition)»
+ «ENDIF»
+ «IF schemaNode instanceof GroupingDefinition»
+ «writeGroupingDef(schemaNode as GroupingDefinition)»
+ «ENDIF»
+ «IF schemaNode instanceof IdentitySchemaNode»
+ «writeIdentity(schemaNode as IdentitySchemaNode)»
+ «ENDIF»
+ «IF schemaNode instanceof NotificationDefinition»
+ «writeNotification(schemaNode as NotificationDefinition)»
+ «ENDIF»
+ «IF schemaNode instanceof RpcDefinition»
+ «writeRPC(schemaNode as RpcDefinition)»
+ «ENDIF»
+ «IF schemaNode instanceof TypeDefinition<?>»
+ «writeTypeDefinition(schemaNode as TypeDefinition<?>)»
+ «ENDIF»
+ «IF schemaNode instanceof UnknownSchemaNode»
+ «writeUnknownSchemaNode(schemaNode as UnknownSchemaNode)»
+ «ENDIF»
+ '''
+ }
+
+ def static String generateYangSnipet(Set<? extends SchemaNode> nodes) {
+ if (nodes.nullOrEmpty)
+ return ''
+
+ '''
+ «FOR node : nodes»
+ «IF node instanceof NotificationDefinition»
+ «writeNotification(node as NotificationDefinition)»
+ «ELSEIF node instanceof RpcDefinition»
+ «writeRPC(node as RpcDefinition)»
+ «ENDIF»
+ «ENDFOR»
+ '''
+ }
+
+ def static writeEnumPair(EnumPair pair) {
+ var boolean hasEnumPairValue = pair.value != null
+ '''
+ enum «pair.name»«IF !hasEnumPairValue»;«ELSE»{
+ value «pair.value»;
+ }
+ «ENDIF»
+ '''
+ }
+
+ def static String writeModuleImports(Set<ModuleImport> moduleImports) {
+ if (moduleImports.nullOrEmpty)
+ return ''
+
+ '''
+ «FOR moduleImport : moduleImports SEPARATOR "\n"»
+ «IF moduleImport != null && !moduleImport.moduleName.nullOrEmpty»
+ import «moduleImport.moduleName» { prefix "«moduleImport.prefix»"; }
+ «ENDIF»
+ «ENDFOR»
+ '''
+ }
+
+ def static formatDate(Date moduleRevision) {
+ val SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-mm-dd")
+ return dateFormat.format(moduleRevision)
+ }
+
+ def static writeRevision(Date moduleRevision, String moduleDescription) {
+ val revisionIndent = 12
+
+ '''
+ revision «formatDate(moduleRevision)» {
+ description "«formatToParagraph(moduleDescription, revisionIndent)»";
+ }
+ '''
+ }
+
+ def static String generateYangSnipet(Module module) {
+
+ '''
+ module «module.name» {
+ yang-version «module.yangVersion»;
+ namespace "«module.QNameModule.namespace.toString»";
+ prefix "«module.prefix»";
+
+ «IF !module.imports.nullOrEmpty»
+ «writeModuleImports(module.imports)»
+ «ENDIF»
+ «IF module.revision != null»
+ «writeRevision(module.revision, module.description)»
+ «ENDIF»
+ «IF !module.childNodes.nullOrEmpty»
+
+ «writeDataSchemaNodes(module.childNodes)»
+ «ENDIF»
+ «IF !module.groupings.nullOrEmpty»
+
+ «writeGroupingDefs(module.groupings)»
+ «ENDIF»
+ «IF !module.augmentations.nullOrEmpty»
+
+ «writeAugments(module.augmentations)»
+ «ENDIF»
+ «IF !module.deviations.nullOrEmpty»
+
+ «writeDeviations(module.deviations)»
+ «ENDIF»
+ «IF !module.extensionSchemaNodes.nullOrEmpty»
+
+ «writeExtensions(module.extensionSchemaNodes)»
+ «ENDIF»
+ «IF !module.features.nullOrEmpty»
+
+ «writeFeatures(module.features)»
+ «ENDIF»
+ «IF !module.identities.nullOrEmpty»
+
+ «writeIdentities(module.identities)»
+ «ENDIF»
+ «IF !module.notifications.nullOrEmpty»
+
+ «writeNotifications(module.notifications)»
+ «ENDIF»
+ «IF !module.rpcs.nullOrEmpty»
+
+ «writeRPCs(module.rpcs)»
+ «ENDIF»
+ «IF !module.unknownSchemaNodes.nullOrEmpty»
+
+ «writeUnknownSchemaNodes(module.unknownSchemaNodes)»
+ «ENDIF»
+ «IF !module.uses.nullOrEmpty»
+
+ «writeUsesNodes(module.uses)»
+ «ENDIF»
+ }
+ '''
+ }
+
+ def static writeRPCs(Set<RpcDefinition> rpcDefs) {
+ '''
+ «FOR rpc : rpcDefs»
+ «IF rpc != null»
+ «writeRPC(rpc)»
+ «ENDIF»
+ «ENDFOR»
+ '''
+ }
+
+ def static writeRPC(RpcDefinition rpc) {
+ '''
+ rpc «rpc.QName.localName» {
+ «IF !rpc.description.nullOrEmpty»
+ "«rpc.description»";
+ «ENDIF»
+ «IF !rpc.groupings.nullOrEmpty»
+ «writeGroupingDefs(rpc.groupings)»
+ «ENDIF»
+ «IF rpc.input != null»
+ «writeRpcInput(rpc.input)»
+ «ENDIF»
+ «IF rpc.output != null»
+ «writeRpcOutput(rpc.output)»
+ «ENDIF»
+ «IF !rpc.reference.nullOrEmpty»
+ reference
+ "«rpc.reference»";
+ «ENDIF»
+ «IF rpc.status != null»
+ status «rpc.status»;
+ «ENDIF»
+ }
+ '''
+ }
+
+ def static writeRpcInput(ContainerSchemaNode input) {
+ if(input == null)
+ return ''
+
+ '''
+ input {
+ «IF input instanceof DataSchemaNode && !input.childNodes.nullOrEmpty»
+ «writeDataSchemaNodes(input.childNodes)»
+ «ENDIF»
+ }
+
+ '''
+ }
+
+ def static writeRpcOutput(ContainerSchemaNode output) {
+ if(output == null)
+ return ''
+
+ '''
+ output {
+ «IF output instanceof DataSchemaNode && !output.childNodes.nullOrEmpty»
+ «writeDataSchemaNodes(output.childNodes)»
+ «ENDIF»
+ }
+ '''
+ }
+
+ def static writeNotifications(Set<NotificationDefinition> notifications) {
+ '''
+ «FOR notification : notifications»
+ «IF notification != null»
+ «writeNotification(notification)»
+ «ENDIF»
+ «ENDFOR»
+ '''
+ }
+
+ def static writeNotification(NotificationDefinition notification) {
+ '''
+ notification «notification.QName.localName» {
+ «IF !notification.description.nullOrEmpty»
+ description
+ "«notification.description»";
+ «ENDIF»
+ «IF !notification.childNodes.nullOrEmpty»
+ «writeDataSchemaNodes(notification.childNodes)»
+ «ENDIF»
+ «IF !notification.availableAugmentations.nullOrEmpty»
+ «writeAugments(notification.availableAugmentations)»
+ «ENDIF»
+ «IF !notification.groupings.nullOrEmpty»
+ «writeGroupingDefs(notification.groupings)»
+ «ENDIF»
+ «IF !notification.uses.nullOrEmpty»
+ «writeUsesNodes(notification.uses)»
+ «ENDIF»
+ «IF !notification.reference.nullOrEmpty»
+ reference
+ "«notification.reference»";
+ «ENDIF»
+ «IF notification.status != null»
+ status «notification.status»;
+ «ENDIF»
+ }
+ '''
+ }
+
+ def static writeUnknownSchemaNodes(List<UnknownSchemaNode> unknownSchemaNodes) {
+ if (unknownSchemaNodes.nullOrEmpty)
+ return ''
+
+ '''
+ «FOR unknownSchemaNode : unknownSchemaNodes»
+ «writeUnknownSchemaNode(unknownSchemaNode)»
+ «ENDFOR»
+ '''
+ }
+
+ def static writeUnknownSchemaNode(UnknownSchemaNode unknownSchemaNode) {
+ if (unknownSchemaNode == null)
+ return ''
+
+ '''
+ anyxml «unknownSchemaNode.QName.localName» {
+ «IF !unknownSchemaNode.description.nullOrEmpty»
+ description
+ "«unknownSchemaNode.description»";
+ «ENDIF»
+ «IF !unknownSchemaNode.reference.nullOrEmpty»
+ reference
+ "«unknownSchemaNode.reference»";
+ «ENDIF»
+ «IF unknownSchemaNode.status != null»
+ status «unknownSchemaNode.status»;
+ «ENDIF»
+ }
+ '''
+ }
+
+ def static writeUsesNodes(Set<UsesNode> usesNodes) {
+ if (usesNodes == null) {
+ return ''
+ }
+
+ '''
+ «FOR usesNode : usesNodes»
+ «IF usesNode != null»
+ «writeUsesNode(usesNode)»
+ «ENDIF»
+ «ENDFOR»
+ '''
+ }
+
+ def static writeUsesNode(UsesNode usesNode) {
+ val hasRefines = !usesNode.refines.empty
+
+ '''
+ uses «usesNode.groupingPath.pathFromRoot.head.localName»«IF !hasRefines»;«ELSE» {«ENDIF»
+ «IF hasRefines»
+ «writeRefines(usesNode.refines)»
+ }
+ «ENDIF»
+ '''
+ }
+
+ def static writeRefines(Map<SchemaPath, SchemaNode> refines) {
+ '''
+ «FOR path : refines.keySet»
+ «val schemaNode = refines.get(path)»
+ «writeRefine(path, schemaNode)»
+ «ENDFOR»
+ '''
+ }
+
+ def static writeRefine(SchemaPath path, SchemaNode schemaNode) {
+ '''
+ refine «path.pathFromRoot.last» {
+ «IF schemaNode instanceof DataSchemaNode»
+ «writeDataSchemaNode(schemaNode as DataSchemaNode)»
+ «ENDIF»
+ }
+ '''
+ }
+
+ def static writeTypeDefinitions(Set<TypeDefinition<?>> typeDefinitions) {
+ '''
+ «FOR typeDefinition : typeDefinitions»
+ «IF typeDefinition != null»
+ «writeTypeDefinition(typeDefinition)»
+ «ENDIF»
+ «ENDFOR»
+ '''
+ }
+
+ def static writeTypeDefinition(TypeDefinition<?> typeDefinition) {
+ '''
+ type «typeDefinition.QName.localName»;
+ '''
+ }
+
+ def static writeIdentities(Set<IdentitySchemaNode> identities) {
+ if (identities.nullOrEmpty)
+ return ''
+ '''
+ «FOR identity : identities»
+ «writeIdentity(identity)»
+ «ENDFOR»
+ '''
+ }
+
+ def static writeIdentity(IdentitySchemaNode identity) {
+ if (identity == null)
+ return ''
+ '''
+ identity «identity.QName.localName» {
+ «IF identity.baseIdentity != null»
+ base "«writeIdentityPrefix(identity.baseIdentity)»«identity.baseIdentity»";
+ «ENDIF»
+ «IF !identity.description.nullOrEmpty»
+ description
+ "«identity.description»";
+ «ENDIF»
+ «IF !identity.reference.nullOrEmpty»
+ reference
+ "«identity.reference»";
+ «ENDIF»
+ «IF identity.status != null»
+ status «identity.status»;
+ «ENDIF»
+ }
+ '''
+ }
+
+ def static writeIdentityPrefix(IdentitySchemaNode identity) {
+ if(module == null)
+ return ''
+
+ if(identity.QName.prefix.nullOrEmpty || module.prefix.nullOrEmpty)
+ return ''
+
+ val identityPrefix = identity.QName.prefix
+
+ if(!module.prefix.equals(identity.QName.prefix))
+ return identityPrefix + ":"
+ return ''
+ }
+
+ def static writeFeatures(Set<FeatureDefinition> features) {
+ '''
+ «FOR feature : features»
+ «IF feature != null»
+ «writeFeature(feature)»
+ «ENDIF»
+ «ENDFOR»
+ '''
+ }
+
+ def static writeFeature(FeatureDefinition featureDef) {
+ '''
+ feature «featureDef.QName.localName» {
+ «IF !featureDef.description.nullOrEmpty»
+ description
+ "«featureDef.description»";
+ «ENDIF»
+ «IF !featureDef.reference.nullOrEmpty»
+ reference
+ "«featureDef.reference»";
+ «ENDIF»
+ «IF featureDef.status != null»
+ status «featureDef.status»;
+ «ENDIF»
+ }
+ '''
+ }
+
+ def static writeExtensions(List<ExtensionDefinition> extensions) {
+ '''
+ «FOR anExtension : extensions»
+ «IF anExtension != null»
+ «writeExtension(anExtension)»
+ «ENDIF»
+ «ENDFOR»
+ '''
+ }
+
+ def static writeExtension(ExtensionDefinition extensionDef) {
+ '''
+ extension «extensionDef.QName.localName» {
+ «IF !extensionDef.description.nullOrEmpty»
+ description
+ "«extensionDef.description»";
+ «ENDIF»
+ «IF !extensionDef.argument.nullOrEmpty»
+ argument "«extensionDef.argument»";
+ «ENDIF»
+ «IF !extensionDef.reference.nullOrEmpty»
+ reference
+ "«extensionDef.reference»";
+ «ENDIF»
+ «IF extensionDef.status != null»
+ status «extensionDef.status»;
+ «ENDIF»
+ }
+ '''
+ }
+
+ def static writeDeviations(Set<Deviation> deviations) {
+ '''
+ «FOR deviation : deviations»
+ «IF deviation != null»
+ «writeDeviation(deviation)»
+ «ENDIF»
+ «ENDFOR»
+ '''
+ }
+
+ def static writeDeviation(Deviation deviation) {
+ '''
+ deviation «deviation.targetPath» {
+ «IF !deviation.reference.nullOrEmpty»
+ reference
+ "«deviation.reference»";
+ «ENDIF»
+ «IF deviation.deviate != null && !deviation.deviate.name.nullOrEmpty»
+ deviation «deviation.deviate.name»;
+ «ENDIF»
+ }
+ '''
+ }
+
+ def static writeAugments(Set<AugmentationSchema> augments) {
+ '''
+ «FOR augment : augments»
+ «IF augment != null»
+ «writeAugment(augment)»
+ «ENDIF»
+ «ENDFOR»
+ '''
+ }
+
+ def static writeDataSchemaNodes(Collection<DataSchemaNode> dataSchemaNodes) {
+ '''
+ «FOR schemaNode : dataSchemaNodes»
+ «writeDataSchemaNode(schemaNode)»
+ «ENDFOR»
+ '''
+ }
+
+ def static CharSequence writeGroupingDefs(Set<GroupingDefinition> groupingDefs) {
+ '''
+ «FOR groupingDef : groupingDefs»
+ «IF groupingDef != null»
+ «writeGroupingDef(groupingDef)»
+ «ENDIF»
+ «ENDFOR»
+ '''
+ }
+
+ def static writeAugment(AugmentationSchema augment) {
+ '''
+ augment «formatToAugmentPath(augment.targetPath.pathFromRoot)» {
+ «IF augment.whenCondition != null && !augment.whenCondition.toString.nullOrEmpty»
+ when "«augment.whenCondition.toString»";
+ «ENDIF»
+ «IF !augment.description.nullOrEmpty»
+ description
+ "«augment.description»";
+ «ENDIF»
+ «IF !augment.reference.nullOrEmpty»
+ reference
+ "«augment.reference»";
+ «ENDIF»
+ «IF augment.status != null»
+ status «augment.status»;
+ «ENDIF»
+ «IF !augment.childNodes.nullOrEmpty»
+ «writeDataSchemaNodes(augment.childNodes)»
+ «ENDIF»
+ «IF !augment.uses.nullOrEmpty»
+ «writeUsesNodes(augment.uses)»
+ «ENDIF»
+ }
+ '''
+ }
+
+ def static writeGroupingDef(GroupingDefinition groupingDef) {
+ '''
+ grouping «groupingDef.QName.localName» {
+ «IF !groupingDef.groupings.nullOrEmpty»
+ «writeGroupingDefs(groupingDef.groupings)»
+ «ENDIF»
+ «IF !groupingDef.childNodes.nullOrEmpty»
+ «writeDataSchemaNodes(groupingDef.childNodes)»
+ «ENDIF»
+ «IF !groupingDef.unknownSchemaNodes.nullOrEmpty»
+ «writeUnknownSchemaNodes(groupingDef.unknownSchemaNodes)»
+ «ENDIF»
+ }
+ '''
+ }
+
+ def static writeContSchemaNode(ContainerSchemaNode contSchemaNode) {
+ '''
+ container «contSchemaNode.getQName.localName» {
+ «IF !contSchemaNode.childNodes.nullOrEmpty»
+ «writeDataSchemaNodes(contSchemaNode.childNodes)»
+ «ENDIF»
+ «IF !contSchemaNode.availableAugmentations.nullOrEmpty»
+ «writeAugments(contSchemaNode.availableAugmentations)»
+ «ENDIF»
+ «IF !contSchemaNode.groupings.nullOrEmpty»
+ «writeGroupingDefs(contSchemaNode.groupings)»
+ «ENDIF»
+ «IF !contSchemaNode.uses.nullOrEmpty»
+ «writeUsesNodes(contSchemaNode.uses)»
+ «ENDIF»
+ «IF !contSchemaNode.unknownSchemaNodes.nullOrEmpty»
+ «writeUnknownSchemaNodes(contSchemaNode.unknownSchemaNodes)»
+ «ENDIF»
+ }
+ '''
+ }
+
+ def static writeAnyXmlSchemaNode(AnyXmlSchemaNode anyXmlSchemaNode) {
+ '''
+ anyxml «anyXmlSchemaNode.getQName.localName»;
+ '''
+ }
+
+ def static writeLeafSchemaNode(LeafSchemaNode leafSchemaNode) {
+ '''
+ leaf «leafSchemaNode.getQName.localName» {
+ type «leafSchemaNode.type.getQName.localName»;
+ }
+ '''
+ }
+
+ def static writeLeafListSchemaNode(LeafListSchemaNode leafListSchemaNode) {
+ '''
+ leaf-list «leafListSchemaNode.getQName.localName» {
+ type «leafListSchemaNode.type.getQName.localName»;
+ }
+ '''
+ }
+
+ def static writeChoiceCaseNode(ChoiceCaseNode choiceCaseNode) {
+ '''
+ case «choiceCaseNode.getQName.localName» {
+ «FOR childNode : choiceCaseNode.childNodes»
+ «writeDataSchemaNode(childNode)»
+ «ENDFOR»
+ }
+ '''
+ }
+
+ def static writeChoiceNode(ChoiceNode choiceNode) {
+ '''
+ choice «choiceNode.getQName.localName» {
+ «FOR child : choiceNode.cases»
+ «writeDataSchemaNode(child)»
+ «ENDFOR»
+ }
+ '''
+ }
+
+ def static writeListSchemaNode(ListSchemaNode listSchemaNode) {
+ '''
+ list «listSchemaNode.getQName.localName» {
+ key «FOR listKey : listSchemaNode.keyDefinition SEPARATOR " "»"«listKey.localName»"
+ «ENDFOR»
+ «IF !listSchemaNode.childNodes.nullOrEmpty»
+ «writeDataSchemaNodes(listSchemaNode.childNodes)»
+ «ENDIF»
+ «IF !listSchemaNode.availableAugmentations.nullOrEmpty»
+ «writeAugments(listSchemaNode.availableAugmentations)»
+ «ENDIF»
+ «IF !listSchemaNode.groupings.nullOrEmpty»
+ «writeGroupingDefs(listSchemaNode.groupings)»
+ «ENDIF»
+ «IF !listSchemaNode.uses.nullOrEmpty»
+ «writeUsesNodes(listSchemaNode.uses)»
+ «ENDIF»
+ «IF !listSchemaNode.unknownSchemaNodes.nullOrEmpty»
+ «writeUnknownSchemaNodes(listSchemaNode.unknownSchemaNodes)»
+ «ENDIF»
+ }
+ '''
+ }
+
+ def static CharSequence writeDataSchemaNode(DataSchemaNode child) {
+ '''
+ «IF child instanceof ContainerSchemaNode»
+ «writeContSchemaNode(child as ContainerSchemaNode)»
+ «ENDIF»
+ «IF child instanceof AnyXmlSchemaNode»
+ «writeAnyXmlSchemaNode(child as AnyXmlSchemaNode)»
+ «ENDIF»
+ «IF child instanceof LeafSchemaNode»
+ «writeLeafSchemaNode(child as LeafSchemaNode)»
+ «ENDIF»
+ «IF child instanceof LeafListSchemaNode»
+ «writeLeafListSchemaNode(child as LeafListSchemaNode)»
+ «ENDIF»
+ «IF child instanceof ChoiceCaseNode»
+ «writeChoiceCaseNode(child as ChoiceCaseNode)»
+ «ENDIF»
+ «IF child instanceof ChoiceNode»
+ «writeChoiceNode(child as ChoiceNode)»
+ «ENDIF»
+ «IF child instanceof ListSchemaNode»
+ «writeListSchemaNode(child as ListSchemaNode)»
+ «ENDIF»
+ '''
+ }
+
+ static def String formatSchemaPath(String moduleName, Iterable<QName> schemaPath) {
+ var currentElement = schemaPath.head
+ val StringBuilder sb = new StringBuilder()
+ sb.append(moduleName)
+
+ for(pathElement : schemaPath) {
+ if(!currentElement.namespace.equals(pathElement.namespace)) {
+ currentElement = pathElement
+ sb.append('/')
+ sb.append(pathElement)
+ }
+ else {
+ sb.append('/')
+ sb.append(pathElement.localName)
+ }
+ }
+ return sb.toString
+ }
+
+ static def String formatToParagraph(String text, int nextLineIndent) {
+ if (text == null || text.isEmpty())
+ return '';
+
+ var String formattedText = text;
+ val StringBuilder sb = new StringBuilder();
+ val StringBuilder lineBuilder = new StringBuilder();
+ var boolean isFirstElementOnNewLineEmptyChar = false;
+ val lineIndent = computeNextLineIndent(nextLineIndent);
+
+ formattedText = formattedText.replace("*/", "*/");
+ formattedText = formattedText.replace("\n", "");
+ formattedText = formattedText.replace("\t", "");
+ formattedText = formattedText.replaceAll(" +", " ");
+
+ val StringTokenizer tokenizer = new StringTokenizer(formattedText, " ", true);
+
+ while (tokenizer.hasMoreElements()) {
+ val String nextElement = tokenizer.nextElement().toString();
+
+ if (lineBuilder.length() + nextElement.length() > 80) {
+ if (lineBuilder.charAt(lineBuilder.length() - 1) == ' ') {
+ lineBuilder.setLength(0);
+ lineBuilder.append(lineBuilder.substring(0, lineBuilder.length() - 1));
+ }
+ if (lineBuilder.charAt(0) == ' ') {
+ lineBuilder.setLength(0);
+ lineBuilder.append(lineBuilder.substring(1));
+ }
+
+ sb.append(lineBuilder);
+ lineBuilder.setLength(0);
+ sb.append("\n");
+
+ if (nextLineIndent > 0) {
+ sb.append(lineIndent)
+ }
+
+ if (nextElement.toString().equals(" "))
+ isFirstElementOnNewLineEmptyChar = !isFirstElementOnNewLineEmptyChar;
+ }
+ if (isFirstElementOnNewLineEmptyChar) {
+ isFirstElementOnNewLineEmptyChar = !isFirstElementOnNewLineEmptyChar;
+ } else {
+ lineBuilder.append(nextElement);
+ }
+ }
+ sb.append(lineBuilder);
+ sb.append("\n");
+
+ return sb.toString();
+ }
+
+ def private static formatToAugmentPath(Iterable<QName> schemaPath) {
+ val StringBuilder sb = new StringBuilder();
+
+ for(pathElement : schemaPath) {
+ val prefix = pathElement.prefix
+ val localName = pathElement.localName
+
+ sb.append("\\")
+ sb.append(prefix)
+ sb.append(":")
+ sb.append(localName)
+ }
+ return sb.toString
+ }
+
+ private static def computeNextLineIndent(int nextLineIndent) {
+ val StringBuilder sb = new StringBuilder()
+ var i = 0
+ while (i < nextLineIndent) {
+ sb.append(' ')
+ i = i + 1
+ }
+ return sb.toString
+ }
+}
}
def protected String formatDataForJavaDoc(GeneratedType type) {
- val typeDescription = type.description
- val typeReference = type.reference
- val typeModuleName = type.moduleName
- val typeSchemaPath = type.schemaPath
+ val typeDescription = type.getDescription();
return '''
- «IF !type.isDocumentationParametersNullOrEmtpy»
- «IF typeDescription != null && !typeDescription.empty»
- «formatToParagraph(typeDescription)»
- «ENDIF»
- «IF typeReference != null && !typeReference.empty»
- Reference:
- «formatReference(typeReference)»
- «ENDIF»
- «IF typeModuleName != null && !typeModuleName.empty»
- Module name:
- «typeModuleName»
- «ENDIF»
- «IF typeSchemaPath != null && !typeSchemaPath.empty»
- Schema path:
- «formatPath(typeSchemaPath)»
- «ENDIF»
+ «IF !typeDescription.nullOrEmpty»
+ «typeDescription»
«ENDIF»
'''.toString
}
- def formatPath(Iterable<QName> schemaPath) {
- var currentElement = schemaPath.head
- val StringBuilder sb = new StringBuilder()
- sb.append('[')
- sb.append(currentElement)
-
- for(pathElement : schemaPath) {
- if(!currentElement.namespace.equals(pathElement.namespace)) {
- currentElement = pathElement
- sb.append('/')
- sb.append(pathElement)
- }
- else {
- sb.append('/')
- sb.append(pathElement.localName)
- }
- }
- sb.append(']')
- return sb.toString
- }
-
- def formatReference(String reference) {
- if(reference == null || reference.isEmpty)
- return reference
-
- val StringTokenizer tokenizer = new StringTokenizer(reference, " ", true)
- val StringBuilder sb = new StringBuilder();
-
- while(tokenizer.hasMoreTokens) {
- var String oneElement = tokenizer.nextToken
- if (oneElement.contains("http://")) {
- oneElement = asLink(oneElement)
- }
- sb.append(oneElement)
- }
- return sb.toString
- }
-
def asLink(String text) {
val StringBuilder sb = new StringBuilder()
var tempText = text
}
def isDocumentationParametersNullOrEmtpy(GeneratedType type) {
- var boolean isNullOrEmpty = true
- val String typeDescription = type.description
- val String typeReference = type.reference
- val String typeModuleName = type.moduleName
- val Iterable<QName> typeSchemaPath = type.schemaPath
-
- if(typeDescription != null && !typeDescription.empty) {
- isNullOrEmpty = false
- return isNullOrEmpty
- }
- if(typeReference != null && !typeReference.empty) {
- isNullOrEmpty = false
- return isNullOrEmpty
- }
- if(typeModuleName != null && !typeModuleName.empty) {
- isNullOrEmpty = false
- return isNullOrEmpty
- }
- if(typeSchemaPath != null && !typeSchemaPath.empty) {
- isNullOrEmpty = false
- return isNullOrEmpty
+ val boolean isTypeDescriptionNullOrEmpty = type.description.nullOrEmpty
+ val boolean isTypeReferenceNullOrEmpty = type.reference.nullOrEmpty
+ val boolean isTypeModuleNameNullOrEmpty = type.moduleName.nullOrEmpty
+ val boolean isTypeSchemaPathNullOrEmpty = type.schemaPath.nullOrEmpty
+
+ if (isTypeDescriptionNullOrEmpty && isTypeReferenceNullOrEmpty && isTypeModuleNameNullOrEmpty
+ && isTypeSchemaPathNullOrEmpty) {
+ return true
}
- return isNullOrEmpty
+ return false
}
def generateRestrictions(Type type, String paramName, Type returnType) '''
return «type.importedName».class;
}
'''
+
+ private def createDescription(GeneratedType type) {
+ return '''
+ Class that builds {@link «type.importedName»} instances.
+
+ @see «type.importedName»
+ '''
+ }
+
+ override def protected String formatDataForJavaDoc(GeneratedType type) {
+ val typeDescription = createDescription(type)
+ return '''
+ «IF !typeDescription.nullOrEmpty»
+ «typeDescription»
+ «ENDIF»
+ '''.toString
+ }
}
import org.opendaylight.yangtools.sal.binding.model.api.GeneratedTransferObject
import java.beans.ConstructorProperties
import org.opendaylight.yangtools.sal.binding.model.api.Enumeration
+import static org.opendaylight.yangtools.binding.generator.util.Types.*
/**
* Template for generating JAVA class.
«ELSEIF propRet instanceof GeneratedTransferObject && (propRet as GeneratedTransferObject).unionType»
««« union type
this.«other.fieldName» = «property.fieldName».getValue();
+ «ELSEIF propRet instanceof GeneratedTransferObject // Is it a GeneratedTransferObject
+ && (propRet as GeneratedTransferObject).typedef // Is it a typedef
+ && (propRet as GeneratedTransferObject).properties != null
+ && !(propRet as GeneratedTransferObject).properties.empty
+ && ((propRet as GeneratedTransferObject).properties.size == 1)
+ && (propRet as GeneratedTransferObject).properties.get(0).name.equals("value")
+ && BOOLEAN.equals((propRet as GeneratedTransferObject).properties.get(0).returnType)» // And the property value is of type boolean
+ ««« generated boolean typedef
+ this.«other.fieldName» = «property.fieldName».isValue().toString().toCharArray();
«ELSE»
««« generated type
this.«other.fieldName» = «property.fieldName».getValue().toString().toCharArray();
private static final Logger LOG = LoggerFactory.getLogger(ReadOnlyTrieMap.class);
private final TrieMap<K, V> readWrite;
private final int size;
- private TrieMap<K, V> readOnly;
+ private volatile TrieMap<K, V> readOnly;
ReadOnlyTrieMap(final TrieMap<K, V> map, final int size) {
super();
@Override
protected Map<K, V> delegate() {
- if (readOnly == null) {
+ TrieMap<K, V> ret = readOnly;
+ if (ret == null) {
synchronized (this) {
- if (readOnly == null) {
- readOnly = readWrite.readOnlySnapshot();
+ ret = readOnly;
+ if (ret == null) {
+ ret = readWrite.readOnlySnapshot();
+ readOnly = ret;
}
}
}
- return readOnly;
+ return ret;
}
@Override
this.opName = Preconditions.checkNotNull(opName);
}
+ /**
+ * Return the exception class produced by this instance.
+ *
+ * @return Exception class.
+ */
+ protected final Class<X> getExceptionType() {
+ return exceptionType;
+ }
+
/**
* Invoked to create a new exception instance of the specified type.
*
--- /dev/null
+/*
+ * Copyright (c) 2014 Robert Varga. 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.util.concurrent;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * Convenience {@link ExceptionMapper} which instantiates specified Exception using
+ * reflection. The Exception types are expected to declare an accessible constructor
+ * which takes two arguments: a String and a Throwable.
+ *
+ * @param <X> Exception type
+ */
+public final class ReflectiveExceptionMapper<X extends Exception> extends ExceptionMapper<X> {
+ private final Constructor<X> ctor;
+
+ private ReflectiveExceptionMapper(final String opName, final Constructor<X> ctor) {
+ super(opName, ctor.getDeclaringClass());
+ this.ctor = ctor;
+ }
+
+ @Override
+ protected X newWithCause(final String message, final Throwable cause) {
+ try {
+ return ctor.newInstance(message, cause);
+ } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+ throw new IllegalStateException("Failed to instantiate exception " + ctor.getDeclaringClass(), e);
+ }
+ }
+
+ /**
+ * Create a new instance of the reflective exception mapper. This method performs basic
+ * sanity checking on the exception class. This method is potentially very costly, so
+ * users are strongly encouraged to cache the returned mapper for reuse.
+ *
+ * @param opName Operation performed
+ * @param exceptionType Exception type
+ * @return A new mapper instance
+ * @throws IllegalArgumentException when the supplied exception class does not pass sanity checks
+ * @throws SecurityException when the required constructor is not accessible
+ */
+ public static <X extends Exception> ReflectiveExceptionMapper<X> create(final String opName, final Class<X> exceptionType) throws SecurityException {
+ final Constructor<X> c;
+ try {
+ c = exceptionType.getConstructor(String.class, Throwable.class);
+ } catch (NoSuchMethodException e) {
+ throw new IllegalArgumentException("Class does not define a String, Throwable constructor", e);
+ }
+
+ try {
+ c.newInstance(opName, new Throwable());
+ } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+ throw new IllegalArgumentException("Constructor " + c.getName() + " failed to pass instantiation test", e);
+ }
+
+ return new ReflectiveExceptionMapper<>(opName, c);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Robert Varga. 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.util.concurrent;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.concurrent.ExecutionException;
+
+import org.junit.Test;
+
+public final class ReflectiveExceptionMapperTest {
+ static final class NoArgumentCtorException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ public NoArgumentCtorException() {
+ super();
+ }
+ }
+
+ static final class PrivateCtorException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ private PrivateCtorException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+ }
+
+ static final class FailingCtorException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ public FailingCtorException(final String message, final Throwable cause) {
+ throw new IllegalArgumentException("just for test");
+ }
+ }
+
+ static final class GoodException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ public GoodException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+ }
+
+
+ @Test(expected=IllegalArgumentException.class)
+ public void testNoArgumentsContructor() {
+ ReflectiveExceptionMapper.create("no arguments", NoArgumentCtorException.class);
+ }
+
+ @Test(expected=IllegalArgumentException.class)
+ public void testPrivateContructor() {
+ ReflectiveExceptionMapper.create("private constructor", PrivateCtorException.class);
+ }
+
+ @Test(expected=IllegalArgumentException.class)
+ public void testFailingContructor() {
+ ReflectiveExceptionMapper.create("failing constructor", FailingCtorException.class);
+ }
+
+ @Test
+ public void testInstantiation() {
+ ReflectiveExceptionMapper<GoodException> mapper = ReflectiveExceptionMapper.create("instantiation", GoodException.class);
+
+ final Throwable cause = new Throwable("some test message");
+
+ GoodException ret = mapper.apply(new ExecutionException("test", cause));
+
+ assertEquals("instantiation execution failed", ret.getMessage());
+ assertEquals(cause, ret.getCause());
+ }
+}
*/
package org.opendaylight.yangtools.websocket.server;
+import com.google.common.util.concurrent.SettableFuture;
+
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.net.SocketAddress;
import java.net.InetSocketAddress;
-
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
+import java.net.SocketAddress;
import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeoutException;
+import java.util.concurrent.Future;
-import com.google.common.util.concurrent.SettableFuture;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* A HTTP server which serves Web Socket requests at:
private static final Logger logger = LoggerFactory.getLogger(WebSocketServer.class.toString());
- public WebSocketServer(int inPort) {
+ public WebSocketServer(final int inPort) {
this.inPort = inPort;
port = SettableFuture.<Integer>create();
}
+ @Override
public void run(){
try {
startServer();
public void startServer() throws Exception {
try {
bootstrap.group(bossGroup, workerGroup)
- .channel(NioServerSocketChannel.class)
- .childHandler(new WebSocketServerInitializer());
+ .channel(NioServerSocketChannel.class)
+ .childHandler(new WebSocketServerInitializer());
Channel ch = bootstrap.bind(inPort).sync().channel();
SocketAddress localSocket = ch.localAddress();
* @param localName
* YANG schema identifier
*
+ * @deprecated Prefix storage in QNames is deprecated.
*/
+ @Deprecated
public QName(final URI namespace, final Date revision, final String prefix, final String localName) {
this(QNameModule.create(namespace, revision), prefix, localName);
}
* Returns locally defined prefix assigned to local name
*
* @return locally defined prefix assigned to local name
+ *
+ * @deprecated Prefix storage in QNames is deprecated.
*/
+ @Deprecated
public String getPrefix() {
return prefix;
}
* @param localName
* Local name part of QName. MUST NOT BE null.
* @return Instance of QName
+ *
+ * @deprecated Prefix storage in QNames is deprecated.
*/
+ @Deprecated
public static QName create(final QNameModule module, final String prefix, final String localName) {
if (module == null) {
throw new NullPointerException("module may not be null");
}
final TypeDefinition<?> baseType = XmlUtils.resolveBaseTypeFrom(schema.getType());
- if (baseType instanceof org.opendaylight.yangtools.yang.model.util.InstanceIdentifier) {
+ if (baseType instanceof org.opendaylight.yangtools.yang.model.util.InstanceIdentifierType) {
value = InstanceIdentifierForXmlCodec.deserialize(xmlElement,schemaCtx);
} else if(baseType instanceof IdentityrefTypeDefinition){
value = InstanceIdentifierForXmlCodec.toIdentity(xmlElement.getTextContent(), xmlElement, schemaCtx);
if (codec != null) {
value = codec.deserialize(text);
}
- if (schema.getType() instanceof org.opendaylight.yangtools.yang.model.util.InstanceIdentifier) {
+ if (schema.getType() instanceof org.opendaylight.yangtools.yang.model.util.InstanceIdentifierType) {
value = InstanceIdentifierForXmlCodec.deserialize(xmlElement,schemaCtx);
}
if (value == null) {
import com.google.common.base.Preconditions;
import java.net.URI;
-import java.util.Map;
import java.util.Map.Entry;
import javax.annotation.Nonnull;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.AttributesContainer;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.Node;
import org.opendaylight.yangtools.yang.data.api.SimpleNode;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec;
import org.opendaylight.yangtools.yang.data.impl.schema.SchemaUtils;
import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
}
writer.writeStartElement(pfx, qname.getLocalName(), ns);
+ writeValue(writer, data, schema);
+ writer.writeEndElement();
+ }
+
+ /**
+ * Write a value into a XML stream writer. This method assumes the start and end of element is
+ * emitted by the caller.
+ *
+ * @param writer XML Stream writer
+ * @param data data node
+ * @param schema Schema node
+ * @throws XMLStreamException if an encoding problem occurs
+ */
+ public void writeValue(final XMLStreamWriter writer, final @Nonnull Node<?> data, final SchemaNode schema) throws XMLStreamException {
if (data instanceof AttributesContainer && ((AttributesContainer) data).getAttributes() != null) {
RandomPrefix randomPrefix = new RandomPrefix();
for (Entry<QName, String> attribute : ((AttributesContainer) data).getAttributes().entrySet()) {
writeElement(writer, child, childSchema);
}
}
-
- writer.writeEndElement();
}
@VisibleForTesting
* emitted by the caller.
*
* @param writer XML Stream writer
- * @param data data node
- * @param schema Schema node
+ * @param type data type
+ * @param value data value
* @throws XMLStreamException if an encoding problem occurs
*/
public void writeValue(final @Nonnull XMLStreamWriter writer, final @Nonnull TypeDefinition<?> type, final Object value) throws XMLStreamException {
*/
package org.opendaylight.yangtools.yang.data.impl.schema.tree;
+import com.google.common.base.Optional;
+
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.TreeNode;
import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.Version;
-import com.google.common.base.Optional;
-
-public abstract class RootModificationApplyOperation implements ModificationApplyOperation {
+/**
+ * Represents a {@link ModificationApplyOperation} which is rooted at conceptual
+ * top of data tree.
+ *
+ * <p>
+ * This implementation differs from other implementations in this package that
+ * is not immutable, but may be upgraded to newer state if available by
+ * explicitly invoking {@link #upgradeIfPossible()} and also serves as factory
+ * for deriving snapshot {@link RootModificationApplyOperation} which will not
+ * be affected by upgrade of original one.
+ *
+ * <p>
+ * There are two variations of this {@link ModificationApplyOperation}:
+ * <ul>
+ * <li>
+ * <b>Upgradable</b> - operation may be upgraded to different backing
+ * implementation by invoking {@link #upgradeIfPossible()}.</li>
+ * <li><b>Not Upgradable</b> - operation is immutable, invocation of
+ * {@link #upgradeIfPossible()} is no-op and method {@link #snapshot()} returns
+ * pointer on same object.
+ *
+ * <h3>Upgradable Root Modification Operation</h3>
+ *
+ * Upgradable Root Modification Operation may be created using:
+ * <ul>
+ * <li> {@link #from(ModificationApplyOperation)} with other upgradable root
+ * modification as an argument
+ * <li>using factory {@link LatestOperationHolder} which instantiates Upgradable
+ * Root Modification Operations and provides an option to set latest
+ * implementation.
+ * </ul>
+ * <p>
+ * Upgradable root operation is never upgraded to latest operation
+ * automatically, but client code must explicitly invoke
+ * {@link #upgradeIfPossible()} to get latest implementation.
+ *
+ * Note: This is helpful for implementing
+ * {@link org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification}
+ * which may be derived from
+ * {@link org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree} before
+ * update of schema and user actually writes data after schema update. During
+ * update user did not invoked any operation.
+ *
+ */
+abstract class RootModificationApplyOperation implements ModificationApplyOperation {
@Override
public Optional<ModificationApplyOperation> getChild(final PathArgument child) {
}
@Override
- public final Optional<TreeNode> apply(final ModifiedNode modification, final Optional<TreeNode> currentMeta, final Version version) {
+ public final Optional<TreeNode> apply(final ModifiedNode modification, final Optional<TreeNode> currentMeta,
+ final Version version) {
return getDelegate().apply(modification, currentMeta, version);
}
getDelegate().verifyStructure(modification);
}
+ /**
+ * Return the underlying delegate.
+ *
+ * @return Underlying delegate.
+ */
abstract ModificationApplyOperation getDelegate();
+ /**
+ * Creates a snapshot from this modification, which may have separate
+ * upgrade lifecycle and is not affected by upgrades
+ * <p>
+ * Newly created snapshot uses backing implementation of this modi
+ *
+ * @return Derived {@link RootModificationApplyOperation} with separate
+ * upgrade lifecycle.
+ */
public abstract RootModificationApplyOperation snapshot();
+ /**
+ * Upgrades backing implementation to latest available, if possible.
+ * <p>
+ * Latest implementation of {@link RootModificationApplyOperation} is
+ * managed by {@link LatestOperationHolder} which was used to construct this
+ * operation and latest operation is updated by
+ * {@link LatestOperationHolder#setCurrent(ModificationApplyOperation)}.
+ */
public abstract void upgradeIfPossible();
-
-
public static RootModificationApplyOperation from(final ModificationApplyOperation resolver) {
- if(resolver instanceof RootModificationApplyOperation) {
+ if (resolver instanceof RootModificationApplyOperation) {
return ((RootModificationApplyOperation) resolver).snapshot();
}
return new NotUpgradable(resolver);
}
+ /**
+ * Implementation of Upgradable {@link RootModificationApplyOperation}
+ *
+ * This implementation is associated with {@link LatestOperationHolder}
+ * which holds latest available implementation, which may be used for
+ * upgrade.
+ *
+ * Upgrading {@link LatestOperationHolder} will not affect any instance,
+ * unless client invoked {@link #upgradeIfPossible()} which will result in
+ * changing delegate to the latest one.
+ *
+ */
private static final class Upgradable extends RootModificationApplyOperation {
private final LatestOperationHolder holder;
private ModificationApplyOperation delegate;
-
public Upgradable(final LatestOperationHolder holder, final ModificationApplyOperation delegate) {
this.holder = holder;
this.delegate = delegate;
@Override
public void upgradeIfPossible() {
ModificationApplyOperation holderCurrent = holder.getCurrent();
- if(holderCurrent != delegate) {
- // FIXME: Allow update only if there is addition of models, not removals.
+ if (holderCurrent != delegate) {
+ // FIXME: Allow update only if there is addition of models, not
+ // removals.
delegate = holderCurrent;
}
@Override
public RootModificationApplyOperation snapshot() {
- return new Upgradable(holder,getDelegate());
+ return new Upgradable(holder, getDelegate());
}
}
}
}
- public static class LatestOperationHolder {
+ /**
+ * Holder and factory for upgradable root modifications
+ *
+ * This class is factory for upgradable root modifications and provides an
+ * access to set latest backing implementation.
+ *
+ */
+ static class LatestOperationHolder {
private ModificationApplyOperation current = new AlwaysFailOperation();
+ /**
+ * Return latest backing implemenation
+ *
+ * @return
+ */
public ModificationApplyOperation getCurrent() {
return current;
}
+ /**
+ * Sets latest backing implementation of associated
+ * {@link RootModificationApplyOperation}.
+ * <p>
+ * Note: This does not result in upgrading implementation of already
+ * existing {@link RootModificationApplyOperation}. Users, which
+ * obtained instances using {@link #newSnapshot()}, deriving
+ * {@link RootModificationApplyOperation} from this modification must
+ * explicitly invoke
+ * {@link RootModificationApplyOperation#upgradeIfPossible()} on their
+ * instance to be updated to latest backing implementation.
+ *
+ * @param newApplyOper
+ * New backing implementation
+ */
public void setCurrent(final ModificationApplyOperation newApplyOper) {
current = newApplyOper;
}
+ /**
+ *
+ * Creates new upgradable {@link RootModificationApplyOperation}
+ * associated with holder.
+ *
+ * @return New upgradable {@link RootModificationApplyOperation} with
+ * {@link #getCurrent()} used as backing implementation.
+ */
public RootModificationApplyOperation newSnapshot() {
- return new Upgradable(this,current);
+ return new Upgradable(this, current);
}
}
*/
package org.opendaylight.yangtools.yang.model.api;
-public interface SchemaContextListener extends SchemaServiceListener {
- @Override
+import java.util.EventListener;
+
+/**
+ * Interface for listeners interested in updates of the global schema context.
+ * The global schema context reflects the global view of the model world, and
+ * all entities interacting at the global scale need to maintain a consistent
+ * view of that world.
+ */
+public interface SchemaContextListener extends EventListener {
+ /**
+ * The global schema context is being updated.
+ * @param context New global schema context
+ */
void onGlobalContextUpdated(SchemaContext context);
}
+++ /dev/null
-/*
- * Copyright (c) 2014 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/eplv10.html
- */
-package org.opendaylight.yangtools.yang.model.repo.api;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableList.Builder;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-
-/**
- * A {@link SchemaSourceFilter} which accepts any schema source it is presented with.
- */
-public final class AcceptingSchemaSourceFilter implements SchemaSourceFilter {
- private static final AcceptingSchemaSourceFilter INSTANCE = new AcceptingSchemaSourceFilter();
-
- private final Iterable<Class<? extends SchemaSourceRepresentation>> representations;
-
- private AcceptingSchemaSourceFilter() {
- final Builder<Class<? extends SchemaSourceRepresentation>> b = ImmutableList.builder();
- b.add(SchemaSourceRepresentation.class);
- representations = b.build();
- }
-
- /**
- * Return the singleton instance of this filter.
- *
- * @return Singleton shared instance.
- */
- public static final AcceptingSchemaSourceFilter getSingletonInstance() {
- return INSTANCE;
- }
-
- @Override
- public Iterable<Class<? extends SchemaSourceRepresentation>> supportedRepresentations() {
- return representations;
- }
-
- @Override
- public ListenableFuture<Boolean> apply(final SchemaSourceRepresentation schemaSource) {
- return Futures.immediateFuture(Boolean.TRUE);
- }
-}
--- /dev/null
+/*
+ * Copyright (c) 2014 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/eplv10.html
+ */
+package org.opendaylight.yangtools.yang.model.repo.api;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * Exception thrown when a the specified schema source is not available.
+ */
+@Beta
+public class MissingSchemaSourceException extends SchemaSourceException {
+ private static final long serialVersionUID = 1L;
+
+ public MissingSchemaSourceException(final String message) {
+ super(message);
+ }
+
+ public MissingSchemaSourceException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+}
*/
package org.opendaylight.yangtools.yang.model.repo.api;
+import com.google.common.annotations.Beta;
import com.google.common.util.concurrent.CheckedFuture;
import java.util.Collection;
* based on a specification of what {@link SourceIdentifier}s are required
* and dynamic recursive resolution.
*/
+@Beta
public interface SchemaContextFactory {
/**
* Create a new schema context containing specified sources, pulling in
*/
package org.opendaylight.yangtools.yang.model.repo.api;
+import com.google.common.annotations.Beta;
+import com.google.common.util.concurrent.CheckedFuture;
+
import javax.annotation.Nonnull;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
* Interface exposed by repository implementations. A schema repository is a logically
* centralized place for model storage and creation of {@link SchemaContext} instances.
*/
+@Beta
public interface SchemaRepository {
/**
* Instantiate a new {@link SchemaContextFactory}, which will filter available schema
* @return A new schema context factory.
*/
SchemaContextFactory createSchemaContextFactory(@Nonnull SchemaSourceFilter filter);
+
+ <T extends SchemaSourceRepresentation> CheckedFuture<T, SchemaSourceException> getSchemaSource(@Nonnull SourceIdentifier id, @Nonnull Class<T> represetation);
}
*/
package org.opendaylight.yangtools.yang.model.repo.api;
+import com.google.common.annotations.Beta;
import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.Multimap;
-import java.util.Map;
+import java.util.Collection;
+import java.util.Collections;
import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.model.api.ModuleImport;
+
/**
* Exception thrown when a Schema Source fails to resolve.
*/
-public class SchemaResolutionException extends Exception {
+@Beta
+public class SchemaResolutionException extends SchemaSourceException {
private static final long serialVersionUID = 1L;
- private final Map<SourceIdentifier, Throwable> unresolvedSources;
+ private final Multimap<SourceIdentifier, ModuleImport> unsatisfiedImports;
+ private final Collection<SourceIdentifier> resolvedSources;
public SchemaResolutionException(final @Nonnull String message) {
this(message, (Throwable)null);
}
public SchemaResolutionException(final @Nonnull String message, final Throwable cause) {
- this(message, cause, ImmutableMap.<SourceIdentifier, Exception>of());
+ this(message, cause, Collections.<SourceIdentifier>emptySet(), ImmutableMultimap.<SourceIdentifier, ModuleImport>of());
}
- public SchemaResolutionException(final @Nonnull String message, final @Nonnull Map<SourceIdentifier, ? extends Throwable> unresolvedSources) {
- super(Preconditions.checkNotNull(message));
- this.unresolvedSources = ImmutableMap.copyOf(unresolvedSources);
+ public SchemaResolutionException(final @Nonnull String message, final Collection<SourceIdentifier> resolvedSources,
+ final @Nonnull Multimap<SourceIdentifier, ModuleImport> unsatisfiedImports) {
+ this(message, null, Collections.<SourceIdentifier>emptySet(), unsatisfiedImports);
}
- public SchemaResolutionException(final @Nonnull String message, final Throwable cause, @Nonnull final Map<SourceIdentifier, ? extends Throwable> unresolvedSources) {
+ public SchemaResolutionException(final @Nonnull String message, final Throwable cause,
+ @Nonnull final Collection<SourceIdentifier> resolvedSources,
+ @Nonnull final Multimap<SourceIdentifier, ModuleImport> unsatisfiedImports) {
super(message, cause);
- this.unresolvedSources = ImmutableMap.copyOf(unresolvedSources);
+ this.unsatisfiedImports = ImmutableMultimap.copyOf(unsatisfiedImports);
+ this.resolvedSources = ImmutableList.copyOf(resolvedSources);
}
/**
*
* @return Source/reason map.
*/
- public final Map<SourceIdentifier, Throwable> getUnresolvedSources() {
- return unresolvedSources;
+ public final Multimap<SourceIdentifier, ModuleImport> getUnsatisfiedImports() {
+ return unsatisfiedImports;
+ }
+
+
+ // FIXME: should be leak actual mapping?
+ public final Collection<SourceIdentifier> getResolvedSources() {
+ return resolvedSources;
}
@Override
public final String toString() {
- return addToStringAttributes(Objects.toStringHelper(this).add("unresolvedSources", unresolvedSources)).toString();
+ return addToStringAttributes(Objects.toStringHelper(this).add("unsatisfiedImports", unsatisfiedImports)).toString();
}
protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/eplv10.html
*/
-package org.opendaylight.yangtools.yang.model.repo.spi;
+package org.opendaylight.yangtools.yang.model.repo.api;
+
+import com.google.common.annotations.Beta;
/**
- * Exception thrown when a failure to translate a schema source between
- * representations.
+ * Exception thrown when a failure to acquire a schema source occurs.
*/
-public class SchemaSourceTransformationException extends Exception {
+@Beta
+public class SchemaSourceException extends Exception {
private static final long serialVersionUID = 1L;
- public SchemaSourceTransformationException(final String message) {
+ public SchemaSourceException(final String message) {
super(message);
}
- public SchemaSourceTransformationException(final String message, final Throwable cause) {
+ public SchemaSourceException(final String message, final Throwable cause) {
super(message, cause);
}
}
*/
package org.opendaylight.yangtools.yang.model.repo.api;
+import com.google.common.annotations.Beta;
+import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
+import java.util.Collections;
+
+/*
+ * A filter of schema sources. This is used to restrict which sources representation
+ * instances are allowed to participate in construction of a schema context. This
+ * allows, for example, to create an non-shared island, or require the sources to
+ * be certified before use.
+ */
+@Beta
public interface SchemaSourceFilter {
+ /**
+ * A {@link SchemaSourceFilter} which accepts any schema source it is presented with.
+ */
+ public static final SchemaSourceFilter ALWAYS_ACCEPT = new SchemaSourceFilter() {
+ private final Iterable<Class<? extends SchemaSourceRepresentation>> REPRESENTATIONS =
+ Collections.<Class<? extends SchemaSourceRepresentation>>singletonList(SchemaSourceRepresentation.class);
+
+ @Override
+ public Iterable<Class<? extends SchemaSourceRepresentation>> supportedRepresentations() {
+ return REPRESENTATIONS;
+ }
+
+ @Override
+ public ListenableFuture<Boolean> apply(final SchemaSourceRepresentation schemaSource) {
+ return Futures.immediateFuture(Boolean.TRUE);
+ }
+ };
+
+ /**
+ * Get the representations this filter supports. A schema source is translated
+ * into one of these representations before it is presented for filtering.
+ *
+ * @return Set of supported representations.
+ */
Iterable<Class<? extends SchemaSourceRepresentation>> supportedRepresentations();
+
+ /**
+ * Check if a particular schema source is acceptable to the filter. The process
+ * of checking may be asynchronous, but at some point it needs to produce an
+ * affirmative or negative answer before the schema context construction can
+ * proceed.
+ *
+ * @param schemaSource Schema source to be filtered
+ * @return Promise of a filtering decision. The result should be {@link Boolean#TRUE}
+ * if the source is acceptable.
+ */
ListenableFuture<Boolean> apply(SchemaSourceRepresentation schemaSource);
}
*/
package org.opendaylight.yangtools.yang.model.repo.api;
+import com.google.common.annotations.Beta;
+
import org.opendaylight.yangtools.concepts.Identifiable;
import org.opendaylight.yangtools.concepts.Immutable;
* Implementations of this interface expected to comply with the {@link Immutable}
* contract.
*/
+@Beta
public interface SchemaSourceRepresentation extends Identifiable<SourceIdentifier>, Immutable {
/**
* {@inheritDoc}
*/
package org.opendaylight.yangtools.yang.model.repo.api;
+import com.google.common.annotations.Beta;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import org.opendaylight.yangtools.concepts.Immutable;
/**
- *
* YANG Schema source identifier
*
* Simple transfer object represents identifier of source for YANG schema (module or submodule),
* <p>
* (For further reference see: http://tools.ietf.org/html/rfc6020#section-5.2 and
* http://tools.ietf.org/html/rfc6022#section-3.1 ).
- *
- *
*/
+@Beta
public final class SourceIdentifier implements Identifier, Immutable {
private static final long serialVersionUID = 1L;
private final String revision;
*/
package org.opendaylight.yangtools.yang.model.repo.api;
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.common.annotations.Beta;
import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper;
+import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.io.ByteSource;
* YANG text schema source representation. Exposes an RFC6020 text representation
* as an {@link InputStream}.
*/
+@Beta
public abstract class YangTextSchemaSource extends ByteSource implements SchemaSourceRepresentation {
private final SourceIdentifier identifier;
this.identifier = Preconditions.checkNotNull(identifier);
}
+ public static SourceIdentifier identifierFromFilename(final String name) {
+ checkArgument(name.endsWith(".yang"), "Filename %s does not have a .yang extension", name);
+ // FIXME: add revision-awareness
+ return SourceIdentifier.create(name.substring(0, name.length() - 5), Optional.<String>absent());
+ }
+
/**
* {@inheritDoc}
*/
*/
package org.opendaylight.yangtools.yang.model.repo.api;
+import com.google.common.annotations.Beta;
+
import org.w3c.dom.Document;
/**
* Yin schema source representation. Exposes an RFC6020 YIN XML representation
* as an W3C {@link Document}.
*/
+@Beta
public interface YinSchemaSource extends SchemaSourceRepresentation {
/**
* {@inheritDoc}
--- /dev/null
+/*
+ * Copyright (c) 2014 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/eplv10.html
+ */
+package org.opendaylight.yangtools.yang.model.repo.spi;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
+import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+
+/**
+ * A potential schema source. Instances of this class track the various
+ * representations of a schema source and the cost attached to obtaining
+ * the source from them.
+ */
+@Beta
+public final class PotentialSchemaSource<T extends SchemaSourceRepresentation> {
+ /**
+ * Each registered source has a cost associated with it. Since a particular
+ * representation can be acquired by various means, here are general constants
+ * for common cases.
+ */
+ public enum Costs {
+ /**
+ * The source is immediately available, via a lookup or similar.
+ */
+ IMMEDIATE(0),
+ /**
+ * The source is available via a computation. For transformation-type
+ * computation, the cost of acquiring the cost needs to be added, too.
+ */
+ COMPUTATION(1),
+ /**
+ * The source is available by performing local IO, such that reading
+ * from a disk.
+ */
+ LOCAL_IO(4),
+ /**
+ * The source is available by performing remote IO, such as fetching
+ * from an HTTP server or similar.
+ */
+ REMOTE_IO(8);
+
+ private final int value;
+
+ private Costs(final int value) {
+ this.value = value;
+ }
+
+ /**
+ * The the cost value.
+ *
+ * @return Const constant.
+ */
+ public int getValue() {
+ return value;
+ }
+ }
+
+ private final Class<? extends T> representation;
+ private final SourceIdentifier sourceIdentifier;
+ private final int cost;
+
+ private PotentialSchemaSource(final SourceIdentifier sourceIdentifier, final Class<? extends T> representation, final int cost) {
+ this.representation = Preconditions.checkNotNull(representation);
+ this.sourceIdentifier = Preconditions.checkNotNull(sourceIdentifier);
+ Preconditions.checkArgument(cost >= 0, "cost has to be non-negative");
+ this.cost = cost;
+ }
+
+ public static final <T extends SchemaSourceRepresentation> PotentialSchemaSource<T> create(final SourceIdentifier sourceIdentifier, final Class<? extends T> representation, final int cost) {
+ return new PotentialSchemaSource<>(sourceIdentifier, representation, cost);
+ }
+
+ public SourceIdentifier getSourceIdentifier() {
+ return sourceIdentifier;
+ }
+
+ public Class<? extends T> getRepresentation() {
+ return representation;
+ }
+
+ public int getCost() {
+ return cost;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + cost;
+ result = prime * result + representation.hashCode();
+ result = prime * result + sourceIdentifier.hashCode();
+ return result;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof PotentialSchemaSource)) {
+ return false;
+ }
+ final PotentialSchemaSource<?> other = (PotentialSchemaSource<?>) obj;
+ if (cost != other.cost) {
+ return false;
+ }
+ if (!representation.equals(other.representation)) {
+ return false;
+ }
+ if (!sourceIdentifier.equals(other.sourceIdentifier)) {
+ return false;
+ }
+ return true;
+ }
+}
*/
package org.opendaylight.yangtools.yang.model.repo.spi;
-import org.opendaylight.yangtools.concepts.ObjectRegistration;
+import com.google.common.annotations.Beta;
+
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+
+/**
+ * Registration of a SchemaSourceListener.
+ */
+@Beta
+public interface SchemaListenerRegistration extends ListenerRegistration<SchemaSourceListener> {
-public interface SchemaTransformerRegistration extends ObjectRegistration<SchemaSourceTransformer<?, ?>> {
- @Override
- void close();
}
--- /dev/null
+/*
+ * Copyright (c) 2014 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/eplv10.html
+ */
+package org.opendaylight.yangtools.yang.model.repo.spi;
+
+import com.google.common.annotations.Beta;
+
+import java.util.EventListener;
+
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
+
+/**
+ * Listener for schema source lifecycle events.
+ */
+@Beta
+public interface SchemaSourceListener extends EventListener {
+ /**
+ * Invoked when the registry sees a concrete source. This callback is typically
+ * used by cache-type listeners, who intercept the source, store it locally and
+ * announce themselves as a provider of that particular schema source.
+ *
+ * @param source Schema source
+ */
+ void schemaSourceEncountered(SchemaSourceRepresentation source);
+
+ /**
+ * Invoked when a new schema source is registered by a provider. This call
+ * callback, along with {@link #schemaSourceUnregistered(PotentialSchemaSource)}
+ * is typically used by transformer-type listeners, who intercept the registration
+ * if the advertised representation matches their input type and register
+ * themselves as a potential provider of the same source in their output
+ * representation type.
+ *
+ * @param sources Newly available sources
+ */
+ void schemaSourceRegistered(Iterable<PotentialSchemaSource<?>> sources);
+
+ /**
+ * Invoked when a schema source is unregistered.
+ *
+ * @param source Schema source representation
+ */
+ void schemaSourceUnregistered(PotentialSchemaSource<?> source);
+}
package org.opendaylight.yangtools.yang.model.repo.spi;
import com.google.common.annotations.Beta;
-import com.google.common.base.Optional;
-import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.CheckedFuture;
+import org.opendaylight.yangtools.yang.model.repo.api.MissingSchemaSourceException;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
*
* <ul>
* <li> If the source identifier specifies a revision, this method returns either
- * a representation of that particular revision, or report the identifier as absent
- * by returning {@link Optional#absent()}.
+ * a representation of that particular revision or throw {@link MissingSchemaSourceException}.
* <li> If the source identifier does not specify a revision, this method returns
- * the newest available revision, or {@link Optional#absent()}.
+ * the newest available revision, or throws {@link MissingSchemaSourceException}.
*
* In either case the returned representation is required to report a non-null
* revision in the {@link SourceIdentifier} returned from
*
* @param sourceIdentifier source identifier
* @return source representation if supplied YANG module is available
- * {@link Optional#absent()} otherwise.
+ *
*/
- ListenableFuture<Optional<T>> getSource(SourceIdentifier sourceIdentifier);
+ CheckedFuture<? extends T, SchemaSourceException> getSource(SourceIdentifier sourceIdentifier);
}
*/
package org.opendaylight.yangtools.yang.model.repo.spi;
+import com.google.common.annotations.Beta;
+
import org.opendaylight.yangtools.concepts.ObjectRegistration;
-import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
-public interface SchemaSourceRegistration extends ObjectRegistration<SourceIdentifier> {
+/**
+ * Registration of a schema source.
+ */
+@Beta
+public interface SchemaSourceRegistration<T extends SchemaSourceRepresentation> extends ObjectRegistration<PotentialSchemaSource<T>> {
@Override
void close();
}
*/
package org.opendaylight.yangtools.yang.model.repo.spi;
+import com.google.common.annotations.Beta;
+
import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
* {@link SchemaSourceProvider} instances which would then acquire the schema
* source.
*/
+@Beta
public interface SchemaSourceRegistry {
/**
* Register a new schema source which is potentially available from a provider.
* A registration does not guarantee that a subsequent call to
* {@link SchemaSourceProvider#getSource(SourceIdentifier)} will succeed.
*
- * @param identifier Schema source identifier
* @param provider Resolver which can potentially resolve the identifier
- * @param representation Schema source representation which the source may
- * be available.
+ * @param source Schema source details
* @return A registration handle. Invoking {@link SchemaSourceRegistration#close()}
* will cancel the registration.
*/
- <T extends SchemaSourceRepresentation> SchemaSourceRegistration registerSchemaSource(
- SourceIdentifier identifier, SchemaSourceProvider<? super T> provider, Class<T> representation);
+ <T extends SchemaSourceRepresentation> SchemaSourceRegistration<T> registerSchemaSource(SchemaSourceProvider<? super T> provider, PotentialSchemaSource<T> source);
/**
- * Register a schema transformer. The registry can invoke it to transform between
- * the various schema source formats.
+ * Register a schema source listener. The listener will be notified as new
+ * sources and their representations become available, subject to the provided
+ * filter.
*
- * @param transformer Schema source transformer
- * @return A registration handle. Invoking {@link SchemaTransformerRegistration#close()}
+ * @param listener Schema source listener
+ * @return A registration handle. Invoking {@link SchemaListenerRegistration#close()}
* will cancel the registration.
*/
- SchemaTransformerRegistration registerSchemaSourceTransformer(SchemaSourceTransformer<?, ?> transformer);
+ SchemaListenerRegistration registerSchemaSourceListener(SchemaSourceListener listener);
}
+++ /dev/null
-/*
- * Copyright (c) 2014 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/eplv10.html
- */
-package org.opendaylight.yangtools.yang.model.repo.spi;
-
-import com.google.common.util.concurrent.CheckedFuture;
-
-import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
-
-/**
- * An schema source representation transformation service. An instance can create
- * some output schema source representation based on some input source representation.
- *
- * @param <I> Input {@link SchemaSourceRepresentation}
- * @param <O> Output {@link SchemaSourceRepresentation}
- */
-public interface SchemaSourceTransformer<I extends SchemaSourceRepresentation, O extends SchemaSourceRepresentation> {
- /**
- * Return the {@link SchemaSourceRepresentation} which this transformer
- * accepts on its input.
- *
- * @return The input source representation type.
- */
- Class<I> getInputRepresentation();
-
- /**
- * Return the {@link SchemeSourceRepresentation} which this transformer
- * produces on its output.
- *
- * @return The output source representation type.
- */
- Class<O> getOutputRepresentation();
-
- /**
- * Transform a schema source representation from its input form to
- * the transformers output form.
- *
- * @param source Schema source in its source representation
- * @return A future which produces the output schema source representation.
- */
- CheckedFuture<O, SchemaSourceTransformationException> transformSchemaSource(I source);
-
- /**
- * Return the relative cost of performing the transformation. When in doubt,
- * return 1.
- *
- * @return Relative cost.
- */
- int getCost();
-}
--- /dev/null
+/*
+ * Copyright (c) 2014 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/eplv10.html
+ */
+package org.opendaylight.yangtools.yang.model.repo.util;
+
+import org.opendaylight.yangtools.concepts.AbstractListenerRegistration;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaListenerRegistration;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceListener;
+
+public abstract class AbstractSchemaListenerRegistration extends AbstractListenerRegistration<SchemaSourceListener> implements SchemaListenerRegistration {
+ protected AbstractSchemaListenerRegistration(final SchemaSourceListener listener) {
+ super(listener);
+ }
+}
*/
package org.opendaylight.yangtools.yang.model.repo.util;
-import com.google.common.base.Optional;
+import com.google.common.annotations.Beta;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
-import com.google.common.util.concurrent.AsyncFunction;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.FutureFallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
-import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
-import java.util.List;
import java.util.Map;
-import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory;
+import javax.annotation.concurrent.GuardedBy;
+
+import org.opendaylight.yangtools.util.concurrent.ExceptionMapper;
+import org.opendaylight.yangtools.util.concurrent.ReflectiveExceptionMapper;
+import org.opendaylight.yangtools.yang.model.repo.api.MissingSchemaSourceException;
import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceFilter;
import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaListenerRegistration;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceListener;
import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceProvider;
import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistration;
import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry;
-import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceTransformationException;
-import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceTransformer;
-import org.opendaylight.yangtools.yang.model.repo.spi.SchemaTransformerRegistration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-public class AbstractSchemaRepository implements SchemaRepository, SchemaSourceRegistry {
+/**
+ * Abstract base class for {@link SchemaRepository} implementations. It handles registration
+ * and lookup of schema sources, subclasses need only to provide their own
+ * {@link #createSchemaContextFactory(SchemaSourceFilter)} implementation.
+ */
+@Beta
+public abstract class AbstractSchemaRepository implements SchemaRepository, SchemaSourceRegistry {
private static final Logger LOG = LoggerFactory.getLogger(AbstractSchemaRepository.class);
- private static final Comparator<SchemaTransformerRegistration> TRANSFORMER_COST_COMPARATOR = new Comparator<SchemaTransformerRegistration>() {
- @Override
- public int compare(final SchemaTransformerRegistration o1, final SchemaTransformerRegistration o2) {
- return o1.getInstance().getCost() - o2.getInstance().getCost();
- }
- };
+ private static final ExceptionMapper<SchemaSourceException> FETCH_MAPPER = ReflectiveExceptionMapper.create("Schema source fetch", SchemaSourceException.class);
/*
- * Output-type -> transformer map. Our usage involves knowing the destination type,
- * so we have to work backwards and find a transformer chain which will get us
- * to that representation given our available sources.
+ * Source identifier -> representation -> provider map. We usually are looking for
+ * a specific representation of a source.
*/
- private final Multimap<Class<? extends SchemaSourceRepresentation>, SchemaTransformerRegistration> transformers =
- HashMultimap.create();
+ @GuardedBy("this")
+ private final Map<SourceIdentifier, Multimap<Class<? extends SchemaSourceRepresentation>, AbstractSchemaSourceRegistration<?>>> sources = new HashMap<>();
/*
- * Source identifier -> representation -> provider map. We usually are looking for
- * a specific representation a source.
+ * Schema source listeners.
*/
- private final Map<SourceIdentifier, Multimap<Class<?>, AbstractSchemaSourceRegistration>> sources = new HashMap<>();
+ @GuardedBy("this")
+ private final Collection<SchemaListenerRegistration> listeners = new ArrayList<>();
+ private static final <T extends SchemaSourceRepresentation> CheckedFuture<T, SchemaSourceException> fetchSource(final SourceIdentifier id, final Iterator<AbstractSchemaSourceRegistration<?>> it) {
+ final AbstractSchemaSourceRegistration<?> reg = it.next();
- private static final <T extends SchemaSourceRepresentation> ListenableFuture<Optional<T>> fetchSource(final SourceIdentifier id, final Iterator<AbstractSchemaSourceRegistration> it) {
- if (!it.hasNext()) {
- return Futures.immediateFuture(Optional.<T>absent());
- }
-
- return Futures.transform(((SchemaSourceProvider<T>)it.next().getProvider()).getSource(id), new AsyncFunction<Optional<T>, Optional<T>>() {
+ @SuppressWarnings("unchecked")
+ final CheckedFuture<? extends T, SchemaSourceException> f = ((SchemaSourceProvider<T>)reg.getProvider()).getSource(id);
+ return Futures.makeChecked(Futures.withFallback(f, new FutureFallback<T>() {
@Override
- public ListenableFuture<Optional<T>> apply(final Optional<T> input) throws Exception {
- if (input.isPresent()) {
- return Futures.immediateFuture(input);
- } else {
+ public ListenableFuture<T> create(final Throwable t) throws SchemaSourceException {
+ LOG.debug("Failed to acquire source from {}", reg, t);
+
+ if (it.hasNext()) {
return fetchSource(id, it);
}
- }
- });
- }
-
- private <T extends SchemaSourceRepresentation> ListenableFuture<Optional<T>> transformSchemaSource(final SourceIdentifier id, final Class<T> representation) {
- final Multimap<Class<?>, AbstractSchemaSourceRegistration> srcs = sources.get(id);
- if (srcs.isEmpty()) {
- return Futures.immediateFailedFuture(new SchemaSourceTransformationException(
- String.format("No providers producing a representation of %s registered", id)));
- }
-
- final Collection<SchemaTransformerRegistration> ts = transformers.get(representation);
- if (ts.isEmpty()) {
- return Futures.immediateFailedFuture(new SchemaSourceTransformationException(
- String.format("No transformers producing representation %s registered", representation)));
- }
- // Build up the candidate list
- final List<SchemaTransformerRegistration> candidates = new ArrayList<>();
- for (SchemaTransformerRegistration tr : ts) {
- final SchemaSourceTransformer<?, ?> t = tr.getInstance();
- final Class<?> i = t.getInputRepresentation();
- if (srcs.containsKey(i)) {
- candidates.add(tr);
- } else {
- LOG.debug("Provider for {} in {} not found, skipping transfomer {}", id, i, t);
+ throw new MissingSchemaSourceException("All available providers exhausted");
}
- }
-
- if (candidates.isEmpty()) {
- return Futures.immediateFailedFuture(new SchemaSourceTransformationException(
- String.format("No matching source/transformer pair for source %s representation %s found", id, representation)));
- }
-
- Collections.sort(candidates, TRANSFORMER_COST_COMPARATOR);
- // return transform(candidates.iterator(), id);
- return null;
+ }), FETCH_MAPPER);
}
- /**
- * Obtain a SchemaSource is selected representation
- */
- protected <T extends SchemaSourceRepresentation> ListenableFuture<Optional<T>> getSchemaSource(final SourceIdentifier id, final Class<T> representation) {
- final Multimap<Class<?>, AbstractSchemaSourceRegistration> srcs = sources.get(id);
+ @Override
+ public <T extends SchemaSourceRepresentation> CheckedFuture<T, SchemaSourceException> getSchemaSource(final SourceIdentifier id, final Class<T> representation) {
+ final Multimap<Class<? extends SchemaSourceRepresentation>, AbstractSchemaSourceRegistration<?>> srcs = sources.get(id);
if (srcs == null) {
- LOG.debug("No providers registered for source {}", id);
- return Futures.immediateFuture(Optional.<T>absent());
+ return Futures.<T, SchemaSourceException>immediateFailedCheckedFuture(new MissingSchemaSourceException("No providers registered for source" + id));
}
- final Collection<AbstractSchemaSourceRegistration> candidates = srcs.get(representation);
- return Futures.transform(AbstractSchemaRepository.<T>fetchSource(id, candidates.iterator()), new AsyncFunction<Optional<T>, Optional<T>>() {
- @Override
- public ListenableFuture<Optional<T>> apply(final Optional<T> input) throws Exception {
- if (input.isPresent()) {
- return Futures.immediateFuture(input);
- }
-
- return transformSchemaSource(id, representation);
- }
- });
- }
+ final Iterator<AbstractSchemaSourceRegistration<?>> regs = srcs.get(representation).iterator();
+ if (!regs.hasNext()) {
+ return Futures.<T, SchemaSourceException>immediateFailedCheckedFuture(
+ new MissingSchemaSourceException("No providers for source " + id + " representation " + representation + " available"));
+ }
- @Override
- public SchemaContextFactory createSchemaContextFactory(final SchemaSourceFilter filter) {
- // TODO Auto-generated method stub
- return null;
+ return fetchSource(id, regs);
}
- private void addSource(final SourceIdentifier id, final Class<?> rep, final AbstractSchemaSourceRegistration reg) {
- Multimap<Class<?>, AbstractSchemaSourceRegistration> m = sources.get(id);
+ private synchronized <T extends SchemaSourceRepresentation> void addSource(final PotentialSchemaSource<T> source, final AbstractSchemaSourceRegistration<T> reg) {
+ Multimap<Class<? extends SchemaSourceRepresentation>, AbstractSchemaSourceRegistration<?>> m = sources.get(source.getSourceIdentifier());
if (m == null) {
m = HashMultimap.create();
- sources.put(id, m);
+ sources.put(source.getSourceIdentifier(), m);
}
- m.put(rep, reg);
+ m.put(source.getRepresentation(), reg);
+
+ final Collection<PotentialSchemaSource<?>> reps = Collections.<PotentialSchemaSource<?>>singleton(source);
+ for (SchemaListenerRegistration l : listeners) {
+ l.getInstance().schemaSourceRegistered(reps);
+ }
}
- private void removeSource(final SourceIdentifier id, final Class<?> rep, final SchemaSourceRegistration reg) {
- final Multimap<Class<?>, AbstractSchemaSourceRegistration> m = sources.get(id);
+ private synchronized <T extends SchemaSourceRepresentation> void removeSource(final PotentialSchemaSource<?> source, final SchemaSourceRegistration<?> reg) {
+ final Multimap<Class<? extends SchemaSourceRepresentation>, AbstractSchemaSourceRegistration<?>> m = sources.get(source.getSourceIdentifier());
if (m != null) {
- m.remove(rep, reg);
+ m.remove(source.getRepresentation(), reg);
+
+ for (SchemaListenerRegistration l : listeners) {
+ l.getInstance().schemaSourceUnregistered(source);
+ }
+
if (m.isEmpty()) {
sources.remove(m);
}
}
@Override
- public <T extends SchemaSourceRepresentation> SchemaSourceRegistration registerSchemaSource(
- final SourceIdentifier identifier, final SchemaSourceProvider<? super T> provider, final Class<T> representation) {
- final AbstractSchemaSourceRegistration ret = new AbstractSchemaSourceRegistration(identifier, provider) {
+ public <T extends SchemaSourceRepresentation> SchemaSourceRegistration<T> registerSchemaSource(final SchemaSourceProvider<? super T> provider, final PotentialSchemaSource<T> source) {
+ final AbstractSchemaSourceRegistration<T> ret = new AbstractSchemaSourceRegistration<T>(provider, source) {
@Override
protected void removeRegistration() {
- removeSource(identifier, representation, this);
+ removeSource(source, this);
}
};
- addSource(identifier, representation, ret);
+ addSource(source, ret);
return ret;
}
@Override
- public SchemaTransformerRegistration registerSchemaSourceTransformer(final SchemaSourceTransformer<?, ?> transformer) {
- final SchemaTransformerRegistration ret = new AbstractSchemaTransformerRegistration(transformer) {
+ public SchemaListenerRegistration registerSchemaSourceListener(final SchemaSourceListener listener) {
+ final SchemaListenerRegistration ret = new AbstractSchemaListenerRegistration(listener) {
@Override
protected void removeRegistration() {
- transformers.remove(transformer.getOutputRepresentation(), this);
+ listeners.remove(this);
}
};
- transformers.put(transformer.getOutputRepresentation(), ret);
+ synchronized (this) {
+ final Collection<PotentialSchemaSource<?>> col = new ArrayList<>();
+ for (Multimap<Class<? extends SchemaSourceRepresentation>, AbstractSchemaSourceRegistration<?>> m : sources.values()) {
+ for (AbstractSchemaSourceRegistration<?> r : m.values()) {
+ col.add(r.getInstance());
+ }
+ }
+
+ // Notify first, so translator-type listeners, who react by registering a source
+ // do not cause infinite loop.
+ listener.schemaSourceRegistered(col);
+ listeners.add(ret);
+ }
return ret;
}
}
--- /dev/null
+/*
+ * Copyright (c) 2014 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.model.repo.util;
+
+import com.google.common.base.Preconditions;
+
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
+import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource;
+import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource.Costs;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceListener;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceProvider;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistration;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry;
+
+/**
+ * Abstract base class for cache-type SchemaSourceListeners. It needs to be
+ * registered with a {@link SchemaSourceRegistry}, where it gets notifications
+ * from. It performs filtering and {@link #offer(SchemaSourceRepresentation)}s
+ * conforming sources to the subclass.
+ *
+ * @param <T> Cached schema source type.
+ */
+public abstract class AbstractSchemaSourceCache<T extends SchemaSourceRepresentation> implements SchemaSourceListener, SchemaSourceProvider<T> {
+ private final SchemaSourceRegistry consumer;
+ private final Class<T> representation;
+ private final Costs cost;
+
+ protected AbstractSchemaSourceCache(final SchemaSourceRegistry consumer, final Class<T> representation, final Costs cost) {
+ this.consumer = Preconditions.checkNotNull(consumer);
+ this.representation = Preconditions.checkNotNull(representation);
+ this.cost = Preconditions.checkNotNull(cost);
+ }
+
+ /**
+ * Offer a schema source in requested representation for caching. Subclasses
+ * need to implement this method to store the schema source. Once they have
+ * determined to cache the source, they should call {@link #register(SourceIdentifier)}.
+ *
+ * @param source schema source
+ */
+ protected abstract void offer(T source);
+
+ /**
+ * Register the presence of a cached schema source with the consumer. Subclasses
+ * need to call this method once they have cached a schema source representation,
+ * or when they have determined they have a schema source is available -- like
+ * when a persistent cache reads its cache index.
+ *
+ * @param sourceIdentifier Source identifier
+ * @return schema source registration, which the subclass needs to
+ * {@link SchemaSourceRegistration#close() once it expunges the source
+ * from the cache.
+ */
+ protected final SchemaSourceRegistration<T> register(final SourceIdentifier sourceIdentifier) {
+ final PotentialSchemaSource<T> src = PotentialSchemaSource.create(sourceIdentifier, representation, cost.getValue());
+ return consumer.registerSchemaSource(this, src);
+ }
+
+ @Override
+ public void schemaSourceEncountered(final SchemaSourceRepresentation source) {
+ if (representation.isAssignableFrom(source.getType())) {
+ @SuppressWarnings("unchecked")
+ final T src = (T)source;
+ offer(src);
+ }
+ }
+
+ @Override
+ public final void schemaSourceRegistered(final Iterable<PotentialSchemaSource<?>> sources) {
+ // Not interesting
+ }
+
+ @Override
+ public final void schemaSourceUnregistered(final PotentialSchemaSource<?> source) {
+ // Not interesting
+ }
+}
import com.google.common.base.Preconditions;
import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
-import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
+import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource;
import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceProvider;
import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistration;
-public abstract class AbstractSchemaSourceRegistration extends AbstractObjectRegistration<SourceIdentifier> implements SchemaSourceRegistration {
+public abstract class AbstractSchemaSourceRegistration<T extends SchemaSourceRepresentation> extends AbstractObjectRegistration<PotentialSchemaSource<T>> implements SchemaSourceRegistration<T> {
private final SchemaSourceProvider<?> provider;
- protected AbstractSchemaSourceRegistration(final SourceIdentifier identifier, final SchemaSourceProvider<?> provider) {
- super(identifier);
+ protected AbstractSchemaSourceRegistration(final SchemaSourceProvider<?> provider, final PotentialSchemaSource<T> source) {
+ super(source);
this.provider = Preconditions.checkNotNull(provider);
}
- protected SchemaSourceProvider<?> getProvider() {
+ protected final SchemaSourceProvider<?> getProvider() {
return provider;
}
}
+++ /dev/null
-/*
- * Copyright (c) 2014 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/eplv10.html
- */
-package org.opendaylight.yangtools.yang.model.repo.util;
-
-import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
-import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceTransformer;
-import org.opendaylight.yangtools.yang.model.repo.spi.SchemaTransformerRegistration;
-
-public abstract class AbstractSchemaTransformerRegistration extends AbstractObjectRegistration<SchemaSourceTransformer<?, ?>> implements SchemaTransformerRegistration {
- protected AbstractSchemaTransformerRegistration(
- final SchemaSourceTransformer<?, ?> transformer) {
- super(transformer);
- }
-}
--- /dev/null
+/*
+ * Copyright (c) 2014 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.model.repo.util;
+
+import com.google.common.base.Preconditions;
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.RemovalListener;
+import com.google.common.cache.RemovalNotification;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+
+import org.opendaylight.yangtools.yang.model.repo.api.MissingSchemaSourceException;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
+import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource.Costs;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistration;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry;
+
+public class InMemorySchemaSourceCache<T extends SchemaSourceRepresentation> extends AbstractSchemaSourceCache<T> {
+ private static final class CacheEntry<T extends SchemaSourceRepresentation> {
+ private final SchemaSourceRegistration<T> reg;
+ private final T source;
+
+ public CacheEntry(final T source, final SchemaSourceRegistration<T> reg) {
+ this.source = Preconditions.checkNotNull(source);
+ this.reg = Preconditions.checkNotNull(reg);
+ }
+ }
+
+ private static final RemovalListener<SourceIdentifier, CacheEntry<?>> LISTENER = new RemovalListener<SourceIdentifier, CacheEntry<?>>() {
+ @Override
+ public void onRemoval(final RemovalNotification<SourceIdentifier, CacheEntry<?>> notification) {
+ notification.getValue().reg.close();
+ }
+ };
+
+ private final Cache<SourceIdentifier, CacheEntry<T>> cache;
+
+ protected InMemorySchemaSourceCache(final SchemaSourceRegistry consumer, final Class<T> representation, final int maxSize) {
+ super(consumer, representation, Costs.IMMEDIATE);
+ cache = CacheBuilder.newBuilder().softValues().maximumSize(maxSize).removalListener(LISTENER).build();
+ }
+
+ @Override
+ public CheckedFuture<? extends T, SchemaSourceException> getSource(final SourceIdentifier sourceIdentifier) {
+ final CacheEntry<T> present = cache.getIfPresent(sourceIdentifier);
+ if (present != null) {
+ return Futures.immediateCheckedFuture(present.source);
+ }
+
+ return Futures.<T, SchemaSourceException>immediateFailedCheckedFuture(new MissingSchemaSourceException("Source not found"));
+ }
+
+ @Override
+ protected void offer(final T source) {
+ final CacheEntry<T> present = cache.getIfPresent(source.getIdentifier());
+ if (present == null) {
+ final SchemaSourceRegistration<T> reg = register(source.getIdentifier());
+ cache.put(source.getIdentifier(), new CacheEntry<T>(source, reg));
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 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.model.repo.util;
+
+import com.google.common.base.Preconditions;
+
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistration;
+
+final class RefcountedRegistration {
+ private final SchemaSourceRegistration<?> reg;
+ private int refcount = 1;
+
+ RefcountedRegistration(final SchemaSourceRegistration<?> reg) {
+ this.reg = Preconditions.checkNotNull(reg);
+ }
+
+ public void incRef() {
+ refcount++;
+ }
+
+ public boolean decRef() {
+ Preconditions.checkState(refcount > 0, "Refcount underflow: %s", refcount);
+
+ if (0 == --refcount) {
+ reg.close();
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2014 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.model.repo.util;
+
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.AsyncFunction;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.opendaylight.yangtools.util.concurrent.ExceptionMapper;
+import org.opendaylight.yangtools.util.concurrent.ReflectiveExceptionMapper;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
+import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceListener;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceProvider;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistration;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry;
+
+public class SchemaSourceTransformer<S extends SchemaSourceRepresentation, D extends SchemaSourceRepresentation> implements SchemaSourceListener, SchemaSourceProvider<D> {
+ private static final ExceptionMapper<SchemaSourceException> MAPPER = ReflectiveExceptionMapper.create("Source transformation", SchemaSourceException.class);
+
+ public static interface Transformation<S extends SchemaSourceRepresentation, D extends SchemaSourceRepresentation> extends AsyncFunction<S, D> {
+ @Override
+ CheckedFuture<D, SchemaSourceException> apply(final S input) throws Exception;
+ }
+
+ private final Map<PotentialSchemaSource<?>, RefcountedRegistration> sources = new HashMap<>();
+ private final SchemaSourceRegistry consumer;
+ private final SchemaRepository provider;
+ private final AsyncFunction<S, D> function;
+ private final Class<S> srcClass;
+ private final Class<D> dstClass;
+
+ public SchemaSourceTransformer(final SchemaRepository provider, final Class<S> srcClass,
+ final SchemaSourceRegistry consumer, final Class<D> dstClass, final AsyncFunction<S, D> function) {
+ this.provider = Preconditions.checkNotNull(provider);
+ this.consumer = Preconditions.checkNotNull(consumer);
+ this.function = Preconditions.checkNotNull(function);
+ this.srcClass = Preconditions.checkNotNull(srcClass);
+ this.dstClass = Preconditions.checkNotNull(dstClass);
+ }
+
+ @Override
+ public CheckedFuture<D, SchemaSourceException> getSource(final SourceIdentifier sourceIdentifier) {
+ final CheckedFuture<S, SchemaSourceException> f = provider.getSchemaSource(sourceIdentifier, srcClass);
+ return Futures.makeChecked(Futures.transform(f, function), MAPPER);
+ }
+
+ @Override
+ public final void schemaSourceEncountered(final SchemaSourceRepresentation source) {
+ // Not interesting
+ }
+
+ @Override
+ public final void schemaSourceRegistered(final Iterable<PotentialSchemaSource<?>> sources) {
+ for (PotentialSchemaSource<?> src : sources) {
+ final Class<?> rep = src.getRepresentation();
+ if (srcClass.isAssignableFrom(rep) && dstClass != rep) {
+ registerSource(src);
+ }
+ }
+ }
+
+ @Override
+ public final void schemaSourceUnregistered(final PotentialSchemaSource<?> source) {
+ final Class<?> rep = source.getRepresentation();
+ if (srcClass.isAssignableFrom(rep) && dstClass != rep) {
+ unregisterSource(source);
+ }
+ }
+
+ private void registerSource(final PotentialSchemaSource<?> src) {
+ RefcountedRegistration reg = sources.get(src);
+ if (reg != null) {
+ reg.incRef();
+ return;
+ }
+
+ final PotentialSchemaSource<D> newSrc = PotentialSchemaSource.create(src.getSourceIdentifier(), dstClass,
+ src.getCost() + PotentialSchemaSource.Costs.COMPUTATION.getValue());
+
+ final SchemaSourceRegistration<D> r = consumer.registerSchemaSource(this, newSrc);
+ sources.put(src, new RefcountedRegistration(r));
+ }
+
+ private void unregisterSource(final PotentialSchemaSource<?> src) {
+ final RefcountedRegistration reg = sources.get(src);
+ if (reg != null && reg.decRef()) {
+ sources.remove(src);
+ }
+ }
+}
} else if ("empty".equals(typeName)) {
return EmptyType.getInstance();
} else if ("instance-identifier".equals(typeName)) {
- return InstanceIdentifier.getInstance();
+ return InstanceIdentifierType.getInstance();
}
return null;
}
* @see InstanceIdentifierTypeDefinition
*
*/
-public final class InstanceIdentifier implements InstanceIdentifierTypeDefinition, Immutable {
+public final class InstanceIdentifierType implements InstanceIdentifierTypeDefinition, Immutable {
private static final QName NAME = BaseTypes.INSTANCE_IDENTIFIER_QNAME;
private static final SchemaPath PATH = SchemaPath.create(true, NAME);
private static final String UNITS = "";
private final Boolean requireInstance;
- private static final InstanceIdentifier INSTANCE_WITH_REQUIRED_TRUE = new InstanceIdentifier(true);
- private static final InstanceIdentifier INSTANCE_WITH_REQUIRED_FALSE = new InstanceIdentifier(false);
+ private static final InstanceIdentifierType INSTANCE_WITH_REQUIRED_TRUE = new InstanceIdentifierType(true);
+ private static final InstanceIdentifierType INSTANCE_WITH_REQUIRED_FALSE = new InstanceIdentifierType(false);
/**
* Constructs new instance identifier.
* @deprecated Use {@link #getInstance()} for default one, since Instance Identifier does not have xpath.
*/
@Deprecated
- public InstanceIdentifier(final RevisionAwareXPath xpath) {
+ public InstanceIdentifierType(final RevisionAwareXPath xpath) {
requireInstance = true;
}
* @deprecated Use {@link #create(boolean)}, since Instance Identifier does not have xpath.
*/
@Deprecated
- public InstanceIdentifier(final RevisionAwareXPath xpath, final boolean requireInstance) {
+ public InstanceIdentifierType(final RevisionAwareXPath xpath, final boolean requireInstance) {
this.requireInstance = requireInstance;
}
- private InstanceIdentifier(final boolean requiredInstance) {
+ private InstanceIdentifierType(final boolean requiredInstance) {
this.requireInstance = requiredInstance;
}
- public static InstanceIdentifier getInstance() {
+ public static InstanceIdentifierType getInstance() {
return INSTANCE_WITH_REQUIRED_TRUE;
}
- public static InstanceIdentifier create(final boolean requireInstance) {
+ public static InstanceIdentifierType create(final boolean requireInstance) {
return requireInstance ? INSTANCE_WITH_REQUIRED_TRUE : INSTANCE_WITH_REQUIRED_FALSE;
}
if (getClass() != obj.getClass()) {
return false;
}
- InstanceIdentifier other = (InstanceIdentifier) obj;
+ InstanceIdentifierType other = (InstanceIdentifierType) obj;
return requireInstance.equals(other.requireInstance);
}
* <dt>uint64</dt>
* <dd>64-bit unsigned integer -{@link org.opendaylight.yangtools.yang.model.util.Int64}</dd>
* <dt>instance-identifier</dt>
- * <dd>References a data tree node - {@link org.opendaylight.yangtools.yang.model.util.InstanceIdentifier}</dd>
+ * <dd>References a data tree node - {@link org.opendaylight.yangtools.yang.model.util.InstanceIdentifierType}</dd>
* <dt>string</dt>
* <dd>{@link org.opendaylight.yangtools.yang.model.util.StringType}</dd>
* </dl>
import org.opendaylight.yangtools.yang.model.util.Decimal64;
import org.opendaylight.yangtools.yang.model.util.EnumerationType;
import org.opendaylight.yangtools.yang.model.util.ExtendedType;
-import org.opendaylight.yangtools.yang.model.util.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.util.InstanceIdentifierType;
import org.opendaylight.yangtools.yang.model.util.Int16;
import org.opendaylight.yangtools.yang.model.util.Int32;
import org.opendaylight.yangtools.yang.model.util.Int64;
constraints.addLengths(binaryType.getLengthConstraints());
baseType = binaryType;
} else if ("instance-identifier".equals(typeName)) {
- return InstanceIdentifier.create(isRequireInstance(typeBody));
+ return InstanceIdentifierType.create(isRequireInstance(typeBody));
}
if (parent instanceof TypeDefinitionBuilder && !(parent instanceof UnionTypeBuilder)) {
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.collect.Iterables;
+
import java.net.URI;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
+
import org.antlr.v4.runtime.tree.ParseTree;
+import org.antlr.v4.runtime.tree.ParseTreeWalker;
import org.opendaylight.yangtools.antlrv4.code.gen.YangParser;
import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Argument_stmtContext;
import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Base_stmtContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+
public final class YangParserListenerImpl extends YangParserBaseListener {
private static final Logger LOG = LoggerFactory.getLogger(YangParserListenerImpl.class);
private static final Splitter COLON_SPLITTER = Splitter.on(':');
this.sourcePath = sourcePath;
}
+ /**
+ * Create a new instance.
+ *
+ * FIXME: the resulting type needs to be extracted, such that we can reuse
+ * the "BaseListener" aspect, which need not be exposed to the user.
+ * Maybe factor out a base class into repo.spi?
+ *
+ * @param sourcePath
+ * @param walker
+ * @param tree
+ * @return
+ */
+ public static YangParserListenerImpl create(final String sourcePath, final ParseTreeWalker walker, final ParseTree tree) {
+ final YangParserListenerImpl ret = new YangParserListenerImpl(sourcePath);
+ walker.walk(ret, tree);
+ return ret;
+ }
+
@Override
public void enterModule_stmt(final YangParser.Module_stmtContext ctx) {
moduleName = stringFromNode(ctx);
--- /dev/null
+/*
+ * Copyright (c) 2014 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.repo;
+
+import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
+import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
+
+public abstract class AbstractURLRegistration extends AbstractObjectRegistration<YangTextSchemaSource> implements URLRegistration{
+ protected AbstractURLRegistration(final YangTextSchemaSource text) {
+ super(text);
+ }
+}
\ No newline at end of file
return rev == null && findWildcard(haystack, mi.getModuleName()) != null;
}
+
+
public static final DependencyResolver create(final Map<SourceIdentifier, YangModelDependencyInfo> depInfo) {
final Collection<SourceIdentifier> resolved = new ArrayList<>(depInfo.size());
final Collection<SourceIdentifier> pending = new ArrayList<>(depInfo.keySet());
--- /dev/null
+/*
+ * Copyright (c) 2014 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.repo;
+
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Maps;
+import com.google.common.util.concurrent.AsyncFunction;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.antlr.v4.runtime.ParserRuleContext;
+import org.antlr.v4.runtime.tree.ParseTreeWalker;
+import org.opendaylight.yangtools.util.concurrent.ExceptionMapper;
+import org.opendaylight.yangtools.util.concurrent.ReflectiveExceptionMapper;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaResolutionException;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceFilter;
+import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserListenerImpl;
+import org.opendaylight.yangtools.yang.parser.impl.util.YangModelDependencyInfo;
+import org.opendaylight.yangtools.yang.parser.util.ASTSchemaSource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class SharedSchemaContextFactory implements SchemaContextFactory {
+ private static final ExceptionMapper<SchemaResolutionException> MAPPER = ReflectiveExceptionMapper.create("resolve sources", SchemaResolutionException.class);
+ private static final Logger LOG = LoggerFactory.getLogger(SharedSchemaContextFactory.class);
+
+ private final Function<SourceIdentifier, ListenableFuture<ASTSchemaSource>> requestSources = new Function<SourceIdentifier, ListenableFuture<ASTSchemaSource>>() {
+ @Override
+ public ListenableFuture<ASTSchemaSource> apply(final SourceIdentifier input) {
+ return repository.getSchemaSource(input, ASTSchemaSource.class);
+ }
+ };
+ private final Cache<Collection<SourceIdentifier>, SchemaContext> cache = CacheBuilder.newBuilder().softValues().build();
+
+ private final AsyncFunction<List<ASTSchemaSource>, SchemaContext> assembleSources = new AsyncFunction<List<ASTSchemaSource>, SchemaContext>() {
+ @Override
+ public ListenableFuture<SchemaContext> apply(final List<ASTSchemaSource> sources) throws SchemaResolutionException {
+ final Map<SourceIdentifier, ASTSchemaSource> srcs =
+ Maps.uniqueIndex(sources, ASTSchemaSource.GET_IDENTIFIER);
+ final Map<SourceIdentifier, YangModelDependencyInfo> deps =
+ Maps.transformValues(srcs, ASTSchemaSource.GET_DEPINFO);
+
+ LOG.debug("Resolving dependency reactor {}", deps);
+
+ final DependencyResolver res = DependencyResolver.create(deps);
+ if (!res.getUnresolvedSources().isEmpty()) {
+ LOG.debug("Omitting models {} due to unsatisfied imports {}", res.getUnresolvedSources(), res.getUnsatisfiedImports());
+
+ // FIXME: push into DependencyResolver
+
+ throw new SchemaResolutionException("Failed to resolve required models",
+ res.getResolvedSources(), res.getUnsatisfiedImports());
+ }
+
+ final Map<SourceIdentifier, ParserRuleContext> asts =
+ Maps.transformValues(srcs, ASTSchemaSource.GET_AST);
+
+ final ParseTreeWalker walker = new ParseTreeWalker();
+ final Map<SourceIdentifier, ModuleBuilder> sourceToBuilder = new LinkedHashMap<>();
+
+ for (Entry<SourceIdentifier, ParserRuleContext> entry : asts.entrySet()) {
+ ModuleBuilder moduleBuilder =
+ YangParserListenerImpl.create(entry.getKey().getName(), walker, entry.getValue()).getModuleBuilder();
+
+ moduleBuilder.setSource(srcs.get(entry.getKey()).getYangText());
+ sourceToBuilder.put(entry.getKey(), moduleBuilder);
+ }
+ LOG.debug("Modules ready for integration");
+
+ final YangParserImpl parser = YangParserImpl.getInstance();
+ final Collection<Module> modules = parser.buildModules(sourceToBuilder.values());
+ LOG.debug("Integrated cross-references modules");
+ return Futures.immediateCheckedFuture(parser.assembleContext(modules));
+ }
+ };
+
+ private final SharedSchemaRepository repository;
+ // FIXME: ignored right now
+ private final SchemaSourceFilter filter;
+
+ public SharedSchemaContextFactory(final SharedSchemaRepository repository, final SchemaSourceFilter filter) {
+ this.repository = Preconditions.checkNotNull(repository);
+ this.filter = Preconditions.checkNotNull(filter);
+ }
+
+ @Override
+ public CheckedFuture<SchemaContext, SchemaResolutionException> createSchemaContext(final Collection<SourceIdentifier> requiredSources) {
+ final SchemaContext existing = cache.getIfPresent(requiredSources);
+ if (existing != null) {
+ LOG.debug("Returning cached context {}", existing);
+ return Futures.immediateCheckedFuture(existing);
+ }
+
+ // Request all sources be loaded
+ final ListenableFuture<List<ASTSchemaSource>> sf = Futures.allAsList(Collections2.transform(requiredSources, requestSources));
+
+ // Assemble sources into a schemacontext
+ final ListenableFuture<SchemaContext> cf = Futures.transform(sf, assembleSources);
+
+ // Populate cache when successful
+ Futures.addCallback(cf, new FutureCallback<SchemaContext>() {
+ @Override
+ public void onSuccess(final SchemaContext result) {
+ cache.put(requiredSources, result);
+ }
+
+ @Override
+ public void onFailure(final Throwable t) {
+ LOG.info("Failed to assemble sources", t);
+ }
+ });
+
+ return Futures.makeChecked(cf, MAPPER);
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2014 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.repo;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+
+import org.opendaylight.yangtools.concepts.Identifiable;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceFilter;
+import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+import org.opendaylight.yangtools.yang.model.repo.util.AbstractSchemaRepository;
+
+/**
+ * A {@link SchemaRepository} which allows sharing of {@link SchemaContext} as
+ * long as their specification is the same.
+ *
+ * Note: for current implementation, "same" means the same filter and the same
+ * set of {@link SourceIdentifier}s.
+ */
+@Beta
+public final class SharedSchemaRepository extends AbstractSchemaRepository implements Identifiable<String> {
+ private final LoadingCache<SchemaSourceFilter, SchemaContextFactory> cache =
+ CacheBuilder.newBuilder().softValues().build(new CacheLoader<SchemaSourceFilter, SchemaContextFactory>() {
+ @Override
+ public SchemaContextFactory load(final SchemaSourceFilter key) {
+ return new SharedSchemaContextFactory(SharedSchemaRepository.this, key);
+ }
+ });
+ private final String id;
+
+ public SharedSchemaRepository(final String id) {
+ this.id = Preconditions.checkNotNull(id);
+ }
+
+ @Override
+ public String getIdentifier() {
+ return id;
+ }
+
+ @Override
+ public SchemaContextFactory createSchemaContextFactory(final SchemaSourceFilter filter) {
+ return cache.getUnchecked(filter);
+ }
+
+ @Override
+ public String toString() {
+ return "SchemaRepository: " + id;
+ }
+}
* 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.model.api;
+package org.opendaylight.yangtools.yang.parser.repo;
-import java.util.EventListener;
+import org.opendaylight.yangtools.concepts.ObjectRegistration;
+import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
-/**
- * @deprecated Please use {@link SchemaContextListener} instead.
- */
-@Deprecated
-public interface SchemaServiceListener extends EventListener {
- void onGlobalContextUpdated(SchemaContext context);
-}
+public interface URLRegistration extends ObjectRegistration<YangTextSchemaSource> {
+ @Override
+ void close();
+}
\ No newline at end of file
import static com.google.common.base.Preconditions.checkArgument;
-import com.google.common.base.Function;
+import com.google.common.annotations.Beta;
import com.google.common.base.Objects.ToStringHelper;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
-import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.ImmutableMultimap;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Maps.EntryTransformer;
-import com.google.common.collect.Multimap;
-import com.google.common.collect.Multimaps;
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.CheckedFuture;
-import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.common.util.concurrent.MoreExecutors;
-import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Collection;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Queue;
-import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.atomic.AtomicReference;
-import javax.annotation.concurrent.GuardedBy;
-import javax.annotation.concurrent.ThreadSafe;
-
-import org.antlr.v4.runtime.ParserRuleContext;
-import org.antlr.v4.runtime.tree.ParseTreeWalker;
-import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
-import org.opendaylight.yangtools.concepts.ObjectRegistration;
-import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
+import org.opendaylight.yangtools.yang.model.repo.api.MissingSchemaSourceException;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaResolutionException;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceFilter;
import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
-import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceTransformationException;
-import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
-import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
-import org.opendaylight.yangtools.yang.parser.impl.YangParserListenerImpl;
-import org.opendaylight.yangtools.yang.parser.impl.util.YangModelDependencyInfo;
+import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceProvider;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistration;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry;
import org.opendaylight.yangtools.yang.parser.util.ASTSchemaSource;
import org.opendaylight.yangtools.yang.parser.util.TextToASTTransformer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-@ThreadSafe
-public class URLSchemaContextResolver {
+@Beta
+public class URLSchemaContextResolver implements SchemaSourceProvider<YangTextSchemaSource> {
private static final Logger LOG = LoggerFactory.getLogger(URLSchemaContextResolver.class);
- private static final Function<ASTSchemaSource, YangModelDependencyInfo> EXTRACT_DEPINFO = new Function<ASTSchemaSource, YangModelDependencyInfo>() {
- @Override
- public YangModelDependencyInfo apply(final ASTSchemaSource input) {
- return input.getDependencyInformation();
- }
- };
- private static final EntryTransformer<SourceIdentifier, Collection<YangModelDependencyInfo>, YangModelDependencyInfo> SQUASH_DEPINFO =
- new EntryTransformer<SourceIdentifier, Collection<YangModelDependencyInfo>, YangModelDependencyInfo>() {
- @Override
- public YangModelDependencyInfo transformEntry(final SourceIdentifier key, final Collection<YangModelDependencyInfo> value) {
- // FIXME: validate that all the info objects are the same
- return value.iterator().next();
- }
- };
- private static final Function<ASTSchemaSource, ParserRuleContext> EXTRACT_AST = new Function<ASTSchemaSource, ParserRuleContext>() {
- @Override
- public ParserRuleContext apply(final ASTSchemaSource input) {
- return input.getAST();
- }
- };
- private static final EntryTransformer<SourceIdentifier, Collection<ParserRuleContext>, ParserRuleContext> SQUASH_AST =
- new EntryTransformer<SourceIdentifier, Collection<ParserRuleContext>, ParserRuleContext>() {
- @Override
- public ParserRuleContext transformEntry(final SourceIdentifier key, final Collection<ParserRuleContext> value) {
- // FIXME: validate that all the info objects are the same
- return value.iterator().next();
- }
- };
-
- @GuardedBy("this")
- private final Multimap<SourceIdentifier, ASTSchemaSource> resolvedRegs = ArrayListMultimap.create();
- private final AtomicReference<Optional<SchemaContext>> currentSchemaContext = new AtomicReference<>(Optional.<SchemaContext>absent());
- private final Queue<URLRegistration> outstandingRegs = new ConcurrentLinkedQueue<>();
- private final TextToASTTransformer transformer;
- @GuardedBy("this")
- private Object version = new Object();
- @GuardedBy("this")
- private Object contextVersion = version;
-
- private final class URLRegistration extends AbstractObjectRegistration<URL> {
- @GuardedBy("this")
- private CheckedFuture<ASTSchemaSource, SchemaSourceTransformationException> future;
- @GuardedBy("this")
- private ASTSchemaSource result;
-
- protected URLRegistration(final URL url, final CheckedFuture<ASTSchemaSource, SchemaSourceTransformationException> future) {
- super(url);
- this.future = Preconditions.checkNotNull(future);
- }
-
- private synchronized boolean setResult(final ASTSchemaSource result) {
- if (future != null) {
- this.result = result;
- return true;
- } else {
- return false;
- }
- }
- @Override
- protected void removeRegistration() {
- // Cancel the future, but it may already be completing
- future.cancel(false);
-
- synchronized (this) {
- future = null;
- outstandingRegs.remove(this);
- if (result != null) {
- removeSchemaSource(result);
- }
- }
- }
- }
-
- private URLSchemaContextResolver(final TextToASTTransformer transformer) {
- this.transformer = Preconditions.checkNotNull(transformer);
+ private final Cache<SourceIdentifier, YangTextSchemaSource> sources = CacheBuilder.newBuilder().build();
+ private final Collection<SourceIdentifier> requiredSources = new ConcurrentLinkedDeque<>();
+ private final AtomicReference<Optional<SchemaContext>> currentSchemaContext =
+ new AtomicReference<>(Optional.<SchemaContext>absent());
+ private final SchemaSourceRegistry registry;
+ private final SchemaRepository repository;
+ private volatile Object version = new Object();
+ private volatile Object contextVersion = version;
+
+ private URLSchemaContextResolver(final SchemaRepository repository, final SchemaSourceRegistry registry) {
+ this.repository = Preconditions.checkNotNull(repository);
+ this.registry = Preconditions.checkNotNull(registry);
}
public static URLSchemaContextResolver create(final String name) {
- final ThreadFactory f = new ThreadFactoryBuilder().setDaemon(true).setNameFormat(name + "yangparser-%d").build();
- final ListeningExecutorService s = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor(f));
-
- return new URLSchemaContextResolver(TextToASTTransformer.create(s));
+ final SharedSchemaRepository sharedRepo = new SharedSchemaRepository(name);
+ return new URLSchemaContextResolver(sharedRepo, sharedRepo);
}
/**
* Register a URL hosting a YANG Text file.
*
* @param url URL
+ * @throws YangSyntaxErrorException When the YANG file is syntactically invalid
+ * @throws IOException when the URL is not readable
+ * @throws SchemaSourceException When parsing encounters general error
*/
- public ObjectRegistration<URL> registerSource(final URL url) {
+ public URLRegistration registerSource(final URL url) throws SchemaSourceException, IOException, YangSyntaxErrorException {
checkArgument(url != null, "Supplied URL must not be null");
- final SourceIdentifier id = SourceIdentifier.create(url.getFile().toString(), Optional.<String>absent());
- final YangTextSchemaSource text = new YangTextSchemaSource(id) {
+ final SourceIdentifier guessedId = new SourceIdentifier(url.getFile(), Optional.<String>absent());
+ final YangTextSchemaSource text = new YangTextSchemaSource(guessedId) {
@Override
public InputStream openStream() throws IOException {
return url.openStream();
}
};
- final CheckedFuture<ASTSchemaSource, SchemaSourceTransformationException> ast = transformer.transformSchemaSource(text);
- final URLRegistration reg = new URLRegistration(url, ast);
- outstandingRegs.add(reg);
+ final ASTSchemaSource ast = TextToASTTransformer.TRANSFORMATION.apply(text).checkedGet();
+ LOG.trace("Resolved URL {} to source {}", url, ast);
- Futures.addCallback(ast, new FutureCallback<ASTSchemaSource>() {
- @Override
- public void onSuccess(final ASTSchemaSource result) {
- LOG.trace("Resolved URL {} to source {}", url, result);
+ final SourceIdentifier resolvedId = ast.getIdentifier();
+ final SchemaSourceRegistration<YangTextSchemaSource> reg = registry.registerSchemaSource(this,
+ PotentialSchemaSource.create(resolvedId, YangTextSchemaSource.class, 0));
- outstandingRegs.remove(reg);
- if (reg.setResult(result)) {
- addSchemaSource(result);
- }
- }
+ requiredSources.add(resolvedId);
+ LOG.trace("Added source {} to schema context requirements", resolvedId);
+ version = new Object();
+ return new AbstractURLRegistration(text) {
@Override
- public void onFailure(final Throwable t) {
- LOG.warn("Failed to parse YANG text from {}, ignoring it", url, t);
- outstandingRegs.remove(reg);
+ protected void removeRegistration() {
+ requiredSources.remove(resolvedId);
+ LOG.trace("Removed source {} from schema context requirements", resolvedId);
+ version = new Object();
+ reg.close();
+ sources.invalidate(resolvedId);
}
- });
-
- return reg;
- }
-
- private synchronized void addSchemaSource(final ASTSchemaSource src) {
- resolvedRegs.put(src.getIdentifier(), src);
- version = new Object();
- }
-
- private synchronized void removeSchemaSource(final ASTSchemaSource src) {
- resolvedRegs.put(src.getIdentifier(), src);
- version = new Object();
+ };
}
/**
* new schema context was successfully built.
*/
public Optional<SchemaContext> getSchemaContext() {
- while (true) {
- Optional<SchemaContext> result;
- final Multimap<SourceIdentifier, ASTSchemaSource> sources;
- final Object v;
- synchronized (this) {
- result = currentSchemaContext.get();
- if (version == contextVersion) {
- return result;
+ final SchemaContextFactory factory = repository.createSchemaContextFactory(SchemaSourceFilter.ALWAYS_ACCEPT);
+ Optional<SchemaContext> sc;
+ Object v;
+ do {
+ // Spin get stable context version
+ Object cv;
+ do {
+ cv = contextVersion;
+ sc = currentSchemaContext.get();
+ if (version == cv) {
+ return sc;
}
+ } while (cv != contextVersion);
- sources = ImmutableMultimap.copyOf(resolvedRegs);
+ // Version has been updated
+ Collection<SourceIdentifier> sources;
+ do {
v = version;
- }
-
- if (!sources.isEmpty()) {
- final Map<SourceIdentifier, YangModelDependencyInfo> deps =
- Maps.transformEntries(Multimaps.transformValues(sources, EXTRACT_DEPINFO).asMap(), SQUASH_DEPINFO);
-
- LOG.debug("Resolving dependency reactor {}", deps);
- final DependencyResolver res = DependencyResolver.create(deps);
- if (!res.getUnresolvedSources().isEmpty()) {
- LOG.debug("Omitting models {} due to unsatisfied imports {}", res.getUnresolvedSources(), res.getUnsatisfiedImports());
+ sources = ImmutableList.copyOf(requiredSources);
+ } while (v != version);
+
+ while (true) {
+ final CheckedFuture<SchemaContext, SchemaResolutionException> f = factory.createSchemaContext(sources);
+ try {
+ sc = Optional.of(f.checkedGet());
+ break;
+ } catch (SchemaResolutionException e) {
+ LOG.info("Failed to fully assemble schema context for {}", sources, e);
+ sources = e.getResolvedSources();
}
-
- final Map<SourceIdentifier, ParserRuleContext> asts =
- Maps.transformEntries(Multimaps.transformValues(sources, EXTRACT_AST).asMap(), SQUASH_AST);
-
- final ParseTreeWalker walker = new ParseTreeWalker();
- final Map<SourceIdentifier, ModuleBuilder> sourceToBuilder = new LinkedHashMap<>();
-
- for (Entry<SourceIdentifier, ParserRuleContext> entry : asts.entrySet()) {
- final YangParserListenerImpl yangModelParser = new YangParserListenerImpl(entry.getKey().getName());
- walker.walk(yangModelParser, entry.getValue());
- ModuleBuilder moduleBuilder = yangModelParser.getModuleBuilder();
-
- moduleBuilder.setSource(sources.get(entry.getKey()).iterator().next().getYangText());
- sourceToBuilder.put(entry.getKey(), moduleBuilder);
- }
- LOG.debug("Modules ready for integration");
-
- final YangParserImpl parser = YangParserImpl.getInstance();
- final Collection<Module> modules = parser.buildModules(sourceToBuilder.values());
- LOG.debug("Integrated cross-references modules");
-
- result = Optional.of(parser.assembleContext(modules));
- } else {
- result = Optional.absent();
}
synchronized (this) {
- if (v == version) {
- currentSchemaContext.set(result);
- contextVersion = version;
- return result;
+ if (contextVersion == cv) {
+ currentSchemaContext.set(sc);
+ contextVersion = v;
}
-
- LOG.debug("Context version {} expected {}, retry", version, v);
}
+ } while (version == v);
+
+ return sc;
+ }
+
+ @Override
+ public CheckedFuture<YangTextSchemaSource, SchemaSourceException> getSource(final SourceIdentifier sourceIdentifier) {
+ final YangTextSchemaSource ret = sources.getIfPresent(sourceIdentifier);
+ if (ret == null) {
+ return Futures.<YangTextSchemaSource, SchemaSourceException>immediateFailedCheckedFuture(
+ new MissingSchemaSourceException("URL for " + sourceIdentifier + " not registered"));
}
+
+ return Futures.immediateCheckedFuture(ret);
}
}
*/
package org.opendaylight.yangtools.yang.parser.util;
+import com.google.common.annotations.Beta;
+import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
* passes basic semantic validation and we were able to extract dependency
* information.
*/
+@Beta
public final class ASTSchemaSource implements SchemaSourceRepresentation {
+ public static final Function<ASTSchemaSource, SourceIdentifier> GET_IDENTIFIER = new Function<ASTSchemaSource, SourceIdentifier>() {
+ @Override
+ public SourceIdentifier apply(final ASTSchemaSource input) {
+ return input.getIdentifier();
+ }
+ };
+ public static final Function<ASTSchemaSource, YangModelDependencyInfo> GET_DEPINFO = new Function<ASTSchemaSource, YangModelDependencyInfo>() {
+ @Override
+ public YangModelDependencyInfo apply(final ASTSchemaSource input) {
+ return input.getDependencyInformation();
+ }
+ };
+ public static final Function<ASTSchemaSource, ParserRuleContext> GET_AST = new Function<ASTSchemaSource, ParserRuleContext>() {
+ @Override
+ public ParserRuleContext apply(final ASTSchemaSource input) {
+ return input.getAST();
+ }
+ };
+
private final YangModelDependencyInfo depInfo;
private final ParserRuleContext tree;
private final SourceIdentifier id;
*/
package org.opendaylight.yangtools.yang.parser.util;
+import com.google.common.annotations.Beta;
import com.google.common.base.Charsets;
-import com.google.common.base.Function;
-import com.google.common.base.Preconditions;
import com.google.common.io.CharStreams;
import com.google.common.io.InputSupplier;
import com.google.common.util.concurrent.CheckedFuture;
import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListeningExecutorService;
import java.io.IOException;
import java.io.InputStream;
-import java.util.concurrent.Callable;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.YangContext;
-import org.opendaylight.yangtools.util.concurrent.ExceptionMapper;
import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
-import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceTransformationException;
-import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceTransformer;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry;
+import org.opendaylight.yangtools.yang.model.repo.util.SchemaSourceTransformer;
import org.opendaylight.yangtools.yang.parser.impl.YangModelBasicValidationListener;
import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
import org.slf4j.Logger;
/**
* A {@link SchemaSourceTransformer} which handles translation of models from
* {@link YangTextSchemaSource} representation into {@link ASTSchemaSource}.
- *
- * While this class is currently used explicitly, its long-term purpose is to
- * be registered with a {@link org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry}
- * and be invoked on demand when the processing pipeline requests the
- * ASTSchemaSource representation.
*/
-public final class TextToASTTransformer implements SchemaSourceTransformer<YangTextSchemaSource, ASTSchemaSource> {
- private static final Logger LOG = LoggerFactory.getLogger(TextToASTTransformer.class);
- private static final Function<Exception, SchemaSourceTransformationException> MAPPER = new ExceptionMapper<SchemaSourceTransformationException>("Source transformation", SchemaSourceTransformationException.class) {
+@Beta
+public final class TextToASTTransformer extends SchemaSourceTransformer<YangTextSchemaSource, ASTSchemaSource> {
+ public static final class TextToASTTransformation implements Transformation<YangTextSchemaSource, ASTSchemaSource> {
@Override
- protected SchemaSourceTransformationException newWithCause(final String message, final Throwable cause) {
- return new SchemaSourceTransformationException(message, cause);
- }
- };
-
- private final ListeningExecutorService executor;
-
- private TextToASTTransformer(final ListeningExecutorService executor) {
- this.executor = Preconditions.checkNotNull(executor);
- }
-
- public static final TextToASTTransformer create(final ListeningExecutorService executor) {
- return new TextToASTTransformer(executor);
- }
+ public CheckedFuture<ASTSchemaSource, SchemaSourceException> apply(final YangTextSchemaSource input) throws IOException, YangSyntaxErrorException {
+ try (InputStream is = input.openStream()) {
+ final YangContext ctx = YangParserImpl.parseYangSource(is);
+ LOG.debug("Model {} parsed successfully", input);
- @Override
- public Class<YangTextSchemaSource> getInputRepresentation() {
- return YangTextSchemaSource.class;
- }
-
- @Override
- public Class<ASTSchemaSource> getOutputRepresentation() {
- return ASTSchemaSource.class;
- }
+ final ParseTreeWalker walker = new ParseTreeWalker();
+ final YangModelBasicValidationListener validator = new YangModelBasicValidationListener();
+ walker.walk(validator, ctx);
+ LOG.debug("Model {} validated successfully", input);
- @Override
- public CheckedFuture<ASTSchemaSource, SchemaSourceTransformationException> transformSchemaSource(final YangTextSchemaSource source) {
- return Futures.makeChecked(executor.submit(new Callable<ASTSchemaSource>() {
- @Override
- public ASTSchemaSource call() throws IOException, YangSyntaxErrorException {
- try (InputStream is = source.openStream()) {
- final YangContext ctx = YangParserImpl.parseYangSource(is);
- LOG.debug("Model {} parsed successfully", source);
+ // Backwards compatibility
+ final String text = CharStreams.toString(
+ CharStreams.newReaderSupplier(new InputSupplier<InputStream>() {
+ @Override
+ public InputStream getInput() throws IOException {
+ return input.openStream();
+ }
+ }, Charsets.UTF_8));
- final ParseTreeWalker walker = new ParseTreeWalker();
- final YangModelBasicValidationListener validator = new YangModelBasicValidationListener();
- walker.walk(validator, ctx);
- LOG.debug("Model {} validated successfully", source);
+ return Futures.immediateCheckedFuture(ASTSchemaSource.create(input.getIdentifier().getName(), ctx, text));
+ }
+ }
+ };
- // Backwards compatibility
- final String text = CharStreams.toString(
- CharStreams.newReaderSupplier(new InputSupplier<InputStream>() {
- @Override
- public InputStream getInput() throws IOException {
- return source.openStream();
- }
- }, Charsets.UTF_8));
+ public static final TextToASTTransformation TRANSFORMATION = new TextToASTTransformation();
+ private static final Logger LOG = LoggerFactory.getLogger(TextToASTTransformer.class);
- return ASTSchemaSource.create(source.getIdentifier().getName(), ctx, text);
- }
- }
- }), MAPPER);
+ private TextToASTTransformer(final SchemaRepository provider, final SchemaSourceRegistry consumer) {
+ super(provider, YangTextSchemaSource.class, consumer, ASTSchemaSource.class, TRANSFORMATION);
}
- @Override
- public int getCost() {
- // We perform a direct translation, so the cost is 1.
- return 1;
+ public static final TextToASTTransformer create(final SchemaRepository provider, final SchemaSourceRegistry consumer) {
+ return new TextToASTTransformer(provider, consumer);
}
}
import org.opendaylight.yangtools.yang.model.util.EnumerationType;
import org.opendaylight.yangtools.yang.model.util.ExtendedType;
import org.opendaylight.yangtools.yang.model.util.IdentityrefType;
-import org.opendaylight.yangtools.yang.model.util.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.util.InstanceIdentifierType;
import org.opendaylight.yangtools.yang.model.util.UnionType;
public class TypesResolutionTest {
public void testInstanceIdentifier1() {
Module tested = TestUtils.findModule(testedModules, "custom-types-test");
LeafSchemaNode leaf = (LeafSchemaNode) tested.getDataChildByName("inst-id-leaf1");
- InstanceIdentifier leafType = (InstanceIdentifier) leaf.getType();
+ InstanceIdentifierType leafType = (InstanceIdentifierType) leaf.getType();
assertFalse(leafType.requireInstance());
assertEquals(1, leaf.getUnknownSchemaNodes().size());
}
public void testInstanceIdentifier2() {
Module tested = TestUtils.findModule(testedModules, "custom-types-test");
LeafSchemaNode leaf = (LeafSchemaNode) tested.getDataChildByName("inst-id-leaf2");
- InstanceIdentifier leafType = (InstanceIdentifier) leaf.getType();
+ InstanceIdentifierType leafType = (InstanceIdentifierType) leaf.getType();
assertTrue(leafType.requireInstance());
}