Tech Blog

Using the Alma APIs with Java Proxy Classes

The Alma REST APIs return JSON natively. This is the natural choice for developers working in dynamic languages, such as Node.js and Ruby. These languages interpret the JSON into native types, such as Array, Hash, String, and make it easy to manipulate data returned by the APIs.

For those who work in a strongly-typed language such as Java, it may be more comfortable to work with the Alma REST API  data structures as full-fledged classes. Luckily, the APIs support XML and even make the XSD schemas available for download. This means that we can use standard Java tools to create proxy classes and marshal/unmarshal between the generated classes and the XML that the APIs accept.

About the XSD Schemas

The documentation for each Alma REST API includes a link to the description of the object that it accepts or returns.
The link takes you to a page which describes the object in detail. At the beginning of the data dictionary, there is a link to the XSD schema which describes the object.

Creating the Proxy Classes

In order to create the proxy classes, we will use functionality provided by JAXB, which is included in the Java JDK. The xjc compiler accepts a namespace to use for the generated classes and the filenames (or URLs) of the XSD schemas.

Update (June 2016): Some REST objects have compound names, such as “Representation File” or “User Deposit”. In these cases, the default behavior of the xjc compiler will create incorrect root element names (UserDeposit rather than user_deposit as the REST API expects). To change that default behavior, we need to create a bindings file and reference it in the call to xjc with the -b flag. The file should contain the following:

<jaxb:bindings jaxb:extensionBindingPrefixes="xjc" version="2.1"
  xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
  xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc">
  <jaxb:globalBindings>
    <xjc:simple/>
  </jaxb:globalBindings>
</jaxb:bindings>

For example, on Windows, you could run:

"%java_home%\bin\xjc" -p com.exlibrisgroup.almarestmodels.representation -extension -b bindings.xml https://developers.exlibrisgroup.com/resources/xsd/rest_representation.xsd
"%java_home%\bin\xjc" -p com.exlibrisgroup.almarestmodels.user -extension -b bindings.xml https://developers.exlibrisgroup.com/resources/xsd/rest_user.xsd

This will create classes in the almarestmodels namespace for two schema files- representation and user. Since this command creates classes for the entire hierarchy of data structures, the result will be a long list of class files ready for use.

 

Unmarshal (Deserialize) from XML to the Class

Now that we’ve created the classes, they’re ready for us to use in our code. First, we need to get the XML from Alma. We can use the JAX-RS package to do so. You can extract the code to call Alma APIs to a utility method such as the one below:
public static String get(String server, String path, String apikey) {
    Client client = ClientBuilder.newBuilder()
      .register(JacksonFeature.class)
      .build();
    WebTarget target = client.target(server).path(path);
    String resp = target.request(MediaType.APPLICATION_XML)
      .header("Authorization", "apikey " + apikey)
      .get(String.class);
    return resp;
}

Now we can retrieve the XML and use JAXB to populate the relevant class(es). For our example, we’ll retreive a user record using the Get User API:

String resp = AlmaRestUtil.get(
    properties.getAlmaUrl(),
    "users/" + userName,
    properties.getApiKey(),
  );

User user = JAXB.unmarshal(new StringReader(resp), User.class);

Now we have a populated user object, and we can access the relevant properties and subclasses:

System.out.println("Retrieved user: " + user.getPrimaryId());
  System.out.println(user.getContactInfo()
    .getEmails()
    .getEmail()
    .get(0)
    .getEmailAddress()
);

Marshal (Serialize) from the Class to XML

We can follow the reverse process to create a new object, marshal it to XML, and send the resulting XML to Alma in a POST API. In our example, we want to create a new digital representation. First, we create the Representation object and set the relevant properties:
Representation rep = new Representation();

// Set Library, Usage Type, and Repository
Representation.Library library = new Representation.Library();
library.setValue("MAIN");
Representation.UsageType usageType = new Representation.UsageType();
usageType.setValue("PRESERVATION_MASTER");
Representation.Repository repository = new Representation.Repository();
repository.setValue("AWS");
rep.setLibrary(library);
rep.setUsageType(usageType);
rep.setRepository(repository);

// Set representation properties
rep.setLinkingParameter1(mmsId);
rep.setIsRemote(true);
rep.setOriginatingRecordId(originatingRecord);

Then we want to marshal the object into an XML string:

StringWriter sw = new StringWriter();
JAXB.marshal(rep, sw);
String xml = sw.toString();

In order to POST our XML to Alma, we can call a utility method similar to the one above for GET:

String resp = AlmaRestUtil.post(
    properties.getAlmaUrl(),
    "bibs/" + mmsId + "/representations",
    properties.getApiKey(),
    xml
);

And here’s the post method:

public static String post(String server, String path, String apikey, 
    String data) {

    Client client = ClientBuilder.newBuilder()
      .register(JacksonFeature.class)
      .build();
    WebTarget target = client.target(server).path(path);
    
    String resp;  
    resp = target.request(MediaType.APPLICATION_XML)
      .header("Authorization", "apikey " + apikey)
      .post(Entity.xml(data)).readEntity(String.class);

    return resp;
}

Now we can even complete the round-trip by unmarshaling the reponse from Alma to read the newly-added properties:

rep = JAXB.unmarshal(new StringReader(resp), Representation.class);
System.out.println("Created new representation: " + rep.getId();

Library system librarians and programmers work in a wide variety of development stacks. We aim to make the Alma REST APIs easy and intuitive to use no matter what language you’re working in. We hope this example of data manipulation with the Alma REST APIs using standard Java tools will be helpful for those working in that environment.

The full code from which these samples were taken is available in this Github repository.

Github

Leave a Reply