blob: ed4b066f360ed2bdda0e96fb889354634919b33e [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;
Jordan Haltermanc10a5012017-06-12 10:34:42 -070028import com.esotericsoftware.kryo.serializers.CompatibleFieldSerializer;
Yuta HIGUCHI91768e32014-11-22 05:06:35 -080029import com.google.common.base.MoreObjects;
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070030import com.google.common.collect.ImmutableList;
Jonathan Hartbe093f72016-03-25 11:14:29 -070031import org.apache.commons.lang3.tuple.Pair;
32import org.objenesis.strategy.StdInstantiatorStrategy;
33import org.slf4j.Logger;
34
35import java.io.InputStream;
36import java.io.OutputStream;
37import java.nio.ByteBuffer;
38import java.util.ArrayList;
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -070039import java.util.Arrays;
Jonathan Hartbe093f72016-03-25 11:14:29 -070040import java.util.List;
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -070041import java.util.Objects;
Jonathan Hartbe093f72016-03-25 11:14:29 -070042
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -070043import static com.google.common.base.Preconditions.checkNotNull;
Jonathan Hartbe093f72016-03-25 11:14:29 -070044import static org.slf4j.LoggerFactory.getLogger;
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070045
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070046/**
47 * Pool of Kryo instances, with classes pre-registered.
48 */
49//@ThreadSafe
Yuta HIGUCHI91768e32014-11-22 05:06:35 -080050public final class KryoNamespace implements KryoFactory, KryoPool {
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070051
52 /**
53 * Default buffer size used for serialization.
54 *
55 * @see #serialize(Object)
56 */
Yuta HIGUCHI38782052014-11-09 23:51:58 -080057 public static final int DEFAULT_BUFFER_SIZE = 4096;
Yuta HIGUCHId2a38822014-11-06 19:05:04 -080058 public static final int MAX_BUFFER_SIZE = 100 * 1000 * 1000;
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070059
Yuta HIGUCHI91768e32014-11-22 05:06:35 -080060 /**
61 * ID to use if this KryoNamespace does not define registration id.
62 */
63 public static final int FLOATING_ID = -1;
64
65 /**
66 * Smallest ID free to use for user defined registrations.
67 */
HIGUCHI Yuta0a1f29e2016-05-05 15:34:41 -070068 public static final int INITIAL_ID = 16;
Yuta HIGUCHI91768e32014-11-22 05:06:35 -080069
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -070070 private static final String NO_NAME = "(no name)";
71
HIGUCHI Yutab49b0072016-02-22 22:50:45 -080072 private static final Logger log = getLogger(KryoNamespace.class);
73
Yuta HIGUCHI91768e32014-11-22 05:06:35 -080074
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -070075
Yuta HIGUCHI91768e32014-11-22 05:06:35 -080076 private final KryoPool pool = new KryoPool.Builder(this)
77 .softReferences()
78 .build();
79
80 private final ImmutableList<RegistrationBlock> registeredBlocks;
81
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070082 private final boolean registrationRequired;
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -070083 private final String friendlyName;
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070084
85 /**
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070086 * KryoNamespace builder.
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070087 */
88 //@NotThreadSafe
89 public static final class Builder {
90
Yuta HIGUCHI91768e32014-11-22 05:06:35 -080091 private int blockHeadId = INITIAL_ID;
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -070092 private List<Pair<Class<?>[], Serializer<?>>> types = new ArrayList<>();
Yuta HIGUCHI91768e32014-11-22 05:06:35 -080093 private List<RegistrationBlock> blocks = new ArrayList<>();
Yuta HIGUCHI2befc662014-10-30 15:57:49 -070094 private boolean registrationRequired = true;
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070095
96 /**
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070097 * Builds a {@link KryoNamespace} instance.
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070098 *
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070099 * @return KryoNamespace
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700100 */
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -0700101 public KryoNamespace build() {
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -0700102 return build(NO_NAME);
103 }
104
105 /**
106 * Builds a {@link KryoNamespace} instance.
107 *
108 * @param friendlyName friendly name for the namespace
109 * @return KryoNamespace
110 */
111 public KryoNamespace build(String friendlyName) {
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800112 if (!types.isEmpty()) {
113 blocks.add(new RegistrationBlock(this.blockHeadId, types));
114 }
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -0700115 return new KryoNamespace(blocks, registrationRequired, friendlyName).populate(1);
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800116 }
117
118 /**
119 * Sets the next Kryo registration Id for following register entries.
120 *
121 * @param id Kryo registration Id
122 * @return this
123 *
124 * @see Kryo#register(Class, Serializer, int)
125 */
126 public Builder nextId(final int id) {
127 if (!types.isEmpty()) {
HIGUCHI Yutab49b0072016-02-22 22:50:45 -0800128 if (id != FLOATING_ID && id < blockHeadId + types.size()) {
129
HIGUCHI Yuta163efb52016-05-18 19:24:19 -0700130 if (log.isWarnEnabled()) {
131 log.warn("requested nextId {} could potentially overlap " +
132 "with existing registrations {}+{} ",
133 id, blockHeadId, types.size(), new RuntimeException());
134 }
HIGUCHI Yutab49b0072016-02-22 22:50:45 -0800135 }
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800136 blocks.add(new RegistrationBlock(this.blockHeadId, types));
137 types = new ArrayList<>();
138 }
139 this.blockHeadId = id;
140 return this;
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700141 }
142
143 /**
144 * Registers classes to be serialized using Kryo default serializer.
145 *
146 * @param expectedTypes list of classes
147 * @return this
148 */
149 public Builder register(final Class<?>... expectedTypes) {
150 for (Class<?> clazz : expectedTypes) {
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700151 types.add(Pair.of(new Class<?>[]{clazz}, null));
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700152 }
153 return this;
154 }
155
156 /**
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700157 * Registers serializer for the given set of classes.
158 * <p>
159 * When multiple classes are registered with an explicitly provided serializer, the namespace guarantees
160 * all instances will be serialized with the same type ID.
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700161 *
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800162 * @param classes list of classes to register
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700163 * @param serializer serializer to use for the class
164 * @return this
165 */
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800166 public Builder register(Serializer<?> serializer, final Class<?>... classes) {
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700167 types.add(Pair.of(classes, checkNotNull(serializer)));
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800168 return this;
169 }
170
171 private Builder register(RegistrationBlock block) {
172 if (block.begin() != FLOATING_ID) {
173 // flush pending types
174 nextId(block.begin());
175 blocks.add(block);
176 nextId(block.begin() + block.types().size());
177 } else {
178 // flush pending types
179 final int addedBlockBegin = blockHeadId + types.size();
180 nextId(addedBlockBegin);
181 blocks.add(new RegistrationBlock(addedBlockBegin, block.types()));
182 nextId(addedBlockBegin + block.types().size());
183 }
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700184 return this;
185 }
186
187 /**
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -0700188 * Registers all the class registered to given KryoNamespace.
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700189 *
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800190 * @param ns KryoNamespace
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700191 * @return this
192 */
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800193 public Builder register(final KryoNamespace ns) {
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -0700194
195 if (blocks.containsAll(ns.registeredBlocks)) {
196 // Everything was already registered.
197 log.debug("Ignoring {}, already registered.", ns);
198 return this;
199 }
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800200 for (RegistrationBlock block : ns.registeredBlocks) {
201 this.register(block);
202 }
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700203 return this;
204 }
Yuta HIGUCHI2befc662014-10-30 15:57:49 -0700205
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800206 /**
207 * Sets the registrationRequired flag.
208 *
209 * @param registrationRequired Kryo's registrationRequired flag
210 * @return this
211 *
212 * @see Kryo#setRegistrationRequired(boolean)
213 */
Yuta HIGUCHI2befc662014-10-30 15:57:49 -0700214 public Builder setRegistrationRequired(boolean registrationRequired) {
215 this.registrationRequired = registrationRequired;
216 return this;
217 }
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700218 }
219
220 /**
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -0700221 * Creates a new {@link KryoNamespace} builder.
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700222 *
223 * @return builder
224 */
225 public static Builder newBuilder() {
226 return new Builder();
227 }
228
229 /**
230 * Creates a Kryo instance pool.
231 *
Jonathan Hart4f60f982014-10-27 08:11:17 -0700232 * @param registeredTypes types to register
Yuta HIGUCHI2befc662014-10-30 15:57:49 -0700233 * @param registrationRequired
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -0700234 * @param friendlyName friendly name for the namespace
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700235 */
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -0700236 private KryoNamespace(final List<RegistrationBlock> registeredTypes,
237 boolean registrationRequired,
238 String friendlyName) {
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800239 this.registeredBlocks = ImmutableList.copyOf(registeredTypes);
Yuta HIGUCHI2befc662014-10-30 15:57:49 -0700240 this.registrationRequired = registrationRequired;
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -0700241 this.friendlyName = checkNotNull(friendlyName);
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700242 }
243
244 /**
245 * Populates the Kryo pool.
246 *
247 * @param instances to add to the pool
248 * @return this
249 */
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -0700250 public KryoNamespace populate(int instances) {
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800251
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700252 for (int i = 0; i < instances; ++i) {
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800253 release(create());
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700254 }
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700255 return this;
256 }
257
258 /**
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700259 * Serializes given object to byte array using Kryo instance in pool.
260 * <p>
Yuta HIGUCHI38782052014-11-09 23:51:58 -0800261 * Note: Serialized bytes must be smaller than {@link #MAX_BUFFER_SIZE}.
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700262 *
263 * @param obj Object to serialize
264 * @return serialized bytes
265 */
266 public byte[] serialize(final Object obj) {
267 return serialize(obj, DEFAULT_BUFFER_SIZE);
268 }
269
270 /**
271 * Serializes given object to byte array using Kryo instance in pool.
272 *
273 * @param obj Object to serialize
274 * @param bufferSize maximum size of serialized bytes
275 * @return serialized bytes
276 */
277 public byte[] serialize(final Object obj, final int bufferSize) {
Yuta HIGUCHI86f142f2016-07-09 17:44:09 -0700278 Output out = new Output(bufferSize, MAX_BUFFER_SIZE);
279 return pool.run(kryo -> {
280 kryo.writeClassAndObject(out, obj);
281 out.flush();
282 return out.toBytes();
283 });
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700284 }
285
286 /**
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -0700287 * Serializes given object to byte buffer using Kryo instance in pool.
288 *
289 * @param obj Object to serialize
290 * @param buffer to write to
291 */
292 public void serialize(final Object obj, final ByteBuffer buffer) {
293 ByteBufferOutput out = new ByteBufferOutput(buffer);
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800294 Kryo kryo = borrow();
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -0700295 try {
296 kryo.writeClassAndObject(out, obj);
Yuta HIGUCHIcac919c2014-10-20 22:17:20 -0700297 out.flush();
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -0700298 } finally {
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800299 release(kryo);
300 }
301 }
302
303 /**
304 * Serializes given object to OutputStream using Kryo instance in pool.
305 *
306 * @param obj Object to serialize
307 * @param stream to write to
308 */
309 public void serialize(final Object obj, final OutputStream stream) {
310 serialize(obj, stream, DEFAULT_BUFFER_SIZE);
311 }
312
313 /**
314 * Serializes given object to OutputStream using Kryo instance in pool.
315 *
316 * @param obj Object to serialize
317 * @param stream to write to
318 * @param bufferSize size of the buffer in front of the stream
319 */
320 public void serialize(final Object obj, final OutputStream stream, final int bufferSize) {
321 ByteBufferOutput out = new ByteBufferOutput(stream, bufferSize);
322 Kryo kryo = borrow();
323 try {
324 kryo.writeClassAndObject(out, obj);
325 out.flush();
326 } finally {
327 release(kryo);
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -0700328 }
329 }
330
331 /**
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700332 * Deserializes given byte array to Object using Kryo instance in pool.
333 *
334 * @param bytes serialized bytes
335 * @param <T> deserialized Object type
336 * @return deserialized Object
337 */
338 public <T> T deserialize(final byte[] bytes) {
339 Input in = new Input(bytes);
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800340 Kryo kryo = borrow();
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700341 try {
342 @SuppressWarnings("unchecked")
343 T obj = (T) kryo.readClassAndObject(in);
344 return obj;
345 } finally {
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800346 release(kryo);
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700347 }
348 }
349
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -0700350 /**
351 * Deserializes given byte buffer to Object using Kryo instance in pool.
352 *
353 * @param buffer input with serialized bytes
354 * @param <T> deserialized Object type
355 * @return deserialized Object
356 */
357 public <T> T deserialize(final ByteBuffer buffer) {
358 ByteBufferInput in = new ByteBufferInput(buffer);
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800359 Kryo kryo = borrow();
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -0700360 try {
361 @SuppressWarnings("unchecked")
362 T obj = (T) kryo.readClassAndObject(in);
363 return obj;
364 } finally {
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800365 release(kryo);
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -0700366 }
367 }
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700368
369 /**
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800370 * Deserializes given InputStream to an Object using Kryo instance in pool.
371 *
372 * @param stream input stream
373 * @param <T> deserialized Object type
374 * @return deserialized Object
375 */
376 public <T> T deserialize(final InputStream stream) {
377 return deserialize(stream, DEFAULT_BUFFER_SIZE);
378 }
379
380 /**
381 * Deserializes given InputStream to an Object using Kryo instance in pool.
382 *
383 * @param stream input stream
384 * @param <T> deserialized Object type
385 * @return deserialized Object
386 * @param bufferSize size of the buffer in front of the stream
387 */
388 public <T> T deserialize(final InputStream stream, final int bufferSize) {
389 ByteBufferInput in = new ByteBufferInput(stream, bufferSize);
390 Kryo kryo = borrow();
391 try {
392 @SuppressWarnings("unchecked")
393 T obj = (T) kryo.readClassAndObject(in);
394 return obj;
395 } finally {
396 release(kryo);
397 }
398 }
399
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -0700400 private String friendlyName() {
401 return friendlyName;
402 }
403
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800404 /**
Jonathan Hart679d24d2016-05-13 13:29:53 -0700405 * Gets the number of classes registered in this Kryo namespace.
406 *
407 * @return size of namespace
408 */
409 public int size() {
410 return (int) registeredBlocks.stream()
411 .flatMap(block -> block.types().stream())
412 .count();
413 }
414
415 /**
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800416 * Creates a Kryo instance.
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700417 *
418 * @return Kryo instance
419 */
Yuta HIGUCHI633cf882014-10-20 09:10:28 -0700420 @Override
421 public Kryo create() {
HIGUCHI Yuta0a1f29e2016-05-05 15:34:41 -0700422 log.trace("Creating Kryo instance for {}", this);
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700423 Kryo kryo = new Kryo();
424 kryo.setRegistrationRequired(registrationRequired);
Jordan Haltermanc10a5012017-06-12 10:34:42 -0700425 kryo.setDefaultSerializer(CompatibleFieldSerializer::new);
Jonathan Hartbe093f72016-03-25 11:14:29 -0700426
427 // TODO rethink whether we want to use StdInstantiatorStrategy
428 kryo.setInstantiatorStrategy(
429 new Kryo.DefaultInstantiatorStrategy(new StdInstantiatorStrategy()));
430
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800431 for (RegistrationBlock block : registeredBlocks) {
432 int id = block.begin();
433 if (id == FLOATING_ID) {
434 id = kryo.getNextRegistrationId();
435 }
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700436 for (Pair<Class<?>[], Serializer<?>> entry : block.types()) {
HIGUCHI Yuta0a1f29e2016-05-05 15:34:41 -0700437 register(kryo, entry.getLeft(), entry.getRight(), id++);
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700438 }
439 }
440 return kryo;
441 }
Yuta HIGUCHI533ec322014-09-30 13:29:52 -0700442
HIGUCHI Yuta0a1f29e2016-05-05 15:34:41 -0700443 /**
444 * Register {@code type} and {@code serializer} to {@code kryo} instance.
445 *
446 * @param kryo Kryo instance
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700447 * @param types types to register
HIGUCHI Yuta0a1f29e2016-05-05 15:34:41 -0700448 * @param serializer Specific serializer to register or null to use default.
449 * @param id type registration id to use
450 */
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700451 private void register(Kryo kryo, Class<?>[] types, Serializer<?> serializer, int id) {
HIGUCHI Yuta0a1f29e2016-05-05 15:34:41 -0700452 Registration existing = kryo.getRegistration(id);
453 if (existing != null) {
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700454 boolean matches = false;
455 for (Class<?> type : types) {
456 if (existing.getType() == type) {
457 matches = true;
458 break;
459 }
460 }
461
462 if (!matches) {
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -0700463 log.error("{}: Failed to register {} as {}, {} was already registered.",
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700464 friendlyName(), types, id, existing.getType());
HIGUCHI Yuta0a1f29e2016-05-05 15:34:41 -0700465
466 throw new IllegalStateException(String.format(
467 "Failed to register %s as %s, %s was already registered.",
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700468 Arrays.toString(types), id, existing.getType()));
HIGUCHI Yuta0a1f29e2016-05-05 15:34:41 -0700469 }
470 // falling through to register call for now.
471 // Consider skipping, if there's reasonable
472 // way to compare serializer equivalence.
473 }
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700474
475 for (Class<?> type : types) {
476 Registration r;
477 if (serializer == null) {
478 r = kryo.register(type, id);
479 } else {
480 r = kryo.register(type, serializer, id);
481 }
482 if (r.getId() != id) {
Ray Milkey5dae9222017-06-15 11:55:51 -0700483 log.warn("{}: {} already registered as {}. Skipping {}.",
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700484 friendlyName(), r.getType(), r.getId(), id);
485 }
486 log.trace("{} registered as {}", r.getType(), r.getId());
HIGUCHI Yuta0a1f29e2016-05-05 15:34:41 -0700487 }
HIGUCHI Yuta0a1f29e2016-05-05 15:34:41 -0700488 }
489
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800490 @Override
491 public Kryo borrow() {
492 return pool.borrow();
493 }
Yuta HIGUCHI533ec322014-09-30 13:29:52 -0700494
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800495 @Override
496 public void release(Kryo kryo) {
497 pool.release(kryo);
498 }
Yuta HIGUCHI533ec322014-09-30 13:29:52 -0700499
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800500 @Override
501 public <T> T run(KryoCallback<T> callback) {
502 return pool.run(callback);
503 }
504
505 @Override
506 public String toString() {
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -0700507 if (friendlyName != NO_NAME) {
508 return MoreObjects.toStringHelper(getClass())
509 .omitNullValues()
510 .add("friendlyName", friendlyName)
511 // omit lengthy detail, when there's a name
512 .toString();
513 }
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800514 return MoreObjects.toStringHelper(getClass())
515 .add("registeredBlocks", registeredBlocks)
516 .toString();
517 }
518
519 static final class RegistrationBlock {
520 private final int begin;
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700521 private final ImmutableList<Pair<Class<?>[], Serializer<?>>> types;
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800522
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700523 public RegistrationBlock(int begin, List<Pair<Class<?>[], Serializer<?>>> types) {
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800524 this.begin = begin;
525 this.types = ImmutableList.copyOf(types);
Yuta HIGUCHI533ec322014-09-30 13:29:52 -0700526 }
527
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800528 public int begin() {
529 return begin;
Yuta HIGUCHI533ec322014-09-30 13:29:52 -0700530 }
531
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700532 public ImmutableList<Pair<Class<?>[], Serializer<?>>> types() {
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800533 return types;
534 }
535
536 @Override
537 public String toString() {
538 return MoreObjects.toStringHelper(getClass())
539 .add("begin", begin)
540 .add("types", types)
541 .toString();
Yuta HIGUCHI533ec322014-09-30 13:29:52 -0700542 }
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -0700543
544 @Override
545 public int hashCode() {
546 return types.hashCode();
547 }
548
549 // Only the registered types are used for equality.
550 @Override
551 public boolean equals(Object obj) {
552 if (this == obj) {
553 return true;
554 }
555
556 if (obj instanceof RegistrationBlock) {
557 RegistrationBlock that = (RegistrationBlock) obj;
558 return Objects.equals(this.types, that.types);
559 }
560 return false;
561 }
Yuta HIGUCHI533ec322014-09-30 13:29:52 -0700562 }
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700563}