blob: 1eb1569b314a90500543ee338d603592e30cd09c [file] [log] [blame]
Thomas Vachuska24c849c2014-10-27 09:53:05 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2014-present 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 HIGUCHI24a086b2014-09-21 23:28:41 -070018import com.esotericsoftware.kryo.Kryo;
HIGUCHI Yuta0a1f29e2016-05-05 15:34:41 -070019import com.esotericsoftware.kryo.Registration;
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070020import com.esotericsoftware.kryo.Serializer;
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -070021import com.esotericsoftware.kryo.io.ByteBufferInput;
22import com.esotericsoftware.kryo.io.ByteBufferOutput;
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070023import com.esotericsoftware.kryo.io.Input;
Yuta HIGUCHI86f142f2016-07-09 17:44:09 -070024import com.esotericsoftware.kryo.io.Output;
Yuta HIGUCHI91768e32014-11-22 05:06:35 -080025import com.esotericsoftware.kryo.pool.KryoCallback;
Yuta HIGUCHI633cf882014-10-20 09:10:28 -070026import com.esotericsoftware.kryo.pool.KryoFactory;
Yuta HIGUCHI91768e32014-11-22 05:06:35 -080027import com.esotericsoftware.kryo.pool.KryoPool;
28import com.google.common.base.MoreObjects;
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070029import com.google.common.collect.ImmutableList;
Jonathan Hartbe093f72016-03-25 11:14:29 -070030import org.apache.commons.lang3.tuple.Pair;
31import org.objenesis.strategy.StdInstantiatorStrategy;
32import org.slf4j.Logger;
33
34import java.io.InputStream;
35import java.io.OutputStream;
36import java.nio.ByteBuffer;
37import java.util.ArrayList;
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -070038import java.util.Arrays;
Jonathan Hartbe093f72016-03-25 11:14:29 -070039import java.util.List;
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -070040import java.util.Objects;
Jonathan Hartbe093f72016-03-25 11:14:29 -070041
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -070042import static com.google.common.base.Preconditions.checkNotNull;
Jonathan Hartbe093f72016-03-25 11:14:29 -070043import static org.slf4j.LoggerFactory.getLogger;
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070044
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070045/**
46 * Pool of Kryo instances, with classes pre-registered.
47 */
48//@ThreadSafe
Yuta HIGUCHI91768e32014-11-22 05:06:35 -080049public final class KryoNamespace implements KryoFactory, KryoPool {
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070050
51 /**
52 * Default buffer size used for serialization.
53 *
54 * @see #serialize(Object)
55 */
Yuta HIGUCHI38782052014-11-09 23:51:58 -080056 public static final int DEFAULT_BUFFER_SIZE = 4096;
Yuta HIGUCHId2a38822014-11-06 19:05:04 -080057 public static final int MAX_BUFFER_SIZE = 100 * 1000 * 1000;
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070058
Yuta HIGUCHI91768e32014-11-22 05:06:35 -080059 /**
60 * ID to use if this KryoNamespace does not define registration id.
61 */
62 public static final int FLOATING_ID = -1;
63
64 /**
65 * Smallest ID free to use for user defined registrations.
66 */
HIGUCHI Yuta0a1f29e2016-05-05 15:34:41 -070067 public static final int INITIAL_ID = 16;
Yuta HIGUCHI91768e32014-11-22 05:06:35 -080068
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -070069 private static final String NO_NAME = "(no name)";
70
HIGUCHI Yutab49b0072016-02-22 22:50:45 -080071 private static final Logger log = getLogger(KryoNamespace.class);
72
Yuta HIGUCHI91768e32014-11-22 05:06:35 -080073
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -070074
Yuta HIGUCHI91768e32014-11-22 05:06:35 -080075 private final KryoPool pool = new KryoPool.Builder(this)
76 .softReferences()
77 .build();
78
79 private final ImmutableList<RegistrationBlock> registeredBlocks;
80
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070081 private final boolean registrationRequired;
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -070082 private final String friendlyName;
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070083
84 /**
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070085 * KryoNamespace builder.
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070086 */
87 //@NotThreadSafe
88 public static final class Builder {
89
Yuta HIGUCHI91768e32014-11-22 05:06:35 -080090 private int blockHeadId = INITIAL_ID;
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -070091 private List<Pair<Class<?>[], Serializer<?>>> types = new ArrayList<>();
Yuta HIGUCHI91768e32014-11-22 05:06:35 -080092 private List<RegistrationBlock> blocks = new ArrayList<>();
Yuta HIGUCHI2befc662014-10-30 15:57:49 -070093 private boolean registrationRequired = true;
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070094
95 /**
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070096 * Builds a {@link KryoNamespace} instance.
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070097 *
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070098 * @return KryoNamespace
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070099 */
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -0700100 public KryoNamespace build() {
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -0700101 return build(NO_NAME);
102 }
103
104 /**
105 * Builds a {@link KryoNamespace} instance.
106 *
107 * @param friendlyName friendly name for the namespace
108 * @return KryoNamespace
109 */
110 public KryoNamespace build(String friendlyName) {
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800111 if (!types.isEmpty()) {
112 blocks.add(new RegistrationBlock(this.blockHeadId, types));
113 }
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -0700114 return new KryoNamespace(blocks, registrationRequired, friendlyName).populate(1);
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800115 }
116
117 /**
118 * Sets the next Kryo registration Id for following register entries.
119 *
120 * @param id Kryo registration Id
121 * @return this
122 *
123 * @see Kryo#register(Class, Serializer, int)
124 */
125 public Builder nextId(final int id) {
126 if (!types.isEmpty()) {
HIGUCHI Yutab49b0072016-02-22 22:50:45 -0800127 if (id != FLOATING_ID && id < blockHeadId + types.size()) {
128
HIGUCHI Yuta163efb52016-05-18 19:24:19 -0700129 if (log.isWarnEnabled()) {
130 log.warn("requested nextId {} could potentially overlap " +
131 "with existing registrations {}+{} ",
132 id, blockHeadId, types.size(), new RuntimeException());
133 }
HIGUCHI Yutab49b0072016-02-22 22:50:45 -0800134 }
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800135 blocks.add(new RegistrationBlock(this.blockHeadId, types));
136 types = new ArrayList<>();
137 }
138 this.blockHeadId = id;
139 return this;
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700140 }
141
142 /**
143 * Registers classes to be serialized using Kryo default serializer.
144 *
145 * @param expectedTypes list of classes
146 * @return this
147 */
148 public Builder register(final Class<?>... expectedTypes) {
149 for (Class<?> clazz : expectedTypes) {
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700150 types.add(Pair.of(new Class<?>[]{clazz}, null));
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700151 }
152 return this;
153 }
154
155 /**
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700156 * Registers serializer for the given set of classes.
157 * <p>
158 * When multiple classes are registered with an explicitly provided serializer, the namespace guarantees
159 * all instances will be serialized with the same type ID.
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700160 *
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800161 * @param classes list of classes to register
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700162 * @param serializer serializer to use for the class
163 * @return this
164 */
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800165 public Builder register(Serializer<?> serializer, final Class<?>... classes) {
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700166 types.add(Pair.of(classes, checkNotNull(serializer)));
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800167 return this;
168 }
169
170 private Builder register(RegistrationBlock block) {
171 if (block.begin() != FLOATING_ID) {
172 // flush pending types
173 nextId(block.begin());
174 blocks.add(block);
175 nextId(block.begin() + block.types().size());
176 } else {
177 // flush pending types
178 final int addedBlockBegin = blockHeadId + types.size();
179 nextId(addedBlockBegin);
180 blocks.add(new RegistrationBlock(addedBlockBegin, block.types()));
181 nextId(addedBlockBegin + block.types().size());
182 }
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700183 return this;
184 }
185
186 /**
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -0700187 * Registers all the class registered to given KryoNamespace.
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700188 *
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800189 * @param ns KryoNamespace
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700190 * @return this
191 */
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800192 public Builder register(final KryoNamespace ns) {
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -0700193
194 if (blocks.containsAll(ns.registeredBlocks)) {
195 // Everything was already registered.
196 log.debug("Ignoring {}, already registered.", ns);
197 return this;
198 }
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800199 for (RegistrationBlock block : ns.registeredBlocks) {
200 this.register(block);
201 }
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700202 return this;
203 }
Yuta HIGUCHI2befc662014-10-30 15:57:49 -0700204
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800205 /**
206 * Sets the registrationRequired flag.
207 *
208 * @param registrationRequired Kryo's registrationRequired flag
209 * @return this
210 *
211 * @see Kryo#setRegistrationRequired(boolean)
212 */
Yuta HIGUCHI2befc662014-10-30 15:57:49 -0700213 public Builder setRegistrationRequired(boolean registrationRequired) {
214 this.registrationRequired = registrationRequired;
215 return this;
216 }
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700217 }
218
219 /**
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -0700220 * Creates a new {@link KryoNamespace} builder.
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700221 *
222 * @return builder
223 */
224 public static Builder newBuilder() {
225 return new Builder();
226 }
227
228 /**
229 * Creates a Kryo instance pool.
230 *
Jonathan Hart4f60f982014-10-27 08:11:17 -0700231 * @param registeredTypes types to register
Yuta HIGUCHI2befc662014-10-30 15:57:49 -0700232 * @param registrationRequired
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -0700233 * @param friendlyName friendly name for the namespace
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700234 */
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -0700235 private KryoNamespace(final List<RegistrationBlock> registeredTypes,
236 boolean registrationRequired,
237 String friendlyName) {
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800238 this.registeredBlocks = ImmutableList.copyOf(registeredTypes);
Yuta HIGUCHI2befc662014-10-30 15:57:49 -0700239 this.registrationRequired = registrationRequired;
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -0700240 this.friendlyName = checkNotNull(friendlyName);
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700241 }
242
243 /**
244 * Populates the Kryo pool.
245 *
246 * @param instances to add to the pool
247 * @return this
248 */
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -0700249 public KryoNamespace populate(int instances) {
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800250
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700251 for (int i = 0; i < instances; ++i) {
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800252 release(create());
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700253 }
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700254 return this;
255 }
256
257 /**
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700258 * Serializes given object to byte array using Kryo instance in pool.
259 * <p>
Yuta HIGUCHI38782052014-11-09 23:51:58 -0800260 * Note: Serialized bytes must be smaller than {@link #MAX_BUFFER_SIZE}.
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700261 *
262 * @param obj Object to serialize
263 * @return serialized bytes
264 */
265 public byte[] serialize(final Object obj) {
266 return serialize(obj, DEFAULT_BUFFER_SIZE);
267 }
268
269 /**
270 * Serializes given object to byte array using Kryo instance in pool.
271 *
272 * @param obj Object to serialize
273 * @param bufferSize maximum size of serialized bytes
274 * @return serialized bytes
275 */
276 public byte[] serialize(final Object obj, final int bufferSize) {
Yuta HIGUCHI86f142f2016-07-09 17:44:09 -0700277 Output out = new Output(bufferSize, MAX_BUFFER_SIZE);
278 return pool.run(kryo -> {
279 kryo.writeClassAndObject(out, obj);
280 out.flush();
281 return out.toBytes();
282 });
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700283 }
284
285 /**
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -0700286 * Serializes given object to byte buffer using Kryo instance in pool.
287 *
288 * @param obj Object to serialize
289 * @param buffer to write to
290 */
291 public void serialize(final Object obj, final ByteBuffer buffer) {
292 ByteBufferOutput out = new ByteBufferOutput(buffer);
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800293 Kryo kryo = borrow();
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -0700294 try {
295 kryo.writeClassAndObject(out, obj);
Yuta HIGUCHIcac919c2014-10-20 22:17:20 -0700296 out.flush();
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -0700297 } finally {
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800298 release(kryo);
299 }
300 }
301
302 /**
303 * Serializes given object to OutputStream using Kryo instance in pool.
304 *
305 * @param obj Object to serialize
306 * @param stream to write to
307 */
308 public void serialize(final Object obj, final OutputStream stream) {
309 serialize(obj, stream, DEFAULT_BUFFER_SIZE);
310 }
311
312 /**
313 * Serializes given object to OutputStream using Kryo instance in pool.
314 *
315 * @param obj Object to serialize
316 * @param stream to write to
317 * @param bufferSize size of the buffer in front of the stream
318 */
319 public void serialize(final Object obj, final OutputStream stream, final int bufferSize) {
320 ByteBufferOutput out = new ByteBufferOutput(stream, bufferSize);
321 Kryo kryo = borrow();
322 try {
323 kryo.writeClassAndObject(out, obj);
324 out.flush();
325 } finally {
326 release(kryo);
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -0700327 }
328 }
329
330 /**
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700331 * Deserializes given byte array to Object using Kryo instance in pool.
332 *
333 * @param bytes serialized bytes
334 * @param <T> deserialized Object type
335 * @return deserialized Object
336 */
337 public <T> T deserialize(final byte[] bytes) {
338 Input in = new Input(bytes);
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800339 Kryo kryo = borrow();
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700340 try {
341 @SuppressWarnings("unchecked")
342 T obj = (T) kryo.readClassAndObject(in);
343 return obj;
344 } finally {
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800345 release(kryo);
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700346 }
347 }
348
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -0700349 /**
350 * Deserializes given byte buffer to Object using Kryo instance in pool.
351 *
352 * @param buffer input with serialized bytes
353 * @param <T> deserialized Object type
354 * @return deserialized Object
355 */
356 public <T> T deserialize(final ByteBuffer buffer) {
357 ByteBufferInput in = new ByteBufferInput(buffer);
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800358 Kryo kryo = borrow();
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -0700359 try {
360 @SuppressWarnings("unchecked")
361 T obj = (T) kryo.readClassAndObject(in);
362 return obj;
363 } finally {
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800364 release(kryo);
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -0700365 }
366 }
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700367
368 /**
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800369 * Deserializes given InputStream to an Object using Kryo instance in pool.
370 *
371 * @param stream input stream
372 * @param <T> deserialized Object type
373 * @return deserialized Object
374 */
375 public <T> T deserialize(final InputStream stream) {
376 return deserialize(stream, DEFAULT_BUFFER_SIZE);
377 }
378
379 /**
380 * Deserializes given InputStream to an Object using Kryo instance in pool.
381 *
382 * @param stream input stream
383 * @param <T> deserialized Object type
384 * @return deserialized Object
385 * @param bufferSize size of the buffer in front of the stream
386 */
387 public <T> T deserialize(final InputStream stream, final int bufferSize) {
388 ByteBufferInput in = new ByteBufferInput(stream, bufferSize);
389 Kryo kryo = borrow();
390 try {
391 @SuppressWarnings("unchecked")
392 T obj = (T) kryo.readClassAndObject(in);
393 return obj;
394 } finally {
395 release(kryo);
396 }
397 }
398
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -0700399 private String friendlyName() {
400 return friendlyName;
401 }
402
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800403 /**
Jonathan Hart679d24d2016-05-13 13:29:53 -0700404 * Gets the number of classes registered in this Kryo namespace.
405 *
406 * @return size of namespace
407 */
408 public int size() {
409 return (int) registeredBlocks.stream()
410 .flatMap(block -> block.types().stream())
411 .count();
412 }
413
414 /**
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800415 * Creates a Kryo instance.
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700416 *
417 * @return Kryo instance
418 */
Yuta HIGUCHI633cf882014-10-20 09:10:28 -0700419 @Override
420 public Kryo create() {
HIGUCHI Yuta0a1f29e2016-05-05 15:34:41 -0700421 log.trace("Creating Kryo instance for {}", this);
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700422 Kryo kryo = new Kryo();
423 kryo.setRegistrationRequired(registrationRequired);
Jonathan Hartbe093f72016-03-25 11:14:29 -0700424
425 // TODO rethink whether we want to use StdInstantiatorStrategy
426 kryo.setInstantiatorStrategy(
427 new Kryo.DefaultInstantiatorStrategy(new StdInstantiatorStrategy()));
428
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800429 for (RegistrationBlock block : registeredBlocks) {
430 int id = block.begin();
431 if (id == FLOATING_ID) {
432 id = kryo.getNextRegistrationId();
433 }
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700434 for (Pair<Class<?>[], Serializer<?>> entry : block.types()) {
HIGUCHI Yuta0a1f29e2016-05-05 15:34:41 -0700435 register(kryo, entry.getLeft(), entry.getRight(), id++);
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700436 }
437 }
438 return kryo;
439 }
Yuta HIGUCHI533ec322014-09-30 13:29:52 -0700440
HIGUCHI Yuta0a1f29e2016-05-05 15:34:41 -0700441 /**
442 * Register {@code type} and {@code serializer} to {@code kryo} instance.
443 *
444 * @param kryo Kryo instance
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700445 * @param types types to register
HIGUCHI Yuta0a1f29e2016-05-05 15:34:41 -0700446 * @param serializer Specific serializer to register or null to use default.
447 * @param id type registration id to use
448 */
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700449 private void register(Kryo kryo, Class<?>[] types, Serializer<?> serializer, int id) {
HIGUCHI Yuta0a1f29e2016-05-05 15:34:41 -0700450 Registration existing = kryo.getRegistration(id);
451 if (existing != null) {
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700452 boolean matches = false;
453 for (Class<?> type : types) {
454 if (existing.getType() == type) {
455 matches = true;
456 break;
457 }
458 }
459
460 if (!matches) {
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -0700461 log.error("{}: Failed to register {} as {}, {} was already registered.",
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700462 friendlyName(), types, id, existing.getType());
HIGUCHI Yuta0a1f29e2016-05-05 15:34:41 -0700463
464 throw new IllegalStateException(String.format(
465 "Failed to register %s as %s, %s was already registered.",
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700466 Arrays.toString(types), id, existing.getType()));
HIGUCHI Yuta0a1f29e2016-05-05 15:34:41 -0700467 }
468 // falling through to register call for now.
469 // Consider skipping, if there's reasonable
470 // way to compare serializer equivalence.
471 }
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700472
473 for (Class<?> type : types) {
474 Registration r;
475 if (serializer == null) {
476 r = kryo.register(type, id);
477 } else {
478 r = kryo.register(type, serializer, id);
479 }
480 if (r.getId() != id) {
481 log.warn("{}: {} already registed as {}. Skipping {}.",
482 friendlyName(), r.getType(), r.getId(), id);
483 }
484 log.trace("{} registered as {}", r.getType(), r.getId());
HIGUCHI Yuta0a1f29e2016-05-05 15:34:41 -0700485 }
HIGUCHI Yuta0a1f29e2016-05-05 15:34:41 -0700486 }
487
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800488 @Override
489 public Kryo borrow() {
490 return pool.borrow();
491 }
Yuta HIGUCHI533ec322014-09-30 13:29:52 -0700492
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800493 @Override
494 public void release(Kryo kryo) {
495 pool.release(kryo);
496 }
Yuta HIGUCHI533ec322014-09-30 13:29:52 -0700497
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800498 @Override
499 public <T> T run(KryoCallback<T> callback) {
500 return pool.run(callback);
501 }
502
503 @Override
504 public String toString() {
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -0700505 if (friendlyName != NO_NAME) {
506 return MoreObjects.toStringHelper(getClass())
507 .omitNullValues()
508 .add("friendlyName", friendlyName)
509 // omit lengthy detail, when there's a name
510 .toString();
511 }
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800512 return MoreObjects.toStringHelper(getClass())
513 .add("registeredBlocks", registeredBlocks)
514 .toString();
515 }
516
517 static final class RegistrationBlock {
518 private final int begin;
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700519 private final ImmutableList<Pair<Class<?>[], Serializer<?>>> types;
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800520
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700521 public RegistrationBlock(int begin, List<Pair<Class<?>[], Serializer<?>>> types) {
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800522 this.begin = begin;
523 this.types = ImmutableList.copyOf(types);
Yuta HIGUCHI533ec322014-09-30 13:29:52 -0700524 }
525
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800526 public int begin() {
527 return begin;
Yuta HIGUCHI533ec322014-09-30 13:29:52 -0700528 }
529
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700530 public ImmutableList<Pair<Class<?>[], Serializer<?>>> types() {
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800531 return types;
532 }
533
534 @Override
535 public String toString() {
536 return MoreObjects.toStringHelper(getClass())
537 .add("begin", begin)
538 .add("types", types)
539 .toString();
Yuta HIGUCHI533ec322014-09-30 13:29:52 -0700540 }
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -0700541
542 @Override
543 public int hashCode() {
544 return types.hashCode();
545 }
546
547 // Only the registered types are used for equality.
548 @Override
549 public boolean equals(Object obj) {
550 if (this == obj) {
551 return true;
552 }
553
554 if (obj instanceof RegistrationBlock) {
555 RegistrationBlock that = (RegistrationBlock) obj;
556 return Objects.equals(this.types, that.types);
557 }
558 return false;
559 }
Yuta HIGUCHI533ec322014-09-30 13:29:52 -0700560 }
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700561}