Create a Graph - jgralab/jgralab GitHub Wiki

Create a Graph

JGraLab has two different Graph APIs: the generic API and the standard API.

With the generic API, all vertices and edges are just Vertex and Edge objects. Every Vertex and Edge knows its VertexClass or EdgeClass that represents its type.

The standard API uses code generation to create a java interface and a java class for each VertexClass and EdgeClass in a Schema. The new generated code can than be used to create a type save graph. Of course, every Vertex and Edge still knows its VertexClass or EdgeClass.

The following subsections show, how the example graph below can be created by the generic API and the standard API.

ExampleTGraph

Create a generic Graph instance

To create a graph of a certain schema, the Schema object is needed. For convenient access to VertexClasses and EdgeClasses, the GraphClass is referenced by gc.

Schema schema = ...
GraphClass gc = schema.getGraphClass();		

Now the Graph is created.

Graph graph = schema.createGraph(ImplementationType.GENERIC, "ExampleGraph", 50, 100);

To create a generic graph, the createGraph method takes the constant GENERIC as ImplementationType. The second parameter represents the graph ID. Besides that, the maximum number of vertices and edges in the graph are specified. Note that this are not fixed numbers but can be extended while the graph grows.

In the example, a generic implementation graph with the id "ExampleGraph", the maximum vertex count of 50 and the maximum edge count of 100 is created.

Now some vertices can be created. To create a vertex in a graph, the VertexClass is needed. To get a VertexClass from a schema, the GraphClass is used as shown in Access Schema elements.

The following snippet shows the creation of two JavaPackages. They will become the default package and the family package in the example graph.

Vertex v_defPack = graph.createVertex(gc.getVertexClass("JavaPackage"));
Vertex v_famPack = graph.createVertex(gc.getVertexClass("JavaPackage"));

After the vertex is created, attributes can be set. The attributes name and value are the parameters. Note that it is checked, if an attribute of the specified name is allowed for the VertexClass of the newly created vertex. Only if the name is known and the value matches the specified type, the attribute setting is successful.

v_defPack.setAttribute("qualifiedName", "");
v_defPack.setAttribute("simpleName", "");
v_famPack.setAttribute("qualifiedName", "family");
v_famPack.setAttribute("simpleName", "family");

The default package has the empty name as simple and qualified name. The family package has the value "family" for both attributes.

The SourceFile Person.java is created alike.

Vertex v_perSour = graph.createVertex(gc.getVertexClass("SourceFile"));
v_perSour.setAttribute("lines", 18);
v_perSour.setAttribute("name", "../TutorialExample/src/family/Person.java");
v_perSour.setAttribute("numberOfStmts", 2);

For the vertices of VertexClass JavaType, an enumeration constant for the attribute kind must be created. In the generic implementation API, the graph can be used for that, too.

Vertex v_perType = graph.createVertex(gc.getVertexClass("JavaType"));
v_perType.setAttribute("abstract", false);
v_perType.setAttribute("kind", 
	graph.getEnumConstant((EnumDomain) schema.getDomain("TypeKind"), "CLASS"));
v_perType.setAttribute("qualifiedName", "family.Person");
v_perType.setAttribute("simpleName", "Person");
		
Vertex v_lisType = graph.createVertex(gc.getVertexClass("JavaType"));
v_lisType.setAttribute("abstract", false);
v_lisType.setAttribute("kind", 
	graph.getEnumConstant((EnumDomain) schema.getDomain("TypeKind"), "UNKNOWN"));
v_lisType.setAttribute("qualifiedName", "java.util.ArrayList");

To complete the example graph, the JavaMember vertices are created.

Vertex v_finMemb = graph.createVertex(gc.getVertexClass("JavaMember"));
v_finMemb.setAttribute("simpleName", "firstName");
		
Vertex v_lanMemb = graph.createVertex(gc.getVertexClass("JavaMember"));
v_lanMemb.setAttribute("simpleName", "lastName");

Vertex v_chiMemb = graph.createVertex(gc.getVertexClass("JavaMember"));
v_chiMemb.setAttribute("simpleName", "children");

Vertex v_perMemb = graph.createVertex(gc.getVertexClass("JavaMember"));
v_perMemb.setAttribute("simpleName", "Person");

Now, after all vertices in the example graph are completed, the edges between them can be created. To create an edge, the EdgeClass must be given as well as the alpha and omega (source and target) of the edge. It is not allowed to have a floating edge with a missing alpha or omega.

At first, the Defines edge between the the SourceFile Person.java and the JavaType Person is created. The attribute lineNumber is set in the same way as before.

Edge e_defines = graph.createEdge(gc.getEdgeClass("Defines"), v_perSour, v_perType);
e_defines.setAttribute("lineNumber", 5);

The Edge object represents the directed edge e7 in the image above. In addition, a second object is created automatically during the creation of e7: the reversed edge of e7. Every edge knows its reversed edge and vice versa.

Edge e_defines_reverse = e_defines.getReversedEdge();
System.out.println(e_defines);
System.out.println(e_defines_reverse);

Console output:

+e7: Defines

-e7: Defines

The "-" in the console output indicates that the edge object is a reversed edge while the "+" indicates a normal edge. Reversed edges and how to use them is explained in more detail in Access Graph elements.

The other edges are created alike:

Edge e_imports = graph.createEdge(gc.getEdgeClass("Imports"), v_perSour, v_lisType);
e_imports.setAttribute("lineNumber", 3);

graph.createEdge(gc.getEdgeClass("ContainsPackage"), v_defPack, v_famPack);

graph.createEdge(gc.getEdgeClass("ContainsType"), v_famPack, v_perType);

graph.createEdge(gc.getEdgeClass("Declares"), v_perType, v_finMemb);
graph.createEdge(gc.getEdgeClass("Declares"), v_perType, v_lanMemb);
graph.createEdge(gc.getEdgeClass("Declares"), v_perType, v_chiMemb);
graph.createEdge(gc.getEdgeClass("Declares"), v_perType, v_perMemb);

After that, the example graph is completed.

Create a standard Graph instance

Before creating a standard implementation graph, it is necessary to create the java classes for the schema. The commit method takes the target path and a CodeGeneratorConfiguration as parameters. The java classes are generated and saved into the folder given by the target path.

Schema schema = ...
schema.commit("src", CodeGeneratorConfiguration.NORMAL);

The picture below shows the result of the code generation.

overview generated code

In the package de.uni_koblenz.jgralab.demo.schema are the Schema implementation JavaSchema, the enumeration TypeKind and interfaces for all VertexClasses and EdgeClasses. The package de.uni_koblenz.jgralab.dem.schema.impl contains the implementation of all VertexClasses and EdgeClasses.

Now a new graph can be created. Instead of the former schema object, used to generate the classes, the new created specific JavaSchema is used. The parameters are again the ImplementationType, now STANDARD, a graph ID and the maximum number of vertices and edges.

JavaGraph graph = JavaSchema.instance()
	.createJavaGraph(ImplementationType.STANDARD, "ExampleGraph", 50, 100);

The resulting graph object is now of type JavaGraph. The class JavaGraph has create methods for every VertexClass and EdgeClass in the schema.

So, the creation of a SourceFile vertex is a little bit shorter now. The snippet below shows how the SourceFile vertex representing Person.java is created.

SourceFile v_perSour = graph.createSourceFile();
v_perSour.set_lines(18);
v_perSour.set_name("../TutorialExample/src/family/Person.java");
v_perSour.set_numberOfStmts(2);

Note that the result of the create method is now not just a Vertex but the more special SourceFile.

The EnumDomain TypeKind is now represented by a real enumeration. Because of that, the setting of the kind attribute of JavaType is now much shorter: The constant CLASS can now be accessed directly.

JavaType v_perType = graph.createJavaType();
v_perType.set_abstract(false);
v_perType.set_kind(TypeKind.CLASS);
v_perType.set_qualifiedName("family.Person");
v_perType.set_simpleName("Person");

Edges are also created by type specific methods. The snippet below shows creation of the Defines edge between the SourceFile Person.java and the JavaType Person.

Defines e_defines = graph.createDefines(v_perSour, v_perType);
e_defines.set_lineNumber(5);

previous page: Graphs                                                         next page: Load and save a Graph