import org.osgi.framework.BundleContext
import java.util.Hashtable
import org.osgi.framework.ServiceRegistration
+import org.opendaylight.controller.sal.binding.impl.connect.dom.DeserializationException
+import java.util.concurrent.Callable
+import org.opendaylight.yangtools.yang.binding.Augmentation
+import org.opendaylight.controller.sal.binding.impl.util.YangSchemaUtils
+import org.opendaylight.controller.sal.binding.dom.serializer.api.AugmentationCodec
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates
+import java.util.ArrayList
+import org.opendaylight.yangtools.yang.data.api.Node
+import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
+import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
+import org.opendaylight.yangtools.yang.binding.RpcService
+import java.util.Set
+import org.opendaylight.yangtools.yang.common.QName
+import com.google.common.collect.FluentIterable
+import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil
class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingService, SchemaServiceListener, AutoCloseable {
@Property
val ConcurrentMap<Type, SchemaNode> typeToSchemaNode = new ConcurrentHashMap();
+
+ @Property
+ val ConcurrentMap<Type,Set<QName>> serviceTypeToRpc = new ConcurrentHashMap();
val promisedTypeDefinitions = HashMultimap.<Type, SettableFuture<GeneratedTypeBuilder>>create;
val promisedSchemas = HashMultimap.<Type, SettableFuture<SchemaNode>>create;
-
+
ServiceRegistration<SchemaServiceListener> listenerRegistration
override onGlobalContextUpdated(SchemaContext arg0) {
for (entry : newBinding.moduleContexts.entrySet) {
registry.onModuleContextAdded(schemaContext, entry.key, entry.value);
-
- //val module = entry.key;
+ binding.pathToType.putAll(entry.value.childNodes)
+ val module = entry.key;
val context = entry.value;
updateBindingFor(context.childNodes, schemaContext);
updateBindingFor(context.cases, schemaContext);
+ val namespace = BindingGeneratorUtil.moduleNamespaceToPackageName(module);
+ if(!module.rpcs.empty) {
+ val rpcs = FluentIterable.from(module.rpcs).transform[QName].toSet
+ val serviceClass = new ReferencedTypeImpl(namespace,BindingGeneratorUtil.parseToClassName(module.name)+"Service");
+ serviceTypeToRpc.put(serviceClass,rpcs);
+ }
val typedefs = context.typedefs;
- for (typedef : typedefs.values) {
- binding.typeDefinitions.put(typedef, typedef as GeneratedType);
+ for (typedef : typedefs.entrySet) {
+ val typeRef = new ReferencedTypeImpl(typedef.value.packageName,typedef.value.name)
+ binding.typeDefinitions.put(typeRef, typedef.value as GeneratedType);
+ val schemaNode = YangSchemaUtils.findTypeDefinition(schemaContext,typedef.key);
+ if(schemaNode != null) {
+
+ binding.typeToSchemaNode.put(typeRef,schemaNode);
+ } else {
+ LOG.error("Type definition for {} is not available",typedef.value);
+ }
+
}
val augmentations = context.augmentations;
for (augmentation : augmentations) {
binding.typeToDefinition.put(augmentation, augmentation);
}
-
+
binding.typeToAugmentation.putAll(context.typeToAugmentation);
}
}
override Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> toDataDom(
Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry) {
+
+ try {
val key = toDataDom(entry.key)
- val data = toCompositeNodeImpl(entry.value);
+ var CompositeNode data;
+ if(Augmentation.isAssignableFrom(entry.key.targetType)) {
+ data = toCompositeNodeImpl(key,entry.value);
+ } else {
+ data = toCompositeNodeImpl(entry.value);
+ }
return new SimpleEntry(key, data);
+
+ } catch (Exception e) {
+ LOG.error("Error during serialization for {}.", entry.key,e);
+ throw e;
+ }
}
private def CompositeNode toCompositeNodeImpl(DataObject object) {
val ret = codec.serialize(new ValueWithQName(null, object));
return ret as CompositeNode;
}
+
+
+ private def CompositeNode toCompositeNodeImpl(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier identifier,DataObject object) {
+
+ //val cls = object.implementedInterface;
+ //waitForSchema(cls);
+ val last = identifier.path.last;
+ val codec = registry.getCodecForAugmentation(object.implementedInterface as Class) as AugmentationCodec;
+ val ret = codec.serialize(new ValueWithQName(last.nodeType, object));
+ if(last instanceof NodeIdentifierWithPredicates) {
+ val predicates = last as NodeIdentifierWithPredicates;
+ val newNodes = new ArrayList<Node<?>>(predicates.keyValues.size);
+ for(predicate : predicates.keyValues.entrySet) {
+ newNodes.add(new SimpleNodeTOImpl(predicate.key,null,predicate.value));
+ }
+ newNodes.addAll(ret.children);
+ return new CompositeNodeTOImpl(last.nodeType,null,newNodes);
+ }
+ return ret as CompositeNode;
+ }
- private def waitForSchema(Class<? extends DataContainer> class1) {
+ private def void waitForSchema(Class<? extends DataContainer> class1) {
+ if(Augmentation.isAssignableFrom(class1)) {
+ /* FIXME: We should wait also for augmentations. Currently YANGTools does not provide correct
+ * mapping between java Augmentation classes and augmentations.
+ */
+ return;
+ }
+ if(registry.isCodecAvailable(class1)) {
+ return;
+ }
val ref = Types.typeForClass(class1);
getSchemaWithRetry(ref);
}
}
override dataObjectFromDataDom(InstanceIdentifier<? extends DataObject> path, CompositeNode node) {
- if (node == null) {
- return null;
- }
- val targetType = path.targetType
- val transformer = registry.getCodecForDataObject(targetType);
- val ret = transformer.deserialize(node)?.value as DataObject;
- return ret;
+ dataObjectFromDataDom(path.targetType,node) as DataObject;
}
-
+
override fromDataDom(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry) {
- return registry.instanceIdentifierCodec.deserialize(entry);
+ return tryDeserialization[ |
+ registry.instanceIdentifierCodec.deserialize(entry);
+ ]
+ }
+
+ private static def <T> T tryDeserialization(Callable<T> deserializationBlock) throws DeserializationException {
+ try {
+ deserializationBlock.call()
+ } catch (Exception e) {
+
+ // FIXME: Make this block providing more information.
+ throw new DeserializationException(e);
+ }
}
private def void updateBindingFor(Map<SchemaPath, GeneratedTypeBuilder> map, SchemaContext module) {
+
for (entry : map.entrySet) {
val schemaNode = SchemaContextUtil.findDataSchemaNode(module, entry.key);
+
//LOG.info("{} : {}",entry.key,entry.value.fullyQualifiedName)
+ val typeRef = new ReferencedTypeImpl(entry.value.packageName,entry.value.name)
+ typeToDefinition.put(typeRef, entry.value);
if (schemaNode != null) {
- typeToSchemaNode.put(entry.value, schemaNode);
- typeToDefinition.put(entry.value, entry.value);
- updatePromisedSchemas(entry.value, schemaNode);
+ typeToSchemaNode.put(typeRef, schemaNode);
+ updatePromisedSchemas(typeRef, schemaNode);
}
+
}
}
binding.typeToDefinition = typeToDefinition
binding.typeToSchemaNode = typeToSchemaNode
binding.typeDefinitions = typeDefinitions
- if(ctx !== null) {
- listenerRegistration = ctx.registerService(SchemaServiceListener,this,new Hashtable<String,String>());
- }
- }
-
- private def getTypeDefinition(Type type) {
- val typeDef = typeToDefinition.get(type);
- if (typeDef !== null) {
- return typeDef;
+ if (ctx !== null) {
+ listenerRegistration = ctx.registerService(SchemaServiceListener, this, new Hashtable<String, String>());
}
- return type.getTypeDefInFuture.get();
- }
-
- private def Future<GeneratedTypeBuilder> getTypeDefInFuture(Type type) {
- val future = SettableFuture.<GeneratedTypeBuilder>create()
- promisedTypeDefinitions.put(type, future);
- return future;
}
-
- private def void updatePromisedTypeDefinitions(GeneratedTypeBuilder builder) {
- val futures = promisedTypeDefinitions.get(builder);
- if (futures === null || futures.empty) {
- return;
- }
- for (future : futures) {
- future.set(builder);
- }
- promisedTypeDefinitions.removeAll(builder);
+
+ override getRpcQNamesFor(Class<? extends RpcService> service) {
+ return serviceTypeToRpc.get(new ReferencedTypeImpl(service.package.name,service.simpleName));
}
private def getSchemaWithRetry(Type type) {
if (typeDef !== null) {
return typeDef;
}
+ LOG.info("Thread blocked waiting for schema for: {}",type.fullyQualifiedName)
return type.getSchemaInFuture.get();
}
}
promisedSchemas.removeAll(builder);
}
-
+
override close() throws Exception {
listenerRegistration?.unregister();
}
+ override dataObjectFromDataDom(Class<? extends DataContainer> container, CompositeNode domData) {
+ return tryDeserialization[ |
+ if (domData == null) {
+ return null;
+ }
+ val transformer = registry.getCodecForDataObject(container);
+ val ret = transformer.deserialize(domData)?.value as DataObject;
+ return ret;
+ ]
+ }
+
}