blob: 2f2b79f4d6ae9aa1b08e50774e308fb929a80182 [file] [log] [blame]
Thomas Vachuska24c849c2014-10-27 09:53:05 -07001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070019package org.onlab.util;
20
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -070021import java.nio.ByteBuffer;
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070022import java.util.ArrayList;
23import java.util.List;
24import java.util.concurrent.ConcurrentLinkedQueue;
25
26import org.apache.commons.lang3.tuple.Pair;
27
28import com.esotericsoftware.kryo.Kryo;
29import com.esotericsoftware.kryo.Serializer;
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -070030import com.esotericsoftware.kryo.io.ByteBufferInput;
31import com.esotericsoftware.kryo.io.ByteBufferOutput;
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070032import com.esotericsoftware.kryo.io.Input;
33import com.esotericsoftware.kryo.io.Output;
Yuta HIGUCHI633cf882014-10-20 09:10:28 -070034import com.esotericsoftware.kryo.pool.KryoFactory;
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070035import com.google.common.collect.ImmutableList;
36
37// TODO Add tests for this class.
38/**
39 * Pool of Kryo instances, with classes pre-registered.
40 */
41//@ThreadSafe
Yuta HIGUCHI633cf882014-10-20 09:10:28 -070042public final class KryoNamespace implements KryoFactory {
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070043
44 /**
45 * Default buffer size used for serialization.
46 *
47 * @see #serialize(Object)
48 */
49 public static final int DEFAULT_BUFFER_SIZE = 1 * 1000 * 1000;
50
51 private final ConcurrentLinkedQueue<Kryo> pool = new ConcurrentLinkedQueue<>();
52 private final ImmutableList<Pair<Class<?>, Serializer<?>>> registeredTypes;
53 private final boolean registrationRequired;
54
55 /**
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070056 * KryoNamespace builder.
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070057 */
58 //@NotThreadSafe
59 public static final class Builder {
60
61 private final List<Pair<Class<?>, Serializer<?>>> types = new ArrayList<>();
62
63 /**
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070064 * Builds a {@link KryoNamespace} instance.
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070065 *
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070066 * @return KryoNamespace
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070067 */
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070068 public KryoNamespace build() {
69 return new KryoNamespace(types);
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070070 }
71
72 /**
73 * Registers classes to be serialized using Kryo default serializer.
74 *
75 * @param expectedTypes list of classes
76 * @return this
77 */
78 public Builder register(final Class<?>... expectedTypes) {
79 for (Class<?> clazz : expectedTypes) {
80 types.add(Pair.<Class<?>, Serializer<?>>of(clazz, null));
81 }
82 return this;
83 }
84
85 /**
86 * Registers a class and it's serializer.
87 *
88 * @param clazz the class to register
89 * @param serializer serializer to use for the class
90 * @return this
91 */
92 public Builder register(final Class<?> clazz, Serializer<?> serializer) {
93 types.add(Pair.<Class<?>, Serializer<?>>of(clazz, serializer));
94 return this;
95 }
96
97 /**
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070098 * Registers all the class registered to given KryoNamespace.
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070099 *
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -0700100 * @param pool KryoNamespace
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700101 * @return this
102 */
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -0700103 public Builder register(final KryoNamespace pool) {
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700104 types.addAll(pool.registeredTypes);
105 return this;
106 }
107 }
108
109 /**
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -0700110 * Creates a new {@link KryoNamespace} builder.
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700111 *
112 * @return builder
113 */
114 public static Builder newBuilder() {
115 return new Builder();
116 }
117
118 /**
119 * Creates a Kryo instance pool.
120 *
121 * @param registerdTypes types to register
122 */
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -0700123 private KryoNamespace(final List<Pair<Class<?>, Serializer<?>>> registerdTypes) {
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700124 this.registeredTypes = ImmutableList.copyOf(registerdTypes);
125 // always true for now
126 this.registrationRequired = true;
127 }
128
129 /**
130 * Populates the Kryo pool.
131 *
132 * @param instances to add to the pool
133 * @return this
134 */
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -0700135 public KryoNamespace populate(int instances) {
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700136 List<Kryo> kryos = new ArrayList<>(instances);
137 for (int i = 0; i < instances; ++i) {
Yuta HIGUCHI633cf882014-10-20 09:10:28 -0700138 kryos.add(create());
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700139 }
140 pool.addAll(kryos);
141 return this;
142 }
143
144 /**
145 * Gets a Kryo instance from the pool.
146 *
147 * @return Kryo instance
148 */
149 public Kryo getKryo() {
150 Kryo kryo = pool.poll();
151 if (kryo == null) {
Yuta HIGUCHI633cf882014-10-20 09:10:28 -0700152 return create();
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700153 }
154 return kryo;
155 }
156
157 /**
158 * Returns a Kryo instance to the pool.
159 *
160 * @param kryo instance obtained from this pool.
161 */
162 public void putKryo(Kryo kryo) {
163 if (kryo != null) {
164 pool.add(kryo);
165 }
166 }
167
168 /**
169 * Serializes given object to byte array using Kryo instance in pool.
170 * <p>
171 * Note: Serialized bytes must be smaller than {@link #DEFAULT_BUFFER_SIZE}.
172 *
173 * @param obj Object to serialize
174 * @return serialized bytes
175 */
176 public byte[] serialize(final Object obj) {
177 return serialize(obj, DEFAULT_BUFFER_SIZE);
178 }
179
180 /**
181 * Serializes given object to byte array using Kryo instance in pool.
182 *
183 * @param obj Object to serialize
184 * @param bufferSize maximum size of serialized bytes
185 * @return serialized bytes
186 */
187 public byte[] serialize(final Object obj, final int bufferSize) {
188 Output out = new Output(bufferSize);
189 Kryo kryo = getKryo();
190 try {
191 kryo.writeClassAndObject(out, obj);
Yuta HIGUCHIcac919c2014-10-20 22:17:20 -0700192 out.flush();
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700193 return out.toBytes();
194 } finally {
195 putKryo(kryo);
196 }
197 }
198
199 /**
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -0700200 * Serializes given object to byte buffer using Kryo instance in pool.
201 *
202 * @param obj Object to serialize
203 * @param buffer to write to
204 */
205 public void serialize(final Object obj, final ByteBuffer buffer) {
206 ByteBufferOutput out = new ByteBufferOutput(buffer);
207 Kryo kryo = getKryo();
208 try {
209 kryo.writeClassAndObject(out, obj);
Yuta HIGUCHIcac919c2014-10-20 22:17:20 -0700210 out.flush();
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -0700211 } finally {
212 putKryo(kryo);
213 }
214 }
215
216 /**
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700217 * Deserializes given byte array to Object using Kryo instance in pool.
218 *
219 * @param bytes serialized bytes
220 * @param <T> deserialized Object type
221 * @return deserialized Object
222 */
223 public <T> T deserialize(final byte[] bytes) {
224 Input in = new Input(bytes);
225 Kryo kryo = getKryo();
226 try {
227 @SuppressWarnings("unchecked")
228 T obj = (T) kryo.readClassAndObject(in);
229 return obj;
230 } finally {
231 putKryo(kryo);
232 }
233 }
234
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -0700235 /**
236 * Deserializes given byte buffer to Object using Kryo instance in pool.
237 *
238 * @param buffer input with serialized bytes
239 * @param <T> deserialized Object type
240 * @return deserialized Object
241 */
242 public <T> T deserialize(final ByteBuffer buffer) {
243 ByteBufferInput in = new ByteBufferInput(buffer);
244 Kryo kryo = getKryo();
245 try {
246 @SuppressWarnings("unchecked")
247 T obj = (T) kryo.readClassAndObject(in);
248 return obj;
249 } finally {
250 putKryo(kryo);
251 }
252 }
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700253
254 /**
255 * Creates a Kryo instance with {@link #registeredTypes} pre-registered.
256 *
257 * @return Kryo instance
258 */
Yuta HIGUCHI633cf882014-10-20 09:10:28 -0700259 @Override
260 public Kryo create() {
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700261 Kryo kryo = new Kryo();
262 kryo.setRegistrationRequired(registrationRequired);
263 for (Pair<Class<?>, Serializer<?>> registry : registeredTypes) {
Yuta HIGUCHI533ec322014-09-30 13:29:52 -0700264 final Serializer<?> serializer = registry.getRight();
265 if (serializer == null) {
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700266 kryo.register(registry.getLeft());
267 } else {
Yuta HIGUCHI533ec322014-09-30 13:29:52 -0700268 kryo.register(registry.getLeft(), serializer);
269 if (serializer instanceof FamilySerializer) {
270 FamilySerializer<?> fser = (FamilySerializer<?>) serializer;
271 fser.registerFamilies(kryo);
272 }
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700273 }
274 }
275 return kryo;
276 }
Yuta HIGUCHI533ec322014-09-30 13:29:52 -0700277
278 /**
279 * Serializer implementation, which required registration of family of Classes.
280 * @param <T> base type of this serializer.
281 */
282 public abstract static class FamilySerializer<T> extends Serializer<T> {
283
284
285 public FamilySerializer(boolean acceptsNull) {
286 super(acceptsNull);
287 }
288
289 public FamilySerializer(boolean acceptsNull, boolean immutable) {
290 super(acceptsNull, immutable);
291 }
292
293 /**
294 * Registers other classes this Serializer supports.
295 *
296 * @param kryo instance to register classes to
297 */
298 public void registerFamilies(Kryo kryo) {
299 }
300 }
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700301}