Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

This tutorial documents the steps to expose an ofbiz service using REST. The ofbiz ping service is exposed.  The ping service returns a copy on the input message to the response.  If the input message is null, ping returns PONG.


This is related: REST Service Implementation

The following steps show Apache wink was chosen as the REST implementation purely on the basis that it is an apache project. on base of Apache Wink.

Info
titleApache Wink is retired

As of April 2017, Apache Wink is retired. For new REST implementations, it is not recommended to use it.

This tutorial does not work with OFBIz Release 16.11 and above.

This page will be either updated with an alternative or deprecated in the future.

Assumptions

This tutorial assumes you have followed the ofbiz developer tutorial: http://cwiki.apache.org/confluence/x/cQFk

Step 1 - Create a new component

Code Block

ant create-component

Component name: restcomponent
Component resource name: RestComponent
Webapp name: restcomponent
Base permission: RESTCOMPONENT

Step 2 - Grab

...

Apache Wink*

Download apache wink . I used httpfrom here: https://wwwwink.apache.org/dyn/closer.cgi/incubator/wink/1.0-incubating/apache-wink-1.0-incubating.zipdownloads.html

Unzip and copy lib/* and dist/* to your ofbiz component restcomponent/lib

\* read this https://dzone.com/articles/apache-cxf-vs-apache-axis-vs for a comparison between 2 Apache solutions regarding REST and Spring WS

Step 3 - Create java files and update web.xml

The steps followed were taken from the wink user (i.e. developer) guide):  http://incubator.apache.org/wink/1.0/Apache_Wink_User_Guide.pdf:  apache-wink-developer-guide.html

In the folder restcomponent/src/restcomponent, create:

PingApplication.java
PingResource.java

Code Block

package restcomponent;

import java.util.HashSet;
import java.util.Set;

import javax.ws.rs.core.Application;

public class PingApplication extends Application {
  @Override
  public Set<Class<?>> getClasses() {
      Set<Class<?>> classes = new HashSet<Class<?>>();
      classes.add(PingResource.class);
      return classes;
  }
}


Code Block

package restcomponent;


import java.util.Map;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;

import javolution.util.FastMap;

import org.ofbiz.base.util.Debug;
import org.ofbiz.base.util.UtilMisc;
import org.ofbiz.entity.DelegatorFactory;
import org.ofbiz.entity.GenericDelegator;
import org.ofbiz.service.GenericDispatcher;
import org.ofbiz.service.GenericServiceException;
import org.ofbiz.service.LocalDispatcher;
import org.ofbiz.service.ServiceUtil;

@Path("/ping")
public class PingResource {

	@GET
	@Produces("text/plain")
	@Path("{message}")
    public Response sayHello(@PathParam("message") String message) {

    	GenericDelegator delegator = (GenericDelegator) DelegatorFactory.getDelegator("default");
    	LocalDispatcher dispatcher = GenericDispatcher.getLocalDispatcher("default",delegator);

    	Map<String, String> paramMap = UtilMisc.toMap( "message", message );

		Map<String, Object> result = FastMap.newInstance();
		try {
			result = dispatcher.runSync("ping", paramMap);
		} catch (GenericServiceException e1) {
			Debug.logError(e1, PingResource.class.getName());
			return Response.serverError().entity(e1.toString()).build();
		}

		if (ServiceUtil.isSuccess(result)) {
			return Response.ok("RESPONSE: *** " + result.get("message") + " ***").type("text/plain").build();
		}

		if (ServiceUtil.isError(result) || ServiceUtil.isFailure(result)) {
			return Response.serverError().entity(ServiceUtil.getErrorMessage(result)).build();
		}

		// shouldn't ever get here ... should we?
		throw new RuntimeException("Invalid ");
    }
}

Update restcomponent/webapp/restcomponent/WEB-INF/web.xml:

Code Block

<?xml version="1.0" encoding="UTF-8"?>
<web-app>
    <display-name>Open For Business - RestComponent Component</display-name>
    <description>RestComponent Component of the Open For Business Project</description>

  	<servlet>
		<servlet-name>restServlet</servlet-name>
		<servlet-class>org.apache.wink.server.internal.servlet.RestServlet</servlet-class>
                <init-param>
                  <param-name>javax.ws.rs.Application</param-name>
                  <param-value>restcomponent.PingApplication</param-value>
                </init-param>
                <load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>restServlet</servlet-name>
		<url-pattern>/*</url-pattern>
	</servlet-mapping>

</web-app>

...

Turn on auth="true" in framework/common/servicedef/services_test.xml

Code Block

    <service name="ping" engine="java" export="true" require-new-transaction="true"
            location="org.ofbiz.common.CommonServices" invoke="ping" auth="true">

Now change PingResource to take http headers with the login.username and login.password and pass the values to the service.

Code Block

package restcomponent;


import java.util.Map;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;

import javolution.util.FastMap;

import org.ofbiz.base.util.Debug;
import org.ofbiz.base.util.UtilMisc;
import org.ofbiz.entity.DelegatorFactory;
import org.ofbiz.entity.GenericDelegator;
import org.ofbiz.service.GenericDispatcher;
import org.ofbiz.service.GenericServiceException;
import org.ofbiz.service.LocalDispatcher;
import org.ofbiz.service.ServiceUtil;

@Path("/ping")
public class PingResource {

	@Context
	HttpHeaders headers;

	@GET
	@Produces("text/plain")
	@Path("{message}")
    public Response sayHello(@PathParam("message") String message) {

		String username = null;
		String password = null;

		try {
			username = headers.getRequestHeader("login.username").get(0);
			password = headers.getRequestHeader("login.password").get(0);
		} catch (NullPointerException e) {
			return Response.serverError().entity("Problem reading http header(s): login.username or login.password").build();
		}

		if (username == null || password == null) {
			return Response.serverError().entity("Problem reading http header(s): login.username or login.password").build();
		}

    	GenericDelegator delegator = (GenericDelegator) DelegatorFactory.getDelegator("default");
    	LocalDispatcher dispatcher = GenericDispatcher.getLocalDispatcher("default",delegator);

    	Map<String, String> paramMap = UtilMisc.toMap(
    			"message", message,
    			"login.username", username,
    			"login.password", password
    		);

		Map<String, Object> result = FastMap.newInstance();
		try {
			result = dispatcher.runSync("ping", paramMap);
		} catch (GenericServiceException e1) {
			Debug.logError(e1, PingResource.class.getName());
			return Response.serverError().entity(e1.toString()).build();
		}

		if (ServiceUtil.isSuccess(result)) {
			return Response.ok("RESPONSE: *** " + result.get("message") + " ***").type("text/plain").build();
		}

		if (ServiceUtil.isError(result) || ServiceUtil.isFailure(result)) {
			return Response.serverError().entity(ServiceUtil.getErrorMessage(result)).build();
		}

		// shouldn't ever get here ... should we?
		throw new RuntimeException("Invalid ");
    }
}

Now trying accessing with web browser:

Code Block

Access to the specified resource () has been forbidden.

...