blob: b89544efb5718516f1c056146931433e64c499e9 [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;
Yuta HIGUCHI633cf882014-10-20 09:10:28 -070030import com.esotericsoftware.kryo.pool.KryoFactory;
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070031import com.google.common.collect.ImmutableList;
32
33// TODO Add tests for this class.
34/**
35 * Pool of Kryo instances, with classes pre-registered.
36 */
37//@ThreadSafe
Yuta HIGUCHI633cf882014-10-20 09:10:28 -070038public final class KryoNamespace implements KryoFactory {
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070039
40 /**
41 * Default buffer size used for serialization.
42 *
43 * @see #serialize(Object)
44 */
Yuta HIGUCHI38782052014-11-09 23:51:58 -080045 public static final int DEFAULT_BUFFER_SIZE = 4096;
Yuta HIGUCHId2a38822014-11-06 19:05:04 -080046 public static final int MAX_BUFFER_SIZE = 100 * 1000 * 1000;
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070047
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<>();
Yuta HIGUCHI2befc662014-10-30 15:57:49 -070059 private boolean registrationRequired = true;
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070060
61 /**
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070062 * Builds a {@link KryoNamespace} instance.
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070063 *
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070064 * @return KryoNamespace
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070065 */
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070066 public KryoNamespace build() {
Yuta HIGUCHI2befc662014-10-30 15:57:49 -070067 return new KryoNamespace(types, registrationRequired);
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070068 }
69
70 /**
71 * Registers classes to be serialized using Kryo default serializer.
72 *
73 * @param expectedTypes list of classes
74 * @return this
75 */
76 public Builder register(final Class<?>... expectedTypes) {
77 for (Class<?> clazz : expectedTypes) {
78 types.add(Pair.<Class<?>, Serializer<?>>of(clazz, null));
79 }
80 return this;
81 }
82
83 /**
84 * Registers a class and it's serializer.
85 *
86 * @param clazz the class to register
87 * @param serializer serializer to use for the class
88 * @return this
89 */
90 public Builder register(final Class<?> clazz, Serializer<?> serializer) {
91 types.add(Pair.<Class<?>, Serializer<?>>of(clazz, serializer));
92 return this;
93 }
94
95 /**
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070096 * Registers all the class registered to given KryoNamespace.
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070097 *
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070098 * @param pool KryoNamespace
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070099 * @return this
100 */
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -0700101 public Builder register(final KryoNamespace pool) {
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700102 types.addAll(pool.registeredTypes);
103 return this;
104 }
Yuta HIGUCHI2befc662014-10-30 15:57:49 -0700105
106 public Builder setRegistrationRequired(boolean registrationRequired) {
107 this.registrationRequired = registrationRequired;
108 return this;
109 }
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700110 }
111
112 /**
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -0700113 * Creates a new {@link KryoNamespace} builder.
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700114 *
115 * @return builder
116 */
117 public static Builder newBuilder() {
118 return new Builder();
119 }
120
121 /**
122 * Creates a Kryo instance pool.
123 *
Jonathan Hart4f60f982014-10-27 08:11:17 -0700124 * @param registeredTypes types to register
Yuta HIGUCHI2befc662014-10-30 15:57:49 -0700125 * @param registrationRequired
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700126 */
Yuta HIGUCHI2befc662014-10-30 15:57:49 -0700127 private KryoNamespace(final List<Pair<Class<?>, Serializer<?>>> registeredTypes, boolean registrationRequired) {
Jonathan Hart4f60f982014-10-27 08:11:17 -0700128 this.registeredTypes = ImmutableList.copyOf(registeredTypes);
Yuta HIGUCHI2befc662014-10-30 15:57:49 -0700129 this.registrationRequired = registrationRequired;
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700130 }
131
132 /**
133 * Populates the Kryo pool.
134 *
135 * @param instances to add to the pool
136 * @return this
137 */
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -0700138 public KryoNamespace populate(int instances) {
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700139 List<Kryo> kryos = new ArrayList<>(instances);
140 for (int i = 0; i < instances; ++i) {
Yuta HIGUCHI633cf882014-10-20 09:10:28 -0700141 kryos.add(create());
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700142 }
143 pool.addAll(kryos);
144 return this;
145 }
146
147 /**
148 * Gets a Kryo instance from the pool.
149 *
150 * @return Kryo instance
151 */
152 public Kryo getKryo() {
153 Kryo kryo = pool.poll();
154 if (kryo == null) {
Yuta HIGUCHI633cf882014-10-20 09:10:28 -0700155 return create();
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700156 }
157 return kryo;
158 }
159
160 /**
161 * Returns a Kryo instance to the pool.
162 *
163 * @param kryo instance obtained from this pool.
164 */
165 public void putKryo(Kryo kryo) {
166 if (kryo != null) {
167 pool.add(kryo);
168 }
169 }
170
171 /**
172 * Serializes given object to byte array using Kryo instance in pool.
173 * <p>
Yuta HIGUCHI38782052014-11-09 23:51:58 -0800174 * Note: Serialized bytes must be smaller than {@link #MAX_BUFFER_SIZE}.
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700175 *
176 * @param obj Object to serialize
177 * @return serialized bytes
178 */
179 public byte[] serialize(final Object obj) {
180 return serialize(obj, DEFAULT_BUFFER_SIZE);
181 }
182
183 /**
184 * Serializes given object to byte array using Kryo instance in pool.
185 *
186 * @param obj Object to serialize
187 * @param bufferSize maximum size of serialized bytes
188 * @return serialized bytes
189 */
190 public byte[] serialize(final Object obj, final int bufferSize) {
Yuta HIGUCHId2a38822014-11-06 19:05:04 -0800191 ByteBufferOutput out = new ByteBufferOutput(bufferSize, MAX_BUFFER_SIZE);
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700192 Kryo kryo = getKryo();
193 try {
194 kryo.writeClassAndObject(out, obj);
Yuta HIGUCHIcac919c2014-10-20 22:17:20 -0700195 out.flush();
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700196 return out.toBytes();
197 } finally {
198 putKryo(kryo);
199 }
200 }
201
202 /**
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -0700203 * Serializes given object to byte buffer using Kryo instance in pool.
204 *
205 * @param obj Object to serialize
206 * @param buffer to write to
207 */
208 public void serialize(final Object obj, final ByteBuffer buffer) {
209 ByteBufferOutput out = new ByteBufferOutput(buffer);
210 Kryo kryo = getKryo();
211 try {
212 kryo.writeClassAndObject(out, obj);
Yuta HIGUCHIcac919c2014-10-20 22:17:20 -0700213 out.flush();
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -0700214 } finally {
215 putKryo(kryo);
216 }
217 }
218
219 /**
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700220 * Deserializes given byte array to Object using Kryo instance in pool.
221 *
222 * @param bytes serialized bytes
223 * @param <T> deserialized Object type
224 * @return deserialized Object
225 */
226 public <T> T deserialize(final byte[] bytes) {
227 Input in = new Input(bytes);
228 Kryo kryo = getKryo();
229 try {
230 @SuppressWarnings("unchecked")
231 T obj = (T) kryo.readClassAndObject(in);
232 return obj;
233 } finally {
234 putKryo(kryo);
235 }
236 }
237
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -0700238 /**
239 * Deserializes given byte buffer to Object using Kryo instance in pool.
240 *
241 * @param buffer input with serialized bytes
242 * @param <T> deserialized Object type
243 * @return deserialized Object
244 */
245 public <T> T deserialize(final ByteBuffer buffer) {
246 ByteBufferInput in = new ByteBufferInput(buffer);
247 Kryo kryo = getKryo();
248 try {
249 @SuppressWarnings("unchecked")
250 T obj = (T) kryo.readClassAndObject(in);
251 return obj;
252 } finally {
253 putKryo(kryo);
254 }
255 }
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700256
257 /**
258 * Creates a Kryo instance with {@link #registeredTypes} pre-registered.
259 *
260 * @return Kryo instance
261 */
Yuta HIGUCHI633cf882014-10-20 09:10:28 -0700262 @Override
263 public Kryo create() {
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700264 Kryo kryo = new Kryo();
265 kryo.setRegistrationRequired(registrationRequired);
266 for (Pair<Class<?>, Serializer<?>> registry : registeredTypes) {
Yuta HIGUCHI533ec322014-09-30 13:29:52 -0700267 final Serializer<?> serializer = registry.getRight();
268 if (serializer == null) {
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700269 kryo.register(registry.getLeft());
270 } else {
Yuta HIGUCHI533ec322014-09-30 13:29:52 -0700271 kryo.register(registry.getLeft(), serializer);
272 if (serializer instanceof FamilySerializer) {
273 FamilySerializer<?> fser = (FamilySerializer<?>) serializer;
274 fser.registerFamilies(kryo);
275 }
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700276 }
277 }
278 return kryo;
279 }
Yuta HIGUCHI533ec322014-09-30 13:29:52 -0700280
281 /**
282 * Serializer implementation, which required registration of family of Classes.
283 * @param <T> base type of this serializer.
284 */
285 public abstract static class FamilySerializer<T> extends Serializer<T> {
286
287
288 public FamilySerializer(boolean acceptsNull) {
289 super(acceptsNull);
290 }
291
292 public FamilySerializer(boolean acceptsNull, boolean immutable) {
293 super(acceptsNull, immutable);
294 }
295
296 /**
297 * Registers other classes this Serializer supports.
298 *
299 * @param kryo instance to register classes to
300 */
301 public void registerFamilies(Kryo kryo) {
302 }
303 }
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700304}