Learning to Use Cortex Java SDK
Cortex Java SDK (Software Development Kit) can consume Cortex resources in client applications that are built with Java.
For an example to review and use, see cortex-sdk-example.
Setup
Cortex Java SDK is available from the Elastic Path Public Maven Repository.
To add Cortex Java SDK to your Maven project, add the following dependencies to your pom.xml
:
<properties>
<guice.version>6.0.0</guice.version>
<cortex-jaxrs-client.version>4.0.0</cortex-jaxrs-client.version>
<json-unmarshaller.version>1.1.2</json-unmarshaller.version>
</properties>
<dependencies>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>${guice.version}</version>
</dependency>
<dependency>
<groupId>com.elasticpath.rest</groupId>
<artifactId>cortex-jaxrs-client</artifactId>
<version>${cortex-jaxrs-client.version}</version>
</dependency>
<dependency>
<groupId>com.elasticpath.json</groupId>
<artifactId>json-unmarshaller</artifactId>
<version>${json-unmarshaller.version}</version>
</dependency>
</dependencies>
Usage
Elastic Path's Cortex Java Client is based on the JAX-RS Java API and the Jersey framework and includes a set of extensions to facilitate development with Cortex. The Cortex Java Client exposes the raw JAX-RS Client
service as well as a CortexClient
to facilitate making calls to Cortex.
The JAX-RS Client
can call any REST service, not just Cortex. The CortexClient
provides the following additional capabilities for making Cortex calls:
- A wrapper around the JAX-RS
Client
that scopes Cortex calls to a specific user - JSON Unmarshaller annotations to marshal/unmarshal deep JSON object graphs into shallow POJOs using JsonPath.
CortexClient
The Cortex client provides the following:
- A user-scoped wrapper around the JAX-RS client to facilitate REST calls to Cortex
- JSON Unmarshaller types to marshall/unmarshal JSONs
tip
Storing Client Instances:
Client instances should not be stored between requests.
Using Cortex Client
To use the Cortex client in your Java project, you need to instantiate the required beans. The following example shows how to use Google Guice to instantiate the client:
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import com.fasterxml.jackson.contrib.jsonpath.DefaultJsonUnmarshaller;
import com.fasterxml.jackson.contrib.jsonpath.JsonUnmarshaller;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import com.google.inject.Singleton;
import org.glassfish.jersey.client.ClientConfig;
import com.elasticpath.rest.client.CortexClientFactory;
import com.elasticpath.rest.client.apache.HttpClientConfigurator;
import com.elasticpath.rest.client.apache.HttpClientConfiguratorBuilder;
import com.elasticpath.rest.client.impl.CortexClientFactoryImpl;
import com.elasticpath.rest.client.jaxrs.WebApplicationExceptionMapper;
import com.elasticpath.rest.client.unmarshalling.JacksonProvider;
import com.elasticpath.rest.client.unmarshalling.JsonUnmarshallReaderInterceptor;
import com.elasticpath.rest.client.urlbuilding.CortexUrlFactory;
import com.elasticpath.rest.client.urlbuilding.impl.CortexUrlFactoryImpl;
public class BasicModule extends AbstractModule {
private static final String CORTEX_BASE_URL_ENV_NAME = "cortexBaseUrl";
@Override
protected void configure() {
bind(JsonUnmarshaller.class).to(DefaultJsonUnmarshaller.class).in(Singleton.class);
bind(CortexUrlFactory.class).to(CortexUrlFactoryImpl.class).in(Singleton.class);
}
/**
* Creates cortex client factory.
*
* @param jacksonProvider the jackson provider.
* @param jsonUnmarshallReaderInterceptor the json unmarshaller interceptor.
* @param cortexUrlFactory the factory for creating cortex urls.
* @return the cortex client factory.
*/
@Provides
@Singleton
protected CortexClientFactory createCortexClientFactory(final JacksonProvider jacksonProvider,
final JsonUnmarshallReaderInterceptor jsonUnmarshallReaderInterceptor,
final CortexUrlFactory cortexUrlFactory) {
final ClientConfig clientConfig = new ClientConfig();
clientConfig.register(new WebApplicationExceptionMapper())
.register(jacksonProvider)
.register(jsonUnmarshallReaderInterceptor);
final HttpClientConfigurator httpClientConfigurator = new HttpClientConfiguratorBuilder().build();
httpClientConfigurator.configure(clientConfig);
final Client jaxRsClient = ClientBuilder.newClient(clientConfig);
return new CortexClientFactoryImpl(cortexUrlFactory, jaxRsClient, getCortexBaseUrl());
}
/**
* Gets cortex base url from environment.
*
* @return the cortex base url string.
*/
@Provides
@Singleton
protected String getCortexBaseUrl() {
String cortexBaseUrl = System.getenv(CORTEX_BASE_URL_ENV_NAME);
if (cortexBaseUrl == null) {
cortexBaseUrl = "http://localhost:9080/cortex";
}
return cortexBaseUrl;
}
}
import java.util.Objects;
import com.google.inject.Guice;
import com.google.inject.Injector;
import view.CartView;
import com.elasticpath.rest.client.CortexClient;
import com.elasticpath.rest.client.CortexClientFactory;
import com.elasticpath.rest.client.CortexResponse;
public class Main {
public static void main(String[] args) {
Injector injector = Guice.createInjector(new BasicModule());
CortexClientFactory cortexClientFactory = injector.getInstance(CortexClientFactory.class);
CortexClient cortexClient = cortexClientFactory.create(getAuthToken(), getScope());
CortexResponse<CartView> cortexResponse = cortexClient.get(CartView.class);
System.out.println(cortexResponse.getCortexView().getCartDescriptor());
}
private static String getAuthToken() {
String authToken = System.getenv("authToken");
Objects.requireNonNull(authToken, "Please set JVM parameter authToken.");
return authToken;
}
private static String getScope() {
String scope = System.getenv("scope");
Objects.requireNonNull(scope, "Please set JVM parameter scope.");
return scope;
}
}
Sending Requests
Once a client is obtained, it can be used to fetch a view:
CartView cart = client.get(CartView.class);
CartView is a custom class with @JsonPath
and @JsonProperty
annotations.
Constructing URIs
Cortex Java SDK provides four class level annotations to construct Cortex resource URLs:
@Uri
: Defines the URI of a Cortex entry point resource@Zoom
: Adds a Zoom query parameter to the request URL@Path
: Used together with@Zoom
,@Path
specifies the relation/link to follow from the Zoom request@FollowLocation
: Adds a FollowLocation query parameter to the request URL@Format
: Adds a Format query parameter to the request URL
Zoom
, FollowLocation
and Format
Example: A class that models the expected response should be annotated as follows:
@Zoom(@Path("order"))
@FollowLocation
@Format({FormatOptionEnum.STANDARDLINKS, FormatOptionEnum.ZOOM_NOSELF, FormatOptionEnum.ZOOM_NODATALINKS})
public class Cart {}
URLs with Zoom, FollowLocation or Format query parameters can be constructed by calling the createResourceUrlWithQueryParameters()
method:
baseUrl = "http://localhost:9080/cortex/"
path = "carts/mobee/default"
result = cortexUrlFactory.addQueryParametersToResourceUrl(baseUrl, path, Cart.class)
//result = "http://localhost:9080/cortex/carts/mobee/default?zoom=order&followLocation=true"
Example: Without Query Parameters
URLs without query parameters can be constructed by calling the createResourceUrl()
method:
baseUrl = "http://localhost:9080/cortex/"
path = "carts/mobee/default"
result = cortexUrlFactory.createResourceUrl(baseUrl, path)
//result = "http://localhost:9080/cortex/carts/mobee/default"
Example: With Entry Point Resource
A class that models the expected response should be annotated as follows:
@Uri(“carts/{scope}/default”)
@Zoom(@Path("lineitems"))
@FollowLocation
public class Carts {}
URLs using entry point URIs can be constructed by calling the createResourceUrlFromAnnotations()
method:
baseUrl = "http://localhost:9080/cortex/"
store = "mobee"
result = cortexUrlFactory.createResourceUrlFromAnnotations(baseUrl, store, Carts.class)
//result = "http://localhost:9080/cortex/carts/mobee/default?zoom=lineitems&followLocation=true"
Zoom
, FollowLocation
and Format
Query Parameters
Example: Programmatically Specify String cartUri = "carts/mobee/default";
Map<String, Object> queryParameters = ImmutableMap.of("zoom", "lineitems",
"format", "standardlinks,zoom.noself,zoom.nodatalinks",
"followLocation", "true");
String cartJsonResponseString = cortexClient.get(cartUri, queryParameters).getCortexView();
tip
An alternative way to get response without annotation:
The CortexClient#get(String resourcePath, Map<String, Object> queryParameters)
method accepts query parameters. You can customize the query parameters without an annotation. It works like a proxying request to Cortex and forwards a raw JSON string response back to the caller.
Unmarshalling Cortex Responses
Cortex Java SDK unmarshalling is provided by the Elastic Path JSON Unmarshaller, an open source project. This section shows some simple examples of how to use the JSON Unmarshaller. For more complex unmarhalling examples, see the JSON Unmarshaller project page.
Cortex Java SDK provides two annotations to extract data from a Cortex response:
@JsonProperty
: Extracts a JSON property from a Cortex response@JsonPath
: Uses JSONPath to extract either a single or multiple JSON properties from a Cortex response. This annotation is useful to extract nested JSON properties
tip
JSONPath Expression Tester
Cortex Studio comes bundled with a JSONPath tester for creating and testing JSONPath expressions.
The examples below parse this response:
{
"self": {
"type": "elasticpath.carts.cart",
"uri": "/carts/mobee/gwu=?zoom=lineitems:element",
"href": "http://api.demo.elasticpath.com/cortex/carts/mobee/gwu=?zoom=lineitems:element"
},
"total-quantity": 1,
"_lineitems": [
{
"_element": [
{
"self": {
"type": "elasticpath.carts.line-item",
"uri": "/carts/mobee/gwu=/lineitems/gq4=",
"href": "http://api.demo.elasticpath.com/cortex/carts/mobee/gwu=/lineitems/gq4="
},
"links": [
{
"rel": "list",
"type": "elasticpath.collections.links",
"uri": "/carts/mobee/gwu=/lineitems",
"href": "http://api.demo.elasticpath.com/cortex/carts/mobee/gwu=/lineitems"
}
],
"quantity": 1
}
]
}
],
"links": [
{
"rel": "lineitems",
"rev": "cart",
"type": "elasticpath.collections.links",
"uri": "/carts/mobee/gwu=/lineitems",
"href": "http://api.demo.elasticpath.com/cortex/carts/mobee/gwu=/lineitems"
},
{
"rel": "order",
"rev": "cart",
"type": "elasticpath.orders.order",
"uri": "/orders/mobee/hbr=",
"href": "http://api.demo.elasticpath.com/cortex/orders/mobee/hbr="
},
{
"rel": "total",
"rev": "cart",
"type": "elasticpath.totals.total",
"uri": "/totals/carts/mobee/gwu=",
"href": "http://api.demo.elasticpath.com/cortex/totals/carts/mobee/gwu="
}
]
}
@JsonProperty
Example: Extract JSON Property using Extract a single, non-nested, JSON property:
public class Cart {
@JsonProperty("total-quantity")
private String totalQuantity;
}
@JsonPath
Example: Extract Nested JSON Properties using Extract nested JSON properties:
public class Cart {
//Non-nested JSON property
@JsonPath("$.total-quantity")
private int totalQuantity;
//Nested Property
@JsonPath("$._lineitems[0]._element[0].quantity")
private int quantity;
//Nested Array
@JsonPath("$._lineitems[0]._element")
private List<LineItem> lineItems;
}