blob: 42d801b819fe930cc255edeefa8580ba3406683a [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);
174 return out.toBytes();
175 } finally {
176 putKryo(kryo);
177 }
178 }
179
180 /**
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -0700181 * Serializes given object to byte buffer using Kryo instance in pool.
182 *
183 * @param obj Object to serialize
184 * @param buffer to write to
185 */
186 public void serialize(final Object obj, final ByteBuffer buffer) {
187 ByteBufferOutput out = new ByteBufferOutput(buffer);
188 Kryo kryo = getKryo();
189 try {
190 kryo.writeClassAndObject(out, obj);
191 } finally {
192 putKryo(kryo);
193 }
194 }
195
196 /**
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700197 * Deserializes given byte array to Object using Kryo instance in pool.
198 *
199 * @param bytes serialized bytes
200 * @param <T> deserialized Object type
201 * @return deserialized Object
202 */
203 public <T> T deserialize(final byte[] bytes) {
204 Input in = new Input(bytes);
205 Kryo kryo = getKryo();
206 try {
207 @SuppressWarnings("unchecked")
208 T obj = (T) kryo.readClassAndObject(in);
209 return obj;
210 } finally {
211 putKryo(kryo);
212 }
213 }
214
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -0700215 /**
216 * Deserializes given byte buffer to Object using Kryo instance in pool.
217 *
218 * @param buffer input with serialized bytes
219 * @param <T> deserialized Object type
220 * @return deserialized Object
221 */
222 public <T> T deserialize(final ByteBuffer buffer) {
223 ByteBufferInput in = new ByteBufferInput(buffer);
224 Kryo kryo = getKryo();
225 try {
226 @SuppressWarnings("unchecked")
227 T obj = (T) kryo.readClassAndObject(in);
228 return obj;
229 } finally {
230 putKryo(kryo);
231 }
232 }
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700233
234 /**
235 * Creates a Kryo instance with {@link #registeredTypes} pre-registered.
236 *
237 * @return Kryo instance
238 */
Yuta HIGUCHI633cf882014-10-20 09:10:28 -0700239 @Override
240 public Kryo create() {
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700241 Kryo kryo = new Kryo();
242 kryo.setRegistrationRequired(registrationRequired);
243 for (Pair<Class<?>, Serializer<?>> registry : registeredTypes) {
Yuta HIGUCHI533ec322014-09-30 13:29:52 -0700244 final Serializer<?> serializer = registry.getRight();
245 if (serializer == null) {
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700246 kryo.register(registry.getLeft());
247 } else {
Yuta HIGUCHI533ec322014-09-30 13:29:52 -0700248 kryo.register(registry.getLeft(), serializer);
249 if (serializer instanceof FamilySerializer) {
250 FamilySerializer<?> fser = (FamilySerializer<?>) serializer;
251 fser.registerFamilies(kryo);
252 }
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700253 }
254 }
255 return kryo;
256 }
Yuta HIGUCHI533ec322014-09-30 13:29:52 -0700257
258 /**
259 * Serializer implementation, which required registration of family of Classes.
260 * @param <T> base type of this serializer.
261 */
262 public abstract static class FamilySerializer<T> extends Serializer<T> {
263
264
265 public FamilySerializer(boolean acceptsNull) {
266 super(acceptsNull);
267 }
268
269 public FamilySerializer(boolean acceptsNull, boolean immutable) {
270 super(acceptsNull, immutable);
271 }
272
273 /**
274 * Registers other classes this Serializer supports.
275 *
276 * @param kryo instance to register classes to
277 */
278 public void registerFamilies(Kryo kryo) {
279 }
280 }
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700281}