├── .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 extends Animal> 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 extends Animal> 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 | *
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 | *
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 | *