Merge "BUG-2679 Workaround for wrong nagasena encode/decode with reused transmogrifier"
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / main / java / org / opendaylight / controller / cluster / datastore / utils / SerializationUtils.java
1 /*
2  * Copyright (c) 2014 Brocade Communications Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.cluster.datastore.utils;
9
10 import com.google.common.base.Preconditions;
11 import com.google.protobuf.InvalidProtocolBufferException;
12 import java.io.ByteArrayInputStream;
13 import java.io.ByteArrayOutputStream;
14 import java.io.DataInput;
15 import java.io.DataInputStream;
16 import java.io.DataOutput;
17 import java.io.DataOutputStream;
18 import java.io.IOException;
19 import org.opendaylight.controller.cluster.datastore.node.NormalizedNodeToNodeCodec;
20 import org.opendaylight.controller.cluster.datastore.node.utils.stream.InvalidNormalizedNodeStreamException;
21 import org.opendaylight.controller.cluster.datastore.node.utils.stream.NormalizedNodeInputStreamReader;
22 import org.opendaylight.controller.cluster.datastore.node.utils.stream.NormalizedNodeOutputStreamWriter;
23 import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages;
24 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
25 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
26
27 /**
28  * Provides various utility methods for serialization and de-serialization.
29  *
30  * @author Thomas Pantelis
31  */
32 public final class SerializationUtils {
33     public static ThreadLocal<NormalizedNodeOutputStreamWriter> REUSABLE_WRITER_TL = new ThreadLocal<>();
34     public static ThreadLocal<NormalizedNodeInputStreamReader> REUSABLE_READER_TL = new ThreadLocal<>();
35
36     public static interface Applier<T> {
37         void apply(T instance, YangInstanceIdentifier path, NormalizedNode<?, ?> node);
38     }
39
40     private static NormalizedNodeOutputStreamWriter streamWriter(DataOutput out) throws IOException {
41         NormalizedNodeOutputStreamWriter streamWriter = REUSABLE_WRITER_TL.get();
42         if(streamWriter == null) {
43             streamWriter = new NormalizedNodeOutputStreamWriter(out);
44         }
45
46         return streamWriter;
47     }
48
49     private static NormalizedNodeInputStreamReader streamReader(DataInput in) throws IOException {
50         NormalizedNodeInputStreamReader streamWriter = REUSABLE_READER_TL.get();
51         if(streamWriter == null) {
52             streamWriter = new NormalizedNodeInputStreamReader(in);
53         }
54
55         return streamWriter;
56     }
57
58     public static void serializePathAndNode(YangInstanceIdentifier path, NormalizedNode<?, ?> node,
59             DataOutput out) {
60         Preconditions.checkNotNull(path);
61         Preconditions.checkNotNull(node);
62         try {
63             NormalizedNodeOutputStreamWriter streamWriter = streamWriter(out);
64             streamWriter.writeNormalizedNode(node);
65             streamWriter.writeYangInstanceIdentifier(path);
66         } catch (IOException e) {
67             throw new IllegalArgumentException(String.format("Error serializing path %s and Node %s",
68                     path, node), e);
69         }
70     }
71
72     public static <T> void deserializePathAndNode(DataInput in, T instance, Applier<T> applier) {
73         try {
74             NormalizedNodeInputStreamReader streamReader = streamReader(in);
75             NormalizedNode<?, ?> node = streamReader.readNormalizedNode();
76             YangInstanceIdentifier path = streamReader.readYangInstanceIdentifier();
77             applier.apply(instance, path, node);
78         } catch (IOException e) {
79             throw new IllegalArgumentException("Error deserializing path and Node", e);
80         }
81     }
82
83     public static void serializeNormalizedNode(NormalizedNode<?, ?> node, DataOutput out) {
84         try {
85             out.writeBoolean(node != null);
86             if(node != null) {
87                 NormalizedNodeOutputStreamWriter streamWriter = streamWriter(out);
88                 streamWriter.writeNormalizedNode(node);
89             }
90         } catch (IOException e) {
91             throw new IllegalArgumentException(String.format("Error serializing NormalizedNode %s",
92                     node), e);
93         }
94     }
95
96     public static NormalizedNode<?, ?> deserializeNormalizedNode(DataInput in) {
97         try {
98             return tryDeserializeNormalizedNode(in);
99         } catch (IOException e) {
100             throw new IllegalArgumentException("Error deserializing NormalizedNode", e);
101         }
102     }
103
104     private static NormalizedNode<?, ?> tryDeserializeNormalizedNode(DataInput in) throws IOException {
105         boolean present = in.readBoolean();
106         if(present) {
107             NormalizedNodeInputStreamReader streamReader = streamReader(in);
108             return streamReader.readNormalizedNode();
109         }
110
111         return null;
112     }
113
114     public static NormalizedNode<?, ?> deserializeNormalizedNode(byte [] bytes) {
115         NormalizedNode<?, ?> node = null;
116         try {
117             node = tryDeserializeNormalizedNode(new DataInputStream(new ByteArrayInputStream(bytes)));
118         } catch(InvalidNormalizedNodeStreamException e) {
119             // Probably from legacy protobuf serialization - try that.
120             try {
121                 NormalizedNodeMessages.Node serializedNode = NormalizedNodeMessages.Node.parseFrom(bytes);
122                 node =  new NormalizedNodeToNodeCodec(null).decode(serializedNode);
123             } catch (InvalidProtocolBufferException e2) {
124                 throw new IllegalArgumentException("Error deserializing NormalizedNode", e);
125             }
126         } catch (IOException e) {
127             throw new IllegalArgumentException("Error deserializing NormalizedNode", e);
128         }
129
130         return node;
131     }
132
133     public static byte [] serializeNormalizedNode(NormalizedNode<?, ?> node) {
134         ByteArrayOutputStream bos = new ByteArrayOutputStream();
135         serializeNormalizedNode(node, new DataOutputStream(bos));
136         return bos.toByteArray();
137     }
138
139     public static void serializePath(YangInstanceIdentifier path, DataOutput out) {
140         Preconditions.checkNotNull(path);
141         try {
142             NormalizedNodeOutputStreamWriter streamWriter = streamWriter(out);
143             streamWriter.writeYangInstanceIdentifier(path);
144         } catch (IOException e) {
145             throw new IllegalArgumentException(String.format("Error serializing path %s", path), e);
146         }
147     }
148
149     public static YangInstanceIdentifier deserializePath(DataInput in) {
150         try {
151             NormalizedNodeInputStreamReader streamReader = streamReader(in);
152             return streamReader.readYangInstanceIdentifier();
153         } catch (IOException e) {
154             throw new IllegalArgumentException("Error deserializing path", e);
155         }
156     }
157 }