diff options
author | Emmanuel Bourg <ebourg@apache.org> | 2016-08-03 10:17:09 +0200 |
---|---|---|
committer | Emmanuel Bourg <ebourg@apache.org> | 2016-08-03 10:17:09 +0200 |
commit | 3d9b009255ffd897a9bd84ca3977cd3f553da8ef (patch) | |
tree | 13a8296e2989ff8da3fc50d335fd48b2dd0c6064 /lang/src/main/java/net/openhft/lang/io/serialization | |
parent | b2ec1a2d459cfef3ff13133c1f7f5972e3740258 (diff) |
Imported Upstream version 6.7.6
Diffstat (limited to 'lang/src/main/java/net/openhft/lang/io/serialization')
40 files changed, 1828 insertions, 660 deletions
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/BytesMarshallable.java b/lang/src/main/java/net/openhft/lang/io/serialization/BytesMarshallable.java index a92b316..5ac643e 100644 --- a/lang/src/main/java/net/openhft/lang/io/serialization/BytesMarshallable.java +++ b/lang/src/main/java/net/openhft/lang/io/serialization/BytesMarshallable.java @@ -1,23 +1,23 @@ /* - * Copyright 2013 Peter Lawrey + * Copyright (C) 2015 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 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License. * - * http://www.apache.org/licenses/LICENSE-2.0 + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package net.openhft.lang.io.serialization; import net.openhft.lang.io.Bytes; -import org.jetbrains.annotations.NotNull; +import net.openhft.lang.model.constraints.NotNull; /** * Integrated marshaller for objects. diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/BytesMarshallableSerializer.java b/lang/src/main/java/net/openhft/lang/io/serialization/BytesMarshallableSerializer.java new file mode 100644 index 0000000..d68e355 --- /dev/null +++ b/lang/src/main/java/net/openhft/lang/io/serialization/BytesMarshallableSerializer.java @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2015 higherfrequencytrading.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package net.openhft.lang.io.serialization; + +import net.openhft.lang.io.AbstractBytes; +import net.openhft.lang.io.Bytes; +import net.openhft.lang.io.NativeBytes; +import net.openhft.lang.io.serialization.impl.NoMarshaller; +import net.openhft.lang.io.serialization.impl.StringBuilderPool; +import net.openhft.lang.io.serialization.impl.VanillaBytesMarshallerFactory; +import net.openhft.lang.model.constraints.NotNull; +import net.openhft.lang.pool.EnumInterner; + +import java.io.Externalizable; +import java.io.IOException; + +/** + * An extension of built-in Java serialization, featuring special treatment of {@link + * BytesMarshallable} objects, compact {@link String} encoding and support of pluggable custom + * serializers for arbitrary classes. + * + * <p>{@code BytesMarshallableSerializer} could benefit if objects (either top-level serialized or + * nested fields) implement {@link BytesMarshallable} interface the same way as built-in + * serialization benefit if objects implement {@link Externalizable} (of cause, {@code + * BytesMarshallableSerializer} supports {@code Externalizable} too). + * + * <p>{@link CharSequence}s, including {@code String}s (either top-level serialized or nested + * fields) are serialized in UTF-8 encoding. + * + * <p>Custom per-class serializers are held by {@link BytesMarshallerFactory}, which could be + * passed via constructor or static factory {@link #create create()} method. + * + * @see #create(BytesMarshallerFactory, ObjectSerializer) + */ +public class BytesMarshallableSerializer implements ObjectSerializer { + private static final long serialVersionUID = 0L; + + private static final byte NULL = 'N'; + private static final byte ENUMED = 'E'; + private static final byte SERIALIZED = 'S'; + private static final StringBuilderPool SBP = new StringBuilderPool(); + + private final BytesMarshallerFactory bytesMarshallerFactory; + private final ObjectSerializer objectSerializer; + + protected BytesMarshallableSerializer(BytesMarshallerFactory bytesMarshallerFactory, ObjectSerializer objectSerializer) { + this.bytesMarshallerFactory = bytesMarshallerFactory; + this.objectSerializer = objectSerializer; + } + + @Override + public void writeSerializable(Bytes bytes, Object object, Class expectedClass) throws IOException { + if (object == null) { + bytes.writeByte(NULL); + return; + } + if (expectedClass != null) { + if (BytesMarshallable.class.isAssignableFrom(expectedClass)) { + ((BytesMarshallable) object).writeMarshallable(bytes); + return; + + } else if (Externalizable.class.isAssignableFrom(expectedClass)) { + ((Externalizable) object).writeExternal(bytes); + return; + + } else if (CharSequence.class.isAssignableFrom(expectedClass)) { + bytes.writeUTFΔ((CharSequence) object); + return; + + } else if (Enum.class.isAssignableFrom(expectedClass)) { + bytes.write8bitText(object.toString()); + return; + } + } + writeSerializable2(bytes, object); + } + + private void writeSerializable2(Bytes bytes, Object object) throws IOException { + Class<?> clazz = object.getClass(); + BytesMarshaller em = bytesMarshallerFactory.acquireMarshaller(clazz, false); + if (em == NoMarshaller.INSTANCE && autoGenerateMarshaller(object)) + em = bytesMarshallerFactory.acquireMarshaller(clazz, true); + + if (em != NoMarshaller.INSTANCE) { + if (em instanceof CompactBytesMarshaller) { + bytes.writeByte(((CompactBytesMarshaller) em).code()); + em.write(bytes, object); + return; + } + bytes.writeByte(ENUMED); + this.writeSerializable(bytes, clazz, Class.class); + em.write(bytes, object); + return; + } + bytes.writeByte(SERIALIZED); + // TODO this is the lame implementation, but it works. + objectSerializer.writeSerializable(bytes, object, null); + } + + static boolean autoGenerateMarshaller(Object obj) { + return (obj instanceof Comparable && obj.getClass().getPackage().getName().startsWith("java")) + || obj instanceof Externalizable + || obj instanceof BytesMarshallable; + } + + @Override + public <T> T readSerializable(@NotNull Bytes bytes, Class<T> expectedClass, T object) throws IOException, ClassNotFoundException { + if (expectedClass != null) { + try { + if (BytesMarshallable.class.isAssignableFrom(expectedClass)) { + return readBytesMarshallable(bytes, expectedClass, object); + + } else if (Externalizable.class.isAssignableFrom(expectedClass)) { + return readExternalizable(bytes, expectedClass, object); + + } else if (CharSequence.class.isAssignableFrom(expectedClass)) { + return readCharSequence(bytes, object); + + } else if (Enum.class.isAssignableFrom(expectedClass)) { + StringBuilder sb = SBP.acquireStringBuilder(); + bytes.read8bitText(sb); + return (T) EnumInterner.intern((Class<Enum>) expectedClass, sb); + } + } catch (InstantiationException e) { + throw new IOException("Unable to create " + expectedClass, e); + } + } + int type = bytes.readUnsignedByteOrThrow(); + switch (type) { + case AbstractBytes.END_OF_BUFFER: + case NULL: + return null; + case ENUMED: { + Class clazz = this.readSerializable(bytes, Class.class, null); + assert clazz != null; + return (T) bytesMarshallerFactory.acquireMarshaller(clazz, true).read(bytes, object); + } + + case SERIALIZED: { + return objectSerializer.readSerializable(bytes, expectedClass, object); + } + + default: + BytesMarshaller<Object> m = bytesMarshallerFactory.getMarshaller((byte) type); + if (m == null) + throw new IllegalStateException("Unknown type " + (char) type); + return (T) m.read(bytes); + } + } + + private <T> T readCharSequence(Bytes bytes, T object) { + if (object instanceof StringBuilder) { + bytes.readUTFΔ(((StringBuilder) object)); + return object; + + } else { + return (T) bytes.readUTFΔ(); + } + } + + private <T> T readExternalizable(Bytes bytes, Class<T> expectedClass, T object) throws InstantiationException, IOException, ClassNotFoundException { + if (object == null) + object = (T) NativeBytes.UNSAFE.allocateInstance(expectedClass); + ((Externalizable) object).readExternal(bytes); + return object; + } + + private <T> T readBytesMarshallable(Bytes bytes, Class<T> expectedClass, T object) throws InstantiationException { + if (object == null) + object = (T) NativeBytes.UNSAFE.allocateInstance(expectedClass); + ((BytesMarshallable) object).readMarshallable(bytes); + return object; + } + + public static ObjectSerializer create() { + return create(new VanillaBytesMarshallerFactory(), JDKZObjectSerializer.INSTANCE); + } + + public static ObjectSerializer create(BytesMarshallerFactory bytesMarshallerFactory, ObjectSerializer instance) { + return bytesMarshallerFactory == null ? instance : new BytesMarshallableSerializer(bytesMarshallerFactory, instance); + } +} diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/BytesMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/BytesMarshaller.java index d9a4fa2..d2593aa 100644 --- a/lang/src/main/java/net/openhft/lang/io/serialization/BytesMarshaller.java +++ b/lang/src/main/java/net/openhft/lang/io/serialization/BytesMarshaller.java @@ -1,45 +1,60 @@ /* - * Copyright 2013 Peter Lawrey + * Copyright (C) 2015 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 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License. * - * http://www.apache.org/licenses/LICENSE-2.0 + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package net.openhft.lang.io.serialization; import net.openhft.lang.io.Bytes; -import org.jetbrains.annotations.Nullable; +import net.openhft.lang.model.constraints.Nullable; + +import java.io.Serializable; /** - * External marshaller for classes. + * External marshaller for classes. From design patterns point of view, this interface + * is marshalling <i>strategy</i>. * * @author peter.lawrey * @see BytesMarshallable */ -public interface BytesMarshaller<E> { +public interface BytesMarshaller<E> extends Serializable { + /** - * write the object out as bytes. + * Write the object out to the {@code bytes}. * * @param bytes to write to - * @param e to write + * @param e the object to write */ void write(Bytes bytes, E e); /** - * Read bytes and obtain an object + * Reads and returns an object from {@code bytes}. * * @param bytes to read - * @return the object + * @return the read object */ @Nullable E read(Bytes bytes); + + /** + * Reads and returns an object from {@code bytes}, reusing the given object, if possible. + * + * @param bytes to read + * @param e an object to reuse, if possible. {@code null} could be passed, in this case + * a new object should be allocated anyway. + * @return the read object + */ + @Nullable + E read(Bytes bytes, @Nullable E e); } diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/BytesMarshallerFactory.java b/lang/src/main/java/net/openhft/lang/io/serialization/BytesMarshallerFactory.java index 87218b7..6814fe8 100644 --- a/lang/src/main/java/net/openhft/lang/io/serialization/BytesMarshallerFactory.java +++ b/lang/src/main/java/net/openhft/lang/io/serialization/BytesMarshallerFactory.java @@ -1,27 +1,29 @@ /* - * Copyright 2013 Peter Lawrey + * Copyright (C) 2015 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 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License. * - * http://www.apache.org/licenses/LICENSE-2.0 + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package net.openhft.lang.io.serialization; -import org.jetbrains.annotations.NotNull; +import net.openhft.lang.model.constraints.NotNull; + +import java.io.Serializable; /** * @author peter.lawrey */ -public interface BytesMarshallerFactory { +public interface BytesMarshallerFactory extends Serializable { @NotNull <E> BytesMarshaller<E> acquireMarshaller(@NotNull Class<E> eClass, boolean create); diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/CompactBytesMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/CompactBytesMarshaller.java index 6ee1f87..5b8ef29 100644 --- a/lang/src/main/java/net/openhft/lang/io/serialization/CompactBytesMarshaller.java +++ b/lang/src/main/java/net/openhft/lang/io/serialization/CompactBytesMarshaller.java @@ -1,17 +1,17 @@ /* - * Copyright 2013 Peter Lawrey + * Copyright (C) 2015 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 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License. * - * http://www.apache.org/licenses/LICENSE-2.0 + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package net.openhft.lang.io.serialization; @@ -20,8 +20,21 @@ package net.openhft.lang.io.serialization; * A BytesMarshaller with a byte code for the class. */ public interface CompactBytesMarshaller<E> extends BytesMarshaller<E> { + byte BYTE_BUFFER_CODE = 'B' & 31; + byte CLASS_CODE = 'C' & 31; + byte INT_CODE = 'I' & 31; + byte LONG_CODE = 'L' & 31; + byte DOUBLE_CODE = 'D' & 31; + byte DATE_CODE = 'T' & 31; + byte STRING_CODE = 'S' & 31; + byte STRINGZ_MAP_CODE = 'Y' & 31; // compressed string. + byte STRINGZ_CODE = 'Z' & 31; // compressed string. + byte LIST_CODE = '['; + byte SET_CODE = '[' & 31; + byte MAP_CODE = '{'; + /** - * the code for this marshaller + * @return the code for this marshaller */ byte code(); } diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/JDKObjectSerializer.java b/lang/src/main/java/net/openhft/lang/io/serialization/JDKObjectSerializer.java new file mode 100644 index 0000000..30557fe --- /dev/null +++ b/lang/src/main/java/net/openhft/lang/io/serialization/JDKObjectSerializer.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2015 higherfrequencytrading.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package net.openhft.lang.io.serialization; + +import net.openhft.lang.io.Bytes; +import net.openhft.lang.model.constraints.NotNull; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +public enum JDKObjectSerializer implements ObjectSerializer { + INSTANCE; + + @Override + public void writeSerializable(Bytes bytes, Object object, Class expectedClass) throws IOException { + new ObjectOutputStream(bytes.outputStream()).writeObject(object); + } + + @Override + public <T> T readSerializable(@NotNull Bytes bytes, Class<T> expectedClass, T object) throws IOException, ClassNotFoundException { + return (T) new ObjectInputStream(bytes.inputStream()).readObject(); + } +} diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/JDKZObjectSerializer.java b/lang/src/main/java/net/openhft/lang/io/serialization/JDKZObjectSerializer.java new file mode 100644 index 0000000..784e7a9 --- /dev/null +++ b/lang/src/main/java/net/openhft/lang/io/serialization/JDKZObjectSerializer.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2015 higherfrequencytrading.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package net.openhft.lang.io.serialization; + +import net.openhft.lang.io.Bytes; +import net.openhft.lang.model.constraints.NotNull; + +import java.io.*; +import java.util.zip.DeflaterOutputStream; +import java.util.zip.InflaterInputStream; + +public enum JDKZObjectSerializer implements ObjectSerializer { + INSTANCE; + + @Override + public void writeSerializable(Bytes bytes, Object object, Class expectedClass) throws IOException { + // reset the finished flag and append + long position = bytes.position(); + bytes.clear(); + bytes.position(position + 4); + OutputStream out = bytes.outputStream(); + ObjectOutputStream oos = new ObjectOutputStream(new DeflaterOutputStream(out)); + oos.writeObject(object); + oos.close(); + long length = bytes.position() - position - 4; + bytes.writeUnsignedInt(position, length); + } + + @Override + public <T> T readSerializable(@NotNull Bytes bytes, Class<T> expectedClass, T object) throws IOException, ClassNotFoundException { + long length = bytes.readUnsignedInt(); + if (length < 8 || length > Integer.MAX_VALUE) + throw new StreamCorruptedException("length = " + Long.toHexString(length)); + long end = bytes.position() + length; + long lim = bytes.limit(); + bytes.limit(end); + int magic = bytes.readUnsignedShort(bytes.position()); + InputStream in = bytes.inputStream(); + switch (magic) { + case 0xEDAC: + break; + + case 0x9c78: + in = new InflaterInputStream(in); + break; + default: + throw new StreamCorruptedException("Unknown magic number " + Integer.toHexString(magic)); + } + T t = (T) new ObjectInputStream(in).readObject(); + bytes.limit(lim); + if (end != bytes.position()) { + System.out.println("diff: " + (end - bytes.position())); + bytes.position(end); + } + return t; + } +} diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/ObjectFactory.java b/lang/src/main/java/net/openhft/lang/io/serialization/ObjectFactory.java new file mode 100644 index 0000000..40dea33 --- /dev/null +++ b/lang/src/main/java/net/openhft/lang/io/serialization/ObjectFactory.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2015 higherfrequencytrading.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package net.openhft.lang.io.serialization; + +import java.io.Serializable; + +public interface ObjectFactory<E> extends Serializable { + E create() throws InstantiationException, IllegalAccessException; +} diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/ObjectSerializer.java b/lang/src/main/java/net/openhft/lang/io/serialization/ObjectSerializer.java new file mode 100644 index 0000000..7683862 --- /dev/null +++ b/lang/src/main/java/net/openhft/lang/io/serialization/ObjectSerializer.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2015 higherfrequencytrading.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package net.openhft.lang.io.serialization; + +import net.openhft.lang.io.Bytes; +import net.openhft.lang.model.constraints.NotNull; + +import java.io.*; + +/** + * Abstracts serialization implementation, which at least should be able to serialize objects that + * Java built-in serialization is able serialize. In other words, {@code ObjectSerializer} abstracts + * Java serialization re-implementations and extensions. {@link Bytes} is used as core IO interface + * instead of {@link InputStream} + {@link OutputStream} pair, which Java built-in serialization + * use. However, note that {@code Bytes} could always be converted to these old interfaces by + * {@link Bytes#inputStream()} and {@link Bytes#outputStream()}, if needed. + * + * <p>The default fallback implementation is Java built-in serialization itself: + * {@link JDKObjectSerializer}. + * + * <p>Another provided implementation is {@link BytesMarshallableSerializer}, which basically + * extends built-in serialization with some improvements. For example, it could benefit if objects + * implement {@link BytesMarshallable} interface the same way as built-in serialization benefit + * if objects implement {@link Externalizable}. See {@link BytesMarshallableSerializer} docs for + * more information. + * + * <p>This interface is supposed to be implemented to plug such third-party serialization + * re-implementations, as Kryo, fast-serialization, etc. + */ +public interface ObjectSerializer extends Serializable { + /** + * write an object + * + * @param bytes to write to + * @param object object to write + * @param expectedClass which will be provided on read, can be null + */ + void writeSerializable(@NotNull Bytes bytes, Object object, Class expectedClass) throws IOException; + + /** + * Read an object + * + * @param bytes to read + * @param expectedClass proved when writing, can be null + * @param object to populate, can be null + * @return object read. + * @throws IOException if it not possible to serialize the object + * @throws ClassNotFoundException if the expectedClass can not be created + */ + <T> T readSerializable(@NotNull Bytes bytes, Class<T> expectedClass, T object) throws IOException, ClassNotFoundException; +} diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/RawCopier.java b/lang/src/main/java/net/openhft/lang/io/serialization/RawCopier.java deleted file mode 100644 index eaf5760..0000000 --- a/lang/src/main/java/net/openhft/lang/io/serialization/RawCopier.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2013 Peter Lawrey - * - * 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.lang.io.serialization; - -import net.openhft.lang.io.Bytes; - -import java.lang.reflect.Array; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - -import static net.openhft.lang.io.NativeBytes.UNSAFE; - -/** - * User: peter.lawrey Date: 22/09/13 Time: 16:51 - */ -public class RawCopier<T> { - final int start, end; - private final Class<T> tClass; - - public RawCopier(Class<T> tClass) { - this.tClass = tClass; - List<Field> fields = new ArrayList<Field>(); - addAllFields(fields, tClass); - Collections.sort(fields, new Comparator<Field>() { - @Override - public int compare(Field o1, Field o2) { - long off1 = UNSAFE.objectFieldOffset(o1); - long off2 = UNSAFE.objectFieldOffset(o2); - return Double.compare(off1, off2); - } - }); - start = (int) UNSAFE.objectFieldOffset(fields.get(0)); - Field lastField = null; - for (Field field : fields) { - if (Modifier.isTransient(field.getModifiers()) || !field.getType().isPrimitive()) - break; - lastField = field; - } - end = (int) UNSAFE.objectFieldOffset(lastField) + sizeOf(lastField.getType()); - - assert end > start : "end <= start, start: " + start + ", end: " + end; - } - - public static <T> RawCopier<T> copies(Class<T> tClass) { - return new RawCopier<T>(tClass); - } - - private static int sizeOf(Class<?> type) { - return UNSAFE.arrayIndexScale(Array.newInstance(type, 0).getClass()); - } - - public int start() { - return start; - } - - public int end() { - return end; - } - - public void toBytes(Object obj, Bytes bytes) { - bytes.writeObject(obj, start, end); - } - - public void fromBytes(Bytes bytes, Object obj) { - bytes.readObject(obj, start, end); - } - - public void copy(T from, T to) { - long i; - for (i = start; i < end - 7; i += 8) { - UNSAFE.putLong(to, i, UNSAFE.getLong(from, i)); - } - for (; i < end; i++) { - UNSAFE.putByte(to, i, UNSAFE.getByte(from, i)); - } - } - - private void addAllFields(List<Field> fields, Class tClass) { - if (tClass != null && tClass != Object.class) - addAllFields(fields, tClass.getSuperclass()); - for (Field field : tClass.getDeclaredFields()) { - if (!Modifier.isStatic(field.getModifiers())) - fields.add(field); - } - } -} diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/direct/DirectSerializationFilter.java b/lang/src/main/java/net/openhft/lang/io/serialization/direct/DirectSerializationFilter.java deleted file mode 100644 index c6b5b2e..0000000 --- a/lang/src/main/java/net/openhft/lang/io/serialization/direct/DirectSerializationFilter.java +++ /dev/null @@ -1,29 +0,0 @@ -package net.openhft.lang.io.serialization.direct; - -import java.lang.reflect.Field; -import java.util.*; - -import static net.openhft.lang.io.serialization.direct.FieldMetadata.*; - -public final class DirectSerializationFilter { - public static List<Field> stopAtFirstIneligibleField(List<Field> fields) { - ArrayList<Field> eligibleFields = new ArrayList<Field>(); - for (Field f : fields) { - if (checkEligible(f)) { - eligibleFields.add(f); - } else { - break; - } - } - - return eligibleFields.isEmpty() ? - Collections.<Field>emptyList() : - eligibleFields; - } - - private static boolean checkEligible(Field f) { - return isPrimitive(f) && - !isStatic(f) && - !isTransient(f); - } -}
\ No newline at end of file diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/direct/DirectSerializationMetadata.java b/lang/src/main/java/net/openhft/lang/io/serialization/direct/DirectSerializationMetadata.java deleted file mode 100644 index 2fcd50c..0000000 --- a/lang/src/main/java/net/openhft/lang/io/serialization/direct/DirectSerializationMetadata.java +++ /dev/null @@ -1,89 +0,0 @@ -package net.openhft.lang.io.serialization.direct; - -import net.openhft.lang.Jvm; - -import java.lang.reflect.Field; -import java.util.List; - -import static net.openhft.lang.io.NativeBytes.UNSAFE; - -public class DirectSerializationMetadata { - private static final int OBJECT_ALIGNMENT = 8; - private static final int OBJECT_ALIGNMENT_MASK = OBJECT_ALIGNMENT - 1; - - static final long NATIVE_WORD_SIZE = Jvm.is64Bit() ? 8 : 4; - static final long OOP_SIZE = UNSAFE.arrayIndexScale(Object[].class); - static final long OBJECT_HEADER_SIZE = NATIVE_WORD_SIZE + OOP_SIZE; // Object header has a native sized mark word + variable sized oop to klass meta object - - public static final SerializationMetadata EmptyObjectMetadata = new SerializationMetadata(0, 0); - - public static final class SerializationMetadata { - final long start; - final long length; - - SerializationMetadata(long start, long length) { - this.start = start; - this.length = length; - } - - @Override - public String toString() { - return String.format("SerializationMetadata: Start %s Length %s", start, length); - } - } - - public static SerializationMetadata extractMetadata(List<Field> fields) { - if (fields.isEmpty()) return EmptyObjectMetadata; - - Offsets offsets = minMaxOffsets(fields); - - long totalSize = OBJECT_HEADER_SIZE + offsets.max - offsets.min + 1; - return new SerializationMetadata(offsets.min, padToObjectAlignment(totalSize) - OBJECT_HEADER_SIZE); - } - - public static SerializationMetadata extractMetadataForPartialCopy(List<Field> fields) { - if (fields.isEmpty()) return EmptyObjectMetadata; - - Offsets offsets = minMaxOffsets(fields); - - Field lastField = fields.get(fields.size() - 1); - - return new SerializationMetadata(offsets.min, offsets.max + sizeOf(lastField) - OBJECT_HEADER_SIZE); - } - - private static Offsets minMaxOffsets(List<Field> fields) { - long minOffset = UNSAFE.objectFieldOffset(fields.get(0)); - long maxOffset = UNSAFE.objectFieldOffset(fields.get(fields.size() - 1)); - - return new Offsets(minOffset, maxOffset); - } - - static long padToObjectAlignment(long length) { - if ((length & OBJECT_ALIGNMENT_MASK) != 0) { - long padding = OBJECT_ALIGNMENT - (length & OBJECT_ALIGNMENT_MASK); - length += padding; - } - - return length; - } - - private static long sizeOf(Field field) { - if (boolean.class.equals(field.getType())) return 1; - else if (byte.class.equals(field.getType())) return 1; - else if (short.class.equals(field.getType())) return 2; - else if (char.class.equals(field.getType())) return 2; - else if (int.class.equals(field.getType())) return 4; - else if (float.class.equals(field.getType())) return 4; - else return 8; - } - - private static final class Offsets { - public final long min; - public final long max; - - private Offsets(long min, long max) { - this.min = min; - this.max = max; - } - } -}
\ No newline at end of file diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/direct/FieldMetadata.java b/lang/src/main/java/net/openhft/lang/io/serialization/direct/FieldMetadata.java deleted file mode 100644 index d186c77..0000000 --- a/lang/src/main/java/net/openhft/lang/io/serialization/direct/FieldMetadata.java +++ /dev/null @@ -1,22 +0,0 @@ -package net.openhft.lang.io.serialization.direct; - -import java.lang.reflect.*; - -public final class FieldMetadata { - public static boolean isPrimitive(Field f) { - return f.getType().isPrimitive(); - } - - public static boolean isPrimitiveArray(Field f) { - Class<?> clazz = f.getType(); - return clazz.isArray() && clazz.getComponentType().isPrimitive(); - } - - public static boolean isStatic(Field f) { - return Modifier.isStatic(f.getModifiers()); - } - - public static boolean isTransient(Field f) { - return Modifier.isTransient(f.getModifiers()); - } -} diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/direct/Introspect.java b/lang/src/main/java/net/openhft/lang/io/serialization/direct/Introspect.java deleted file mode 100644 index 28ff782..0000000 --- a/lang/src/main/java/net/openhft/lang/io/serialization/direct/Introspect.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2013 Peter Lawrey - * - * 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.lang.io.serialization.direct; - -import net.openhft.lang.Maths; - -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - -import static net.openhft.lang.io.NativeBytes.UNSAFE; -import static net.openhft.lang.io.serialization.direct.FieldMetadata.isStatic; - -public class Introspect { - public static List<Field> fields(Class<?> clazz) { - ArrayList<Field> fields = new ArrayList<Field>(); - - addToFields(clazz, fields); - Collections.sort(fields, FieldOffsetComparator.Instance); - - return fields; - } - - private static List<Field> addToFields(Class<?> clazz, ArrayList<Field> accumulator) { - Collections.addAll(accumulator, clazz.getDeclaredFields()); - Class<?> maybeSuper = clazz.getSuperclass(); - - return maybeSuper != null ? - addToFields(maybeSuper, accumulator) : - accumulator; - } - - private static final class FieldOffsetComparator implements Comparator<Field> { - public static final FieldOffsetComparator Instance = new FieldOffsetComparator(); - - @Override - public int compare(Field first, Field second) { - return Maths.compare(offset(first), offset(second)); - } - - private static long offset(Field field) { - return isStatic(field) ? - UNSAFE.staticFieldOffset(field) : - UNSAFE.objectFieldOffset(field); - } - } -}
\ No newline at end of file diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/direct/ObjectMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/direct/ObjectMarshaller.java deleted file mode 100644 index 24f8a48..0000000 --- a/lang/src/main/java/net/openhft/lang/io/serialization/direct/ObjectMarshaller.java +++ /dev/null @@ -1,50 +0,0 @@ -package net.openhft.lang.io.serialization.direct; - -import net.openhft.lang.io.Bytes; - -import static net.openhft.lang.io.NativeBytes.UNSAFE; -import static net.openhft.lang.io.serialization.direct.DirectSerializationMetadata.SerializationMetadata; - -public final class ObjectMarshaller<T> { - private final SerializationMetadata metadata; - - public ObjectMarshaller(SerializationMetadata metadata) { - this.metadata = metadata; - } - - public void write(Bytes bytes, T tObject) { - long i = metadata.start; - long end = metadata.start + metadata.length; - - while (i < end - 7) { - bytes.writeLong(UNSAFE.getLong(tObject, i)); - i += 8; - } - - while (i < end) { - bytes.writeByte(UNSAFE.getByte(tObject, i)); - ++i; - } - } - - public T read(Bytes bytes, T tObject) { - long i = metadata.start; - long end = metadata.start + metadata.length; - - while (i < end - 7) { - UNSAFE.putLong(tObject, i, bytes.readLong()); - i += 8; - } - - while (i < end) { - UNSAFE.putByte(tObject, i, bytes.readByte()); - ++i; - } - - return tObject; - } - - public long length() { - return metadata.length; - } -}
\ No newline at end of file diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/direct/ObjectMarshallers.java b/lang/src/main/java/net/openhft/lang/io/serialization/direct/ObjectMarshallers.java deleted file mode 100644 index bb9e35d..0000000 --- a/lang/src/main/java/net/openhft/lang/io/serialization/direct/ObjectMarshallers.java +++ /dev/null @@ -1,72 +0,0 @@ -package net.openhft.lang.io.serialization.direct; - -import net.openhft.lang.io.NativeBytes; - -import java.lang.reflect.Field; -import java.util.*; -import java.util.logging.Logger; - -import static java.util.logging.Level.WARNING; -import static net.openhft.lang.io.serialization.direct.DirectSerializationMetadata.SerializationMetadata; - -public final class ObjectMarshallers { - private static final Logger Log = Logger.getLogger(ObjectMarshallers.class.getName()); - - private static final Map<Class, ObjectMarshaller> metadata = new HashMap<Class, ObjectMarshaller>(); - - @SuppressWarnings("unchecked") - public static <T> ObjectMarshaller<T> forClass(Class<T> clazz) { - ObjectMarshaller om = metadata.get(clazz); - if (om == null) { - List<Field> fields = Introspect.fields(clazz); - List<Field> eligibleFields = DirectSerializationFilter.stopAtFirstIneligibleField(fields); - - SerializationMetadata serializationMetadata; - - if (hasIneligibleFields(fields, eligibleFields)) { - WarnAboutIneligibleFields.apply(clazz, fields, eligibleFields); - serializationMetadata = DirectSerializationMetadata.extractMetadataForPartialCopy(eligibleFields); - } else { - serializationMetadata = DirectSerializationMetadata.extractMetadata(eligibleFields); - } - - om = new ObjectMarshaller<T>(serializationMetadata); - Log.log(WARNING, String.format("Class %s has metadata %s", clazz.getName(), serializationMetadata)); - metadata.put(clazz, om); - } - - return (ObjectMarshaller<T>) om; - } - - private static boolean hasIneligibleFields(List<Field> allFields, List<Field> eligibleFields) { - return allFields.size() != eligibleFields.size(); - } - - private static class WarnAboutIneligibleFields { - static void apply(Class clazz, List<Field> allFields, List<Field> eligibleFields) { - List<Field> ineligibleFields = allFields.subList(eligibleFields.size(), allFields.size()); - Log.log(WARNING, String.format( - "The following fields in Class %s will not be copied by ObjectMarshaller:\n%s", - clazz.getName(), - commaSeparate(ineligibleFields) - )); - } - - private static String commaSeparate(Collection<Field> fields) { - StringBuilder sb = new StringBuilder(); - boolean first = true; - for (Field field : fields) { - if (first) { - sb.append("\t"); - sb.append(field.getName()); - first = false; - } else { - sb.append("\n\t"); - sb.append(field.getName()); - } - } - - return sb.toString(); - } - } -} diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/AllocateInstanceObjectFactory.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/AllocateInstanceObjectFactory.java new file mode 100644 index 0000000..70ac6f7 --- /dev/null +++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/AllocateInstanceObjectFactory.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2015 higherfrequencytrading.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package net.openhft.lang.io.serialization.impl; + +import net.openhft.lang.io.NativeBytes; +import net.openhft.lang.io.serialization.ObjectFactory; + +import java.lang.reflect.Modifier; + +/** + * Object factory which creates an object by means of {@code Unsafe.allocateInstance()} call, + * i. e. without calling constructor. + * + * @param <E> type of created objects + */ +public final class AllocateInstanceObjectFactory<E> implements ObjectFactory<E> { + private static final long serialVersionUID = 0L; + + private final Class<E> eClass; + + public AllocateInstanceObjectFactory(Class<E> eClass) { + if (eClass.isInterface() || Modifier.isAbstract(eClass.getModifiers()) || + eClass.isEnum()) { + throw new IllegalArgumentException(eClass + " should be a non-abstract non-enum class"); + } + this.eClass = eClass; + } + + public Class<E> allocatedClass() { + return eClass; + } + + @SuppressWarnings("unchecked") + @Override + public E create() throws InstantiationException { + return (E) NativeBytes.UNSAFE.allocateInstance(eClass); + } + + @Override + public boolean equals(Object obj) { + return obj != null && obj.getClass() == getClass() && + ((AllocateInstanceObjectFactory) obj).eClass == eClass; + } + + @Override + public int hashCode() { + return eClass.hashCode(); + } + + @Override + public String toString() { + return getClass().getSimpleName() + "{eClass=" + eClass + "}"; + } +} diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/ByteBufferMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/ByteBufferMarshaller.java new file mode 100644 index 0000000..ac4051f --- /dev/null +++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/ByteBufferMarshaller.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2015 higherfrequencytrading.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package net.openhft.lang.io.serialization.impl; + +import net.openhft.lang.io.Bytes; +import net.openhft.lang.io.serialization.CompactBytesMarshaller; +import net.openhft.lang.model.constraints.Nullable; + +import java.nio.ByteBuffer; + +public enum ByteBufferMarshaller implements CompactBytesMarshaller<ByteBuffer> { + INSTANCE; + + @Override + public byte code() { + return BYTE_BUFFER_CODE; + } + + @Override + public void write(Bytes bytes, ByteBuffer byteBuffer) { + int position = byteBuffer.position(); + bytes.writeStopBit(byteBuffer.remaining()); + bytes.write(byteBuffer); + + // reset the position back as we found it + byteBuffer.position(position); + } + + @Override + public ByteBuffer read(Bytes bytes) { + return read(bytes, null); + } + + @Override + public ByteBuffer read(Bytes bytes, @Nullable ByteBuffer byteBuffer) { + long length = bytes.readStopBit(); + assert length <= Integer.MAX_VALUE; + if (length < 0 || length > Integer.MAX_VALUE) { + throw new IllegalStateException("Invalid length: " + length); + } + if (byteBuffer == null || byteBuffer.capacity() < length) { + byteBuffer = newByteBuffer((int) length); + + } else { + byteBuffer.position(0); + byteBuffer.limit((int) length); + } + + bytes.read(byteBuffer); + byteBuffer.flip(); + return byteBuffer; + } + + protected ByteBuffer newByteBuffer(int length) { + return ByteBuffer.allocate(length); + } +} diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/ByteBufferZMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/ByteBufferZMarshaller.java new file mode 100644 index 0000000..fe648e9 --- /dev/null +++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/ByteBufferZMarshaller.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2015 higherfrequencytrading.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package net.openhft.lang.io.serialization.impl; + +import net.openhft.lang.io.Bytes; +import net.openhft.lang.io.serialization.CompactBytesMarshaller; +import net.openhft.lang.model.constraints.Nullable; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.zip.DeflaterOutputStream; +import java.util.zip.InflaterInputStream; + +public enum ByteBufferZMarshaller implements CompactBytesMarshaller<ByteBuffer> { + INSTANCE; + + @Override + public byte code() { + return BYTE_BUFFER_CODE; + } + + @Override + public void write(Bytes bytes, ByteBuffer byteBuffer) { + bytes.writeStopBit(byteBuffer.remaining()); + long position = bytes.position(); + bytes.clear(); + bytes.position(position + 4); + DataOutputStream dos = new DataOutputStream(new DeflaterOutputStream(bytes.outputStream())); + try { + while (byteBuffer.remaining() >= 8) + dos.writeLong(byteBuffer.getLong()); + while (byteBuffer.remaining() > 0) + dos.write(byteBuffer.get()); + dos.close(); + } catch (IOException e) { + throw new IllegalStateException(e); + } + bytes.writeUnsignedInt(position, bytes.position() - position - 4); + + bytes.write(byteBuffer); + } + + @Override + public ByteBuffer read(Bytes bytes) { + return read(bytes, null); + } + + @Override + public ByteBuffer read(Bytes bytes, @Nullable ByteBuffer byteBuffer) { + long length = bytes.readStopBit(); + if (length < 0 || length > Integer.MAX_VALUE) { + throw new IllegalStateException("Invalid length: " + length); + } + if (byteBuffer == null || byteBuffer.capacity() < length) { + byteBuffer = newByteBuffer((int) length); + + } else { + byteBuffer.clear(); + } + byteBuffer.limit((int) length); + + long position = bytes.position(); + long end = position + length; + + long limit = bytes.limit(); + bytes.limit(end); + + DataInputStream dis = new DataInputStream(new InflaterInputStream(bytes.inputStream())); + try { + while (byteBuffer.remaining() >= 8) + byteBuffer.putLong(dis.readLong()); + while (byteBuffer.remaining() >= 0) + byteBuffer.put(dis.readByte()); + } catch (IOException e) { + throw new IllegalStateException(e); + } + bytes.position(end); + bytes.limit(limit); + + byteBuffer.flip(); + return byteBuffer; + } + + protected ByteBuffer newByteBuffer(int length) { + return ByteBuffer.allocate(length); + } +} diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/BytesMarshallableMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/BytesMarshallableMarshaller.java index ebcb95f..59ea161 100644 --- a/lang/src/main/java/net/openhft/lang/io/serialization/impl/BytesMarshallableMarshaller.java +++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/BytesMarshallableMarshaller.java @@ -1,31 +1,34 @@ /* - * Copyright 2013 Peter Lawrey + * Copyright (C) 2015 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 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License. * - * http://www.apache.org/licenses/LICENSE-2.0 + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package net.openhft.lang.io.serialization.impl; import net.openhft.lang.io.Bytes; +import net.openhft.lang.io.NativeBytes; import net.openhft.lang.io.serialization.BytesMarshallable; import net.openhft.lang.io.serialization.BytesMarshaller; -import net.openhft.lang.io.NativeBytes; -import org.jetbrains.annotations.NotNull; +import net.openhft.lang.model.constraints.NotNull; +import net.openhft.lang.model.constraints.Nullable; /** * @author peter.lawrey */ -public class BytesMarshallableMarshaller<E extends BytesMarshallable> implements BytesMarshaller<E> { +public class BytesMarshallableMarshaller<E extends BytesMarshallable> + implements BytesMarshaller<E> { + private static final long serialVersionUID = 0L; @NotNull private final Class<E> classMarshaled; @@ -33,6 +36,10 @@ public class BytesMarshallableMarshaller<E extends BytesMarshallable> implements this.classMarshaled = classMarshaled; } + public final Class<E> marshaledClass() { + return classMarshaled; + } + @Override public void write(@NotNull Bytes bytes, @NotNull E e) { e.writeMarshallable(bytes); @@ -40,13 +47,42 @@ public class BytesMarshallableMarshaller<E extends BytesMarshallable> implements @Override public E read(@NotNull Bytes bytes) { - E e; - try { - e = (E) NativeBytes.UNSAFE.allocateInstance(classMarshaled); - } catch (Exception e2) { - throw new IllegalStateException(e2); + return read(bytes, null); + } + + @Nullable + @Override + public E read(Bytes bytes, @Nullable E e) { + if (e == null) { + try { + e = getInstance(); + } catch (Exception e2) { + throw new IllegalStateException(e2); + } } e.readMarshallable(bytes); return e; } + + @SuppressWarnings("unchecked") + @NotNull + protected E getInstance() throws Exception { + return (E) NativeBytes.UNSAFE.allocateInstance(classMarshaled); + } + + @Override + public boolean equals(Object obj) { + return obj != null && obj.getClass() == getClass() && + ((BytesMarshallableMarshaller) obj).classMarshaled == classMarshaled; + } + + @Override + public int hashCode() { + return classMarshaled.hashCode(); + } + + @Override + public String toString() { + return getClass().getSimpleName() + "{classMarshaled=" + classMarshaled + "}"; + } } diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/ClassMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/ClassMarshaller.java index db36c37..92be9bd 100644 --- a/lang/src/main/java/net/openhft/lang/io/serialization/impl/ClassMarshaller.java +++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/ClassMarshaller.java @@ -1,17 +1,17 @@ /* - * Copyright 2013 Peter Lawrey + * Copyright (C) 2015 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 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License. * - * http://www.apache.org/licenses/LICENSE-2.0 + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package net.openhft.lang.io.serialization.impl; @@ -19,8 +19,9 @@ package net.openhft.lang.io.serialization.impl; import net.openhft.lang.Compare; import net.openhft.lang.io.Bytes; import net.openhft.lang.io.serialization.CompactBytesMarshaller; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import net.openhft.lang.model.constraints.NotNull; +import net.openhft.lang.model.constraints.Nullable; +import net.openhft.lang.pool.StringInterner; import java.lang.ref.WeakReference; import java.math.BigDecimal; @@ -32,7 +33,8 @@ import java.util.Map; /** * @author peter.lawrey */ -public class ClassMarshaller implements CompactBytesMarshaller<Class> { +public class ClassMarshaller extends ImmutableMarshaller<Class> + implements CompactBytesMarshaller<Class> { private static final int CACHE_SIZE = 1019; private static final Map<String, Class> SC_SHORT_NAME = new LinkedHashMap<String, Class>(); private static final Map<Class, String> CS_SHORT_NAME = new LinkedHashMap<Class, String>(); @@ -48,7 +50,7 @@ public class ClassMarshaller implements CompactBytesMarshaller<Class> { } private final ClassLoader classLoader; - private final StringBuilder className = new StringBuilder(40); + private static final StringBuilderPool sbp = new StringBuilderPool(); @Nullable @SuppressWarnings("unchecked") private WeakReference<Class>[] classWeakReference = null; @@ -68,9 +70,9 @@ public class ClassMarshaller implements CompactBytesMarshaller<Class> { @Nullable @Override public Class read(@NotNull Bytes bytes) { - className.setLength(0); - bytes.readUTFΔ(className); - return load(className); + StringBuilder sb = sbp.acquireStringBuilder(); + bytes.readUTFΔ(sb); + return load(sb); } @Nullable @@ -82,15 +84,16 @@ public class ClassMarshaller implements CompactBytesMarshaller<Class> { WeakReference<Class> ref = classWeakReference[hash]; if (ref != null) { Class clazz = ref.get(); - if (clazz != null && clazz.getName().equals(name)) + if (clazz != null && StringInterner.isEqual(clazz.getName(), name)) return clazz; } try { - Class<?> clazz = SC_SHORT_NAME.get(name.toString()); + String className = name.toString(); + Class<?> clazz = SC_SHORT_NAME.get(className); if (clazz != null) return clazz; - clazz = classLoader.loadClass(name.toString()); + clazz = classLoader.loadClass(className); classWeakReference[hash] = new WeakReference<Class>(clazz); return clazz; } catch (ClassNotFoundException e) { @@ -100,6 +103,7 @@ public class ClassMarshaller implements CompactBytesMarshaller<Class> { @Override public byte code() { - return 'C' & 31; // control C + return CLASS_CODE; // control C } } +
\ No newline at end of file diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/CollectionMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/CollectionMarshaller.java new file mode 100644 index 0000000..dbf8f53 --- /dev/null +++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/CollectionMarshaller.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2015 higherfrequencytrading.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package net.openhft.lang.io.serialization.impl; + +import net.openhft.lang.io.Bytes; +import net.openhft.lang.io.serialization.BytesMarshaller; +import net.openhft.lang.model.constraints.Nullable; + +import java.util.Collection; + +abstract class CollectionMarshaller<E, C extends Collection<E>> { + + public static final int NULL_LENGTH = -1; + final BytesMarshaller<E> eBytesMarshaller; + + protected CollectionMarshaller(BytesMarshaller<E> eBytesMarshaller) { + this.eBytesMarshaller = eBytesMarshaller; + } + + public void write(Bytes bytes, C c) { + if (c == null) { + bytes.writeStopBit(NULL_LENGTH); + return; + } + bytes.writeStopBit(c.size()); + for (E e : c) { + eBytesMarshaller.write(bytes, e); + } + } + + public C read(Bytes bytes) { + return read(bytes, null); + } + + abstract C newCollection(); + + public C read(Bytes bytes, @Nullable C c) { + long length = bytes.readStopBit(); + + if (length == 0 && c != null) { + c.clear(); + return c; + } + + if (length < NULL_LENGTH || length > Integer.MAX_VALUE) + throw new IllegalStateException("Invalid length: " + length); + + if (length == NULL_LENGTH) + return null; + + if (c == null) + c = newCollection(); + + return readCollection(bytes, c, (int) length); + } + + abstract C readCollection(Bytes bytes, C c, int length); +} diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/CompactEnumBytesMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/CompactEnumBytesMarshaller.java index 08f66e4..676c86c 100644..100755 --- a/lang/src/main/java/net/openhft/lang/io/serialization/impl/CompactEnumBytesMarshaller.java +++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/CompactEnumBytesMarshaller.java @@ -1,26 +1,26 @@ /* - * Copyright 2013 Peter Lawrey + * Copyright (C) 2015 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 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License. * - * http://www.apache.org/licenses/LICENSE-2.0 + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package net.openhft.lang.io.serialization.impl; import net.openhft.lang.io.serialization.CompactBytesMarshaller; -import org.jetbrains.annotations.NotNull; +import net.openhft.lang.model.constraints.NotNull; /** - * Created with IntelliJ IDEA. User: peter Date: 09/12/13 Time: 17:05 To change this template use File | Settings | File + * Created with IntelliJ IDEA. User: peter.lawrey Date: 09/12/13 Time: 17:05 * Templates. */ public class CompactEnumBytesMarshaller<E> extends GenericEnumMarshaller<E> implements CompactBytesMarshaller<E> { diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/DateMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/DateMarshaller.java index 03f6bb1..1e949c5 100644 --- a/lang/src/main/java/net/openhft/lang/io/serialization/impl/DateMarshaller.java +++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/DateMarshaller.java @@ -1,25 +1,25 @@ /* - * Copyright 2013 Peter Lawrey + * Copyright (C) 2015 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 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License. * - * http://www.apache.org/licenses/LICENSE-2.0 + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package net.openhft.lang.io.serialization.impl; import net.openhft.lang.io.Bytes; import net.openhft.lang.io.serialization.CompactBytesMarshaller; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import net.openhft.lang.model.constraints.NotNull; +import net.openhft.lang.model.constraints.Nullable; import java.util.Date; @@ -27,8 +27,8 @@ import java.util.Date; * @author peter.lawrey */ public class DateMarshaller implements CompactBytesMarshaller<Date> { - final int size1; - private final StringBuilder sb = new StringBuilder(); + private final int size1; + private static final StringBuilderPool sbp = new StringBuilderPool(); @Nullable private Date[] interner = null; @@ -65,12 +65,25 @@ public class DateMarshaller implements CompactBytesMarshaller<Date> { @Nullable @Override public Date read(@NotNull Bytes bytes) { + StringBuilder sb = sbp.acquireStringBuilder(); bytes.readUTFΔ(sb); long time = parseLong(sb); return lookupDate(time); } @Nullable + @Override + public Date read(Bytes bytes, @Nullable Date date) { + if (date == null) + return read(bytes); + StringBuilder sb = sbp.acquireStringBuilder(); + bytes.readUTFΔ(sb); + long time = parseLong(sb); + date.setTime(time); + return date; + } + + @Nullable private Date lookupDate(long time) { int idx = hashFor(time); if (interner == null) @@ -90,6 +103,6 @@ public class DateMarshaller implements CompactBytesMarshaller<Date> { @Override public byte code() { - return 'T' & 31; // Control T. + return DATE_CODE; // Control T. } } diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/EnumBytesMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/EnumBytesMarshaller.java index 11f060b..189f7f5 100644 --- a/lang/src/main/java/net/openhft/lang/io/serialization/impl/EnumBytesMarshaller.java +++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/EnumBytesMarshaller.java @@ -1,25 +1,25 @@ /* - * Copyright 2013 Peter Lawrey + * Copyright (C) 2015 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 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License. * - * http://www.apache.org/licenses/LICENSE-2.0 + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package net.openhft.lang.io.serialization.impl; import net.openhft.lang.io.Bytes; import net.openhft.lang.io.serialization.BytesMarshaller; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import net.openhft.lang.model.constraints.NotNull; +import net.openhft.lang.model.constraints.Nullable; import java.util.BitSet; import java.util.LinkedHashMap; @@ -28,19 +28,17 @@ import java.util.Map; /** * @author peter.lawrey */ -public class EnumBytesMarshaller<E extends Enum<E>> implements BytesMarshaller<E> { - @NotNull - private final Class<E> classMarshaled; +public class EnumBytesMarshaller<E extends Enum<E>> extends ImmutableMarshaller<E> + implements BytesMarshaller<E> { @SuppressWarnings("unchecked") private final E[] interner = (E[]) new Enum[1024]; private final BitSet internerDup = new BitSet(1024); - private final Map<String, E> map = new LinkedHashMap<String, E>(); + private final Map<String, E> map = new LinkedHashMap<String, E>(64); private final E defaultValue; private final int mask; - private final StringBuilder reader = new StringBuilder(); + private static final StringBuilderPool sbp = new StringBuilderPool(); public EnumBytesMarshaller(@NotNull Class<E> classMarshaled, E defaultValue) { - this.classMarshaled = classMarshaled; this.defaultValue = defaultValue; mask = interner.length - 1; @@ -52,6 +50,7 @@ public class EnumBytesMarshaller<E extends Enum<E>> implements BytesMarshaller<E //noinspection UnqualifiedFieldAccess,AssignmentToNull interner[idx] = null; internerDup.set(idx); + } else { interner[idx] = e; } @@ -77,17 +76,18 @@ public class EnumBytesMarshaller<E extends Enum<E>> implements BytesMarshaller<E @Override public E read(@NotNull Bytes bytes) { - bytes.readUTFΔ(reader); - return builderToEnum(); + StringBuilder sb = sbp.acquireStringBuilder(); + bytes.readUTFΔ(sb); + return builderToEnum(sb); } - private E builderToEnum() { - int num = hashFor(reader); + private E builderToEnum(StringBuilder sb) { + int num = hashFor(sb); int idx = num & mask; E e = interner[idx]; if (e != null) return e; if (!internerDup.get(idx)) return defaultValue; - e = map.get(reader.toString()); + e = map.get(sb.toString()); return e == null ? defaultValue : e; } } diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/ExternalizableMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/ExternalizableMarshaller.java index 05f5390..4e9b82c 100644 --- a/lang/src/main/java/net/openhft/lang/io/serialization/impl/ExternalizableMarshaller.java +++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/ExternalizableMarshaller.java @@ -1,25 +1,26 @@ /* - * Copyright 2013 Peter Lawrey + * Copyright (C) 2015 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 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License. * - * http://www.apache.org/licenses/LICENSE-2.0 + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package net.openhft.lang.io.serialization.impl; import net.openhft.lang.io.Bytes; -import net.openhft.lang.io.serialization.BytesMarshaller; import net.openhft.lang.io.NativeBytes; -import org.jetbrains.annotations.NotNull; +import net.openhft.lang.io.serialization.BytesMarshaller; +import net.openhft.lang.model.constraints.NotNull; +import net.openhft.lang.model.constraints.Nullable; import java.io.Externalizable; import java.io.IOException; @@ -28,6 +29,8 @@ import java.io.IOException; * @author peter.lawrey */ public class ExternalizableMarshaller<E extends Externalizable> implements BytesMarshaller<E> { + private static final long serialVersionUID = 0L; + @NotNull private final Class<E> classMarshaled; @@ -35,6 +38,10 @@ public class ExternalizableMarshaller<E extends Externalizable> implements Bytes this.classMarshaled = classMarshaled; } + public final Class<E> marshaledClass() { + return classMarshaled; + } + @Override public void write(Bytes bytes, @NotNull E e) { try { @@ -46,13 +53,41 @@ public class ExternalizableMarshaller<E extends Externalizable> implements Bytes @Override public E read(Bytes bytes) { - E e; + return read(bytes, null); + } + + @Nullable + @Override + public E read(Bytes bytes, @Nullable E e) { try { - e = (E) NativeBytes.UNSAFE.allocateInstance(classMarshaled); + if (e == null) + e = getInstance(); e.readExternal(bytes); + return e; } catch (Exception e2) { throw new IllegalStateException(e2); } - return e; + } + + @SuppressWarnings("unchecked") + @NotNull + protected E getInstance() throws Exception { + return (E) NativeBytes.UNSAFE.allocateInstance(classMarshaled); + } + + @Override + public boolean equals(Object obj) { + return obj != null && obj.getClass() == getClass() && + ((ExternalizableMarshaller) obj).classMarshaled == classMarshaled; + } + + @Override + public int hashCode() { + return classMarshaled.hashCode(); + } + + @Override + public String toString() { + return getClass().getSimpleName() + "{marshaledClass=" + classMarshaled + "}"; } } diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/GenericEnumMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/GenericEnumMarshaller.java index 8a1b52d..8ed4590 100644 --- a/lang/src/main/java/net/openhft/lang/io/serialization/impl/GenericEnumMarshaller.java +++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/GenericEnumMarshaller.java @@ -1,25 +1,25 @@ /* - * Copyright 2013 Peter Lawrey + * Copyright (C) 2015 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 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License. * - * http://www.apache.org/licenses/LICENSE-2.0 + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package net.openhft.lang.io.serialization.impl; import net.openhft.lang.io.Bytes; import net.openhft.lang.io.serialization.BytesMarshaller; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import net.openhft.lang.model.constraints.NotNull; +import net.openhft.lang.model.constraints.Nullable; import java.lang.reflect.Constructor; import java.lang.reflect.Method; @@ -30,17 +30,20 @@ import java.util.Map; * @author peter.lawrey */ public class GenericEnumMarshaller<E> implements BytesMarshaller<E> { - @NotNull - private final Class<E> classMarshaled; + private final int capacity; @Nullable - private final Constructor<E> constructor; + private transient final Constructor<E> constructor; @Nullable - private final Method valueOf; + private transient final Method valueOf; @NotNull private final Map<String, E> map; + //used by the read resolve method + private final Class<E> classMarshaled; + public GenericEnumMarshaller(@NotNull Class<E> classMarshaled, final int capacity) { this.classMarshaled = classMarshaled; + this.capacity = capacity; Constructor<E> constructor = null; Method valueOf = null; try { @@ -48,6 +51,7 @@ public class GenericEnumMarshaller<E> implements BytesMarshaller<E> { } catch (NoSuchMethodException e) { try { constructor = classMarshaled.getConstructor(String.class); + constructor.setAccessible(true); } catch (NoSuchMethodException e1) { throw new IllegalArgumentException(classMarshaled + " doesn't have a valueOf(String) or a Constructor(String)"); } @@ -62,6 +66,10 @@ public class GenericEnumMarshaller<E> implements BytesMarshaller<E> { }; } + private Object readResolve() { + return new GenericEnumMarshaller(classMarshaled, capacity); + } + @Override public void write(@NotNull Bytes bytes, @Nullable E e) { bytes.writeUTFΔ(e == null ? null : e.toString()); @@ -74,19 +82,26 @@ public class GenericEnumMarshaller<E> implements BytesMarshaller<E> { return s == null ? null : valueOf(s); } + @Nullable + @Override + public E read(Bytes bytes, @Nullable E e) { + return read(bytes); + } + private E valueOf(String s) { E e = map.get(s); if (e == null) try { if (constructor != null) { map.put(s, e = constructor.newInstance(s)); + } else { @SuppressWarnings("unchecked") E invoke = (E) valueOf.invoke(null, s); map.put(s, e = invoke); } } catch (Exception t) { - throw new AssertionError(t.getCause()); + throw new AssertionError(t); } return e; } diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/ImmutableMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/ImmutableMarshaller.java new file mode 100644 index 0000000..de55a9c --- /dev/null +++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/ImmutableMarshaller.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2015 higherfrequencytrading.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package net.openhft.lang.io.serialization.impl; + +import net.openhft.lang.io.Bytes; +import net.openhft.lang.io.serialization.BytesMarshaller; +import net.openhft.lang.model.constraints.Nullable; + +abstract class ImmutableMarshaller<E> implements BytesMarshaller<E> { + @Nullable + @Override + public final E read(Bytes bytes, @Nullable E e) { + return read(bytes); + } +} diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/ListMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/ListMarshaller.java new file mode 100644 index 0000000..cc9b592 --- /dev/null +++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/ListMarshaller.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2015 higherfrequencytrading.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package net.openhft.lang.io.serialization.impl; + +import net.openhft.lang.io.Bytes; +import net.openhft.lang.io.serialization.BytesMarshaller; +import net.openhft.lang.io.serialization.CompactBytesMarshaller; + +import java.util.ArrayList; +import java.util.List; + +public class ListMarshaller<E> extends CollectionMarshaller<E, List<E>> implements CompactBytesMarshaller<List<E>> { + + ListMarshaller(BytesMarshaller<E> eBytesMarshaller) { + super(eBytesMarshaller); + } + + public static <E> BytesMarshaller<List<E>> of(BytesMarshaller<E> eBytesMarshaller) { + return new ListMarshaller<E>(eBytesMarshaller); + } + + @Override + public byte code() { + return LIST_CODE; + } + + @Override + List<E> newCollection() { + return new ArrayList<E>(); + } + + @Override + List<E> readCollection(Bytes bytes, List<E> es, int length) { + List<E> ret = es; + ret.clear(); + + for (int i = 0; i < length; i++) { + ret.add(eBytesMarshaller.read(bytes)); + } + + return ret; + } +} diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/MapMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/MapMarshaller.java new file mode 100755 index 0000000..195d96d --- /dev/null +++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/MapMarshaller.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2015 higherfrequencytrading.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package net.openhft.lang.io.serialization.impl; + +import net.openhft.lang.io.Bytes; +import net.openhft.lang.io.serialization.BytesMarshaller; +import net.openhft.lang.io.serialization.CompactBytesMarshaller; +import net.openhft.lang.model.constraints.Nullable; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Created by peter.lawrey on 24/10/14. + */ +public class MapMarshaller<K, V> implements CompactBytesMarshaller<Map<K, V>> { + private final BytesMarshaller<K> kBytesMarshaller; + private final BytesMarshaller<V> vBytesMarshaller; + + MapMarshaller(BytesMarshaller<K> kBytesMarshaller, BytesMarshaller<V> vBytesMarshaller) { + this.kBytesMarshaller = kBytesMarshaller; + this.vBytesMarshaller = vBytesMarshaller; + } + + @Override + public byte code() { + return MAP_CODE; + } + + @Override + public void write(Bytes bytes, Map<K, V> kvMap) { + bytes.writeInt(kvMap.size()); + for (Map.Entry<K, V> entry : kvMap.entrySet()) { + kBytesMarshaller.write(bytes, entry.getKey()); + vBytesMarshaller.write(bytes, entry.getValue()); + } + } + + @Override + public Map<K, V> read(Bytes bytes) { + return read(bytes, null); + } + + @Override + public Map<K, V> read(Bytes bytes, @Nullable Map<K, V> kvMap) { + if (kvMap == null) { + kvMap = new LinkedHashMap<K, V>(); + + } else { + kvMap.clear(); + } + int size = bytes.readInt(); + for (int i = 0; i < size; i++) + kvMap.put(kBytesMarshaller.read(bytes), vBytesMarshaller.read(bytes)); + return kvMap; + } + + public static <K, V> BytesMarshaller<Map<K, V>> of(BytesMarshaller<K> keyMarshaller, BytesMarshaller<V> valueMarshaller) { + return new MapMarshaller<K, V>(keyMarshaller, valueMarshaller); + } +} diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/NewInstanceObjectFactory.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/NewInstanceObjectFactory.java new file mode 100644 index 0000000..0fba720 --- /dev/null +++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/NewInstanceObjectFactory.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2015 higherfrequencytrading.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package net.openhft.lang.io.serialization.impl; + +import net.openhft.lang.io.serialization.ObjectFactory; + +import java.lang.reflect.Modifier; + +/** + * Object factory which creates an object by means of {@link Class#newInstance()} call, + * i. e. with calling the default no-arg constructor of the class. + * + * @param <E> type of created objects + */ +public final class NewInstanceObjectFactory<E> implements ObjectFactory<E> { + private static final long serialVersionUID = 0L; + + private final Class<E> eClass; + + public NewInstanceObjectFactory(Class<E> eClass) { + if (eClass.isInterface() || Modifier.isAbstract(eClass.getModifiers()) || + eClass.isEnum()) { + throw new IllegalArgumentException(eClass + " should be a non-abstract non-enum class"); + } + this.eClass = eClass; + } + + @Override + public E create() throws IllegalAccessException, InstantiationException { + return eClass.newInstance(); + } + + @Override + public boolean equals(Object obj) { + return obj != null && obj.getClass() == getClass() && + ((NewInstanceObjectFactory) obj).eClass == eClass; + } + + @Override + public int hashCode() { + return eClass.hashCode(); + } + + @Override + public String toString() { + return getClass().getSimpleName() + "{eClass=" + eClass + "}"; + } +} diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/NoMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/NoMarshaller.java index 1369c4a..c76054c 100644 --- a/lang/src/main/java/net/openhft/lang/io/serialization/impl/NoMarshaller.java +++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/NoMarshaller.java @@ -1,23 +1,24 @@ /* - * Copyright 2013 Peter Lawrey + * Copyright (C) 2015 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 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License. * - * http://www.apache.org/licenses/LICENSE-2.0 + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package net.openhft.lang.io.serialization.impl; import net.openhft.lang.io.Bytes; import net.openhft.lang.io.serialization.BytesMarshaller; +import net.openhft.lang.model.constraints.Nullable; /** * Created with IntelliJ IDEA. User: peter.lawrey Date: 19/09/13 Time: 18:26 To change this template use File | Settings | File @@ -35,4 +36,10 @@ public enum NoMarshaller implements BytesMarshaller<Void> { public Void read(Bytes bytes) { throw new UnsupportedOperationException(); } + + @Nullable + @Override + public Void read(Bytes bytes, @Nullable Void aVoid) { + throw new UnsupportedOperationException(); + } } diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/NoObjectFactory.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/NoObjectFactory.java new file mode 100644 index 0000000..c3e061f --- /dev/null +++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/NoObjectFactory.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2015 higherfrequencytrading.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package net.openhft.lang.io.serialization.impl; + +import net.openhft.lang.io.serialization.ObjectFactory; + +/** + * Placeholder object factory which always throws {@code UnsupportedOperationException}. + */ +public enum NoObjectFactory implements ObjectFactory { + INSTANCE; + + /** + * Always throws {@code UnsupportedOperationException}. + * + * @return nothing + * @throws UnsupportedOperationException always + */ + @Override + public Object create() throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } +} diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/NullObjectFactory.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/NullObjectFactory.java new file mode 100644 index 0000000..af76bc7 --- /dev/null +++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/NullObjectFactory.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2015 higherfrequencytrading.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package net.openhft.lang.io.serialization.impl; + +import net.openhft.lang.io.serialization.ObjectFactory; + +/** + * Object factory which always returns {@code null}. + */ +public enum NullObjectFactory implements ObjectFactory { + INSTANCE; + + public static <E> ObjectFactory<E> of() { + return INSTANCE; + } + + /** + * Always returns {@code null}. + * + * @return {@code null} + */ + @Override + public Object create() { + return null; + } +} diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/SetMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/SetMarshaller.java new file mode 100644 index 0000000..e401722 --- /dev/null +++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/SetMarshaller.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2015 higherfrequencytrading.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package net.openhft.lang.io.serialization.impl; + +import net.openhft.lang.io.Bytes; +import net.openhft.lang.io.serialization.BytesMarshaller; +import net.openhft.lang.io.serialization.CompactBytesMarshaller; + +import java.util.LinkedHashSet; +import java.util.Set; + +public class SetMarshaller<E> extends CollectionMarshaller<E, Set<E>> implements CompactBytesMarshaller<Set<E>> { + SetMarshaller(BytesMarshaller<E> eBytesMarshaller) { + super(eBytesMarshaller); + } + + public static <E> BytesMarshaller<Set<E>> of(BytesMarshaller<E> eBytesMarshaller) { + return new SetMarshaller<E>(eBytesMarshaller); + } + + @Override + public byte code() { + return SET_CODE; + } + + @Override + Set<E> newCollection() { + return new LinkedHashSet<E>(); + } + + @Override + Set<E> readCollection(Bytes bytes, Set<E> es, int length) { + es.clear(); + + for (int i = 0; i < length; i++) { + es.add(eBytesMarshaller.read(bytes)); + } + + return es; + } +} diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/SnappyStringMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/SnappyStringMarshaller.java new file mode 100755 index 0000000..14ff64f --- /dev/null +++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/SnappyStringMarshaller.java @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2015 higherfrequencytrading.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package net.openhft.lang.io.serialization.impl; + +import net.openhft.lang.io.ByteBufferBytes; +import net.openhft.lang.io.Bytes; +import net.openhft.lang.io.serialization.CompactBytesMarshaller; +import net.openhft.lang.model.constraints.Nullable; +import org.xerial.snappy.Snappy; + +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.nio.ByteBuffer; + +/** + * Created by peter.lawrey on 24/10/14. + */ +public enum SnappyStringMarshaller implements CompactBytesMarshaller<CharSequence> { + INSTANCE; + private static final StringFactory STRING_FACTORY = getStringFactory(); + + private static final int NULL_LENGTH = -1; + + private static StringFactory getStringFactory() { + try { + return new StringFactory17(); + } catch (Exception e) { + // do nothing + } + + try { + return new StringFactory16(); + } catch (Exception e) { + // no more alternatives + throw new AssertionError(e); + } + } + + private static final ThreadLocal<ThreadLocals> THREAD_LOCALS = new ThreadLocal<ThreadLocals>(); + + static class ThreadLocals { + ByteBuffer decompressedByteBuffer = ByteBuffer.allocateDirect(32 * 1024); + Bytes decompressedBytes = ByteBufferBytes.wrap(decompressedByteBuffer); + ByteBuffer compressedByteBuffer = ByteBuffer.allocateDirect(0); + + public void clear() { + decompressedByteBuffer.clear(); + decompressedBytes.clear(); + compressedByteBuffer.clear(); + } + } + + @Override + public byte code() { + return STRINGZ_CODE; + } + + public ThreadLocals acquireThreadLocals() { + ThreadLocals threadLocals = THREAD_LOCALS.get(); + if (threadLocals == null) + THREAD_LOCALS.set(threadLocals = new ThreadLocals()); + threadLocals.clear(); + return threadLocals; + } + + @Override + public void write(Bytes bytes, CharSequence s) { + if (s == null) { + bytes.writeStopBit(NULL_LENGTH); + return; + + } else if (s.length() == 0) { + bytes.writeStopBit(0); + return; + } + // write the total length. + int length = s.length(); + bytes.writeStopBit(length); + + ThreadLocals threadLocals = acquireThreadLocals(); + // stream the portions of the string. + Bytes db = threadLocals.decompressedBytes; + ByteBuffer dbb = threadLocals.decompressedByteBuffer; + ByteBuffer cbb = bytes.sliceAsByteBuffer(threadLocals.compressedByteBuffer); + + int position = 0; + while (position < length) { + // 3 is the longest encoding. + while (position < length && db.remaining() >= 3) + db.writeStopBit(s.charAt(position++)); + dbb.position(0); + dbb.limit((int) db.position()); + // portion copied now compress it. + int portionLengthPos = cbb.position(); + cbb.putShort((short) 0); + int compressedLength; + try { + Snappy.compress(dbb, cbb); + compressedLength = cbb.remaining(); + if (compressedLength >= 1 << 16) + throw new AssertionError(); + // unflip. + cbb.position(cbb.limit()); + cbb.limit(cbb.capacity()); + } catch (IOException e) { + throw new AssertionError(e); + } + cbb.putShort(portionLengthPos, (short) compressedLength); + db.clear(); + } + // the end. + cbb.putShort((short) 0); + bytes.position(bytes.position() + cbb.position()); + } + + @Override + public String read(Bytes bytes) { + return read(bytes, null); + } + + @Override + public String read(Bytes bytes, @Nullable CharSequence ignored) { + long size = bytes.readStopBit(); + if (size == NULL_LENGTH) + return null; + if (size < 0 || size > Integer.MAX_VALUE) + throw new IllegalStateException("Invalid length: " + size); + if (size == 0) + return ""; + ThreadLocals threadLocals = acquireThreadLocals(); + // stream the portions of the string. + Bytes db = threadLocals.decompressedBytes; + ByteBuffer dbb = threadLocals.decompressedByteBuffer; + ByteBuffer cbb = bytes.sliceAsByteBuffer(threadLocals.compressedByteBuffer); + + char[] chars = new char[(int) size]; + int pos = 0; + for (int chunkLen; (chunkLen = cbb.getShort() & 0xFFFF) > 0; ) { + cbb.limit(cbb.position() + chunkLen); + dbb.clear(); + try { + Snappy.uncompress(cbb, dbb); + cbb.position(cbb.limit()); + cbb.limit(cbb.capacity()); + } catch (IOException e) { + throw new AssertionError(e); + } + db.position(0); + db.limit(dbb.limit()); + while (db.remaining() > 0) + chars[pos++] = (char) db.readStopBit(); + } + bytes.position(bytes.position() + cbb.position()); + try { + return STRING_FACTORY.fromChars(chars); + } catch (Exception e) { + throw new AssertionError(e); + } + } + + private static abstract class StringFactory { + abstract String fromChars(char[] chars) throws IllegalAccessException, InvocationTargetException, InstantiationException; + } + + private static final class StringFactory16 extends StringFactory { + private final Constructor<String> constructor; + + private StringFactory16() throws NoSuchMethodException { + constructor = String.class.getDeclaredConstructor(int.class, + int.class, char[].class); + constructor.setAccessible(true); + } + + @Override + String fromChars(char[] chars) throws IllegalAccessException, InvocationTargetException, InstantiationException { + return constructor.newInstance(0, chars.length, chars); + } + } + + private static final class StringFactory17 extends StringFactory { + private final Constructor<String> constructor; + + private StringFactory17() throws NoSuchMethodException { + constructor = String.class.getDeclaredConstructor(char[].class, boolean.class); + constructor.setAccessible(true); + } + + @Override + String fromChars(char[] chars) throws IllegalAccessException, InvocationTargetException, InstantiationException { + return constructor.newInstance(chars, true); + } + } +} diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/StringBuilderPool.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/StringBuilderPool.java new file mode 100755 index 0000000..d7ca469 --- /dev/null +++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/StringBuilderPool.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2015 higherfrequencytrading.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package net.openhft.lang.io.serialization.impl; + +/** + * Created by peter.lawrey on 29/10/14. + */ +public class StringBuilderPool { + final ThreadLocal<StringBuilder> sbtl = new ThreadLocal<StringBuilder>(); + + public StringBuilder acquireStringBuilder() { + StringBuilder sb = sbtl.get(); + if (sb == null) { + sbtl.set(sb = new StringBuilder(128)); + } + sb.setLength(0); + return sb; + } +} diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/StringMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/StringMarshaller.java index 2fb2ee5..67843ae 100644 --- a/lang/src/main/java/net/openhft/lang/io/serialization/impl/StringMarshaller.java +++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/StringMarshaller.java @@ -1,34 +1,35 @@ /* - * Copyright 2013 Peter Lawrey + * Copyright (C) 2015 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 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License. * - * http://www.apache.org/licenses/LICENSE-2.0 + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package net.openhft.lang.io.serialization.impl; import net.openhft.lang.io.Bytes; import net.openhft.lang.io.serialization.CompactBytesMarshaller; +import net.openhft.lang.model.constraints.NotNull; +import net.openhft.lang.model.constraints.Nullable; import net.openhft.lang.pool.StringInterner; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; /** * @author peter.lawrey */ -public class StringMarshaller implements CompactBytesMarshaller<String> { +public class StringMarshaller extends ImmutableMarshaller<String> + implements CompactBytesMarshaller<String> { private final int size; - private final StringBuilder reader = new StringBuilder(); - private StringInterner interner; + private static final StringBuilderPool sbp = new StringBuilderPool(); + private transient StringInterner interner; public StringMarshaller(int size) { this.size = size; @@ -42,19 +43,22 @@ public class StringMarshaller implements CompactBytesMarshaller<String> { @Nullable @Override public String read(@NotNull Bytes bytes) { - if (bytes.readUTFΔ(reader)) - return builderToString(); + StringBuilder sb = sbp.acquireStringBuilder(); + if (bytes.readUTFΔ(sb)) + return builderToString(sb); return null; } - - private String builderToString() { - if (interner == null) + private String builderToString(StringBuilder reader) { + if (interner == null) { + if (size == 0) + return reader.toString(); interner = new StringInterner(size); + } return interner.intern(reader); } public byte code() { - return 'S' & 31; + return STRING_CODE; } } diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/StringZMapMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/StringZMapMarshaller.java new file mode 100755 index 0000000..efec05e --- /dev/null +++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/StringZMapMarshaller.java @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2015 higherfrequencytrading.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package net.openhft.lang.io.serialization.impl; + +import net.openhft.lang.io.Bytes; +import net.openhft.lang.io.serialization.CompactBytesMarshaller; +import net.openhft.lang.model.constraints.Nullable; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.StreamCorruptedException; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.zip.Deflater; +import java.util.zip.DeflaterOutputStream; +import java.util.zip.InflaterInputStream; + +/** + * Created by peter.lawrey on 24/10/14. + */ +public enum StringZMapMarshaller implements CompactBytesMarshaller<Map<String, String>> { + FAST(Deflater.BEST_SPEED), + COMPACT(Deflater.BEST_COMPRESSION), + INSTANCE(Deflater.DEFAULT_STRATEGY); + + private final int level; + + private static final long NULL_SIZE = -1; + + StringZMapMarshaller(int level) { + this.level = level; + } + + @Override + public byte code() { + return STRINGZ_MAP_CODE; + } + + @Override + public void write(Bytes bytes, Map<String, String> kvMap) { + if (kvMap == null) { + bytes.writeStopBit(NULL_SIZE); + return; + } + + bytes.writeStopBit(kvMap.size()); + long position = bytes.position(); + bytes.clear(); + bytes.position(position + 4); + DataOutputStream dos = new DataOutputStream( + new DeflaterOutputStream(bytes.outputStream(), new Deflater(level))); + try { + for (Map.Entry<String, String> entry : kvMap.entrySet()) { + dos.writeUTF(entry.getKey()); + dos.writeUTF(entry.getValue()); + } + dos.close(); + } catch (IOException e) { + throw new IllegalStateException(e); + } + bytes.writeUnsignedInt(position, bytes.position() - position - 4); + } + + @Override + public Map<String, String> read(Bytes bytes) { + return read(bytes, null); + } + + @Override + public Map<String, String> read(Bytes bytes, @Nullable Map<String, String> kvMap) { + long size = bytes.readStopBit(); + if (size == NULL_SIZE) + return null; + if (size < 0 || size > Integer.MAX_VALUE) + throw new IllegalStateException("Invalid length: " + size); + + long length = bytes.readUnsignedInt(); + if (length < 0 || length > Integer.MAX_VALUE) + throw new IllegalStateException(new StreamCorruptedException()); + long position = bytes.position(); + long end = position + length; + + long limit = bytes.limit(); + bytes.limit(end); + + DataInputStream dis = new DataInputStream(new InflaterInputStream(bytes.inputStream())); + if (kvMap == null) { + kvMap = new LinkedHashMap<String, String>(); + + } else { + kvMap.clear(); + } + try { + for (int i = 0; i < size; i++) { + String key = dis.readUTF(); + String value = dis.readUTF(); + kvMap.put(key, value); + } + } catch (IOException e) { + throw new IllegalStateException(e); + } + bytes.position(end); + bytes.limit(limit); + return kvMap; + } +} diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/VanillaBytesMarshallerFactory.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/VanillaBytesMarshallerFactory.java index 6fc66ee..3e8d94a 100644 --- a/lang/src/main/java/net/openhft/lang/io/serialization/impl/VanillaBytesMarshallerFactory.java +++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/VanillaBytesMarshallerFactory.java @@ -1,17 +1,17 @@ /* - * Copyright 2013 Peter Lawrey + * Copyright (C) 2015 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 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License. * - * http://www.apache.org/licenses/LICENSE-2.0 + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package net.openhft.lang.io.serialization.impl; @@ -20,63 +20,92 @@ import net.openhft.lang.io.serialization.BytesMarshallable; import net.openhft.lang.io.serialization.BytesMarshaller; import net.openhft.lang.io.serialization.BytesMarshallerFactory; import net.openhft.lang.io.serialization.CompactBytesMarshaller; -import org.jetbrains.annotations.NotNull; +import net.openhft.lang.model.constraints.NotNull; import java.io.Externalizable; +import java.nio.ByteBuffer; import java.util.Date; import java.util.LinkedHashMap; import java.util.Map; +import static net.openhft.lang.io.serialization.CompactBytesMarshaller.*; + /** * @author peter.lawrey */ -public class VanillaBytesMarshallerFactory implements BytesMarshallerFactory { +public final class VanillaBytesMarshallerFactory implements BytesMarshallerFactory { + private static final long serialVersionUID = 1L; + + private transient Map<Class<?>, BytesMarshaller<?>> marshallerMap; + private transient BytesMarshaller<?>[] compactMarshallerMap; - private final Map<Class, BytesMarshaller> marshallerMap = new LinkedHashMap<Class, BytesMarshaller>(); - private final BytesMarshaller[] compactMarshallerMap = new BytesMarshaller[256]; + private void init() { + marshallerMap = new LinkedHashMap<Class<?>, BytesMarshaller<?>>(); + compactMarshallerMap = new BytesMarshaller[256]; - // private final Map<Class, BytesMarshaller> marshallerTextMap = new LinkedHashMap<Class, BytesMarshaller>(); - { - BytesMarshaller stringMarshaller = new StringMarshaller(16 * 1024); + BytesMarshaller<String> stringMarshaller = new StringMarshaller(16 * 1024); addMarshaller(String.class, stringMarshaller); - addMarshaller(CharSequence.class, stringMarshaller); + addMarshaller(CharSequence.class, (BytesMarshaller)stringMarshaller); addMarshaller(Class.class, new ClassMarshaller(Thread.currentThread().getContextClassLoader())); addMarshaller(Date.class, new DateMarshaller(10191)); - addMarshaller(Integer.class, new CompactEnumBytesMarshaller<Integer>(Integer.class, 10191, (byte) ('I' & 31))); - addMarshaller(Long.class, new CompactEnumBytesMarshaller<Long>(Long.class, 10191, (byte) ('L' & 31))); - addMarshaller(Double.class, new CompactEnumBytesMarshaller<Double>(Double.class, 10191, (byte) ('D' & 31))); + addMarshaller(Integer.class, new CompactEnumBytesMarshaller<Integer>(Integer.class, 10191, INT_CODE)); + addMarshaller(Long.class, new CompactEnumBytesMarshaller<Long>(Long.class, 10191, LONG_CODE)); + addMarshaller(Double.class, new CompactEnumBytesMarshaller<Double>(Double.class, 10191, DOUBLE_CODE)); + addMarshaller(ByteBuffer.class, ByteBufferMarshaller.INSTANCE); } @NotNull @SuppressWarnings("unchecked") @Override public <E> BytesMarshaller<E> acquireMarshaller(@NotNull Class<E> eClass, boolean create) { + if (marshallerMap == null) { + init(); + } + BytesMarshaller em = marshallerMap.get(eClass); - if (em == null) - if (eClass.isEnum()) + if (em == null) { + if (eClass.isEnum()) { marshallerMap.put(eClass, em = new EnumBytesMarshaller(eClass, null)); - else if (BytesMarshallable.class.isAssignableFrom(eClass)) + + } else if (BytesMarshallable.class.isAssignableFrom(eClass)) { marshallerMap.put(eClass, em = new BytesMarshallableMarshaller((Class) eClass)); - else if (Externalizable.class.isAssignableFrom(eClass)) + + } else if (Externalizable.class.isAssignableFrom(eClass)) { marshallerMap.put(eClass, em = new ExternalizableMarshaller((Class) eClass)); - else { + + } else if (Throwable.class.isAssignableFrom(eClass)) { + marshallerMap.put(eClass, em = NoMarshaller.INSTANCE); + + } else { try { marshallerMap.put(eClass, em = new GenericEnumMarshaller<E>(eClass, 1000)); } catch (Exception e) { marshallerMap.put(eClass, em = NoMarshaller.INSTANCE); } } + } + return em; } @Override + @SuppressWarnings("unchecked") public <E> BytesMarshaller<E> getMarshaller(byte code) { - return compactMarshallerMap[code & 0xFF]; + if (marshallerMap == null) { + init(); + } + + return (BytesMarshaller<E>) compactMarshallerMap[code & 0xFF]; } public <E> void addMarshaller(Class<E> eClass, BytesMarshaller<E> marshaller) { + if (marshallerMap == null) { + init(); + } + marshallerMap.put(eClass, marshaller); - if (marshaller instanceof CompactBytesMarshaller) + if (marshaller instanceof CompactBytesMarshaller) { compactMarshallerMap[((CompactBytesMarshaller) marshaller).code()] = marshaller; + } } } |