├── .gitignore ├── .travis.yml ├── CHANGELOG.textile ├── LICENSE.txt ├── README.textile ├── doc ├── Acknowledgments.textile ├── Core-Annotations.textile ├── Creating-Frames.textile ├── Custom-modules.textile ├── Factories-and-Modules.textile ├── Frame-initializers.textile ├── Frames-Ecosystem.textile ├── Getting-Started.textile ├── Gremlin-Groovy.textile ├── Home.textile ├── Introduction.textile ├── Java-Handler.textile ├── Method-Handlers.textile ├── Release-Notes.textile ├── Type-resolvers.textile ├── Typed-Graph.textile ├── Upgrading-from-2.3.1.textile └── images │ ├── frames-2.png │ ├── frames-beams.png │ ├── frames-bracket.png │ ├── frames-brick-by-brick.png │ ├── frames-character-1.png │ ├── frames-character-2.png │ ├── frames-character-3.png │ ├── frames-huff-and-puff.png │ ├── frames-logo.graffle │ ├── frames-logo.png │ ├── frames-lumber.png │ ├── frames-studs.png │ ├── frames-truss.png │ └── gremlin-in-frames.png ├── pom.xml └── src ├── assembly ├── distribution.xml └── standalone.xml ├── main └── java │ └── com │ └── tinkerpop │ └── frames │ ├── Adjacency.java │ ├── ClassUtilities.java │ ├── Domain.java │ ├── EdgeFrame.java │ ├── FrameInitializer.java │ ├── FramedElement.java │ ├── FramedGraph.java │ ├── FramedGraphConfiguration.java │ ├── FramedGraphFactory.java │ ├── FramedGraphQuery.java │ ├── FramedTransactionalGraph.java │ ├── InVertex.java │ ├── Incidence.java │ ├── OutVertex.java │ ├── Property.java │ ├── Range.java │ ├── UnhandledMethodException.java │ ├── VertexFrame.java │ ├── annotations │ ├── AdjacencyAnnotationHandler.java │ ├── AnnotationHandler.java │ ├── DomainAnnotationHandler.java │ ├── InVertexAnnotationHandler.java │ ├── IncidenceAnnotationHandler.java │ ├── OutVertexAnnotationHandler.java │ ├── PropertyAnnotationHandler.java │ ├── RangeAnnotationHandler.java │ └── gremlin │ │ ├── GremlinGroovy.java │ │ ├── GremlinGroovyAnnotationHandler.java │ │ └── GremlinParam.java │ ├── core │ └── FramedGraphQueryImpl.java │ ├── modules │ ├── AbstractModule.java │ ├── DefaultClassLoaderResolver.java │ ├── FrameClassLoaderResolver.java │ ├── MethodHandler.java │ ├── Module.java │ ├── TypeResolver.java │ ├── gremlingroovy │ │ └── GremlinGroovyModule.java │ ├── javahandler │ │ ├── Initializer.java │ │ ├── JavaFrameInitializer.java │ │ ├── JavaHandler.java │ │ ├── JavaHandlerClass.java │ │ ├── JavaHandlerContext.java │ │ ├── JavaHandlerContextImpl.java │ │ ├── JavaHandlerException.java │ │ ├── JavaHandlerFactory.java │ │ ├── JavaHandlerModule.java │ │ └── JavaMethodHandler.java │ └── typedgraph │ │ ├── TypeField.java │ │ ├── TypeManager.java │ │ ├── TypeRegistry.java │ │ ├── TypeValue.java │ │ └── TypedGraphModuleBuilder.java │ ├── structures │ ├── FramedEdgeIterable.java │ ├── FramedVertexIterable.java │ ├── FramedVertexMap.java │ └── FramedVertexSet.java │ └── util │ ├── ExceptionUtils.java │ └── Validate.java └── test └── java └── com └── tinkerpop └── frames ├── ClassUtilitiesTest.java ├── FrameInitializerTest.java ├── FramedEdgeTest.java ├── FramedElementTest.java ├── FramedGraphFactoryTest.java ├── FramedGraphTest.java ├── FramedTransactionalGraphTest.java ├── FramedVertexTest.java ├── SailFramesTest.java ├── core └── FramedGraphQueryImplTest.java ├── domain ├── classes │ ├── NamedObject.java │ ├── Person.java │ ├── Project.java │ └── ProjectImpl.java └── incidences │ ├── Created.java │ ├── CreatedBy.java │ ├── CreatedInfo.java │ ├── Knows.java │ └── WeightedEdge.java ├── modules ├── AbstractModuleTest.java ├── TypeResolverTest.java ├── javahandler │ ├── JavaHandlerContextImplTest.java │ └── JavaHandlerTest.java └── typedgraph │ ├── TypeRegistryTest.java │ └── TypedGraphModuleTest.java ├── structures └── FramedVertexSetTest.java └── util └── ValidateTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | target/ 3 | frames.iml 4 | .idea/ -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | jdk: 3 | - oraclejdk7 4 | - openjdk7 5 | - openjdk6 6 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009-Infinity, TinkerPop [http://tinkerpop.com] 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of the TinkerPop nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL TINKERPOP BE LIABLE FOR ANY 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /README.textile: -------------------------------------------------------------------------------- 1 | !https://github.com/tinkerpop/frames/raw/master/doc/images/frames-logo.png! 2 | 3 | 4 | 5 | *IMPORTANT* - TinkerPop is now a part of the Apache Software Foundation and "TinkerPop 3.x":http://tinkerpop.apache.org/ is the latest incarnation of The TinkerPop. This project is TinkerPop 2.x and is no longer active. 6 | 7 | Frames exposes the elements of a "Blueprints":http://blueprints.tinkerpop.com graph as Java objects. Instead of writing software in terms of vertices and edges, with Frames, software is written in terms of domain objects and their relationships to each other. 8 | -------------------------------------------------------------------------------- /doc/Acknowledgments.textile: -------------------------------------------------------------------------------- 1 | [[https://raw.github.com/tinkerpop/frames/master/doc/images/frames-character-2.png|width=120px]] 2 | 3 | This section provides a list of the people that have contributed in some way to the creation of Frames. 4 | 5 | # "Marko A. Rodriguez":http://markorodriguez.com -- designed, developed, tested, and documented Gremlin. 6 | # "Stephen Mallette":http://stephen.genoprime.com/ -- repository and issue tracker support. 7 | # "Bryn Cooke":https://github.com/BrynCooke -- feature design, development, and testing. 8 | # "Joshua Shinavier":http://fortytwo.net -- help with interface design. 9 | # "Ketrina Yim":http://www.ketrinayim.com/ -- designed the Frames logo. 10 | 11 | Please review Frames' "pom.xml":http://github.com/tinkerpop/frames/blob/master/pom.xml. Frames would not be possible without the work done by others to create these useful packages. -------------------------------------------------------------------------------- /doc/Core-Annotations.textile: -------------------------------------------------------------------------------- 1 | In Frames, a schema is defined by a collection of Java interfaces. The rules that bind the Java interfaces to the underlying graph representation are defined by the following: 2 | 3 | * Method name prefixes: get, is, can, set, add, remove 4 | * Annotations: method metadata. 5 | 6 | Below specifies that annotations that can be used when defining a Frames interface. By specifying the method argument and return types, the underlying graph is constrained to the interface specification. 7 | 8 | h3. Annotations valid on all frames (VertexFrame and EdgeFrame): 9 | 10 | |_. annotation |_. method prefix |_. arguments |_. description |_. example | 11 | | @@Property@ | @get@,@is@,@can@ | @value@ |get the property value of an element | @@Property("name")@ | 12 | | @@Property@ | @set@ | @value@ | set the property value of an element | @@Property("name")@ | 13 | | @@Property@ | @remove@ | @value@ | remove the property of an element | @@Property("name")@ | 14 | 15 | h3. Annotations valid on vertices (VertexFrame): 16 | 17 | |_. annotation |_. method prefix |_. arguments |_. description |_. example | 18 | | @@Adjacency@ | @get@ | @label@, @direction@ | get the vertex or vertices @X@ related to the vertex | @@Adjacency(label="X", direction=Direction.OUT)@ | 19 | | @@Adjacency@ | @set@ | @label@, @direction@ | set the vertex or vertices @X@ related to the vertex | @@Adjacency(label="X", direction=Direction.OUT)@ | 20 | | @@Adjacency@ | @add@ | @label@, @direction@ | add a vertex @X@ related to the vertex and return the vertex @X@| @@Adjacency(label="X", direction=Direction.OUT)@ | 21 | | @@Adjacency@ | @remove@ | @label@, @direction@ | remove a vertex @X@ related to the vertex| @@Adjacency(label="X", direction=Direction.OUT)@ | 22 | | @@Incidence@ | @get@ | @label@, @direction@ | get the edges @X@ related to the vertex | @@Incidence(label="X", direction=Direction.OUT)@ | 23 | | @@Incidence@ | @add@ | @label@, @direction@ | add an edge @X@ related to the vertex and return the edge @X@| @@Incidence(label="X", direction=Direction.OUT)@ | 24 | | @@Incidence@ | @remove@ | @label@, @direction@ | remove an edge @X@ related to the vertex | @@Incidence(label="X", direction=Direction.OUT)@ | 25 | 26 | Note that "get" and "set" methods for @@Adjacency@ can be either single-valued or Iterable-valued. For example: 27 | 28 | ```java 29 | public interface Person { 30 | @Adjacency(label = "spouse") 31 | Person getSpouse(); 32 | 33 | @Adjacency(label = "spouse") 34 | void setSpouse(Person spouse); 35 | 36 | @Adjacency(label = "child") 37 | Iterable getChildren(); 38 | 39 | @Adjacency(label = "child") 40 | void setChildren(Iterable children); 41 | } 42 | ``` 43 | 44 | The above interface uses both styles of getter and setter: an Iterable-valued style which allows you to set multiple values simultaneously, and gives you back all values at once, and a "functional" style which requires you to specify exactly one value (which can be null), and gives you back at most one value. Each style has its advantages, depending on your application. 45 | 46 | "add" methods for @@Adjacency@ can be either single-valued or no-valued For example: 47 | ```java 48 | public interface Person { 49 | @Adjacency(label = "friend") 50 | Person addFriend(); //Returns a new vertex of type friend 51 | 52 | @Adjacency(label = "friend") 53 | Person addFriend(Person friend); //Add an existing person as a friend 54 | } 55 | ``` 56 | 57 | h3. Annotations valid on edges (EdgeFrame): 58 | 59 | |_. annotation |_. method prefix |_. arguments |_. description |_. example | 60 | | @@InVertex@ | @get@ | none | get the in-vertex. This is equivalent to calling Edge.getVertex(Direction.IN) | @@InVertex@ | 61 | | @@OutVertex@ | @get@ | none | get the out-vertex. This is equivalent to calling Edge.getVertex(Direction.OUT) | @@OutVertex@ | 62 | | -@@Domain@- | @get@ | none | get the out-vertex of the edge when the frame was created with direction parameter @Direction.OUT@, otherwise get the in-vertex of the edge | @@Domain@ | 63 | | -@@Range@- | @get@ | none | get the out-vertex of the edge when the frame was created with direction parameter @Direction.IN@, otherwise get the in-vertex of the edge | @@Range@ | 64 | 65 | Please note: @@Domain@ and @@Range@ are deprecated. You should use @@InVertex@ and @@OutVertex@ 66 | 67 | The use of @@Domain@ and @@Range@ on an @EdgeFrame@ created by an @@Incidence@ annotation, has the following characteristics: The @Incidence.direction@ parameter of the annotation is used for both the edge direction and for determining the @@Domain@ and @@Range@ of the frame. Effectively with @Direction.OUT@ the frame source and edge source are equal, with @Direction.IN@ they are each others opposites. This means that when you want to put an @@Incidence@ annotation on the vertices at both sides of the edge, you must create two EdgeFrame types e.g. @Created@ and @CreatedBy@. -------------------------------------------------------------------------------- /doc/Creating-Frames.textile: -------------------------------------------------------------------------------- 1 | When you develop a Frames-annotation Java interface, you provide it "life" by binding it to the underlying "Blueprints":http://blueprints.tinkerpop.com graph. To make this binding, the @FramedGraph@ is used. In @FramedGraph@ there are a collection of helpful methods which are demonstrated using the toy graph diagrammed below and the example Java code. 2 | 3 | [[https://github.com/tinkerpop/blueprints/raw/master/doc/images/graph-example-1.jpg|width=450px]] 4 | 5 | ```java 6 | Graph graph = ... // get a reference to the graph 7 | FramedGraphFactory factory = new FramedGraphFactory(); // make sure you reuse the factory when creating new framed graphs. 8 | FramedGraph framedGraph = factory.create(graph); // wrap the base graph 9 | 10 | Person marko = framedGraph.getVertex(1, Person.class); 11 | Person peter = framedGraph.getVertex(6, Person.class); 12 | Iterable javaProjects = framedGraph.getVertices("lang","java", Project.class); 13 | 14 | Knows markoKnowsVadas = framedGraph.getEdge(7, Knows.class); 15 | Knows markoKnowsJosh = framedGraph.getEdge(8, Knows.class); 16 | ``` -------------------------------------------------------------------------------- /doc/Custom-modules.textile: -------------------------------------------------------------------------------- 1 | You can extend the functionality of a @FramedGraph@ via modules. 2 | 3 | ```java 4 | public interface Module { 5 | /** 6 | * @param baseGraph The graph being framed. 7 | * @param config The configuration for the new FramedGraph. 8 | * @return The graph being framed. 9 | */ 10 | T configure(Graph baseGraph, FramedGraphConfiguration config); 11 | } 12 | ``` 13 | 14 | @configure@ will be called for every graph that is being framed. At this point you can add [[Method Handlers]], [[Frame Initializers]] and [[Type Resolvers]] to the @FramedGraphConfiguration@. 15 | 16 | You may wrap the graph being framed by returning the wrapped graph from this @configure@. For example, you could return an EventGraph if your module needs to know about graph events. 17 | 18 | *Notes* 19 | * The configure method should be fast, as it will potentially be called many times. 20 | * The configure method should be threadsafe. 21 | * [[Method Handlers]], [[Frame Initializers]] and [[Type Resolvers]] should be threadsafe. -------------------------------------------------------------------------------- /doc/Factories-and-Modules.textile: -------------------------------------------------------------------------------- 1 | h3. Factories 2 | 3 | To obtain a framed graph use a @FramedGraphFactory@. 4 | 5 | ```java 6 | FramedGraphFactory factory = new FramedGraphFactory(); 7 | FramedGraph framedGraph = factory.create(baseGraph); 8 | ``` 9 | TransactionalFramedGraph can be created from a TransactionalGraph 10 | ```java 11 | FramedGraphFactory factory = new FramedGraphFactory(); 12 | TransactionalFramedGraph transactionalFramedGraph = factory.create(baseTransactionalGraph); 13 | ``` 14 | 15 | *A factory should be reused to create many graphs. Under the hood it may share resources between graphs where appropriate. This can make a big difference to performance and memory footprint.* 16 | 17 | h3. Modules 18 | 19 | @Modules@ are used to extend the capability of FramedGraph. They are registered in the constructor of the @FramedGraphFactory@. 20 | 21 | In this example the framed graph will now support the @@GremlinGroovy@ annotation on frames. 22 | ```java 23 | FramedGraphFactory factory = new FramedGraphFactory(new GremlinGroovyModule()); 24 | FramedGraph framedGraph = factory.create(baseGraph); 25 | ``` 26 | Any number of modules can be added to the factory, but a @FramedGraph@ will always support the [[Core Annotations]]. -------------------------------------------------------------------------------- /doc/Frame-initializers.textile: -------------------------------------------------------------------------------- 1 | Sometimes you need to be able to initialize a vertex or edge is added to the graph knowing the type of frame that it was created with. 2 | 3 | The @FrameInitializer@ interface allows a newly added vertex or edge to be initialized before it is returned to the user. 4 | 5 | ```java 6 | public interface FrameInitializer { 7 | /** 8 | * @param kind The kind of frame. 9 | * @param framedGraph The graph. 10 | * @param element The new element that is being inserted into the graph. 11 | */ 12 | public void initElement(final Class kind, final FramedGraph framedGraph, final Element element); 13 | } 14 | ``` 15 | 16 | To use the initializer register it via a module with the @FramedGraphFactory@. 17 | ```java 18 | FrameInitializer myInitializer = new FrameInitializer() { 19 | public void initElement(final Class kind, final FramedGraph framedGraph, final Element element) { 20 | element.setProperty("class", kind.getName()); //For example: save the class name of the frame on the element 21 | } 22 | }; 23 | 24 | FramedGraph g = new FramedGraphFactory(new AbstractModule() { 25 | public void doConfigure(FramedGraphConfiguration config) { 26 | config.addFrameInitializer(myInitializer); 27 | } 28 | }).create(baseGraph); 29 | 30 | Person p = g.addVertex(null, Person.class); //myInitializer is called. 31 | ``` 32 | Every registered initializer is called before returning the new element. 33 | 34 | Some possible use cases 35 | * You want to save the type information of the frame to the vertex. 36 | * You want to set the default property values of the vertex based on the frame type. -------------------------------------------------------------------------------- /doc/Frames-Ecosystem.textile: -------------------------------------------------------------------------------- 1 | Frames is a bare-bones library. Luckily, its part of a larger ecosystem of graph technologies. When using Frames, you will find yourself making use of framed domain objects and "Blueprints":http://blueprints.tinkerpop.com. 2 | 3 | h2. Getting Indexes 4 | 5 | Frames has no notion of indexes. To obtain an index, use Blueprints. 6 | 7 | ```java 8 | IndexedGraph graph = framedGraph.getBaseGraph(); // get reference to graph 9 | Index index = graph.getIndex("myIndex", Vertex.class); 10 | ``` 11 | -------------------------------------------------------------------------------- /doc/Getting-Started.textile: -------------------------------------------------------------------------------- 1 | [[http://i579.photobucket.com/albums/ss235/krissy_bby93/icon_UnderConstruction.png|width=120px]] 2 | 3 | h2. Creating a Domain Model with Java Interfaces 4 | 5 | Frames makes use of Java interfaces and annotations. Here is a simple example that mixes people and software projects. People create projects and know each other. To represent such concepts in Java, do the following. First, lets create a @Person@ interface. 6 | 7 | ```java 8 | public interface Person { 9 | @Property("name") 10 | public void setName(String name); 11 | @Property("name") 12 | public String getName(); 13 | @Property("age") 14 | public void setAge(int age); 15 | @Property("age") 16 | public int getAge(); 17 | 18 | @Adjacency(label="knows") 19 | public Iterable getKnowsPeople(); 20 | @Adjacency(label="knows") 21 | public void addKnowsPerson(Person person); 22 | 23 | @Adjacency(label="created") 24 | public Iterable getCreatedProjects(); 25 | @Adjacency(label="created") 26 | public void addCreatedProject(Project project); 27 | } 28 | ``` 29 | 30 | That is all there is to it. Once an interface has been constructed to represent a vertex type, then a vertex in the graph can be framed within the perspective of that interface. 31 | 32 | h2. Framing Graph Elements in Terms of the Java Interfaces 33 | 34 | For the remainder of this section, the following graph example will be used. Note that this toy graph comes hardcoded with "Blueprints":http://blueprints.tinkerpop.com and is available as @TinkerGraphFactory.createTinkerGraph()@. 35 | 36 | [[https://github.com/tinkerpop/blueprints/raw/master/doc/images/graph-example-1.jpg|width=450px]] 37 | 38 | To frame vertex 1 (marko) in terms of the @Person@ interface defined previously, simply do the following. 39 | 40 | ```java 41 | Graph graph = TinkerGraphFactory.createTinkerGraph(); 42 | FramedGraphFactory factory = new FramedGraphFactory(); 43 | FramedGraph manager = factory.create(graph); 44 | Person marko = manager.frame(graph.getVertex(1), Person.class); 45 | ``` 46 | 47 | Now its possible to update Marko's age, get his name, and determine the names of all the people he knows. 48 | 49 | ```java 50 | marko.setAge(31) 51 | assert marko.getName().equals("marko") 52 | for(Person person : marko.getKnowsPeople()) { 53 | System.out.println(person.getName()); // prints vadas and josh 54 | } 55 | ``` 56 | 57 | h2. Adding a Few More Constructs 58 | 59 | In the example graph, there are people and there are projects. Lets model a project as a Java interface. 60 | 61 | ```java 62 | public interface Project extends VertexFrame { 63 | @Property("name") 64 | public void setName(String name); 65 | @Property("name") 66 | public String getName(); 67 | @Property("lang") 68 | public void setLanguage(String language); 69 | @Property("lang") 70 | public int getLanguage(); 71 | 72 | @Adjacency(label="created", direction=Direction.IN) 73 | public Iterable getCreatedByPerson(); 74 | 75 | @Incidence(label = "created", direction = Direction.IN) 76 | public Iterable getCreatedInfo(); 77 | } 78 | 79 | public interface CreatedInfo extends EdgeFrame { 80 | @Property("weight") 81 | public Float getWeight(); 82 | @Property("weight") 83 | public void setWeight(float weight); 84 | 85 | @OutVertex 86 | Person getPerson(); 87 | 88 | @InVertex 89 | Project getProject(); 90 | } 91 | ``` 92 | 93 | There are a few things that are worth exemplifying. First, while the property of the project vertex may have the key @lang@, the method to get and set the property value can be anything. The @@Property@ annotation makes it clear what the explicit property key is. Second, note that there is a difference between a *Adjacency* and an *Incidence*. An adjacency exists between two vertices. An incidence exists between a vertex and edge. An incidence is an @EdgeFrame@ and thus, a wrapper to an edge. The frame class for the edge (@CreatedInfo@) has annotations to mark what the out-vertex (@@OutVertex@) and in-vertex (@@InVertex@) of the edge frame represent. 94 | 95 | Finally, notice that @Project@ extends the special, @VertexFrame@ interface. While it is not necessary to extend @VertexFrame@ in order to create and manipulate Frames objects, doing so provides access to the @asVertex@ method which takes you from a frame to the underlying Blueprints vertex. The @EdgeFrame@ interface provides a similar method, @asEdge@. 96 | 97 | ```java 98 | Project ripple = manager.frame(graph.getVertex(5), Project.class); 99 | System.out.println(ripple.getCreatedByPerson().iterator().next().getName()); // prints "josh" 100 | 101 | System.out.println(ripple.asVertex().getId()); // prints "5" 102 | ``` 103 | 104 | The full code for this simple domain is provided in the Frames test case available "here":https://github.com/tinkerpop/frames/tree/master/src/test/java/com/tinkerpop/frames/domain. 105 | There is more to Frames, but what has been presented are the basic constructs to help get you started. -------------------------------------------------------------------------------- /doc/Gremlin-Groovy.textile: -------------------------------------------------------------------------------- 1 | [[https://raw.github.com/tinkerpop/frames/master/doc/images/gremlin-in-frames.png|align=left]] 2 | 3 | "Gremlin":http://gremlin.tinkerpop.com is the graph traversal language of the TinkerPop stack and provides a concise syntax for traversing a "Blueprints":http://blueprints.tinkerpop.com graph data structure. Frames leverages Gremlin via annotations in order to allow methods to do more complex computations/traversals than direct incidences and adjacencies as seen with the core Frames annotations. 4 | 5 | h2. Frame Adjacencies 6 | 7 | It is possible to make use of a Gremlin path expression as a means of determining vertex adjacency via the @GremlinGroovyModule@. 8 | 9 | |_. annotation |_. method prefix |_. arguments |_. description |_. example | 10 | | @@GremlinGroovy@ | @get@ | @value@ | get and frame the vertices at then end of the expression | @@GremlinGroovy("it.out('knows')")@ | 11 | | @@GremlinGroovy@ | @get@, @can@, @is@ | @value@, @frame=false@ | return the objects at then end of the expression | @@GremlinGroovy(value="it.out('knows').name", frame=false)@ | 12 | 13 | ```java 14 | public interface Person { 15 | @GremlinGroovy("it.as('x').out('created').in('created').except('x')") 16 | public Iterable getCoCreators(); 17 | } 18 | ``` 19 | 20 | In the example above, the vertices at the end of the path expression are framed as @Person@ classes. 21 | 22 | ```java 23 | FramedGraphFactory factory = new FramedGraphFactory(new GremlinGroovyModule()); //Use the gremlin groovy module 24 | FramedGraph framedGraph = factory.create(graph); 25 | 26 | Person marko = framedGraph.frame(graph.getVertex(1), Person.class); 27 | for (Person coCreator : marko.getCoCreators()) { 28 | System.out.println(coCreator.getName()); 29 | } 30 | // josh 31 | // peter 32 | ``` 33 | 34 | When constructing your @FramedGraphFactory@ ensure you include the @GremlinGroovyModule@. 35 | 36 | You can also pass parameters to the gremlin expression by using @@GremlinParam@ to specify the name of the parameter. 37 | 38 | ```java 39 | public interface Person { 40 | @GremlinGroovy("it.as('x').out('created').in('created').except('x').has('age',age)") 41 | public Iterable getCoCreatorsOfAge(@GremlinParam("age") int age); 42 | } 43 | ``` 44 | 45 | In this example the paramater named 'age' is passed to the script. 46 | 47 | ```java 48 | Person josh = marko.getCoCreatorsOfAge(32).iterator().next(); 49 | ``` 50 | 51 | h2. Arbitrary Java objects 52 | 53 | If the resultant object return type is not a Frame, then @frame=false@ should be used in the @@GremlinGroovy@ annotation. 54 | 55 | ```java 56 | @GremlinGroovy(value="'1+2'", frame=false) 57 | public Integer getASumOfTwoNumbers(); 58 | ``` -------------------------------------------------------------------------------- /doc/Home.textile: -------------------------------------------------------------------------------- 1 | [[https://github.com/tinkerpop/frames/raw/master/doc/images/frames-logo.png|height=143px]] 2 | 3 | Frames exposes any "Blueprints":http://blueprints.tinkerpop.com graph as a collection of interrelated domain objects. Frames makes heavy use of @InvocationHandler@, @Proxy@ classes, and @Annotations@ to allow a developer to _frame_ a graph element (vertex or edge) in terms of a particular Java interface. With Frames, its easy to ensure that data within a graph is respective of a schema represented as a collection of annotated Java interfaces. 4 | 5 | Please join the Gremlin users group at "http://groups.google.com/group/gremlin-users":http://groups.google.com/group/gremlin-users for all "TinkerPop":http://tinkerpop.com related discussions. 6 | 7 | Frames JavaDoc: "2.5.0":http://tinkerpop.com/docs/javadocs/frames/2.5.0/ - "2.4.0":http://tinkerpop.com/docs/javadocs/frames/2.4.0/ - "2.3.1":http://tinkerpop.com/docs/javadocs/frames/2.3.0/ - "2.3.0":http://tinkerpop.com/docs/javadocs/frames/2.3.0/ - "2.2.0":http://tinkerpop.com/docs/javadocs/frames/2.2.0/ - "2.1.0":http://tinkerpop.com/docs/javadocs/frames/2.1.0/ - "2.0.0":http://tinkerpop.com/docs/javadocs/frames/2.0.0/ - "0.7":http://tinkerpop.com/maven2/com/tinkerpop/frames/0.7/api/ - "0.6":http://tinkerpop.com/maven2/com/tinkerpop/frames/0.6/api/ - "0.5":http://tinkerpop.com/maven2/com/tinkerpop/frames/0.5/api/ - "0.4":http://tinkerpop.com/maven2/com/tinkerpop/frames/0.4/api/ - "0.3":http://tinkerpop.com/maven2/com/tinkerpop/frames/0.3/api/ - "0.2":http://tinkerpop.com/maven2/com/tinkerpop/frames/0.2/api/ - "0.1":http://tinkerpop.com/maven2/com/tinkerpop/frames/0.1/api/ 8 | Frames WikiDoc: "2.5.0":http://www.tinkerpop.com/docs/wikidocs/frames/2.5.0/Home.html - "2.4.0":http://www.tinkerpop.com/docs/wikidocs/frames/2.4.0/Home.html - "2.3.1":http://www.tinkerpop.com/docs/wikidocs/frames/2.3.0/Home.html - "2.3.0":http://www.tinkerpop.com/docs/wikidocs/frames/2.3.0/Home.html - "2.2.0":http://www.tinkerpop.com/docs/wikidocs/frames/2.2.0/Home.html - "2.1.0":http://www.tinkerpop.com/docs/wikidocs/frames/2.1.0/Home.html - "2.0.0":http://www.tinkerpop.com/docs/wikidocs/frames/2.0.0/Home.html 9 | 10 | ```xml 11 | 12 | com.tinkerpop 13 | frames 14 | 2.5.0 15 | 16 | ``` 17 | 18 | Non-Maven users can get the raw release jars from Apache's "Central Repository":http://maven.org. Snapshots can be obtained from "Sonatype":https://oss.sonatype.org/content/repositories/snapshots/ (see "Maven Repositories":https://github.com/tinkerpop/homepage/wiki/Maven-Repositories for more information). 19 | 20 | Here is an example Frame interface: 21 | ```java 22 | public interface Person { 23 | @Property("name") 24 | public String getName(); 25 | 26 | @Adjacency(label="knows") 27 | public Iterable getKnowsPeople(); 28 | 29 | @Adjacency(label="knows") 30 | public void addKnowsPerson(final Person person); 31 | 32 | @GremlinGroovy("it.out('knows').out('knows').dedup") //Make sure you use the GremlinGroovy module! #1 33 | public Iterable getFriendsOfAFriend() 34 | } 35 | ``` 36 | 37 | Now you can use it to interact with the graph: 38 | ```java 39 | TinkerGraph graph = TinkerGraphFactory.createTinkerGraph(); //This graph is pre-populated. 40 | FramedGraphFactory factory = new FramedGraphFactory(new GremlinGroovyModule()); //(1) Factories should be reused for performance and memory conservation. 41 | 42 | FramedGraph framedGraph = factory.create(graph); //Frame the graph. 43 | 44 | Person person = framedGraph.getVertex(1, Person.class); 45 | person.getName(); // equals "marko" 46 | ``` 47 | Frames can be used with "Rexster":http://rexster.tinkerpop.com through the "Rexster Kibbles":https://github.com/tinkerpop/rexster/wiki/Rexster-Kibbles Frames extension. 48 | 49 | ==
== 50 | 51 | * [[Introduction]] 52 | ** [[Getting Started]] 53 | ** [[Creating Frames]] 54 | ** [[Core Annotations]] (*Cheat Sheet*) 55 | ** [[Factories and Modules]] 56 | ** [[Frames Ecosystem]] 57 | ** [[Upgrading from 2.3.1]] 58 | * Core Modules 59 | ** [[Gremlin Groovy]] 60 | ** [[Typed Graph]] 61 | ** [[Java Handler]] 62 | * [[Custom Modules]] 63 | *** [[Method Handlers]] 64 | *** [[Frame Initializers]] 65 | *** [[Type Resolvers]] 66 | * Conclusion 67 | ** [[Acknowledgments]] 68 | ** [[Release Notes]] -------------------------------------------------------------------------------- /doc/Introduction.textile: -------------------------------------------------------------------------------- 1 | [[http://markorodriguez.files.wordpress.com/2011/01/graph-example1.png|width=150px|align=left|float]] 2 | 3 | A "graph database":http://en.wikipedia.org/wiki/Graph_database represents a collection of vertices (nodes, dots) connected to each other by edges (arcs, lines). Some graph database vendors provide data schema functionality. In such databases, vertices and edges are typed and there are notions of data restrictions--e.g. subclassing, data validation, rules of inference, etc. Other graph database are "schema-free" in that there is no notion of a type system--only vertices, edges, and their adjacencies. When modeling worldly objects (people, places, things) and their relationships to each other, schema-based graph databases are handy. When modeling graphical data structures such as arbitrary topologies, a schema is somewhat less important. In general, as the complexity of the the domain model increases, the need for a schema system increases. 4 | 5 | The purpose of Frames it to provide a data schema layer to "Blueprints":http://blueprints.tinkerpop.com enabled graph databases. With Blueprints, there are simply vertices, edges, and key/value properties. Frames is used to represent (or _frame_) aspects of the underlying graph in terms of domain objects and their relationships to one another. As such, the developer can work in terms of real-world objects instead of vertices and edges. -------------------------------------------------------------------------------- /doc/Java-Handler.textile: -------------------------------------------------------------------------------- 1 | You can use Java to handle your frames methods. This is useful you want to embed some logic in your model. 2 | 3 | h2. Usage 4 | 5 | To use @@JavaHandler@ you must include the module when creating the graph factory: 6 | ```java 7 | FramedGraph framedGraph = new FramedGraphFactory(new JavaHandlerModule()).create(graph); 8 | ``` 9 | 10 | Here we demonstrate how the @getCoCreators@ using the @@GremlinGroovy@ annotation can be emulated using @@JavaHandler@ and also a generic method that uses other methods on the frame. 11 | 12 | ```java 13 | public interface Person { 14 | 15 | @Property("name") 16 | public String getName(); 17 | 18 | @Property("age") 19 | public Integer getAge(); 20 | 21 | @GremlinGroovy("it.as('x').out('created').in('created').except('x')") 22 | public Iterable getCoCreators(); 23 | 24 | @JavaHandler 25 | public Iterable getCoCreatorsJava(); 26 | 27 | @JavaHandler 28 | public String getNameAndAge(); 29 | 30 | } 31 | ``` 32 | Create a nested abstract class in your frame called 'Impl'. 33 | Note that this class must implement the original interface and may optionally implement @JavaHandlerContext@ with either Vertex or Edge as a parameter. 34 | 35 | ```java 36 | public interface Person { 37 | 38 | //Interface methods excluded for brevity. 39 | 40 | public abstract class Impl implements JavaHandlerContext, Person { 41 | 42 | public Iterable getCoCreatorsJava() { 43 | return frameVertices(gremlin().as("x").out("created").in("created").except("x")); 44 | } 45 | 46 | public String getNameAndAge() { 47 | return getName() + " (" + getAge() + ")"; //Call other methods that are handled by other annotations. 48 | } 49 | } 50 | } 51 | ``` 52 | 53 | h3. Interacting with the underlying element. 54 | 55 | By implementing @JavaHandlerContext@ your implementation has access to the following: 56 | ```java 57 | FramedGraph g(); //The graph 58 | C it(); //The element being framed 59 | GremlinPipeline gremlin(); //Start a gremlin pipeline from the framed element 60 | GremlinPipeline gremlin(Object starts); //Start a gremlin pipeline from an element 61 | //... Also all the framing methods available on FramedGraph. 62 | ``` 63 | 64 | h3. Frame initialization. 65 | 66 | To perform initialization on the frame annotate a no-args method with @@Initializer@. It will be called when a frame is created via the @FramedGraph.addVertex@ or @FramedGraph.addEdge@. 67 | 68 | ```java 69 | public interface Person { 70 | 71 | //Interface methods excluded for brevity. 72 | 73 | public abstract class Impl implements JavaHandlerContext, Person { 74 | 75 | @Initializer 76 | public void init() { 77 | //This will be called when a new framed element is added to the graph. 78 | setAge(23);//Set the default age 79 | } 80 | } 81 | } 82 | ``` 83 | 84 | 85 | h2. Specifying an alternative implementation class 86 | 87 | You can specify an alternative class for your @JavaHandler@ implementation using the @@JavaHandlerClass@ annotation. 88 | ``` 89 | @JavaHandlerClass(MyPersonImpl.class) 90 | public interface Person { 91 | 92 | } 93 | ``` 94 | In this case @MyPersonImpl@ will be used in preference to the nested Impl class. 95 | 96 | h2. Custom handler factory 97 | 98 | If you would rather be in control of the creating the handlers for your methods then you can specify a factory on the module. 99 | 100 | ```java 101 | JavaHandlerFactory handlerFactory = new JavaHandlerFactory() {...}; 102 | FramedGraphFactory factory = new FramedGraphFactory(new JavaHandlerModule().withFactory(handlerFactory)) 103 | FramedGraph framedGraph = factory.create(graph); 104 | ``` -------------------------------------------------------------------------------- /doc/Method-Handlers.textile: -------------------------------------------------------------------------------- 1 | [[https://github.com/tinkerpop/frames/raw/master/doc/images/frames-character-3.png|width=135px]] 2 | 3 | *Note: The @MethodHandler@ interface supercedes the @AnnotationHandler@ interface from Frames 2.3.1* 4 | 5 | It is possible to create new annotations, behaviors for those annotations, and then register them with a @Module@. In order to make use of this feature, two Java classes are required of the developer. 6 | 7 | # @Annotation@: An annotation object. 8 | # @MethodHandler@: A class defining the behavior to evaluate when the respective @Annotation@ is used. 9 | 10 | The @MethodHandler@ interface is provided below. 11 | 12 | ```java 13 | public interface MethodHandler { 14 | public Class getAnnotationType(); 15 | public Object processElement(final Object frame, final Method method, final Object[] arguments, final T annotation, final FramedGraph framedGraph, final Element element); 16 | } 17 | ``` 18 | 19 | Any implementation of an @MethodHandler@ must implement the respective methods where @getAnnotationType()@ returns the class of the respective @Annotation@ it represents. The @processElement@ method has arguments that provide information to allow the developer to determine the requisite logic to execute. For example, here are some aspects to reason on: 20 | 21 | * Determine if the method is a _get_, _set_, or _remove_ by @method.getName().startsWith("get")@ 22 | * Make use of @ClassUtilities@ for standard, static reasoning methods. 23 | * Analyze the types of method's provided arguments. 24 | * Analyze the type of the methods return object. 25 | * All framed elements implement @VertexFrame@ or @EdgeFrame@ even if the framing interface doesn't extend these. Use these interfaces to get access to the underlying element. 26 | 27 | All the @Annotation@ objects provided by Frames make use of handlers. Please feel free to inspect the source code to get ideas for how to implement your own handlers. Finally, once an @Annotation@ and @MethodHandler@ have been created, they can be registered with a @Module@. 28 | 29 | ```java 30 | FramedGraph g = new FramedGraphFactory(new AbstractModule() { 31 | public void doConfigure(FramedGraphConfiguration config) { 32 | config.addMethodHandler(new MyHandler()); 33 | } 34 | }).create(baseGraph); 35 | ``` -------------------------------------------------------------------------------- /doc/Type-resolvers.textile: -------------------------------------------------------------------------------- 1 | The @TypeResolver@ interface allows you to add interfaces that a framed element will implement. These are in addition to the interface that was passed in to the framing method, and EdgeFrame or VertexFrame. 2 | 3 | ```java 4 | public interface TypeResolver { 5 | 6 | /** 7 | * @param v The vertex being framed. 8 | * @param defaultType The default as passed in to the framing method. 9 | * @return Any additional interfaces that the frame should implement. 10 | */ 11 | Class[] resolveTypes(Vertex v, Class defaultType); 12 | /** 13 | * @param e The edge being framed. 14 | * @param defaultType The default as passed in to the framing method. 15 | * @return Any additional interfaces that the frame should implement. 16 | */ 17 | Class[] resolveTypes(Edge e, Class defaultType); 18 | } 19 | ``` 20 | 21 | To use the type resolver, register it via a module supplied to the @FramedGraphFactory@. 22 | ```java 23 | TypeResolver myTypeResolver = new TypeResolver() { 24 | public Class[] resolveTypes(Edge e, Class defaultType) { 25 | return new Class[] { AdditionalEdge.class }; //Add the AdditionalEdge interface 26 | } 27 | 28 | public Class[] resolveTypes(Vertex v, Class defaultType) { 29 | return new Class[] { AdditionalVertex.class }; //Add the AdditionalVertex interface 30 | } 31 | }; 32 | 33 | FramedGraph g = new FramedGraphFactory(new AbstractModule() { 34 | public void doConfigure(FramedGraphConfiguration config) { 35 | config.addTypeResolver(myTypeResolver); 36 | } 37 | }).create(baseGraph); 38 | 39 | 40 | Person p = g.addVertex(Person.class); //p is also an instance of AdditionalVertex 41 | AdditionalVertex av = (AdditionalVertex) p; 42 | ``` 43 | Every registered @TypeResolver@ is called before returning the new element. 44 | 45 | Some possible use cases 46 | * You want to use information stored on the graph to create elements of different types. -------------------------------------------------------------------------------- /doc/Typed-Graph.textile: -------------------------------------------------------------------------------- 1 | Frames can also be configured to store type-information in properties, and to use that information runtime when instantiating objects. For example, consider an object model for relating persons to the pets they own: 2 | 3 | ```java 4 | interface Person extends VertexFrame { 5 | @Adjacency(label = "pet") Iterable getPets(); 6 | @Adjacency(label = "pet") void addPet(Animal animal); 7 | } 8 | 9 | interface Animal extends VertexFrame { 10 | } 11 | 12 | interface Fish extends Animal { 13 | } 14 | ``` 15 | 16 | h2. The Problem 17 | 18 | Without any extra information Frames isn't aware of the actual types of Animal objects. If you call @person.getPets()@, all returned objects are Animal-instances. It's not possible to instantiate them as Fish, or Dog, or other sub-classes of Animal, based on runtime information. Likewise, when you call @person.addPet(aFish)@, the fact that this particular pet is actually a Fish will be lost. 19 | 20 | h2. Frames can Store and Use Type Data 21 | 22 | Since Frames 2.4.0 Frames has support for instantiating polymorphic types, to tackle the above problem, and make runtime decisions about what interfaces to proxy. This is done by telling Frames what the name of each type is, and in which property field that name should be stored: 23 | # The root of your class hierarchy (in this case the Animal interface), should be annotated with a @TypeField@ annotation. That annotation contains the property-key in which type information is stored. 24 | # Each concrete (instantiatable) sub-type should be annotated with a @TypeValue@ annotation. That annotation holds the property value that is stored in the property with the key from @TypeField@. 25 | # A @TypedGraphModuleBuilder@ can be used to make Frames aware of these annotations. 26 | 27 | This may lead to the following interface definitions for our Person -> Pet graph: 28 | 29 | ```java 30 | interface Person extends VertexFrame { 31 | @Adjacency(label = "pet") Iterable getPets(); 32 | @Adjacency(label = "pet") void addPet(Animal animal); 33 | } 34 | 35 | @TypeField("type") interface Animal extends VertexFrame { 36 | } 37 | 38 | interface Mammal extends Animal {} 39 | 40 | @TypeValue("dog") interface Dog extends Mammal {} 41 | 42 | @TypeValue("shepherd") interface Shepherd extends Dog {} 43 | 44 | @TypeValue("cat") interface Cat extends Mammal {} 45 | 46 | @TypeValue("fish") interface Fish extends Animal {} 47 | ``` 48 | 49 | Please note that only Animal has a @TypeField@ annotation, because it is the root of our hierarchy. You are not allowed to change the property-key used for storing type information in subtypes of Animal. Also note that both Animal and Mammal don't have @TypeValue@ annotations. This is because pets are typically subtypes of Animal/Mammal, e.g. a Cat, or a Fish. It is not forbidden to have a @TypeValue@ annotation on the same interface that holds the @TypeField@ annotation. It just doesn't make sense in this particular example. Please also note that it's perfectly valid to have TypeValue annotations on subtypes of interfaces that already have a @TypeValue@ annotation, like the Shepherd above, which is a specific type of Dog. 50 | 51 | With these extra annotations, Frames is now able to automatically add a @type=fish@ property when storing a vertex that represents a Fish, or @type=dog@ for a Dog. Additionally, Frames may return sub-types of Animal, using the actual property value for @type@. Thus @person.getPets()@ now returns Dogs, Fishes, etc. 52 | 53 | h2. Using TypedGraphModuleBuilder 54 | 55 | For Frames to actually use the @TypeField@ and @TypeValue@ annotations, a FramedGraph has to know about the interfaces annotated with @TypeValue@. Since there is no efficient way in Java to get all interfaces that have a specific annotation, your code should tell a FramedGraph where to find those interfaces. For the animal hierarchy in the previous example this may be done as follows: 56 | 57 | ```java 58 | static final FramedGraphFactory FACTORY = new FramedGraphFactory( 59 | new TypedGraphModuleBuilder() 60 | .withClass(Fish.class) 61 | .withClass(Cat.class) 62 | .withClass(Dog.class) 63 | .withClass(Shepherd.class) 64 | .build() 65 | ); 66 | ``` 67 | 68 | Please note that only the interfaces with @TypeValue@ annotations are given. Frames will detect the @TypeField@ by itself. The @FACTORY@ created this way is reusable and thread-safe once fully initialized. It can be used to create FramedGraphs as follows: 69 | 70 | ```java 71 | FramedGraph framedGraph = FACTORY.create(graph); 72 | ``` 73 | 74 | h2. FAQ for Polymorphic Types 75 | 76 | *What happens when I frame an element that doesn't have a value for the property defined in TypeField?* 77 | 78 | Frames will just instantiate the compile time supplied interface (i.e. Animal in the previous examples). 79 | 80 | *What happens when I frame an element that has an unknown value for the property defined in TypeValue (thus a corresponding TypeValue is missing or not registered)?* 81 | 82 | Frames will ignore the value, hence will instantiate the compile time supplied interface (i.e. Animal in the previous examples). 83 | 84 | *What happens when I create a Frame for an interface that has a @TypeField@ in the hierarchy, but no (registered) @TypeValue@ annotation?* 85 | 86 | No type information will be stored. Thus if you later frame that element, it will be framed as an instance of the compile time supplied interface. -------------------------------------------------------------------------------- /doc/Upgrading-from-2.3.1.textile: -------------------------------------------------------------------------------- 1 | Frames 2.4.0 is fully backward compatible with 2.3.1 so you won't need to make any code changes if you upgrade. 2 | 3 | However there have been some significant additions to the APIs to enable some new features and pave the way for more features in the future. 4 | 5 | To this end you will find that some classes and method in Frames have been deprecated. However, these won't be removed until at least the next major version of Tinkerpop. 6 | 7 | For most frames users there will only be minor modifications to make to migrate to the new APIs, but for now this is completely optional. 8 | 9 | h3. Creating a FramedGraph 10 | 11 | The recommended way of creating a @FramedGraph@ is now via @FramedGraphFactory@ rather than via the @FramedGraph@ constructor. 12 | 13 | ```java 14 | FramedGraphFactory factory = new FramedGraphFactory(); 15 | FramedGraph framedGraph = factory.create(baseGraph); 16 | ``` 17 | 18 | This has a couple of benefits: 19 | * Resources can be shared between graphs. 20 | * Complex configuration of the @FramedGraph@ can be pushed out to separate @Module@ classes with their own APIs. 21 | 22 | You should ideally use the same framed graph factory to create many framed graphs. 23 | *Note: That the gremlin groovy module is not included by default, this is to prevent having to start up a Groovy script engine if your application doesn't require it. If you require @@GremlinGroovy@ support make sure you are using the @GremlinGroovyModule@.* 24 | 25 | h3. Extending FramedGraph functionality. 26 | 27 | Modules are now used to encapsulate the extensions of @FramedGraph@. This brings together MethodHandlers(was AnnotationHandlers), TypeResolvers and FrameInitializers in to single units of configuration. 28 | 29 | @FramedGraphFactory@ may be constructed with any number of modules which will all be applied to every @FramedGraph@ created. 30 | 31 | ```java 32 | FramedGraphFactory factory = new FramedGraphFactory( 33 | new GremlinGroovyModule(), 34 | new TypedGraphModuleBuilder().withClass(A.class).build()); 35 | FramedGraph framedGraph = factory.create(baseGraph); //Groovy and typed graph created. 36 | ``` 37 | 38 | The advantage of this is that each module may internally register any number of @MethodHandler@, @TypeResolver@ and @FrameInitializer@ leaving the you to concentrate on the high level feature you are adding to your FramedGraphs. 39 | 40 | h3. Use @@InVertex@ or @@OutVertex@ instead of @@Domain@ and @@Range@ 41 | 42 | Framed edges have currently got additional internal state over and above the edge they are framing. This is the direction that the frame was created with. This direction is used to flip the meaning of @@Domain@ and @@Range@. 43 | 44 | In frames 2.4.0 two new annotations have been introduced that follow the Blueprints edge API more closely: 45 | * Edge.getVertex(Direction.Out) = @OutVertex 46 | * Edge.getVertex(Direction.In) = @InVertex 47 | 48 | These statements will always be true regardless of the direction that the edge was created with. 49 | 50 | Please note that @@Domain@ and @@Range@ do not map directly to either @@InVertex@ or @@OutVertex@ 51 | 52 | @@Domain@ and @@Range@ have been deprecated. 53 | 54 | h3. Deprecation of FramedGraph.createEdge(edge, direction) 55 | 56 | @@InVertex@ and @@OutVertex@ do not require the additional direction state on framed edges. 57 | Therefore if you have migrated all your @@Domain@ and @@Range@ annotations to @@InVertex@ and @@OutVertex@ you can safely use FramedGraph.createEdge(edge) to create your edges without specifying the direction. 58 | 59 | h3. Use @MethodHandler@ instead of @AnnotationHandler@ 60 | 61 | To support the new JavaHandler module and a future validation module @AnnotationHandler@ has been deprecated in favour of @MethodHandler@. 62 | The new @MethodHandler@ interface is almost identical to @AnnotationHandler@ with the exception of also receiving the frame object and not receiving the Direction parameter. 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /doc/images/frames-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkerpop/frames/5465d476369bf9d431f47b1af01f70b70914b268/doc/images/frames-2.png -------------------------------------------------------------------------------- /doc/images/frames-beams.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkerpop/frames/5465d476369bf9d431f47b1af01f70b70914b268/doc/images/frames-beams.png -------------------------------------------------------------------------------- /doc/images/frames-bracket.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkerpop/frames/5465d476369bf9d431f47b1af01f70b70914b268/doc/images/frames-bracket.png -------------------------------------------------------------------------------- /doc/images/frames-brick-by-brick.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkerpop/frames/5465d476369bf9d431f47b1af01f70b70914b268/doc/images/frames-brick-by-brick.png -------------------------------------------------------------------------------- /doc/images/frames-character-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkerpop/frames/5465d476369bf9d431f47b1af01f70b70914b268/doc/images/frames-character-1.png -------------------------------------------------------------------------------- /doc/images/frames-character-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkerpop/frames/5465d476369bf9d431f47b1af01f70b70914b268/doc/images/frames-character-2.png -------------------------------------------------------------------------------- /doc/images/frames-character-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkerpop/frames/5465d476369bf9d431f47b1af01f70b70914b268/doc/images/frames-character-3.png -------------------------------------------------------------------------------- /doc/images/frames-huff-and-puff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkerpop/frames/5465d476369bf9d431f47b1af01f70b70914b268/doc/images/frames-huff-and-puff.png -------------------------------------------------------------------------------- /doc/images/frames-logo.graffle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkerpop/frames/5465d476369bf9d431f47b1af01f70b70914b268/doc/images/frames-logo.graffle -------------------------------------------------------------------------------- /doc/images/frames-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkerpop/frames/5465d476369bf9d431f47b1af01f70b70914b268/doc/images/frames-logo.png -------------------------------------------------------------------------------- /doc/images/frames-lumber.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkerpop/frames/5465d476369bf9d431f47b1af01f70b70914b268/doc/images/frames-lumber.png -------------------------------------------------------------------------------- /doc/images/frames-studs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkerpop/frames/5465d476369bf9d431f47b1af01f70b70914b268/doc/images/frames-studs.png -------------------------------------------------------------------------------- /doc/images/frames-truss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkerpop/frames/5465d476369bf9d431f47b1af01f70b70914b268/doc/images/frames-truss.png -------------------------------------------------------------------------------- /doc/images/gremlin-in-frames.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkerpop/frames/5465d476369bf9d431f47b1af01f70b70914b268/doc/images/gremlin-in-frames.png -------------------------------------------------------------------------------- /src/assembly/distribution.xml: -------------------------------------------------------------------------------- 1 | 2 | distribution 3 | 4 | zip 5 | 6 | 7 | 8 | 9 | pom.xml 10 | 11 | 12 | 13 | src 14 | 15 | 16 | target/apidocs 17 | 18 | 19 | target/site 20 | 21 | 22 | target 23 | 24 | frames-*.jar 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/assembly/standalone.xml: -------------------------------------------------------------------------------- 1 | 2 | standalone 3 | 4 | jar 5 | 6 | false 7 | 8 | 9 | 10 | target/classes 11 | / 12 | 13 | 14 | 15 | 16 | 17 | / 18 | true 19 | runtime 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/Adjacency.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames; 2 | 3 | import com.tinkerpop.blueprints.Direction; 4 | 5 | import java.lang.annotation.ElementType; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.RetentionPolicy; 8 | import java.lang.annotation.Target; 9 | 10 | /** 11 | * Adjacencies annotate getters and adders to represent a Vertex adjacent to a Vertex. 12 | * 13 | * @author Marko A. Rodriguez (http://markorodriguez.com) 14 | */ 15 | @Retention(RetentionPolicy.RUNTIME) 16 | @Target(ElementType.METHOD) 17 | public @interface Adjacency { 18 | /** 19 | * The label of the edges making the adjacency between the vertices. 20 | * 21 | * @return the edge label 22 | */ 23 | public String label(); 24 | 25 | /** 26 | * The edge direction of the adjacency. 27 | * 28 | * @return the direction of the edges composing the adjacency 29 | */ 30 | public Direction direction() default Direction.OUT; 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/ClassUtilities.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames; 2 | 3 | import com.tinkerpop.blueprints.Vertex; 4 | 5 | import java.lang.reflect.*; 6 | import java.util.Map; 7 | 8 | 9 | public class ClassUtilities { 10 | private static final String SET = "set"; 11 | private static final String GET = "get"; 12 | private static final String REMOVE = "remove"; 13 | private static final String ADD = "add"; 14 | private static final String IS = "is"; 15 | private static final String CAN = "can"; 16 | 17 | public static boolean isGetMethod(final Method method) { 18 | Class returnType = method.getReturnType(); 19 | return (method.getName().startsWith(GET) || (returnType == Boolean.class || returnType == Boolean.TYPE) && (method.getName().startsWith(IS) || method.getName().startsWith(CAN))); 20 | } 21 | 22 | public static boolean isSetMethod(final Method method) { 23 | return method.getName().startsWith(SET); 24 | } 25 | 26 | public static boolean isRemoveMethod(final Method method) { 27 | return method.getName().startsWith(REMOVE); 28 | } 29 | 30 | public static boolean acceptsIterable(final Method method) { 31 | return 1 == method.getParameterTypes().length && Iterable.class.isAssignableFrom(method.getParameterTypes()[0]); 32 | } 33 | 34 | public static boolean returnsIterable(final Method method) { 35 | return Iterable.class.isAssignableFrom(method.getReturnType()); 36 | } 37 | 38 | public static boolean returnsVertex(final Method method) { 39 | return Vertex.class.isAssignableFrom(method.getReturnType()); 40 | } 41 | 42 | public static boolean returnsMap(final Method method) { 43 | return Map.class.isAssignableFrom(method.getReturnType()); 44 | } 45 | 46 | public static boolean isAddMethod(final Method method) { 47 | return method.getName().startsWith(ADD); 48 | } 49 | 50 | public static Type getType(Type[] types, int pos) { 51 | if (pos >= types.length) { 52 | throw new RuntimeException("No type can be found at position " 53 | + pos); 54 | } 55 | return types[pos]; 56 | } 57 | public static Class getActualType(Type genericType, int pos) { 58 | 59 | if (genericType == null) { 60 | return null; 61 | } 62 | if (!ParameterizedType.class.isAssignableFrom(genericType.getClass())) { 63 | if (genericType instanceof TypeVariable) { 64 | genericType = getType(((TypeVariable) genericType).getBounds(), pos); 65 | } else if (genericType instanceof WildcardType) { 66 | WildcardType wildcardType = (WildcardType) genericType; 67 | Type[] bounds = wildcardType.getLowerBounds(); 68 | if (bounds.length == 0) { 69 | bounds = wildcardType.getUpperBounds(); 70 | } 71 | genericType = getType(bounds, pos); 72 | } 73 | 74 | Class cls = (Class) genericType; 75 | return cls.isArray() ? cls.getComponentType() : cls; 76 | } 77 | ParameterizedType paramType = (ParameterizedType) genericType; 78 | Type t = getType(paramType.getActualTypeArguments(), pos); 79 | return t instanceof Class ? (Class) t : getActualType(t, pos); 80 | } 81 | 82 | @SuppressWarnings("rawtypes") 83 | public static Class getGenericClass(final Method method) { 84 | final Type returnType = method.getGenericReturnType(); 85 | return getActualType(returnType,0); 86 | 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/Domain.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * The source of the adjacency. 10 | * 11 | * @author Marko A. Rodriguez (http://markorodriguez.com) 12 | * 13 | * @deprecated Use {@link InVertex} or {@link OutVertex} instead. 14 | */ 15 | @Retention(RetentionPolicy.RUNTIME) 16 | @Target(ElementType.METHOD) 17 | public @interface Domain { 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/EdgeFrame.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames; 2 | 3 | import com.tinkerpop.blueprints.Edge; 4 | 5 | /** 6 | * An interface for Edge-based frames which provides access to the underlying Edge. 7 | * 8 | * @author Joshua Shinavier (http://fortytwo.net) 9 | */ 10 | public interface EdgeFrame { 11 | Edge asEdge(); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/FrameInitializer.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames; 2 | 3 | import com.tinkerpop.blueprints.Element; 4 | 5 | /** 6 | * Allows new framed vertices and edges to be initialized before they are returned to the user. This can be used for defaulting of properties. 7 | * Instances of this class should be threadsafe. 8 | * 9 | * @author Bryn Cooke 10 | */ 11 | public interface FrameInitializer { 12 | /** 13 | * @param kind The kind of frame. 14 | * @param framedGraph The graph. 15 | * @param element The new element that is being inserted into the graph. 16 | */ 17 | public void initElement(final Class kind, final FramedGraph framedGraph, final Element element); 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/FramedElement.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames; 2 | 3 | import com.tinkerpop.blueprints.Direction; 4 | import com.tinkerpop.blueprints.Element; 5 | import com.tinkerpop.blueprints.util.ElementHelper; 6 | import com.tinkerpop.frames.annotations.AnnotationHandler; 7 | import com.tinkerpop.frames.modules.MethodHandler; 8 | 9 | import java.lang.annotation.Annotation; 10 | import java.lang.reflect.InvocationHandler; 11 | import java.lang.reflect.Method; 12 | import java.lang.reflect.Proxy; 13 | import java.util.Map; 14 | 15 | /** 16 | * The proxy class of a framed element. 17 | * 18 | * @author Marko A. Rodriguez (http://markorodriguez.com) 19 | */ 20 | public class FramedElement implements InvocationHandler { 21 | 22 | private final Direction direction; 23 | protected final FramedGraph framedGraph; 24 | protected final Element element; 25 | private static Method hashCodeMethod; 26 | private static Method equalsMethod; 27 | private static Method toStringMethod; 28 | private static Method asVertexMethod; 29 | private static Method asEdgeMethod; 30 | 31 | 32 | static { 33 | try { 34 | hashCodeMethod = Object.class.getMethod("hashCode"); 35 | equalsMethod = Object.class.getMethod("equals", new Class[]{Object.class}); 36 | toStringMethod = Object.class.getMethod("toString"); 37 | asVertexMethod = VertexFrame.class.getMethod("asVertex"); 38 | asEdgeMethod = EdgeFrame.class.getMethod("asEdge"); 39 | } catch (NoSuchMethodException e) { 40 | throw new NoSuchMethodError(e.getMessage()); 41 | } 42 | } 43 | 44 | /** 45 | * @deprecated The direction field will be dropped in the next major release 46 | */ 47 | public FramedElement(final FramedGraph framedGraph, final Element element, final Direction direction) { 48 | if (null == framedGraph) { 49 | throw new IllegalArgumentException("FramedGraph can not be null"); 50 | } 51 | 52 | if (null == element) { 53 | throw new IllegalArgumentException("Element can not be null"); 54 | } 55 | 56 | this.element = element; 57 | this.framedGraph = framedGraph; 58 | this.direction = direction; 59 | } 60 | 61 | public FramedElement(final FramedGraph framedGraph, final Element element) { 62 | this(framedGraph, element, Direction.OUT); 63 | } 64 | 65 | public Object invoke(final Object proxy, final Method method, final Object[] arguments) { 66 | 67 | if (method.equals(hashCodeMethod)) { 68 | return this.element.hashCode(); 69 | } else if (method.equals(equalsMethod)) { 70 | return this.proxyEquals(arguments[0]); 71 | } else if (method.equals(toStringMethod)) { 72 | return this.element.toString(); 73 | } else if (method.equals(asVertexMethod) || method.equals(asEdgeMethod)) { 74 | return this.element; 75 | } 76 | 77 | final Annotation[] annotations = method.getAnnotations(); 78 | Map, AnnotationHandler> annotationHandlers = this.framedGraph.getConfig().getAnnotationHandlers(); 79 | Map, MethodHandler> methodHandlers = this.framedGraph.getConfig().getMethodHandlers(); 80 | for (final Annotation annotation : annotations) { 81 | MethodHandler methodHandler = methodHandlers.get(annotation.annotationType()); 82 | if (methodHandler != null) { 83 | return methodHandler.processElement(proxy, method, arguments, annotation, this.framedGraph, this.element); 84 | } 85 | } 86 | for (final Annotation annotation : annotations) { 87 | AnnotationHandler annotationHandler = annotationHandlers.get(annotation.annotationType()); 88 | if (annotationHandler != null) { 89 | return annotationHandler.processElement(annotation, method, arguments, this.framedGraph, this.element, this.direction); 90 | } 91 | } 92 | 93 | if(method.getAnnotations().length == 0) { 94 | throw new UnhandledMethodException("The method " + method.getDeclaringClass().getName() + "." + method.getName() + " has no annotations, therefore frames cannot handle the method."); 95 | } 96 | throw new UnhandledMethodException("The method " + method.getDeclaringClass().getName() + "." + method.getName() + " was not annotated with any annotations that the framed graph is configured for. Please check your frame interface and/or graph configuration."); 97 | } 98 | 99 | private Boolean proxyEquals(final Object other) { 100 | if (other instanceof VertexFrame) { 101 | return this.element.equals(((VertexFrame) other).asVertex()); 102 | } if (other instanceof EdgeFrame) { 103 | return this.element.equals(((EdgeFrame) other).asEdge()); 104 | } else if (other instanceof Element) { 105 | return ElementHelper.areEqual(this.element, other); 106 | } else { 107 | return Boolean.FALSE; 108 | } 109 | } 110 | 111 | public Element getElement() { 112 | return this.element; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/FramedGraphConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames; 2 | 3 | import java.lang.annotation.Annotation; 4 | import java.util.ArrayList; 5 | import java.util.HashMap; 6 | import java.util.List; 7 | import java.util.Map; 8 | 9 | import com.tinkerpop.blueprints.Graph; 10 | import com.tinkerpop.frames.annotations.AnnotationHandler; 11 | import com.tinkerpop.frames.modules.DefaultClassLoaderResolver; 12 | import com.tinkerpop.frames.modules.FrameClassLoaderResolver; 13 | import com.tinkerpop.frames.modules.MethodHandler; 14 | import com.tinkerpop.frames.modules.Module; 15 | import com.tinkerpop.frames.modules.TypeResolver; 16 | 17 | /** 18 | * A configuration for a {@link FramedGraph}. These are supplied to 19 | * {@link Module}s for each {@link FramedGraph} being create by a 20 | * {@link FramedGraphFactory}. 21 | * 22 | * Allows registration of {@link AnnotationHandler}s, {@link FrameInitializer}s 23 | * and {@link TypeResolver}s. 24 | * 25 | * @author Bryn Cooke 26 | * 27 | */ 28 | public class FramedGraphConfiguration { 29 | private Map, AnnotationHandler> annotationHandlers = new HashMap, AnnotationHandler>(); 30 | private Map, MethodHandler> methodHandlers = new HashMap, MethodHandler>(); 31 | private List frameInitializers = new ArrayList(); 32 | private List typeResolvers = new ArrayList(); 33 | private FrameClassLoaderResolver frameClassLoaderResolver = new DefaultClassLoaderResolver(); 34 | private Graph configuredGraph; 35 | 36 | 37 | 38 | /** 39 | * @param annotationHandler 40 | * The {@link AnnotationHandler} to add to the 41 | * {@link FramedGraph}. 42 | */ 43 | void addAnnotationHandler(AnnotationHandler annotationHandler) { 44 | annotationHandlers.put(annotationHandler.getAnnotationType(), annotationHandler); 45 | } 46 | 47 | 48 | /** 49 | * @param methodHandler 50 | * The {@link MethodHandler} to add to the 51 | * {@link FramedGraph}. 52 | */ 53 | public void addMethodHandler(MethodHandler methodHandler) { 54 | methodHandlers.put(methodHandler.getAnnotationType(), methodHandler); 55 | } 56 | 57 | /** 58 | * @param frameInitializer 59 | * The {@link FrameInitializer} to add to the {@link FramedGraph} 60 | * . 61 | */ 62 | public void addFrameInitializer(FrameInitializer frameInitializer) { 63 | frameInitializers.add(frameInitializer); 64 | } 65 | 66 | /** 67 | * @param typeResolver 68 | * The {@link TypeResolver} to add to the {@link FramedGraph}. 69 | */ 70 | public void addTypeResolver(TypeResolver typeResolver) { 71 | typeResolvers.add(typeResolver); 72 | } 73 | 74 | public void setFrameClassLoaderResolver(FrameClassLoaderResolver frameClassLoaderResolver) { 75 | this.frameClassLoaderResolver = frameClassLoaderResolver; 76 | } 77 | 78 | List getFrameInitializers() { 79 | return frameInitializers; 80 | } 81 | 82 | Map, AnnotationHandler> getAnnotationHandlers() { 83 | return annotationHandlers; 84 | } 85 | 86 | List getTypeResolvers() { 87 | return typeResolvers; 88 | } 89 | 90 | FrameClassLoaderResolver getFrameClassLoaderResolver() { 91 | return frameClassLoaderResolver; 92 | } 93 | 94 | public void setConfiguredGraph(Graph configuredGraph) { 95 | this.configuredGraph = configuredGraph; 96 | } 97 | 98 | Graph getConfiguredGraph() { 99 | return configuredGraph; 100 | } 101 | 102 | Map, MethodHandler> getMethodHandlers() { 103 | return methodHandlers; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/FramedGraphFactory.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames; 2 | 3 | import com.tinkerpop.blueprints.Graph; 4 | import com.tinkerpop.blueprints.TransactionalGraph; 5 | import com.tinkerpop.frames.annotations.AdjacencyAnnotationHandler; 6 | import com.tinkerpop.frames.annotations.DomainAnnotationHandler; 7 | import com.tinkerpop.frames.annotations.IncidenceAnnotationHandler; 8 | import com.tinkerpop.frames.annotations.InVertexAnnotationHandler; 9 | import com.tinkerpop.frames.annotations.PropertyAnnotationHandler; 10 | import com.tinkerpop.frames.annotations.RangeAnnotationHandler; 11 | import com.tinkerpop.frames.annotations.OutVertexAnnotationHandler; 12 | import com.tinkerpop.frames.modules.Module; 13 | 14 | /** 15 | * Creates a factory for creating {@link FramedGraph}s using a set of modules to 16 | * configure each graph. Note that by default all Framed graphs have the 17 | * following handlers registered: {@link PropertyAnnotationHandler} 18 | * {@link AdjacencyAnnotationHandler} {@link IncidenceAnnotationHandler} 19 | * {@link DomainAnnotationHandler} {@link RangeAnnotationHandler} 20 | * 21 | * @author Bryn Cooke 22 | * 23 | */ 24 | public class FramedGraphFactory { 25 | 26 | private Module[] modules; 27 | 28 | 29 | /** 30 | * Create a {@link FramedGraphFactory} with a set of modules. 31 | * 32 | * @param modules 33 | * The modules used to configure each {@link FramedGraph} created 34 | * by the factory. 35 | */ 36 | public FramedGraphFactory(Module... modules) { 37 | this.modules = modules; 38 | 39 | } 40 | 41 | /** 42 | * Create a new {@link FramedGraph}. 43 | * 44 | * @param baseGraph 45 | * The graph whose elements to frame. 46 | * @return The {@link FramedGraph} 47 | */ 48 | public FramedGraph create(T baseGraph) { 49 | FramedGraphConfiguration config = getConfiguration(Graph.class, baseGraph); 50 | FramedGraph framedGraph = new FramedGraph(baseGraph, config); 51 | return framedGraph; 52 | } 53 | 54 | /** 55 | * Create a new {@link FramedGraph}. 56 | * 57 | * @param baseGraph 58 | * The graph whose elements to frame. 59 | * @return The {@link FramedGraph} 60 | */ 61 | public FramedTransactionalGraph create(T baseGraph) { 62 | FramedGraphConfiguration config = getConfiguration(TransactionalGraph.class, baseGraph); 63 | FramedTransactionalGraph framedGraph = new FramedTransactionalGraph(baseGraph, config); 64 | return framedGraph; 65 | } 66 | 67 | /** 68 | * Returns a configuration that can be used when constructing a framed graph. 69 | * @param requiredType The type of graph required after configuration e.g. {@link TransactionalGraph} 70 | * @param baseGraph The base graph to get a configuration for. 71 | * @return The configuration. 72 | */ 73 | protected FramedGraphConfiguration getConfiguration(Class requiredType, T baseGraph) { 74 | Graph configuredGraph = baseGraph; 75 | FramedGraphConfiguration config = getBaseConfig(); 76 | for (Module module : modules) { 77 | configuredGraph = module.configure(configuredGraph, config); 78 | if(!(requiredType.isInstance(configuredGraph))) { 79 | throw new UnsupportedOperationException("Module '" + module.getClass() + "' returned a '" + baseGraph.getClass().getName() + "' but factory requires '" + requiredType.getName() + "'"); 80 | } 81 | } 82 | config.setConfiguredGraph(configuredGraph); 83 | return config; 84 | } 85 | 86 | private FramedGraphConfiguration getBaseConfig() { 87 | FramedGraphConfiguration config = new FramedGraphConfiguration(); 88 | config.addAnnotationHandler(new PropertyAnnotationHandler()); 89 | config.addAnnotationHandler(new AdjacencyAnnotationHandler()); 90 | config.addAnnotationHandler(new IncidenceAnnotationHandler()); 91 | config.addAnnotationHandler(new DomainAnnotationHandler()); 92 | config.addAnnotationHandler(new RangeAnnotationHandler()); 93 | config.addAnnotationHandler(new InVertexAnnotationHandler()); 94 | config.addAnnotationHandler(new OutVertexAnnotationHandler()); 95 | return config; 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/FramedGraphQuery.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames; 2 | 3 | import com.tinkerpop.blueprints.GraphQuery; 4 | import com.tinkerpop.blueprints.Predicate; 5 | import com.tinkerpop.blueprints.Query.Compare; 6 | 7 | /** 8 | * GraphQuery that allows framing of results. 9 | * 10 | * @author Bryn Cooke 11 | * 12 | */ 13 | public interface FramedGraphQuery extends GraphQuery { 14 | @Override 15 | public FramedGraphQuery has(String key); 16 | 17 | @Override 18 | public FramedGraphQuery hasNot(String key); 19 | 20 | @Override 21 | public FramedGraphQuery has(String key, Object value); 22 | 23 | @Override 24 | public FramedGraphQuery hasNot(String key, Object value); 25 | 26 | @Override 27 | public FramedGraphQuery has(String key, Predicate predicate, Object value); 28 | 29 | @Override 30 | @Deprecated 31 | public > FramedGraphQuery has(String key, T value, Compare compare); 32 | 33 | @Override 34 | public > FramedGraphQuery interval(String key, T startValue, T endValue); 35 | 36 | @Override 37 | public FramedGraphQuery limit(int limit); 38 | 39 | 40 | /** 41 | * Execute the query and return the matching edges. 42 | * 43 | * @param the default annotated interface to frame the edge as 44 | * @return the unfiltered incident edges 45 | */ 46 | public Iterable edges(Class kind); 47 | 48 | /** 49 | * Execute the query and return the vertices on the other end of the matching edges. 50 | * 51 | * @param the default annotated interface to frame the vertex as 52 | * @return the unfiltered adjacent vertices 53 | */ 54 | public Iterable vertices(Class kind); 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/FramedTransactionalGraph.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames; 2 | 3 | import com.tinkerpop.blueprints.TransactionalGraph; 4 | 5 | /** 6 | * An implementation of {@link FramedGraph} that supports transactions. 7 | * 8 | * @author Bryn Cooke 9 | * 10 | * @param 11 | */ 12 | public class FramedTransactionalGraph extends FramedGraph implements TransactionalGraph { 13 | 14 | 15 | protected FramedTransactionalGraph(T baseGraph, FramedGraphConfiguration config) { 16 | super(baseGraph, config); 17 | 18 | } 19 | 20 | /* (non-Javadoc) 21 | * @see com.tinkerpop.blueprints.TransactionalGraph#commit() 22 | */ 23 | @Override 24 | public void commit() { 25 | getBaseGraph().commit(); 26 | } 27 | 28 | /* (non-Javadoc) 29 | * @see com.tinkerpop.blueprints.TransactionalGraph#rollback() 30 | */ 31 | @Override 32 | public void rollback() { 33 | getBaseGraph().rollback(); 34 | } 35 | 36 | /* (non-Javadoc) 37 | * @see com.tinkerpop.blueprints.TransactionalGraph#stopTransaction(com.tinkerpop.blueprints.TransactionalGraph.Conclusion) 38 | */ 39 | @Override 40 | @Deprecated 41 | public void stopTransaction(Conclusion conclusion) { 42 | getBaseGraph().stopTransaction(conclusion); 43 | } 44 | 45 | 46 | 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/InVertex.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * Marks the in vertex (head) of a framed edge. 10 | */ 11 | @Retention(RetentionPolicy.RUNTIME) 12 | @Target(ElementType.METHOD) 13 | public @interface InVertex { 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/Incidence.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames; 2 | 3 | import com.tinkerpop.blueprints.Direction; 4 | 5 | import java.lang.annotation.ElementType; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.RetentionPolicy; 8 | import java.lang.annotation.Target; 9 | 10 | /** 11 | * Incidences annotate getters and adders to represent a Vertex incident to an Edge. 12 | * 13 | * @author Marko A. Rodriguez (http://markorodriguez.com) 14 | */ 15 | @Retention(RetentionPolicy.RUNTIME) 16 | @Target(ElementType.METHOD) 17 | public @interface Incidence { 18 | /** 19 | * The labels of the edges that are incident to the vertex. 20 | * 21 | * @return the edge label 22 | */ 23 | public String label(); 24 | 25 | /** 26 | * The direction of the edges. 27 | * 28 | * @return the edge direction 29 | */ 30 | public Direction direction() default Direction.OUT; 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/OutVertex.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * Marks the out vertex (tail) of a framed edge. 10 | */ 11 | @Retention(RetentionPolicy.RUNTIME) 12 | @Target(ElementType.METHOD) 13 | public @interface OutVertex { 14 | } -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/Property.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * Property annotations are for getter and setters to manipulate the property value of an Element. 10 | * 11 | * @author Marko A. Rodriguez (http://markorodriguez.com) 12 | */ 13 | @Retention(RetentionPolicy.RUNTIME) 14 | @Target(ElementType.METHOD) 15 | public @interface Property { 16 | public String value(); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/Range.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * The target of the adjacency. 10 | * 11 | * @author Marko A. Rodriguez (http://markorodriguez.com) 12 | * 13 | * @deprecated Use {@link InVertex} or {@link OutVertex} instead. 14 | */ 15 | @Retention(RetentionPolicy.RUNTIME) 16 | @Target(ElementType.METHOD) 17 | public @interface Range { 18 | } -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/UnhandledMethodException.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames; 2 | 3 | import com.tinkerpop.frames.annotations.AnnotationHandler; 4 | import com.tinkerpop.frames.modules.MethodHandler; 5 | 6 | /** 7 | * Thrown if a method could not be handled because an appropriate 8 | * {@link AnnotationHandler} or {@link MethodHandler} could not be found that 9 | * responds to the method 10 | * 11 | * @author Bryn Cooke 12 | * 13 | */ 14 | public class UnhandledMethodException extends RuntimeException { 15 | 16 | 17 | public UnhandledMethodException(String message) { 18 | super(message); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/VertexFrame.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames; 2 | 3 | import com.tinkerpop.blueprints.Vertex; 4 | 5 | /** 6 | * An interface for Vertex-based frames which provides access to the underlying Vertex. 7 | * 8 | * @author Joshua Shinavier (http://fortytwo.net) 9 | */ 10 | public interface VertexFrame { 11 | Vertex asVertex(); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/annotations/AdjacencyAnnotationHandler.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.annotations; 2 | 3 | import com.tinkerpop.blueprints.Direction; 4 | import com.tinkerpop.blueprints.Edge; 5 | import com.tinkerpop.blueprints.Element; 6 | import com.tinkerpop.blueprints.Vertex; 7 | import com.tinkerpop.frames.Adjacency; 8 | import com.tinkerpop.frames.ClassUtilities; 9 | import com.tinkerpop.frames.FramedGraph; 10 | import com.tinkerpop.frames.VertexFrame; 11 | import com.tinkerpop.frames.structures.FramedVertexIterable; 12 | 13 | import java.lang.reflect.Method; 14 | 15 | public class AdjacencyAnnotationHandler implements AnnotationHandler { 16 | 17 | @Override 18 | public Class getAnnotationType() { 19 | return Adjacency.class; 20 | } 21 | 22 | @Override 23 | public Object processElement(final Adjacency annotation, final Method method, final Object[] arguments, final FramedGraph framedGraph, 24 | final Element element, final Direction direction) { 25 | if (element instanceof Vertex) { 26 | return processVertex(annotation, method, arguments, framedGraph, (Vertex) element); 27 | } else { 28 | throw new UnsupportedOperationException(); 29 | } 30 | } 31 | 32 | public Object processVertex(final Adjacency adjacency, final Method method, final Object[] arguments, final FramedGraph framedGraph, final Vertex vertex) { 33 | if (ClassUtilities.isGetMethod(method)) { 34 | final FramedVertexIterable r = new FramedVertexIterable(framedGraph, vertex.getVertices(adjacency.direction(), adjacency.label()), 35 | ClassUtilities.getGenericClass(method)); 36 | if (ClassUtilities.returnsIterable(method)) { 37 | return r; 38 | } else { 39 | return r.iterator().hasNext() ? r.iterator().next() : null; 40 | } 41 | } else if (ClassUtilities.isAddMethod(method)) { 42 | Class returnType = method.getReturnType(); 43 | Vertex newVertex; 44 | Object returnValue = null; 45 | if (arguments == null) { 46 | // Use this method to get the vertex so that the vertex 47 | // initializer is called. 48 | returnValue = framedGraph.addVertex(null, returnType); 49 | newVertex = ((VertexFrame) returnValue).asVertex(); 50 | } else { 51 | newVertex = ((VertexFrame) arguments[0]).asVertex(); 52 | } 53 | addEdges(adjacency, framedGraph, vertex, newVertex); 54 | 55 | if (returnType.isPrimitive()) { 56 | return null; 57 | } else { 58 | return returnValue; 59 | } 60 | 61 | } else if (ClassUtilities.isRemoveMethod(method)) { 62 | removeEdges(adjacency.direction(), adjacency.label(), vertex, ((VertexFrame) arguments[0]).asVertex(), framedGraph); 63 | return null; 64 | } else if (ClassUtilities.isSetMethod(method)) { 65 | removeEdges(adjacency.direction(), adjacency.label(), vertex, null, framedGraph); 66 | if (ClassUtilities.acceptsIterable(method)) { 67 | for (Object o : (Iterable) arguments[0]) { 68 | Vertex v = ((VertexFrame) o).asVertex(); 69 | addEdges(adjacency, framedGraph, vertex, v); 70 | } 71 | return null; 72 | } else { 73 | if (null != arguments[0]) { 74 | Vertex newVertex = ((VertexFrame) arguments[0]).asVertex(); 75 | addEdges(adjacency, framedGraph, vertex, newVertex); 76 | } 77 | return null; 78 | } 79 | } 80 | 81 | return null; 82 | } 83 | 84 | private void addEdges(final Adjacency adjacency, final FramedGraph framedGraph, final Vertex vertex, Vertex newVertex) { 85 | switch(adjacency.direction()) { 86 | case OUT: 87 | framedGraph.addEdge(null, vertex, newVertex, adjacency.label()); 88 | break; 89 | case IN: 90 | framedGraph.addEdge(null, newVertex, vertex, adjacency.label()); 91 | break; 92 | case BOTH: 93 | throw new UnsupportedOperationException("Direction.BOTH it not supported on 'add' or 'set' methods"); 94 | } 95 | } 96 | 97 | private void removeEdges(final Direction direction, final String label, final Vertex element, final Vertex otherVertex, final FramedGraph framedGraph) { 98 | for (final Edge edge : element.getEdges(direction, label)) { 99 | if (null == otherVertex || edge.getVertex(direction.opposite()).equals(otherVertex)) { 100 | framedGraph.removeEdge(edge); 101 | } 102 | } 103 | } 104 | } -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/annotations/AnnotationHandler.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.annotations; 2 | 3 | import com.tinkerpop.blueprints.Direction; 4 | import com.tinkerpop.blueprints.Element; 5 | import com.tinkerpop.frames.FramedGraph; 6 | import com.tinkerpop.frames.modules.MethodHandler; 7 | 8 | import java.lang.annotation.Annotation; 9 | import java.lang.reflect.Method; 10 | 11 | /** 12 | * Allows handling of method on frames. Only the first annotation handler found is called. 13 | * Instances of this class should be threadsafe. 14 | * 15 | * @param The type of annotation handled. 16 | * @deprecated Use {@link MethodHandler} instead 17 | */ 18 | public interface AnnotationHandler { 19 | /** 20 | * @return The annotation type that this handler responds to. 21 | */ 22 | public Class getAnnotationType(); 23 | 24 | /** 25 | * @param annotation The annotation 26 | * @param method The method being called on the frame. 27 | * @param arguments The arguments to the method. 28 | * @param framedGraph The graph being called. 29 | * @param element The underlying element. 30 | * @param direction The direction of the edge. 31 | * @return A return value for the method. 32 | */ 33 | public Object processElement(final T annotation, final Method method, final Object[] arguments, final FramedGraph framedGraph, final Element element, final Direction direction); 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/annotations/DomainAnnotationHandler.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.annotations; 2 | 3 | import com.tinkerpop.blueprints.Direction; 4 | import com.tinkerpop.blueprints.Edge; 5 | import com.tinkerpop.blueprints.Element; 6 | import com.tinkerpop.frames.Domain; 7 | import com.tinkerpop.frames.FramedGraph; 8 | 9 | import java.lang.reflect.Method; 10 | 11 | public class DomainAnnotationHandler implements AnnotationHandler { 12 | 13 | @Override 14 | public Class getAnnotationType() { 15 | return Domain.class; 16 | } 17 | 18 | @Override 19 | public Object processElement(final Domain annotation, final Method method, final Object[] arguments, final FramedGraph framedGraph, final Element element, final Direction direction) { 20 | if (element instanceof Edge) { 21 | return processEdge(annotation, method, arguments, framedGraph, (Edge) element, direction); 22 | } else { 23 | throw new UnsupportedOperationException(); 24 | } 25 | } 26 | 27 | public Object processEdge(final Domain annotation, final Method method, final Object[] arguments, final FramedGraph framedGraph, final Edge edge, final Direction direction) { 28 | return framedGraph.frame(edge.getVertex(direction), method.getReturnType()); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/annotations/InVertexAnnotationHandler.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.annotations; 2 | 3 | import java.lang.reflect.Method; 4 | 5 | import com.tinkerpop.blueprints.Direction; 6 | import com.tinkerpop.blueprints.Edge; 7 | import com.tinkerpop.blueprints.Element; 8 | import com.tinkerpop.frames.FramedGraph; 9 | import com.tinkerpop.frames.InVertex; 10 | 11 | public class InVertexAnnotationHandler implements AnnotationHandler { 12 | @Override 13 | public Class getAnnotationType() { 14 | return InVertex.class; 15 | } 16 | 17 | @Override 18 | public Object processElement(final InVertex annotation, final Method method, final Object[] arguments, final FramedGraph framedGraph, final Element element, final Direction direction) { 19 | if (element instanceof Edge) { 20 | return framedGraph.frame(((Edge)element).getVertex(Direction.IN), method.getReturnType()); 21 | } else { 22 | throw new UnsupportedOperationException(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/annotations/IncidenceAnnotationHandler.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.annotations; 2 | 3 | import java.lang.reflect.Method; 4 | 5 | import com.tinkerpop.blueprints.Direction; 6 | import com.tinkerpop.blueprints.Element; 7 | import com.tinkerpop.blueprints.Vertex; 8 | import com.tinkerpop.frames.ClassUtilities; 9 | import com.tinkerpop.frames.EdgeFrame; 10 | import com.tinkerpop.frames.FramedGraph; 11 | import com.tinkerpop.frames.Incidence; 12 | import com.tinkerpop.frames.VertexFrame; 13 | import com.tinkerpop.frames.structures.FramedEdgeIterable; 14 | 15 | public class IncidenceAnnotationHandler implements AnnotationHandler { 16 | 17 | @Override 18 | public Class getAnnotationType() { 19 | return Incidence.class; 20 | } 21 | 22 | @Override 23 | public Object processElement(final Incidence annotation, final Method method, final Object[] arguments, final FramedGraph framedGraph, final Element element, final Direction direction) { 24 | if (element instanceof Vertex) { 25 | return processVertex(annotation, method, arguments, framedGraph, (Vertex) element); 26 | } else { 27 | throw new UnsupportedOperationException(); 28 | } 29 | } 30 | 31 | public Object processVertex(final Incidence incidence, final Method method, final Object[] arguments, final FramedGraph framedGraph, final Vertex element) { 32 | if (ClassUtilities.isGetMethod(method)) { 33 | return new FramedEdgeIterable(framedGraph, element.getEdges(incidence.direction(), incidence.label()), incidence.direction(), ClassUtilities.getGenericClass(method)); 34 | } else if (ClassUtilities.isAddMethod(method)) { 35 | 36 | switch(incidence.direction()) { 37 | case OUT: 38 | return framedGraph.addEdge(null, element, ((VertexFrame) arguments[0]).asVertex(), incidence.label(), Direction.OUT, method.getReturnType()); 39 | case IN: 40 | return framedGraph.addEdge(null, ((VertexFrame) arguments[0]).asVertex(), element, incidence.label(), Direction.IN, method.getReturnType()); 41 | case BOTH: 42 | throw new UnsupportedOperationException("Direction.BOTH it not supported on 'add' or 'set' methods"); 43 | } 44 | 45 | } else if (ClassUtilities.isRemoveMethod(method)) { 46 | framedGraph.removeEdge(((EdgeFrame) arguments[0]).asEdge()); 47 | return null; 48 | } 49 | 50 | return null; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/annotations/OutVertexAnnotationHandler.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.annotations; 2 | 3 | import java.lang.reflect.Method; 4 | 5 | import com.tinkerpop.blueprints.Direction; 6 | import com.tinkerpop.blueprints.Edge; 7 | import com.tinkerpop.blueprints.Element; 8 | import com.tinkerpop.frames.FramedGraph; 9 | import com.tinkerpop.frames.OutVertex; 10 | 11 | public class OutVertexAnnotationHandler implements AnnotationHandler { 12 | @Override 13 | public Class getAnnotationType() { 14 | return OutVertex.class; 15 | } 16 | 17 | @Override 18 | public Object processElement(final OutVertex annotation, final Method method, final Object[] arguments, final FramedGraph framedGraph, final Element element, final Direction direction) { 19 | if (element instanceof Edge) { 20 | return framedGraph.frame(((Edge)element).getVertex(Direction.OUT), method.getReturnType()); 21 | } else { 22 | throw new UnsupportedOperationException(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/annotations/PropertyAnnotationHandler.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.annotations; 2 | 3 | import com.tinkerpop.blueprints.Direction; 4 | import com.tinkerpop.blueprints.Element; 5 | import com.tinkerpop.frames.ClassUtilities; 6 | import com.tinkerpop.frames.FramedGraph; 7 | import com.tinkerpop.frames.Property; 8 | 9 | import java.lang.reflect.Method; 10 | 11 | public class PropertyAnnotationHandler implements AnnotationHandler { 12 | 13 | @Override 14 | public Class getAnnotationType() { 15 | return Property.class; 16 | } 17 | 18 | @Override 19 | public Object processElement(final Property annotation, final Method method, final Object[] arguments, final FramedGraph framedGraph, final Element element, final Direction direction) { 20 | if (ClassUtilities.isGetMethod(method)) { 21 | Object value = element.getProperty(annotation.value()); 22 | if (method.getReturnType().isEnum()) 23 | return getValueAsEnum(method, value); 24 | else 25 | return value; 26 | } else if (ClassUtilities.isSetMethod(method)) { 27 | Object value = arguments[0]; 28 | if (null == value) { 29 | element.removeProperty(annotation.value()); 30 | } else { 31 | if (value.getClass().isEnum()) { 32 | element.setProperty(annotation.value(), ((Enum) value).name()); 33 | } else { 34 | element.setProperty(annotation.value(), value); 35 | } 36 | } 37 | return null; 38 | } else if (ClassUtilities.isRemoveMethod(method)) { 39 | element.removeProperty(annotation.value()); 40 | return null; 41 | } 42 | 43 | return null; 44 | } 45 | 46 | private Enum getValueAsEnum(final Method method, final Object value) { 47 | Class en = (Class) method.getReturnType(); 48 | if (value != null) 49 | return Enum.valueOf(en, value.toString()); 50 | 51 | return null; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/annotations/RangeAnnotationHandler.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.annotations; 2 | 3 | import com.tinkerpop.blueprints.Direction; 4 | import com.tinkerpop.blueprints.Edge; 5 | import com.tinkerpop.blueprints.Element; 6 | import com.tinkerpop.frames.FramedGraph; 7 | import com.tinkerpop.frames.Range; 8 | 9 | import java.lang.reflect.Method; 10 | 11 | public class RangeAnnotationHandler implements AnnotationHandler { 12 | 13 | @Override 14 | public Class getAnnotationType() { 15 | return Range.class; 16 | } 17 | 18 | @Override 19 | public Object processElement(final Range annotation, final Method method, final Object[] arguments, final FramedGraph framedGraph, final Element element, final Direction direction) { 20 | if (element instanceof Edge) { 21 | return processEdge(annotation, method, arguments, framedGraph, (Edge) element, direction); 22 | } else { 23 | throw new UnsupportedOperationException(); 24 | } 25 | } 26 | 27 | public Object processEdge(final Range annotation, final Method method, final Object[] arguments, final FramedGraph framedGraph, final Edge edge, final Direction direction) { 28 | return framedGraph.frame(edge.getVertex(direction.opposite()), method.getReturnType()); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/annotations/gremlin/GremlinGroovy.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.annotations.gremlin; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * Use a Gremlin Groovy script to determine a vertex-to-vertex adjacency. 10 | * 11 | * @author Marko A. Rodriguez (http://markorodriguez.com) 12 | */ 13 | @Retention(RetentionPolicy.RUNTIME) 14 | @Target(ElementType.METHOD) 15 | public @interface GremlinGroovy { 16 | 17 | public String value(); 18 | 19 | public boolean frame() default true; 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/annotations/gremlin/GremlinGroovyAnnotationHandler.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.annotations.gremlin; 2 | 3 | import java.lang.annotation.Annotation; 4 | import java.lang.reflect.Method; 5 | import java.util.Map; 6 | import java.util.logging.Logger; 7 | 8 | import javax.script.Bindings; 9 | import javax.script.CompiledScript; 10 | import javax.script.ScriptException; 11 | 12 | import com.tinkerpop.blueprints.Direction; 13 | import com.tinkerpop.blueprints.Element; 14 | import com.tinkerpop.blueprints.Vertex; 15 | import com.tinkerpop.frames.ClassUtilities; 16 | import com.tinkerpop.frames.FramedGraph; 17 | import com.tinkerpop.frames.annotations.AnnotationHandler; 18 | import com.tinkerpop.frames.modules.MethodHandler; 19 | import com.tinkerpop.frames.structures.FramedVertexIterable; 20 | import com.tinkerpop.frames.structures.FramedVertexMap; 21 | import com.tinkerpop.frames.util.ExceptionUtils; 22 | import com.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine; 23 | import com.tinkerpop.pipes.Pipe; 24 | import com.tinkerpop.pipes.util.iterators.SingleIterator; 25 | 26 | /** 27 | * @author Marko A. Rodriguez (http://markorodriguez.com) 28 | * @author Bryn Cooke 29 | */ 30 | public class GremlinGroovyAnnotationHandler implements AnnotationHandler, MethodHandler { 31 | private static final String PIPE = "_()"; 32 | private final GremlinGroovyScriptEngine engine = new GremlinGroovyScriptEngine(); 33 | private static final String IT = "it"; 34 | private static final String G = "g"; 35 | 36 | private static final Logger LOGGER = Logger.getLogger(GremlinGroovyAnnotationHandler.class.getName()); 37 | 38 | public GremlinGroovyScriptEngine getGremlinScriptEngine() { 39 | return this.engine; 40 | } 41 | 42 | @Override 43 | public Class getAnnotationType() { 44 | return GremlinGroovy.class; 45 | } 46 | 47 | @Override 48 | public Object processElement(final GremlinGroovy annotation, final Method method, final Object[] arguments, final FramedGraph framedGraph, 49 | final Element element, final Direction direction) { 50 | if (element instanceof Vertex) { 51 | return processVertex(annotation, method, arguments, framedGraph, (Vertex) element); 52 | } else { 53 | throw new UnsupportedOperationException("This method only works for vertices"); 54 | } 55 | } 56 | 57 | public Object processVertex(final GremlinGroovy annotation, final Method method, final Object[] arguments, final FramedGraph framedGraph, 58 | final Vertex vertex) { 59 | try { 60 | final CompiledScript script = this.engine.compile(annotation.value()); 61 | final Bindings bindings = getBindings(method, arguments); 62 | bindings.put(IT, vertex); 63 | bindings.put(G, framedGraph); 64 | final Object result = script.eval(bindings); 65 | 66 | // TODO: Deprecate the use of _() and replace with it 67 | if (result instanceof Pipe & annotation.value().startsWith(PIPE)) { 68 | LOGGER.warning("_() is deprecated in favor of using 'it' to represent the framed vertex"); 69 | ((Pipe) result).setStarts(new SingleIterator(vertex)); 70 | } 71 | 72 | if (annotation.frame()) { 73 | if (result instanceof Iterable) { 74 | final FramedVertexIterable r = new FramedVertexIterable(framedGraph, (Iterable) result, ClassUtilities.getGenericClass(method)); 75 | return (ClassUtilities.returnsIterable(method)) ? r : r.iterator().hasNext() ? r.iterator().next() : null; 76 | } else if (ClassUtilities.returnsMap(method)) { 77 | return new FramedVertexMap(framedGraph, (Map) result, ClassUtilities.getGenericClass(method)); 78 | } else if (result instanceof Vertex) { 79 | return framedGraph.frame((Vertex) result, ClassUtilities.getGenericClass(method)); 80 | } else { 81 | throw new IllegalStateException("The returned object can not be framed: " + result.getClass()); 82 | } 83 | } else { 84 | return result; 85 | } 86 | 87 | } catch (ScriptException e) { 88 | ExceptionUtils.sneakyThrow(e); //Preserve original exception functionality. 89 | return null; 90 | } 91 | } 92 | 93 | private Bindings getBindings(final Method method, final Object[] arguments) { 94 | Bindings bindings = engine.createBindings(); 95 | Annotation[][] allParameterAnnotations = method.getParameterAnnotations(); 96 | for (int pCount = 0; pCount < allParameterAnnotations.length; pCount++) { 97 | Annotation parameterAnnotations[] = allParameterAnnotations[pCount]; 98 | for (int aCount = 0; aCount < parameterAnnotations.length; aCount++) { 99 | Annotation paramAnnotation = parameterAnnotations[aCount]; 100 | if (paramAnnotation instanceof GremlinParam) { 101 | bindings.put(((GremlinParam) paramAnnotation).value(), arguments[pCount]); 102 | break; 103 | } 104 | } 105 | } 106 | return bindings; 107 | } 108 | 109 | @Override 110 | public Object processElement(Object framedElement, Method method, 111 | Object[] arguments, GremlinGroovy annotation, 112 | FramedGraph framedGraph, Element element) { 113 | if (element instanceof Vertex) { 114 | return processVertex(annotation, method, arguments, framedGraph, (Vertex) element); 115 | } else { 116 | throw new UnsupportedOperationException("This method only works for vertices"); 117 | } 118 | } 119 | 120 | 121 | } 122 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/annotations/gremlin/GremlinParam.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.annotations.gremlin; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * Use to name parameters for that get bound when executing a script defined by @GremlinGroovy. 10 | * 11 | * @author Bryn Cooke 12 | */ 13 | @Retention(RetentionPolicy.RUNTIME) 14 | @Target(ElementType.PARAMETER) 15 | public @interface GremlinParam { 16 | String value(); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/core/FramedGraphQueryImpl.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.core; 2 | 3 | import com.tinkerpop.blueprints.Edge; 4 | import com.tinkerpop.blueprints.GraphQuery; 5 | import com.tinkerpop.blueprints.Predicate; 6 | import com.tinkerpop.blueprints.Vertex; 7 | import com.tinkerpop.frames.FramedGraph; 8 | import com.tinkerpop.frames.FramedGraphQuery; 9 | import com.tinkerpop.frames.structures.FramedEdgeIterable; 10 | import com.tinkerpop.frames.structures.FramedVertexIterable; 11 | 12 | public class FramedGraphQueryImpl implements FramedGraphQuery { 13 | private GraphQuery graphQuery; 14 | private FramedGraph graph; 15 | 16 | public FramedGraphQueryImpl(FramedGraph graph, GraphQuery graphQuery) { 17 | this.graph = graph; 18 | this.graphQuery = graphQuery; 19 | } 20 | 21 | public FramedGraphQuery has(String key) { 22 | graphQuery = graphQuery.has(key); 23 | return this; 24 | } 25 | 26 | public FramedGraphQuery hasNot(String key) { 27 | graphQuery = graphQuery.hasNot(key); 28 | return this; 29 | } 30 | 31 | public FramedGraphQuery has(String key, Object value) { 32 | graphQuery = graphQuery.has(key, value); 33 | return this; 34 | } 35 | 36 | public FramedGraphQuery hasNot(String key, Object value) { 37 | graphQuery = graphQuery.hasNot(key, value); 38 | return this; 39 | } 40 | 41 | public FramedGraphQuery has(String key, Predicate predicate, Object value) { 42 | graphQuery = graphQuery.has(key, predicate, value); 43 | return this; 44 | } 45 | 46 | public > FramedGraphQuery has(String key, T value, 47 | Compare compare) { 48 | graphQuery = graphQuery.has(key, value, compare); 49 | return this; 50 | } 51 | 52 | public > FramedGraphQuery interval(String key, 53 | T startValue, T endValue) { 54 | graphQuery = graphQuery.interval(key, startValue, endValue); 55 | return this; 56 | } 57 | 58 | public FramedGraphQuery limit(int limit) { 59 | graphQuery = graphQuery.limit(limit); 60 | return this; 61 | } 62 | 63 | @Override 64 | public Iterable edges(Class kind) { 65 | return new FramedEdgeIterable(graph, edges(), kind); 66 | } 67 | 68 | @Override 69 | public Iterable vertices(Class kind) { 70 | return new FramedVertexIterable(graph, vertices(), kind); 71 | } 72 | 73 | @Override 74 | public Iterable edges() { 75 | return graphQuery.edges(); 76 | } 77 | 78 | @Override 79 | public Iterable vertices() { 80 | return graphQuery.vertices(); 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/modules/AbstractModule.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.modules; 2 | 3 | import com.tinkerpop.blueprints.Graph; 4 | import com.tinkerpop.blueprints.TransactionalGraph; 5 | import com.tinkerpop.frames.FramedGraphConfiguration; 6 | 7 | /** 8 | * Helper base module to simplify configuring different types of graph. Override doConfigure for the appropriate type of graph. 9 | * @author Bryn Cooke 10 | * 11 | */ 12 | public class AbstractModule implements Module { 13 | 14 | @Override 15 | public final Graph configure(Graph baseGraph, FramedGraphConfiguration config) { 16 | if(baseGraph instanceof TransactionalGraph) { 17 | baseGraph = doConfigure((TransactionalGraph)baseGraph, config); 18 | } 19 | else { 20 | baseGraph = doConfigure(baseGraph, config); 21 | } 22 | doConfigure(config); 23 | return baseGraph; 24 | } 25 | 26 | 27 | /** 28 | * @param baseGraph The graph being framed. 29 | * @param config The configuration for the new FramedGraph. 30 | * @return The graph being framed. 31 | */ 32 | protected Graph doConfigure(Graph baseGraph, FramedGraphConfiguration config) { 33 | return baseGraph; 34 | } 35 | 36 | /** 37 | * Perform configuration 38 | * @param baseGraph The graph being framed. 39 | * @param config The configuration for the new FramedGraph. 40 | * @return The graph being framed. 41 | */ 42 | protected TransactionalGraph doConfigure(TransactionalGraph baseGraph, FramedGraphConfiguration config) { 43 | return baseGraph; 44 | } 45 | 46 | /** 47 | * Perform common configuration across all graph types. 48 | * @param config 49 | */ 50 | protected void doConfigure(FramedGraphConfiguration config) { 51 | 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/modules/DefaultClassLoaderResolver.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.modules; 2 | 3 | /** 4 | * Implements a basic FrameClassLoaderResolver that simply returns 5 | * the ClassLoader of the provided Frame Type. 6 | * 7 | * @author Jess Sightler 8 | */ 9 | public class DefaultClassLoaderResolver implements FrameClassLoaderResolver { 10 | @Override 11 | public ClassLoader resolveClassLoader(Class frameType) { 12 | return frameType.getClassLoader(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/modules/FrameClassLoaderResolver.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.modules; 2 | 3 | /** 4 | * This allows the user to provide a custom ClassLoaderResolver. In some 5 | * cases, the user may wish for a type to be framed with a non-default 6 | * classloader (for example, if supplementary types from a TypeResolver 7 | * need to be loaded from some other classloader). 8 | * 9 | * This resolution system allows the user to provide their own custom classloader 10 | * resolver. 11 | * 12 | * Instances of this class should be threadsafe. 13 | * 14 | * @author Jess Sightler 15 | */ 16 | public interface FrameClassLoaderResolver { 17 | public ClassLoader resolveClassLoader(Class frameType); 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/modules/MethodHandler.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.modules; 2 | 3 | import java.lang.annotation.Annotation; 4 | import java.lang.reflect.Method; 5 | 6 | import com.tinkerpop.blueprints.Element; 7 | import com.tinkerpop.frames.FramedGraph; 8 | 9 | /** 10 | * Allows handling of method on frames. Only the first method handler found is called. 11 | * Instances of this class should be threadsafe. 12 | * 13 | * @param The type of annotation handled. 14 | */ 15 | public interface MethodHandler { 16 | /** 17 | * @return The annotation type that this handler responds to. 18 | */ 19 | public Class getAnnotationType(); 20 | 21 | /** 22 | * @param frame The frame upon which the method is being called. 23 | * @param method The method being called on the frame. 24 | * @param arguments The arguments to the method. 25 | * @param annotation The annotation 26 | * @param framedGraph The graph being called. 27 | * @param element The underlying element. 28 | * @return A return value for the method. 29 | */ 30 | public Object processElement(final Object frame, final Method method, final Object[] arguments, final T annotation, final FramedGraph framedGraph, final Element element); 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/modules/Module.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.modules; 2 | 3 | import com.tinkerpop.blueprints.Graph; 4 | import com.tinkerpop.frames.FrameInitializer; 5 | import com.tinkerpop.frames.FramedGraph; 6 | import com.tinkerpop.frames.FramedGraphConfiguration; 7 | import com.tinkerpop.frames.FramedGraphFactory; 8 | import com.tinkerpop.frames.annotations.AnnotationHandler; 9 | 10 | /** 11 | * A module is a group of functionality that must be configured on a 12 | * FramedGraph. They are used by {@link FramedGraphFactory} to create a 13 | * configuration for each graphs produced by that factory. 14 | * 15 | * Modules may add {@link FrameInitializer}s {@link TypeResolver}s and 16 | * {@link AnnotationHandler}s to the configuration. 17 | * 18 | * Modules may wrap the graph being framed. For example to add an event graph. 19 | * 20 | * Modules should be fast and light weight as configure will be called for each {@link FramedGraph} created. 21 | * 22 | * @see FramedGraphFactory 23 | * 24 | * @author Bryn Cooke 25 | */ 26 | public interface Module { 27 | /** 28 | * @param baseGraph The graph being framed. 29 | * @param config The configuration for the new FramedGraph. 30 | * @return The graph being framed. 31 | */ 32 | Graph configure(Graph baseGraph, FramedGraphConfiguration config); 33 | 34 | 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/modules/TypeResolver.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.modules; 2 | 3 | import com.tinkerpop.blueprints.Edge; 4 | import com.tinkerpop.blueprints.Vertex; 5 | 6 | /** 7 | * Allows dynamic resolution of interfaces that a frame will implement when framing an element. 8 | * For instance the java type information may retrieved from a property on the element. 9 | * Instances of this class should be threadsafe. 10 | * 11 | * @author Bryn Cooke 12 | */ 13 | public interface TypeResolver { 14 | 15 | /** 16 | * @param v The vertex being framed. 17 | * @param defaultType The default as passed in to the framing method. 18 | * @return Any additional interfaces that the frame should implement. 19 | */ 20 | Class[] resolveTypes(Vertex v, Class defaultType); 21 | /** 22 | * @param e The edge being framed. 23 | * @param defaultType The default as passed in to the framing method. 24 | * @return Any additional interfaces that the frame should implement. 25 | */ 26 | Class[] resolveTypes(Edge e, Class defaultType); 27 | } -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/modules/gremlingroovy/GremlinGroovyModule.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.modules.gremlingroovy; 2 | 3 | import com.tinkerpop.frames.FramedGraphConfiguration; 4 | import com.tinkerpop.frames.annotations.gremlin.GremlinGroovyAnnotationHandler; 5 | import com.tinkerpop.frames.modules.AbstractModule; 6 | 7 | /** 8 | * Adds @GremlinGroovy support to the framed graph. 9 | * @author Bryn Cooke 10 | * 11 | */ 12 | public class GremlinGroovyModule extends AbstractModule { 13 | private GremlinGroovyAnnotationHandler handler = new GremlinGroovyAnnotationHandler(); //Factory will share handler. 14 | 15 | @Override 16 | public void doConfigure(FramedGraphConfiguration config) { 17 | config.addMethodHandler(handler); 18 | 19 | } 20 | 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/modules/javahandler/Initializer.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.modules.javahandler; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | import com.tinkerpop.frames.FrameInitializer; 9 | 10 | /** 11 | * Allows methods in a java handler implementation to be called when a vertex or an edge is added to the graph. 12 | * This effectively has the same function as a {@link FrameInitializer}. 13 | * 14 | * For each interface in the hierarchy initializer methods will be called. 15 | * 16 | *
17 |  * interface A {
18 |  * 
19 |  *   abstract class Impl implements A {
20 |  *   
21 |  *     @Initializer
22 |  *     void init() {
23 |  *       //Called when a framed vertex or edge is added to the graph.
24 |  *     }
25 |  *   }
26 |  * 
27 |  * }
28 |  * 
29 |  * 
30 | * 31 | * @author Bryn Cooke 32 | * 33 | */ 34 | @Target(ElementType.METHOD) 35 | @Retention(RetentionPolicy.RUNTIME) 36 | public @interface Initializer { 37 | 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/modules/javahandler/JavaFrameInitializer.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.modules.javahandler; 2 | 3 | import java.lang.reflect.InvocationTargetException; 4 | import java.lang.reflect.Method; 5 | import java.util.ArrayList; 6 | import java.util.Collections; 7 | import java.util.LinkedHashSet; 8 | import java.util.List; 9 | import java.util.concurrent.ExecutionException; 10 | 11 | import com.google.common.cache.CacheBuilder; 12 | import com.google.common.cache.CacheLoader; 13 | import com.google.common.cache.LoadingCache; 14 | import com.google.common.collect.Lists; 15 | import com.tinkerpop.blueprints.Edge; 16 | import com.tinkerpop.blueprints.Element; 17 | import com.tinkerpop.blueprints.Vertex; 18 | import com.tinkerpop.frames.FrameInitializer; 19 | import com.tinkerpop.frames.FramedGraph; 20 | import com.tinkerpop.frames.util.ExceptionUtils; 21 | import javassist.util.proxy.ProxyFactory; 22 | 23 | /** 24 | * Calls the methods annotated with {@link Initializer} on frame 25 | * implementations. 26 | * 27 | * @author Bryn Cooke 28 | * 29 | */ 30 | class JavaFrameInitializer implements FrameInitializer { 31 | 32 | private JavaHandlerModule module; 33 | 34 | /** 35 | * Caches lists of InitializerMethods for a given frame class. See "doLoad" method below. 36 | */ 37 | private LoadingCache, List> initializerCache = CacheBuilder 38 | .newBuilder().build(new CacheLoader, List>() { 39 | @Override 40 | public List load(final Class frameClass) throws Exception { 41 | return doLoad(frameClass); 42 | } 43 | }); 44 | 45 | 46 | JavaFrameInitializer(JavaHandlerModule module) { 47 | this.module = module; 48 | } 49 | 50 | /** 51 | * Captures the work of calling an "@Initializer" annotated method. 52 | */ 53 | private class InitializerMethod { 54 | private final Class h; 55 | private final Method method; 56 | 57 | private InitializerMethod(Class h, Method method) { 58 | this.h = h; 59 | this.method = method; 60 | } 61 | 62 | void execute(Object framedElement, FramedGraph framedGraph, Element element) 63 | throws InvocationTargetException, IllegalAccessException { 64 | Object handler = module.createHandler(framedElement, framedGraph, element, h, method); 65 | method.invoke(handler); 66 | } 67 | } 68 | 69 | @Override 70 | public void initElement(Class kind, FramedGraph framedGraph, Element element) { 71 | 72 | Object framedElement; 73 | if (element instanceof Vertex) { 74 | framedElement = framedGraph.frame((Vertex) element, kind); 75 | } else { 76 | framedElement = framedGraph.frame((Edge) element, kind); 77 | } 78 | 79 | try { 80 | for (InitializerMethod method : initializerCache.get(kind)) { 81 | try { 82 | method.execute(framedElement, framedGraph, element); 83 | } catch (IllegalArgumentException e) { 84 | throw new JavaHandlerException("Problem calling Java handler", e); 85 | } catch (IllegalAccessException e) { 86 | throw new JavaHandlerException("Problem calling Java handler", e); 87 | } catch (InvocationTargetException e) { 88 | ExceptionUtils.sneakyThrow(e.getTargetException()); 89 | } 90 | } 91 | } catch (ExecutionException e) { 92 | throw new JavaHandlerException("Problem calling Java handler", e); 93 | } 94 | 95 | } 96 | 97 | /** 98 | * Finds all the relevant @Initializer methods for the given class. 99 | */ 100 | private List doLoad(Class kind) { 101 | // We have to order this correctly. Dependencies should be initialised 102 | // first so we first recursively collect an an array of classes to call 103 | // and then reverse the array before putting them in a linked hash set. 104 | // That way the classes discovered last will be called first. 105 | List> classes = new ArrayList>(); 106 | depthFirstClassSearch(classes, kind); 107 | 108 | Collections.reverse(classes); 109 | LinkedHashSet> hierarchy = new LinkedHashSet>(classes); 110 | List methods = Lists.newArrayList(); 111 | 112 | // Now we can store InitializerMethod objects for each method call. 113 | for (Class h : hierarchy) { 114 | try { 115 | try { 116 | Class implKind = module.getHandlerClass(h); 117 | for (Method method : implKind.getDeclaredMethods()) { 118 | if (method.isAnnotationPresent(Initializer.class)) { 119 | if (method.getParameterTypes().length != 0) { 120 | throw new JavaHandlerException("Java handler initializer " + method + "cannot have parameters"); 121 | } 122 | methods.add(new InitializerMethod(h, method)); 123 | } 124 | 125 | } 126 | } catch (ClassNotFoundException e) { 127 | // There was no impl class to check 128 | } 129 | } catch (IllegalArgumentException e) { 130 | throw new JavaHandlerException("Problem calling Java handler", e); 131 | } 132 | } 133 | 134 | return methods; 135 | } 136 | 137 | private void depthFirstClassSearch(List> initializers, Class kind) { 138 | 139 | if (kind == null || kind == Object.class) { 140 | return; 141 | } 142 | 143 | initializers.add(kind); 144 | 145 | for (Class i : kind.getInterfaces()) { 146 | depthFirstClassSearch(initializers, i); 147 | } 148 | depthFirstClassSearch(initializers, kind.getSuperclass()); 149 | 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/modules/javahandler/JavaHandler.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.modules.javahandler; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | *

10 | * Use a Java class to handle frame method calls. Unless overridden using the 11 | * {@link JavaHandlerClass} annotation the default handler will be a nested 12 | * class inside your frame interface called Impl. For example: 13 | *

14 | *
15 |  * 
16 |  * interface Person {
17 |  * 
18 |  *   @JavaHandler
19 |  *   public String doSomething(); 
20 |  * 
21 |  *   abstract class Impl implements Person, JavaHandlerContext {
22 |  *     public String doSomething() {
23 |  *       return "Use Frames!";
24 |  *     }
25 |  *   }
26 |  * }
27 |  * 
28 | * 29 | * @author Bryn Cooke 30 | */ 31 | @Retention(RetentionPolicy.RUNTIME) 32 | @Target(ElementType.METHOD) 33 | public @interface JavaHandler { 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/modules/javahandler/JavaHandlerClass.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.modules.javahandler; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | *

10 | * When using the {@link JavaHandler} you can change the implementation class 11 | * from the default to another class by using this annotation on your frame 12 | * class. For example: 13 | *

14 | * 15 | *
16 |  * 
17 |  * @JavaHandlerClass(PersonImpl.class)
18 |  * interface Person {
19 |  * 
20 |  *   @JavaHandler
21 |  *   public String doSomething(); 
22 |  * 
23 |  *   
24 |  * }
25 |  * 
26 |  * abstract class PersonImpl implements Person, JavaHandlerContext {
27 |  *   public String doSomething() {
28 |  *     return "Use Frames!";
29 |  *   }
30 |  * }
31 |  * 
32 |  * 
33 | * 34 | * @author Bryn Cooke 35 | */ 36 | @Retention(RetentionPolicy.RUNTIME) 37 | @Target(ElementType.TYPE) 38 | public @interface JavaHandlerClass { 39 | Class value(); 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/modules/javahandler/JavaHandlerContext.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.modules.javahandler; 2 | 3 | import com.tinkerpop.blueprints.Direction; 4 | import com.tinkerpop.blueprints.Edge; 5 | import com.tinkerpop.blueprints.Element; 6 | import com.tinkerpop.blueprints.Vertex; 7 | import com.tinkerpop.frames.FramedGraph; 8 | import com.tinkerpop.gremlin.java.GremlinPipeline; 9 | 10 | /** 11 | * By implementing this interface your Java handler implementation can access the underlying graph and the framed vertex/edge. 12 | * 13 | * @author Bryn Cooke 14 | * 15 | * @param 16 | */ 17 | public interface JavaHandlerContext { 18 | 19 | /** 20 | * @return The framed graph 21 | */ 22 | public FramedGraph g(); 23 | 24 | /** 25 | * @return The element that was framed 26 | */ 27 | public C it(); 28 | 29 | /** 30 | * @return A gremlin pipeline at the context element 31 | */ 32 | public GremlinPipeline gremlin(); 33 | 34 | /** 35 | * Start a gremlin pipeline 36 | * 37 | * @param starts 38 | * @return Start a gremlin pipeline at an element 39 | */ 40 | public GremlinPipeline gremlin(Object starts); 41 | 42 | /** 43 | * Frame a vertex using the return type of the method 44 | * 45 | * @param vertex The vertex to frame 46 | * @return The framed vertex 47 | */ 48 | public T frame(Vertex vertex); 49 | 50 | /** 51 | * Frame a vertex using an explicit kind of frame 52 | * 53 | * @param vertex The vertex to frame 54 | * @param kind The type of frame 55 | * @return The framed vertex 56 | */ 57 | public T frame(Vertex vertex, Class kind); 58 | 59 | /** 60 | * Frame an edge using the return type of the method 61 | * 62 | * @param edge The edge to frame 63 | * @return The framed edge 64 | */ 65 | public T frame(Edge edge); 66 | 67 | 68 | /** 69 | * Frame an edge using an explicit kind of frame 70 | * 71 | * @param edge The edge to frame 72 | * @param kind The type of frame 73 | * @return The framed edge 74 | */ 75 | public T frame(Edge edge, Class kind); 76 | 77 | /** 78 | * Frame an edge using the return type of the method 79 | * 80 | * @param edge The edge to frame 81 | * @param direction The direction of the edge 82 | * @return The framed edge 83 | */ 84 | public T frame(Edge edge, Direction direction); 85 | 86 | /** 87 | * Frame an edge using an explicit kind of frame 88 | * 89 | * @param edge The edge to frame 90 | * @param direction The direction of the edge 91 | * @param kind The type of frame 92 | * @return The framed edge 93 | */ 94 | public T frame(Edge edge, Direction direction, Class kind); 95 | 96 | /** 97 | * Frame some vertices using the return type of the method 98 | * 99 | * @param vertices The vertices to frame 100 | * @return The framed vertices 101 | */ 102 | public Iterable frameVertices(Iterable vertices); 103 | 104 | /** 105 | * Frame some vertices using an explicit kind of frame 106 | * 107 | * @param vertices The vertices to frame 108 | * @param kind The kind of frame 109 | * @return The framed vertices 110 | */ 111 | public Iterable frameVertices(Iterable vertices, Class kind); 112 | 113 | 114 | /** 115 | * Frame some edges using the return type of the method 116 | * 117 | * @param edges the edges to frame 118 | * @param direction The direction of the edges 119 | * @return The framed edges 120 | */ 121 | public Iterable frameEdges(Iterable edges); 122 | 123 | /** 124 | * Frame some edges using an explicit kind of frame 125 | * 126 | * @param edges the edges to frame 127 | * @param direction The direction of the edges 128 | * @param kind The kind of frame 129 | * @return The framed edges 130 | */ 131 | public Iterable frameEdges(Iterable edges, Class kind); 132 | 133 | 134 | /** 135 | * Frame some edges using the return type of the method 136 | * 137 | * @param edges the edges to frame 138 | * @param direction The direction of the edges 139 | * @return The framed edges 140 | */ 141 | public Iterable frameEdges(Iterable edges, Direction direction); 142 | 143 | /** 144 | * Frame some edges using an explicit kind of frame 145 | * 146 | * @param edges the edges to frame 147 | * @param direction The direction of the edges 148 | * @param kind The kind of frame 149 | * @return The framed edges 150 | */ 151 | public Iterable frameEdges(Iterable edges, Direction direction, Class kind); 152 | 153 | } 154 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/modules/javahandler/JavaHandlerContextImpl.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.modules.javahandler; 2 | 3 | import java.lang.reflect.Method; 4 | import java.lang.reflect.ParameterizedType; 5 | import java.lang.reflect.Type; 6 | 7 | import com.tinkerpop.blueprints.Direction; 8 | import com.tinkerpop.blueprints.Edge; 9 | import com.tinkerpop.blueprints.Element; 10 | import com.tinkerpop.blueprints.Vertex; 11 | import com.tinkerpop.frames.ClassUtilities; 12 | import com.tinkerpop.frames.FramedGraph; 13 | import com.tinkerpop.gremlin.java.GremlinPipeline; 14 | 15 | /** 16 | * Implementation for java handler context. 17 | * 18 | * @author Bryn Cooke 19 | * 20 | */ 21 | class JavaHandlerContextImpl implements JavaHandlerContext { 22 | 23 | private final FramedGraph graph; 24 | private final Method method; 25 | private final C context; 26 | 27 | JavaHandlerContextImpl(FramedGraph graph, Method method, C context) { 28 | super(); 29 | this.graph = graph; 30 | this.method = method; 31 | this.context = context; 32 | } 33 | 34 | /** 35 | * @return The framed graph 36 | */ 37 | public FramedGraph g() { 38 | return graph; 39 | } 40 | 41 | /** 42 | * @return The element that was framed 43 | */ 44 | public C it() { 45 | return context; 46 | } 47 | 48 | /** 49 | * @return A gremlin pipeline at the context element 50 | */ 51 | public GremlinPipeline gremlin() { 52 | return new GremlinPipeline(it()); 53 | } 54 | 55 | /** 56 | * Start a gremlin pipeline 57 | * 58 | * @param starts 59 | * @return Start a gremlin pipeline at an element 60 | */ 61 | public GremlinPipeline gremlin(Object starts) { 62 | return new GremlinPipeline(starts); 63 | } 64 | 65 | /** 66 | * Frame a vertex using the return type of the method 67 | * 68 | * @param vertex The vertex to frame 69 | * @return The framed vertex 70 | */ 71 | public T frame(Vertex vertex) { 72 | return g().frame(vertex, (Class) method.getReturnType()); 73 | } 74 | 75 | /** 76 | * Frame a vertex using an explicit kind of frame 77 | * 78 | * @param vertex The vertex to frame 79 | * @param kind The type of frame 80 | * @return The framed vertex 81 | */ 82 | public T frame(Vertex vertex, Class kind) { 83 | return g().frame(vertex, kind); 84 | } 85 | 86 | /** 87 | * Frame an edge using the return type of the method 88 | * 89 | * @param edge The edge to frame 90 | * @param direction The direction of the edge 91 | * @return The framed edge 92 | */ 93 | public T frame(Edge edge, Direction direction) { 94 | return g().frame(edge, direction, (Class) method.getReturnType()); 95 | } 96 | 97 | /** 98 | * Frame an edge using an explicit kind of frame 99 | * 100 | * @param edge The edge to frame 101 | * @param direction The direction of the edge 102 | * @param kind The type of frame 103 | * @return The framed edge 104 | */ 105 | public T frame(Edge edge, Direction direction, Class kind) { 106 | return (T) g().frame(edge, direction, kind); 107 | } 108 | 109 | /** 110 | * Frame some vertices using the return type of the method 111 | * 112 | * @param vertices The vertices to frame 113 | * @return The framed vertices 114 | */ 115 | public Iterable frameVertices(Iterable vertices) { 116 | Type type = getIterableType(); 117 | 118 | return g().frameVertices(vertices, (Class) type); 119 | } 120 | 121 | 122 | 123 | /** 124 | * Frame some vertices using an explicit kind of frame 125 | * 126 | * @param vertices The vertices to frame 127 | * @param kind The kind of frame 128 | * @return The framed vertices 129 | */ 130 | public Iterable frameVertices(Iterable vertices, Class kind) { 131 | return (Iterable) g().frameVertices(vertices, kind); 132 | } 133 | 134 | /** 135 | * Frame some edges using the return type of the method 136 | * 137 | * @param edges the edges to frame 138 | * @param direction The direction of the edges 139 | * @return The framed edges 140 | */ 141 | public Iterable frameEdges(Iterable edges, Direction direction) { 142 | Type type = getIterableType(); 143 | return g().frameEdges(edges, direction, (Class) type); 144 | } 145 | 146 | /** 147 | * Frame some edges using an explicit kind of frame 148 | * 149 | * @param edges the edges to frame 150 | * @param direction The direction of the edges 151 | * @param kind The kind of frame 152 | * @return The framed edges 153 | */ 154 | public Iterable frameEdges(Iterable edges, Direction direction, Class kind) { 155 | return (Iterable) g().frameEdges(edges, direction, kind); 156 | } 157 | 158 | 159 | private Type getIterableType() { 160 | 161 | if(method.getReturnType() != Iterable.class) { 162 | throw new JavaHandlerException("Method return type is not iterable: " + method); 163 | } 164 | Type genericReturnType = method.getGenericReturnType(); 165 | if(!(genericReturnType instanceof ParameterizedType)) { 166 | throw new JavaHandlerException("Method must specify generic parameter for Iterable: " + method); 167 | } 168 | return ClassUtilities.getGenericClass(method); 169 | } 170 | 171 | @Override 172 | public T frame(Edge edge) { 173 | return g().frame(edge, (Class) method.getReturnType()); 174 | } 175 | 176 | 177 | @Override 178 | public T frame(Edge edge, Class kind) { 179 | return g().frame(edge, kind); 180 | } 181 | 182 | @Override 183 | public Iterable frameEdges(Iterable edges) { 184 | Type type = getIterableType(); 185 | return g().frameEdges(edges, (Class) type); 186 | } 187 | 188 | @Override 189 | public Iterable frameEdges(Iterable edges, Class kind) { 190 | return g().frameEdges(edges, kind); 191 | } 192 | 193 | 194 | 195 | } -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/modules/javahandler/JavaHandlerException.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.modules.javahandler; 2 | 3 | public class JavaHandlerException extends RuntimeException { 4 | 5 | public JavaHandlerException() { 6 | } 7 | 8 | public JavaHandlerException(String message) { 9 | super(message); 10 | } 11 | 12 | public JavaHandlerException(Throwable cause) { 13 | super(cause); 14 | } 15 | 16 | public JavaHandlerException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/modules/javahandler/JavaHandlerFactory.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.modules.javahandler; 2 | 3 | 4 | /** 5 | * {@link JavaHandlerModule} uses this interface to create the concrete classes that will handle the method calls. 6 | * @author Bryn Cooke 7 | */ 8 | public interface JavaHandlerFactory { 9 | 10 | /** 11 | * @param handlerClass The class to create. 12 | * @return The created class. 13 | * @throws InstantiationException 14 | * @throws IllegalAccessException 15 | */ 16 | public T create(Class handlerClass) throws InstantiationException, IllegalAccessException; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/modules/javahandler/JavaHandlerModule.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.modules.javahandler; 2 | 3 | import java.lang.reflect.Method; 4 | import java.lang.reflect.Modifier; 5 | import java.net.URL; 6 | import java.net.URLClassLoader; 7 | import java.util.concurrent.ExecutionException; 8 | 9 | import javassist.util.proxy.MethodHandler; 10 | import javassist.util.proxy.Proxy; 11 | import javassist.util.proxy.ProxyFactory; 12 | 13 | import com.google.common.cache.CacheBuilder; 14 | import com.google.common.cache.CacheLoader; 15 | import com.google.common.cache.LoadingCache; 16 | import com.tinkerpop.blueprints.Element; 17 | import com.tinkerpop.blueprints.Graph; 18 | import com.tinkerpop.frames.FramedGraph; 19 | import com.tinkerpop.frames.FramedGraphConfiguration; 20 | import com.tinkerpop.frames.modules.Module; 21 | 22 | /** 23 | *

24 | * Adds support for calling Java methods to handle a frames call. A call to a 25 | * frames method annotated with {@link JavaHandler} will cause the supplied 26 | * factory to instantiate an instance of the handler class and call the 27 | * appropriate method on it. 28 | *

29 | *

30 | * The default implementation is an inner class of the frame interface named 'Impl'. For example: 31 | *

32 | *
 33 |  * interface Person {
 34 |  * 
 35 |  *   @JavaHandler
 36 |  *   public String doSomething(); 
 37 |  *   
 38 |  *   abstract class Impl implements Person, JavaHandlerContext {
 39 |  *     public String doSomething() {
 40 |  *       return "Use Frames!";
 41 |  *     }
 42 |  *   }
 43 |  *   
 44 |  * }
 45 |  * 
 46 |  * 
47 | *

The implementation class can be overridden by using the {@link JavaHandlerClass} annotation.

48 | * 49 | * 50 | * @author Bryn Cooke 51 | */ 52 | public class JavaHandlerModule implements Module { 53 | 54 | 55 | // We don't want to use the global class cache. Instead we cache the classes 56 | // at the module level. 57 | // Maps from frameClass -> proxy class. 58 | private LoadingCache, Class> classCache = CacheBuilder 59 | .newBuilder().build(new CacheLoader, Class>() { 60 | 61 | @Override 62 | public Class load(final Class frameClass) throws Exception { 63 | final Class handlerClass = getHandlerClass(frameClass); 64 | ProxyFactory proxyFactory = new ProxyFactory() { 65 | protected ClassLoader getClassLoader() { 66 | 67 | return new URLClassLoader(new URL[0], handlerClass.getClassLoader()); 68 | } 69 | }; 70 | proxyFactory.setUseCache(false); 71 | proxyFactory.setSuperclass(handlerClass); 72 | return proxyFactory.createClass(); 73 | } 74 | }); 75 | 76 | private JavaHandlerFactory factory = new JavaHandlerFactory() { 77 | 78 | @Override 79 | public T create(Class handlerClass) 80 | throws InstantiationException, IllegalAccessException { 81 | return handlerClass.newInstance(); 82 | } 83 | 84 | }; 85 | 86 | /** 87 | * Provide an alternative factory for creating objects that handle frames 88 | * calls. 89 | * 90 | * @param factory 91 | * The factory to use. 92 | * @return The module. 93 | */ 94 | public JavaHandlerModule withFactory(JavaHandlerFactory factory) { 95 | this.factory = factory; 96 | return this; 97 | } 98 | 99 | @Override 100 | public Graph configure(Graph baseGraph, FramedGraphConfiguration config) { 101 | 102 | config.addMethodHandler(new JavaMethodHandler(this)); 103 | config.addFrameInitializer(new JavaFrameInitializer(this)); 104 | return baseGraph; 105 | } 106 | 107 | 108 | Class getHandlerClass(Class frameClass) 109 | throws ClassNotFoundException { 110 | JavaHandlerClass handlerClass = frameClass 111 | .getAnnotation(JavaHandlerClass.class); 112 | if (handlerClass != null) { 113 | return handlerClass.value(); 114 | } 115 | return frameClass.getClassLoader().loadClass( 116 | frameClass.getName() + "$Impl"); 117 | } 118 | 119 | T createHandler(final Object framedElement, final FramedGraph graph, final Element element, Class frameClass, 120 | final Method method) { 121 | 122 | try { 123 | Class implClass = (Class) classCache.get(frameClass); 124 | T handler = factory.create(implClass); 125 | ((Proxy) handler).setHandler(new MethodHandler() { 126 | private JavaHandlerContextImpl defaultJavahandlerImpl = new JavaHandlerContextImpl( 127 | graph, method, element); 128 | 129 | 130 | @Override 131 | public Object invoke(Object o, Method m, Method proceed, 132 | Object[] args) throws Throwable { 133 | if (!Modifier.isAbstract(m.getModifiers())) { 134 | return proceed.invoke(o, args); 135 | } else { 136 | if(m.getAnnotation(JavaHandler.class) != null) { 137 | throw new JavaHandlerException("Method " + m + " is marked with @JavaHandler but is not implemented"); 138 | } 139 | if (m.getDeclaringClass() == JavaHandlerContext.class) { 140 | return m.invoke(defaultJavahandlerImpl, args); 141 | } 142 | 143 | return m.invoke(framedElement, args); 144 | } 145 | } 146 | 147 | }); 148 | return handler; 149 | } catch (ExecutionException e) { 150 | Throwable cause = e.getCause(); 151 | if (cause instanceof ClassNotFoundException) { 152 | throw new JavaHandlerException("Problem locating handler class for " + frameClass, e); 153 | } else { 154 | throw new JavaHandlerException( 155 | "Cannot create class for handling framed method", cause); 156 | } 157 | } catch (InstantiationException e) { 158 | throw new JavaHandlerException( 159 | "Problem instantiating handler class", e); 160 | } catch (IllegalAccessException e) { 161 | throw new JavaHandlerException( 162 | "Problem instantiating handler class", e); 163 | } 164 | 165 | } 166 | 167 | 168 | } 169 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/modules/javahandler/JavaMethodHandler.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.modules.javahandler; 2 | 3 | import java.lang.reflect.InvocationTargetException; 4 | import java.lang.reflect.Method; 5 | 6 | import com.tinkerpop.blueprints.Element; 7 | import com.tinkerpop.frames.FramedGraph; 8 | import com.tinkerpop.frames.util.ExceptionUtils; 9 | 10 | class JavaMethodHandler implements 11 | com.tinkerpop.frames.modules.MethodHandler { 12 | 13 | private JavaHandlerModule module; 14 | 15 | JavaMethodHandler(JavaHandlerModule module) { 16 | this.module = module; 17 | } 18 | 19 | @Override 20 | public Class getAnnotationType() { 21 | return JavaHandler.class; 22 | } 23 | 24 | 25 | 26 | @Override 27 | public Object processElement(Object framedElement, Method method, 28 | Object[] arguments, JavaHandler annotation, 29 | FramedGraph framedGraph, Element element) { 30 | try { 31 | Object handler = module.createHandler(framedElement, framedGraph, element, method.getDeclaringClass(), method); 32 | return method.invoke(handler, arguments); 33 | } catch (IllegalArgumentException e) { 34 | throw new JavaHandlerException("Problem calling Java handler", e); 35 | } catch (IllegalAccessException e) { 36 | throw new JavaHandlerException("Problem calling Java handler", e); 37 | } catch (InvocationTargetException e) { 38 | ExceptionUtils.sneakyThrow(e.getTargetException()); 39 | return null; 40 | } 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/modules/typedgraph/TypeField.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.modules.typedgraph; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * Interface annotation for marking the Element property-key that may contain type information. 10 | * 11 | * @see TypeValue 12 | */ 13 | @Retention(RetentionPolicy.RUNTIME) 14 | @Target(ElementType.TYPE) 15 | public @interface TypeField { 16 | public String value(); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/modules/typedgraph/TypeManager.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.modules.typedgraph; 2 | 3 | import com.tinkerpop.blueprints.Edge; 4 | import com.tinkerpop.blueprints.Element; 5 | import com.tinkerpop.blueprints.Vertex; 6 | import com.tinkerpop.frames.EdgeFrame; 7 | import com.tinkerpop.frames.FrameInitializer; 8 | import com.tinkerpop.frames.FramedGraph; 9 | import com.tinkerpop.frames.VertexFrame; 10 | import com.tinkerpop.frames.modules.TypeResolver; 11 | 12 | public class TypeManager implements TypeResolver, FrameInitializer { 13 | 14 | private TypeRegistry typeRegistry; 15 | public TypeManager(TypeRegistry typeRegistry) { 16 | this.typeRegistry = typeRegistry; 17 | } 18 | 19 | @Override public Class[] resolveTypes(Vertex v, Class defaultType) { 20 | return new Class[] {resolve(v, defaultType), VertexFrame.class }; 21 | } 22 | 23 | @Override public Class[] resolveTypes(Edge e, Class defaultType) { 24 | return new Class[] {resolve(e, defaultType), EdgeFrame.class }; 25 | } 26 | 27 | private Class resolve(Element e, Class defaultType) { 28 | Class typeHoldingTypeField = typeRegistry.getTypeHoldingTypeField(defaultType); 29 | if (typeHoldingTypeField != null) { 30 | String value = e.getProperty(typeHoldingTypeField.getAnnotation(TypeField.class).value()); 31 | Class type = value == null ? null : typeRegistry.getType(typeHoldingTypeField, value); 32 | if (type != null) { 33 | return type; 34 | } 35 | } 36 | return defaultType; 37 | } 38 | 39 | @Override 40 | public void initElement(Class kind, FramedGraph framedGraph, Element element) { 41 | Class typeHoldingTypeField = typeRegistry.getTypeHoldingTypeField(kind); 42 | if (typeHoldingTypeField != null) { 43 | TypeValue typeValue = kind.getAnnotation(TypeValue.class); 44 | if (typeValue != null) { 45 | element.setProperty(typeHoldingTypeField.getAnnotation(TypeField.class).value(), typeValue.value()); 46 | } 47 | } 48 | } 49 | 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/modules/typedgraph/TypeRegistry.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.modules.typedgraph; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import com.tinkerpop.blueprints.Element; 7 | import com.tinkerpop.frames.FramedGraph; 8 | import com.tinkerpop.frames.util.Validate; 9 | 10 | /** 11 | * A TypeRegistry for a {@link FramedGraph}. With a {@link TypeRegistry} the {@link FramedGraph} is able to store type-information on edges, 12 | * and use stored type-information to construct vertices/edges based on type-information stored in the graph (runtime). 13 | * 14 | * @see TypeField 15 | * @see TypeValue 16 | * @see FramedGraph 17 | */ 18 | public class TypeRegistry { 19 | Map, Class> typeFields = new HashMap, Class>(); 20 | Map> typeDiscriminators = new HashMap>(); 21 | 22 | 23 | 24 | /** 25 | * @return The interface that has the {@link TypeField} annotation for this class. (Either the class itself, or a base class if the class was registered). 26 | */ 27 | public Class getTypeHoldingTypeField(Class type) { 28 | if (type.getAnnotation(TypeField.class) != null) 29 | return type; 30 | return typeFields.get(type); 31 | } 32 | 33 | /** 34 | * @param typeHoldingTypeField The type that has the {@link TypeField} annotation for the Proxy class to be constructed. 35 | * @param typeValue The actual persisted value for a type field on an {@link Element} in the graph 36 | * @return The type that needs to be constructed, or null if there is no registered class that matches the input values. 37 | */ 38 | public Class getType(Class typeHoldingTypeField, String typeValue) { 39 | Class result = typeDiscriminators.get(new TypeDiscriminator(typeHoldingTypeField, typeValue)); 40 | return result; 41 | } 42 | 43 | static final class TypeDiscriminator { 44 | private Class typeHoldingTypeField; 45 | private String value; 46 | 47 | TypeDiscriminator(Class typeHoldingTypeField, String value) { 48 | Validate.assertNotNull(typeHoldingTypeField, value); 49 | this.typeHoldingTypeField = typeHoldingTypeField; 50 | this.value = value; 51 | } 52 | 53 | @Override public int hashCode() { 54 | return 31 * (31 + typeHoldingTypeField.hashCode()) + value.hashCode(); 55 | } 56 | 57 | @Override public boolean equals(Object obj) { 58 | if (obj instanceof TypeDiscriminator) { 59 | TypeDiscriminator other = (TypeDiscriminator)obj; 60 | //fields are never null: 61 | return typeHoldingTypeField.equals(other.typeHoldingTypeField) && value.equals(other.value); 62 | } 63 | return false; 64 | } 65 | } 66 | 67 | /** 68 | * @param Add the interface to the registry. The interface should have a {@link TypeValue} annotation, and there should be a {@link TypeField} annotation 69 | * on the interface or its parents. 70 | */ 71 | public TypeRegistry add(Class type) { 72 | Validate.assertArgument(type.isInterface(), "Not an interface: %s", type.getName()); 73 | if (!typeFields.containsKey(type)) { 74 | Class typeHoldingTypeField = findTypeHoldingTypeField(type); 75 | Validate.assertArgument(typeHoldingTypeField != null, "The type and its supertypes don't have a @TypeField annotation: %s", type.getName()); 76 | typeFields.put(type, typeHoldingTypeField); 77 | registerTypeValue(type, typeHoldingTypeField); 78 | } 79 | return this; 80 | } 81 | 82 | 83 | 84 | 85 | private Class findTypeHoldingTypeField(Class type) { 86 | Class typeHoldingTypeField = type.getAnnotation(TypeField.class) == null ? null : type; 87 | for (Class parentType: type.getInterfaces()) { 88 | Class parentTypeHoldingTypeField = findTypeHoldingTypeField(parentType); 89 | Validate.assertArgument(parentTypeHoldingTypeField == null || typeHoldingTypeField == null || parentTypeHoldingTypeField == typeHoldingTypeField, "You have multiple TypeField annotations in your class-hierarchy for %s", type.getName()); 90 | if (typeHoldingTypeField == null) 91 | typeHoldingTypeField = parentTypeHoldingTypeField; 92 | } 93 | return typeHoldingTypeField; 94 | } 95 | 96 | private void registerTypeValue(Class type, Class typeHoldingTypeField) { 97 | TypeValue typeValue = type.getAnnotation(TypeValue.class); 98 | Validate.assertArgument(typeValue != null, "The type does not have a @TypeValue annotation: %s", type.getName()); 99 | typeDiscriminators.put(new TypeRegistry.TypeDiscriminator(typeHoldingTypeField, typeValue.value()), type); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/modules/typedgraph/TypeValue.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.modules.typedgraph; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * Interface annotation for marking the Element property-value that may contain type information. 10 | * 11 | * @see TypeField 12 | */ 13 | @Retention(RetentionPolicy.RUNTIME) 14 | @Target(ElementType.TYPE) 15 | public @interface TypeValue { 16 | public String value(); 17 | } -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/modules/typedgraph/TypedGraphModuleBuilder.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.modules.typedgraph; 2 | 3 | import com.tinkerpop.frames.FramedGraphConfiguration; 4 | import com.tinkerpop.frames.modules.AbstractModule; 5 | import com.tinkerpop.frames.modules.Module; 6 | 7 | /** 8 | * TODO 9 | */ 10 | public class TypedGraphModuleBuilder { 11 | private TypeRegistry typeRegistry = new TypeRegistry(); 12 | 13 | public TypedGraphModuleBuilder() { 14 | 15 | } 16 | 17 | public TypedGraphModuleBuilder withClass(Class type) { 18 | typeRegistry.add(type); 19 | return this; 20 | } 21 | 22 | public Module build() { 23 | final TypeManager manager = new TypeManager(typeRegistry); 24 | return new AbstractModule() { 25 | 26 | @Override 27 | public void doConfigure(FramedGraphConfiguration config) { 28 | config.addTypeResolver(manager); 29 | config.addFrameInitializer(manager); 30 | } 31 | }; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/structures/FramedEdgeIterable.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.structures; 2 | 3 | import java.util.Iterator; 4 | 5 | import com.tinkerpop.blueprints.Direction; 6 | import com.tinkerpop.blueprints.Edge; 7 | import com.tinkerpop.blueprints.Graph; 8 | import com.tinkerpop.frames.FramedGraph; 9 | import com.tinkerpop.frames.InVertex; 10 | 11 | /** 12 | * @author Marko A. Rodriguez (http://markorodriguez.com) 13 | */ 14 | public class FramedEdgeIterable implements Iterable { 15 | protected final Class kind; 16 | protected final Direction direction; 17 | protected final Iterable iterable; 18 | protected final FramedGraph framedGraph; 19 | 20 | /** 21 | * @deprecated Use {@link #FramedEdgeIterable(FramedGraph, Iterable, Class)}, in combination with {@link InVertex} and {@link OutVertex}. 22 | */ 23 | public FramedEdgeIterable(final FramedGraph framedGraph, final Iterable iterable, final Direction direction, final Class kind) { 24 | this.framedGraph = framedGraph; 25 | this.iterable = iterable; 26 | this.kind = kind; 27 | this.direction = direction; 28 | } 29 | 30 | public FramedEdgeIterable(final FramedGraph framedGraph, final Iterable iterable, final Class kind) { 31 | this.framedGraph = framedGraph; 32 | this.iterable = iterable; 33 | this.kind = kind; 34 | this.direction = Direction.OUT; 35 | } 36 | 37 | public Iterator iterator() { 38 | return new Iterator() { 39 | 40 | private final Iterator iterator = iterable.iterator(); 41 | 42 | public void remove() { 43 | throw new UnsupportedOperationException(); 44 | } 45 | 46 | public boolean hasNext() { 47 | return this.iterator.hasNext(); 48 | } 49 | 50 | public T next() { 51 | return framedGraph.frame(this.iterator.next(), direction, kind); 52 | } 53 | }; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/structures/FramedVertexIterable.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.structures; 2 | 3 | import com.tinkerpop.blueprints.Graph; 4 | import com.tinkerpop.blueprints.Vertex; 5 | import com.tinkerpop.frames.FramedGraph; 6 | 7 | import java.util.Iterator; 8 | 9 | /** 10 | * @author Marko A. Rodriguez (http://markorodriguez.com) 11 | */ 12 | public class FramedVertexIterable implements Iterable { 13 | protected final Class kind; 14 | protected final Iterable iterable; 15 | protected final FramedGraph framedGraph; 16 | 17 | public FramedVertexIterable(final FramedGraph framedGraph, final Iterable iterable, final Class kind) { 18 | this.framedGraph = framedGraph; 19 | this.iterable = iterable; 20 | this.kind = kind; 21 | } 22 | 23 | public Iterator iterator() { 24 | return new Iterator() { 25 | private Iterator iterator = iterable.iterator(); 26 | 27 | public void remove() { 28 | throw new UnsupportedOperationException(); 29 | } 30 | 31 | public boolean hasNext() { 32 | return this.iterator.hasNext(); 33 | } 34 | 35 | public T next() { 36 | return framedGraph.frame(this.iterator.next(), kind); 37 | } 38 | }; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/structures/FramedVertexMap.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.structures; 2 | 3 | import com.tinkerpop.blueprints.Graph; 4 | import com.tinkerpop.blueprints.Vertex; 5 | import com.tinkerpop.frames.FramedGraph; 6 | 7 | import java.util.Collection; 8 | import java.util.HashSet; 9 | import java.util.LinkedHashSet; 10 | import java.util.Map; 11 | import java.util.Set; 12 | 13 | /** 14 | * @author Marko A. Rodriguez (http://markorodriguez.com) 15 | */ 16 | public class FramedVertexMap implements Map { 17 | 18 | private final Map map; 19 | protected final Class kind; 20 | protected final FramedGraph framedGraph; 21 | 22 | public FramedVertexMap(final FramedGraph framedGraph, final Map map, final Class kind) { 23 | this.framedGraph = framedGraph; 24 | this.map = map; 25 | this.kind = kind; 26 | } 27 | 28 | public Object get(final Object key) { 29 | return this.map.get(key); 30 | } 31 | 32 | public Object remove(final Object key) { 33 | return this.map.remove(key); 34 | } 35 | 36 | public int size() { 37 | return this.map.size(); 38 | } 39 | 40 | public boolean isEmpty() { 41 | return this.map.isEmpty(); 42 | } 43 | 44 | public Object put(final T key, final Object value) { 45 | throw new UnsupportedOperationException(); 46 | } 47 | 48 | public void putAll(final Map otherMap) { 49 | throw new UnsupportedOperationException(); 50 | } 51 | 52 | public boolean containsValue(final Object value) { 53 | return this.map.containsValue(value); 54 | } 55 | 56 | public boolean containsKey(final Object key) { 57 | return this.map.containsKey(key); 58 | } 59 | 60 | public Set keySet() { 61 | return new FramedVertexSet(framedGraph, this.map.keySet(), kind); 62 | } 63 | 64 | public Collection values() { 65 | return this.map.values(); 66 | } 67 | 68 | public Set> entrySet() { 69 | final Set> entries = new LinkedHashSet>(); 70 | for (final Entry entry : this.map.entrySet()) { 71 | entries.add(new FramedEntry(entry)); 72 | } 73 | return entries; 74 | } 75 | 76 | public void clear() { 77 | this.map.clear(); 78 | } 79 | 80 | private class FramedEntry implements Entry { 81 | 82 | private final Entry entry; 83 | 84 | public FramedEntry(final Entry entry) { 85 | this.entry = entry; 86 | } 87 | 88 | public Object setValue(final Object object) { 89 | return this.entry.setValue(object); 90 | } 91 | 92 | public Object getValue() { 93 | return entry.getValue(); 94 | } 95 | 96 | public T getKey() { 97 | return (T) framedGraph.frame(entry.getKey(), kind); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/structures/FramedVertexSet.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.structures; 2 | 3 | import com.tinkerpop.blueprints.Graph; 4 | import com.tinkerpop.blueprints.Vertex; 5 | import com.tinkerpop.frames.FramedGraph; 6 | 7 | import java.util.Collection; 8 | import java.util.Iterator; 9 | import java.util.Set; 10 | 11 | /** 12 | * @author Marko A. Rodriguez (http://markorodriguez.com) 13 | */ 14 | public class FramedVertexSet implements Set { 15 | protected final Class kind; 16 | protected final Set set; 17 | protected final FramedGraph framedGraph; 18 | 19 | public FramedVertexSet(final FramedGraph framedGraph, final Set set, final Class kind) { 20 | this.framedGraph = framedGraph; 21 | this.set = set; 22 | this.kind = kind; 23 | } 24 | 25 | public boolean contains(final Object object) { 26 | return this.set.contains(object); 27 | } 28 | 29 | public boolean containsAll(final Collection collection) { 30 | return this.set.containsAll(collection); 31 | } 32 | 33 | public boolean add(T t) { 34 | throw new UnsupportedOperationException(); 35 | } 36 | 37 | public boolean isEmpty() { 38 | return this.set.isEmpty(); 39 | } 40 | 41 | public boolean addAll(final Collection collection) { 42 | throw new UnsupportedOperationException(); 43 | } 44 | 45 | public boolean retainAll(final Collection collection) { 46 | return this.set.retainAll(collection); 47 | } 48 | 49 | public boolean remove(final Object object) { 50 | return this.set.remove(object); 51 | } 52 | 53 | public boolean removeAll(final Collection collection) { 54 | return this.set.removeAll(collection); 55 | } 56 | 57 | public void clear() { 58 | this.set.clear(); 59 | } 60 | 61 | public int size() { 62 | return this.set.size(); 63 | } 64 | 65 | public Object[] toArray() { 66 | throw new UnsupportedOperationException(); 67 | } 68 | 69 | public T[] toArray(T[] array) { 70 | throw new UnsupportedOperationException(); 71 | } 72 | 73 | public Iterator iterator() { 74 | return new Iterator() { 75 | private Iterator iterator = set.iterator(); 76 | 77 | public void remove() { 78 | throw new UnsupportedOperationException(); 79 | } 80 | 81 | public boolean hasNext() { 82 | return this.iterator.hasNext(); 83 | } 84 | 85 | public T next() { 86 | return framedGraph.frame(this.iterator.next(), kind); 87 | } 88 | }; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/util/ExceptionUtils.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.util; 2 | 3 | 4 | public class ExceptionUtils { 5 | 6 | public static void sneakyThrow(final Throwable checkedException) { 7 | ExceptionUtils. thrownInsteadOf(checkedException); 8 | } 9 | 10 | @SuppressWarnings("unchecked") 11 | private static void thrownInsteadOf(Throwable t) throws T { 12 | throw (T) t; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/tinkerpop/frames/util/Validate.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.util; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.PrintStream; 5 | 6 | /** 7 | * Helper methods for validating input parameters and state. 8 | */ 9 | public final class Validate { 10 | public static void assertArgument(boolean assertionResult, String message, Object... args) { 11 | if (!assertionResult) 12 | throw new IllegalArgumentException(format(message, args)); 13 | } 14 | 15 | public static void assertNotNull(Object... args) { 16 | for (Object arg: args) 17 | if (arg == null) 18 | throw new NullPointerException(); 19 | } 20 | 21 | public static String format(String message, Object... args) { 22 | ByteArrayOutputStream msgStream = new ByteArrayOutputStream(); 23 | new PrintStream(msgStream, true).printf(message, args); 24 | return msgStream.toString(); 25 | } 26 | } -------------------------------------------------------------------------------- /src/test/java/com/tinkerpop/frames/ClassUtilitiesTest.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames; 2 | 3 | import junit.framework.TestCase; 4 | 5 | public class ClassUtilitiesTest extends TestCase { 6 | public void testGetGenericClassForParametrizedType() throws SecurityException, NoSuchMethodException { 7 | assertEquals(Clazz.class, ClassUtilities.getGenericClass(ClassUtilitiesTest.class.getMethod("getSomething", Class.class))); 8 | } 9 | 10 | public static class Clazz {} 11 | 12 | public Iterable getSomething(Class clazz) { 13 | return null; 14 | } 15 | } -------------------------------------------------------------------------------- /src/test/java/com/tinkerpop/frames/FrameInitializerTest.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames; 2 | 3 | import com.tinkerpop.blueprints.Element; 4 | import com.tinkerpop.blueprints.Graph; 5 | import com.tinkerpop.blueprints.impls.tg.TinkerGraphFactory; 6 | import com.tinkerpop.frames.domain.classes.Person; 7 | import com.tinkerpop.frames.domain.incidences.Knows; 8 | import com.tinkerpop.frames.modules.AbstractModule; 9 | 10 | import org.junit.Before; 11 | import org.junit.Test; 12 | 13 | import static org.junit.Assert.assertEquals; 14 | import static org.junit.Assert.assertNotNull; 15 | 16 | /** 17 | * @author Bryn Cooke 18 | */ 19 | public class FrameInitializerTest { 20 | 21 | private FramedGraph framedGraph; 22 | 23 | @Before 24 | public void setup() { 25 | Graph graph = TinkerGraphFactory.createTinkerGraph(); 26 | framedGraph = new FramedGraphFactory(new AbstractModule(){ 27 | @Override 28 | protected void doConfigure(FramedGraphConfiguration config) { 29 | config.addFrameInitializer(nameDefaulter); 30 | config.addFrameInitializer(weightDefaulter); 31 | } 32 | }).create(graph); 33 | 34 | } 35 | 36 | @Test 37 | public void testDeprecatedRegistration() { 38 | Graph graph = TinkerGraphFactory.createTinkerGraph(); 39 | FramedGraph framedGraph = new FramedGraph(graph); 40 | framedGraph.registerFrameInitializer(nameDefaulter); 41 | Person person = framedGraph.addVertex(null, Person.class); 42 | assertEquals("Defaulted", person.getName()); 43 | 44 | } 45 | 46 | 47 | @Test 48 | public void testVertexInitialization() { 49 | Person person = framedGraph.addVertex(null, Person.class); 50 | assertEquals("Defaulted", person.getName()); 51 | } 52 | 53 | @Test 54 | public void testEdgeInitialization() { 55 | Person person1 = framedGraph.addVertex(null, Person.class); 56 | Person person2 = framedGraph.addVertex(null, Person.class); 57 | person1.addKnows(person2); 58 | assertEquals(Float.valueOf(1.0f), person1.getKnows().iterator().next().getWeight()); 59 | } 60 | 61 | public static FrameInitializer nameDefaulter = new FrameInitializer() { 62 | 63 | @Override 64 | public void initElement(Class kind, FramedGraph framedGraph, Element element) { 65 | if (kind == Person.class) { 66 | assertNotNull(framedGraph); 67 | element.setProperty("name", "Defaulted"); 68 | } 69 | } 70 | }; 71 | 72 | public static FrameInitializer weightDefaulter = new FrameInitializer() { 73 | 74 | @Override 75 | public void initElement(Class kind, FramedGraph framedGraph, Element element) { 76 | assertNotNull(framedGraph); 77 | if (kind == Knows.class) { 78 | element.setProperty("weight", 1.0f); 79 | } 80 | } 81 | }; 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/test/java/com/tinkerpop/frames/FramedElementTest.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertNull; 5 | 6 | import org.junit.Test; 7 | 8 | import com.tinkerpop.blueprints.Direction; 9 | import com.tinkerpop.blueprints.Graph; 10 | import com.tinkerpop.blueprints.impls.tg.TinkerGraph; 11 | import com.tinkerpop.blueprints.impls.tg.TinkerGraphFactory; 12 | import com.tinkerpop.frames.domain.classes.Person; 13 | import com.tinkerpop.frames.domain.classes.Project; 14 | import com.tinkerpop.frames.domain.incidences.Created; 15 | import com.tinkerpop.frames.domain.incidences.CreatedBy; 16 | import com.tinkerpop.frames.domain.incidences.CreatedInfo; 17 | 18 | /** 19 | * @author Marko A. Rodriguez (http://markorodriguez.com) 20 | */ 21 | public class FramedElementTest { 22 | 23 | @Test 24 | public void testGettingProperties() { 25 | Graph graph = TinkerGraphFactory.createTinkerGraph(); 26 | FramedGraph framedGraph = new FramedGraphFactory().create(graph); 27 | 28 | Person marko = framedGraph.getVertex(1, Person.class); 29 | assertEquals(marko.getName(), "marko"); 30 | assertEquals(marko.getAge(), new Integer(29)); 31 | 32 | Project lop = framedGraph.getVertex(3, Project.class); 33 | assertEquals(lop.getName(), "lop"); 34 | assertEquals(lop.getLanguage(), "java"); 35 | 36 | CreatedInfo markoCreatedLopInfo = framedGraph.getEdge(9, CreatedInfo.class); 37 | assertEquals(markoCreatedLopInfo.getWeight(), 0.4f, 0.1f); 38 | //Same with using deprecated Domain/Range annotations: 39 | Created markoCreatedLop = framedGraph.getEdge(9, Direction.OUT, Created.class); 40 | assertEquals(markoCreatedLop.getWeight(), 0.4f, 0.1f); 41 | CreatedBy lopCreatedByMarko = framedGraph.getEdge(9, Direction.IN, CreatedBy.class); 42 | assertEquals(lopCreatedByMarko.getWeight(), 0.4f, 0.1f); 43 | 44 | Person temp = framedGraph.frame(graph.addVertex(null), Person.class); 45 | assertNull(temp.getName()); 46 | assertNull(temp.getAge()); 47 | 48 | } 49 | 50 | @Test 51 | public void testSettingProperties() { 52 | Graph graph = TinkerGraphFactory.createTinkerGraph(); 53 | FramedGraph framedGraph = new FramedGraphFactory().create(graph); 54 | 55 | Person marko = framedGraph.getVertex(1, Person.class); 56 | assertEquals(marko.getName(), "marko"); 57 | marko.setName("pavel"); 58 | assertEquals(marko.getName(), "pavel"); 59 | assertEquals(marko.getAge(), new Integer(29)); 60 | marko.setAge(31); 61 | assertEquals(marko.getAge(), new Integer(31)); 62 | 63 | CreatedInfo markoCreatedLopInfo = framedGraph.getEdge(9, CreatedInfo.class); 64 | assertEquals(markoCreatedLopInfo.getWeight(), 0.4f, 0.1f); 65 | markoCreatedLopInfo.setWeight(99.0f); 66 | assertEquals(markoCreatedLopInfo.getWeight(), 99.0f, 0.1f); 67 | markoCreatedLopInfo.setWeight(0.4f); 68 | 69 | //Same with deprecated Domain/Range annotations: 70 | Created markoCreatedLop = framedGraph.getEdge(9, Direction.OUT, Created.class); 71 | assertEquals(markoCreatedLop.getWeight(), 0.4f, 0.1f); 72 | markoCreatedLop.setWeight(99.0f); 73 | assertEquals(markoCreatedLop.getWeight(), 99.0f, 0.1f); 74 | } 75 | 76 | @Test 77 | public void testRemoveProperties() { 78 | Graph graph = TinkerGraphFactory.createTinkerGraph(); 79 | FramedGraph framedGraph = new FramedGraphFactory().create(graph); 80 | 81 | Person marko = framedGraph.getVertex(1, Person.class); 82 | assertEquals(marko.getAge(), new Integer(29)); 83 | marko.removeAge(); 84 | assertNull(marko.getAge()); 85 | } 86 | 87 | @Test 88 | public void testSetPropertiesToNull() { 89 | Graph graph = TinkerGraphFactory.createTinkerGraph(); 90 | FramedGraph framedGraph = new FramedGraphFactory().create(graph); 91 | 92 | Person marko = framedGraph.getVertex(1, Person.class); 93 | assertEquals(marko.getAge(), new Integer(29)); 94 | marko.setAge(null); 95 | assertNull(marko.getAge()); 96 | } 97 | 98 | @Test 99 | public void testEnumProperty() { 100 | Graph graph = TinkerGraphFactory.createTinkerGraph(); 101 | FramedGraph framedGraph = new FramedGraphFactory().create(graph); 102 | 103 | Person marko = framedGraph.getVertex(1, Person.class); 104 | assertEquals(marko.getGender(), null); 105 | marko.setGender(Person.Gender.MALE); 106 | assertEquals(Person.Gender.MALE, marko.getGender()); 107 | marko.setGender(null); 108 | assertEquals(null, marko.getGender()); 109 | marko.setGender(Person.Gender.MALE); 110 | marko.removeGender(); 111 | assertEquals(marko.getGender(), null); 112 | } 113 | 114 | @Test 115 | public void testToString() { 116 | Graph graph = TinkerGraphFactory.createTinkerGraph(); 117 | FramedGraph framedGraph = new FramedGraphFactory().create(graph); 118 | 119 | Person marko = framedGraph.getVertex(1, Person.class); 120 | assertEquals("v[1]", marko.toString()); 121 | 122 | CreatedInfo markoCreatedLopInfo = framedGraph.getEdge(9, CreatedInfo.class); 123 | assertEquals("e[9][1-created->3]", markoCreatedLopInfo.toString()); 124 | //Using deprecated Domain/Range annotations: 125 | Created markoCreatedLop = framedGraph.getEdge(9, Direction.OUT, Created.class); 126 | assertEquals("e[9][1-created->3]", markoCreatedLop.toString()); 127 | } 128 | 129 | @Test 130 | public void testEquality() { 131 | TinkerGraph graph = TinkerGraphFactory.createTinkerGraph(); 132 | FramedGraph framedGraph = new FramedGraphFactory().create(graph); 133 | 134 | assertEquals(framedGraph.getVertex(1, Person.class), framedGraph.frame(graph.getVertex(1), Person.class)); 135 | 136 | } 137 | 138 | @Test(expected=UnhandledMethodException.class) 139 | public void testUnhandledMethodNoAnnotation() { 140 | Graph graph = TinkerGraphFactory.createTinkerGraph(); 141 | FramedGraph framedGraph = new FramedGraphFactory().create(graph); 142 | 143 | Person marko = framedGraph.getVertex(1, Person.class); 144 | marko.unhandledNoAnnotation(); 145 | } 146 | 147 | @Test(expected=UnhandledMethodException.class) 148 | public void testUnhandledMethodWithAnnotation() { 149 | Graph graph = TinkerGraphFactory.createTinkerGraph(); 150 | FramedGraph framedGraph = new FramedGraphFactory().create(graph); 151 | 152 | Person marko = framedGraph.getVertex(1, Person.class); 153 | marko.unhandledNoHandler(); 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /src/test/java/com/tinkerpop/frames/FramedGraphFactoryTest.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames; 2 | 3 | import junit.framework.Assert; 4 | 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | import org.mockito.Mockito; 8 | import org.mockito.internal.stubbing.answers.ReturnsArgumentAt; 9 | 10 | import com.tinkerpop.blueprints.Graph; 11 | import com.tinkerpop.blueprints.TransactionalGraph; 12 | import com.tinkerpop.blueprints.Vertex; 13 | import com.tinkerpop.frames.modules.Module; 14 | 15 | public class FramedGraphFactoryTest { 16 | 17 | private Module mockModule; 18 | private Graph base; 19 | 20 | 21 | @Before 22 | public void setup() { 23 | mockModule = Mockito.mock(Module.class); 24 | base = Mockito.mock(Graph.class); 25 | } 26 | 27 | @Test 28 | public void testFactory() { 29 | 30 | Mockito.when(mockModule.configure(Mockito.any(Graph.class), Mockito.any(FramedGraphConfiguration.class))).then(new ReturnsArgumentAt(0)); 31 | FramedGraphFactory graphFactory = new FramedGraphFactory(mockModule); 32 | 33 | FramedGraph framed = graphFactory.create(base); 34 | Assert.assertEquals(base, framed.getBaseGraph()); 35 | 36 | Mockito.verify(mockModule, Mockito.times(1)).configure(Mockito.any(Graph.class), Mockito.any(FramedGraphConfiguration.class)); 37 | 38 | TransactionalGraph baseTransactional = Mockito.mock(TransactionalGraph.class); 39 | FramedTransactionalGraph framedTransactional = graphFactory.create(baseTransactional); 40 | Assert.assertEquals(baseTransactional, framedTransactional.getBaseGraph()); 41 | 42 | Mockito.verify(mockModule, Mockito.times(2)).configure(Mockito.any(TransactionalGraph.class), Mockito.any(FramedGraphConfiguration.class)); 43 | } 44 | 45 | @Test 46 | public void testWrapping() { 47 | Graph wrapper = Mockito.mock(Graph.class); 48 | Mockito.when(mockModule.configure(Mockito.any(Graph.class), Mockito.any(FramedGraphConfiguration.class))).thenReturn(wrapper); 49 | FramedGraphFactory graphFactory = new FramedGraphFactory(mockModule); 50 | FramedGraph framed = graphFactory.create(base); 51 | 52 | Mockito.verify(mockModule).configure(Mockito.any(Graph.class), Mockito.any(FramedGraphConfiguration.class)); 53 | 54 | //Unwrapping the graph should retrieve the base graph. 55 | Assert.assertEquals(base, framed.getBaseGraph()); 56 | 57 | //But using the framed graph should go through the wrappers installed by the module. 58 | Vertex vertex = Mockito.mock(Vertex.class); 59 | Mockito.when(wrapper.getVertex(1)).thenReturn(vertex); 60 | Assert.assertEquals(vertex, framed.getVertex(1)); 61 | } 62 | 63 | @Test(expected=UnsupportedOperationException.class) 64 | public void testWrappingError() { 65 | Graph wrapper = Mockito.mock(Graph.class); 66 | Mockito.when(mockModule.configure(Mockito.any(Graph.class), Mockito.any(FramedGraphConfiguration.class))).thenReturn(wrapper); 67 | FramedGraphFactory graphFactory = new FramedGraphFactory(mockModule); 68 | TransactionalGraph baseTransactional = Mockito.mock(TransactionalGraph.class); 69 | graphFactory.create(baseTransactional); 70 | } 71 | 72 | @Test 73 | public void testSubclassing() { 74 | MyFramedGraphFactory myFramedGraphFactory = new MyFramedGraphFactory(mockModule); 75 | Mockito.when(mockModule.configure(Mockito.any(Graph.class), Mockito.any(FramedGraphConfiguration.class))).then(new ReturnsArgumentAt(0)); 76 | MyFramedGraph create = myFramedGraphFactory.create(base); 77 | Assert.assertEquals(base, create.getBaseGraph()); 78 | } 79 | 80 | static class MyFramedGraph extends FramedGraph { 81 | 82 | protected MyFramedGraph(T baseGraph, FramedGraphConfiguration config) { 83 | super(baseGraph, config); 84 | } 85 | 86 | } 87 | 88 | 89 | static class MyFramedGraphFactory extends FramedGraphFactory { 90 | 91 | public MyFramedGraphFactory(Module... modules) { 92 | super(modules); 93 | } 94 | 95 | @Override 96 | public MyFramedGraph create(T baseGraph) { 97 | return new MyFramedGraph(baseGraph, getConfiguration(Graph.class, baseGraph)); 98 | } 99 | 100 | } 101 | 102 | 103 | } 104 | -------------------------------------------------------------------------------- /src/test/java/com/tinkerpop/frames/FramedTransactionalGraphTest.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames; 2 | 3 | import org.junit.Test; 4 | import org.mockito.Mockito; 5 | 6 | import com.tinkerpop.blueprints.TransactionalGraph; 7 | 8 | public class FramedTransactionalGraphTest { 9 | @Test 10 | public void testTransactions() { 11 | 12 | TransactionalGraph t = Mockito.mock(TransactionalGraph.class); 13 | FramedTransactionalGraph g = new FramedTransactionalGraph(t, new FramedGraphConfiguration()); 14 | g.commit(); 15 | Mockito.verify(t).commit(); 16 | Mockito.reset(t); 17 | 18 | g.rollback(); 19 | Mockito.verify(t).rollback(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/com/tinkerpop/frames/SailFramesTest.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames; 2 | 3 | import static junit.framework.Assert.assertEquals; 4 | import static junit.framework.Assert.assertNotNull; 5 | 6 | import org.junit.After; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | import org.openrdf.model.URI; 10 | import org.openrdf.model.impl.LiteralImpl; 11 | import org.openrdf.model.impl.URIImpl; 12 | import org.openrdf.model.vocabulary.RDFS; 13 | import org.openrdf.sail.Sail; 14 | import org.openrdf.sail.SailConnection; 15 | import org.openrdf.sail.memory.MemoryStore; 16 | 17 | import com.tinkerpop.blueprints.TransactionalGraph; 18 | import com.tinkerpop.blueprints.Vertex; 19 | import com.tinkerpop.blueprints.impls.sail.SailGraph; 20 | 21 | /** 22 | * @author Joshua Shinavier (http://fortytwo.net) 23 | */ 24 | public class SailFramesTest { 25 | private Sail sail; 26 | private SailGraph sailGraph; 27 | 28 | @Before 29 | public void setUp() throws Exception { 30 | sail = new MemoryStore(); 31 | sailGraph = new SailGraph(sail); 32 | } 33 | 34 | @After 35 | public void tearDown() throws Exception { 36 | sailGraph.shutdown(); 37 | } 38 | 39 | @Test 40 | public void testAll() throws Exception { 41 | URI planet = new URIImpl("http://example.org/terms/planet"); 42 | URI gasGiant = new URIImpl("http://example.org/terms/gasGiant"); 43 | URI narrower = new URIImpl("http://www.w3.org/2004/02/skos/core#narrower"); 44 | 45 | SailConnection sc = sail.getConnection(); 46 | try { 47 | sc.begin(); 48 | sc.addStatement(planet, RDFS.LABEL, new LiteralImpl("planet", "en")); 49 | sc.addStatement(gasGiant, RDFS.LABEL, new LiteralImpl("gas giant", "en")); 50 | sc.addStatement(planet, narrower, gasGiant); 51 | sc.commit(); 52 | } finally { 53 | sc.close(); 54 | } 55 | 56 | Vertex p = sailGraph.getVertex(planet.stringValue()); 57 | 58 | FramedGraph framedGraph = new FramedGraphFactory().create(sailGraph); 59 | Concept planetFrame = framedGraph.frame(p, Concept.class); 60 | assertNotNull(planetFrame); 61 | 62 | assertEquals("uri", planetFrame.getKind()); 63 | //assertEquals("...", planetFrame.getValue()); 64 | RDFFrame label = planetFrame.getLabel(); 65 | assertNotNull(label); 66 | assertEquals("literal", label.getKind()); 67 | assertEquals("en", label.getLang()); 68 | assertEquals("planet", label.getValue()); 69 | 70 | Iterable narrowerConcepts = planetFrame.getNarrower(); 71 | int counter = 0; 72 | for (Concept c : narrowerConcepts) { 73 | counter++; 74 | } 75 | assertEquals(counter, 1); 76 | 77 | Concept gasGiantFrame = narrowerConcepts.iterator().next(); 78 | label = gasGiantFrame.getLabel(); 79 | assertEquals("literal", label.getKind()); 80 | assertEquals("en", label.getLang()); 81 | assertEquals("gas giant", label.getValue()); 82 | } 83 | 84 | private interface RDFFrame { 85 | @Property("value") 86 | public String getValue(); 87 | 88 | @Property("kind") 89 | public String getKind(); 90 | 91 | @Property("type") 92 | public String getType(); 93 | 94 | @Property("lang") 95 | public String getLang(); 96 | } 97 | 98 | private interface Concept extends RDFFrame { 99 | @Adjacency(label = "http://www.w3.org/2004/02/skos/core#narrower") 100 | public Iterable getNarrower(); 101 | 102 | @Adjacency(label = "http://www.w3.org/2000/01/rdf-schema#label") 103 | public RDFFrame getLabel(); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/test/java/com/tinkerpop/frames/core/FramedGraphQueryImplTest.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.core; 2 | 3 | import static org.junit.Assert.assertFalse; 4 | import static org.mockito.Matchers.eq; 5 | import static org.mockito.Matchers.same; 6 | import static org.mockito.Mockito.mock; 7 | import static org.mockito.Mockito.stub; 8 | import static org.mockito.Mockito.times; 9 | import static org.mockito.Mockito.verify; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | import org.junit.Test; 15 | 16 | import com.tinkerpop.blueprints.Edge; 17 | import com.tinkerpop.blueprints.GraphQuery; 18 | import com.tinkerpop.blueprints.Predicate; 19 | import com.tinkerpop.blueprints.Query.Compare; 20 | import com.tinkerpop.blueprints.Vertex; 21 | import com.tinkerpop.frames.FramedGraph; 22 | import com.tinkerpop.frames.FramedGraphFactory; 23 | import com.tinkerpop.frames.domain.classes.Person; 24 | import com.tinkerpop.frames.domain.incidences.Knows; 25 | 26 | /** 27 | * @author Bryn Cooke 28 | * 29 | */ 30 | public class FramedGraphQueryImplTest { 31 | 32 | @Test 33 | public void testDelegation() { 34 | GraphQuery mockGraphQuery = mock(GraphQuery.class); 35 | FramedGraph framedGraph = new FramedGraphFactory().create(null); 36 | 37 | FramedGraphQueryImpl query = new FramedGraphQueryImpl(framedGraph, mockGraphQuery); 38 | stub(mockGraphQuery.has("")).toReturn(mockGraphQuery); 39 | query.has(""); 40 | verify(mockGraphQuery).has(""); 41 | 42 | 43 | stub(mockGraphQuery.has("", "bar")).toReturn(mockGraphQuery); 44 | query.has("", "bar"); 45 | verify(mockGraphQuery).has("", "bar"); 46 | 47 | 48 | Predicate predicate = new Predicate() { 49 | 50 | @Override 51 | public boolean evaluate(Object first, Object second) { 52 | return false; 53 | } 54 | }; 55 | stub(mockGraphQuery.has("", predicate, "bar")).toReturn(mockGraphQuery); 56 | query.has("", predicate, "bar"); 57 | verify(mockGraphQuery).has(eq(""), same(predicate), eq("bar")); 58 | 59 | 60 | stub(mockGraphQuery.has("", 2, Compare.EQUAL)).toReturn(mockGraphQuery); 61 | query.has("", 2, Compare.EQUAL); 62 | verify(mockGraphQuery).has(eq(""), same(2), eq(Compare.EQUAL)); 63 | 64 | stub(mockGraphQuery.hasNot("")).toReturn(mockGraphQuery); 65 | query.hasNot(""); 66 | verify(mockGraphQuery).hasNot(eq("")); 67 | 68 | stub(mockGraphQuery.hasNot("", "bar")).toReturn(mockGraphQuery); 69 | query.hasNot("", "bar"); 70 | verify(mockGraphQuery).hasNot(eq(""), eq("bar")); 71 | 72 | 73 | stub(mockGraphQuery.interval("", "bar", "bif")).toReturn(mockGraphQuery); 74 | query.interval("", "bar", "bif"); 75 | verify(mockGraphQuery).interval(eq(""), eq("bar"), eq("bif")); 76 | 77 | stub(mockGraphQuery.limit(1)).toReturn(mockGraphQuery); 78 | query.limit(1); 79 | verify(mockGraphQuery).limit(1); 80 | 81 | 82 | 83 | List v = new ArrayList(); 84 | stub(mockGraphQuery.vertices()).toReturn(v); 85 | query.vertices(); 86 | verify(mockGraphQuery).vertices(); 87 | 88 | Iterable people = query.vertices(Person.class); 89 | verify(mockGraphQuery, times(2)).vertices(); 90 | assertFalse(people.iterator().hasNext()); 91 | 92 | 93 | List e = new ArrayList(); 94 | stub(mockGraphQuery.edges()).toReturn(e); 95 | query.edges(); 96 | verify(mockGraphQuery).edges(); 97 | 98 | Iterable knows = query.edges(Knows.class); 99 | verify(mockGraphQuery, times(2)).edges(); 100 | assertFalse(knows.iterator().hasNext()); 101 | 102 | } 103 | 104 | 105 | } 106 | -------------------------------------------------------------------------------- /src/test/java/com/tinkerpop/frames/domain/classes/NamedObject.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.domain.classes; 2 | 3 | import com.tinkerpop.frames.Property; 4 | import com.tinkerpop.frames.VertexFrame; 5 | 6 | /** 7 | * @author Marko A. Rodriguez (http://markorodriguez.com) 8 | */ 9 | public interface NamedObject extends VertexFrame { 10 | 11 | @Property("name") 12 | public String getName(); 13 | 14 | @Property("name") 15 | public void setName(final String name); 16 | } 17 | -------------------------------------------------------------------------------- /src/test/java/com/tinkerpop/frames/domain/classes/Person.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.domain.classes; 2 | 3 | import java.util.Map; 4 | 5 | import com.tinkerpop.blueprints.Direction; 6 | import com.tinkerpop.blueprints.Vertex; 7 | import com.tinkerpop.frames.Adjacency; 8 | import com.tinkerpop.frames.Incidence; 9 | import com.tinkerpop.frames.Property; 10 | import com.tinkerpop.frames.annotations.gremlin.GremlinGroovy; 11 | import com.tinkerpop.frames.annotations.gremlin.GremlinParam; 12 | import com.tinkerpop.frames.domain.incidences.Created; 13 | import com.tinkerpop.frames.domain.incidences.CreatedInfo; 14 | import com.tinkerpop.frames.domain.incidences.Knows; 15 | import com.tinkerpop.frames.modules.javahandler.JavaHandler; 16 | import com.tinkerpop.frames.modules.javahandler.JavaHandlerContext; 17 | 18 | /** 19 | * @author Marko A. Rodriguez (http://markorodriguez.com) 20 | */ 21 | public interface Person extends NamedObject { 22 | enum Gender {FEMALE, MALE}; 23 | 24 | @Property("age") 25 | public Integer getAge(); 26 | 27 | @Property("age") 28 | public void setAge(Integer age); 29 | 30 | @Property("age") 31 | public void removeAge(); 32 | 33 | @Property("gender") 34 | public void setGender(Gender gender); 35 | 36 | @Property("gender") 37 | public Gender getGender(); 38 | 39 | @Property("gender") 40 | public void removeGender(); 41 | 42 | @Incidence(label = "knows") 43 | public Iterable getKnows(); 44 | 45 | @Adjacency(label = "knows") 46 | public Iterable getKnowsPeople(); 47 | 48 | @Adjacency(label = "knows") 49 | public void setKnowsPeople(final Iterable knows); 50 | 51 | @Incidence(label = "created") 52 | public Iterable getCreated(); 53 | 54 | @Incidence(label = "created") 55 | public Iterable getCreatedInfo(); 56 | 57 | @Adjacency(label = "created") 58 | public Iterable getCreatedProjects(); 59 | 60 | @Adjacency(label = "knows") 61 | public void addKnowsPerson(final Person person); 62 | 63 | @Adjacency(label = "knows") 64 | public Person addKnowsNewPerson(); 65 | 66 | @Incidence(label = "knows") 67 | public Knows addKnows(final Person person); 68 | 69 | @Adjacency(label = "created") 70 | public void addCreatedProject(final Project project); 71 | 72 | @Incidence(label = "created") 73 | public Created addCreated(final Project project); 74 | 75 | @Incidence(label = "created") 76 | public CreatedInfo addCreatedInfo(final Project project); 77 | 78 | @Adjacency(label = "knows") 79 | public void removeKnowsPerson(final Person person); 80 | 81 | @Incidence(label = "knows") 82 | public void removeKnows(final Knows knows); 83 | 84 | @Adjacency(label = "latestProject") 85 | public Project getLatestProject(); 86 | 87 | @Adjacency(label = "latestProject") 88 | public void setLatestProject(final Project latestProject); 89 | 90 | @GremlinGroovy("it.as('x').out('created').in('created').except('x')") 91 | public Iterable getCoCreators(); 92 | 93 | @GremlinGroovy("_().as('x').out('created').in('created').except('x').shuffle") 94 | public Person getRandomCoCreators(); 95 | 96 | @GremlinGroovy("_().as('x').out('created').in('created').except('x').has('age',age)") 97 | public Person getCoCreatorOfAge(@GremlinParam("age") int age); 98 | 99 | @GremlinGroovy(value = "'aStringProperty'", frame = false) 100 | public String getAStringProperty(); 101 | 102 | @GremlinGroovy(value = "['a','b','c']", frame = false) 103 | public Iterable getListOfStrings(); 104 | 105 | @GremlinGroovy("it.as('x').out('created').in('created').except('x').groupCount.cap.next()") 106 | public Map getRankedCoauthors(); 107 | 108 | @GremlinGroovy("person.asVertex().in('knows')") 109 | public Iterable getKnownRootedFromParam(@GremlinParam("person") Person person); 110 | 111 | @Deprecated 112 | @GremlinGroovy("_().out('knows')") 113 | public Iterable getDeprecatedKnowsPeople(); 114 | 115 | @Property("boolean") 116 | public void setBoolean(boolean b); 117 | 118 | @Property("boolean") 119 | public boolean isBooleanPrimitive(); 120 | 121 | @Property("boolean") 122 | public Boolean isBoolean(); 123 | 124 | @Property("boolean") 125 | public boolean canBooleanPrimitive(); 126 | 127 | @Property("boolean") 128 | public Boolean canBoolean(); 129 | 130 | @Adjacency(label = "knows", direction=Direction.BOTH) 131 | public void addKnowsPersonDirectionBothError(final Person person); 132 | 133 | @Adjacency(label = "knows", direction=Direction.BOTH) 134 | public void setKnowsPersonDirectionBothError(final Person person); 135 | 136 | @Incidence(label = "created", direction=Direction.BOTH) 137 | public Created addCreatedDirectionBothError(final Project project); 138 | 139 | @JavaHandler 140 | public String getNameAndAge(); 141 | 142 | @JavaHandler 143 | public Iterable getCoCreatorsJava(); 144 | 145 | @JavaHandler 146 | public void notImplemented(); 147 | 148 | 149 | abstract class Impl implements JavaHandlerContext, Person { 150 | 151 | @Override 152 | @JavaHandler 153 | public String getNameAndAge() { 154 | return getName() + " (" + getAge() + ")"; 155 | } 156 | 157 | @Override 158 | @JavaHandler 159 | public Iterable getCoCreatorsJava() { 160 | return frameVertices(gremlin().as("x").out("created").in("created").except("x")); 161 | 162 | } 163 | } 164 | 165 | 166 | public void unhandledNoAnnotation(); 167 | 168 | @GremlinGroovy("") 169 | public void unhandledNoHandler(); 170 | 171 | 172 | 173 | } 174 | -------------------------------------------------------------------------------- /src/test/java/com/tinkerpop/frames/domain/classes/Project.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.domain.classes; 2 | 3 | import com.tinkerpop.blueprints.Direction; 4 | import com.tinkerpop.frames.Adjacency; 5 | import com.tinkerpop.frames.Incidence; 6 | import com.tinkerpop.frames.Property; 7 | import com.tinkerpop.frames.domain.incidences.CreatedBy; 8 | import com.tinkerpop.frames.domain.incidences.CreatedInfo; 9 | import com.tinkerpop.frames.modules.javahandler.JavaHandler; 10 | import com.tinkerpop.frames.modules.javahandler.JavaHandlerClass; 11 | 12 | /** 13 | * @author Marko A. Rodriguez (http://markorodriguez.com) 14 | */ 15 | @JavaHandlerClass(ProjectImpl.class) 16 | public interface Project extends NamedObject { 17 | 18 | @Property("lang") 19 | public String getLanguage(); 20 | 21 | @Adjacency(label = "created", direction = Direction.IN) 22 | public Iterable getCreatedByPeople(); 23 | 24 | @Incidence(label = "created", direction = Direction.IN) 25 | public Iterable getCreatedBy(); 26 | 27 | @Incidence(label = "created", direction = Direction.IN) 28 | public Iterable getCreatedInfo(); 29 | 30 | @Adjacency(label = "created", direction = Direction.IN) 31 | public void removeCreatedByPerson(Person person); 32 | 33 | @Incidence(label = "created", direction = Direction.IN) 34 | public void removeCreatedBy(CreatedBy createdBy); 35 | 36 | @Incidence(label = "created", direction = Direction.IN) 37 | public void removeCreatedInfo(CreatedInfo createdBy); 38 | 39 | @Incidence(label = "created", direction = Direction.IN) 40 | public CreatedBy addCreatedByPersonIncidence(Person person); 41 | 42 | @Incidence(label = "created", direction = Direction.IN) 43 | public CreatedInfo addCreatedByPersonInfo(Person person); 44 | 45 | @Incidence(label = "created", direction = Direction.IN) 46 | public CreatedBy addCreatedInfo(CreatedInfo person); 47 | 48 | @Adjacency(label = "created", direction = Direction.IN) 49 | public void addCreatedByPersonAdjacency(Person person); 50 | 51 | @JavaHandler 52 | public String getLanguageUsingMixin(); 53 | 54 | } 55 | 56 | -------------------------------------------------------------------------------- /src/test/java/com/tinkerpop/frames/domain/classes/ProjectImpl.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.domain.classes; 2 | 3 | public abstract class ProjectImpl implements Project { 4 | @Override 5 | public String getLanguageUsingMixin() { 6 | 7 | return getLanguage(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/test/java/com/tinkerpop/frames/domain/incidences/Created.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.domain.incidences; 2 | 3 | import com.tinkerpop.frames.Domain; 4 | import com.tinkerpop.frames.EdgeFrame; 5 | import com.tinkerpop.frames.Property; 6 | import com.tinkerpop.frames.Range; 7 | import com.tinkerpop.frames.domain.classes.Person; 8 | import com.tinkerpop.frames.domain.classes.Project; 9 | 10 | /** 11 | * @author Marko A. Rodriguez (http://markorodriguez.com) 12 | */ 13 | public interface Created extends EdgeFrame { 14 | //Please note: Domain and Range are incorrectly annotated here, they should be inverted if you want this interface working 15 | // with @Incidence annotations. See FramedEdgeTest.testGettingDomainAndRange. 16 | 17 | @Domain 18 | public Project getDomain(); 19 | 20 | @Range 21 | public Person getRange(); 22 | 23 | @Property("weight") 24 | public Float getWeight(); 25 | 26 | @Property("weight") 27 | public void setWeight(float weight); 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/com/tinkerpop/frames/domain/incidences/CreatedBy.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.domain.incidences; 2 | 3 | import com.tinkerpop.frames.Domain; 4 | import com.tinkerpop.frames.Property; 5 | import com.tinkerpop.frames.Range; 6 | import com.tinkerpop.frames.domain.classes.Person; 7 | import com.tinkerpop.frames.domain.classes.Project; 8 | 9 | /** 10 | * @author Marko A. Rodriguez (http://markorodriguez.com) 11 | */ 12 | public interface CreatedBy { 13 | 14 | @Domain 15 | public Project getDomain(); 16 | 17 | @Range 18 | public Person getRange(); 19 | 20 | @Property("weight") 21 | public Float getWeight(); 22 | } 23 | -------------------------------------------------------------------------------- /src/test/java/com/tinkerpop/frames/domain/incidences/CreatedInfo.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.domain.incidences; 2 | 3 | import com.tinkerpop.frames.EdgeFrame; 4 | import com.tinkerpop.frames.InVertex; 5 | import com.tinkerpop.frames.OutVertex; 6 | import com.tinkerpop.frames.Property; 7 | import com.tinkerpop.frames.domain.classes.Person; 8 | import com.tinkerpop.frames.domain.classes.Project; 9 | 10 | /** 11 | * This class frames "created" edges (just like Created and CreatedBy), but uses 12 | * the {@link InVertex} and {@link OutVertex} annotations instead of the now deprecated 13 | * Source/Target. 14 | */ 15 | public interface CreatedInfo extends EdgeFrame { 16 | @OutVertex 17 | Person getPerson(); 18 | 19 | @InVertex 20 | Project getProject(); 21 | 22 | @Property("weight") 23 | public Float getWeight(); 24 | 25 | @Property("weight") 26 | public void setWeight(float weight); 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/com/tinkerpop/frames/domain/incidences/Knows.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.domain.incidences; 2 | 3 | import com.tinkerpop.blueprints.Edge; 4 | import com.tinkerpop.frames.Domain; 5 | import com.tinkerpop.frames.InVertex; 6 | import com.tinkerpop.frames.OutVertex; 7 | import com.tinkerpop.frames.Property; 8 | import com.tinkerpop.frames.Range; 9 | import com.tinkerpop.frames.domain.classes.Person; 10 | import com.tinkerpop.frames.modules.javahandler.JavaHandler; 11 | import com.tinkerpop.frames.modules.javahandler.JavaHandlerContext; 12 | 13 | /** 14 | * @author Marko A. Rodriguez (http://markorodriguez.com) 15 | */ 16 | public interface Knows { 17 | 18 | @Property("weight") 19 | public Float getWeight(); 20 | 21 | @Property("weight") 22 | public Float setWeight(float weight); 23 | 24 | @OutVertex 25 | public Person getOut(); 26 | 27 | 28 | @InVertex 29 | public Person getIn(); 30 | 31 | @Domain 32 | public Person getDomain(); 33 | 34 | @Range 35 | public Person getRange(); 36 | 37 | @JavaHandler 38 | public String getNames(); 39 | 40 | abstract class Impl implements Knows, JavaHandlerContext { 41 | 42 | @Override 43 | @JavaHandler 44 | public String getNames() { 45 | return getDomain().getName() + "<->" + getRange().getName(); 46 | } 47 | } 48 | 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/test/java/com/tinkerpop/frames/domain/incidences/WeightedEdge.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.domain.incidences; 2 | 3 | import com.tinkerpop.frames.EdgeFrame; 4 | import com.tinkerpop.frames.Property; 5 | 6 | /** 7 | * @author Mike Bryant (https://github.com/mikesname) 8 | */ 9 | public interface WeightedEdge extends EdgeFrame { 10 | @Property("weight") 11 | public Float getWeight(); 12 | 13 | @Property("weight") 14 | public void setWeight(float weight); 15 | } 16 | -------------------------------------------------------------------------------- /src/test/java/com/tinkerpop/frames/modules/AbstractModuleTest.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.modules; 2 | 3 | import junit.framework.Assert; 4 | 5 | import org.junit.Test; 6 | import org.mockito.Mockito; 7 | 8 | import com.tinkerpop.blueprints.Graph; 9 | import com.tinkerpop.blueprints.TransactionalGraph; 10 | import com.tinkerpop.frames.FramedGraphConfiguration; 11 | import com.tinkerpop.frames.modules.AbstractModule; 12 | 13 | public class AbstractModuleTest { 14 | 15 | @Test 16 | public void testNoWrapping() { 17 | Graph baseGraph = Mockito.mock(Graph.class); 18 | TransactionalGraph baseTransactionalGraph = Mockito.mock(TransactionalGraph.class); 19 | 20 | FramedGraphConfiguration config = new FramedGraphConfiguration(); 21 | AbstractModule module = Mockito.mock(AbstractModule.class); 22 | Mockito.when(module.doConfigure(Mockito.any(Graph.class), Mockito.any(FramedGraphConfiguration.class))).thenCallRealMethod(); 23 | 24 | 25 | Graph configuredGraph = module.configure(baseGraph, config); 26 | Assert.assertEquals(baseGraph, configuredGraph); 27 | Mockito.verify(module).doConfigure(Mockito.any(Graph.class), Mockito.any(FramedGraphConfiguration.class)); 28 | Mockito.verify(module).doConfigure(Mockito.any(FramedGraphConfiguration.class)); 29 | 30 | 31 | Mockito.reset(module); 32 | Mockito.when(module.doConfigure(Mockito.any(TransactionalGraph.class), Mockito.any(FramedGraphConfiguration.class))).thenCallRealMethod(); 33 | Graph configuredTransactionalGraph = module.configure(baseTransactionalGraph, config); 34 | Assert.assertEquals(baseTransactionalGraph, configuredTransactionalGraph); 35 | Mockito.verify(module).doConfigure(Mockito.any(TransactionalGraph.class), Mockito.any(FramedGraphConfiguration.class)); 36 | Mockito.verify(module).doConfigure(Mockito.any(FramedGraphConfiguration.class)); 37 | } 38 | 39 | 40 | @Test 41 | public void testWrapping() { 42 | Graph baseGraph = Mockito.mock(Graph.class); 43 | TransactionalGraph baseTransactionalGraph = Mockito.mock(TransactionalGraph.class); 44 | 45 | Graph wrappedGraph = Mockito.mock(Graph.class); 46 | TransactionalGraph wrappedTransactionalGraph = Mockito.mock(TransactionalGraph.class); 47 | 48 | FramedGraphConfiguration config = new FramedGraphConfiguration(); 49 | AbstractModule module = Mockito.mock(AbstractModule.class); 50 | Mockito.when(module.doConfigure(Mockito.any(Graph.class), Mockito.any(FramedGraphConfiguration.class))).thenReturn(wrappedGraph); 51 | 52 | 53 | Graph configuredGraph = module.configure(baseGraph, config); 54 | Assert.assertEquals(wrappedGraph, configuredGraph); 55 | 56 | 57 | Mockito.reset(module); 58 | Mockito.when(module.doConfigure(Mockito.any(TransactionalGraph.class), Mockito.any(FramedGraphConfiguration.class))).thenReturn(wrappedTransactionalGraph); 59 | Graph configuredTransactionalGraph = module.configure(baseTransactionalGraph, config); 60 | Assert.assertEquals(wrappedTransactionalGraph, configuredTransactionalGraph); 61 | 62 | 63 | 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/test/java/com/tinkerpop/frames/modules/TypeResolverTest.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.modules; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | 6 | import com.tinkerpop.blueprints.Edge; 7 | import com.tinkerpop.blueprints.Graph; 8 | import com.tinkerpop.blueprints.TransactionalGraph; 9 | import com.tinkerpop.blueprints.Vertex; 10 | import com.tinkerpop.blueprints.impls.tg.TinkerGraphFactory; 11 | import com.tinkerpop.frames.FramedGraph; 12 | import com.tinkerpop.frames.FramedGraphConfiguration; 13 | import com.tinkerpop.frames.FramedGraphFactory; 14 | import com.tinkerpop.frames.domain.classes.Person; 15 | import com.tinkerpop.frames.domain.incidences.Knows; 16 | import com.tinkerpop.frames.modules.AbstractModule; 17 | import com.tinkerpop.frames.modules.TypeResolver; 18 | 19 | /** 20 | * @author Bryn Cooke 21 | */ 22 | public class TypeResolverTest { 23 | 24 | private FramedGraph framedGraph; 25 | 26 | public static interface AdditionalVertex { 27 | 28 | } 29 | 30 | public static interface ExtendedPerson extends Person { 31 | 32 | } 33 | 34 | public static interface AdditionalEdge { 35 | 36 | } 37 | 38 | @Test 39 | public void testAdditionalTypes() { 40 | Graph graph = TinkerGraphFactory.createTinkerGraph(); 41 | FramedGraphFactory factory = new FramedGraphFactory(new AbstractModule() { 42 | 43 | @Override 44 | public void doConfigure(FramedGraphConfiguration config) { 45 | config.addTypeResolver(new TypeResolver() { 46 | 47 | @Override 48 | public Class[] resolveTypes(Edge e, Class defaultType) { 49 | 50 | return new Class[] { AdditionalEdge.class }; 51 | } 52 | 53 | @Override 54 | public Class[] resolveTypes(Vertex v, Class defaultType) { 55 | return new Class[] { AdditionalVertex.class }; 56 | } 57 | }); 58 | } 59 | }); 60 | framedGraph = factory.create(graph); 61 | 62 | Person marko = framedGraph.getVertex(1, Person.class); 63 | Assert.assertTrue(marko instanceof AdditionalVertex); 64 | Assert.assertFalse(marko instanceof AdditionalEdge); 65 | 66 | Knows knows = marko.getKnows().iterator().next(); 67 | Assert.assertTrue(knows instanceof AdditionalEdge); 68 | Assert.assertFalse(knows instanceof AdditionalVertex); 69 | 70 | } 71 | 72 | @Test 73 | public void testExtendedTypes() { 74 | Graph graph = TinkerGraphFactory.createTinkerGraph(); 75 | FramedGraphFactory factory = new FramedGraphFactory(new AbstractModule() { 76 | 77 | @Override 78 | public void doConfigure(FramedGraphConfiguration config) { 79 | config.addTypeResolver(new TypeResolver() { 80 | 81 | @Override 82 | public Class[] resolveTypes(Edge e, Class defaultType) { 83 | 84 | return new Class[0]; 85 | } 86 | 87 | @Override 88 | public Class[] resolveTypes(Vertex v, Class defaultType) { 89 | return new Class[] { ExtendedPerson.class }; 90 | } 91 | }); 92 | } 93 | 94 | }); 95 | framedGraph = factory.create(graph); 96 | 97 | Person marko = framedGraph.getVertex(1, Person.class); 98 | Assert.assertTrue(marko instanceof ExtendedPerson); 99 | 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /src/test/java/com/tinkerpop/frames/modules/javahandler/JavaHandlerTest.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.modules.javahandler; 2 | 3 | import java.util.HashSet; 4 | import java.util.Set; 5 | 6 | import junit.framework.Assert; 7 | 8 | import org.junit.Before; 9 | import org.junit.Test; 10 | 11 | import com.google.common.collect.Iterables; 12 | import com.google.common.collect.Sets; 13 | import com.tinkerpop.blueprints.Direction; 14 | import com.tinkerpop.blueprints.Vertex; 15 | import com.tinkerpop.blueprints.impls.tg.TinkerGraph; 16 | import com.tinkerpop.blueprints.impls.tg.TinkerGraphFactory; 17 | import com.tinkerpop.frames.FramedGraph; 18 | import com.tinkerpop.frames.FramedGraphFactory; 19 | import com.tinkerpop.frames.Property; 20 | import com.tinkerpop.frames.domain.classes.Person; 21 | import com.tinkerpop.frames.domain.classes.Project; 22 | import com.tinkerpop.frames.domain.incidences.Knows; 23 | 24 | /** 25 | * @author Bryn Cooke 26 | * 27 | */ 28 | public class JavaHandlerTest { 29 | 30 | private FramedGraph g; 31 | 32 | @Test 33 | public void testJavaHandlerVertices() { 34 | 35 | Person person = g.getVertex(1, Person.class); 36 | String profile = person.getNameAndAge(); 37 | Assert.assertEquals("marko (29)", profile); 38 | 39 | Person person2 = g.getVertex(2, Person.class); 40 | String profile2 = person2.getNameAndAge(); 41 | Assert.assertEquals("vadas (27)", profile2); 42 | 43 | Set coCreators = new HashSet(); 44 | 45 | Iterables.addAll(coCreators, person.getCoCreatorsJava()); 46 | Assert.assertEquals(Sets.newHashSet(g.getVertex(4), g.getVertex(6)), coCreators); 47 | 48 | } 49 | 50 | @Test 51 | public void testJavaHandlerEdges() { 52 | Knows knows = g.getEdge(7, Direction.OUT, Knows.class); 53 | Assert.assertEquals("marko<->vadas", knows.getNames()); 54 | } 55 | 56 | 57 | @Test 58 | public void testJavaHandlerClassAnnotation() { 59 | Project project = g.getVertex(5, Project.class); 60 | Assert.assertEquals("java", project.getLanguageUsingMixin()); 61 | } 62 | 63 | @Test(expected=JavaHandlerException.class) 64 | public void testMethodNotImplemented() { 65 | Person person = g.getVertex(1, Person.class); 66 | person.notImplemented(); 67 | } 68 | 69 | @Test 70 | public void testIntitializersVertices() { 71 | A a = g.addVertex(null, A.class); 72 | Assert.assertEquals("A", a.getProperty()); 73 | B b = g.addVertex(null, B.class); 74 | Assert.assertEquals("AB", b.getProperty()); 75 | C c = g.addVertex(null, C.class); 76 | Assert.assertTrue(c.getProperty().equals("ABCC2") || c.getProperty().equals("ABC2C")); 77 | } 78 | 79 | @Test 80 | public void testIntitializersEdges() { 81 | Vertex v = g.addVertex(null); 82 | 83 | A a = g.addEdge(null, v, v, "test", A.class); 84 | Assert.assertEquals("A", a.getProperty()); 85 | B b = g.addEdge(null, v, v, "test", B.class); 86 | Assert.assertEquals("AB", b.getProperty()); 87 | C c = g.addEdge(null, v, v, "test", C.class); 88 | Assert.assertTrue(c.getProperty().equals("ABCC2") || c.getProperty().equals("ABC2C")); 89 | } 90 | 91 | interface A { 92 | 93 | @Property("property") 94 | String getProperty(); 95 | 96 | @Property("property") 97 | void setProperty(String property); 98 | 99 | abstract class Impl implements A { 100 | @Initializer 101 | void init() { 102 | setProperty("A"); 103 | } 104 | } 105 | } 106 | 107 | interface B extends A { 108 | abstract class Impl implements B { 109 | @Initializer 110 | void init() { 111 | setProperty(getProperty() + "B"); 112 | } 113 | } 114 | } 115 | 116 | 117 | interface C extends A, B { 118 | abstract class Impl implements C { 119 | @Initializer 120 | void init() { 121 | setProperty(getProperty() + "C"); 122 | } 123 | 124 | @Initializer 125 | void init2() { 126 | setProperty(getProperty() + "C2"); 127 | } 128 | } 129 | } 130 | 131 | @Before 132 | public void setup() { 133 | TinkerGraph base = TinkerGraphFactory.createTinkerGraph(); 134 | g = new FramedGraphFactory(new JavaHandlerModule()).create(base); 135 | 136 | } 137 | 138 | 139 | } 140 | -------------------------------------------------------------------------------- /src/test/java/com/tinkerpop/frames/modules/typedgraph/TypeRegistryTest.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.modules.typedgraph; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertNull; 5 | 6 | import org.junit.Test; 7 | 8 | import com.tinkerpop.frames.modules.typedgraph.TypeField; 9 | import com.tinkerpop.frames.modules.typedgraph.TypeRegistry; 10 | import com.tinkerpop.frames.modules.typedgraph.TypeValue; 11 | 12 | public class TypeRegistryTest { 13 | @Test(expected = IllegalArgumentException.class) public void noAnotations() { 14 | //You can't register interfaces when there is no @TypeField on it or on any of the parents: 15 | new TypeRegistry().add(Empty.class); 16 | } 17 | 18 | @Test(expected = IllegalArgumentException.class) public void multipleTypeField() { 19 | //Only one type in the hierarchy can hold a @TypeField annotation: 20 | new TypeRegistry().add(MultipleTypeField.class); 21 | } 22 | 23 | @Test(expected = IllegalArgumentException.class) public void multipleTypeFieldInParents() { 24 | //Only one type in the hierarchy can hold a @TypeField annotation: 25 | new TypeRegistry().add(MultipleTypeFieldInParents.class); 26 | } 27 | 28 | @Test(expected = IllegalArgumentException.class) public void onlyTypeField() { 29 | new TypeRegistry().add(Abstract.class); 30 | } 31 | 32 | @Test(expected = IllegalArgumentException.class) public void onlyTypeField2() { 33 | new TypeRegistry().add(SubAbstract.class); 34 | } 35 | 36 | @Test public void registerDuplicate() { 37 | TypeRegistry builder = new TypeRegistry().add(A.class).add(A.class); 38 | assertEquals(1, builder.typeFields.size()); 39 | } 40 | 41 | @Test public void registerHierarchy() { 42 | TypeRegistry reg = new TypeRegistry().add(A.class).add(B.class); 43 | assertEquals(2, reg.typeFields.size()); 44 | assertEquals(2, reg.typeDiscriminators.size()); 45 | assertEquals(Abstract.class, reg.getTypeHoldingTypeField(A.class)); 46 | assertEquals(Abstract.class, reg.getTypeHoldingTypeField(B.class)); 47 | assertEquals(Abstract.class, reg.getTypeHoldingTypeField(Abstract.class)); 48 | assertNull(reg.getTypeHoldingTypeField(C.class)); 49 | 50 | reg.add(C.class); 51 | assertEquals(3, reg.typeFields.size()); 52 | assertEquals(3, reg.typeDiscriminators.size()); 53 | assertEquals(Abstract.class, reg.getTypeHoldingTypeField(C.class)); 54 | assertEquals(A.class, reg.getType(Abstract.class, "A")); 55 | assertEquals(B.class, reg.getType(Abstract.class, "B")); 56 | assertEquals(C.class, reg.getType(Abstract.class, "C")); 57 | } 58 | 59 | @Test public void registerParentsSeparately() { 60 | TypeRegistry reg = new TypeRegistry().add(C.class); 61 | //Allthough C extends A and B, registering C doesn't imply that A and B are also registered: 62 | assertEquals(1, reg.typeFields.size()); 63 | assertEquals(1, reg.typeDiscriminators.size()); 64 | assertNull(reg.getType(Abstract.class, "A")); 65 | } 66 | 67 | @Test public void registerMultipleHierarchies() { 68 | TypeRegistry reg = new TypeRegistry().add(A.class).add(B.class).add(C.class).add(X.class).add(Y.class); 69 | assertEquals(5, reg.typeFields.size()); 70 | assertEquals(5, reg.typeDiscriminators.size()); 71 | assertEquals(Abstract.class, reg.getTypeHoldingTypeField(C.class)); 72 | assertEquals(X.class, reg.getTypeHoldingTypeField(X.class)); 73 | assertEquals(X.class, reg.getTypeHoldingTypeField(Y.class)); 74 | assertEquals(A.class, reg.getType(Abstract.class, "A")); 75 | assertEquals(X.class, reg.getType(X.class, "X")); 76 | assertEquals(Y.class, reg.getType(X.class, "Y")); 77 | assertNull(reg.getType(X.class, "A")); 78 | } 79 | 80 | public static interface Empty {}; 81 | public static @TypeField("type") interface Abstract extends Empty {}; 82 | public static @TypeField("type") interface Abstract2 {}; 83 | public static interface SubAbstract extends Abstract {}; 84 | 85 | 86 | public static @TypeValue("multipleTypeField") @TypeField("type") interface MultipleTypeField extends Abstract{}; 87 | public static @TypeValue("multipleTypeFieldChildren") interface MultipleTypeFieldInParents extends Abstract, Abstract2{}; 88 | 89 | public static @TypeValue("A") interface A extends Abstract {}; 90 | public static @TypeValue("B") interface B extends Abstract {}; 91 | public static @TypeValue("C") interface C extends A, B {}; // diamond shape inheritance diagram (multiple paths from C to Abstract) 92 | 93 | public static @TypeValue("X") @TypeField("what") interface X {}; 94 | public static @TypeValue("Y") interface Y extends X {}; 95 | } -------------------------------------------------------------------------------- /src/test/java/com/tinkerpop/frames/modules/typedgraph/TypedGraphModuleTest.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.modules.typedgraph; 2 | 3 | import com.tinkerpop.frames.*; 4 | import junit.framework.TestCase; 5 | 6 | import com.tinkerpop.blueprints.Direction; 7 | import com.tinkerpop.blueprints.Edge; 8 | import com.tinkerpop.blueprints.Graph; 9 | import com.tinkerpop.blueprints.Vertex; 10 | import com.tinkerpop.blueprints.impls.tg.TinkerGraph; 11 | import com.tinkerpop.frames.modules.typedgraph.TypeField; 12 | import com.tinkerpop.frames.modules.typedgraph.TypeValue; 13 | import com.tinkerpop.frames.modules.typedgraph.TypedGraphModuleBuilder; 14 | 15 | 16 | public class TypedGraphModuleTest extends TestCase { 17 | public static @TypeField("type") 18 | interface Base { 19 | @Property("label") 20 | String getLabel(); 21 | }; 22 | 23 | public static @TypeValue("A") 24 | interface A extends Base { 25 | }; 26 | 27 | public static @TypeValue("B") 28 | interface B extends Base { 29 | }; 30 | 31 | public static @TypeValue("C") 32 | interface C extends B { 33 | @Property("label") 34 | void setLabel(String label); 35 | 36 | @InVertex 37 | T getInVertex(); 38 | }; 39 | 40 | public void testSerializeVertexType() { 41 | Graph graph = new TinkerGraph(); 42 | FramedGraphFactory factory = new FramedGraphFactory(new TypedGraphModuleBuilder().withClass(A.class).withClass(B.class) 43 | .withClass(C.class).build()); 44 | FramedGraph framedGraph = factory.create(graph); 45 | A a = framedGraph.addVertex(null, A.class); 46 | C c = framedGraph.addVertex(null, C.class); 47 | assertEquals("A", ((VertexFrame) a).asVertex().getProperty("type")); 48 | assertEquals("C", ((VertexFrame) c).asVertex().getProperty("type")); 49 | } 50 | 51 | public void testDeserializeVertexType() { 52 | Graph graph = new TinkerGraph(); 53 | FramedGraphFactory factory = new FramedGraphFactory(new TypedGraphModuleBuilder().withClass(A.class).withClass(B.class) 54 | .withClass(C.class).build()); 55 | FramedGraph framedGraph = factory.create(graph); 56 | Vertex cV = graph.addVertex(null); 57 | cV.setProperty("type", "C"); 58 | cV.setProperty("label", "C Label"); 59 | 60 | Base c = framedGraph.getVertex(cV.getId(), Base.class); 61 | assertTrue(c instanceof C); 62 | assertEquals("C Label", c.getLabel()); 63 | ((C) c).setLabel("new label"); 64 | assertEquals("new label", cV.getProperty("label")); 65 | } 66 | 67 | public void testSerializeEdgeType() { 68 | Graph graph = new TinkerGraph(); 69 | FramedGraphFactory factory = new FramedGraphFactory(new TypedGraphModuleBuilder().withClass(A.class).withClass(B.class) 70 | .withClass(C.class).build()); 71 | FramedGraph framedGraph = factory.create(graph); 72 | Vertex v1 = graph.addVertex(null); 73 | Vertex v2 = graph.addVertex(null); 74 | A a = framedGraph.addEdge(null, v1, v2, "label", Direction.OUT, A.class); 75 | C c = framedGraph.addEdge(null, v1, v2, "label", Direction.OUT, C.class); 76 | assertEquals("A", ((EdgeFrame) a).asEdge().getProperty("type")); 77 | assertEquals("C", ((EdgeFrame) c).asEdge().getProperty("type")); 78 | } 79 | 80 | public void testDeserializeEdgeType() { 81 | Graph graph = new TinkerGraph(); 82 | FramedGraphFactory factory = new FramedGraphFactory(new TypedGraphModuleBuilder().withClass(A.class).withClass(B.class) 83 | .withClass(C.class).build()); 84 | FramedGraph framedGraph = factory.create(graph); 85 | Vertex v1 = graph.addVertex(null); 86 | Vertex v2 = graph.addVertex(null); 87 | Edge cE = graph.addEdge(null, v1, v2, "label"); 88 | cE.setProperty("type", "C"); 89 | Base c = framedGraph.getEdge(cE.getId(), Direction.OUT, Base.class); 90 | assertTrue(c instanceof C); 91 | } 92 | 93 | public void testWildcard() { 94 | Graph graph = new TinkerGraph(); 95 | FramedGraphFactory factory = new FramedGraphFactory(new TypedGraphModuleBuilder().withClass(A.class).withClass(B.class) 96 | .withClass(C.class).build()); 97 | FramedGraph framedGraph = factory.create(graph); 98 | Vertex v1 = graph.addVertex(null); 99 | 100 | Vertex v2 = graph.addVertex(null); 101 | v2.setProperty("type", "A"); 102 | Edge cE = graph.addEdge(null, v1, v2, "label"); 103 | cE.setProperty("type", "C"); 104 | Base c = framedGraph.getEdge(cE.getId(), Direction.OUT, Base.class); 105 | assertTrue(c instanceof C); 106 | assertTrue(((C) c).getInVertex() instanceof A); 107 | 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/test/java/com/tinkerpop/frames/structures/FramedVertexSetTest.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.structures; 2 | 3 | import com.tinkerpop.blueprints.Graph; 4 | import com.tinkerpop.blueprints.Vertex; 5 | import com.tinkerpop.blueprints.impls.tg.TinkerGraphFactory; 6 | import com.tinkerpop.frames.FramedGraph; 7 | import com.tinkerpop.frames.domain.classes.Person; 8 | import junit.framework.TestCase; 9 | 10 | import java.util.HashSet; 11 | import java.util.Set; 12 | 13 | /** 14 | * @author Marko A. Rodriguez (http://markorodriguez.com) 15 | */ 16 | public class FramedVertexSetTest extends TestCase { 17 | 18 | public void testFramedSet() { 19 | Graph graph = TinkerGraphFactory.createTinkerGraph(); 20 | FramedGraph framedGraph = new FramedGraph(graph); 21 | Set vertices = new HashSet(); 22 | vertices.add(graph.getVertex(1)); 23 | vertices.add(graph.getVertex(4)); 24 | vertices.add(graph.getVertex(6)); 25 | FramedVertexSet set = new FramedVertexSet(framedGraph, vertices, Person.class); 26 | assertEquals(set.size(), 3); 27 | assertTrue(set.contains(graph.getVertex(1))); 28 | assertTrue(set.contains(graph.getVertex(4))); 29 | assertTrue(set.contains(graph.getVertex(6))); 30 | assertTrue(set.contains(framedGraph.frame(graph.getVertex(1), Person.class))); 31 | assertTrue(set.contains(framedGraph.frame(graph.getVertex(4), Person.class))); 32 | assertTrue(set.contains(framedGraph.frame(graph.getVertex(6), Person.class))); 33 | 34 | int counter = 0; 35 | for (Person person : set) { 36 | assertTrue(person.asVertex().getId().equals("1") || person.asVertex().getId().equals("4") || person.asVertex().getId().equals("6")); 37 | counter++; 38 | } 39 | assertEquals(counter, 3); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/test/java/com/tinkerpop/frames/util/ValidateTest.java: -------------------------------------------------------------------------------- 1 | package com.tinkerpop.frames.util; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import org.junit.Test; 6 | 7 | public class ValidateTest { 8 | @Test public void assertNotNull() { 9 | Validate.assertNotNull(); 10 | Validate.assertNotNull("x"); 11 | Validate.assertNotNull("x", "y"); 12 | } 13 | 14 | @Test(expected = NullPointerException.class) public void assertNotNullOneArg() { 15 | Validate.assertNotNull((Object)null); 16 | } 17 | 18 | @Test(expected = NullPointerException.class) public void assertMultipleArgs() { 19 | Validate.assertNotNull("x", null, "y"); 20 | } 21 | 22 | @Test public void assertArgument() { 23 | assertArgumentThrowCheck(null, true, "message"); 24 | assertArgumentThrowCheck(null, true, "message: %s", "x"); 25 | assertArgumentThrowCheck("message", false, "message"); 26 | assertArgumentThrowCheck("message: x", false, "message: %s", "x"); 27 | } 28 | 29 | private static void assertArgumentThrowCheck(String throwMessage, boolean assertionResult, String message, Object... args) { 30 | boolean success = false; 31 | try { 32 | Validate.assertArgument(assertionResult, message, args); 33 | success = true; 34 | } catch (IllegalArgumentException e) { 35 | assertEquals(throwMessage, e.getMessage()); 36 | } 37 | assertEquals(success, throwMessage == null); 38 | } 39 | 40 | 41 | @Test public void format() { 42 | assertEquals("aap - noot", Validate.format("%s - %s", "aap", "noot")); 43 | } 44 | 45 | } 46 | --------------------------------------------------------------------------------