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

com.hazelcast.internal.serialization.impl.compact.Schema Maven / Gradle / Ivy

There is a newer version: 5.5.0
Show newest version
/*
 * Copyright (c) 2008-2021, Hazelcast, Inc. All Rights Reserved.
 *
 * 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 com.hazelcast.internal.serialization.impl.compact;

import com.hazelcast.internal.serialization.impl.compact.schema.SchemaDataSerializerHook;
import com.hazelcast.nio.ObjectDataInput;
import com.hazelcast.nio.ObjectDataOutput;
import com.hazelcast.nio.serialization.FieldKind;
import com.hazelcast.nio.serialization.IdentifiedDataSerializable;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;

import static com.hazelcast.internal.serialization.impl.FieldKindBasedOperations.VARIABLE_SIZE;
import static com.hazelcast.internal.serialization.impl.FieldOperations.fieldOperations;

/**
 * Represents the schema of a class.
 * Consists of field definitions and the class name.
 */
public class Schema implements IdentifiedDataSerializable {

    private String typeName;
    private TreeMap fieldDefinitionMap;
    private int numberVarSizeFields;
    private int fixedSizeFieldsLength;
    private transient long schemaId;

    public Schema() {
    }

    public Schema(String typeName, TreeMap fieldDefinitionMap) {
        this.typeName = typeName;
        this.fieldDefinitionMap = fieldDefinitionMap;
        init();
    }

    private void init() {
        List fixedSizeFields = new ArrayList<>();
        List booleanFields = new ArrayList<>();
        List variableSizeFields = new ArrayList<>();

        for (FieldDescriptor descriptor : fieldDefinitionMap.values()) {
            FieldKind fieldKind = descriptor.getKind();
            if (fieldOperations(fieldKind).kindSizeInBytes() == VARIABLE_SIZE) {
                variableSizeFields.add(descriptor);
            } else {
                if (FieldKind.BOOLEAN == fieldKind) {
                    booleanFields.add(descriptor);
                } else {
                    fixedSizeFields.add(descriptor);
                }
            }
        }

        fixedSizeFields.sort(Comparator.comparingInt(
                d -> fieldOperations(((FieldDescriptor) d).getKind()).kindSizeInBytes()).reversed()
        );

        int offset = 0;
        for (FieldDescriptor descriptor : fixedSizeFields) {
            descriptor.setOffset(offset);
            offset += fieldOperations(descriptor.getKind()).kindSizeInBytes();
        }

        int bitOffset = 0;
        for (FieldDescriptor descriptor : booleanFields) {
            descriptor.setOffset(offset);
            descriptor.setBitOffset((byte) (bitOffset % Byte.SIZE));
            bitOffset++;
            if (bitOffset % Byte.SIZE == 0) {
                offset += 1;
            }
        }
        if (bitOffset % Byte.SIZE != 0) {
            offset++;
        }

        fixedSizeFieldsLength = offset;

        int index = 0;
        for (FieldDescriptor descriptor : variableSizeFields) {
            descriptor.setIndex(index++);
        }

        numberVarSizeFields = index;
        schemaId = RabinFingerprint.fingerprint64(this);
    }

    /**
     * The class name provided when building a schema
     * In Java, when it is not configured explicitly, this falls back to
     * fully qualified class name.
     *
     * @return name of the class
     */
    public String getTypeName() {
        return typeName;
    }

    public Collection getFields() {
        return fieldDefinitionMap.values();
    }

    public Set getFieldNames() {
        return fieldDefinitionMap.keySet();
    }

    public int getNumberOfVariableSizeFields() {
        return numberVarSizeFields;
    }

    public int getFixedSizeFieldsLength() {
        return fixedSizeFieldsLength;
    }

    public int getFieldCount() {
        return fieldDefinitionMap.size();
    }

    public FieldDescriptor getField(String fieldName) {
        return fieldDefinitionMap.get(fieldName);
    }

    public boolean hasField(String fieldName) {
        return fieldDefinitionMap.containsKey(fieldName);
    }

    public long getSchemaId() {
        return schemaId;
    }

    @Override
    public String toString() {
        return "Schema {"
                + " className = " + typeName
                + " numberOfComplexFields = " + numberVarSizeFields
                + " primitivesLength = " + fixedSizeFieldsLength
                + ", map = " + fieldDefinitionMap
                + '}';
    }

    @Override
    public void writeData(ObjectDataOutput out) throws IOException {
        out.writeString(typeName);
        out.writeInt(fieldDefinitionMap.size());
        Collection fields = fieldDefinitionMap.values();
        for (FieldDescriptor descriptor : fields) {
            out.writeString(descriptor.getFieldName());
            out.writeInt(descriptor.getKind().getId());
        }
    }

    @Override
    public void readData(ObjectDataInput in) throws IOException {
        typeName = in.readString();
        int fieldDefinitionsSize = in.readInt();
        fieldDefinitionMap = new TreeMap<>(Comparator.naturalOrder());
        for (int i = 0; i < fieldDefinitionsSize; i++) {
            String name = in.readString();
            FieldKind kind = FieldKind.get(in.readInt());
            FieldDescriptor descriptor = new FieldDescriptor(name, kind);
            fieldDefinitionMap.put(name, descriptor);
        }
        init();
    }

    @Override
    public int getFactoryId() {
        return SchemaDataSerializerHook.F_ID;
    }

    @Override
    public int getClassId() {
        return SchemaDataSerializerHook.SCHEMA;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        Schema schema = (Schema) o;
        return numberVarSizeFields == schema.numberVarSizeFields
                && fixedSizeFieldsLength == schema.fixedSizeFieldsLength
                && schemaId == schema.schemaId
                && Objects.equals(typeName, schema.typeName)
                && Objects.equals(fieldDefinitionMap, schema.fieldDefinitionMap);
    }

    @Override
    public int hashCode() {
        return (int) schemaId;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy