1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
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
162
163 public DatabaseRepresentation root()
164 {
165 return new DatabaseRepresentation( graphDb );
166 }
167
168
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
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
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
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
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
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 }