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

com.hazelcast.internal.serialization.impl.PortableNavigatorContext Maven / Gradle / Ivy

/*
 * Copyright (c) 2008-2016, 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;

import com.hazelcast.nio.BufferObjectDataInput;
import com.hazelcast.nio.serialization.ClassDefinition;
import com.hazelcast.nio.serialization.FieldDefinition;
import com.hazelcast.nio.serialization.FieldType;
import com.hazelcast.nio.serialization.HazelcastSerializationException;

import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;

import static com.hazelcast.internal.serialization.impl.PortableUtils.createUnknownFieldException;
import static com.hazelcast.query.impl.getters.ExtractorHelper.extractAttributeNameNameWithoutArguments;

/**
 * Mutable navigator context that holds the state of the navigation in the portable byte stream.
 * Tightly coupled with the {@link PortablePositionNavigator}
 */
final class PortableNavigatorContext {

    // mutable fields that hold the mutable state
    private BufferObjectDataInput in;
    private int offset;
    private FieldDefinition fd;
    private Deque multiPositions;

    private int finalPosition;
    private ClassDefinition cd;
    private PortableSerializer serializer;

    // final fields that hold the initial state for reset
    private final int initPosition;
    private final ClassDefinition initCd;
    private final int initOffset;
    private final int initFinalPosition;
    private final PortableSerializer initSerializer;

    PortableNavigatorContext(BufferObjectDataInput in, ClassDefinition cd, PortableSerializer serializer) {
        this.in = in;
        this.cd = cd;
        this.serializer = serializer;

        initFinalPositionAndOffset(in, cd);

        this.initCd = cd;
        this.initSerializer = serializer;
        this.initPosition = in.position();
        this.initFinalPosition = finalPosition;
        this.initOffset = offset;
    }

    /**
     * Initialises the finalPosition and offset and validates the fieldCount against the given class definition
     */
    private void initFinalPositionAndOffset(BufferObjectDataInput in, ClassDefinition cd) {
        int fieldCount;
        try {
            // final position after portable is read
            finalPosition = in.readInt();
            fieldCount = in.readInt();
        } catch (IOException e) {
            throw new HazelcastSerializationException(e);
        }
        if (fieldCount != cd.getFieldCount()) {
            throw new IllegalStateException("Field count[" + fieldCount + "] in stream does not match " + cd);
        }
        offset = in.position();
    }

    /**
     * Resets the state to the initial state for future reuse.
     */
    void reset() {
        cd = initCd;
        serializer = initSerializer;
        in.position(initPosition);
        finalPosition = initFinalPosition;
        offset = initOffset;
    }

    BufferObjectDataInput getIn() {
        return in;
    }

    int getCurrentOffset() {
        return offset;
    }

    int getCurrentFinalPosition() {
        return finalPosition;
    }

    FieldDefinition getCurrentFieldDefinition() {
        return fd;
    }

    ClassDefinition getCurrentClassDefinition() {
        return cd;
    }

    FieldType getCurrentFieldType() {
        return fd.getType();
    }

    boolean isCurrentFieldOfType(FieldType type) {
        return fd.getType() == type;
    }

    boolean areThereMultiPositions() {
        return multiPositions != null && !multiPositions.isEmpty();
    }

    NavigationFrame pollFirstMultiPosition() {
        return multiPositions.pollFirst();
    }

    /**
     * When we advance in the token navigation we need to re-initialise the class definition with the coordinates
     * of the new portable object in the context of which we will be navigating further.
     */
    void advanceContextToNextPortableToken(int factoryId, int classId, int version) throws IOException {
        cd = serializer.setupPositionAndDefinition(in, factoryId, classId, version);
        initFinalPositionAndOffset(in, cd);
    }

    /**
     * Sets up the stream for the given frame which contains all info required to change to context for a given field.
     */
    void advanceContextToGivenFrame(NavigationFrame frame) {
        in.position(frame.streamPosition);
        offset = frame.streamOffset;
        cd = frame.cd;
    }

    void setupContextForGivenPathToken(PortablePathCursor path) {
        String fieldName = path.token();
        fd = cd.getField(fieldName);
        if (fd != null) {
            return;
        }

        fieldName = extractAttributeNameNameWithoutArguments(path.token());
        fd = cd.getField(fieldName);
        if (fd == null || fieldName == null) {
            throw createUnknownFieldException(this, path.path());
        }
    }

    /**
     * @return true if managed to setup the context and the path was a single token path indeed, false otherwise
     */
    boolean trySetupContextForSingleTokenPath(String path) {
        fd = cd.getField(path);
        return fd != null;
    }

    /**
     * Populates the context with multi-positions that have to be processed later on in the navigation process.
     * The contract is that the cell[0] path is read in the non-multi-position navigation.
     * Cells[1, len-1] are stored in the multi-positions and will be followed up on later on.
     */
    void populateAnyNavigationFrames(int pathTokenIndex, int len) {
        // populate "recursive" multi-positions
        if (multiPositions == null) {
            // lazy-init only if necessary
            multiPositions = new ArrayDeque();
        }
        for (int cellIndex = len - 1; cellIndex > 0; cellIndex--) {
            multiPositions.addFirst(new NavigationFrame(cd, pathTokenIndex, cellIndex, in.position(), offset));
        }
    }

    /**
     * Navigation frame that saves the state of the current navigation
     * It is used when the navigation path diverges, e.g. when [any] operator is used, since then the whole branch
     * has to be read.
     */
    static class NavigationFrame {
        final ClassDefinition cd;

        final int pathTokenIndex;
        final int arrayIndex;

        final int streamPosition;
        final int streamOffset;

        NavigationFrame(ClassDefinition cd, int pathTokenIndex, int arrayIndex, int streamPosition,
                        int streamOffset) {
            this.cd = cd;
            this.pathTokenIndex = pathTokenIndex;
            this.arrayIndex = arrayIndex;
            this.streamPosition = streamPosition;
            this.streamOffset = streamOffset;
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy