All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.atomix.catalyst.serializer.SerializerRegistry Maven / Gradle / Ivy

There is a newer version: 1.2.1
Show newest version
/*
 * Copyright 2015 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.atomix.catalyst.serializer;

import io.atomix.catalyst.util.hash.Hasher;
import io.atomix.catalyst.util.hash.StringHasher;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Serializer registry.
 *
 * @author Jordan Halterman
 */
public class SerializerRegistry {
  private final Hasher hasher = new StringHasher();
  private final Map, TypeSerializerFactory> factories = new ConcurrentHashMap<>();
  private final Map, TypeSerializerFactory> abstractFactories = Collections.synchronizedMap(new LinkedHashMap<>(1024, 0.75f, true));
  private final Map, TypeSerializerFactory> defaultFactories = Collections.synchronizedMap(new LinkedHashMap<>(1024, 0.75f, true));
  private final Map, Integer> ids = new ConcurrentHashMap<>();
  private final Map> types = new ConcurrentHashMap<>();

  @SuppressWarnings("unchecked")
  public SerializerRegistry() {
    this(Collections.EMPTY_LIST);
  }

  public SerializerRegistry(SerializableTypeResolver... resolvers) {
    this(Arrays.asList(resolvers));
  }

  public SerializerRegistry(Collection resolvers) {
    resolve(new PrimitiveTypeResolver());
    resolve(new JdkTypeResolver());
    resolve(resolvers);
  }

  /**
   * Resolves serializable types with the given resolver.
   * 

* This allows users to modify the serializable types registered to an existing {@link Serializer} instance. Types resolved * by the provided resolver(s) will be added to existing types resolved by any type resolvers provided to this object's * constructor or by previous calls to this method. * * @param resolvers The resolvers with which to resolve serializable types. * @return The serializer registry instance. */ @SuppressWarnings("unchecked") public SerializerRegistry resolve(SerializableTypeResolver... resolvers) { return resolve(resolvers != null ? Arrays.asList(resolvers) : Collections.EMPTY_LIST); } /** * Resolves serializable types with the given resolver. *

* This allows users to modify the serializable types registered to an existing {@link Serializer} instance. Types resolved * by the provided resolver(s) will be added to existing types resolved by any type resolvers provided to this object's * constructor or by previous calls to this method. * * @param resolvers The resolvers with which to resolve serializable types. * @return The serializer registry instance. */ public SerializerRegistry resolve(Collection resolvers) { if (resolvers != null) { for (SerializableTypeResolver resolver : resolvers) { resolver.resolve(this); } } return this; } /** * Returns the type ID for the given class. */ private int calculateTypeId(Class type) { if (type == null) throw new NullPointerException("type cannot be null"); return hasher.hash32(type.getName()); } /** * Registers the given class for serialization. * * @param type The type class. * @return The serializer registry. * @throws RegistrationException If the given {@code type} is already registered */ public SerializerRegistry register(Class type) { if (type == null) throw new NullPointerException("type cannot be null"); return register(type, calculateTypeId(type)); } /** * Registers the given class for serialization. * * @param type The serializable class. * @param id The serialization ID. * @return The serializer registry. * @throws RegistrationException If the given {@code type} is already registered or if no default * serializer could be found for the given type. */ public synchronized SerializerRegistry register(Class type, int id) { if (type == null) throw new NullPointerException("type cannot be null"); // Search for a default serializer for the type. Class baseType = findBaseType(type, defaultFactories); if (baseType == null) { throw new RegistrationException("no default serializer found for type: " + type); } return register(type, id, defaultFactories.get(baseType)); } /** * Registers a serializer for the given class. * * @param type The serializable class. * @param serializer The serializer. * @return The serializer registry. * @throws RegistrationException If the given {@code type} is already registered */ @SuppressWarnings("rawtypes") public SerializerRegistry register(Class type, Class serializer) { return register(type, calculateTypeId(type), new DefaultTypeSerializerFactory(serializer)); } /** * Registers a serializer for the given class. * * @param type The serializable class. * @param factory The serializer factory. * @return The serializer registry. * @throws RegistrationException If the given {@code type} is already registered */ public SerializerRegistry register(Class type, TypeSerializerFactory factory) { return register(type, calculateTypeId(type), factory); } /** * Registers the given class for serialization. * * @param type The serializable class. * @param id The serializable type ID. * @param serializer The serializer. * @return The serializer registry. * @throws RegistrationException If the given {@code type} is already registered */ @SuppressWarnings("rawtypes") public SerializerRegistry register(Class type, int id, Class serializer) { return register(type, id, new DefaultTypeSerializerFactory(serializer)); } /** * Registers the given class for serialization. * * @param type The serializable class. * @param factory The serializer factory. * @param id The serializable type ID. * @return The serializer registry. * @throws RegistrationException If the given {@code type} or {@code id} is already registered */ public synchronized SerializerRegistry register(Class type, int id, TypeSerializerFactory factory) { if (type == null) throw new NullPointerException("type cannot be null"); // If the type ID has already been registered, throw an exception. if (types.containsKey(id) && types.get(id) != type) { throw new RegistrationException("serializable type ID already registered: " + id); } // If the type has already been registered, throw an exception if the IDs don't match. if (ids.containsKey(type)) { if (ids.get(type) != id) { throw new RegistrationException("type registered with a different ID: " + type); } return this; } factories.put(type, factory); types.put(id, type); ids.put(type, id); return this; } /** * Registers the given class as an abstract serializer for the given abstract type. * * @param abstractType The abstract type for which to register the serializer. * @param serializer The serializer class. * @return The serializer registry. */ public SerializerRegistry registerAbstract(Class abstractType, Class serializer) { return registerAbstract(abstractType, calculateTypeId(abstractType), new DefaultTypeSerializerFactory(serializer)); } /** * Registers the given class as an abstract serializer for the given abstract type. * * @param abstractType The abstract type for which to register the serializer. * @param factory The serializer factory. * @return The serializer registry. */ public SerializerRegistry registerAbstract(Class abstractType, TypeSerializerFactory factory) { return registerAbstract(abstractType, calculateTypeId(abstractType), factory); } /** * Registers the given class as an abstract serializer for the given abstract type. * * @param abstractType The abstract type for which to register the serializer. * @param id The serializable type ID. * @param serializer The serializer class. * @return The serializer registry. */ public SerializerRegistry registerAbstract(Class abstractType, int id, Class serializer) { return registerAbstract(abstractType, id, new DefaultTypeSerializerFactory(serializer)); } /** * Registers the given class as an abstract serializer for the given abstract type. * * @param abstractType The abstract type for which to register the serializer. * @param id The serializable type ID. * @param factory The serializer factory. * @return The serializer registry. */ public SerializerRegistry registerAbstract(Class abstractType, int id, TypeSerializerFactory factory) { abstractFactories.put(abstractType, factory); types.put(id, abstractType); ids.put(abstractType, id); return this; } /** * Registers the given class as a default serializer for the given base type. * * @param baseType The base type for which to register the serializer. * @param serializer The serializer class. * @return The serializer registry. */ public SerializerRegistry registerDefault(Class baseType, Class serializer) { return registerDefault(baseType, new DefaultTypeSerializerFactory(serializer)); } /** * Registers the given factory as a default serializer factory for the given base type. * * @param baseType The base type for which to register the serializer. * @param factory The serializer factory. * @return The serializer registry. */ public synchronized SerializerRegistry registerDefault(Class baseType, TypeSerializerFactory factory) { defaultFactories.put(baseType, factory); return this; } /** * Finds a serializable base type for the given type in the given factories map. */ private Class findBaseType(Class type, Map, TypeSerializerFactory> factories) { if (factories.containsKey(type)) return type; List, TypeSerializerFactory>> orderedFactories = new ArrayList<>(factories.entrySet()); Collections.reverse(orderedFactories); Optional, TypeSerializerFactory>> optional = orderedFactories.stream() .filter(e -> e.getKey().isAssignableFrom(type)) .findFirst(); return optional.isPresent() ? optional.get().getKey() : null; } /** * Looks up the serializer for the given class else {@code null} if no serializer is registered for the {@code type}. * * @param type The serializable class. * @return The serializer for the given class. */ synchronized TypeSerializerFactory factory(Class type) { TypeSerializerFactory factory = factories.get(type); if (factory != null) { return factory; } Class baseType; // If no factory was found, determine if an abstract serializer can be used. baseType = findBaseType(type, abstractFactories); if (baseType != null) { return abstractFactories.get(baseType); } // If no factory was found, determine if a default serializer can be used. baseType = findBaseType(type, defaultFactories); if (baseType != null) { return defaultFactories.get(baseType); } return null; } /** * Looks up the serializable type ID for the given type. */ synchronized int id(Class type) { Integer id = ids.get(type); if (id != null) return id; // If no ID was found for the given type, determine whether the type is an abstract type. Class baseType = findBaseType(type, abstractFactories); if (baseType != null) { id = ids.get(baseType); if (id != null) { return id; } } return 0; } /** * Returns the type for the given ID. * * @param id The ID for which to return the type. * @return The type for the given ID. */ Class type(int id) { return types.get(id); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy