/* * * * Copyright 2014 Orient Technologies LTD (info(at)orientechnologies.com) * * * * Licensed under the Apache License, Version 2.0 (the "License"); * * you may not use this file except in compliance with the License. * * You may obtain a copy of the License at * * * * http://www.apache.org/licenses/LICENSE-2.0 * * * * Unless required by applicable law or agreed to in writing, software * * distributed under the License is distributed on an "AS IS" BASIS, * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * * See the License for the specific language governing permissions and * * limitations under the License. * * * * For more information: http://www.orientechnologies.com * */ package com.orientechnologies.orient.core.serialization.serializer.binary.impl.index; import com.orientechnologies.common.serialization.types.OBinarySerializer; import com.orientechnologies.common.serialization.types.OIntegerSerializer; import com.orientechnologies.common.serialization.types.ONullSerializer; import com.orientechnologies.common.util.OCommonConst; import com.orientechnologies.orient.core.index.OCompositeKey; import com.orientechnologies.orient.core.metadata.schema.OType; import com.orientechnologies.orient.core.serialization.OBinaryProtocol; import com.orientechnologies.orient.core.serialization.OMemoryInputStream; import com.orientechnologies.orient.core.serialization.serializer.binary.OBinarySerializerFactory; import com.orientechnologies.orient.core.serialization.serializer.record.string.ORecordSerializerStringAbstract; import com.orientechnologies.orient.core.serialization.serializer.stream.OStreamSerializer; import com.orientechnologies.orient.core.storage.impl.local.paginated.wal.OWALChanges; import java.io.IOException; import java.nio.ByteBuffer; import java.util.List; /** * Serializer that is used for serialization of {@link OCompositeKey} keys in index. * * @author Andrey Lomakin * @since 29.07.11 */ public class OCompositeKeySerializer implements OBinarySerializer<OCompositeKey>, OStreamSerializer { public static final String NAME = "cks"; public static final OCompositeKeySerializer INSTANCE = new OCompositeKeySerializer(); public static final byte ID = 14; public int getObjectSize(OCompositeKey compositeKey, Object... hints) { final OType[] types = getKeyTypes(hints); final List<Object> keys = compositeKey.getKeys(); int size = 2 * OIntegerSerializer.INT_SIZE; final OBinarySerializerFactory factory = OBinarySerializerFactory.getInstance(); for (int i = 0; i < keys.size(); i++) { final Object key = keys.get(i); if (key != null) { final OType type; if (types.length > i) type = types[i]; else type = OType.getTypeByClass(key.getClass()); size += OBinarySerializerFactory.TYPE_IDENTIFIER_SIZE + ((OBinarySerializer<Object>) factory.getObjectSerializer(type)) .getObjectSize(key); } else { size += OBinarySerializerFactory.TYPE_IDENTIFIER_SIZE + ONullSerializer.INSTANCE.getObjectSize(null); } } return size; } public void serialize(OCompositeKey compositeKey, byte[] stream, int startPosition, Object... hints) { final OType[] types = getKeyTypes(hints); final List<Object> keys = compositeKey.getKeys(); final int keysSize = keys.size(); final int oldStartPosition = startPosition; startPosition += OIntegerSerializer.INT_SIZE; OIntegerSerializer.INSTANCE.serializeLiteral(keysSize, stream, startPosition); startPosition += OIntegerSerializer.INT_SIZE; final OBinarySerializerFactory factory = OBinarySerializerFactory.getInstance(); for (int i = 0; i < keys.size(); i++) { final Object key = keys.get(i); OBinarySerializer<Object> binarySerializer; if (key != null) { final OType type; if (types.length > i) type = types[i]; else type = OType.getTypeByClass(key.getClass()); binarySerializer = factory.getObjectSerializer(type); } else binarySerializer = ONullSerializer.INSTANCE; stream[startPosition] = binarySerializer.getId(); startPosition += OBinarySerializerFactory.TYPE_IDENTIFIER_SIZE; binarySerializer.serialize(key, stream, startPosition); startPosition += binarySerializer.getObjectSize(key); } OIntegerSerializer.INSTANCE.serializeLiteral((startPosition - oldStartPosition), stream, oldStartPosition); } @SuppressWarnings("unchecked") public OCompositeKey deserialize(byte[] stream, int startPosition) { final OCompositeKey compositeKey = new OCompositeKey(); startPosition += OIntegerSerializer.INT_SIZE; final int keysSize = OIntegerSerializer.INSTANCE.deserializeLiteral(stream, startPosition); startPosition += OIntegerSerializer.INSTANCE.getObjectSize(keysSize); final OBinarySerializerFactory factory = OBinarySerializerFactory.getInstance(); for (int i = 0; i < keysSize; i++) { final byte serializerId = stream[startPosition]; startPosition += OBinarySerializerFactory.TYPE_IDENTIFIER_SIZE; OBinarySerializer<Object> binarySerializer = (OBinarySerializer<Object>) factory.getObjectSerializer(serializerId); final Object key = binarySerializer.deserialize(stream, startPosition); compositeKey.addKey(key); startPosition += binarySerializer.getObjectSize(key); } return compositeKey; } public int getObjectSize(byte[] stream, int startPosition) { return OIntegerSerializer.INSTANCE.deserializeLiteral(stream, startPosition); } public byte getId() { return ID; } public byte[] toStream(final Object iObject) throws IOException { throw new UnsupportedOperationException("CSV storage format is out of dated and is not supported."); } public Object fromStream(final byte[] iStream) throws IOException { final OCompositeKey compositeKey = new OCompositeKey(); final OMemoryInputStream inputStream = new OMemoryInputStream(iStream); final int keysSize = inputStream.getAsInteger(); for (int i = 0; i < keysSize; i++) { final byte[] keyBytes = inputStream.getAsByteArray(); final String keyString = new String(keyBytes,"UTF-8"); final int typeSeparatorPos = keyString.indexOf(','); final OType type = OType.valueOf(keyString.substring(0, typeSeparatorPos)); compositeKey.addKey(ORecordSerializerStringAbstract.simpleValueFromStream(keyString.substring(typeSeparatorPos + 1), type)); } return compositeKey; } public String getName() { return NAME; } public int getObjectSizeNative(byte[] stream, int startPosition) { return OIntegerSerializer.INSTANCE.deserializeNative(stream, startPosition); } public void serializeNativeObject(OCompositeKey compositeKey, byte[] stream, int startPosition, Object... hints) { final OType[] types = getKeyTypes(hints); final List<Object> keys = compositeKey.getKeys(); final int keysSize = keys.size(); final int oldStartPosition = startPosition; startPosition += OIntegerSerializer.INT_SIZE; OIntegerSerializer.INSTANCE.serializeNative(keysSize, stream, startPosition); startPosition += OIntegerSerializer.INT_SIZE; final OBinarySerializerFactory factory = OBinarySerializerFactory.getInstance(); for (int i = 0; i < keys.size(); i++) { final Object key = keys.get(i); OBinarySerializer<Object> binarySerializer; if (key != null) { final OType type; if (types.length > i) type = types[i]; else type = OType.getTypeByClass(key.getClass()); binarySerializer = factory.getObjectSerializer(type); } else binarySerializer = ONullSerializer.INSTANCE; stream[startPosition] = binarySerializer.getId(); startPosition += OBinarySerializerFactory.TYPE_IDENTIFIER_SIZE; binarySerializer.serializeNativeObject(key, stream, startPosition); startPosition += binarySerializer.getObjectSize(key); } OIntegerSerializer.INSTANCE.serializeNative((startPosition - oldStartPosition), stream, oldStartPosition); } public OCompositeKey deserializeNativeObject(byte[] stream, int startPosition) { final OCompositeKey compositeKey = new OCompositeKey(); startPosition += OIntegerSerializer.INT_SIZE; final int keysSize = OIntegerSerializer.INSTANCE.deserializeNative(stream, startPosition); startPosition += OIntegerSerializer.INSTANCE.getObjectSize(keysSize); final OBinarySerializerFactory factory = OBinarySerializerFactory.getInstance(); for (int i = 0; i < keysSize; i++) { final byte serializerId = stream[startPosition]; startPosition += OBinarySerializerFactory.TYPE_IDENTIFIER_SIZE; OBinarySerializer<Object> binarySerializer = (OBinarySerializer<Object>) factory.getObjectSerializer(serializerId); final Object key = binarySerializer.deserializeNativeObject(stream, startPosition); compositeKey.addKey(key); startPosition += binarySerializer.getObjectSize(key); } return compositeKey; } private OType[] getKeyTypes(Object[] hints) { final OType[] types; if (hints != null && hints.length > 0) types = (OType[]) hints; else types = OCommonConst.EMPTY_TYPES_ARRAY; return types; } public boolean isFixedLength() { return false; } public int getFixedLength() { return 0; } @Override public OCompositeKey preprocess(OCompositeKey value, Object... hints) { if (value == null) return null; final OType[] types = getKeyTypes(hints); final List<Object> keys = value.getKeys(); final OCompositeKey compositeKey = new OCompositeKey(); final OBinarySerializerFactory factory = OBinarySerializerFactory.getInstance(); for (int i = 0; i < keys.size(); i++) { final Object key = keys.get(i); final OType type; if (types.length > i) type = types[i]; else type = OType.getTypeByClass(key.getClass()); OBinarySerializer<Object> keySerializer = ((OBinarySerializer<Object>) factory.getObjectSerializer(type)); compositeKey.addKey(keySerializer.preprocess(key)); } return compositeKey; } /** * {@inheritDoc} */ @Override public void serializeInByteBufferObject(OCompositeKey object, ByteBuffer buffer, Object... hints) { final OType[] types = getKeyTypes(hints); final List<Object> keys = object.getKeys(); final int keysSize = keys.size(); final int oldStartOffset = buffer.position(); buffer.position(oldStartOffset + OIntegerSerializer.INT_SIZE); buffer.putInt(keysSize); final OBinarySerializerFactory factory = OBinarySerializerFactory.getInstance(); for (int i = 0; i < keys.size(); i++) { final Object key = keys.get(i); OBinarySerializer<Object> binarySerializer; if (key != null) { final OType type; if (types.length > i) type = types[i]; else type = OType.getTypeByClass(key.getClass()); binarySerializer = factory.getObjectSerializer(type); } else binarySerializer = ONullSerializer.INSTANCE; buffer.put(binarySerializer.getId()); binarySerializer.serializeInByteBufferObject(key, buffer); } final int finalPosition = buffer.position(); final int serializedSize = buffer.position() - oldStartOffset; buffer.position(oldStartOffset); buffer.putInt(serializedSize); buffer.position(finalPosition); } /** * {@inheritDoc} */ @Override public OCompositeKey deserializeFromByteBufferObject(ByteBuffer buffer) { final OCompositeKey compositeKey = new OCompositeKey(); buffer.position(buffer.position() + OIntegerSerializer.INT_SIZE); final int keysSize = buffer.getInt(); final OBinarySerializerFactory factory = OBinarySerializerFactory.getInstance(); for (int i = 0; i < keysSize; i++) { final byte serializerId = buffer.get(); OBinarySerializer<Object> binarySerializer = (OBinarySerializer<Object>) factory.getObjectSerializer(serializerId); final Object key = binarySerializer.deserializeFromByteBufferObject(buffer); compositeKey.addKey(key); } return compositeKey; } /** * {@inheritDoc} */ @Override public int getObjectSizeInByteBuffer(ByteBuffer buffer) { return buffer.getInt(); } /** * {@inheritDoc} */ @Override public OCompositeKey deserializeFromByteBufferObject(ByteBuffer buffer, OWALChanges walChanges, int offset) { final OCompositeKey compositeKey = new OCompositeKey(); offset += OIntegerSerializer.INT_SIZE; final int keysSize = walChanges.getIntValue(buffer, offset); offset += OIntegerSerializer.INT_SIZE; final OBinarySerializerFactory factory = OBinarySerializerFactory.getInstance(); for (int i = 0; i < keysSize; i++) { final byte serializerId = walChanges.getByteValue(buffer, offset); offset += OBinarySerializerFactory.TYPE_IDENTIFIER_SIZE; OBinarySerializer<Object> binarySerializer = (OBinarySerializer<Object>) factory.getObjectSerializer(serializerId); final Object key = binarySerializer.deserializeFromByteBufferObject(buffer, walChanges, offset); compositeKey.addKey(key); offset += binarySerializer.getObjectSize(key); } return compositeKey; } /** * {@inheritDoc} */ @Override public int getObjectSizeInByteBuffer(ByteBuffer buffer, OWALChanges walChanges, int offset) { return walChanges.getIntValue(buffer, offset); } }