blob: 66b09c387a9dfea67839540c32197b8871f729b6 [file] [log] [blame]
Thomas Vachuska24c849c2014-10-27 09:53:05 -07001/*
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07002 * Copyright 2014 Open Networking Laboratory
Thomas Vachuska24c849c2014-10-27 09:53:05 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
Thomas Vachuska24c849c2014-10-27 09:53:05 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
Thomas Vachuska24c849c2014-10-27 09:53:05 -070015 */
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070016package org.onlab.util;
17
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -070018import java.nio.ByteBuffer;
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070019import java.util.ArrayList;
20import java.util.List;
21import java.util.concurrent.ConcurrentLinkedQueue;
22
23import org.apache.commons.lang3.tuple.Pair;
24
25import com.esotericsoftware.kryo.Kryo;
26import com.esotericsoftware.kryo.Serializer;
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -070027import com.esotericsoftware.kryo.io.ByteBufferInput;
28import com.esotericsoftware.kryo.io.ByteBufferOutput;
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070029import com.esotericsoftware.kryo.io.Input;
30import com.esotericsoftware.kryo.io.Output;
Yuta HIGUCHI633cf882014-10-20 09:10:28 -070031import com.esotericsoftware.kryo.pool.KryoFactory;
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070032import com.google.common.collect.ImmutableList;
33
34// TODO Add tests for this class.
35/**
36 * Pool of Kryo instances, with classes pre-registered.
37 */
38//@ThreadSafe
Yuta HIGUCHI633cf882014-10-20 09:10:28 -070039public final class KryoNamespace implements KryoFactory {
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070040
41 /**
42 * Default buffer size used for serialization.
43 *
44 * @see #serialize(Object)
45 */
46 public static final int DEFAULT_BUFFER_SIZE = 1 * 1000 * 1000;
47
48 private final ConcurrentLinkedQueue<Kryo> pool = new ConcurrentLinkedQueue<>();
49 private final ImmutableList<Pair<Class<?>, Serializer<?>>> registeredTypes;
50 private final boolean registrationRequired;
51
52 /**
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070053 * KryoNamespace builder.
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070054 */
55 //@NotThreadSafe
56 public static final class Builder {
57
58 private final List<Pair<Class<?>, Serializer<?>>> types = new ArrayList<>();
59
60 /**
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070061 * Builds a {@link KryoNamespace} instance.
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070062 *
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070063 * @return KryoNamespace
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070064 */
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070065 public KryoNamespace build() {
66 return new KryoNamespace(types);
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070067 }
68
69 /**
70 * Registers classes to be serialized using Kryo default serializer.
71 *
72 * @param expectedTypes list of classes
73 * @return this
74 */
75 public Builder register(final Class<?>... expectedTypes) {
76 for (Class<?> clazz : expectedTypes) {
77 types.add(Pair.<Class<?>, Serializer<?>>of(clazz, null));
78 }
79 return this;
80 }
81
82 /**
83 * Registers a class and it's serializer.
84 *
85 * @param clazz the class to register
86 * @param serializer serializer to use for the class
87 * @return this
88 */
89 public Builder register(final Class<?> clazz, Serializer<?> serializer) {
90 types.add(Pair.<Class<?>, Serializer<?>>of(clazz, serializer));
91 return this;
92 }
93
94 /**
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070095 * Registers all the class registered to given KryoNamespace.
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070096 *
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070097 * @param pool KryoNamespace
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070098 * @return this
99 */
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -0700100 public Builder register(final KryoNamespace pool) {
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700101 types.addAll(pool.registeredTypes);
102 return this;
103 }
104 }
105
106 /**
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -0700107 * Creates a new {@link KryoNamespace} builder.
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700108 *
109 * @return builder
110 */
111 public static Builder newBuilder() {
112 return new Builder();
113 }
114
115 /**
116 * Creates a Kryo instance pool.
117 *
118 * @param registerdTypes types to register
119 */
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -0700120 private KryoNamespace(final List<Pair<Class<?>, Serializer<?>>> registerdTypes) {
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700121 this.registeredTypes = ImmutableList.copyOf(registerdTypes);
122 // always true for now
123 this.registrationRequired = true;
124 }
125
126 /**
127 * Populates the Kryo pool.
128 *
129 * @param instances to add to the pool
130 * @return this
131 */
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -0700132 public KryoNamespace populate(int instances) {
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700133 List<Kryo> kryos = new ArrayList<>(instances);
134 for (int i = 0; i < instances; ++i) {
Yuta HIGUCHI633cf882014-10-20 09:10:28 -0700135 kryos.add(create());
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700136 }
137 pool.addAll(kryos);
138 return this;
139 }
140
141 /**
142 * Gets a Kryo instance from the pool.
143 *
144 * @return Kryo instance
145 */
146 public Kryo getKryo() {
147 Kryo kryo = pool.poll();
148 if (kryo == null) {
Yuta HIGUCHI633cf882014-10-20 09:10:28 -0700149 return create();
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700150 }
151 return kryo;
152 }
153
154 /**
155 * Returns a Kryo instance to the pool.
156 *
157 * @param kryo instance obtained from this pool.
158 */
159 public void putKryo(Kryo kryo) {
160 if (kryo != null) {
161 pool.add(kryo);
162 }
163 }
164
165 /**
166 * Serializes given object to byte array using Kryo instance in pool.
167 * <p>
168 * Note: Serialized bytes must be smaller than {@link #DEFAULT_BUFFER_SIZE}.
169 *
170 * @param obj Object to serialize
171 * @return serialized bytes
172 */
173 public byte[] serialize(final Object obj) {
174 return serialize(obj, DEFAULT_BUFFER_SIZE);
175 }
176
177 /**
178 * Serializes given object to byte array using Kryo instance in pool.
179 *
180 * @param obj Object to serialize
181 * @param bufferSize maximum size of serialized bytes
182 * @return serialized bytes
183 */
184 public byte[] serialize(final Object obj, final int bufferSize) {
185 Output out = new Output(bufferSize);
186 Kryo kryo = getKryo();
187 try {
188 kryo.writeClassAndObject(out, obj);
Yuta HIGUCHIcac919c2014-10-20 22:17:20 -0700189 out.flush();
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700190 return out.toBytes();
191 } finally {
192 putKryo(kryo);
193 }
194 }
195
196 /**
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -0700197 * Serializes given object to byte buffer using Kryo instance in pool.
198 *
199 * @param obj Object to serialize
200 * @param buffer to write to
201 */
202 public void serialize(final Object obj, final ByteBuffer buffer) {
203 ByteBufferOutput out = new ByteBufferOutput(buffer);
204 Kryo kryo = getKryo();
205 try {
206 kryo.writeClassAndObject(out, obj);
Yuta HIGUCHIcac919c2014-10-20 22:17:20 -0700207 out.flush();
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -0700208 } finally {
209 putKryo(kryo);
210 }
211 }
212
213 /**
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700214 * Deserializes given byte array to Object using Kryo instance in pool.
215 *
216 * @param bytes serialized bytes
217 * @param <T> deserialized Object type
218 * @return deserialized Object
219 */
220 public <T> T deserialize(final byte[] bytes) {
221 Input in = new Input(bytes);
222 Kryo kryo = getKryo();
223 try {
224 @SuppressWarnings("unchecked")
225 T obj = (T) kryo.readClassAndObject(in);
226 return obj;
227 } finally {
228 putKryo(kryo);
229 }
230 }
231
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -0700232 /**
233 * Deserializes given byte buffer to Object using Kryo instance in pool.
234 *
235 * @param buffer input with serialized bytes
236 * @param <T> deserialized Object type
237 * @return deserialized Object
238 */
239 public <T> T deserialize(final ByteBuffer buffer) {
240 ByteBufferInput in = new ByteBufferInput(buffer);
241 Kryo kryo = getKryo();
242 try {
243 @SuppressWarnings("unchecked")
244 T obj = (T) kryo.readClassAndObject(in);
245 return obj;
246 } finally {
247 putKryo(kryo);
248 }
249 }
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700250
251 /**
252 * Creates a Kryo instance with {@link #registeredTypes} pre-registered.
253 *
254 * @return Kryo instance
255 */
Yuta HIGUCHI633cf882014-10-20 09:10:28 -0700256 @Override
257 public Kryo create() {
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700258 Kryo kryo = new Kryo();
259 kryo.setRegistrationRequired(registrationRequired);
260 for (Pair<Class<?>, Serializer<?>> registry : registeredTypes) {
Yuta HIGUCHI533ec322014-09-30 13:29:52 -0700261 final Serializer<?> serializer = registry.getRight();
262 if (serializer == null) {
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700263 kryo.register(registry.getLeft());
264 } else {
Yuta HIGUCHI533ec322014-09-30 13:29:52 -0700265 kryo.register(registry.getLeft(), serializer);
266 if (serializer instanceof FamilySerializer) {
267 FamilySerializer<?> fser = (FamilySerializer<?>) serializer;
268 fser.registerFamilies(kryo);
269 }
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700270 }
271 }
272 return kryo;
273 }
Yuta HIGUCHI533ec322014-09-30 13:29:52 -0700274
275 /**
276 * Serializer implementation, which required registration of family of Classes.
277 * @param <T> base type of this serializer.
278 */
279 public abstract static class FamilySerializer<T> extends Serializer<T> {
280
281
282 public FamilySerializer(boolean acceptsNull) {
283 super(acceptsNull);
284 }
285
286 public FamilySerializer(boolean acceptsNull, boolean immutable) {
287 super(acceptsNull, immutable);
288 }
289
290 /**
291 * Registers other classes this Serializer supports.
292 *
293 * @param kryo instance to register classes to
294 */
295 public void registerFamilies(Kryo kryo) {
296 }
297 }
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700298}