Florian is the founder of minuteproject; addicted to OS development, he is also interested by productivity, quality development concerns. Florian is a DZone MVB and is not an employee of DZone and has posted 6 posts at DZone. You can read more from them at their website. View Full User Profile

RESTication of Openxava App and Vaadin Client

05.04.2012
| 3608 views |
  • submit to reddit

The purpose of this article is to provide REST interface for Openxava (OX) application.
It shows how-to
  • integrate jersey engine into the OX build
  • extend the JPA2 entities with JAXB and JAXRS annotations
  • write a little UC with methods that returns xml/json message
  • test it
  • Make a sample Vaadin client application for those REST services
To illustrate this, I will take an Openxava application generated by minuteproject (http://minuteproject.blogspot.com/2011/09/sql-select-to-web-application-in-couple.html)

Integrate Jersey engine in OX build

Jersey lib integration
Add the following libraries in your project /web/WEB-INF/lib
  • jsr305-1.3.2.jar
  • jersey-core-1.9-ea03.jar
  • jersey-server-1.9-ea03.jar
  • asm-3.1.jar (although asm.jar is shipped with OX this version is to used)

Here the dependency is on jersey-server-1.9-ea03

In your OX project add the file servlets.xml into /web/WEB-INF

   <servlet>
<servlet-name>petshop Jersey Web Application</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.resourceConfigClass</param-name>
<param-value>com.sun.jersey.api.core.PackagesResourceConfig</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>my.cool.report</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>petshop Jersey Web Application</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>

Openxava build takes what you define in servlets.xml file and insert it in the web.xml
The snippet above specifies the following:

  • Jersey engine will parse the package for JAXRS annotation in the package "my.cool.report"
  • the context path used for REST will be /rest/*

JAXB & JAXRS integration

Add Jaxb and Jaxrs annotation in OX jpa2 entities

Class MyConferenceCoolReport

package my.cool.report.conference.domain.report;

import java.sql.*;
import java.util.Date;
import java.util.List;
import java.util.ArrayList;
import java.util.Set;
import java.util.HashSet;

import javax.persistence.*;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
import javax.xml.bind.annotation.*;

import my.cool.report.conference.dto.report.*;

import org.openxava.annotations.*;
import org.openxava.jpa.*;


/**
*
* <p>Title: MyConferenceCoolReport</p>
*
* <p>Description: Domain Object describing a MyConferenceCoolReport entity</p>
*
*/
@Entity (name="MyConferenceCoolReport")
@Table (name="my_conference_cool_report")
@Views({
@View(
name="base",
members=
""
+ "firstName  ; "
+ "lastName  ; "
+ "email  ; "
+ "status  ; "
+ "addressStreet1  ; "
+ "addressStreet2  ; "
+ "countryCode  ; "
+ "conferenceName  ; "
+ "conferenceBeginDate  ; "
+ "conferenceEndDate  ; "
),
@View(
name="Create",
extendsView="base"
),
@View(
name="Update",
extendsView="base",
members=
 ""
),
@View(extendsView="base",
members=
 ""
),
@View(name="myConferenceCoolReportDEFAULT_VIEW",
members=
 " id ;"
+ "firstName  ; "
+ "lastName  ; "
+ "email  ; "
+ "status  ; "
+ "addressStreet1  ; "
+ "addressStreet2  ; "
+ "countryCode  ; "
+ "conferenceName  ; "
+ "conferenceBeginDate  ; "
+ "conferenceEndDate  ; "
)
})

@Tabs({
@Tab(
properties=
" firstName "
+",  lastName "
+",  email "
+",  status "
+",  addressStreet1 "
+",  addressStreet2 "
+",  countryCode "
+",  conferenceName "
+",  conferenceBeginDate "
+",  conferenceEndDate "
)
,
@Tab(
name = "MyConferenceCoolReportTab",
properties=
" firstName "
+",  lastName "
+",  email "
+",  status "
+",  addressStreet1 "
+",  addressStreet2 "
+",  countryCode "
+",  conferenceName "
+",  conferenceBeginDate "
+",  conferenceEndDate "
)
,
@Tab(
name = "MyConferenceCoolReportTabWithRef",
properties=
" firstName "
+",  lastName "
+",  email "
+",  status "
+",  addressStreet1 "
+",  addressStreet2 "
+",  countryCode "
+",  conferenceName "
+",  conferenceBeginDate "
+",  conferenceEndDate "
)
})
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType
@XmlRootElement
@Path ("/myreports")
public class MyConferenceCoolReport {

@Hidden @Id @Column(name="id" )
private Long id;

@Column(name="first_name",  length=255, nullable=false,  unique=false)
@Required
private String firstName;
@Column(name="last_name",  length=255, nullable=false,  unique=false)
@Required
private String lastName;
@Column(name="email",  length=255, nullable=false,  unique=false)
@Required
private String email;
@Column(name="status",  length=45, nullable=false,  unique=false)
@Required
private String status;
@Column(name="address_street1",  length=255,  nullable=true,  unique=false)
private String addressStreet1;
@Column(name="address_street2",  length=255,  nullable=true,  unique=false)
private String addressStreet2;
@Column(name="country_code",  length=45, nullable=false,  unique=false)
@Required
private String countryCode;
@Column(name="conference_name",  length=255, nullable=false,  unique=false)
@Required
private String conferenceName;
@Column(name="conference_begin_date",    nullable=true,  unique=false)
private Date conferenceBeginDate;
@Column(name="conference_end_date",    nullable=true,  unique=false)
private Date conferenceEndDate;

/**
* Default constructor
*/
public MyConferenceCoolReport() {
}

public Long getId() {
return id;
}

public void setId (Long id) {
this.id =  id;
}

public String getFirstName() {
return firstName;
}

public void setFirstName (String firstName) {
this.firstName =  firstName;
}
public String getLastName() {
return lastName;
}

public void setLastName (String lastName) {
this.lastName =  lastName;
}
public String getEmail() {
return email;
}

public void setEmail (String email) {
this.email =  email;
}
public String getStatus() {
return status;
}

public void setStatus (String status) {
this.status =  status;
}
public String getAddressStreet1() {
return addressStreet1;
}

public void setAddressStreet1 (String addressStreet1) {
this.addressStreet1 =  addressStreet1;
}
public String getAddressStreet2() {
return addressStreet2;
}

public void setAddressStreet2 (String addressStreet2) {
this.addressStreet2 =  addressStreet2;
}
public String getCountryCode() {
return countryCode;
}

public void setCountryCode (String countryCode) {
this.countryCode =  countryCode;
}
public String getConferenceName() {
return conferenceName;
}

public void setConferenceName (String conferenceName) {
this.conferenceName =  conferenceName;
}
public Date getConferenceBeginDate() {
return conferenceBeginDate;
}

public void setConferenceBeginDate (Date conferenceBeginDate) {
this.conferenceBeginDate =  conferenceBeginDate;
}
public Date getConferenceEndDate() {
return conferenceEndDate;
}

public void setConferenceEndDate (Date conferenceEndDate) {
this.conferenceEndDate =  conferenceEndDate;
}

@Transient
@GET
@Path("{reportId}")
@Produces ({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public MyConferenceCoolReport findById (@PathParam ("reportId") Long reportId) {
EntityManager em = XPersistence.getManager();
MyConferenceCoolReport p = em.find(MyConferenceCoolReport.class, reportId);
return p;
}

@Transient
@GET
@QueryParam("{countryCode}")
@Produces ({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public MyConfReports find (@QueryParam ("countryCode") String countryCode) {
String q = null;
EntityManager em = XPersistence.getManager();
if (countryCode!=null) {
   q = "select m from MyConferenceCoolReport m where countryCode = '"+countryCode+"'";
} else
q = "select m from MyConferenceCoolReport m ";
Query query = em.createQuery(q);
List<myconferencecoolreport> l = query.getResultList();
MyConfReports m = new MyConfReports();
m.setMyCoolReport(l);
return m;
}

}

Annotation of entities
The previous snippet indicates that entity MyConferenceCoolReport contains a transient method (findById) use for REST GET operation and using the param reportId to load an entity. It can be returned either as Xml or in a Json format.
It contains also a method find that takes a parameter a country code and return a DTO based on the class MyConfReports

package my.cool.report.conference.dto.report;
package my.cool.report.conference.dto.report;

import java.util.*;

import javax.xml.bind.annotation.*;

import my.cool.report.conference.domain.report.*;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType
@XmlRootElement
public class MyConfReports {

private List<MyConferenceCoolReport> myCoolReport;

public MyConfReports () {
}

public List<MyConferenceCoolReport> getMyCoolReport() {
return myCoolReport;
}

public void setMyCoolReport(List<MyConferenceCoolReport> myCoolReport) {
this.myCoolReport = myCoolReport;
}

}

Deploy
Use the ant build on your project.
Remark: do not forget when using openxava with eclipse to set "Build Automatically" on the "Project" tab.

Testing
Via the browser type
http://localhost:8080/conference/rest/myreports?countryCode=BE to see all the


http://localhost:8080/conference/rest/myreports/ it returns in an XML format.


 

 

Published at DZone with permission of Florian Adler, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)