2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.yangtools.sal.binding.generator.impl
10 import javassist.ClassPool
11 import org.opendaylight.yangtools.yang.model.api.SchemaContext
12 import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener
13 import org.opendaylight.yangtools.sal.binding.generator.impl.BindingGeneratorImpl
15 import java.util.Collections
16 import org.opendaylight.yangtools.sal.binding.model.api.Type
17 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder
18 import org.opendaylight.yangtools.yang.model.api.SchemaNode
19 import java.util.concurrent.ConcurrentHashMap
20 import org.opendaylight.yangtools.yang.data.api.CompositeNode
21 import org.opendaylight.yangtools.yang.binding.DataObject
22 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
23 import java.util.Map.Entry
24 import java.util.AbstractMap.SimpleEntry
25 import org.opendaylight.yangtools.yang.model.api.SchemaPath
26 import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil
27 import org.opendaylight.yangtools.yang.binding.DataContainer
28 import java.util.concurrent.ConcurrentMap
29 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType
30 import com.google.common.collect.HashMultimap
31 import com.google.common.util.concurrent.SettableFuture
32 import java.util.concurrent.Future
33 import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl
34 import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService
35 import org.slf4j.LoggerFactory
36 import org.opendaylight.yangtools.yang.data.impl.codec.ValueWithQName
37 import org.opendaylight.yangtools.yang.data.impl.codec.DataContainerCodec
38 import org.opendaylight.yangtools.binding.generator.util.Types
40 //import org.osgi.framework.BundleContext
41 import java.util.Hashtable
43 //import org.osgi.framework.ServiceRegistration
44 import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException
45 import java.util.concurrent.Callable
46 import org.opendaylight.yangtools.yang.binding.Augmentation
47 import org.opendaylight.yangtools.sal.binding.generator.util.YangSchemaUtils
48 import org.opendaylight.yangtools.yang.data.impl.codec.AugmentationCodec
49 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates
50 import java.util.ArrayList
51 import org.opendaylight.yangtools.yang.data.api.Node
52 import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
53 import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
54 import org.opendaylight.yangtools.yang.binding.RpcService
56 import org.opendaylight.yangtools.yang.common.QName
57 import com.google.common.collect.FluentIterable
58 import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil
59 import java.util.HashMap
61 import org.opendaylight.yangtools.yang.model.api.Module
62 import com.google.common.base.Optional
63 import org.opendaylight.yangtools.yang.binding.BindingMapping
64 import org.opendaylight.yangtools.yang.model.api.SchemaContextHolder
66 class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingService, SchemaServiceListener,
67 SchemaLock, AutoCloseable, SchemaContextHolder {
72 private static val LOG = LoggerFactory.getLogger(RuntimeGeneratedMappingServiceImpl);
75 extension TransformerGenerator binding;
78 extension LazyGeneratedCodecRegistry registry;
81 val ConcurrentMap<Type, Type> typeDefinitions = new ConcurrentHashMap();
84 val ConcurrentMap<Type, GeneratedTypeBuilder> typeToDefinition = new ConcurrentHashMap();
87 val ConcurrentMap<Type, SchemaNode> typeToSchemaNode = new ConcurrentHashMap();
90 val ConcurrentMap<Type, Set<QName>> serviceTypeToRpc = new ConcurrentHashMap();
92 val promisedTypeDefinitions = HashMultimap.<Type, SettableFuture<GeneratedTypeBuilder>>create;
94 val promisedTypes = HashMultimap.<Type, SettableFuture<Type>>create;
96 val GeneratedClassLoadingStrategy classLoadingStrategy;
99 var SchemaContext schemaContext;
102 this(GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy())
105 new(GeneratedClassLoadingStrategy strat){
106 classLoadingStrategy = strat
109 //ServiceRegistration<SchemaServiceListener> listenerRegistration
110 override onGlobalContextUpdated(SchemaContext arg0) {
112 recreateBindingContext(arg0);
113 registry.onGlobalContextUpdated(arg0);
116 def recreateBindingContext(SchemaContext schemaContext) {
117 val newBinding = new BindingGeneratorImpl();
118 newBinding.generateTypes(schemaContext);
120 for (entry : newBinding.moduleContexts.entrySet) {
122 registry.onModuleContextAdded(schemaContext, entry.key, entry.value);
123 binding.pathToType.putAll(entry.value.childNodes)
124 val module = entry.key;
125 val context = entry.value;
126 updateBindingFor(context.childNodes, schemaContext);
127 updateBindingFor(context.cases, schemaContext);
128 val namespace = BindingGeneratorUtil.moduleNamespaceToPackageName(module);
130 if (!module.rpcs.empty) {
131 val rpcs = FluentIterable.from(module.rpcs).transform[QName].toSet
132 val serviceClass = new ReferencedTypeImpl(namespace,
133 BindingGeneratorUtil.parseToClassName(module.name) + "Service");
134 serviceTypeToRpc.put(serviceClass, rpcs);
137 val typedefs = context.typedefs;
138 for (typedef : typedefs.entrySet) {
139 val typeRef = new ReferencedTypeImpl(typedef.value.packageName, typedef.value.name)
140 binding.typeDefinitions.put(typeRef, typedef.value as GeneratedType);
141 val schemaNode = YangSchemaUtils.findTypeDefinition(schemaContext, typedef.key);
142 if (schemaNode != null) {
144 binding.typeToSchemaNode.put(typeRef, schemaNode);
146 LOG.error("Type definition for {} is not available", typedef.value);
150 val augmentations = context.augmentations;
151 for (augmentation : augmentations) {
152 binding.typeToDefinition.put(augmentation, augmentation);
154 binding.typeToAugmentation.putAll(context.typeToAugmentation);
155 for (augmentation : augmentations) {
156 updatePromisedSchemas(augmentation);
161 override CompositeNode toDataDom(DataObject data) {
162 toCompositeNodeImpl(data);
165 override Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> toDataDom(
166 Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry) {
169 val key = toDataDom(entry.key)
170 var CompositeNode data;
171 if (Augmentation.isAssignableFrom(entry.key.targetType)) {
172 data = toCompositeNodeImplAugument(key, entry.value);
174 data = toCompositeNodeImpl(key, entry.value);
176 return new SimpleEntry(key, data);
178 } catch (Exception e) {
179 LOG.error("Error during serialization for {}.", entry.key, e);
184 private def CompositeNode toCompositeNodeImpl(DataObject object) {
185 val cls = object.implementedInterface;
187 val codec = registry.getCodecForDataObject(cls) as DataContainerCodec<DataObject>;
188 val ret = codec.serialize(new ValueWithQName(null, object));
189 return ret as CompositeNode;
192 private def CompositeNode toCompositeNodeImpl(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier identifier,
194 val last = identifier.path.last;
195 val cls = object.implementedInterface;
197 val codec = registry.getCodecForDataObject(cls) as DataContainerCodec<DataObject>;
198 val ret = codec.serialize(new ValueWithQName(last.nodeType, object));
199 return ret as CompositeNode;
202 private def CompositeNode toCompositeNodeImplAugument(
203 org.opendaylight.yangtools.yang.data.api.InstanceIdentifier identifier, DataObject object) {
205 //val cls = object.implementedInterface;
206 //waitForSchema(cls);
207 val last = identifier.path.last;
208 val codec = registry.getCodecForAugmentation(object.implementedInterface as Class) as AugmentationCodec;
209 val ret = codec.serialize(new ValueWithQName(last.nodeType, object));
210 if (last instanceof NodeIdentifierWithPredicates) {
211 val predicates = last as NodeIdentifierWithPredicates;
212 val newNodes = new ArrayList<Node<?>>(predicates.keyValues.size);
213 for (predicate : predicates.keyValues.entrySet) {
214 newNodes.add(new SimpleNodeTOImpl(predicate.key, null, predicate.value));
216 newNodes.addAll(ret.children);
217 return new CompositeNodeTOImpl(last.nodeType, null, newNodes);
219 return ret as CompositeNode;
222 override waitForSchema(Class class1) {
224 if (registry.isCodecAvailable(class1)) {
227 val ref = Types.typeForClass(class1);
228 getSchemaWithRetry(ref);
231 override org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toDataDom(
232 InstanceIdentifier<? extends DataObject> path) {
233 for (arg : path.path) {
234 waitForSchema(arg.type);
236 return registry.instanceIdentifierCodec.serialize(path);
239 override dataObjectFromDataDom(InstanceIdentifier<? extends DataObject> path, CompositeNode node) {
240 dataObjectFromDataDom(path.targetType, node) as DataObject;
243 override fromDataDom(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry) {
244 return tryDeserialization[ |
245 registry.instanceIdentifierCodec.deserialize(entry);
249 override getCodecRegistry() {
250 return getRegistry();
253 private static def <T> T tryDeserialization(Callable<T> deserializationBlock) throws DeserializationException {
255 deserializationBlock.call()
256 } catch (Exception e) {
258 // FIXME: Make this block providing more information.
259 throw new DeserializationException(e);
263 private def void updateBindingFor(Map<SchemaPath, GeneratedTypeBuilder> map, SchemaContext module) {
265 for (entry : map.entrySet) {
266 val schemaNode = SchemaContextUtil.findDataSchemaNode(module, entry.key);
268 //LOG.info("{} : {}",entry.key,entry.value.fullyQualifiedName)
269 val typeRef = new ReferencedTypeImpl(entry.value.packageName, entry.value.name)
270 typeToDefinition.put(typeRef, entry.value);
271 if (schemaNode != null) {
272 typeToSchemaNode.put(typeRef, schemaNode);
273 updatePromisedSchemas(entry.value);
279 public def void init() {
280 binding = new TransformerGenerator(pool);
281 registry = new LazyGeneratedCodecRegistry(this, classLoadingStrategy)
283 registry.generator = binding
285 //binding.staticFieldsInitializer = registry
286 binding.listener = registry
287 binding.typeToDefinition = typeToDefinition
288 binding.typeToSchemaNode = typeToSchemaNode
289 binding.typeDefinitions = typeDefinitions
291 // if (ctx !== null) {
292 // listenerRegistration = ctx.registerService(SchemaServiceListener, this, new Hashtable<String, String>());
296 override getRpcQNamesFor(Class<? extends RpcService> service) {
297 var serviceRef = serviceTypeToRpc.get(new ReferencedTypeImpl(service.package.name, service.simpleName))
298 if (serviceRef == null) {
299 serviceRef = Collections.emptySet()
304 private def void getSchemaWithRetry(Type type) {
305 if (typeToDefinition.containsKey(type)) {
308 LOG.info("Thread blocked waiting for schema for: {}", type.fullyQualifiedName)
309 type.waitForTypeDefinition.get();
310 LOG.info("Schema for {} became available, thread unblocked", type.fullyQualifiedName)
313 private def Future<Type> waitForTypeDefinition(Type type) {
314 val future = SettableFuture.<Type>create()
315 promisedTypes.put(type, future);
319 private def void updatePromisedSchemas(Type builder) {
320 val ref = new ReferencedTypeImpl(builder.packageName, builder.name);
321 val futures = promisedTypes.get(ref);
322 if (futures === null || futures.empty) {
325 for (future : futures) {
328 promisedTypes.removeAll(builder);
331 override close() throws Exception {
332 //listenerRegistration?.unregister();
335 override dataObjectFromDataDom(Class<? extends DataContainer> container, CompositeNode domData) {
336 return tryDeserialization[ |
337 if (domData == null) {
340 val transformer = registry.getCodecForDataObject(container);
341 val ret = transformer.deserialize(domData)?.value as DataObject;
346 override getRpcServiceClassFor(String namespace, String revision) {
347 val module = schemaContext?.findModuleByName(namespace.toString, QName.parseRevision(revision));
348 if (module == null) {
349 return Optional.absent();
352 val rpcTypeName = module.rpcServiceType;
353 if (rpcTypeName.present) {
354 val rpcClass = binding.classLoadingStrategy.loadClass(rpcTypeName.get.fullyQualifiedName);
355 return Optional.of(rpcClass as Class<? extends RpcService>);
357 } catch (Exception e) {
358 LOG.debug("RPC class not present for {},{}", namespace, revision, e);
360 return Optional.absent()
363 def Optional<Type> getRpcServiceType(Module module) {
364 val namespace = BindingGeneratorUtil.moduleNamespaceToPackageName(module);
365 if (module.rpcs.empty) {
366 return Optional.<Type>absent();
368 return Optional.<Type>of(
369 new ReferencedTypeImpl(namespace,
370 BindingMapping.getClassName(module.name) + BindingMapping.RPC_SERVICE_SUFFIX));