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.mdsal.binding.dom.codec.impl;
10 import com.google.common.base.Function;
11 import com.google.common.base.Optional;
12 import com.google.common.base.Preconditions;
13 import com.google.common.cache.CacheBuilder;
14 import com.google.common.cache.CacheLoader;
15 import com.google.common.cache.LoadingCache;
16 import java.io.IOException;
17 import java.util.AbstractMap.SimpleEntry;
18 import java.util.ArrayList;
19 import java.util.List;
20 import java.util.Map.Entry;
21 import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTree;
22 import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTreeFactory;
23 import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer;
24 import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeWriterFactory;
25 import org.opendaylight.mdsal.binding.dom.codec.gen.impl.DataObjectSerializerGenerator;
26 import org.opendaylight.mdsal.binding.generator.impl.ModuleInfoBackedContext;
27 import org.opendaylight.mdsal.binding.generator.util.BindingRuntimeContext;
28 import org.opendaylight.yangtools.concepts.Delegator;
29 import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
30 import org.opendaylight.yangtools.yang.binding.DataContainer;
31 import org.opendaylight.yangtools.yang.binding.DataObject;
32 import org.opendaylight.yangtools.yang.binding.DataObjectSerializer;
33 import org.opendaylight.yangtools.yang.binding.DataObjectSerializerImplementation;
34 import org.opendaylight.yangtools.yang.binding.DataObjectSerializerRegistry;
35 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
36 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
37 import org.opendaylight.yangtools.yang.binding.Notification;
38 import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
39 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
40 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
41 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
42 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
43 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
44 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
45 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
46 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
47 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
48 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
49 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
50 import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
51 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
52 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
56 public class BindingNormalizedNodeCodecRegistry implements DataObjectSerializerRegistry,
57 BindingCodecTreeFactory, BindingNormalizedNodeWriterFactory,
58 BindingNormalizedNodeSerializer {
59 private static final Logger LOG = LoggerFactory.getLogger(BindingNormalizedNodeCodecRegistry.class);
61 private final DataObjectSerializerGenerator generator;
62 private final LoadingCache<Class<? extends DataObject>, DataObjectSerializer> serializers;
63 private volatile BindingCodecContext codecContext;
65 public BindingNormalizedNodeCodecRegistry(final DataObjectSerializerGenerator generator) {
66 this.generator = Preconditions.checkNotNull(generator);
67 this.serializers = CacheBuilder.newBuilder().weakKeys().build(new GeneratorLoader());
71 public DataObjectSerializer getSerializer(final Class<? extends DataObject> type) {
72 return serializers.getUnchecked(type);
75 public BindingCodecTree getCodecContext() {
79 public void onBindingRuntimeContextUpdated(final BindingRuntimeContext context) {
80 codecContext = new BindingCodecContext(context, this);
81 generator.onBindingRuntimeContextUpdated(context);
85 public YangInstanceIdentifier toYangInstanceIdentifier(final InstanceIdentifier<?> binding) {
86 return codecContext.getInstanceIdentifierCodec().serialize(binding);
90 public InstanceIdentifier<?> fromYangInstanceIdentifier(final YangInstanceIdentifier dom) {
91 return codecContext.getInstanceIdentifierCodec().deserialize(dom);
95 public <T extends DataObject> Entry<YangInstanceIdentifier, NormalizedNode<?,?>> toNormalizedNode(
96 final InstanceIdentifier<T> path, final T data) {
97 final NormalizedNodeResult result = new NormalizedNodeResult();
98 // We create DOM stream writer which produces normalized nodes
99 final NormalizedNodeStreamWriter domWriter = ImmutableNormalizedNodeStreamWriter.from(result);
101 // We create Binding Stream Writer which translates from Binding to Normalized Nodes
102 final Entry<YangInstanceIdentifier, BindingStreamEventWriter> writeCtx = codecContext.newWriter(path,
105 // We get serializer which reads binding data and uses Binding To Normalized Node writer to write result
107 getSerializer(path.getTargetType()).serialize(data, writeCtx.getValue());
108 } catch (final IOException e) {
109 LOG.error("Unexpected failure while serializing path {} data {}", path, data, e);
110 throw new IllegalStateException("Failed to create normalized node", e);
112 return new SimpleEntry<>(writeCtx.getKey(),result.getResult());
116 public ContainerNode toNormalizedNodeNotification(final Notification data) {
117 final NormalizedNodeResult result = new NormalizedNodeResult();
118 // We create DOM stream writer which produces normalized nodes
119 final NormalizedNodeStreamWriter domWriter = ImmutableNormalizedNodeStreamWriter.from(result);
120 @SuppressWarnings({ "unchecked", "rawtypes" })
121 final Class<? extends DataObject> type = (Class) data.getImplementedInterface();
122 @SuppressWarnings({ "unchecked", "rawtypes" })
123 final BindingStreamEventWriter writer = newNotificationWriter((Class) type, domWriter);
125 // FIXME: Should be cast to DataObject necessary?
126 getSerializer(type).serialize((DataObject) data, writer);
127 } catch (final IOException e) {
128 LOG.error("Unexpected failure while serializing data {}", data, e);
129 throw new IllegalStateException("Failed to create normalized node", e);
131 return (ContainerNode) result.getResult();
136 public ContainerNode toNormalizedNodeRpcData(final DataContainer data) {
137 final NormalizedNodeResult result = new NormalizedNodeResult();
138 // We create DOM stream writer which produces normalized nodes
139 final NormalizedNodeStreamWriter domWriter = ImmutableNormalizedNodeStreamWriter.from(result);
140 @SuppressWarnings({ "unchecked", "rawtypes" })
141 final Class<? extends DataObject> type = (Class) data.getImplementedInterface();
142 final BindingStreamEventWriter writer = newRpcWriter(type, domWriter);
144 // FIXME: Should be cast to DataObject necessary?
145 getSerializer(type).serialize((DataObject) data, writer);
146 } catch (final IOException e) {
147 LOG.error("Unexpected failure while serializing data {}", data, e);
148 throw new IllegalStateException("Failed to create normalized node", e);
150 return (ContainerNode) result.getResult();
153 private static boolean isBindingRepresentable(final NormalizedNode<?, ?> data) {
154 if (data instanceof ChoiceNode) {
157 if (data instanceof LeafNode<?>) {
160 if (data instanceof LeafSetNode) {
163 if (data instanceof LeafSetEntryNode<?>) {
166 if (data instanceof MapNode) {
169 if (data instanceof UnkeyedListNode) {
177 public Entry<InstanceIdentifier<?>, DataObject> fromNormalizedNode(final YangInstanceIdentifier path,
178 final NormalizedNode<?, ?> data) {
179 if (!isBindingRepresentable(data)) {
183 final List<PathArgument> builder = new ArrayList<>();
184 final NodeCodecContext<?> codec = codecContext.getCodecContextNode(path, builder);
187 LOG.warn("Path {} does not have a binding equivalent, should have been caught earlier ({})", path,
193 final DataObject lazyObj = codec.deserialize(data);
194 final InstanceIdentifier<?> bindingPath = InstanceIdentifier.create(builder);
195 return new SimpleEntry<>(bindingPath, lazyObj);
199 public Notification fromNormalizedNodeNotification(final SchemaPath path, final ContainerNode data) {
200 final NotificationCodecContext<?> codec = codecContext.getNotificationContext(path);
201 return codec.deserialize(data);
205 public DataObject fromNormalizedNodeRpcData(final SchemaPath path, final ContainerNode data) {
206 final RpcInputCodec<?> codec = codecContext.getRpcInputCodec(path);
207 return codec.deserialize(data);
211 public Entry<YangInstanceIdentifier, BindingStreamEventWriter> newWriterAndIdentifier(
212 final InstanceIdentifier<?> path, final NormalizedNodeStreamWriter domWriter) {
213 return codecContext.newWriter(path, domWriter);
217 public BindingStreamEventWriter newWriter(final InstanceIdentifier<?> path,
218 final NormalizedNodeStreamWriter domWriter) {
219 return codecContext.newWriterWithoutIdentifier(path, domWriter);
223 public BindingStreamEventWriter newNotificationWriter(final Class<? extends Notification> notification,
224 final NormalizedNodeStreamWriter streamWriter) {
225 return codecContext.newNotificationWriter(notification, streamWriter);
229 public BindingStreamEventWriter newRpcWriter(final Class<? extends DataContainer> rpcInputOrOutput,
230 final NormalizedNodeStreamWriter streamWriter) {
231 return codecContext.newRpcWriter(rpcInputOrOutput,streamWriter);
234 public <T extends DataObject> Function<Optional<NormalizedNode<?, ?>>, Optional<T>> deserializeFunction(
235 final InstanceIdentifier<T> path) {
236 final DataObjectCodecContext<?,?> ctx = (DataObjectCodecContext<?,?>) codecContext.getCodecContextNode(path,
238 return new DeserializeFunction<>(ctx);
242 public BindingCodecTree create(final BindingRuntimeContext context) {
243 return new BindingCodecContext(context, this);
247 @SuppressWarnings("checkstyle:illegalCatch")
248 public BindingCodecTree create(final SchemaContext context, final Class<?>... bindingClasses) {
249 final ModuleInfoBackedContext strategy = ModuleInfoBackedContext.create();
250 for (final Class<?> bindingCls : bindingClasses) {
252 strategy.registerModuleInfo(BindingReflections.getModuleInfo(bindingCls));
253 } catch (final Exception e) {
254 throw new IllegalStateException(
255 "Could not create BindingRuntimeContext from class " + bindingCls.getName(), e);
258 final BindingRuntimeContext runtimeCtx = BindingRuntimeContext.create(strategy, context);
259 return create(runtimeCtx);
263 private static final class DeserializeFunction<T> implements Function<Optional<NormalizedNode<?, ?>>, Optional<T>> {
264 private final DataObjectCodecContext<?,?> ctx;
266 DeserializeFunction(final DataObjectCodecContext<?,?> ctx) {
270 @SuppressWarnings("unchecked")
272 public Optional<T> apply(final Optional<NormalizedNode<?, ?>> input) {
273 if (input.isPresent()) {
274 return Optional.of((T) ctx.deserialize(input.get()));
276 return Optional.absent();
280 private final class GeneratorLoader extends CacheLoader<Class<? extends DataContainer>, DataObjectSerializer> {
282 public DataObjectSerializer load(final Class<? extends DataContainer> key) throws Exception {
283 final DataObjectSerializerImplementation prototype = generator.getSerializer(key);
284 return new DataObjectSerializerProxy(prototype);
288 private final class DataObjectSerializerProxy
289 implements DataObjectSerializer, Delegator<DataObjectSerializerImplementation> {
290 private final DataObjectSerializerImplementation delegate;
292 DataObjectSerializerProxy(final DataObjectSerializerImplementation delegate) {
293 this.delegate = delegate;
297 public DataObjectSerializerImplementation getDelegate() {
302 public void serialize(final DataObject obj, final BindingStreamEventWriter stream) throws IOException {
303 delegate.serialize(BindingNormalizedNodeCodecRegistry.this, obj, stream);