1 package org.opendaylight.yangtools.sal.binding.generator.impl
3 import javassist.ClassPool
4 import org.opendaylight.yangtools.yang.model.api.SchemaContext
5 import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener
6 import org.opendaylight.yangtools.sal.binding.generator.impl.BindingGeneratorImpl
8 import org.opendaylight.yangtools.sal.binding.model.api.Type
9 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder
10 import org.opendaylight.yangtools.yang.model.api.SchemaNode
11 import java.util.concurrent.ConcurrentHashMap
12 import org.opendaylight.yangtools.yang.data.api.CompositeNode
13 import org.opendaylight.yangtools.yang.binding.DataObject
14 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
15 import java.util.Map.Entry
16 import java.util.AbstractMap.SimpleEntry
17 import org.opendaylight.yangtools.yang.model.api.SchemaPath
18 import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil
19 import org.opendaylight.yangtools.yang.binding.DataContainer
20 import java.util.concurrent.ConcurrentMap
21 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType
22 import com.google.common.collect.HashMultimap
23 import com.google.common.util.concurrent.SettableFuture
24 import java.util.concurrent.Future
25 import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl
26 import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService
27 import org.slf4j.LoggerFactory
28 import org.opendaylight.yangtools.yang.data.impl.codec.ValueWithQName
29 import org.opendaylight.yangtools.yang.data.impl.codec.DataContainerCodec
30 import org.opendaylight.yangtools.binding.generator.util.Types
31 //import org.osgi.framework.BundleContext
32 import java.util.Hashtable
33 //import org.osgi.framework.ServiceRegistration
34 import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException
35 import java.util.concurrent.Callable
36 import org.opendaylight.yangtools.yang.binding.Augmentation
37 import org.opendaylight.yangtools.sal.binding.generator.util.YangSchemaUtils
38 import org.opendaylight.yangtools.yang.data.impl.codec.AugmentationCodec
39 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates
40 import java.util.ArrayList
41 import org.opendaylight.yangtools.yang.data.api.Node
42 import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
43 import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
44 import org.opendaylight.yangtools.yang.binding.RpcService
46 import org.opendaylight.yangtools.yang.common.QName
47 import com.google.common.collect.FluentIterable
48 import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil
50 class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingService, SchemaServiceListener, AutoCloseable {
55 private static val LOG = LoggerFactory.getLogger(RuntimeGeneratedMappingServiceImpl);
58 extension TransformerGenerator binding;
61 extension LazyGeneratedCodecRegistry registry;
64 val ConcurrentMap<Type, Type> typeDefinitions = new ConcurrentHashMap();
67 val ConcurrentMap<Type, GeneratedTypeBuilder> typeToDefinition = new ConcurrentHashMap();
70 val ConcurrentMap<Type, SchemaNode> typeToSchemaNode = new ConcurrentHashMap();
73 val ConcurrentMap<Type,Set<QName>> serviceTypeToRpc = new ConcurrentHashMap();
75 val promisedTypeDefinitions = HashMultimap.<Type, SettableFuture<GeneratedTypeBuilder>>create;
77 val promisedSchemas = HashMultimap.<Type, SettableFuture<SchemaNode>>create;
79 //ServiceRegistration<SchemaServiceListener> listenerRegistration
81 override onGlobalContextUpdated(SchemaContext arg0) {
82 recreateBindingContext(arg0);
83 registry.onGlobalContextUpdated(arg0);
86 def recreateBindingContext(SchemaContext schemaContext) {
87 val newBinding = new BindingGeneratorImpl();
88 newBinding.generateTypes(schemaContext);
90 for (entry : newBinding.moduleContexts.entrySet) {
92 registry.onModuleContextAdded(schemaContext, entry.key, entry.value);
93 binding.pathToType.putAll(entry.value.childNodes)
94 val module = entry.key;
95 val context = entry.value;
96 updateBindingFor(context.childNodes, schemaContext);
97 updateBindingFor(context.cases, schemaContext);
98 val namespace = BindingGeneratorUtil.moduleNamespaceToPackageName(module);
100 if(!module.rpcs.empty) {
101 val rpcs = FluentIterable.from(module.rpcs).transform[QName].toSet
102 val serviceClass = new ReferencedTypeImpl(namespace,BindingGeneratorUtil.parseToClassName(module.name)+"Service");
103 serviceTypeToRpc.put(serviceClass,rpcs);
106 val typedefs = context.typedefs;
107 for (typedef : typedefs.entrySet) {
108 val typeRef = new ReferencedTypeImpl(typedef.value.packageName,typedef.value.name)
109 binding.typeDefinitions.put(typeRef, typedef.value as GeneratedType);
110 val schemaNode = YangSchemaUtils.findTypeDefinition(schemaContext,typedef.key);
111 if(schemaNode != null) {
113 binding.typeToSchemaNode.put(typeRef,schemaNode);
115 LOG.error("Type definition for {} is not available",typedef.value);
119 val augmentations = context.augmentations;
120 for (augmentation : augmentations) {
121 binding.typeToDefinition.put(augmentation, augmentation);
124 binding.typeToAugmentation.putAll(context.typeToAugmentation);
128 override CompositeNode toDataDom(DataObject data) {
129 toCompositeNodeImpl(data);
132 override Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> toDataDom(
133 Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry) {
136 val key = toDataDom(entry.key)
137 var CompositeNode data;
138 if(Augmentation.isAssignableFrom(entry.key.targetType)) {
139 data = toCompositeNodeImpl(key,entry.value);
141 data = toCompositeNodeImpl(entry.value);
143 return new SimpleEntry(key, data);
145 } catch (Exception e) {
146 LOG.error("Error during serialization for {}.", entry.key,e);
151 private def CompositeNode toCompositeNodeImpl(DataObject object) {
152 val cls = object.implementedInterface;
154 val codec = registry.getCodecForDataObject(cls) as DataContainerCodec<DataObject>;
155 val ret = codec.serialize(new ValueWithQName(null, object));
156 return ret as CompositeNode;
160 private def CompositeNode toCompositeNodeImpl(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier identifier,DataObject object) {
162 //val cls = object.implementedInterface;
163 //waitForSchema(cls);
164 val last = identifier.path.last;
165 val codec = registry.getCodecForAugmentation(object.implementedInterface as Class) as AugmentationCodec;
166 val ret = codec.serialize(new ValueWithQName(last.nodeType, object));
167 if(last instanceof NodeIdentifierWithPredicates) {
168 val predicates = last as NodeIdentifierWithPredicates;
169 val newNodes = new ArrayList<Node<?>>(predicates.keyValues.size);
170 for(predicate : predicates.keyValues.entrySet) {
171 newNodes.add(new SimpleNodeTOImpl(predicate.key,null,predicate.value));
173 newNodes.addAll(ret.children);
174 return new CompositeNodeTOImpl(last.nodeType,null,newNodes);
176 return ret as CompositeNode;
179 private def void waitForSchema(Class<? extends DataContainer> class1) {
180 if(Augmentation.isAssignableFrom(class1)) {
181 /* FIXME: We should wait also for augmentations. Currently YANGTools does not provide correct
182 * mapping between java Augmentation classes and augmentations.
186 if(registry.isCodecAvailable(class1)) {
189 val ref = Types.typeForClass(class1);
190 getSchemaWithRetry(ref);
193 override org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toDataDom(
194 InstanceIdentifier<? extends DataObject> path) {
195 for (arg : path.path) {
196 waitForSchema(arg.type);
198 return registry.instanceIdentifierCodec.serialize(path);
201 override dataObjectFromDataDom(InstanceIdentifier<? extends DataObject> path, CompositeNode node) {
202 dataObjectFromDataDom(path.targetType,node) as DataObject;
205 override fromDataDom(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry) {
206 return tryDeserialization[ |
207 registry.instanceIdentifierCodec.deserialize(entry);
211 override getCodecRegistry() {
212 return getRegistry();
215 private static def <T> T tryDeserialization(Callable<T> deserializationBlock) throws DeserializationException {
217 deserializationBlock.call()
218 } catch (Exception e) {
220 // FIXME: Make this block providing more information.
221 throw new DeserializationException(e);
225 private def void updateBindingFor(Map<SchemaPath, GeneratedTypeBuilder> map, SchemaContext module) {
227 for (entry : map.entrySet) {
228 val schemaNode = SchemaContextUtil.findDataSchemaNode(module, entry.key);
230 //LOG.info("{} : {}",entry.key,entry.value.fullyQualifiedName)
231 val typeRef = new ReferencedTypeImpl(entry.value.packageName,entry.value.name)
232 typeToDefinition.put(typeRef, entry.value);
233 if (schemaNode != null) {
234 typeToSchemaNode.put(typeRef, schemaNode);
235 updatePromisedSchemas(typeRef, schemaNode);
241 public def void init() {
242 binding = new TransformerGenerator(pool);
243 registry = new LazyGeneratedCodecRegistry()
244 registry.generator = binding
246 //binding.staticFieldsInitializer = registry
247 binding.listener = registry
248 binding.typeToDefinition = typeToDefinition
249 binding.typeToSchemaNode = typeToSchemaNode
250 binding.typeDefinitions = typeDefinitions
251 // if (ctx !== null) {
252 // listenerRegistration = ctx.registerService(SchemaServiceListener, this, new Hashtable<String, String>());
256 override getRpcQNamesFor(Class<? extends RpcService> service) {
257 return serviceTypeToRpc.get(new ReferencedTypeImpl(service.package.name,service.simpleName));
260 private def getSchemaWithRetry(Type type) {
261 val typeDef = typeToSchemaNode.get(type);
262 if (typeDef !== null) {
265 LOG.trace("Thread blocked waiting for schema for: {}",type.fullyQualifiedName)
266 return type.getSchemaInFuture.get();
269 private def Future<SchemaNode> getSchemaInFuture(Type type) {
270 val future = SettableFuture.<SchemaNode>create()
271 promisedSchemas.put(type, future);
275 private def void updatePromisedSchemas(Type builder, SchemaNode schema) {
276 val ref = new ReferencedTypeImpl(builder.packageName, builder.name);
277 val futures = promisedSchemas.get(ref);
278 if (futures === null || futures.empty) {
281 for (future : futures) {
284 promisedSchemas.removeAll(builder);
287 override close() throws Exception {
288 //listenerRegistration?.unregister();
291 override dataObjectFromDataDom(Class<? extends DataContainer> container, CompositeNode domData) {
292 return tryDeserialization[ |
293 if (domData == null) {
296 val transformer = registry.getCodecForDataObject(container);
297 val ret = transformer.deserialize(domData)?.value as DataObject;