REST Service Infrastructure

This article applies to the Product Manager Version 6 and following.

Overview

HPM server provides a standard way to contribute REST services based on the JAX-RS (JSR 311) standard. JAX-RS is a JEE standard and API to implement restfull services in Java. Thanks to standardization this is a perfect approach to system integration especially in enterprise landscapes. It allows to expose HPM data to the external systems using a well defined technology and thus provides a way to access HPM data by developers who are not familiar with HPM SDK and API.

HPM platform in Version 6.0 does not provide predefined REST services, rather it provides an infrastructure to develop and contribute services into HPM context. Future versions of the platform will contain a set of rest services to access and modify data in HPM.

images/download/attachments/64980110/HPM_REST_Integration.png

The HPM platform provides REST infrastructure with the following components:

  • JAX-RS implementation called Jersey, the reference implementation developed by Oracle. It contains all necessary classes and interfaces to implement rest services.

  • Servlet container - Jetty 6. This container is integrated into the OSGi Equinox environment. Jetty properties like host, port and others can be configured in the server.properties file of HPM.

  • HTTP and HTTPS connectors (provided by Jetty)

  • Integration with HPM security and authentication.

  • Extension point in HPM platform to which REST services implementations can be contributed. This architecture brings clear separation between HPM API and JAX-RS API and makes REST services development easy and clear for developers.

Security

The security of REST-based access to Product Manager is based on HTTP Basic Authentication combined with Product Manager's own authorization mechanisms. It is required to create a HPM user which has internal authentication mode (not external or mixed mode). For security reasons external authentication (Active Directory authentication) must not be used from outside. We also strongly recommend to activate HTTPS protocol in production environment because HTTP Basic Authentication does not encrypt user password which is sent over HTTP.

Create your own REST service

In order to create a REST services in HPM you need to do following steps

  • Implement JAX-RS complaint service. Please consult Jersey documentation and other documentation how building JAX-RS services.

  • Contribute JAX-RS resources to com.heiler.ppm.rest.server extension point which is exported by com.heiler.ppm.rest.server bundle

Extension point com.heiler.ppm.rest.server is very simple and accepts implementations of ResourceProvider interface. Implementation should have only one method getResources() which returns a list of services implementation (resources in terms of JAX-RS api).

Extension point contribution example:

Resource Provider contribution
<extension point="com.heiler.ppm.rest">
<Resource
class="com.heiler.ppm.custom.rest.CustomResourceProvider">
</Resource>
</extension>

Resource provider implementation

Supplier resource provider implementation
public class CustomResourceProvider implements ResourceProvider
{
@Override
public Collection< Class< ? >> getResources()
{
List< Class< ? >> result = new LinkedList< Class< ? >>();
result.add( ArticleResource.class );
return result;
}
}

REST Resource Example

You can find the complete source code of this example in the HPM 6.0 SDK. The project is called com.heiler.ppm.custom.rest

Find articles by EAN in a given catalog:

Article REST service example
@Path( "/catalogs/{catalogId: [0-9]+}/articles" )
public class ArticleResource
{
@GET
@Produces( MediaType.APPLICATION_XML )
public Articles findAll( @PathParam( "catalogId" ) Long catalogId, @QueryParam( "ean" ) String ean )
throws CoreException, InterruptedException
{
Articles result = new Articles();
result.setArticles( findArticlesByEan( catalogId, ean ) );
return result;
}
private List< Article > findArticlesByEan( Long catalogId, String ean ) throws CoreException, InterruptedException
{
ReportResult report = findAsReport( catalogId, ean );
return loadByReport( report );
}
 
private List< Article > loadByReport( ReportResult report ) throws CoreException, InterruptedException
{
FieldPath articleIdentifier = new FieldPath( "ArticleType.SupplierAid" );
FieldPath shortDescriptionEN = new FieldPath( "ArticleLangType.DescriptionShort" );
shortDescriptionEN.getEntityPath()
.setLogicalKeyValue( "ArticleLangType.LK.Language", new Long( 7 ) );
ListModel listModel = loadArticleList( report, articleIdentifier, shortDescriptionEN );
 
List< Article > articles = new ArrayList( listModel.size() );
for ( ListEntry listEntry : listModel )
{
Article article = new Article();
article.setId( listEntry.getEntityProxy()
.getId() );
article.setIdentifier( ( String ) listEntry.getFieldValue( listModel.getColumn( articleIdentifier )
.getIndex() ) );
article.setShortDescription( ( String ) listEntry.getFieldValue( listModel.getColumn( shortDescriptionEN )
.getIndex() ) );
articles.add( article );
}
 
return articles;
}
}

Article data container:

Article data containers
@XmlRootElement
public class Articles
{
private List< Article > articles;
public Articles()
{
this.articles = new LinkedList< Article >();
}
public List< Article > getArticles()
{
return this.articles;
}
public void setArticles( List< Article > articles )
{
this.articles = articles;
}
}
 
...
 
@XmlRootElement
public class Article
{
private long id;
private String identifier;
private String shortDescription;
public long getId()
{
return this.id;
}
public void setId( long id )
{
this.id = id;
}
public String getIdentifier()
{
return this.identifier;
}
public void setIdentifier( String identifier )
{
this.identifier = identifier;
}
public String getShortDescription()
{
return this.shortDescription;
}
public void setShortDescription( String shortDescription )
{
this.shortDescription = shortDescription;
}
}
 

Please, be careful when designing REST web services. Wrong design or incorrect use of rest-full principals may result a unmanageable solution which is difficult to use and integrate with other systems, which has poor performance and is not clear to other developers. Please remember the following principals of restfull services:

  • REST services are stateless. It means that service implementations should not remember any kind of session between requests.

  • In REST design everything is a resource. Every data structure received from the server represents an identifiable resource. Every request can be seen as a CRUD on a resource.

  • REST services can read and modify resources and usually should not look like remote procedure call (RPC).

You can find a lot of information about designing REST service in a book "Restful Web Services" and "Service Design Patterns: Fundamental Design Solutions for SOAP/WSDL and RESTful Web Services".