Java Cookbook

Getting Started

To get started with the Java driver, please visit the GitanaJava Driver Page.

We recommend that you use Maven. At a minimum, you will need to add the following repository declaration to your pom.xml file:

<repositories>
    <repository>
        <id>cloudcms-public</id>
        <name>cloudcms-public</name>
        <url>https://maven.cloudcms.com/public</url>
    </repository>
</repositories>

Note that newer vesions of Maven require secure repositories so if you currently use http://maven.cloudcms.com/public you should update to https://maven.cloudcms.com/public

You will also need to include the Java driver as a dependency. For example -

<dependencies>
    <dependency>
        <groupId>org.gitana</groupId>
        <artifactId>gitana-java-driver</artifactId>
        <version>1.0.40</version>
    </dependency>
</dependencies>

Connecting to Gitana

There are several ways to connect the driver to Gitana.

Use a Properties file

Add a gitana.properties file to the root of your classpath. The driver will automatically pick it up.

Platform platform = Gitana.connect()

The gitana.properties file should look like:

gitana.clientKey={your client key}
gitana.clientSecret={your client secret}
gitana.username={your username or auth grant key}
gitana.password={your password or auth grant secret}
gitana.baseURL={the url to the Cloud CMS API endpoint}

To get this file and these values, please check out our section on {API Keys.

Alternatively, you can load your own properties file. This loads config.properties from the classpath. You might opt to load it from disk, a URL or anywhere else.

ResourceBundle config = ResourceBundle.getBundle("config");
Platform platform = Gitana.connect(config);

Specify Values Directly

You're also free to connect directly using a Map, like this:

Map<String, String> config = new HashMap<String, String>();
config.put("clientKey", "{your client key}");
config.put("clientSecret", "{your client secret}");
config.put("username", "{your username or auth grant key}");
config.put("password", "{your password or auth grant secret}");
config.put("baseURL", "{the url to the Cloud CMS API endpoint}");

Platform platform = Gitana.connect(config); 

Or using a JSON Object Node, like this:

ObjectNode config = JsonUtil.createObject();
config.put("clientKey", "{your client key}");
config.put("clientSecret", "{your client secret}");
config.put("username", "{your username or auth grant key}");
config.put("password", "{your password or auth grant secret}");
config.put("baseURL", "{the url to the Cloud CMS API endpoint}");

Platform platform = Gitana.connect(config); 

Or via a direct call, like this:

String clientKey = "{your client key}";
String clientSecret = "{your client secret}";
String username = "{your username or auth grant key}";
String password = "{your password or auth grant secret}";
String baseURL = "{the url to the Cloud CMS API endpoint}";

Platform platform = Gitana.connect(clientKey, clientSecret, username, password, baseURL); 

Fallback

In any of these scenarios, if you pass in null for one of the values, a fallback mechanism exists where the driver will look for a gitana.properties resource bundle file in the classpath root. Any values aren't supplied will be pulled from that resource bundle.

Code Samples

Here are some code samples to help you get started. For all of these scenarios, we assume that you're connecting using the simplest method (loading gitana.properties from the classpath). But you're free to connect using any of the methods listed above.

In Cloud CMS, you can have as many repositories as you'd like. And each repository can multiple branches (similar to Git). The first thing you should do is connect and get the branch that you want to work on.

For the purpose of most of these examples, we'll assume the repository ID is 1234567890abcdef1234 and the branch is master.

Get your Repository

Use the readRepository method to fetch a specific repository. The user you've logged in as must have READ permissions to the repository. If they do not have read rights, a null response is expected.

Platform platform = Gitana.connect();

Repository repository = platform.readRepository("1234567890abcdef1234");
if (repository == null) {
    throw new RuntimeException("Unable to read repository: 1234567890abcdef1234");
}

Get the Master Branch

Use the readBranch method to fetch a specific branch. The user you've logged in as must have READ permissions to the branch. If they do not have read rights, a null response is expected.

Platform platform = Gitana.connect();

Repository repository = platform.readRepository("1234567890abcdef1234");
if (repository == null) {
    throw new RuntimeException("Unable to read repository: 1234567890abcdef1234");
}

Branch branch = repository.readBranch("master");
if (branch == null) {
    throw new RuntimeException("Unable to read master branch");
}

Node Creation

Create a Node

Create a basic node of type n:node (the default type).

Platform platform = Gitana.connect();

Repository repository = platform.readRepository("1234567890abcdef1234");
if (repository == null) {
    throw new RuntimeException("Unable to read repository: 1234567890abcdef1234");
}

Branch branch = repository.readBranch("master");
if (branch == null) {
    throw new RuntimeException("Unable to read master branch");
}

ObjectNode object = JsonUtil.createObject();
object.put("title", "My First Node");

Node node = (Node) branch.createNode(object)

Create a Node for a Custom Content Type

Suppose we have a custom content type called custom:article that looks like this:

{
    "title": "Custom Article",
    "_qname": "custom:article",
    "type": "object",
    "properties": {
        "title": {
            "type": "string"
        },
        "body": {
            "type": "string"
        },
        "categories": {
            "type": "array",
            "items": {
                "type": "string"
            }
        },
        "rating": {
            "type": "number"
        }
    }
}

Create a content instance of this type like this:

Platform platform = Gitana.connect();

Repository repository = platform.readRepository("1234567890abcdef1234");
if (repository == null) {
    throw new RuntimeException("Unable to read repository: 1234567890abcdef1234");
}

Branch branch = repository.readBranch("master");
if (branch == null) {
    throw new RuntimeException("Unable to read master branch");
}

ObjectNode object = JsonUtil.createObject();
object,put("_type", "custom:article");
object.put("title", "Article #1");
object.put("body", "A still more glorious dawn awaits");
object.put("categories", JsonUtil.createArray(Arrays.valueOf("category1", "category2", "category3")));
object.put("rating", 5);

Node node = (Node) branch.createNode(object)

Create a Folder

In Gitana, folders are just nodes with the f:container feature on them.

Platform platform = Gitana.connect();

Repository repository = platform.readRepository("1234567890abcdef1234");
if (repository == null) {
    throw new RuntimeException("Unable to read repository: 1234567890abcdef1234");
}

Branch branch = repository.readBranch("master");
if (branch == null) {
    throw new RuntimeException("Unable to read master branch");
}

ObjectNode object = JsonUtil.createObject();
object.put("title", "My Folder");

Node node = (Node) branch.createNode(object)
node.addFeature("f:filename", JsonUtil.createObject());
node.addFeature("f:container", JsonUtil.createObject());
node.update();

If you want your folder to appear in the general folder hierarchy, you must link it to a parent folder that is already a member of the folder hierarchy. The main folder hierarchy descends from the branch root node.

Here is the long way of doing this:

Platform platform = Gitana.connect();

Repository repository = platform.readRepository("1234567890abcdef1234");
if (repository == null) {
    throw new RuntimeException("Unable to read repository: 1234567890abcdef1234");
}

Branch branch = repository.readBranch("master");
if (branch == null) {
    throw new RuntimeException("Unable to read master branch");
}

ObjectNode object = JsonUtil.createObject();
object.put("title", "My Folder");

Node node = (Node) branch.createNode(object)
node.addFeature("f:filename", JsonUtil.createObject());
node.addFeature("f:container", JsonUtil.createObject());
node.update();

// the root node of the branch
Node rootNode = branch.rootNode();

// associate our new node to the root node via an `a:child` relationship
root.associate(node, A_CHILD, Directionality.DIRECTED);

An easier way to do this is to use the following special properties when the node is created:

  • _parentFolderPath - the path to the parent folder where the created node should be linked. The folder must exist. If it does not exist, the operation will fail. There is an example of this in use within the NodeAttachment2Test.java test file.
  • _fileName - the f:filename to be assigned to the node once it is created.

Alternatively, you can use:

  • _filePath - an absolute path where the file should be created. This allows you to specify the parent folder path and the file name at the same time,.

You can also adjust the association type (between the discovered parent folder and your newly created item).

  • _associationTypeString - the QName for the newly created association. The default is a:child.

Thus, you could do:

Platform platform = Gitana.connect();

Repository repository = platform.readRepository("1234567890abcdef1234");
if (repository == null) {
    throw new RuntimeException("Unable to read repository: 1234567890abcdef1234");
}

Branch branch = repository.readBranch("master");
if (branch == null) {
    throw new RuntimeException("Unable to read master branch");
}

ObjectNode object = JsonUtil.createObject();
object.put("title", "My Folder");
object.put("_parentFolderPath", "/");
object.put("_fileName", "my_folder");

Node node = (Node) branch.createNode(object)

Or you could do:

Platform platform = Gitana.connect();

Repository repository = platform.readRepository("1234567890abcdef1234");
if (repository == null) {
    throw new RuntimeException("Unable to read repository: 1234567890abcdef1234");
}

Branch branch = repository.readBranch("master");
if (branch == null) {
    throw new RuntimeException("Unable to read master branch");
}

ObjectNode object = JsonUtil.createObject();
object.put("title", "My Folder");
object.put("_filePath", "/my_folder");

Node node = (Node) branch.createNode(object)

Associations

In Gitana, any two nodes can be connected via an association. You can use an out-of-the-box association type, such as a:linked or a:owned or you can create your own.

Let's imagine that we have two articles that look like this:

  • Article #1
{
    "_doc": "1234567890abcdef1111",
    "_type": "custom:article",
    "title": "Article #1",
    "body": "a mote of dust suspended in a sunbeam",
    "categories": ["category1", "category2"],
    "rating": 1
}
  • Article #2
{
    "_doc": "1234567890abcdef2222",
    "_doc": "",
    "_type": "custom:article",
    "title": "Article #2",
    "body": "harvesting star light",
    "categories": ["category2", "category3"],
    "rating": 2
}

Let's create an association that points from the first article (1234567890abcdef1111) to the second article (1234567890abcdef2222), like this:

Platform platform = Gitana.connect();

Repository repository = platform.readRepository("1234567890abcdef1234");
if (repository == null) {
    throw new RuntimeException("Unable to read repository: 1234567890abcdef1234");
}

Branch branch = repository.readBranch("master");
if (branch == null) {
    throw new RuntimeException("Unable to read master branch");
}

Node article1 = (Node) branch.readNode("1234567890abcdef1111");
Node article2 = (Node) branch.readNode("1234567890abcdef2222");

QName associationTypeQName = QName.create("a:linked");
Association association = article1.associate(article2, associationTypeQName);

You can also find all associations around article1. This will include associations that are INCOMING, OUTGOING and MUTUAL.

ResultMap<Association> associations = article1.associations();

Or find only the INCOMING associations:

ResultMap<Association> incomingAssociations = article1.associations(Direction.INCOMING);

Or find only the OUTGOING associations of type a:linked:

ResultMap<Association> outgoingLinkedAssociations = article1.associations(associationTypeQName, Direction.INCOMING);

Query for Nodes

Let's now look at querying for content. This makes use of MongoDB's query language to express some pretty powerful queries. We recommend further reading on Query with Gitana.

Let's assume that we have the following:

  • Article #1
{
    "_type": "custom:article",
    "title": "Article #1",
    "body": "a mote of dust suspended in a sunbeam",
    "categories": ["category1", "category2"],
    "rating": 1
}
  • Article #2
{
    "_type": "custom:article",
    "title": "Article #2",
    "body": "harvesting star light",
    "categories": ["category2", "category3"],
    "rating": 2
}
  • Article 3
{
    "_type": "custom:article",
    "title": "Article #3",
    "body": "we are star stuff",
    "categories": ["category3", "category1"],
    "rating": 3
}

Basic Querying

Find all of the nodes that have a category with the value category1.

Platform platform = Gitana.connect();

Repository repository = platform.readRepository("1234567890abcdef1234");
if (repository == null) {
    throw new RuntimeException("Unable to read repository: 1234567890abcdef1234");
}

Branch branch = repository.readBranch("master");
if (branch == null) {
    throw new RuntimeException("Unable to read master branch");
}

ObjectNode query = JsonUtil.createObject();
query.put("_type", "custom:article");
query.put("category", "category1");

ResultMap<BaseNode> results = branch.queryNodes(object);
System.out.println("The size was: " + results.size()); // 3
for (BaseNode n: results.values())
{
    Node node = (Node) n;
    
    System.out.println("Found a result, title: " + node.getString("title") + ", rating: " + node.getInt("rating"));
}

Pagination

If you have a lot of potential query hits, you'll want to paginate. Here is an example where we return results starting at index 2 and hand back at most 5 results.

Platform platform = Gitana.connect();

Repository repository = platform.readRepository("1234567890abcdef1234");
if (repository == null) {
    throw new RuntimeException("Unable to read repository: 1234567890abcdef1234");
}

Branch branch = repository.readBranch("master");
if (branch == null) {
    throw new RuntimeException("Unable to read master branch");
}

ObjectNode query = JsonUtil.createObject();
query.put("_type", "custom:article");
query.put("category", "category1");

Pagination pagination = new Pagination(2, 5);
ResultMap<BaseNode> results = branch.queryNodes(object, pagination));
System.out.println("The size was: " + results.size()); // 1
System.out.println("The offset was: " + results.offset()); // 2
System.out.println("The totalRows was: " + results.totalRows()); // 3
for (BaseNode n: results.values())
{
    Node node = (Node) n;
    
    System.out.println("Found a result, title: " + node.getString("title") + ", rating: " + node.getInt("rating"));
}

Sorting

Use the pagination option to sort the results as you see fit. Here we sort descending on rating.

Platform platform = Gitana.connect();

Repository repository = platform.readRepository("1234567890abcdef1234");
if (repository == null) {
    throw new RuntimeException("Unable to read repository: 1234567890abcdef1234");
}

Branch branch = repository.readBranch("master");
if (branch == null) {
    throw new RuntimeException("Unable to read master branch");
}

ObjectNode query = JsonUtil.createObject();
query.put("_type", "custom:article");
query.put("category", "category1");

Pagination pagination = new Pagination();
pagination.getSorting().addSort("rating", -1);
ResultMap<BaseNode> results = branch.queryNodes(object, pagination));
System.out.println("The size was: " + results.size()); // 1
System.out.println("The offset was: " + results.offset()); // 2
System.out.println("The totalRows was: " + results.totalRows()); // 3
for (BaseNode n: results.values())
{
    Node node = (Node) n;
    
    System.out.println("Found a result, title: " + node.getString("title") + ", rating: " + node.getInt("rating"));
}

The results will look like:

Found a result, title: Article #3, rating: 3
Found a result, title: Article #2, rating: 2
Found a result, title: Article #1, rating: 1

Query for values in a range

Find all of the articles where the rating is greater than or equal to 2.
This demonstrates the power of MongoDB's query language.

Platform platform = Gitana.connect();

Repository repository = platform.readRepository("1234567890abcdef1234");
if (repository == null) {
    throw new RuntimeException("Unable to read repository: 1234567890abcdef1234");
}

Branch branch = repository.readBranch("master");
if (branch == null) {
    throw new RuntimeException("Unable to read master branch");
}

ObjectNode query = JsonUtil.createObject("{ '_type': 'custom:article', 'rating': { '$gte': 2 } }");

ResultMap<BaseNode> results = branch.queryNodes(object);

Search for Nodes

Let's now look at searching for content. This makes use of Elastic Search's DSL to express some very powerful full text and structured searches. We recommend further reading on Search within Gitana.

We also suggest reading up on Query Strings to understand how you can write searches textually (in addition to structuring them as JSON objects):

Let's assume that we have the following:

  • Article #1
{
    "_type": "custom:article",
    "title": "Article #1",
    "body": "a mote of dust suspended in a sunbeam",
    "categories": ["category1", "category2"],
    "rating": 1
}
  • Article #2
{
    "_type": "custom:article",
    "title": "Article #2",
    "body": "harvesting star light",
    "categories": ["category2", "category3"],
    "rating": 2
}
  • Article 3
{
    "_type": "custom:article",
    "title": "Article #3",
    "body": "we are star stuff",
    "categories": ["category3", "category1"],
    "rating": 3
}

Full Text Search

Find all of the nodes with the word star. Simple enough!

Platform platform = Gitana.connect();

Repository repository = platform.readRepository("1234567890abcdef1234");
if (repository == null) {
    throw new RuntimeException("Unable to read repository: 1234567890abcdef1234");
}

Branch branch = repository.readBranch("master");
if (branch == null) {
    throw new RuntimeException("Unable to read master branch");
}

ResultMap<BaseNode> results = branch.searchNodes("star");
System.out.println("The size was: " + results.size()); // 2
for (BaseNode n: results.values())
{
    Node node = (Node) n;
    
    System.out.println("Found a result, title: " + node.getString("title") + ", body: " + node.getString("body"));
}

The results will be:

Found a result, title: Article #2, body: harvesting star light
Found a result, title: Article #3, body: we are star stuff

GraphQL

You can make queries for specific fields or content in related items by using GraphQL. Here we do a simple query for just the title and body of our article type:

String query = """query {
    n_nodes {
        title
    }
}""";

ObjectNode results = branch.graphqlQuery(query);