8.4.2. Java client samples

The source of this sample can be found at eXo Docs-samples Repository.

The project implements an eXo Calendar Rest Connector that supports some main CRUD operations for demo, that you can read over the ExoCalendarConnectorInterface.java:

public interface ExoCalendarConnectorInterface {

  
  // Calendar : GET, GET, POST, PUT, DELETE.
  public ExoCalendarCollection getCalendars() throws Exception;  
  public ExoCalendar getCalendarById(String calendar_id) throws Exception;  
  public String createCalendar(ExoCalendar calendar) throws Exception;  
  public int updateCalendar(ExoCalendar calendar, String calendar_id) throws Exception;  
  public int deleteCalendar(String calendar_id) throws Exception;  
  
  // Event : GET, GET, POST, PUT, DELETE.
  public ExoEventCollection getEventsByCalendarId(String calendar_id) throws Exception;  
  public ExoEvent getEventById(String event_id) throws Exception;  
  public String createEvent(ExoEvent event, String calendar_id) throws Exception;  
  public int updateEvent(ExoEvent event, String event_id) throws Exception;
  public int deleteEvent(String event_id) throws Exception;
  
  // Task : GET, GET, POST, PUT, DELETE.
  public ExoTaskCollection getTasksByCalendarId(String calendar_id) throws Exception;
  public ExoTask getTaskById(String task_id) throws Exception;
  public String createTask(ExoTask task, String calendar_id) throws Exception;
  public int updateTask(ExoTask task, String task_id) throws Exception;
  public int deleteTask(String task_id) throws Exception;
  
  // Attachment (of event) : GET, GET, POST, DELETE.
  public AttachmentCollection getAttachmentsByEventId(String event_id) throws Exception;
  public Attachment getAttachmentById(String attachment_id) throws Exception;
  public String createAttachment(List<Path> paths, String event_id) throws Exception;
  public int deleteAttachment(String event_id) throws Exception;
  
  // Invitation : GET, GET, POST, PUT, DELETE.
  public InvitationCollection getInvitationsByEventId(String event_id) throws Exception;
  public Invitation getInvitationById(String invitation_id) throws Exception;
  public String createInvitation(Invitation invitation, String event_id) throws Exception;
  public int updateInvitation(Invitation invitation, String invitation_id) throws Exception;
  public int deleteInvitation(String invitation_id) throws Exception;
}

The overview of the project:

JSON Parsing

You can use Gson, Jackson or alternate libraries to parse JSON to Java object and vice versa.

Gson is used in this sample. Its dependency is:


<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.3.1</version>
</dependency>

You should write POJO classes for every object you want to work with. See the classes in org.exoplatform.calendar.client.model package. The following is the ExoCalendar POJO:

package org.exoplatform.calendar.client.model;

public class ExoCalendar {
  
  String editPermission;
  String viewPermission;
  String privateURL;
  String publicURL;
  String icsURL;
  String color;
  String name;
  String type;
  String owner;
  String timeZone;
  String description;
  String[] groups;
  String href;
  String id;
    
    // Getters and setters.
    // ...
}

To serialize the object to a JSON string, or deserialize:

Gson gson = new Gson();

// serialize object to JSON
String json = gson.toJson(calendar_object);
// parse JSON to an object
ExoCalendar new_calendar_object = gson.fromJson(json, ExoCalendar.class);

The JSON string that is returned from a single calendar query:

{
"editPermission": "",
"viewPermission": "",
"privateURL": null,
"publicURL": null,
"icsURL": "http://localhost:8080/rest/private/v1/calendar/calendars/john-defaultCalendarId/ics",
"description": null,
"color": "asparagus",
"timeZone": "Europe/Brussels",
"groups": null,
"name": "John Smith",
"type": "0",
"owner": "john",
"href": "http://localhost:8080/rest/private/v1/calendar/calendars/john-defaultCalendarId",
"id": "john-defaultCalendarId"
}

A collection query JSON always looks like this:

{
"limit": 10,
"data": [
	{calendar1},
	{calendar2}
],
"size": -1,
"offset": 0
}

The POJO for collection:

public class ExoCalendarCollection {

  
  int limit;
  int size;
  int offset;
  ExoCalendar[] data;
    
    // Getters and setters.
    // ...
}

ISO8601 DateTime format

Some key fields require a correct DateFormat to parse/format:

In Java 7, you can use SimpleDateFormat with the following pattern to parse/format those fields:

DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");

Date date1 = new Date();
//format
String s = df.format(date1);
//parse
Date date2 = df.parse(s);

However, the pattern may not work in other Platforms. Another approach is to re-use eXo's ISO8601 class. It is potentially helpful when you need to parse 'Z' timezone.

The source is here. You can use the following Maven dependency:


<dependency>
    <groupId>org.exoplatform.kernel</groupId>
    <artifactId>exo.kernel.commons</artifactId>
</dependency>

The code sample of using this util:

import org.exoplatform.commons.utils.ISO8601;

//
String s1 = "2015-01-15T05:00:000Z";
Calendar cal = ISO8601.parse(s1);
System.out.println(cal.getTime());
String s2 = ISO8601.format(cal);
System.out.println(s2);

Authentication

Use java.net.Authenticator to authenticate your client with a username and password. Better use its method setDefault(Authenticator authenticator) so the credential is sent automatically along with every request.

In the sample, the ExoCalendarConnector class provides a constructor that sets default authenticator:

import java.net.Authenticator;

import java.net.PasswordAuthentication;
public class ExoCalendarConnector implements ExoCalendarConnectorInterface {
  public ExoCalendarConnector(String base_url, String username, String password) {
    this.BASE_URL = base_url;
    final String _username = username;
    final String _password = password;
    
    Authenticator.setDefault(new Authenticator() {
      @Override
      protected PasswordAuthentication getPasswordAuthentication() {
        return new PasswordAuthentication(_username, _password.toCharArray());
      }
    });
  }
}

Using HttpURLConnection for CRUD requests

You need a Http Client to send requests to the Rest service. In the sample, java.net.HttpURLConnection is used.

Here is the code for sending a GET. The result string then can be converted to a Calendar or Event or some object accordingly.

import java.net.HttpURLConnection;

import java.net.URL;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
  // GET
  public static String get(String url) throws Exception {
    HttpURLConnection connection = (HttpURLConnection) (new URL(url)).openConnection();
    connection.setRequestMethod("GET");
    connection.connect();
    
    int code = connection.getResponseCode();
    if (code > 300) {
      connection.disconnect();
      return null;
    }
    InputStream in = connection.getInputStream();
    BufferedReader reader = new BufferedReader(new InputStreamReader(in));
    String line = null;
    StringBuilder builder = new StringBuilder();
    while ((line = reader.readLine()) != null) {
      builder.append(line).append("\n");
    }
    in.close();
    reader.close();
    connection.disconnect();
    return builder.toString();
  }

For a POST request, pay attention to set the request method and the content-type:

import java.io.DataOutputStream;


  // POST
  public static String post(String json, String url) throws Exception {
    HttpURLConnection connection = (HttpURLConnection) (new URL(url)).openConnection();
    connection.setRequestMethod("POST");
    connection.setDoOutput(true);
    connection.setUseCaches(false);
    connection.setRequestProperty("Content-Type", "application/JSON");
    
    // Write to the connection output stream.
    DataOutputStream out = new DataOutputStream(connection.getOutputStream());
    out.writeBytes(json);
    
    int code = connection.getResponseCode();
    if (code > 300) {
      out.flush();
      out.close();
      connection.disconnect();
      return null;
    }
    String href = connection.getHeaderField("Location");
    out.flush();
    out.close();
    connection.disconnect();
    return href;
  }

Here you see value of the (response) header "Location" is returned. All the Create operations should return this on success. For example when you create an Event, the event's href (a URL to continue to get the created event) is returned.

See PUT and DELETE code in HttpUtils.java.

CRUD Examples

With the POJO models, CRUD operations are very similar between kinds of objects. Hereunder is a code sample to do a chain of tasks:

- create a calendar
- create an event
- update the event
- delete the event
- delete the calendar
 ExoCalendarConnector connector = new ExoCalendarConnector("http://localhost:8080");


String created = Long.toString(System.currentTimeMillis());
// Create calendar.
ExoCalendar calendar = new ExoCalendar();
calendar.setType("0");
calendar.setName(created);
connector.createCalendar(calendar);
// Get the list of calendars and search for one.
String calendar_id = null;
ExoCalendar[] calendars = connector.getCalendars().getData();
int len = calendars.length;
for (int i = 0; i < len; i++) {
    if (calendars[i].getName().equals(created)) {
        calendar_id = calendars[i].getId();
    }
}
// Create event.
ExoEvent event = new ExoEvent();
event.setSubject(created);
Date from = new Date((new Date()).getTime() + TimeUnit.DAYS.toMillis(1)); //from = tomorrow
Date to = new Date(from.getTime() + TimeUnit.HOURS.toMillis(4)); //to = from + 4 hours
event.setFrom((new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")).format(from));
event.setTo((new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")).format(to));
String href = connector.createEvent(event, calendar_id);
System.out.println("Event created, href : " + href);
// Get the list of events then get an event specified by id.
ExoEvent[] events = connector.getEventsByCalendarId(calendar_id).getData();
len = 0; len = events.length; String event_id = null;
for (int i = 0; i < len; i++) {
    if (events[i].getSubject().equals(created)) {
        event_id = events[i].getId();
    }
}
ExoEvent new_event = connector.getEventById(event_id);
System.out.println("Event found, its from is : " + new_event.getFrom());
// Update the event.
new_event.setDescription(created);
System.out.println("Update event, response code : " + connector.updateEvent(new_event, event_id));
// Delete the event.
System.out.println("Delete event, response code : " + connector.deleteEvent(event_id));
// Delete the calendar.
System.out.println("Delete calendar, response code : " + connector.deleteCalendar(calendar_id));

Uploading attachment files

eXo Rest framework uses Apache upload service, then you need to send files in multipart/form-data in order to create attachments. The following code shows how to send a POST with multipart content. The method accepts a list of java.nio.file.Path, for each Path the file data is written to a content part with boundary.

import java.nio.file.Files;

import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.io.DataOutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
  // UPLOAD
  public static String upload(List<Path> paths, String url) throws Exception {
    // form-data stuffs
    String crlf = "\r\n";
    String twoHyphens = "--";
    String boundary = "*****";
    String attachmentName;
    String attachmentFileName;
    byte[] data;
    
    // set up the connection
    HttpURLConnection connection = (HttpURLConnection) (new URL(url).openConnection());
    connection.setRequestMethod("POST");
    connection.setDoOutput(true);
    connection.setUseCaches(false);
    connection.setRequestProperty("Cache-Control", "nocache");
    connection.setRequestProperty("Connection", "Keep-Alive");
    connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
    
    // write to connection output stream
    DataOutputStream out = new DataOutputStream(connection.getOutputStream());
    int len = paths.size();
    for (int i = 0; i < len; i++) {
      attachmentFileName = paths.get(i).getFileName().toString();
      attachmentName = attachmentFileName;
      data = Files.readAllBytes(paths.get(i));
      out.writeBytes(twoHyphens + boundary + crlf);
      out.writeBytes("Content-Disposition: form-data;"
                     + "name=\"" + attachmentName + "\";"
                     + "filename=\"" + attachmentFileName + "\"" + crlf);
      out.writeBytes(crlf);
      out.write(data);
      out.writeBytes(crlf);
    }
    out.writeBytes(twoHyphens + boundary + twoHyphens + crlf);
    
    int code = connection.getResponseCode();
    if (code > 300) {
      out.flush();
      out.close();
      connection.disconnect();
      return null;
    }
    String href = connection.getHeaderField("Location");
    out.flush();
    out.close();
    connection.disconnect();
    return href;
  }
Copyright ©. All rights reserved. eXo Platform SAS
blog comments powered byDisqus