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

This version of Elastic Path Commerce is no longer supported or maintained. To upgrade to the latest version, contact your Elastic Path representative.

Resource Prototypes

Resource Prototypes

Resource prototypes are generated Java classes which implement the resources defined in the API definition. They perform particular operations by instantiating and routing logic for CRUD and other API operations, including create, read, update, delete, submit, info and linkto.

Resource prototypes are generated from the API definition XML as an interface. The interface is also generated with associated interfaces for the CRUD and API operations the resource can perform. To implement a resource prototype, you must create a class which implements the prototype interface itself as well as one of the operation interfaces; all other wiring is handled for the developer.

Implementing a single interface per prototype reduces the number of unneeded or out of scope data injections, as well as reducing the amount of code necessary in each resource prototype.

For example, to generate a ProfileResource interface, a developer could define the following in profiles.xml:

  <resource>
    <name>profile</name>
    <description><![CDATA[The profile for the customer.]]></description>
    <uri>{base.family}/{base.scope}/{profile-id}</uri>
    <entity>profile</entity>
  </resource>
    

This resource definition will generate a ProfileResource interface class. Generated interfaces include specific operation interfaces for the resource, such as create and read. These interfaces are extended by the prototype.

Resource prototypes function without ever communicating directly with the Commerce Engine. The prototype layer communicates directly with the repository layer, and the repositories communicate with Commerce Engine. This allows for abstraction and isolation of a resource's functionality from Commerce Engine functionality. For more information see the Cortex Architecture and Call Stack documentation.

Implementing Operation Prototypes

Responsibilities

The created resource prototype class needs a constructor and an operation method. In general, you want to create one Prototype class per operation needed.

For example, to read for a profile entity, a developer might implement ReadProfilePrototype, which implements ProfileResource.Read. To update a profile entity, developers would add a class called UpdateProfilePrototype, which implements ProfileResource.Update.

The Constructor

The constructor initializes service dependencies and injects data. The constructor should be annotated with @Inject. The parameters to the constructor should be annotated with @RequestIdentifier to specify assignment of injected data.

For example, the constructor for a prototype designed to read a Profile entity might look like:

  @Inject
  public ReadProfilePrototype(@RequestIdentifier final ProfileIdentifier profileIdentifier, final RepositoryRegistry repositoryRegistry) {
    this.profileIdentifier = profileIdentifier;
    this.repositoryRegistry = repositoryRegistry;
  }
        

The Operation Method

The operation method of the prototype should correlate with the Prototype's specific responsibility (i.e. onRead, onUpdate, onLinkTo etc.). This method will be similar across an entity's individual operation prototypes, with differences corresponding to the operations.

The operation method makes a call to a RepositoryRegistry instance, which uses the repositoryFor method to identify the appropriate repository for a given entity and/or identifier. This method then calls the relevant operation on the resulting repository in the RepositoryRegistry.

  @Override
  public Single<ProfileEntity> onRead() {
    return repositoryRegistry.repositoryFor(ProfileEntity.class, ProfileIdentifier.class)
    .orElseThrow(() -> ResourceOperationFailure.serverError("No profile repository found"))
    .findOne(profileIdentifier);
  }
        

This implementation demonstrates the resource prototype model's decoupling and abstraction potential. Rather than find, call, or construct the appropriate repository, the repositoryRegistry identifies the proper repository associated with an entity. This section of the method should not require changes across the different resource prototype implementations, so long as the repositories are properly registered.

The operation method is the only part of this code that must be changed for each resource prototype. For an update prototype, a developer might use update instead of findOne:

    @Override
    public Single<ProfileEntity> onUpdate() {
      return repositoryRegistry.repositoryFor(ProfileEntity.class, ProfileIdentifier.class)
      .orElseThrow(() -> ResourceOperationFailure.serverError("No profile repository found"))
      .update(profileIdentifier);
    }
        

Marking Your Bundle as Discoverable

The Helix runtime must be able to discover the prototype bundle.

To mark your bundle as a bundle that provides a Helix prototype, add the <Require-Capability/> element to your pom.xml file under the maven-bundle-plugin section:

        <plugin>
          <groupId>org.apache.felix</groupId>
          <artifactId>maven-bundle-plugin</artifactId>
          <configuration>
            <obrRepository>NONE</obrRepository>
            <instructions>
              <Require-Capability>osgi.service; filter:="(objectClass=com.elasticpath.rest.helix.client.extender.BootstrapExtender)"; effective:=active,</Require-Capability>
              ....
            </instructions>
          </configuration>
        </plugin>
      

Enabling Validation

To enable compile-time validation of the prototype, add the following to your pom.xml file:

<plugin>
  <groupId>com.elasticpath.rest.helix</groupId>
  <artifactId>helix-maven-plugin</artifactId>
</plugin>
      

If there are validation errors, the plugin will fail the build. The error output of the build indicates which validation rules are broken and gives hints on how to fix these errors. An example output of an validation error is:

[ERROR] Read operation for the resource BookingsPrototype does not have correct return type. It should be Observable<interface com.elasticpath.rest.definition.bookings.BookingIdentifier>
      

In this case, the read operation defined in the BookingsPrototype resource class is returning the wrong return type. The return type should be of type Observable<interface com.elasticpath.rest.definition.bookings.BookingIdentifier>.