Skip to content

Commit

Permalink
Frames 2.5.0 release.
Browse files Browse the repository at this point in the history
  • Loading branch information
okram committed Apr 14, 2014
1 parent 52d15a9 commit 387b8b9
Show file tree
Hide file tree
Showing 19 changed files with 1,007 additions and 6 deletions.
4 changes: 2 additions & 2 deletions CHANGELOG.textile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ h2. Frames 2.y.z
!https://github.com/tinkerpop/frames/raw/master/doc/images/frames-2.png!


h3. Version 2.5.0 (NOT OFFICIALLY RELEASED YET)
h3. Version 2.5.0 (April 14, 2014)

```xml
<dependency>
Expand All @@ -18,7 +18,7 @@ h3. Version 2.5.0 (NOT OFFICIALLY RELEASED YET)

==<hr/>==

h3. Version 2.4.1 (NOT OFFICIALLY RELEASED YET)
h3. Version 2.4.1 (August 10, 2013)

```xml
<dependency>
Expand Down
11 changes: 11 additions & 0 deletions doc/Acknowledgments.textile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[[https://raw.github.com/tinkerpop/frames/master/doc/images/frames-character-2.png|width=120px]]

This section provides a list of the people that have contributed in some way to the creation of Frames.

# "Marko A. Rodriguez":http://markorodriguez.com -- designed, developed, tested, and documented Gremlin.
# "Stephen Mallette":http://stephen.genoprime.com/ -- repository and issue tracker support.
# "Bryn Cooke":https://github.com/BrynCooke -- feature design, development, and testing.
# "Joshua Shinavier":http://fortytwo.net -- help with interface design.
# "Ketrina Yim":http://www.ketrinayim.com/ -- designed the Frames logo.

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.
67 changes: 67 additions & 0 deletions doc/Core-Annotations.textile
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
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:

* Method name prefixes: get, is, can, set, add, remove
* Annotations: method metadata.

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.

h3. Annotations valid on all frames (VertexFrame and EdgeFrame):

|_. annotation |_. method prefix |_. arguments |_. description |_. example |
| @@Property@ | @get@,@is@,@can@ | @value@ |get the property value of an element | @@Property("name")@ |
| @@Property@ | @set@ | @value@ | set the property value of an element | @@Property("name")@ |
| @@Property@ | @remove@ | @value@ | remove the property of an element | @@Property("name")@ |

h3. Annotations valid on vertices (VertexFrame):

|_. annotation |_. method prefix |_. arguments |_. description |_. example |
| @@Adjacency@ | @get@ | @label@, @direction@ | get the vertex or vertices @X@ related to the vertex | @@Adjacency(label="X", direction=Direction.OUT)@ |
| @@Adjacency@ | @set@ | @label@, @direction@ | set the vertex or vertices @X@ related to the vertex | @@Adjacency(label="X", direction=Direction.OUT)@ |
| @@Adjacency@ | @add@ | @label@, @direction@ | add a vertex @X@ related to the vertex and return the vertex @X@| @@Adjacency(label="X", direction=Direction.OUT)@ |
| @@Adjacency@ | @remove@ | @label@, @direction@ | remove a vertex @X@ related to the vertex| @@Adjacency(label="X", direction=Direction.OUT)@ |
| @@Incidence@ | @get@ | @label@, @direction@ | get the edges @X@ related to the vertex | @@Incidence(label="X", direction=Direction.OUT)@ |
| @@Incidence@ | @add@ | @label@, @direction@ | add an edge @X@ related to the vertex and return the edge @X@| @@Incidence(label="X", direction=Direction.OUT)@ |
| @@Incidence@ | @remove@ | @label@, @direction@ | remove an edge @X@ related to the vertex | @@Incidence(label="X", direction=Direction.OUT)@ |

Note that "get" and "set" methods for @@Adjacency@ can be either single-valued or Iterable-valued. For example:

```java
public interface Person {
@Adjacency(label = "spouse")
Person getSpouse();

@Adjacency(label = "spouse")
void setSpouse(Person spouse);

@Adjacency(label = "child")
Iterable<Person> getChildren();

@Adjacency(label = "child")
void setChildren(Iterable<Person> children);
}
```

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.

"add" methods for @@Adjacency@ can be either single-valued or no-valued For example:
```java
public interface Person {
@Adjacency(label = "friend")
Person addFriend(); //Returns a new vertex of type friend

@Adjacency(label = "friend")
Person addFriend(Person friend); //Add an existing person as a friend
}
```

h3. Annotations valid on edges (EdgeFrame):

|_. annotation |_. method prefix |_. arguments |_. description |_. example |
| @@InVertex@ | @get@ | none | get the in-vertex. This is equivalent to calling Edge.getVertex(Direction.IN) | @@InVertex@ |
| @@OutVertex@ | @get@ | none | get the out-vertex. This is equivalent to calling Edge.getVertex(Direction.OUT) | @@OutVertex@ |
| -@@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@ |
| -@@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@ |

Please note: @@Domain@ and @@Range@ are deprecated. You should use @@InVertex@ and @@OutVertex@

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@.
16 changes: 16 additions & 0 deletions doc/Creating-Frames.textile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
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.

[[https://github.com/tinkerpop/blueprints/raw/master/doc/images/graph-example-1.jpg|width=450px]]

```java
Graph graph = ... // get a reference to the graph
FramedGraphFactory factory = new FramedGraphFactory(); // make sure you reuse the factory when creating new framed graphs.
FramedGraph<Graph> framedGraph = factory.create(graph); // wrap the base graph

Person marko = framedGraph.getVertex(1, Person.class);
Person peter = framedGraph.getVertex(6, Person.class);
Iterable<Project> javaProjects = framedGraph.getVertices("lang","java", Project.class);

Knows markoKnowsVadas = framedGraph.getEdge(7, Knows.class);
Knows markoKnowsJosh = framedGraph.getEdge(8, Knows.class);
```
21 changes: 21 additions & 0 deletions doc/Custom-modules.textile
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
You can extend the functionality of a @FramedGraph@ via modules.

```java
public interface Module {
/**
* @param baseGraph The graph being framed.
* @param config The configuration for the new FramedGraph.
* @return The graph being framed.
*/
<T extends Graph> T configure(Graph baseGraph, FramedGraphConfiguration config);
}
```

@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@.

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.

*Notes*
* The configure method should be fast, as it will potentially be called many times.
* The configure method should be threadsafe.
* [[Method Handlers]], [[Frame Initializers]] and [[Type Resolvers]] should be threadsafe.
26 changes: 26 additions & 0 deletions doc/Factories-and-Modules.textile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
h3. Factories

To obtain a framed graph use a @FramedGraphFactory@.

```java
FramedGraphFactory factory = new FramedGraphFactory();
FramedGraph framedGraph = factory.create(baseGraph);
```
TransactionalFramedGraph can be created from a TransactionalGraph
```java
FramedGraphFactory factory = new FramedGraphFactory();
TransactionalFramedGraph transactionalFramedGraph = factory.create(baseTransactionalGraph);
```

*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.*

h3. Modules

@Modules@ are used to extend the capability of FramedGraph. They are registered in the constructor of the @FramedGraphFactory@.

In this example the framed graph will now support the @@GremlinGroovy@ annotation on frames.
```java
FramedGraphFactory factory = new FramedGraphFactory(new GremlinGroovyModule());
FramedGraph framedGraph = factory.create(baseGraph);
```
Any number of modules can be added to the factory, but a @FramedGraph@ will always support the [[Core Annotations]].
36 changes: 36 additions & 0 deletions doc/Frame-initializers.textile
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
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.

The @FrameInitializer@ interface allows a newly added vertex or edge to be initialized before it is returned to the user.

```java
public interface FrameInitializer {
/**
* @param kind The kind of frame.
* @param framedGraph The graph.
* @param element The new element that is being inserted into the graph.
*/
public void initElement(final Class<?> kind, final FramedGraph<?> framedGraph, final Element element);
}
```

To use the initializer register it via a module with the @FramedGraphFactory@.
```java
FrameInitializer myInitializer = new FrameInitializer() {
public void initElement(final Class<?> kind, final FramedGraph<?> framedGraph, final Element element) {
element.setProperty("class", kind.getName()); //For example: save the class name of the frame on the element
}
};

FramedGraph g = new FramedGraphFactory(new AbstractModule() {
public void doConfigure(FramedGraphConfiguration config) {
config.addFrameInitializer(myInitializer);
}
}).create(baseGraph);

Person p = g.addVertex(null, Person.class); //myInitializer is called.
```
Every registered initializer is called before returning the new element.

Some possible use cases
* You want to save the type information of the frame to the vertex.
* You want to set the default property values of the vertex based on the frame type.
10 changes: 10 additions & 0 deletions doc/Frames-Ecosystem.textile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
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.

h2. Getting Indexes

Frames has no notion of indexes. To obtain an index, use Blueprints.

```java
IndexedGraph graph = framedGraph.getBaseGraph(); // get reference to graph
Index index = graph.getIndex("myIndex", Vertex.class);
```
105 changes: 105 additions & 0 deletions doc/Getting-Started.textile
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
[[http://i579.photobucket.com/albums/ss235/krissy_bby93/icon_UnderConstruction.png|width=120px]]

h2. Creating a Domain Model with Java Interfaces

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.

```java
public interface Person {
@Property("name")
public void setName(String name);
@Property("name")
public String getName();
@Property("age")
public void setAge(int age);
@Property("age")
public int getAge();

@Adjacency(label="knows")
public Iterable<Person> getKnowsPeople();
@Adjacency(label="knows")
public void addKnowsPerson(Person person);

@Adjacency(label="created")
public Iterable<Project> getCreatedProjects();
@Adjacency(label="created")
public void addCreatedProject(Project project);
}
```

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.

h2. Framing Graph Elements in Terms of the Java Interfaces

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()@.

[[https://github.com/tinkerpop/blueprints/raw/master/doc/images/graph-example-1.jpg|width=450px]]

To frame vertex 1 (marko) in terms of the @Person@ interface defined previously, simply do the following.

```java
Graph graph = TinkerGraphFactory.createTinkerGraph();
FramedGraphFactory factory = new FramedGraphFactory();
FramedGraph manager = factory.create(graph);
Person marko = manager.frame(graph.getVertex(1), Person.class);
```

Now its possible to update Marko's age, get his name, and determine the names of all the people he knows.

```java
marko.setAge(31)
assert marko.getName().equals("marko")
for(Person person : marko.getKnowsPeople()) {
System.out.println(person.getName()); // prints vadas and josh
}
```

h2. Adding a Few More Constructs

In the example graph, there are people and there are projects. Lets model a project as a Java interface.

```java
public interface Project extends VertexFrame {
@Property("name")
public void setName(String name);
@Property("name")
public String getName();
@Property("lang")
public void setLanguage(String language);
@Property("lang")
public int getLanguage();

@Adjacency(label="created", direction=Direction.IN)
public Iterable<Person> getCreatedByPerson();

@Incidence(label = "created", direction = Direction.IN)
public Iterable<CreatedInfo> getCreatedInfo();
}

public interface CreatedInfo extends EdgeFrame {
@Property("weight")
public Float getWeight();
@Property("weight")
public void setWeight(float weight);

@OutVertex
Person getPerson();

@InVertex
Project getProject();
}
```

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.

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@.

```java
Project ripple = manager.frame(graph.getVertex(5), Project.class);
System.out.println(ripple.getCreatedByPerson().iterator().next().getName()); // prints "josh"

System.out.println(ripple.asVertex().getId()); // prints "5"
```

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.
There is more to Frames, but what has been presented are the basic constructs to help get you started.
58 changes: 58 additions & 0 deletions doc/Gremlin-Groovy.textile
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
[[https://raw.github.com/tinkerpop/frames/master/doc/images/gremlin-in-frames.png|align=left]]

"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.

h2. Frame Adjacencies

It is possible to make use of a Gremlin path expression as a means of determining vertex adjacency via the @GremlinGroovyModule@.

|_. annotation |_. method prefix |_. arguments |_. description |_. example |
| @@GremlinGroovy@ | @get@ | @value@ | get and frame the vertices at then end of the expression | @@GremlinGroovy("it.out('knows')")@ |
| @@GremlinGroovy@ | @get@, @can@, @is@ | @value@, @frame=false@ | return the objects at then end of the expression | @@GremlinGroovy(value="it.out('knows').name", frame=false)@ |

```java
public interface Person {
@GremlinGroovy("it.as('x').out('created').in('created').except('x')")
public Iterable<Person> getCoCreators();
}
```

In the example above, the vertices at the end of the path expression are framed as @Person@ classes.

```java
FramedGraphFactory factory = new FramedGraphFactory(new GremlinGroovyModule()); //Use the gremlin groovy module
FramedGraph framedGraph = factory.create(graph);

Person marko = framedGraph.frame(graph.getVertex(1), Person.class);
for (Person coCreator : marko.getCoCreators()) {
System.out.println(coCreator.getName());
}
// josh
// peter
```

When constructing your @FramedGraphFactory@ ensure you include the @GremlinGroovyModule@.

You can also pass parameters to the gremlin expression by using @@GremlinParam@ to specify the name of the parameter.

```java
public interface Person {
@GremlinGroovy("it.as('x').out('created').in('created').except('x').has('age',age)")
public Iterable<Person> getCoCreatorsOfAge(@GremlinParam("age") int age);
}
```

In this example the paramater named 'age' is passed to the script.

```java
Person josh = marko.getCoCreatorsOfAge(32).iterator().next();
```

h2. Arbitrary Java objects

If the resultant object return type is not a Frame, then @frame=false@ should be used in the @@GremlinGroovy@ annotation.

```java
@GremlinGroovy(value="'1+2'", frame=false)
public Integer getASumOfTwoNumbers();
```
Loading

0 comments on commit 387b8b9

Please sign in to comment.