/* * Copyright 2014 Higher Frequency Trading http://www.higherfrequencytrading.com * * 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 net.openhft.chronicle.map; import net.openhft.chronicle.map.serialization.*; import net.openhft.chronicle.map.serialization.impl.*; import net.openhft.lang.io.Bytes; import net.openhft.lang.io.serialization.*; import net.openhft.lang.io.serialization.impl.*; import net.openhft.lang.model.Byteable; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.Externalizable; import java.io.IOException; import java.io.Serializable; import java.lang.reflect.Modifier; import static net.openhft.chronicle.map.Objects.hash; import static net.openhft.chronicle.map.serialization.SizeMarshallers.stopBit; final class SerializationBuilder implements Cloneable { private static boolean concreteClass(Class c) { return !c.isInterface() && !Modifier.isAbstract(c.getModifiers()); } private static boolean marshallerUseFactory(Class c) { return Byteable.class.isAssignableFrom(c) || BytesMarshallable.class.isAssignableFrom(c) || Externalizable.class.isAssignableFrom(c); } private static boolean instancesAreMutable(Class c) { return c != String.class; } enum Role {KEY, VALUE} private enum CopyingInterop {FROM_MARSHALLER, FROM_WRITER} private final Serializable bufferIdentity; final Class eClass; private boolean instancesAreMutable; private SizeMarshaller sizeMarshaller = stopBit(); private BytesReader reader; private Object interop; private CopyingInterop copyingInterop = null; private MetaBytesInterop metaInterop; private MetaProvider metaInteropProvider; private ObjectFactory factory; @SuppressWarnings("unchecked") SerializationBuilder(Class eClass, Role role) { this.bufferIdentity = role; this.eClass = eClass; instancesAreMutable = instancesAreMutable(eClass); ObjectFactory factory = null; if (role == Role.VALUE) { factory = concreteClass(eClass) && marshallerUseFactory(eClass) ? new NewInstanceObjectFactory(eClass) : NullObjectFactory.INSTANCE; } if (concreteClass(eClass) && Byteable.class.isAssignableFrom(eClass)) { agileMarshaller(ByteableMarshaller.of((Class) eClass), factory); } else if (eClass == CharSequence.class || eClass == String.class) { reader((BytesReader) CharSequenceReader.of(), factory); writer((BytesWriter) CharSequenceWriter.instance()); } else if (eClass == Long.class) { agileMarshaller((AgileBytesMarshaller) LongMarshaller.INSTANCE, factory); } else if (eClass == byte[].class) { reader((BytesReader) ByteArrayMarshaller.INSTANCE, factory); interop((BytesInterop) ByteArrayMarshaller.INSTANCE); } else if (concreteClass(eClass)) { BytesMarshaller marshaller = chooseMarshaller(eClass, eClass); if (marshaller != null) marshaller(marshaller, factory); } if (role == Role.VALUE && concreteClass(eClass) && marshallerUseFactory(eClass)) { factory(factory); } } @SuppressWarnings("unchecked") private BytesMarshaller chooseMarshaller(Class eClass, Class classForMarshaller) { if (BytesMarshallable.class.isAssignableFrom(eClass)) return new BytesMarshallableMarshaller(classForMarshaller); if (Externalizable.class.isAssignableFrom(eClass)) return new ExternalizableMarshaller(classForMarshaller); if (eClass == Integer.class) return (BytesMarshaller) IntegerMarshaller.INSTANCE; if (eClass == Double.class) return (BytesMarshaller) DoubleMarshaller.INSTANCE; return null; } private SerializationBuilder copyingInterop(CopyingInterop copyingInterop) { this.copyingInterop = copyingInterop; return this; } public SerializationBuilder agileMarshaller(AgileBytesMarshaller agileBytesMarshaller, ObjectFactory factory) { if (factory == null) factory = this.factory; return sizeMarshaller(agileBytesMarshaller) .reader(agileBytesMarshaller, factory) .interop(agileBytesMarshaller); } public SerializationBuilder interop(BytesInterop interop) { return copyingInterop(null) .setInterop(interop) .metaInterop(DelegatingMetaBytesInterop.>instance()) .metaInteropProvider(DelegatingMetaBytesInteropProvider .>instance()); } public SerializationBuilder writer(BytesWriter writer) { return copyingInterop(CopyingInterop.FROM_WRITER) .sizeMarshaller(stopBit()) .setInterop(writer) .metaInterop(CopyingMetaBytesInterop .>forBytesWriter(bufferIdentity)); } public SerializationBuilder marshaller(BytesMarshaller marshaller, ObjectFactory factory) { if (factory == null) factory = this.factory; return copyingInterop(CopyingInterop.FROM_MARSHALLER) .sizeMarshaller(stopBit()) .reader(BytesReaders.fromBytesMarshaller(marshaller), factory) .setInterop(marshaller) .metaInterop(CopyingMetaBytesInterop .>forBytesMarshaller(bufferIdentity)); } public SerializationBuilder maxSize(long maxSize) { if (copyingInterop == CopyingInterop.FROM_MARSHALLER) { metaInteropProvider(CopyingMetaBytesInterop .>providerForBytesMarshaller( instancesAreMutable, maxSize)); } else if (copyingInterop == CopyingInterop.FROM_WRITER) { metaInteropProvider(CopyingMetaBytesInterop .>providerForBytesWriter(instancesAreMutable, maxSize)); } return this; } public SerializationBuilder objectSerializer(ObjectSerializer serializer) { if (reader == null || interop == null) { ObjectFactory factory = this.factory; if (factory == null) factory = NullObjectFactory.INSTANCE; marshaller(new SerializableMarshaller(serializer), factory); } return this; } public SerializationBuilder instancesAreMutable(boolean mutable) { this.instancesAreMutable = mutable; return this; } public SizeMarshaller sizeMarshaller() { return sizeMarshaller; } public SerializationBuilder sizeMarshaller(SizeMarshaller sizeMarshaller) { this.sizeMarshaller = sizeMarshaller; return this; } public BytesReader reader() { return reader; } public SerializationBuilder reader(BytesReader reader, ObjectFactory factory) { this.reader = reader; if (factory != null) this.factory = factory; return this; } public Object interop() { return interop; } private SerializationBuilder setInterop(Object interop) { this.interop = interop; return this; } public MetaBytesInterop metaInterop() { return metaInterop; } private SerializationBuilder metaInterop(MetaBytesInterop metaInterop) { this.metaInterop = metaInterop; return this; } @SuppressWarnings("unchecked") public MetaProvider> metaInteropProvider() { return (MetaProvider>) metaInteropProvider; } private SerializationBuilder metaInteropProvider( MetaProvider metaInteropProvider) { this.metaInteropProvider = metaInteropProvider; return this; } public ObjectFactory factory() { return factory; } @SuppressWarnings("unchecked") public SerializationBuilder factory(ObjectFactory factory) { if (!marshallerUseFactory(eClass)) { throw new IllegalStateException("Default marshaller for " + eClass + " value don't use object factory"); } else if (interop instanceof ByteableMarshaller) { if (factory instanceof AllocateInstanceObjectFactory) { agileMarshaller(ByteableMarshaller.of((Class) eClass), factory); } else { agileMarshaller(ByteableMarshaller.of((Class) eClass, (ObjectFactory) factory), factory); } } else if (interop instanceof BytesMarshallableMarshaller) { if (factory instanceof AllocateInstanceObjectFactory) { interop = new BytesMarshallableMarshaller( ((AllocateInstanceObjectFactory) factory).allocatedClass()); } else { interop = new BytesMarshallableMarshallerWithCustomFactory( ((BytesMarshallableMarshaller) interop).marshaledClass(), factory ); } } else if (interop instanceof ExternalizableMarshaller) { if (factory instanceof AllocateInstanceObjectFactory) { interop = new ExternalizableMarshaller( ((AllocateInstanceObjectFactory) factory).allocatedClass()); } else { interop = new ExternalizableMarshallerWithCustomFactory( ((ExternalizableMarshaller) interop).marshaledClass(), factory ); } } else { // interop is custom, it is user's responsibility to use the same factory inside // marshaller and standalone throw new IllegalStateException( "Change the value factory simultaneously with marshaller " + "using *AndFactory() method"); } this.factory = factory; return this; } @Override public SerializationBuilder clone() { try { return (SerializationBuilder) super.clone(); } catch (CloneNotSupportedException e) { throw new AssertionError(e); } } private enum IntegerMarshaller implements BytesMarshaller { INSTANCE; @Override public void write(Bytes bytes, Integer v) { bytes.writeInt(v); } @Nullable @Override public Integer read(Bytes bytes) { return bytes.readInt(); } @Nullable @Override public Integer read(Bytes bytes, @Nullable Integer v) { return bytes.readInt(); } } private enum DoubleMarshaller implements BytesMarshaller { INSTANCE; @Override public void write(Bytes bytes, Double v) { bytes.writeDouble(v); } @Nullable @Override public Double read(Bytes bytes) { return bytes.readDouble(); } @Nullable @Override public Double read(Bytes bytes, @Nullable Double v) { return bytes.readDouble(); } } private static class SerializableMarshaller implements BytesMarshaller { private static final long serialVersionUID = 0L; private final ObjectSerializer serializer; private SerializableMarshaller(ObjectSerializer serializer) { this.serializer = serializer; } @Override public void write(Bytes bytes, Object obj) { try { serializer.writeSerializable(bytes, obj, null); } catch (IOException e) { throw new IllegalStateException(e); } } @Nullable @Override public Object read(Bytes bytes) { try { return serializer.readSerializable(bytes, null, null); } catch (IOException e) { throw new IllegalStateException(e); } catch (ClassNotFoundException e) { throw new IllegalStateException(e); } } @Nullable @Override public Object read(Bytes bytes, @Nullable Object obj) { try { return serializer.readSerializable(bytes, null, obj); } catch (IOException e) { throw new IllegalStateException(e); } catch (ClassNotFoundException e) { throw new IllegalStateException(e); } } } private static class BytesMarshallableMarshallerWithCustomFactory extends BytesMarshallableMarshaller { private static final long serialVersionUID = 0L; @NotNull private final ObjectFactory factory; BytesMarshallableMarshallerWithCustomFactory(@NotNull Class tClass, @NotNull ObjectFactory factory) { super(tClass); this.factory = factory; } @NotNull @Override protected T getInstance() throws Exception { return factory.create(); } @Override public boolean equals(Object obj) { if (obj == null || obj.getClass() != getClass()) return false; BytesMarshallableMarshallerWithCustomFactory that = (BytesMarshallableMarshallerWithCustomFactory) obj; return that.marshaledClass() == marshaledClass() && that.factory.equals(this.factory); } @Override public int hashCode() { return hash(marshaledClass(), factory); } @Override public String toString() { return getClass().getSimpleName() + "{marshaledClass=" + marshaledClass() + ",factory=" + factory + "}"; } } private static class ExternalizableMarshallerWithCustomFactory extends ExternalizableMarshaller { private static final long serialVersionUID = 0L; @NotNull private final ObjectFactory factory; ExternalizableMarshallerWithCustomFactory(@NotNull Class tClass, @NotNull ObjectFactory factory) { super(tClass); this.factory = factory; } @NotNull @Override protected T getInstance() throws Exception { return factory.create(); } @Override public boolean equals(Object obj) { if (obj == null || obj.getClass() != getClass()) return false; ExternalizableMarshallerWithCustomFactory that = (ExternalizableMarshallerWithCustomFactory) obj; return that.marshaledClass() == marshaledClass() && that.factory.equals(this.factory); } @Override public int hashCode() { return hash(marshaledClass(), factory); } @Override public String toString() { return getClass().getSimpleName() + "{marshaledClass=" + marshaledClass() + ",factory=" + factory + "}"; } } }