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

org.neo4j.bolt.v1.messaging.PathPack Maven / Gradle / Ivy

/*
 * Copyright (c) 2002-2017 "Neo Technology,"
 * Network Engine for Objects in Lund AB [http://neotechnology.com]
 *
 * This file is part of Neo4j.
 *
 * Neo4j is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
package org.neo4j.bolt.v1.messaging;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import org.neo4j.bolt.v1.messaging.infrastructure.ValueNode;
import org.neo4j.bolt.v1.messaging.infrastructure.ValuePath;
import org.neo4j.collection.primitive.PrimitiveLongIntKeyValueArray;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Path;
import org.neo4j.graphdb.PropertyContainer;
import org.neo4j.graphdb.Relationship;
import org.neo4j.bolt.v1.messaging.infrastructure.ValueUnboundRelationship;

public class PathPack
{
    private static final int STRUCT_FIELD_COUNT = 5;
    private static final int NO_SUCH_ID = -1;

    public static class Packer
    {
        private static final int INITIAL_PATH_CAPACITY = 500;

        private final PrimitiveLongIntKeyValueArray nodes =
                new PrimitiveLongIntKeyValueArray( INITIAL_PATH_CAPACITY + 1 );
        private final PrimitiveLongIntKeyValueArray relationships =
                new PrimitiveLongIntKeyValueArray( INITIAL_PATH_CAPACITY );

        private void packNodes( Neo4jPack.Packer packer, Path path )
                throws IOException
        {
            nodes.reset( path.length() + 1 );
            for ( Node node : path.nodes() )
            {
                nodes.putIfAbsent( node.getId(), nodes.size() );
            }
            int size = nodes.size();
            packer.packListHeader( size );
            if ( size > 0 )
            {
                Iterator iterator = path.nodes().iterator();
                Node node = iterator.next();
                for ( long id : nodes.keys() )
                {
                    while ( node.getId() != id )
                    {
                        node = iterator.next();
                    }
                    ValueNode.pack( packer, node );
                    if ( iterator.hasNext() )
                    {
                        node = iterator.next();
                    }
                }
            }
        }

        private void packRelationships( Neo4jPack.Packer packer, Path path )
                throws IOException
        {
            relationships.reset( path.length() );
            for ( Relationship rel : path.relationships() )
            {
                // relationship indexes are one-based
                relationships.putIfAbsent( rel.getId(), relationships.size() + 1 );
            }
            int size = relationships.size();
            packer.packListHeader( size );
            if ( size > 0 )
            {
                Iterator iterator = path.relationships().iterator();
                Relationship rel = iterator.next();
                for ( long id : relationships.keys() )
                {
                    while ( rel.getId() != id )
                    {
                        rel = iterator.next();
                    }
                    ValueUnboundRelationship.pack( packer, ValueUnboundRelationship.unbind( rel ) );
                    if ( iterator.hasNext() )
                    {
                        rel = iterator.next();
                    }
                }
            }
        }

        public void pack( Neo4jPack.Packer packer, Path path ) throws IOException
        {
            packer.packStructHeader( 3, Neo4jPack.PATH );

            packNodes( packer, path );
            packRelationships( packer, path );

            Node node = null;
            packer.packListHeader( 2 * path.length() );
            int i = 0;
            for ( PropertyContainer entity : path )
            {
                if ( i % 2 == 0 )
                {
                    node = (Node) entity;
                    if ( i > 0 )
                    {
                        int index = nodes.getOrDefault( node.getId(), NO_SUCH_ID );
                        packer.pack( index );
                    }
                }
                else
                {
                    Relationship relationship = (Relationship) entity;
                    int index = relationships.getOrDefault( relationship.getId(), NO_SUCH_ID );
                    if ( node != null && node.getId() == relationship.getStartNode().getId() )
                    {
                        packer.pack( index );
                    }
                    else
                    {
                        packer.pack( -index );
                    }
                }
                i += 1;
            }
        }

    }

    public static class Unpacker
    {

        public ValuePath unpack( Neo4jPack.Unpacker unpacker )
                throws IOException
        {
            assert unpacker.unpackStructHeader() == STRUCT_FIELD_COUNT;
            assert unpacker.unpackStructSignature() == Neo4jPack.PATH;
            return unpackFields( unpacker );
        }

        public ValuePath unpackFields( Neo4jPack.Unpacker unpacker ) throws IOException
        {
            List nodes = unpackNodes( unpacker );
            List relationships = unpackRelationships( unpacker );
            List sequence = unpackSequence( unpacker );
            return new ValuePath( nodes, relationships, sequence );
        }

        private List unpackNodes( Neo4jPack.Unpacker unpacker )
                throws IOException
        {
            int count = (int) unpacker.unpackListHeader();
            if ( count > 0 )
            {
                List items = new ArrayList<>( count );
                for ( int i = 0; i < count; i++ )
                {
                    items.add( ValueNode.unpack( unpacker ) );
                }
                return items;
            }
            else
            {
                return Collections.emptyList();
            }
        }

        private List unpackRelationships( Neo4jPack.Unpacker unpacker )
                throws IOException
        {
            int count = (int) unpacker.unpackListHeader();
            if ( count > 0 )
            {
                List items = new ArrayList<>( count );
                for ( int i = 0; i < count; i++ )
                {
                    items.add( ValueUnboundRelationship.unpack( unpacker ) );
                }
                return items;
            }
            else
            {
                return Collections.emptyList();
            }
        }

        private List unpackSequence( Neo4jPack.Unpacker unpacker )
                throws IOException
        {
            int count = (int) unpacker.unpackListHeader();
            if ( count > 0 )
            {
                List items = new ArrayList<>( count );
                for ( int i = 0; i < count; i++ )
                {
                    items.add( unpacker.unpackInteger() );
                }
                return items;
            }
            else
            {
                return Collections.emptyList();
            }
        }

    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy