blob: 1bfe3bcdf2a6fc615b731fbd4e9612859b6ad2b9 [file] [log] [blame]
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -07001package org.onlab.util;
2
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -07003import java.nio.ByteBuffer;
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -07004import java.util.ArrayList;
5import java.util.List;
6import java.util.concurrent.ConcurrentLinkedQueue;
7
8import org.apache.commons.lang3.tuple.Pair;
9
10import com.esotericsoftware.kryo.Kryo;
11import com.esotericsoftware.kryo.Serializer;
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -070012import com.esotericsoftware.kryo.io.ByteBufferInput;
13import com.esotericsoftware.kryo.io.ByteBufferOutput;
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070014import com.esotericsoftware.kryo.io.Input;
15import com.esotericsoftware.kryo.io.Output;
Yuta HIGUCHI633cf882014-10-20 09:10:28 -070016import com.esotericsoftware.kryo.pool.KryoFactory;
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070017import com.google.common.collect.ImmutableList;
18
19// TODO Add tests for this class.
20/**
21 * Pool of Kryo instances, with classes pre-registered.
22 */
23//@ThreadSafe
Yuta HIGUCHI633cf882014-10-20 09:10:28 -070024public final class KryoNamespace implements KryoFactory {
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070025
26 /**
27 * Default buffer size used for serialization.
28 *
29 * @see #serialize(Object)
30 */
31 public static final int DEFAULT_BUFFER_SIZE = 1 * 1000 * 1000;
32
33 private final ConcurrentLinkedQueue<Kryo> pool = new ConcurrentLinkedQueue<>();
34 private final ImmutableList<Pair<Class<?>, Serializer<?>>> registeredTypes;
35 private final boolean registrationRequired;
36
37 /**
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070038 * KryoNamespace builder.
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070039 */
40 //@NotThreadSafe
41 public static final class Builder {
42
43 private final List<Pair<Class<?>, Serializer<?>>> types = new ArrayList<>();
44
45 /**
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070046 * Builds a {@link KryoNamespace} instance.
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070047 *
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070048 * @return KryoNamespace
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070049 */
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070050 public KryoNamespace build() {
51 return new KryoNamespace(types);
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070052 }
53
54 /**
55 * Registers classes to be serialized using Kryo default serializer.
56 *
57 * @param expectedTypes list of classes
58 * @return this
59 */
60 public Builder register(final Class<?>... expectedTypes) {
61 for (Class<?> clazz : expectedTypes) {
62 types.add(Pair.<Class<?>, Serializer<?>>of(clazz, null));
63 }
64 return this;
65 }
66
67 /**
68 * Registers a class and it's serializer.
69 *
70 * @param clazz the class to register
71 * @param serializer serializer to use for the class
72 * @return this
73 */
74 public Builder register(final Class<?> clazz, Serializer<?> serializer) {
75 types.add(Pair.<Class<?>, Serializer<?>>of(clazz, serializer));
76 return this;
77 }
78
79 /**
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070080 * Registers all the class registered to given KryoNamespace.
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070081 *
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070082 * @param pool KryoNamespace
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070083 * @return this
84 */
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070085 public Builder register(final KryoNamespace pool) {
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070086 types.addAll(pool.registeredTypes);
87 return this;
88 }
89 }
90
91 /**
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070092 * Creates a new {@link KryoNamespace} builder.
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070093 *
94 * @return builder
95 */
96 public static Builder newBuilder() {
97 return new Builder();
98 }
99
100 /**
101 * Creates a Kryo instance pool.
102 *
103 * @param registerdTypes types to register
104 */
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -0700105 private KryoNamespace(final List<Pair<Class<?>, Serializer<?>>> registerdTypes) {
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700106 this.registeredTypes = ImmutableList.copyOf(registerdTypes);
107 // always true for now
108 this.registrationRequired = true;
109 }
110
111 /**
112 * Populates the Kryo pool.
113 *
114 * @param instances to add to the pool
115 * @return this
116 */
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -0700117 public KryoNamespace populate(int instances) {
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700118 List<Kryo> kryos = new ArrayList<>(instances);
119 for (int i = 0; i < instances; ++i) {
Yuta HIGUCHI633cf882014-10-20 09:10:28 -0700120 kryos.add(create());
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700121 }
122 pool.addAll(kryos);
123 return this;
124 }
125
126 /**
127 * Gets a Kryo instance from the pool.
128 *
129 * @return Kryo instance
130 */
131 public Kryo getKryo() {
132 Kryo kryo = pool.poll();
133 if (kryo == null) {
Yuta HIGUCHI633cf882014-10-20 09:10:28 -0700134 return create();
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700135 }
136 return kryo;
137 }
138
139 /**
140 * Returns a Kryo instance to the pool.
141 *
142 * @param kryo instance obtained from this pool.
143 */
144 public void putKryo(Kryo kryo) {
145 if (kryo != null) {
146 pool.add(kryo);
147 }
148 }
149
150 /**
151 * Serializes given object to byte array using Kryo instance in pool.
152 * <p>
153 * Note: Serialized bytes must be smaller than {@link #DEFAULT_BUFFER_SIZE}.
154 *
155 * @param obj Object to serialize
156 * @return serialized bytes
157 */
158 public byte[] serialize(final Object obj) {
159 return serialize(obj, DEFAULT_BUFFER_SIZE);
160 }
161
162 /**
163 * Serializes given object to byte array using Kryo instance in pool.
164 *
165 * @param obj Object to serialize
166 * @param bufferSize maximum size of serialized bytes
167 * @return serialized bytes
168 */
169 public byte[] serialize(final Object obj, final int bufferSize) {
170 Output out = new Output(bufferSize);
171 Kryo kryo = getKryo();
172 try {
173 kryo.writeClassAndObject(out, obj);
Yuta HIGUCHIcac919c2014-10-20 22:17:20 -0700174 out.flush();
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700175 return out.toBytes();
176 } finally {
177 putKryo(kryo);
178 }
179 }
180
181 /**
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -0700182 * Serializes given object to byte buffer using Kryo instance in pool.
183 *
184 * @param obj Object to serialize
185 * @param buffer to write to
186 */
187 public void serialize(final Object obj, final ByteBuffer buffer) {
188 ByteBufferOutput out = new ByteBufferOutput(buffer);
189 Kryo kryo = getKryo();
190 try {
191 kryo.writeClassAndObject(out, obj);
Yuta HIGUCHIcac919c2014-10-20 22:17:20 -0700192 out.flush();
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -0700193 } finally {
194 putKryo(kryo);
195 }
196 }
197
198 /**
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700199 * Deserializes given byte array to Object using Kryo instance in pool.
200 *
201 * @param bytes serialized bytes
202 * @param <T> deserialized Object type
203 * @return deserialized Object
204 */
205 public <T> T deserialize(final byte[] bytes) {
206 Input in = new Input(bytes);
207 Kryo kryo = getKryo();
208 try {
209 @SuppressWarnings("unchecked")
210 T obj = (T) kryo.readClassAndObject(in);
211 return obj;
212 } finally {
213 putKryo(kryo);
214 }
215 }
216
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -0700217 /**
218 * Deserializes given byte buffer to Object using Kryo instance in pool.
219 *
220 * @param buffer input with serialized bytes
221 * @param <T> deserialized Object type
222 * @return deserialized Object
223 */
224 public <T> T deserialize(final ByteBuffer buffer) {
225 ByteBufferInput in = new ByteBufferInput(buffer);
226 Kryo kryo = getKryo();
227 try {
228 @SuppressWarnings("unchecked")
229 T obj = (T) kryo.readClassAndObject(in);
230 return obj;
231 } finally {
232 putKryo(kryo);
233 }
234 }
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700235
236 /**
237 * Creates a Kryo instance with {@link #registeredTypes} pre-registered.
238 *
239 * @return Kryo instance
240 */
Yuta HIGUCHI633cf882014-10-20 09:10:28 -0700241 @Override
242 public Kryo create() {
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700243 Kryo kryo = new Kryo();
244 kryo.setRegistrationRequired(registrationRequired);
245 for (Pair<Class<?>, Serializer<?>> registry : registeredTypes) {
Yuta HIGUCHI533ec322014-09-30 13:29:52 -0700246 final Serializer<?> serializer = registry.getRight();
247 if (serializer == null) {
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700248 kryo.register(registry.getLeft());
249 } else {
Yuta HIGUCHI533ec322014-09-30 13:29:52 -0700250 kryo.register(registry.getLeft(), serializer);
251 if (serializer instanceof FamilySerializer) {
252 FamilySerializer<?> fser = (FamilySerializer<?>) serializer;
253 fser.registerFamilies(kryo);
254 }
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700255 }
256 }
257 return kryo;
258 }
Yuta HIGUCHI533ec322014-09-30 13:29:52 -0700259
260 /**
261 * Serializer implementation, which required registration of family of Classes.
262 * @param <T> base type of this serializer.
263 */
264 public abstract static class FamilySerializer<T> extends Serializer<T> {
265
266
267 public FamilySerializer(boolean acceptsNull) {
268 super(acceptsNull);
269 }
270
271 public FamilySerializer(boolean acceptsNull, boolean immutable) {
272 super(acceptsNull, immutable);
273 }
274
275 /**
276 * Registers other classes this Serializer supports.
277 *
278 * @param kryo instance to register classes to
279 */
280 public void registerFamilies(Kryo kryo) {
281 }
282 }
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700283}