Package org.qi4j.entitystore.neo4j

Source Code of org.qi4j.entitystore.neo4j.NeoEntityState

package org.qi4j.entitystore.neo4j;

import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.DynamicRelationshipType;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.RelationshipType;
import org.qi4j.api.common.QualifiedName;
import org.qi4j.api.entity.EntityDescriptor;
import org.qi4j.api.entity.EntityReference;
import org.qi4j.api.property.PropertyDescriptor;
import org.qi4j.api.type.ValueType;
import org.qi4j.api.value.ValueSerialization;
import org.qi4j.api.value.ValueSerializationException;
import org.qi4j.spi.entity.EntityState;
import org.qi4j.spi.entity.EntityStatus;
import org.qi4j.spi.entity.ManyAssociationState;
import org.qi4j.spi.entity.NamedAssociationState;
import org.qi4j.spi.entitystore.EntityStoreException;
import org.qi4j.spi.entitystore.EntityStoreUnitOfWork;

public class NeoEntityState
    implements EntityState
{

    static final String ENTITY_ID = "entity_id";
    static final String VERSION = "version";
    static final String MODIFIED = "modified";
    private final NeoEntityStoreUnitOfWork uow;
    private final ValueSerialization valueSerialization;
    private final Node underlyingNode;
    private EntityStatus status;

    NeoEntityState( ValueSerialization valueSerialization, NeoEntityStoreUnitOfWork work, Node node,
                    EntityStatus status )
    {
        this.valueSerialization = valueSerialization;
        this.uow = work;
        this.underlyingNode = node;
        this.status = status;
    }

    protected void setUpdated()
    {
        if( status == EntityStatus.LOADED )
        {
            status = EntityStatus.UPDATED;
            Long version = (Long) underlyingNode.getProperty( VERSION );
            underlyingNode.setProperty( VERSION, version + 1 );
            underlyingNode.setProperty( MODIFIED, uow.currentTime() );
        }
    }

    static RelationshipType namedAssociation( QualifiedName stateName )
    {
        return DynamicRelationshipType.withName( "named_association::" + stateName.toString() );
    }

    static RelationshipType manyAssociation( QualifiedName stateName )
    {
        return DynamicRelationshipType.withName( "many_association::" + stateName.toString() );
    }

    static RelationshipType association( QualifiedName stateName )
    {
        return DynamicRelationshipType.withName( "association::" + stateName.toString() );
    }

    @Override
    public NamedAssociationState namedAssociationValueOf( QualifiedName stateName )
    {
        RelationshipType namedAssociation = namedAssociation( stateName );
        Relationship rel = underlyingNode.getSingleRelationship( namedAssociation, Direction.OUTGOING );
        if( rel != null )
        {
            return new NeoNamedAssociationState( uow, this, rel.getEndNode() );
        }
        Node node = uow.getNeo().createNode();
        node.setProperty( NeoNamedAssociationState.COUNT, 0 );
        underlyingNode.createRelationshipTo( node, namedAssociation );
        return new NeoNamedAssociationState( uow, this, node );
    }
   
    @Override
    public ManyAssociationState manyAssociationValueOf( QualifiedName stateName )
    {
        RelationshipType manyAssociation = manyAssociation( stateName );
        Relationship rel = underlyingNode.getSingleRelationship( manyAssociation, Direction.OUTGOING );
        if( rel != null )
        {
            return new NeoManyAssociationState( uow, this, rel.getEndNode() );
        }
        Node node = uow.getNeo().createNode();
        node.setProperty( NeoManyAssociationState.COUNT, 0 );
        underlyingNode.createRelationshipTo( node, manyAssociation );
        return new NeoManyAssociationState( uow, this, node );
    }

    @Override
    public EntityReference associationValueOf( QualifiedName stateName )
    {
        Relationship rel = underlyingNode.getSingleRelationship( association( stateName ), Direction.OUTGOING );
        if( rel != null )
        {
            String entityId = (String) rel.getEndNode().getProperty( ENTITY_ID );
            return new EntityReference( entityId );
        }
        return null;
    }

    @Override
    public void setAssociationValue( QualifiedName stateName, EntityReference newEntity )
    {
        RelationshipType association = association( stateName );
        Relationship rel = underlyingNode.getSingleRelationship( association, Direction.OUTGOING );
        if( rel != null )
        {
            Node otherNode = rel.getEndNode();
            if( otherNode.getProperty( ENTITY_ID ).equals( identity().identity() ) )
            {
                otherNode.delete();
            }
            rel.delete();
        }
        if( newEntity != null )
        {
            Node otherNode = uow.getEntityStateNode( newEntity );
            if( otherNode.equals( underlyingNode ) )
            {
                // create a blank node for self reference
                otherNode = uow.getNeo().createNode();
                otherNode.setProperty( ENTITY_ID, identity().identity() );
            }
            underlyingNode.createRelationshipTo( otherNode, association );
        }
    }

    @Override
    public Object propertyValueOf( QualifiedName stateName )
    {
        try
        {
            PropertyDescriptor persistentProperty = entityDescriptor().state().findPropertyModelByQualifiedName( stateName );
            Object prop = underlyingNode.getProperty( "prop::" + stateName.toString(), null );
            if( prop == null )
            {
                return null;
            }
            else if( ValueType.isPrimitiveValueType( persistentProperty.valueType() ) )
            {
                return prop;
            }
            else
            {
                return valueSerialization.deserialize( persistentProperty.valueType(), prop.toString() );
            }
        }
        catch( ValueSerializationException e )
        {
            throw new EntityStoreException( e );
        }
    }

    @Override
    public void setPropertyValue( QualifiedName stateName, Object prop )
    {
        try
        {
            if( prop != null )
            {
                PropertyDescriptor persistentProperty = entityDescriptor().state().findPropertyModelByQualifiedName( stateName );
                if( ValueType.isPrimitiveValueType( persistentProperty.valueType() ) )
                {
                    underlyingNode.setProperty( "prop::" + stateName.toString(), prop );
                }
                else
                {
                    String jsonString = valueSerialization.serialize( prop );
                    underlyingNode.setProperty( "prop::" + stateName.toString(), jsonString );
                }
            }
            else
            {
                underlyingNode.removeProperty( stateName.toString() );
            }
            setUpdated();
        }
        catch( ValueSerializationException e )
        {
            throw new EntityStoreException( e );
        }
    }

    @Override
    public void remove()
    {
        // Apparently remove should just force remove associations instead
        // of throwing exception if the entity has incomming associations
//            if ( underlyingNode.hasRelationship( Direction.INCOMING ) )
//            {
//                throw new IllegalStateException(
//                    "Cannot remove entity with reference: " + identity()
//                    + ". It has incoming associtaions.");
//            }
        // remove of all incomming associations
        for( Relationship rel : underlyingNode.getRelationships( Direction.INCOMING ) )
        {
            rel.delete();
        }
        uow.getIndexService().removeIndex( underlyingNode,
                                           NeoEntityStoreUnitOfWork.ENTITY_STATE_ID,
                                           underlyingNode.getProperty( ENTITY_ID ) );

        for( Relationship rel : underlyingNode.getRelationships( Direction.OUTGOING ) )
        {
            Node endNode = rel.getEndNode();
            boolean manyAssocNode = false, namedAssocNode = false;
            for( Relationship manyRel : endNode.getRelationships( RelTypes.MANY_ASSOCIATION, Direction.OUTGOING ) )
            {
                manyRel.delete();
                manyAssocNode = true;
            }
            for( Relationship namedRel : endNode.getRelationships( RelTypes.NAMED_ASSOCIATION, Direction.OUTGOING ) )
            {
                namedRel.delete();
                namedAssocNode = true;
            }
            if( manyAssocNode || namedAssocNode )
            {
                endNode.delete();
            }
            rel.delete();
        }
        underlyingNode.delete();
        status = EntityStatus.REMOVED;
    }

    @Override
    public EntityDescriptor entityDescriptor()
    {
        Node typeNode = underlyingNode.getSingleRelationship( RelTypes.IS_OF_TYPE, Direction.OUTGOING ).getEndNode();
        String type = (String) typeNode.getProperty( NeoEntityStoreUnitOfWork.ENTITY_TYPE );
        return uow.getEntityDescriptor( type );
    }

    public void hasBeenApplied()
    {
        // TODO
    }

    @Override
    public EntityReference identity()
    {
        return new EntityReference( (String) underlyingNode.getProperty( ENTITY_ID ) );
    }

    @Override
    public boolean isAssignableTo( Class<?> type )
    {
        Node typeNode = underlyingNode.getSingleRelationship( RelTypes.IS_OF_TYPE, Direction.OUTGOING ).getEndNode();
        String typeName = (String) typeNode.getProperty( NeoEntityStoreUnitOfWork.ENTITY_TYPE );
        return typeName.equals( type.getName() );
    }

    @Override
    public long lastModified()
    {
        long modified = (Long) underlyingNode.getProperty( MODIFIED );
        return modified;
    }

    @Override
    public EntityStatus status()
    {
        return status;
    }

    @Override
    public String version()
    {
        long version = (Long) underlyingNode.getProperty( VERSION );
        if( status == EntityStatus.UPDATED )
        {
            version--;
        }
        return "" + version;
    }

    public EntityStoreUnitOfWork unitOfWork()
    {
        return uow;
    }
}
TOP

Related Classes of org.qi4j.entitystore.neo4j.NeoEntityState

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.