Skip to content
This repository was archived by the owner on Feb 12, 2022. It is now read-only.

Commit 0e36090

Browse files
Adding Java bindings. Fixes #65
1 parent 9d88589 commit 0e36090

44 files changed

Lines changed: 2367 additions & 8 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,12 @@ $ lein jar
124124
$ lein npm install # this is only required on the first run
125125
$ lein node
126126
```
127-
128127
The output NPM package will be generated at `output/node`.
129128

129+
### Java Bindings
130+
131+
The programming guide the Java Bindings can be found [here](doc/java.md).
132+
Javadoc for the bindings can be consulted [here](https://raml-org.github.io/api-modeling-framework/doc/java/apidocs/index.html).
130133

131134
### API Modeling Framework Clojurescript/Web library
132135

doc/java.md

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
# AMF Java Programming Guide
2+
3+
Java wrapping code for the AMF library can be found in the `org.raml.amf` namespace.
4+
This package provides a Java friendly interface on top of the native Clojure code of the library.
5+
6+
## Compiling
7+
8+
At this moment we don't provide any artifacts in any repository to use AMF or these Java bindings, so they must be built manually with the help of Leiningen.
9+
In order to build the library, you fist need to build an 'ubejar' with AMF. To accomplish this, from the main AMF project directory run the following instruction:
10+
11+
``` bash
12+
$ lein uberjar
13+
```
14+
After Leiningen has finished you should have a standalone jar for AMF and all its dependencies in the `target/api-modeling-framework-0.1.2-SNAPSHOT-standalone.jar` location. Version might be different from the one at the moment of writing this documentation.
15+
16+
Once the jar for AMF has been generated, we can generate the Java bindings jar. For that change to the `java` directory in the AMF project and use maven:
17+
18+
``` bash
19+
mvn package
20+
```
21+
22+
After Maven has finished you should have an additional jar in the `target/amf-java-0.1.2-SNAPSHOT.jar` location with the Java bindings. Add both jars into your project to use the AMF Java bindings.
23+
24+
## Parsing
25+
26+
Parsers can be found in the `org.raml.amf.parsers` package of the project. They can be build using the factories in `org.raml.amf.AMF`
27+
28+
``` java
29+
DocumentModel model = AMF.RAMLParser().parseFile(new URL("http://test.com/worldmusic/api.raml"));
30+
```
31+
32+
Parsers are include for RAML, OpenAPI and the JSON-LD serialisation of the AMF model.
33+
34+
Parsers can accept options, including a hash-map of URLs to local directories that will be used to resolve references in the parsed documents.
35+
36+
For instance, in the next snippet all remote references to the URLs prefixed by `http://test.com/worldmusic` will be resolved looking into the local directory `/Users/antoniogarrote/world-music-api`.
37+
38+
``` java
39+
HashMap<String,String> cacheDirs = new HashMap<>();
40+
cacheDirs.put("http://test.com/worldmusic","/Users/antoniogarrote/vocabs/world-music-api");
41+
ParsingOptions options = new ParsingOptions().setCacheDirs(cacheDirs);
42+
43+
DocumentDocument model = (Document) AMF.RAMLParser().parseFile(new URL("http://test.com/worldmusic/api.raml"), options);
44+
```
45+
The original parsed text can be retrieved using the `rawText` method.
46+
47+
## Navigating the Document Model
48+
The parsing process will return an instance of one of the subclasses of `DocumentModel`.
49+
Depending on what is the parsed file, a `Document`, a `Fragment` or a `Module` instance will be returned.
50+
51+
No matter what is the actual Document Model class, the returned model will also include references to all linked documents in the model.
52+
53+
These references can be listed using the `references` method, and new instances of `DocumentModel` can be built for these references using the `modelForReference` method:
54+
55+
``` java
56+
for (URL ref : model.references()) {
57+
DocumentModel refModel = model.modelForReference(ref);
58+
System.out.println("Found a reference model: " + refModel);
59+
}
60+
```
61+
62+
## Applying resolution
63+
64+
To run the resolution algorithm and combine all the documents from the Document Model into a single Domain Model description, the method `resolve` can be invoked.
65+
66+
``` java
67+
DocumentModel resolvedModel = model.resolve();
68+
```
69+
70+
## Accessing the Domain Model
71+
72+
The parsed Domain Model can be retrieved from the Document Model instance using the appropriate accessor.
73+
74+
Fragments return the encoded Domain Model element using the `encodes` method from the `org.raml.amf.core.document.EncodesDomainModel` interface.
75+
Modules returns the list of declared Domain Model elements using the `declares` method from the `org.raml.amf.core.document.DeclaresDomainModel` interface.
76+
Documents can use both methods to retrieve the top level encoded element and the list of declared elements in the root element.
77+
78+
``` java
79+
if (model instanceof EncodesDomainModel) {
80+
System.out.println(model.encodes());
81+
}
82+
83+
if (targetModel instanceof DeclaresDomainModel) {
84+
List<DomainModel> declarations = model.declares();
85+
for(DomainModel decl : declarations) {
86+
System.out.println(decl);
87+
}
88+
}
89+
```
90+
91+
## Navigating and mutating the Domain Model
92+
93+
The Domain Model includes Java bean classes for all elements in the AMF Domain Model.
94+
These getters and setters can be used to navigate and mutate the model. Please, refer to the [documentation](https://raml-org.github.io/api-modeling-framework/doc/java/apidocs/index.html) for more details.
95+
96+
``` java
97+
APIDocumentation api = (APIDocumentation) model.encodes();
98+
99+
for (EndPoint endpoint : api.getEndpoints()) {
100+
endpoint.setName("Modified " + endpoint.getName());
101+
}
102+
```
103+
104+
## Serialisation
105+
106+
AMF includes generators capable of serialising the AMF model back into one of the supported syntaxes. The method `generateString` can be used to generate a String representation, and the method `generateFile` can be used to dump the serialised model directly into a file.
107+
Factory methods for each generator can be found in the `org.raml.amf.AMF` class.
108+
109+
110+
``` java
111+
// Generating RAML
112+
// Generate can accept just the model
113+
String generated = AMF.RAMLGenerator().generateString(targetModel);
114+
System.out.println(generated);
115+
116+
// Generating OpenAPI
117+
// It can also accept a destination File/URL for the model
118+
generated = AMF.OpenAPIGenerator().generateString(
119+
new File("world_music.json"),
120+
targetModel
121+
);
122+
System.out.println(generated);
123+
124+
// Generating JSON-LD
125+
// Finally it can also accept a set of generation options
126+
generated = AMF.JSONLDGenerator().generateString(
127+
new File("world_music.jsonld"),
128+
targetModel,
129+
new GenerationOptions()
130+
.setFullgraph(true)
131+
.setSourceMapGeneration(true));
132+
System.out.println(generated);
133+
```
134+
135+
Two options are available when generating JSON-LD documents.
136+
`setFullGraph` will nest the JSON-LD graphs for the referenced documents in the model to be serialised, otherwise only URIs will be generated.
137+
`setSourceMapGeneration` enables or disables the generation of source maps JSON-LD information in the output.

java/src/org/raml/amf/AMF.java

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package org.raml.amf;
2+
3+
import org.raml.amf.generators.AMFJSONLDGenerator;
4+
import org.raml.amf.generators.OpenAPIGenerator;
5+
import org.raml.amf.generators.RAMLGenerator;
6+
import org.raml.amf.parsers.AMFJSONLDParser;
7+
import org.raml.amf.parsers.OpenAPIParser;
8+
import org.raml.amf.parsers.RAMLParser;
9+
10+
/**
11+
* Created by antoniogarrote on 04/05/2017.
12+
*/
13+
14+
/**
15+
* Facade class providing access to the main IO facilities in the library
16+
*/
17+
public class AMF {
18+
19+
/**
20+
* Builds a RAML to AMF parser
21+
* @return
22+
*/
23+
public static RAMLParser RAMLParser() {
24+
return new RAMLParser();
25+
}
26+
27+
/**
28+
* Builds an OpenAPI to AMF parser
29+
* @return
30+
*/
31+
public static OpenAPIParser OpenAPIParser() {
32+
return new OpenAPIParser();
33+
}
34+
35+
/**
36+
* Builds a AMF encoded JSON-LD to AMF parser
37+
* @return
38+
*/
39+
public static AMFJSONLDParser JSONLDParser() {
40+
return new AMFJSONLDParser();
41+
}
42+
43+
/**
44+
* Builds a AMF to RAML generator
45+
* @return
46+
*/
47+
public static RAMLGenerator RAMLGenerator() {
48+
return new RAMLGenerator();
49+
}
50+
51+
/**
52+
* Builds a AMF to OpenAPI generator
53+
* @return
54+
*/
55+
public static OpenAPIGenerator OpenAPIGenerator() {
56+
return new OpenAPIGenerator();
57+
}
58+
59+
/**
60+
* Builds a AMF to JSON-LD generator
61+
* @return
62+
*/
63+
public static AMFJSONLDGenerator JSONLDGenerator() {
64+
return new AMFJSONLDGenerator();
65+
}
66+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package org.raml.amf.core;
2+
3+
/**
4+
* Created by antoniogarrote on 04/05/2017.
5+
*/
6+
7+
import org.raml.amf.core.exceptions.InvalidModelException;
8+
import org.raml.amf.utils.Clojure;
9+
10+
/**
11+
* Base class for all AMF parsed models, provides methods to inspect and manipulate the model
12+
*/
13+
public abstract class Model {
14+
15+
static {
16+
Clojure.require(Clojure.API_MODELING_FRAMEWORK_CORE);
17+
}
18+
19+
protected Object rawModel;
20+
21+
protected Model(Object rawModel) {
22+
if (rawModel instanceof Exception) {
23+
throw new InvalidModelException((Exception) rawModel);
24+
}
25+
this.rawModel = rawModel;
26+
}
27+
28+
/**
29+
* Returns the raw Clojure data structure for this instance data
30+
* @return
31+
*/
32+
public abstract Object clojureModel();
33+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package org.raml.amf.core.document;
2+
3+
import org.raml.amf.core.domain.DomainModel;
4+
5+
import java.util.List;
6+
7+
/**
8+
* Created by antoniogarrote on 04/05/2017.
9+
*/
10+
public interface DeclaresDomainModel {
11+
/**
12+
* Declared DomainElements that can be re-used from other documents.
13+
* @return List of domain elements.
14+
*/
15+
public List<DomainModel> declares();
16+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package org.raml.amf.core.document;
2+
3+
import clojure.lang.IFn;
4+
import org.raml.amf.core.domain.DomainModel;
5+
import org.raml.amf.core.exceptions.InvalidModelException;
6+
import org.raml.amf.utils.Clojure;
7+
8+
import java.util.ArrayList;
9+
import java.util.List;
10+
11+
/**
12+
* Created by antoniogarrote on 04/05/2017.
13+
*/
14+
15+
/**
16+
* AMF Documents encode the main element of a description in a particular Domain Model
17+
* For example, in RAML/HTTP, the main domain element is an APIDescription.
18+
*
19+
* Since AMF Documents encode Domain elements they behave like Fragments
20+
* AMF Documents can also contains declarations of domain elements to be used in the description of the domain.
21+
* From this point of view Documents also behave like Modules.
22+
*/
23+
public class Document extends DocumentModel implements EncodesDomainModel, DeclaresDomainModel {
24+
public Document(Object rawModel) {
25+
super(rawModel);
26+
}
27+
28+
/**
29+
* Encoded domain element. It's considered to be the root element of a stand-alone description, not a domain element
30+
* to be re-used and reference
31+
* @return DomainElement encoded in the document.
32+
* @throws InvalidModelException
33+
*/
34+
public DomainModel encodes() throws InvalidModelException {
35+
IFn getFn = Clojure.var(Clojure.API_MODELING_FRAMEWORK_MODEL_DOCUMENT, "encodes");
36+
return DomainModel.fromRawModel(getFn.invoke(this.clojureModel()));
37+
}
38+
39+
/**
40+
* List of domain elements declared in the document to be referenced in the encoded element.
41+
* They are supposed to be private to the description and not meant to be re-used as in Modules.
42+
* @return
43+
*/
44+
public List<DomainModel> declares() {
45+
IFn getFn = Clojure.var(Clojure.API_MODELING_FRAMEWORK_MODEL_DOCUMENT, "declares");
46+
List parsedElements = Clojure.toJavaList((List) getFn.invoke(this.clojureModel()));
47+
ArrayList<DomainModel> declared = new ArrayList<>();
48+
for(Object parsed : parsedElements) {
49+
declared.add(DomainModel.fromRawModel(parsed));
50+
}
51+
52+
return declared;
53+
}
54+
}

0 commit comments

Comments
 (0)