View Javadoc

    1   /**
    2    * Copyright (c) 2002-2011 "Neo Technology,"
    3    * Network Engine for Objects in Lund AB [http://neotechnology.com]
    4    *
    5    * This file is part of Neo4j.
    6    *
    7    * Neo4j is free software: you can redistribute it and/or modify
    8    * it under the terms of the GNU General Public License as published by
    9    * the Free Software Foundation, either version 3 of the License, or
    10   * (at your option) any later version.
    11   *
    12   * This program is distributed in the hope that it will be useful,
    13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    15   * GNU General Public License for more details.
    16   *
    17   * You should have received a copy of the GNU General Public License
    18   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    19   */
    20  package org.neo4j.server.rest.web;
    21
    22  import java.lang.reflect.Array;
    23  import java.util.ArrayList;
    24  import java.util.Collection;
    25  import java.util.Collections;
    26  import java.util.Iterator;
    27  import java.util.List;
    28  import java.util.Map;
    29
    30  import org.neo4j.graphalgo.CommonEvaluators;
    31  import org.neo4j.graphalgo.CostEvaluator;
    32  import org.neo4j.graphalgo.GraphAlgoFactory;
    33  import org.neo4j.graphalgo.PathFinder;
    34  import org.neo4j.graphalgo.WeightedPath;
    35  import org.neo4j.graphdb.Direction;
    36  import org.neo4j.graphdb.DynamicRelationshipType;
    37  import org.neo4j.graphdb.Expander;
    38  import org.neo4j.graphdb.Node;
    39  import org.neo4j.graphdb.NotFoundException;
    40  import org.neo4j.graphdb.Path;
    41  import org.neo4j.graphdb.PropertyContainer;
    42  import org.neo4j.graphdb.Relationship;
    43  import org.neo4j.graphdb.RelationshipExpander;
    44  import org.neo4j.graphdb.Transaction;
    45  import org.neo4j.graphdb.TransactionFailureException;
    46  import org.neo4j.graphdb.index.Index;
    47  import org.neo4j.graphdb.index.IndexHits;
    48  import org.neo4j.graphdb.index.RelationshipIndex;
    49  import org.neo4j.graphdb.traversal.TraversalDescription;
    50  import org.neo4j.helpers.collection.IterableWrapper;
    51  import org.neo4j.kernel.AbstractGraphDatabase;
    52  import org.neo4j.kernel.Traversal;
    53  import org.neo4j.server.database.Database;
    54  import org.neo4j.server.database.DatabaseBlockedException;
    55  import org.neo4j.server.rest.domain.EndNodeNotFoundException;
    56  import org.neo4j.server.rest.domain.RelationshipExpanderBuilder;
    57  import org.neo4j.server.rest.domain.StartNodeNotFoundException;
    58  import org.neo4j.server.rest.domain.StartNodeSameAsEndNodeException;
    59  import org.neo4j.server.rest.domain.TraversalDescriptionBuilder;
    60  import org.neo4j.server.rest.domain.TraverserReturnType;
    61  import org.neo4j.server.rest.repr.DatabaseRepresentation;
    62  import org.neo4j.server.rest.repr.IndexRepresentation;
    63  import org.neo4j.server.rest.repr.IndexedEntityRepresentation;
    64  import org.neo4j.server.rest.repr.ListRepresentation;
    65  import org.neo4j.server.rest.repr.NodeIndexRepresentation;
    66  import org.neo4j.server.rest.repr.NodeIndexRootRepresentation;
    67  import org.neo4j.server.rest.repr.NodeRepresentation;
    68  import org.neo4j.server.rest.repr.PathRepresentation;
    69  import org.neo4j.server.rest.repr.PropertiesRepresentation;
    70  import org.neo4j.server.rest.repr.RelationshipIndexRepresentation;
    71  import org.neo4j.server.rest.repr.RelationshipIndexRootRepresentation;
    72  import org.neo4j.server.rest.repr.RelationshipRepresentation;
    73  import org.neo4j.server.rest.repr.Representation;
    74  import org.neo4j.server.rest.repr.RepresentationType;
    75  import org.neo4j.server.rest.repr.WeightedPathRepresentation;
    76
    77  // TODO: move this to another package. domain?
    78  public class DatabaseActions
    79  {
    80      private final AbstractGraphDatabase graphDb;
    81
    82      public DatabaseActions( Database database )
    83      {
    84          this.graphDb = database.graph;
    85      }
    86
    87      private Node node( long id ) throws NodeNotFoundException
    88      {
    89          try
    90          {
    91              return graphDb.getNodeById( id );
    92          } catch ( NotFoundException e )
    93          {
    94              throw new NodeNotFoundException();
    95          }
    96      }
    97
    98      private Relationship relationship( long id ) throws RelationshipNotFoundException
    99      {
    100         try
    101         {
    102             return graphDb.getRelationshipById( id );
    103         } catch ( NotFoundException e )
    104         {
    105             throw new RelationshipNotFoundException();
    106         }
    107     }
    108
    109     private <T extends PropertyContainer> T set( T entity, Map<String, Object> properties )
    110             throws PropertyValueException
    111     {
    112         if ( properties != null )
    113         {
    114             for ( Map.Entry<String, Object> property : properties.entrySet() )
    115             {
    116                 try
    117                 {
    118                     entity.setProperty( property.getKey(), property( property.getValue() ) );
    119                 } catch ( IllegalArgumentException ex )
    120                 {
    121                     throw new PropertyValueException( property.getKey(), property.getValue() );
    122                 }
    123             }
    124         }
    125         return entity;
    126     }
    127
    128     private Object property( Object value )
    129     {
    130         if ( value instanceof Collection<?> )
    131         {
    132             Collection<?> collection = (Collection<?>) value;
    133             Object[] array = null;
    134             Iterator<?> objects = collection.iterator();
    135             for ( int i = 0; objects.hasNext(); i++ )
    136             {
    137                 Object object = objects.next();
    138                 if ( array == null )
    139                 {
    140                     array = (Object[]) Array.newInstance( object.getClass(), collection.size() );
    141                 }
    142                 array[i] = object;
    143             }
    144             return array;
    145         }
    146         else
    147         {
    148             return value;
    149         }
    150     }
    151
    152     private <T extends PropertyContainer> T clear( T entity )
    153     {
    154         for ( String key : entity.getPropertyKeys() )
    155         {
    156             entity.removeProperty( key );
    157         }
    158         return entity;
    159     }
    160
    161     // API
    162
    163     public DatabaseRepresentation root()
    164     {
    165         return new DatabaseRepresentation( graphDb );
    166     }
    167
    168     // Nodes
    169
    170     public NodeRepresentation createNode( Map<String, Object> properties )
    171             throws PropertyValueException
    172     {
    173         final NodeRepresentation result;
    174         Transaction tx = graphDb.beginTx();
    175         try
    176         {
    177             result = new NodeRepresentation( set( graphDb.createNode(), properties ) );
    178             tx.success();
    179         } finally
    180         {
    181             tx.finish();
    182         }
    183         return result;
    184     }
    185
    186     public NodeRepresentation getNode( long nodeId ) throws NodeNotFoundException
    187     {
    188         return new NodeRepresentation( node( nodeId ) );
    189     }
    190
    191     public void deleteNode( long nodeId ) throws NodeNotFoundException, OperationFailureException
    192     {
    193         Node node = node( nodeId );
    194         Transaction tx = graphDb.beginTx();
    195         try
    196         {
    197             node.delete();
    198             tx.success();
    199         } finally
    200         {
    201             try
    202             {
    203                 tx.finish();
    204             } catch ( TransactionFailureException e )
    205             {
    206                 throw new OperationFailureException();
    207             }
    208         }
    209     }
    210
    211     public NodeRepresentation getReferenceNode()
    212     {
    213         return new NodeRepresentation( graphDb.getReferenceNode() );
    214     }
    215
    216     // Node properties
    217
    218     public Representation getNodeProperty( long nodeId, String key ) throws NodeNotFoundException,
    219             NoSuchPropertyException
    220     {
    221         Node node = node( nodeId );
    222         try
    223         {
    224             return PropertiesRepresentation.value( node.getProperty( key ) );
    225         } catch ( NotFoundException e )
    226         {
    227             throw new NoSuchPropertyException( node, key );
    228         }
    229     }
    230
    231     public void setNodeProperty( long nodeId, String key, Object value )
    232             throws PropertyValueException, NodeNotFoundException
    233     {
    234         Node node = node( nodeId );
    235         value = property( value );
    236         Transaction tx = graphDb.beginTx();
    237         try
    238         {
    239             node.setProperty( key, value );
    240             tx.success();
    241         } catch ( IllegalArgumentException e )
    242         {
    243             throw new PropertyValueException( key, value );
    244         } finally
    245         {
    246             tx.finish();
    247         }
    248     }
    249
    250     public void removeNodeProperty( long nodeId, String key ) throws NodeNotFoundException,
    251             NoSuchPropertyException
    252     {
    253         Node node = node( nodeId );
    254         Transaction tx = graphDb.beginTx();
    255         try
    256         {
    257             if ( node.removeProperty( key ) == null )
    258             {
    259                 throw new NoSuchPropertyException( node, key );
    260             }
    261             tx.success();
    262         } finally
    263         {
    264             tx.finish();
    265         }
    266     }
    267
    268     public PropertiesRepresentation getAllNodeProperties( long nodeId )
    269             throws NodeNotFoundException
    270     {
    271         return new PropertiesRepresentation( node( nodeId ) );
    272     }
    273
    274     public void setAllNodeProperties( long nodeId, Map<String, Object> properties )
    275             throws PropertyValueException, NodeNotFoundException
    276     {
    277         Node node = node( nodeId );
    278         Transaction tx = graphDb.beginTx();
    279         try
    280         {
    281             set( clear( node ), properties );
    282             tx.success();
    283         } finally
    284         {
    285             tx.finish();
    286         }
    287     }
    288
    289     public void removeAllNodeProperties( long nodeId ) throws NodeNotFoundException
    290     {
    291         Node node = node( nodeId );
    292         Transaction tx = graphDb.beginTx();
    293         try
    294         {
    295             clear( node );
    296             tx.success();
    297         } finally
    298         {
    299             tx.finish();
    300         }
    301     }
    302
    303     public String[] getNodeIndexNames()
    304     {
    305         return graphDb.index().nodeIndexNames();
    306     }
    307
    308     public String[] getRelationshipIndexNames()
    309     {
    310         return graphDb.index().relationshipIndexNames();
    311     }
    312
    313     public IndexRepresentation createNodeIndex( Map<String, Object> indexSpecification )
    314     {
    315         final String indexName = (String) indexSpecification.get( "name" );
    316         if ( indexSpecification.containsKey( "config" ) )
    317         {
    318
    319             @SuppressWarnings( "unchecked" )
    320             Map<String, String> config = (Map<String, String>) indexSpecification.get( "config" );
    321             graphDb.index().forNodes( indexName, config );
    322
    323             return new NodeIndexRepresentation( indexName, config );
    324         }
    325
    326         graphDb.index().forNodes( indexName );
    327         return new NodeIndexRepresentation( indexName, Collections.<String, String>emptyMap() );
    328     }
    329
    330
    331     public IndexRepresentation createRelationshipIndex( Map<String, Object> indexSpecification )
    332     {
    333         final String indexName = (String) indexSpecification.get( "name" );
    334         if ( indexSpecification.containsKey( "config" ) )
    335         {
    336
    337             @SuppressWarnings( "unchecked" )
    338             Map<String, String> config = (Map<String, String>) indexSpecification.get( "config" );
    339             graphDb.index().forRelationships( indexName, config );
    340
    341             return new RelationshipIndexRepresentation( indexName, config );
    342         }
    343
    344         graphDb.index().forRelationships( indexName );
    345         return new RelationshipIndexRepresentation( indexName, Collections.<String, String>emptyMap() );
    346     }
    347
    348     public boolean nodeIsIndexed( String indexName, String key, Object value, long nodeId ) throws DatabaseBlockedException
    349     {
    350
    351         Index<Node> index = graphDb.index().forNodes( indexName );
    352         Transaction tx = graphDb.beginTx();
    353         try
    354         {
    355             Node expectedNode = graphDb.getNodeById( nodeId );
    356             IndexHits<Node> hits = index.get( key, value );
    357             boolean contains = iterableContains( hits, expectedNode );
    358             tx.success();
    359             return contains;
    360         } finally
    361         {
    362             tx.finish();
    363         }
    364     }
    365
    366     public boolean relationshipIsIndexed( String indexName, String key, Object value, long relationshipId ) throws DatabaseBlockedException
    367     {
    368
    369         Index<Relationship> index = graphDb.index().forRelationships( indexName );
    370         Transaction tx = graphDb.beginTx();
    371         try
    372         {
    373             Relationship expectedNode = graphDb.getRelationshipById( relationshipId );
    374             IndexHits<Relationship> hits = index.get( key, value );
    375             boolean contains = iterableContains( hits, expectedNode );
    376             tx.success();
    377             return contains;
    378         } finally
    379         {
    380             tx.finish();
    381         }
    382     }
    383
    384     private <T> boolean iterableContains( Iterable<T> iterable, T expectedElement )
    385     {
    386         for ( T possibleMatch : iterable )
    387         {
    388             if ( possibleMatch.equals( expectedElement ) )
    389                 return true;
    390         }
    391         return false;
    392     }
    393
    394     // Relationships
    395
    396     public enum RelationshipDirection
    397     {
    398         all( Direction.BOTH ),
    399         in( Direction.INCOMING ),
    400         out( Direction.OUTGOING );
    401         final Direction internal;
    402
    403         private RelationshipDirection( Direction internal )
    404         {
    405             this.internal = internal;
    406         }
    407     }
    408
    409     public RelationshipRepresentation createRelationship( long startNodeId, long endNodeId,
    410                                                           String type,
    411                                                           Map<String, Object> properties ) throws StartNodeNotFoundException,
    412             EndNodeNotFoundException, StartNodeSameAsEndNodeException, PropertyValueException
    413     {
    414         if ( startNodeId == endNodeId )
    415         {
    416             throw new StartNodeSameAsEndNodeException();
    417         }
    418         Node start, end;
    419         try
    420         {
    421             start = node( startNodeId );
    422         } catch ( NodeNotFoundException e )
    423         {
    424             throw new StartNodeNotFoundException();
    425         }
    426         try
    427         {
    428             end = node( endNodeId );
    429         } catch ( NodeNotFoundException e )
    430         {
    431             throw new EndNodeNotFoundException();
    432         }
    433         final RelationshipRepresentation result;
    434         Transaction tx = graphDb.beginTx();
    435         try
    436         {
    437             result = new RelationshipRepresentation( set( start.createRelationshipTo( end,
    438                     DynamicRelationshipType.withName( type ) ), properties ) );
    439             tx.success();
    440         } finally
    441         {
    442             tx.finish();
    443         }
    444         return result;
    445     }
    446
    447     public RelationshipRepresentation getRelationship( long relationshipId )
    448             throws RelationshipNotFoundException
    449     {
    450         return new RelationshipRepresentation( relationship( relationshipId ) );
    451     }
    452
    453     public void deleteRelationship( long relationshipId ) throws RelationshipNotFoundException
    454     {
    455         Relationship relationship = relationship( relationshipId );
    456         Transaction tx = graphDb.beginTx();
    457         try
    458         {
    459             relationship.delete();
    460             tx.success();
    461         } finally
    462         {
    463             tx.finish();
    464         }
    465     }
    466
    467     public ListRepresentation getNodeRelationships( long nodeId, RelationshipDirection direction,
    468                                                     Collection<String> types ) throws NodeNotFoundException
    469     {
    470         Node node = node( nodeId );
    471         Expander expander;
    472         if ( types.isEmpty() )
    473         {
    474             expander = Traversal.expanderForAllTypes( direction.internal );
    475         }
    476         else
    477         {
    478             expander = Traversal.emptyExpander();
    479             for ( String type : types )
    480             {
    481                 expander = expander.add( DynamicRelationshipType.withName( type ),
    482                         direction.internal );
    483             }
    484         }
    485         return RelationshipRepresentation.list( expander.expand( node ) );
    486     }
    487
    488     // Relationship properties
    489
    490     public PropertiesRepresentation getAllRelationshipProperties( long relationshipId )
    491             throws RelationshipNotFoundException
    492     {
    493         return new PropertiesRepresentation( relationship( relationshipId ) );
    494     }
    495
    496     public Representation getRelationshipProperty( long relationshipId, String key )
    497             throws NoSuchPropertyException, RelationshipNotFoundException
    498     {
    499         Relationship relationship = relationship( relationshipId );
    500         try
    501         {
    502             return PropertiesRepresentation.value( relationship.getProperty( key ) );
    503         } catch ( NotFoundException e )
    504         {
    505             throw new NoSuchPropertyException( relationship, key );
    506         }
    507     }
    508
    509     public void setAllRelationshipProperties( long relationshipId, Map<String, Object> properties )
    510             throws PropertyValueException, RelationshipNotFoundException
    511     {
    512         Relationship relationship = relationship( relationshipId );
    513         Transaction tx = graphDb.beginTx();
    514         try
    515         {
    516             set( clear( relationship ), properties );
    517             tx.success();
    518         } finally
    519         {
    520             tx.finish();
    521         }
    522     }
    523
    524     public void setRelationshipProperty( long relationshipId, String key, Object value )
    525             throws PropertyValueException, RelationshipNotFoundException
    526     {
    527         Relationship relationship = relationship( relationshipId );
    528         value = property( value );
    529         Transaction tx = graphDb.beginTx();
    530         try
    531         {
    532             relationship.setProperty( key, value );
    533             tx.success();
    534         } catch ( IllegalArgumentException e )
    535         {
    536             throw new PropertyValueException( key, value );
    537         } finally
    538         {
    539             tx.finish();
    540         }
    541     }
    542
    543     public void removeAllRelationshipProperties( long relationshipId )
    544             throws RelationshipNotFoundException
    545     {
    546         Relationship relationship = relationship( relationshipId );
    547         Transaction tx = graphDb.beginTx();
    548         try
    549         {
    550             clear( relationship );
    551             tx.success();
    552         } finally
    553         {
    554             tx.finish();
    555         }
    556     }
    557
    558     public void removeRelationshipProperty( long relationshipId, String key )
    559             throws RelationshipNotFoundException, NoSuchPropertyException
    560     {
    561         Relationship relationship = relationship( relationshipId );
    562         Transaction tx = graphDb.beginTx();
    563         try
    564         {
    565             if ( relationship.removeProperty( key ) == null )
    566             {
    567                 throw new NoSuchPropertyException( relationship, key );
    568             }
    569             tx.success();
    570         } finally
    571         {
    572             tx.finish();
    573         }
    574     }
    575
    576     // Index
    577
    578     public enum IndexType
    579     {
    580         node( "index" )
    581                 {
    582                 },
    583         relationship( "index" )
    584                 {
    585                 };
    586         private final String pathPrefix;
    587
    588         private IndexType( String pathPrefix )
    589         {
    590             this.pathPrefix = pathPrefix;
    591         }
    592
    593         @SuppressWarnings("boxing")
    594         String path( String indexName, String key, String value, long id )
    595         {
    596             return String.format( "%s/%s/%s/%s/%s", pathPrefix, indexName, key, value, id );
    597         }
    598     }
    599
    600     public Representation nodeIndexRoot()
    601     {
    602         return new NodeIndexRootRepresentation( graphDb.index() );
    603     }
    604
    605     public Representation relationshipIndexRoot()
    606     {
    607         return new RelationshipIndexRootRepresentation( graphDb.index() );
    608     }
    609
    610     public IndexedEntityRepresentation addToRelationshipIndex( String indexName, String key,
    611                                                                String value, long relationshipId )
    612     {
    613         Transaction tx = graphDb.beginTx();
    614         try
    615         {
    616             Relationship relationship = graphDb.getRelationshipById( relationshipId );
    617             Index<Relationship> index = graphDb.index().forRelationships( indexName );
    618             index.add( relationship, key, value );
    619             tx.success();
    620             return new IndexedEntityRepresentation( relationship, key, value, new RelationshipIndexRepresentation( indexName, Collections.<String, String>emptyMap() ) );
    621         } finally
    622         {
    623             tx.finish();
    624         }
    625     }
    626
    627     public IndexedEntityRepresentation addToNodeIndex( String indexName, String key,
    628                                                        String value, long nodeId )
    629     {
    630         Transaction tx = graphDb.beginTx();
    631         try
    632         {
    633             Node node = graphDb.getNodeById( nodeId );
    634             Index<Node> index = graphDb.index().forNodes( indexName );
    635             index.add( node, key, value );
    636             tx.success();
    637             return new IndexedEntityRepresentation( node, key, value, new NodeIndexRepresentation( indexName, Collections.<String, String>emptyMap() ) );
    638         } finally
    639         {
    640             tx.finish();
    641         }
    642     }
    643
    644     public void removeFromNodeIndex( String indexName, String key, String value, long id )
    645     {
    646         Index<Node> index = graphDb.index().forNodes( indexName );
    647         Transaction tx = graphDb.beginTx();
    648         try
    649         {
    650             index.remove( graphDb.getNodeById( id ), key, value );
    651             tx.success();
    652         } finally
    653         {
    654             tx.finish();
    655         }
    656     }
    657
    658     public void removeFromNodeIndexNoValue( String indexName, String key, long id )
    659     {
    660         Index<Node> index = graphDb.index().forNodes( indexName );
    661         Transaction tx = graphDb.beginTx();
    662         try
    663         {
    664             index.remove( graphDb.getNodeById( id ), key );
    665             tx.success();
    666         } finally
    667         {
    668             tx.finish();
    669         }
    670     }
    671
    672     public void removeFromNodeIndexNoKeyValue( String indexName, long id )
    673     {
    674         Index<Node> index = graphDb.index().forNodes( indexName );
    675         Transaction tx = graphDb.beginTx();
    676         try
    677         {
    678             index.remove( graphDb.getNodeById( id ) );
    679             tx.success();
    680         } finally
    681         {
    682             tx.finish();
    683         }
    684     }
    685
    686     public void removeFromRelationshipIndex( String indexName, String key, String value, long id )
    687     {
    688         RelationshipIndex index = graphDb.index().forRelationships( indexName );
    689         Transaction tx = graphDb.beginTx();
    690         try
    691         {
    692             index.remove( graphDb.getRelationshipById( id ), key, value );
    693             tx.success();
    694         } finally
    695         {
    696             tx.finish();
    697         }
    698     }
    699
    700     public void removeFromRelationshipIndexNoValue( String indexName, String key, long id )
    701     {
    702         RelationshipIndex index = graphDb.index().forRelationships( indexName );
    703         Transaction tx = graphDb.beginTx();
    704         try
    705         {
    706             index.remove( graphDb.getRelationshipById( id ), key );
    707             tx.success();
    708         } finally
    709         {
    710             tx.finish();
    711         }
    712     }
    713
    714     public void removeFromRelationshipIndexNoKeyValue( String indexName, long id )
    715     {
    716         RelationshipIndex index = graphDb.index().forRelationships( indexName );
    717         Transaction tx = graphDb.beginTx();
    718         try
    719         {
    720             index.remove( graphDb.getRelationshipById( id ) );
    721             tx.success();
    722         } finally
    723         {
    724             tx.finish();
    725         }
    726     }
    727
    728     public IndexedEntityRepresentation getIndexedNode( String indexName,
    729                                                        String key, String value, long id )
    730     {
    731         if ( !nodeIsIndexed( indexName, key, value, id ) )
    732             throw new NotFoundException();
    733         Node node = graphDb.getNodeById( id );
    734         return new IndexedEntityRepresentation( node, key, value, new NodeIndexRepresentation( indexName, Collections.<String, String>emptyMap() ) );
    735     }
    736
    737     public IndexedEntityRepresentation getIndexedRelationship( String indexName,
    738                                                                String key, String value, long id )
    739     {
    740         if ( !relationshipIsIndexed( indexName, key, value, id ) )
    741             throw new NotFoundException();
    742         Relationship node = graphDb.getRelationshipById( id );
    743         return new IndexedEntityRepresentation( node, key, value, new RelationshipIndexRepresentation( indexName, Collections.<String, String>emptyMap() ) );
    744     }
    745
    746
    747     public ListRepresentation getIndexedNodesByExactMatch( String indexName, String key,
    748                                                String value )
    749     {
    750         if ( !graphDb.index().existsForNodes( indexName ) )
    751             throw new NotFoundException();
    752         Index<Node> index = graphDb.index().forNodes( indexName );
    753         List<IndexedEntityRepresentation> representations = new ArrayList<IndexedEntityRepresentation>();
    754
    755         Transaction tx = graphDb.beginTx();
    756         try
    757         {
    758             IndexRepresentation indexRepresentation = new NodeIndexRepresentation( indexName );
    759             for ( Node node : index.get( key, value ) )
    760             {
    761                 representations.add( new IndexedEntityRepresentation( node, key, value, indexRepresentation ) );
    762             }
    763             tx.success();
    764             return new ListRepresentation( RepresentationType.NODE, representations );
    765         } finally
    766         {
    767             tx.finish();
    768         }
    769     }
    770
    771     public ListRepresentation getIndexedNodesByQuery( String indexName, String key,
    772                                                String query )
    773     {
    774         if ( !graphDb.index().existsForNodes( indexName ) )
    775             throw new NotFoundException();
    776         Index<Node> index = graphDb.index().forNodes( indexName );
    777         List<Representation> representations = new ArrayList<Representation>();
    778
    779         Transaction tx = graphDb.beginTx();
    780         try
    781         {
    782             for ( Node node : index.query( key, query ) )
    783             {
    784                 representations.add( new NodeRepresentation( node ));
    785             }
    786             tx.success();
    787             return new ListRepresentation( RepresentationType.NODE, representations );
    788         } finally
    789         {
    790             tx.finish();
    791         }
    792     }
    793
    794
    795     public ListRepresentation getIndexedRelationships( String indexName, String key,
    796                                                        String value )
    797     {
    798         if ( !graphDb.index().existsForRelationships( indexName ) )
    799             throw new NotFoundException();
    800         List<IndexedEntityRepresentation> representations = new ArrayList<IndexedEntityRepresentation>();
    801         Index<Relationship> index = graphDb.index().forRelationships( indexName );
    802
    803         Transaction tx = graphDb.beginTx();
    804         try
    805         {
    806             IndexRepresentation indexRepresentation = new RelationshipIndexRepresentation( indexName );
    807             for ( Relationship node : index.get( key, value ) )
    808             {
    809                 representations.add( new IndexedEntityRepresentation( node, key, value, indexRepresentation ) );
    810             }
    811             tx.success();
    812             return new ListRepresentation( RepresentationType.RELATIONSHIP, representations );
    813         } finally
    814         {
    815             tx.finish();
    816         }
    817     }
    818
    819     public ListRepresentation getIndexedRelationshipsByQuery( String indexName, String key,
    820                                                        String query )
    821     {
    822         if ( !graphDb.index().existsForRelationships( indexName ) )
    823             throw new NotFoundException();
    824         List<Representation> representations = new ArrayList<Representation>();
    825         Index<Relationship> index = graphDb.index().forRelationships( indexName );
    826
    827         Transaction tx = graphDb.beginTx();
    828         try
    829         {
    830             for ( Relationship rel : index.query( key, query ) )
    831             {
    832                 representations.add( new RelationshipRepresentation( rel ));
    833             }
    834             tx.success();
    835             return new ListRepresentation( RepresentationType.RELATIONSHIP, representations );
    836         } finally
    837         {
    838             tx.finish();
    839         }
    840     }
    841
    842     // Traversal
    843
    844     public ListRepresentation traverse( long startNode, Map<String, Object> description,
    845                                         TraverserReturnType returnType )
    846     {
    847         Node node = graphDb.getNodeById( startNode );
    848
    849         List<Representation> result = new ArrayList<Representation>();
    850
    851         TraversalDescription traversalDescription = TraversalDescriptionBuilder.from( description );
    852         for ( Path position : traversalDescription.traverse( node ) )
    853         {
    854             result.add( returnType.toRepresentation( position ) );
    855         }
    856
    857         return new ListRepresentation( returnType.repType, result );
    858     }
    859
    860     @SuppressWarnings( "rawtypes" )
    861     public PathRepresentation findSinglePath( long startId, long endId,
    862                                               Map<String, Object> map )
    863     {
    864         FindParams findParams = new FindParams( startId, endId, map ).invoke();
    865         PathFinder finder = findParams.getFinder();
    866         Node startNode = findParams.getStartNode();
    867         Node endNode = findParams.getEndNode();
    868
    869         Path path = finder.findSinglePath( startNode, endNode );
    870         if ( path == null )
    871         {
    872             throw new NotFoundException();
    873         }
    874         return findParams.pathRepresentationOf( path );
    875     }
    876
    877     @SuppressWarnings( { "rawtypes", "unchecked" } )
    878     public ListRepresentation findPaths( long startId, long endId,
    879                                          Map<String, Object> map )
    880     {
    881         final FindParams findParams = new FindParams( startId, endId, map ).invoke();
    882         PathFinder finder = findParams.getFinder();
    883         Node startNode = findParams.getStartNode();
    884         Node endNode = findParams.getEndNode();
    885
    886         Iterable paths = finder.findAllPaths( startNode, endNode );
    887
    888         IterableWrapper<PathRepresentation, Path> pathRepresentations = new IterableWrapper<PathRepresentation, Path>( paths )
    889         {
    890             @Override
    891             protected PathRepresentation underlyingObjectToObject( Path path )
    892             {
    893                 return findParams.pathRepresentationOf( path );
    894             }
    895         };
    896
    897         return new ListRepresentation( RepresentationType.PATH, pathRepresentations );
    898     }
    899
    900     private class FindParams
    901     {
    902         private final long startId;
    903         private final long endId;
    904         private final Map<String, Object> map;
    905         private Node startNode;
    906         private Node endNode;
    907         private PathFinder<? extends Path> finder;
    908         @SuppressWarnings( "rawtypes" )
    909         private PathRepresentationCreator representationCreator = PATH_REPRESENTATION_CREATOR;
    910
    911         public FindParams( final long startId, final long endId, final Map<String, Object> map )
    912         {
    913             this.startId = startId;
    914             this.endId = endId;
    915             this.map = map;
    916         }
    917
    918         public Node getStartNode()
    919         {
    920             return startNode;
    921         }
    922
    923         public Node getEndNode()
    924         {
    925             return endNode;
    926         }
    927
    928         public PathFinder<? extends Path> getFinder()
    929         {
    930             return finder;
    931         }
    932
    933         @SuppressWarnings( "unchecked" )
    934         public PathRepresentation<? extends Path> pathRepresentationOf( Path path )
    935         {
    936             return representationCreator.from( path );
    937         }
    938
    939         public FindParams invoke()
    940         {
    941             startNode = graphDb.getNodeById( startId );
    942             endNode = graphDb.getNodeById( endId );
    943
    944             Integer maxDepthObj = (Integer) map.get( "max depth" );
    945             int maxDepth = (maxDepthObj != null) ? maxDepthObj : 1;
    946
    947             RelationshipExpander expander = RelationshipExpanderBuilder.describeRelationships( map );
    948
    949             String algorithm = (String) map.get( "algorithm" );
    950             algorithm = (algorithm != null) ? algorithm : "shortestPath";
    951
    952             finder = getAlgorithm( algorithm, expander, maxDepth );
    953             return this;
    954         }
    955
    956         private PathFinder<? extends Path> getAlgorithm( String algorithm, RelationshipExpander expander, int maxDepth )
    957         {
    958             if ( algorithm.equals( "shortestPath" ) )
    959             {
    960                 return GraphAlgoFactory.shortestPath( expander, maxDepth );
    961             }
    962             else if ( algorithm.equals( "allSimplePaths" ) )
    963             {
    964                 return GraphAlgoFactory.allSimplePaths( expander, maxDepth );
    965             }
    966             else if ( algorithm.equals( "allPaths" ) )
    967             {
    968                 return GraphAlgoFactory.allPaths( expander, maxDepth );
    969             }
    970             else if ( algorithm.equals( "dijkstra" ) )
    971             {
    972                 String costProperty = (String) map.get( "cost property" );
    973                 Number defaultCost = (Number) map.get( "default cost" );
    974                 CostEvaluator<Double> costEvaluator = defaultCost == null ?
    975                         CommonEvaluators.doubleCostEvaluator( costProperty ) :
    976                         CommonEvaluators.doubleCostEvaluator( costProperty, defaultCost.doubleValue() );
    977                 representationCreator = WEIGHTED_PATH_REPRESENTATION_CREATOR;
    978                 return GraphAlgoFactory.dijkstra( expander, costEvaluator );
    979             }
    980
    981             throw new RuntimeException( "Failed to find matching algorithm" );
    982         }
    983     }
    984
    985     private interface PathRepresentationCreator<T extends Path>
    986     {
    987         PathRepresentation<T> from( T path );
    988     }
    989
    990     private static final PathRepresentationCreator<Path> PATH_REPRESENTATION_CREATOR = new PathRepresentationCreator<Path>()
    991     {
    992         @Override
    993         public PathRepresentation<Path> from( Path path )
    994         {
    995             return new PathRepresentation<Path>( path );
    996         }
    997     };
    998
    999     private static final PathRepresentationCreator<WeightedPath> WEIGHTED_PATH_REPRESENTATION_CREATOR =
    1000             new PathRepresentationCreator<WeightedPath>()
    1001     {
    1002         @Override
    1003         public PathRepresentation<WeightedPath> from( WeightedPath path )
    1004         {
    1005             return new WeightedPathRepresentation( path );
    1006         }
    1007     };
    1008 }