Category Archives: WebService

Building RESTful WebService/Client using WildFly 8.0.0 Final, RESTEasy, and Maven Deployment

WildFly 8.0.0 Final was released recently. For a new project, I had to convert a legacy WebService into RESTful WebService using RESTEasy on JBoss Application Server. Not only converting RPC style JAX-WS WebService (Axis2-1.3), but I have to convert Ant base build/deployment process to Maven. My experience around RESTful WebService was around Jersey and Maven experience was limited before this project. As for my first step, I built a small prototype using WildFly + RESTEasy + Maven combination based on JEE7. There are several tutorials & resources that I could find in the internet, but it was difficult find a complete example. JBoss RESTEasy API and Java EE 7 tutorial have good reference and sample codes. However, I had difficult time finding the best practice based on my requirement. Most of the internet resources are either out of date or too simple for what I need to achieve. Also, most of examples are contained within the Eclipse environment, so considering deployment on a remote server was additional challenge . Eventually, I put things together and share my experience. 

Requirement

  • JDK 1.7 u51
  • Eclipse Keploer
  • WildFly 8.0.0 Final
  • Maven 3.1.1
  • RESTEasy 3.0.6 – comes with WildFly.

Objective

  1. Create a RESTful WebService using RESTEasy deploy to WildFly using Maven.
  2. Prototype should have a WebService and client.
  3. Build a web page that can be exposed by calling a WebService client.
  4. Retrieve a list of object by passing a list of String as a parameter.
  5. Application uses a single properties file fed from pom file based on environment profile. Assuming DEV/TEST/PROD environments are running on WildFly 8.0.0.
  6. Prototype will be deployed to WildFly standalone server. For this reason, portability wasn’t considered in this prototype.

pom.xml

  • WildFly plugin added
  • Two profiles are created ‘development’ and ‘prod’ to simulate different environment.
  • ${project.version} is a maven project property
  • ${maven.build.timestamp} is a special variable in maven
  • Most of JBoss specific jars are defined as ‘provided’ scope.

application.properties

environment=${env}
build_version=${build_version}
build_date=${timestamp}
build_number=${build_number}
student.restws.url=${student.restws.url}

After “mvn package -P development” command application.properties are populated as below.

environment=development
build_version=0.0.1-SNAPSHOT
build_date=2014-03-30 19:29:52
build_number=00001
student.restws.url=http://localhost:8080/RestWebServiceTest/rs/json

 web.xml

  • I wanted to prefix the RESTful WebService URL with ‘rs’, so I can differentiate normal Web Application from the WebService.

WebService Challenges

I need to retrieve a list of object based on user selected strings from list box. This list box has about 100 of items and there is a possibility that user can select “All” from the list box. There seem to be two ways of doing this : Convert string collection to JSON or comma delimited single string, use @PUT instead of @GET if string collection is too long. @PUT is for update, but I can safely pass the parameter in the body rather than URL as a @QueryParam. Also, I came across another way of doing this by passing long string parameter in the Header, but I couldn’t find an example code to follow. Especially, building WebService client passing long string to Header.

 

WebService Client

JAX-RS 2.0 defines client API, which makes it much easier to develop client side. I always felt developing RESTful WebService Client side is difficult because of different implementations use different classes/methods although underneath principle is the same.

Deployment

mvn clean compile package -P development wildfly:deploy-only

Source Code

https://github.com/mjtoolbox/RestWebServiceTest

Conclusion

I felt importance of RESTful WebService becomes bigger and bigger. It is due to modern Web Application development is moving away from server side generated front end pages. For this reason, I feel I need to improve hands on experience and understand the details. Some of learning points from this experience.

  • New JAX-RS 2.0 spec in JEE 7 made client side development easier. At least defines a standard way of implementation.
  • Working on the latest technology requires time and patient : much of the configuration resources are based on the old version.
  • Haven’t handled the security. Need to expand that later post.

 

 

 

 

 

JAX-WS on Glassfish using wsgen

Several times of attempt on creating a JAXWS WebService with CXF, Glassfish, and Eclipse combination, I concluded that there are some issues on the development environment (CXF 2.6.0, Glassfish 3.1.2, and Eclipse Indigo). I followed several tutorials, but I always encountered either NPE or missing WSDL and failed to deploy EAR message.

CXF site suggested that Glassfish Metro library will overwrite CXF, so disable class-load in sun-web.xml page, which I did. Glassfish issue log suggested that generated wsdl is not placed under WEB-INF folder. Wizard generated a wsdl file directly under WebContent. When I moved wsdl folder under WEB-INF and modified wsdl location, I still had the same error.

Now, forget the Wizard in the Eclipse. I created JAX-WS WebService using wsgen. First, create a minimum Dynamic Web Project and create a WebService implementation class with the annotations.

@WebService
public class ExampleService {

@WebMethod
public int add( int a, int b)
{
return a + b;
}

@WebMethod
public String concat(String first, String second)
{
return first + second;
}
}

Now, run wsgen command.

msjo@local $ wsgen -verbose -classpath build/classes/ -wsdl -r WebContent/WEB-INF/wsdl -s src -d build
/classes/ com.mjtoolbox.ws.ExampleService

warning: The apt tool and its associated API are planned to be
removed in the next major JDK release.  These features have been
superseded by javac and the standardized annotation processing API,
javax.annotation.processing and javax.lang.model.  Users are
recommended to migrate to the annotation processing features of
javac; see the javac man page for more information.
Note:   ap round: 1
[ProcessedMethods Class: com.mjtoolbox.ws.ExampleService]
[should process method: add hasWebMethods: true ]
[endpointReferencesInterface: false]
[declaring class has WebSevice: true]
[returning: true]
[WrapperGen - method: add(int,int)]
[method.getDeclaringType(): com.mjtoolbox.ws.ExampleService]
[requestWrapper: com.mjtoolbox.ws.jaxws.Add]
[should process method: concat hasWebMethods: true ]
[endpointReferencesInterface: false]
[declaring class has WebSevice: true]
[returning: true]
[WrapperGen - method: concat(java.lang.String,java.lang.String)]
[method.getDeclaringType(): com.mjtoolbox.ws.ExampleService]
[requestWrapper: com.mjtoolbox.ws.jaxws.Concat]
[ProcessedMethods Class: java.lang.Object]
com\mjtoolbox\ws\jaxws\Add.java
com\mjtoolbox\ws\jaxws\AddResponse.java
com\mjtoolbox\ws\jaxws\Concat.java
com\mjtoolbox\ws\jaxws\ConcatResponse.java
Note:   ap round: 2

In order to run it properly, I have to build the project in the Eclipse. It seems Eclipse doesn’t build the project until Run on Server is executed. Have a look at the wsdl file and update the “REPLACE_WITH_ACTUAL_URL” with the actual WebService Endpoint. Make sure to replace URL with actual Service name defined in the wsdl like below.

<service name="ExampleServiceService">
<port name="ExampleServicePort"
binding="tns:ExampleServicePortBinding">
<soap:address
location="http://127.0.0.1:8080/WSbare/ExampleServiceService"/>
</port>
</service>

Another way of testing JAX-WS WebService is using Endpoint API.

Endpoint API provide the light-weight HTTP container that is included in Java SE 6. Without the web server, we can deploy the same WebService to the desire location. Of course, wsdl will be generated automatically. URL can be anything after the port number.

 

public static void main(String[] args){
Endpoint.publish("http://hy149411:8080/WSbare/Examplews", new ExampleService());
}

JAX-RS parsing XML

I have encountered a few issues when I try to parse XML object from the JAX-RS WebService. Many tutorials out there uses simple object. Just like I did in the previous post. Using one single class. However, in reality, if the Java class represents a complex object, typical Java will implements interface(s) and involves in parent/child relationship. In this circumstance, it is difficult to put @XmlRootElement all over the classes.

There are three options that we can take.

1. @XmlJavaTypeAdapter : Apply the adapter to hide implementation. By using adapter, you can specify the object that will be marshaled/unmarsharled. See JAXB Guide. I tried myself, but it has a problem at marshaling and I didn’t have a chance to dive into this route. At least, it didn’t complain about the object is an interface.

2. Simplify the object : Use a transfer class to make the object simple. Unless you need to pass the whole object & its attributes, simply the structure to represent the data.

3. Assign @XmlRootElement in the hierarchy : Make the JAXB work all the object in the hierarchy. Still it may require a trick. In case, declared variable is an Interface type, if the Interface is not complex, use substitute variable. If complex, use #1 technique or declare @XmlRootElement tag in the implementation class.

Conclusion

In my opinion, #2 seems the best solution when you need to deal with a complex object. Multiple inheritances with interface and abstract classes. Class is structured in this way to be flexible and useful within the domain. However, it may not be suitable to the outside of the domain. WebService is the tool to communicate the data to the outside, so why not spending little more time to make the object simpler?

JAX-RS on Weblogic using Jersey

In my current project, I have a RESTful WebService. Because we are using Weblogic 10.3 with JEE5, I have to use Jersey. Due to the requirement, I used XML instead of JSON. Also, I’d like to focus on JAX-RS client side using Jersey. Server side is relatively simple and lots of tutorials are available.

  • Weblogic 10.3
  • IntelliJ
  • Jersey 1.12
  • Xerces 2.11

[XML binding with POJO – using JAXBElement]

Message.java

public class Message
{
//Asset, Related ID, Functional Area, Message Type, Received At
public String asset;
public String relatedID;
public String functionalArea;
public String messageType;
public String receivedAt;

@Override
public String toString()
{
return "Message{" +
"asset='" + asset + '\'' +
", relatedID='" + relatedID + '\'' +
", functionalArea='" + functionalArea + '\'' +
", messageType='" + messageType + '\'' +
", receivedAt='" + receivedAt + '\'' +
'}';
}
}

Simple object without any complex type. Easy to parse.

@Path("/nprf")
public class NprfResource......(obmitted)...

  @GET
  @Path("/testXML")
  @Produces(MediaType.APPLICATION_XML)
  public JAXBElement<Message> testXML()
  {
    Message message = new Message();
    message.asset = "test";
    message.functionalArea = "myarea";
    message.messageType = "testtype";
    message.receivedAt = "January 1";
    message.relatedID = "000";

    return new JAXBElement( new QName( "testXML" ), Message.class, message );
  }

Defining return type as JAXBElement. It will be useful if the returned object type is complex object and don’t want to add XmlRootElement tag all over.

 try
    {
      // RESTful WebService Client call. Optional to create a DefaultClientConfig.
      DefaultClientConfig config = new DefaultClientConfig();
      config.getProperties().put( ClientConfig.FEATURE_DISABLE_XML_SECURITY, 
       "true" );
      Client client = Client.create( config );
      WebResource webResource 
       = client.resource( "http://localhost:30020/CMWeb/rest/nprf" );

      GenericType<JAXBElement> messageType = new GenericType<JAXBElement>()
      {
      };
      Message message = webResource.path( "testXML" )
                        .accept( MediaType.APPLICATION_XML_TYPE )
                        .get( messageType ).getValue();
      System.out.println( "### " + message );

    }
    catch ( Exception e )
    {
      log.safeError( "testTestXML", e.getClass().getName(), e );
      fail( e.getMessage() );
    }

I was getting “org.xml.sax.SAXNotRecognizedException: http://javax.xml.XMLConstants/feature/secure-processing&#8221; exception when I tried to parse XML to Java object. To resolve the issue, I had to replace Xerces with newer version. I think somewhere in the environment uses the old version of Xerces.

From URL result

  <?xml version=”1.0″ encoding=”UTF-8″ standalone=”yes” ?>
<testXML>
  <asset>test</asset>
  <relatedID>000</relatedID>
  <functionalArea>myarea</functionalArea>
  <messageType>testtype</messageType>
  <receivedAt>January 1</receivedAt>
  </testXML>

Test Result below.

About to run testTestXML
-----------------------------------------------------------------
### Message{asset='test', 
relatedID='000', 
functionalArea='myarea', 
messageType='testtype', 
receivedAt='January 1'}

wsdl2java usage

I have been using wsdl2java command for long time. I feel I need to record this information somewhere even though there are tons of information related to this. So below is for my own reference.

ComplexType object in the WebService, specially, inheritance happened in the WebService, we must use simple Stub and many classes generation.  In general, there are 2 ways of generating consumer.

1. One complex Stub class with inner classes
2. One simple Stub class with complex type classes
Personally, I think one complex Stub class is better because it is easy to maintain and cleaner. I will explain two different WSDL2Java scripts. We can call generateJavaFromWsdl.sh script or directly execute WSDL2Java.bat file in Axis1-1.3/bin folder.

One Complex Stub (Preferred method)
CMNprfService.wsdl package : com.abs.cro

[USR:DEV] msjo@HY126045 $ wsdl2java.bat -o C:/temp/gen
-uri eiservices.wsdl -d adb -sp -s -p com.abs.usr.webservice.dcm
Using AXIS2_HOME: C:\DevApps\axis2-1.6.2Using 
JAVA_HOME:        c:/bea103/jrockit81sp6_142_10
[USR:DEV] msjo@HY126045 $

-o C:/temp/gen indicate output location
-uri location and name of WSDL. I generated locally. Not like Axis1.1, WSDL should be copied locally in order to generate java classes. I think it is because of axis2 architecture changes. As you can see there is no parameter for userid and password.
-d adb Axis Databinding is default. There are 2 other ways to generate java classes, but this way is the simplest and easiest way.
-sp Suppress namespace prefix. To simplify SOAP request/response object.
-s Synchronous call stub only (if you don’t specify -s or generate with -a another class called a CallbackHandler will be generated)
-p specify the package name, so you don’t need to change it later

Simple Stub and many classes

[USR:DEV] msjo@HY126045 $ wsdl2java.bat -o C:/temp/adbAll
-uri CmDcmService.wsdl -g -ss -d adb -p abs.usr.webservices.dcm
Using AXIS2_HOME: C:\DevApps\axis2-1.6.2Using 
JAVA_HOME:        c:/bea103/jrockit81sp6_142_10
[USR:DEV] msjo@HY126045 $

-g generate all classes
-ss generate serverside code