Package org.neo4j.collections.indexedrelationship

Source Code of org.neo4j.collections.indexedrelationship.IndexedRelationship$DirectRelationship

/**
* Copyright (c) 2002-2013 "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 <http://www.gnu.org/licenses/>.
*/
package org.neo4j.collections.indexedrelationship;

import java.util.Iterator;

import org.neo4j.collections.NodeCollection;
import org.neo4j.collections.NodeCollectionLoader;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.RelationshipType;

/**
* A specialized relationship type using a {@link NodeCollection} index.
* Every relationship is stored in the index, making it possible to
* have a sorted collection of relationships, or to enforce a unicity
* constraint on the relationship.
* <p/>
* This class is also useful when confronted with situations where
* normal relationships would lead to densely populated nodes.
* <p/>
* Given an end node, the start node of the relationship
* can be found by traversing:
* <ol>
* <li>KEY_VALUE, INCOMING</li>
* <li>KEY_ENTRY, INCOMING</li>
* <li>SUB_TREE, INCOMING</li>
* <li>TREE_ROOT, INCOMING</li>
* </ol>
* <p/>
* The name of the RelationshipType is stored as a property with keyname "tree_name" on both
* the TREE_ROOT and the KEY_VALUE relationships.
* <p/>
* Given a start node of the relationship, all end nodes
* can be found by traversing:
* <ol>
* <li>TREE_ROOT, OUTGOING</li>
* <li>SUB_TREE, OUTGOING</li>
* <li>KEY_ENTRY, OUTGOING</li>
* <li>KEY_VALUE, OUTGOING</li>
* </ol>
*/
public class IndexedRelationship implements Iterable<Relationship>
{
    public static final String RELATIONSHIP_DIRECTION = "relationship_direction";
    public static final String RELATIONSHIP_TYPE = "relationship_type";

    public static enum RelationshipTypes implements RelationshipType {
        NODE_COLLECTION
    }

    private final Node indexedNode;
    private final RelationshipType relType;
    private final Direction direction;
    private NodeCollection nodeCollection;

    /**
     * Create an IndexedRelationship around all the relationships of a given type from a given node. The underlying
     * NodeCollection must already exist and be attached to the indexed node for the given relationship type and
     * direction.
     *
     * @param indexedNode the node that the indexing is being based on.
     * @param relType {@link org.neo4j.graphdb.RelationshipType} of the relationships maintained in the index.
     * @param direction the {@link org.neo4j.graphdb.Direction} of the relationship.
     */
    public IndexedRelationship( Node indexedNode, RelationshipType relType, Direction direction )
    {
        this.indexedNode = indexedNode;
        this.relType = relType;
        this.direction = direction;
        nodeCollection = getNodeCollection();
    }

    /**
     * Create an IndexedRelationship around all the relationships of a given type from a given node.
     *
     * @param indexedNode the node that the indexing is being based on.
     * @param relType {@link org.neo4j.graphdb.RelationshipType} of the relationships maintained in the index.
     * @param direction the {@link org.neo4j.graphdb.Direction} of the relationship.
     * @param nodeCollection the collection to use to index the nodes linked to by the relationships being indexed.
     */
    public IndexedRelationship( Node indexedNode, RelationshipType relType, Direction direction,
                                    NodeCollection nodeCollection )
    {
        this.indexedNode = indexedNode;
        this.relType = relType;
        this.direction = direction;
        create( nodeCollection );
    }

    /**
     * Does an IndexedRelationship exist at this node for the given relationship type and direction.
     *
     * @return <code>true</code> if an indexed relationship exists.
     */
    public boolean exists()
    {
        return nodeCollection != null;
    }

    /**
     * Create an IndexedRelationship against this node with the given relationship type and direction. The node
     * collection supplied to the IndexedRelationship must already have a base node. The node collection may or may not
     * have any other nodes related to it.
     *
     * @param nodeCollection the { @link NodeCollection } backing this indexed relationship.
     */
    public void create( NodeCollection nodeCollection )
    {
        Relationship indexRelationship = indexedNode.createRelationshipTo( nodeCollection.getBaseNode(), RelationshipTypes.NODE_COLLECTION );
        indexRelationship.setProperty( RELATIONSHIP_TYPE, relType.name() );
        indexRelationship.setProperty( RELATIONSHIP_DIRECTION, direction.name() );
        this.nodeCollection = nodeCollection;
    }

    /**
     * Creates a relationship from the indexed node to the supplied node
     *
     * @param node the end node of the relationship.
     *
     * @return the relationship that was created between the indexedNode and the end node..
     */
    public Relationship createRelationshipTo( Node node )
    {
        Relationship keyValueRelationship = nodeCollection.addNode( node );
        if ( !keyValueRelationship.hasProperty( RELATIONSHIP_DIRECTION ) )
        {
            keyValueRelationship.setProperty( RELATIONSHIP_DIRECTION, direction.name() );
        }
        if ( !keyValueRelationship.hasProperty( RELATIONSHIP_TYPE ) )
        {
            keyValueRelationship.setProperty( RELATIONSHIP_TYPE, relType.name() );
        }
        return getRelationship( keyValueRelationship );
    }

    /**
     * Gets the relationship between the indexed node and the given node.
     *
     * @param relationship the {@link org.neo4j.collections.NodeCollection.RelationshipTypes#VALUE} relationship at the end of the indexed relationship.
     *
     * @return the relationship between the indexed node and the given node.
     */
    public Relationship getRelationship( Relationship relationship )
    {
        return new DirectRelationship( indexedNode, relationship );
    }

    /**
     * Removes the relationship from the indexed node to the supplied node if it exists
     *
     * @param node the end node of the relationship.
     *
     * @return {@code true} if this call modified the index, i.e. if the node
     *         was actually stored in the index.
     */
    public boolean removeRelationshipTo( Node node )
    {
        return nodeCollection.remove( node );
    }

    /**
     * @return the {@link Node} whose outgoing relationships are being indexed.
     */
    public Node getIndexedNode()
    {
        return indexedNode;
    }

    /**
     * @return the {@link RelationshipType} of the indexed relationships.
     */
    public RelationshipType getRelationshipType()
    {
        return relType;
    }

    /**
     * @return the {@link Node}s whose incoming relationships are being indexed.
     */
    public Iterator<Relationship> iterator()
    {
        return new RelationshipIterator();
    }

    private NodeCollection getNodeCollection()
    {
        Relationship indexRelationship = null;
        for ( Relationship candidateRelationship : this.indexedNode.getRelationships( RelationshipTypes.NODE_COLLECTION, Direction.OUTGOING ) )
        {
            String relName = (String) candidateRelationship.getProperty( RELATIONSHIP_TYPE, null );
            if ( relType.name().equals( relName ) )
            {
                String dir = (String) candidateRelationship.getProperty( RELATIONSHIP_DIRECTION, null );
                if ( direction.name().equals( dir ) )
                {
                    if ( indexRelationship != null ) {
                        throw new IllegalStateException(
                            "Multiple IndexedRelationship's on the given node with relationship type: "  +
                                relType.name() + " and direction: " + direction.name());
                    }
                   
                    indexRelationship = candidateRelationship;
                }
            }
        }

        if ( indexRelationship != null )
        {
            return NodeCollectionLoader.load(indexRelationship.getEndNode());
        }

        return null;
    }

    private class RelationshipIterator implements Iterator<Relationship>
    {
        Iterator<Relationship> it = nodeCollection.getValueRelationships().iterator();
        Relationship currentRelationship = null;

        @Override
        public boolean hasNext()
        {
            return it.hasNext();
        }

        @Override
        public Relationship next()
        {
            currentRelationship = it.next();
            return getRelationship( currentRelationship );
        }

        @Override
        public void remove()
        {
            if ( currentRelationship != null )
            {
                removeRelationshipTo( currentRelationship.getEndNode() );
            }
        }
    }

    private class DirectRelationship implements Relationship
    {
        private final Node indexedNode;
        private final Relationship keyValueRelationship;

        DirectRelationship( Node indexedNode, Relationship keyValueRelationship )
        {
            this.indexedNode = indexedNode;
            this.keyValueRelationship = keyValueRelationship;
        }

        @Override
        public GraphDatabaseService getGraphDatabase()
        {
            return indexedNode.getGraphDatabase();
        }

        @Override
        public Object getProperty( String key )
        {
            return keyValueRelationship.getProperty( key );
        }

        @Override
        public Object getProperty( String key, Object defaultValue )
        {
            return keyValueRelationship.getProperty( key, defaultValue );
        }

        @Override
        public Iterable<String> getPropertyKeys()
        {
            return keyValueRelationship.getPropertyKeys();
        }

        @Override
        public boolean hasProperty( String key )
        {
            return keyValueRelationship.hasProperty( key );
        }

        @Override
        public Object removeProperty( String key )
        {
            return keyValueRelationship.removeProperty( key );
        }

        @Override
        public void setProperty( String key, Object value )
        {
            keyValueRelationship.setProperty( key, value );
        }

        @Override
        public void delete()
        {
            removeRelationshipTo( keyValueRelationship.getEndNode() );
        }

        @Override
        public Node getEndNode()
        {
            return direction.equals(Direction.OUTGOING) ? keyValueRelationship.getEndNode() : indexedNode;
        }

        @Override
        public long getId()
        {
            throw new UnsupportedOperationException( "Indexed relationships don't have an ID" );
        }

        @Override
        public Node[] getNodes()
        {
            Node[] nodes = new Node[2];
            nodes[0] = getStartNode();
            nodes[1] = getEndNode();
            return nodes;
        }

        @Override
        public Node getOtherNode( Node node )
        {
            if ( node.equals( indexedNode ) )
            {
                return keyValueRelationship.getEndNode();
            }
            else if ( node.equals( keyValueRelationship.getEndNode() ) )
            {
                return indexedNode;
            }
            else
            {
                throw new RuntimeException( "Node is neither the start nor the end node" );
            }
        }

        @Override
        public Node getStartNode()
        {
            return direction.equals(Direction.OUTGOING) ? indexedNode : keyValueRelationship.getEndNode();
        }

        @Override
        public RelationshipType getType()
        {
            return relType;
        }

        @Override
        public boolean isType( RelationshipType relType )
        {
            return relType.equals( IndexedRelationship.this.relType );
        }
    }
}
TOP

Related Classes of org.neo4j.collections.indexedrelationship.IndexedRelationship$DirectRelationship

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.