Announcement: You can find the guides for Commerce 7.5 and later on the new Elastic Path Documentation site. The Developer Center continues to support Commerce 6.13.0 through 7.4.1.Visit new site

A Closer Look at the Hello World Application

A Closer Look at the Hello World Application

In this section, we take a closer look at the Hello World resource and see how it returns the "Hello World" string.

Components of the Hello World resource

Resource Representation

All resources output data in the form of immutable objects called representations. The Cortex API kernel converts a resource's representation into a JSON object, which is then passed back to the client application. For more details on the JSON conversion process, see Architecture Call Stack.

In this tutorial, the Cortex API outputs a JSON object formed from a HelloWorld representation. In the HelloWorld representation, the getter getMessage() returns the "Hello World" string from the representation.

The HelloWorld representation, shown below, extends the Representation interface:

               <html><body>
<pre class="j-path">rest-resource-helloworld<span class="j-pathsep">/</span>src<span class="j-pathsep">/</span>main<span class="j-pathsep">/</span>java<span class="j-pathsep">/</span>com<span class="j-pathsep">/</span>example<span class="j-pathsep">/</span>rest<span class="j-pathsep">/</span>schema<span class="j-pathsep">/</span>representation<span class="j-pathsep">/</span>HelloWorldRepresentation.java</pre>
<pre class="java"><span class="j-key">import </span>com.elasticpath.rest.schema.Property;
<span class="j-key">import </span>com.elasticpath.rest.schema.Representation;

<span class="j-jdoc">/**
 * The hello world representation.
 */
</span><span class="j-key">public interface </span>HelloWorldRepresentation <span class="j-key">extends </span>Representation <span class="j-sym">{

  </span><span class="j-jdoc">/** MIME type. */
  </span>String TYPE = <span class="j-str">&#34;application/vnd.mycompany.helloworld&#34;</span>;

  <span class="j-jdoc">/** Message property. */
  </span>String MESSAGE_PROPERTY = <span class="j-str">&#34;message&#34;</span>;

  <span class="j-jdoc">/**
   * </span><span class="j-jdoc-key">@return </span><span class="j-jdoc">message to be displayed
   */
  </span>@Property<span class="j-sym">(</span>name = MESSAGE_PROPERTY<span class="j-sym">)
  </span>String getMessage<span class="j-sym">()</span>;
<span class="j-sym">}</span></pre>
</body></html>
            

You must follow two rules when extending the Representation interface:

  • The only methods in a representation are getters.
  • Representation interfaces don't have matching implementation classes.

Resource Mutator

All representations are immutable, so a representation requires an accompanying mutator to create representations and set properties. The HelloWorld mutator, shown below, extends the RepresentationMutator class:

               <html><body>
<pre class="j-path">rest-resource-helloworld<span class="j-pathsep">/</span>src<span class="j-pathsep">/</span>main<span class="j-pathsep">/</span>java<span class="j-pathsep">/</span>com<span class="j-pathsep">/</span>example<span class="j-pathsep">/</span>rest<span class="j-pathsep">/</span>resources<span class="j-pathsep">/</span>helloworld<span class="j-pathsep">/</span>HelloWorldMutator.java</pre>
<pre class="java"><span class="j-key">import </span>com.example.rest.schema.representation.HelloWorldRepresentation;

<span class="j-key">import </span>com.elasticpath.rest.ResourceTypeFactory;
<span class="j-key">import </span>com.elasticpath.rest.schema.RepresentationMutator;

<span class="j-jdoc">/**
 * Mutator for </span><span class="j-jdoc-link">{@link HelloWorldRepresentation}</span><span class="j-jdoc">.
 */
</span><span class="j-key">public final class </span>HelloWorldMutator <span class="j-key">extends </span>RepresentationMutator&lt;HelloWorldRepresentation&gt; <span class="j-sym">{

  </span><span class="j-jdoc">/**
   * Creates a new instance of </span><span class="j-jdoc-link">{@link HelloWorldMutator}</span><span class="j-jdoc">. This also creates the </span><span class="j-jdoc-link">{@link HelloWorldRepresentation} </span><span class="j-jdoc">inside.
   *
   * </span><span class="j-jdoc-key">@return </span><span class="j-jdoc">the new </span><span class="j-jdoc-link">{@link HelloWorldMutator}
   </span><span class="j-jdoc">*/
  </span><span class="j-key">public static </span>HelloWorldMutator create<span class="j-sym">() {
    </span><span class="j-key">return new </span>HelloWorldMutator<span class="j-sym">(</span>ResourceTypeFactory.createRepresentation<span class="j-sym">(</span>HelloWorldRepresentation.<span class="j-key">class</span><span class="j-sym">))</span>;
  <span class="j-sym">}

  </span><span class="j-jdoc">/**
   * Creates a new instance of </span><span class="j-jdoc-link">{@link HelloWorldMutator} </span><span class="j-jdoc">for a provided representation.
   *
   * </span><span class="j-jdoc-key">@param </span><span class="j-jdoc">helloWorldRepresentation the hello world representation
   * </span><span class="j-jdoc-key">@return </span><span class="j-jdoc">the new </span><span class="j-jdoc-link">{@link HelloWorldMutator}
   </span><span class="j-jdoc">*/
  </span><span class="j-key">public static </span>HelloWorldMutator create<span class="j-sym">(</span><span class="j-key">final </span>HelloWorldRepresentation helloWorldRepresentation<span class="j-sym">) {
    </span><span class="j-key">return new </span>HelloWorldMutator<span class="j-sym">(</span>helloWorldRepresentation<span class="j-sym">)</span>;
  <span class="j-sym">}

  </span><span class="j-jdoc">/**
   * constructor for </span><span class="j-jdoc-link">{@link HelloWorldMutator}</span><span class="j-jdoc">.
   *
   * </span><span class="j-jdoc-key">@param </span><span class="j-jdoc">representation the representation.
   */
  </span><span class="j-key">private </span>HelloWorldMutator<span class="j-sym">(</span><span class="j-key">final </span>HelloWorldRepresentation representation<span class="j-sym">) {
    </span><span class="j-key">super</span><span class="j-sym">(</span>representation<span class="j-sym">)</span>;
  <span class="j-sym">}

  </span><span class="j-jdoc">/**
   * Sets the message on this representation.
   *
   * </span><span class="j-jdoc-key">@param </span><span class="j-jdoc">message the message
   * </span><span class="j-jdoc-key">@return </span><span class="j-jdoc">this instance
   */
  </span><span class="j-key">public </span>HelloWorldMutator setMessage<span class="j-sym">(</span><span class="j-key">final </span>String message<span class="j-sym">) {
    </span>set<span class="j-sym">(</span>HelloWorldRepresentation.MESSAGE_PROPERTY, message<span class="j-sym">)</span>;
    <span class="j-key">return this</span>;
  <span class="j-sym">}
}</span></pre>
</body></html>
            

You must follow three rules when extending the RepresentationMutator class:

  • Mutators should override the create method and constructor defined in RepresentationMutator.
  • The names of all setters in the mutator and getters in the representation interface must match. For example, the getMessage method in the representation must have a setter named setMessage in the mutator.
  • In setters, use the the RepresentationMutator's set(PROPERTY, VALUE) method to assign values to representation properties. This will make the Cortex API automatically instantiate the property and implement the matching getter.

Resource Rel

The resource's rel and rev properties, used by the Cortex API kernel, are defined in HelloWorldResourceRels.java.

               <html><body>
<pre class="j-path">rest-resource-helloworld<span class="j-pathsep">/</span>src<span class="j-pathsep">/</span>main<span class="j-pathsep">/</span>java<span class="j-pathsep">/</span>com<span class="j-pathsep">/</span>example<span class="j-pathsep">/</span>rest<span class="j-pathsep">/</span>resources<span class="j-pathsep">/</span>helloworld<span class="j-pathsep">/</span>rel<span class="j-pathsep">/</span>HelloWorldResourceRels.java</pre>
<pre class="java"><span class="j-jdoc">/**
 * Constants for Hello World resources.
 */
</span><span class="j-key">public class </span>HelloWorldResourceRels <span class="j-sym">{

  </span><span class="j-jdoc">/**
   * Hello world rel identifier.
   */
  </span><span class="j-key">public static final </span>String HELLO_WORLD_REL = <span class="j-str">&#34;helloworld&#34;</span>;

  <span class="j-jdoc">/**
   * Hello world rev identifier.
   */
  </span><span class="j-key">public static final </span>String HELLO_WORLD_REV = HELLO_WORLD_REL;

<span class="j-sym">}</span></pre>
</body></html>
            

Resource Operator

The resource operator handles the requests the resource receives. In HelloWorldResourceOperator, shown below, the processRead method sets the "Hello World" string to the representation and wraps the representation in an OperationResult object. The OperationResult is then sent to the kernel for JSON conversion. See Architecture Call Stack for a diagram on how requests are processed.

               <html><body>
<pre class="j-path">rest-resource-helloworld<span class="j-pathsep">/</span>src<span class="j-pathsep">/</span>main<span class="j-pathsep">/</span>java<span class="j-pathsep">/</span>com<span class="j-pathsep">/</span>example<span class="j-pathsep">/</span>rest<span class="j-pathsep">/</span>resources<span class="j-pathsep">/</span>helloworld<span class="j-pathsep">/</span>impl<span class="j-pathsep">/</span>HelloWorldResourceOperatorImpl.java</pre>
<pre class="java"><span class="j-jdoc">/**
 * Processes the resource operations on HelloWorld.
 */
</span>@Singleton
@Named<span class="j-sym">(</span><span class="j-str">&#34;helloWorldResourceOperator&#34;</span><span class="j-sym">)
</span>@Path<span class="j-sym">(</span>ResourceName.PATH_PART<span class="j-sym">)
</span><span class="j-key">public class </span>HelloWorldResourceOperatorImpl <span class="j-key">extends </span>AbstractAnnotatedResourceOperator <span class="j-sym">{

  </span><span class="j-key">private static final </span>String HELLO_WORLD = <span class="j-str">&#34;Hello World&#34;</span>;


  <span class="j-jdoc">/**
   * Handles a request for the hello world resource.
   *
   * </span><span class="j-jdoc-key">@param </span><span class="j-jdoc">resource the resource
   * </span><span class="j-jdoc-key">@param </span><span class="j-jdoc">operation the Resource Operation
   * </span><span class="j-jdoc-key">@return </span><span class="j-jdoc">the operation result
   */
  </span>@Path
  @OperationType<span class="j-sym">(</span>Operation.READ<span class="j-sym">)
  </span><span class="j-key">public </span>OperationResult processRead<span class="j-sym">(
    </span>@ResourceName
    <span class="j-key">final </span>String resource,
    <span class="j-key">final </span>ResourceOperation operation<span class="j-sym">) {

    </span>String selfUri = URIUtil.format<span class="j-sym">(</span>resource<span class="j-sym">)</span>;
    Self self = SelfFactory.createSelf<span class="j-sym">(</span>selfUri, HelloWorldRepresentation.TYPE, <span class="j-num">0</span><span class="j-sym">)</span>;
    HelloWorldMutator exampleMutator = HelloWorldMutator.create<span class="j-sym">()</span>;
    exampleMutator.setMessage<span class="j-sym">(</span>HELLO_WORLD<span class="j-sym">)
      </span>.setSelf<span class="j-sym">(</span>self<span class="j-sym">)</span>;

    <span class="j-key">return </span>OperationResultFactory.createReadOK<span class="j-sym">(</span>exampleMutator.getRepresentation<span class="j-sym">()</span>, operation<span class="j-sym">)</span>;
  <span class="j-sym">}</span></pre>
</body></html>
            

As you can see above, there are several annotations on both the class and the processRead method.

On the class:

  • The @Named annotation is used by the Spring Injector to differentiate resource components.
  • The @Path annotation, along with the specified annotation interface, captures portions of the URI. The annotation interface points to a regex pattern that specifies how to parse the URI and identifies which property is being captured. In this case, the ResourceName.PATH_PART annotation interface captures the resource name from the URI.

On the processRead method:

  • The @OperationType annotation tells the kernel the CRUD operations that the process method maps to.
  • The @Path annotation on the processRead() method matches subresources to the appropriate process methods. Since HelloWorld doesn't have a subresource, the @Path is blank.

The ResourceName annotation interface the class level @Path annotation uses is below:

               <html><body>
<pre class="j-path">commons<span class="j-pathsep">/</span>src<span class="j-pathsep">/</span>main<span class="j-pathsep">/</span>java<span class="j-pathsep">/</span>com<span class="j-pathsep">/</span>elasticpath<span class="j-pathsep">/</span>rest<span class="j-pathsep">/</span>resource<span class="j-pathsep">/</span>dispatch<span class="j-pathsep">/</span>operator<span class="j-pathsep">/</span>annotation<span class="j-pathsep">/</span>ResourceName.java</pre>
<pre class="java"><span class="j-key">package </span>com.elasticpath.rest.resource.dispatch.operator.annotation;

<span class="j-key">import </span>java.lang.annotation.ElementType;
<span class="j-key">import </span>java.lang.annotation.Retention;
<span class="j-key">import </span>java.lang.annotation.RetentionPolicy;
<span class="j-key">import </span>java.lang.annotation.Target;

<span class="j-key">import </span>com.elasticpath.rest.resource.dispatch.operator.annotation.patterns.UriPatterns;

<span class="j-jdoc">/**
 * Annotates a method parameter to be the resource name.
 */
</span>@Target<span class="j-sym">(</span>ElementType.PARAMETER<span class="j-sym">)
</span>@Retention<span class="j-sym">(</span>RetentionPolicy.RUNTIME<span class="j-sym">)
</span>@PathParam<span class="j-sym">(</span><span class="j-str">&#34;resourceName&#34;</span><span class="j-sym">)
</span>@SuppressWarnings<span class="j-sym">(</span><span class="j-str">&#34;PMD.VariableNamingConventions&#34;</span><span class="j-sym">)
</span><span class="j-key">public </span>@interface ResourceName <span class="j-sym">{

  </span><span class="j-jdoc">/**
   * </span><span class="j-jdoc-link">{@link Path} </span><span class="j-jdoc">pattern to capture the Resource name.
   */
  </span>String PATH_PART = <span class="j-str">&#34;{resourceName:&#34; </span>+ UriPatterns.RESOURCE_NAME_PATTERN + <span class="j-str">&#34;}&#34;</span>;
<span class="j-sym">}</span></pre>
</body></html>
            

Configuring OSGi and Spring to run the new resource

Resources have two configuration files responsible for integrating the resource with Cortex API: applicationContext-resource-server.xml and blueprint.xml.

The Spring configuration file applicationContext-resource-server.xml defines two beans for setting up the resource server: resourceServerName and resourceServer.

The resourceServerName bean declares the resource's name that appears in the resource's URIs.

The resourceServer bean creates an AnnotatedResourceServer instance for the resource, which is added to a map of resource servers that the kernel maintains. The bean takes in a ResourceOperator argument, which identifies the resource operator class the server uses when the resource receives requests. In HelloWorld, this ResourceOperator is helloWorldResourceOperator.

               <html><body>
<pre class="j-path">rest-resource-helloworld<span class="j-pathsep">/</span>src<span class="j-pathsep">/</span>main<span class="j-pathsep">/</span>resources<span class="j-pathsep">/</span>spring<span class="j-pathsep">/</span>applicationContext-helloworld-resource.xml</pre>
<pre class="j-text"><code>&lt;bean name="resourceServerName" class="java.lang.String"&gt;
	&lt;constructor-arg value="helloworld"/&gt;
&lt;/bean&gt;

&lt;bean name="resourceServer"
	class="com.elasticpath.rest.resource.dispatch.DispatchResourceServerImpl"&gt;
	&lt;constructor-arg ref="resourceOperationDispatcher" /&gt;
	&lt;constructor-arg&gt;
		&lt;array value-type="com.elasticpath.rest.resource.dispatch.operator.ResourceOperator"&gt;
			&lt;ref bean="helloWorldResourceOperator" /&gt;
		&lt;/array&gt;
	&lt;/constructor-arg&gt;
&lt;/bean&gt;</code></pre>
</body></html>
            

The OSGi blueprint file helloworld-blueprint.xml declares the resource server as an exported service for the OSGiFrameworkProvider to include in bundle loading. It also declares the permission lookup as a separate service so permissions can be checked before a user enters the resource.

Note: blueprint.xml naming

As a convention, Elastic Path names all blueprint.xml files as <resource name>-blueprint.xml.

               <html><body>
<pre class="j-path">rest-resource-helloworld<span class="j-pathsep">/</span>src<span class="j-pathsep">/</span>main<span class="j-pathsep">/</span>resources<span class="j-pathsep">/</span>OSGI-INF<span class="j-pathsep">/</span>blueprint<span class="j-pathsep">/</span>helloworld-blueprint.xml</pre>
<pre class="j-text"><code>&lt;!-- export services --&gt;
&lt;service ref="resourceServer"
	interface="com.elasticpath.rest.resource.ResourceServer"&gt;
	&lt;service-properties&gt;
		&lt;entry key="resourceServerName"&gt;
			&lt;ref component-id="resourceServerName"/&gt;
		&lt;/entry&gt;
	&lt;/service-properties&gt;
&lt;/service&gt;

&lt;service ref="permissionLookup"
	interface="com.elasticpath.rest.authorization.PermissionLookup"&gt;
	&lt;service-properties&gt;
		&lt;entry key="resourceServerNames"&gt;
			&lt;array&gt;
				&lt;ref component-id="resourceServerName"/&gt;
			&lt;/array&gt;
		&lt;/entry&gt;
	&lt;/service-properties&gt;
&lt;/service&gt;</code></pre>
</body></html>