Showing posts with label jax-rs. Show all posts
Showing posts with label jax-rs. Show all posts

31 July 2014

Developing with JAX-RS 2.0 for WebLogic Server 12.1.3

In an earlier post on the topic of Using JAX-RS 2.0 with WebLogic Server 12.1.3, I described that we've utilized the shared-library model to distribute and enable it.

This approach exposes the JAX-RS 2.0 API and enlists the Jersey 2.x implementation on the target server, allowing applications to make use of it as when they are deployed through a library reference in a weblogic deployment descriptor.

The one resulting consideration here from a development perspective is that since this API is not part of the javaee-api-6.jar nor is it a default API of the server, it's not available in the usual development API libraries that WebLogic provides.

For instance the $ORACLE_HOME/wlserver/server/lib/api.jar doesn't contain a reference to the JAX-RS 2.0 API, nor do the set of maven artifacts we produce and push to a repository via the oracle-maven-sync plugin contain the javax.ws.rs-api-2.0.jar library.

To develop an application using JAX-RS 2.0 to deploy to WebLogic Server 12.1.3, the javax.ws.rs-api-2.0.jar needs to be sourced and added to the development classpath.

Using maven, this is very simple to do by adding an additional dependency for the javax.ws.rs:javax.ws.rs-api:2.0 artifact that is hosted in public maven repositories:

    <dependency>
        <groupid>javax.ws.rs</groupid>
        <artifactid>javax.ws.rs-api</artifactid>
        <version>2.0</version>
        <scope>provided</scope>
    </dependency>

Note here that the scope is set to provided since the library will be realized at runtime through jax-rs-2.0.war shared-library that it deployed to the target server and referenced by the application. It doesn't need to be packaged with the application to deploy to WebLogic Server 12.1.3.

For other build systems using automated dependency management such as Gradle or Ant/Ivy, the same sort of approach can be used.

For Ant based build systems, the usual approach of obtaining the necessary API libraries and adding them to the development CLASSPATH will work. Be mindful that there is no need to bundle the jax.ws.rs-ap-2.0.jar in the application itself as it will be available from the server when correctly deployed and referenced in the weblogic deployment descriptor.

24 March 2014

Using the JAX-RS 2.0 Client API with WebLogic Server 12.1.3



Please note: this blog discusses WebLogic Server 12.1.3
which has not yet been released.

As part of the JAX-RS 2.0 support we are providing with WebLogic Server 12.1.3, one really useful new feature is the new Client API it provides, enabling applications to easily interact with REST services to consume and publish information.

By way of a simple example, I'll build out an application that uses the freegeoip.net REST service to lookup the physical location of a specified IP address or domain name and deploy it to WebLogic Server 12.1.3.

The first step to perform is to make a call to the freegeoip.net REST API and examine the JSON payload that is returned.
$ curl http://freegeoip.net/json/buttso.blogspot.com

{"ip":"173.194.115.75","country_code":"US","country_name":"United States","region_code":"CA","region_name":"California","city":"Mountain View","zipcode":"94043","latitude":37.4192,"longitude":-122.0574,"metro_code":"807","area_code":"650"}

The next step is to build a Java class to represent the JSON payload that is returned. In this case, it's quite simple because the JSON payload that is returned doesn't contain any relationships or complex data structures.
/**
 *
 * @author sbutton
 * {"ip":"173.194.115.75","country_code":"US","country_name":"United States","region_code":"CA","region_name":"California","city":"Mountain View","zipcode":"94043","latitude":37.4192,"longitude":-122.0574,"metro_code":"807","area_code":"650"}            
 */
public class GeoIp implements Serializable {

    private String ipAddress;
    private String countryName;
    private String regionName;
    private String city;
    private String zipCode;
    private String latitude;
    private String longitude;

    public String getIpAddress() {
        return ipAddress;
    }

    public void setIpAddress(String ipAddress) {
        this.ipAddress = ipAddress;
    }    

    ...

}
With the GeoIP class defined, the next step is to consider how to convert the JSON payload into an instance of the GeoIP class. I'll show two ways this can be done.

The first way to do it is to create a class that reads the result of the REST request, parses the JSON payload and constructs a representative instance of the GeoIP class. Within the JAX-RS API, there is an interface MessageBodyReader that can be implemented to convert a Stream into a Java type.

http://docs.oracle.com/javaee/6/api/javax/ws/rs/ext/MessageBodyReader.html

Implementing this interface gives you the readFrom(Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, InputStream entityStream) method which supplies an InputStream containing the response to read. The method then parses out the JSON payload and constructs a responding GeoIP instance from it.

Parsing the JSON payload is straightforward with WebLogic Server 12.1.3 since we've included the (JSR-353) Java API for JSON Processing implementation which provides an API for reading and creating JSON objects.
package oracle.demo.wls.jaxrs.client.geoip;

import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import javax.json.Json;
import javax.json.stream.JsonParser;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.Provider;

@Provider
@Produces(MediaType.APPLICATION_JSON)
public class GeoIpReader implements MessageBodyReader {

    @Override
    public boolean isReadable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) {
        return GeoIp.class.isAssignableFrom(type) ;
    }

    @Override
    public GeoIp readFrom(Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, InputStream entityStream) throws IOException, WebApplicationException {
        GeoIp g = new GeoIp();
        JsonParser parser = Json.createParser(entityStream);
        while (parser.hasNext()) {
            switch (parser.next()) {
                case KEY_NAME:
                    String key = parser.getString();
                    parser.next();
                    switch (key) {
                        case "ip":
                            g.setIpAddress(parser.getString());
                            break;
                        case "country_name":
                            g.setCountryName(parser.getString());
                            break;
                        case "latitude":
                            g.setLatitude(parser.getString());
                            break;
                        case "longitude":
                            g.setLongitude(parser.getString());
                            break;
                        case "region_name":
                            g.setRegionName(parser.getString());
                            break;
                        case "city":
                            g.setCity(parser.getString());
                            break;
                        case "zipcode":
                            g.setZipCode(parser.getString());
                            break;
                        default:
                            break;
                    }
                    break;
                default:
                    break;
            }
        }
        return g;
    }
}

Once this class is built, it can be registered with the Client so that it can be called when necessary to convert a payload of MessageType.APPLICATION_JSON type into an instance of the GeoIP object, here done in an @PostConstruct method on a JSF Bean
    @PostConstruct
    public void init() {
        client = ClientBuilder.newClient();
        client.register(GeoIpReader.class);
    }


The alternative way to do thi is to use the EcliseLink MOXY JAXB implementation that is provided with WebLogic Server, which can automatically marhsall and unmarshall JSON payloads to and from Java objects. Helpfully, the JAX-RS 2.0 shared-library that WebLogic Server 12.1.3 contains the jersey-media-moxy extension that enables the EclipseLInk MOXY implementation to be simply registered and used by applications when conversion is needed.

To use the JAXB/MOXY approach, the GeoIPReader class can be thrown away. No manual parsing of the payload is required. Instead, the base GeoIP class is annotated with JAXB annotations to denote it as being JAXB enabled and to provide some assistance in the mapping of the class properties to the payload property names.
package oracle.demo.wls.jaxrs.client.geoip;

import java.io.Serializable;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;

/**
 *
 * @author sbutton
 * {"ip":"173.194.115.75","country_code":"US","country_name":"United States","region_code":"CA","region_name":"California","city":"Mountain View","zipcode":"94043","latitude":37.4192,"longitude":-122.0574,"metro_code":"807","area_code":"650"}            
 */

@XmlRootElement
public class GeoIp implements Serializable {
    
    @XmlAttribute(name = "ip")
    private String ipAddress;
    @XmlAttribute(name = "country_name")
    private String countryName;
    @XmlAttribute(name = "region_name")
    private String regionName;
    @XmlAttribute(name = "city")
    private String city;
    @XmlAttribute(name = "zipcode")
    private String zipCode;
    @XmlAttribute(name = "latitude")
    private String latitude;
    @XmlAttribute(name = "longitude")
    private String longitude;

    ...
   
}


With the JAXB annotations placed on the GeoIP class to enable it to be automatically marshalled/unmarshalled from JSON, the last step is to register the EclipseLink MOXY implementation with the Client. This is done with the assistance of a small utility method, as shown in the Jersey User Guide Media chapter.
    public static ContextResolver createMoxyJsonResolver() {
        final MoxyJsonConfig moxyJsonConfig = new MoxyJsonConfig();
        moxyJsonConfig.setFormattedOutput(true);

        Map namespacePrefixMapper = new HashMap(1);
        namespacePrefixMapper.put("http://www.w3.org/2001/XMLSchema-instance", "xsi");
        moxyJsonConfig.setNamespacePrefixMapper(namespacePrefixMapper).setNamespaceSeparator(':');

        return moxyJsonConfig.resolver();
    }
This method is then used to register the relevant ContextResolver with the Client to use to handle JSON_conversions, instead of the GeoIPReader class that was used before.<
    @PostConstruct
    public void init() {
        client = ClientBuilder.newClient();
        client.register(createMoxyJsonResolver());
        //client.register(GeoIpReader.class);
    }

With the JSON payload to GeoIP conversion now covered, the JAX-RS Client API can be used to make the call to the freegeoip REST service and process the response.

To make a client call, two classes are used: javax.ws.rs.client.Client and javax.ws.rs.client.WebTarget .

The Jersey User Guide provides a good description of theses two classes and their relationship:

The JAX-RS Client API is a designed to allow fluent programming model. This means, a construction of a Client instance, from which a WebTarget is created, from which a request Invocation is built and invoked can be chained in a single "flow" of invocations ... Once you have a Client instance you can create a WebTarget from it ... A resource in the JAX-RS client API is an instance of the Java class WebTarget and encapsulates an URI. The fixed set of HTTP methods can be invoked based on the WebTarget. The [base] representations are Java types, instances of which, may contain links that new instances of WebTarget may be created from.

In this example application, the Client is opened in an @PostConstruct method and closed in a @PreDestroy method, with the WebTarget being created and its GET method called when the lookup is executed by the user.
@Named
@RequestScoped
public class GeoIpBackingBean {

    private WebTarget target = null;
    private Client client = null;

    ...

    @PostConstruct
    public void init() {
        client = ClientBuilder.newClient();
        //client.register(createMoxyJsonResolver());
        client.register(GeoIpReader.class);
    }

    @PreDestroy
    public void byebye() {
        client.close();
    }

    public void lookupAddress() {
        try {
            target = client.target(String.format(rest_base_url, addressToLookup));
            geoIp = target.request().get(GeoIp.class);
        } catch (Exception e) {
            e.printStackTrace();
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Error executing REST call: " + e.getMessage()));
        }
    }
 
    ...
}  


Bringing it all together as a JSF based application results in a JSF Bean being created that allows the IP address to be entered and a method that invokes the JAX-RS Client API to call out to the freegeoip.net REST service to retrieve the JSON payload containing the location information. A simple JSF facelet page is used to support the entering of the IP address and the display of the relevant data from the GeoIP object.


    <h:form>
        <h:panelGrid columns="2" style="vertical-align: top;">
        <h:outputLabel value="Address"/>
        <h:inputText value="${geoIpBackingBean.addressToLookup}"/>
        <h:outputLabel value=""/>
        <h:commandButton action="${geoIpBackingBean.lookupAddress()}" value="Lookup" style="margin: 5px;"/>
        </h:panelGrid>
    </h:form>


    <h:panelGrid columns="2">
        <h:outputText value="IP:"/>
        <h:outputText value="${geoIpBackingBean.geoIp.ipAddress}"/>
        <h:outputText value="Country Code:"/>
        <h:outputText value="${geoIpBackingBean.geoIp.countryName}"/>
        <h:outputText value="State:"/>
        <h:outputText value="${geoIpBackingBean.geoIp.regionName}"/>
        <h:outputText value="City"/>
        <h:outputText value="${geoIpBackingBean.geoIp.city}"/>
        <h:outputText value="Zipcode:"/>
        <h:outputText value="${geoIpBackingBean.geoIp.zipCode}"/>
        <h:outputText value="Coords:"/>
        <c:if test="${geoIpBackingBean.geoIp.ipAddress != null}">
            <h:outputText value="${geoIpBackingBean.geoIp.latitude},${geoIpBackingBean.geoIp.longitude}"/>
        </c:if>
      </h:panelGrid>

The last step to perform is to add a weblogic.xml deployment descriptor with a library-ref to the [jsf,2.0] shared-library, which must be deployed as I described earlier in Using JAX-RS 2.0 with WebLogic Server 12.1.3.

The application is now ready to to deploy and run.

21 March 2014

Using JAX-RS 2.0 in WebLogic Server 12.1.3



Please note: this blog discusses WebLogic Server 12.1.3
which has not yet been released.

We've been working on adding some Java API updates to the coming WebLogic Server 12.1.3 release.

One that I think is going to be very popular is JAX-RS 2.0, which includes some useful new capabilities around filtering, interception and a really useful new client API.

 In the WebLogic Server 12.1.3 release we are providing this in the form of an optional shared-library that contains: the JAX-RS 2.0 API, a Jersey 2.x implementation, some common Jersey extensions such as media support and a utility that works to expose the JAX-RS 2.0 API to referencing applications.

To make use of it, developers first deploy the jax-rs-2.0.war shared-library from the $ORACLE_HOME/wlserver/common/deployable-libraries directory to the server (or cluster) then use it in an application by referencing it as a library using a weblogic deployment descriptor.

Using the library-name and specification-version attributes from the JSF library, an example of a weblogic.xml to use it would be (lines:8-11):

<?xml version="1.0" encoding="UTF-8"?>  
<weblogic-web-app>  
    <jsp-descriptor>  
        <keepgenerated>true</keepgenerated>  
        <debug>true</debug>  
    </jsp-descriptor>  
    <context-root>/service-centre</context-root>  
    <library-ref>  
        <library-name>jax-rs</library-name>  
        <specification-version>2.0</specification-version>  
    </library-ref>  
</weblogic-web-app>  

01 March 2012

WebLogic Server 11g (10.3.6) Documentation

The OTN documentation pages don't appear yet to have a link to the WLS 10.3.6 documentation set.

If you are looking for it in the interim you can find it here: 

http://docs.oracle.com/cd/E23943_01/wls.htm

While this is predominantly a patchset, there are a number of new features listed in the What's New in WebLogic Server document.

Some worthy examples are:

11 February 2011

Using JAX-RS with WebLogic Server 10.3.4

There's been a flurry of blogs recently about using JAX-RS.

It may have slipped under the radar a little, but WebLogic Server 10.3.4 now also provides support for deploying applications that use JAX-RS Web Services.

Here's the documentation for it:

Programming RESTful Web Services

http://download.oracle.com/docs/cd/E17904_01/web.1111/e13734/rest.htm#WSADV550

With WebLogic Server, the JAX-RS support is handled in the same manner as JSF, in that a set of optional shared-libraries are provided that can be deployed to the server, which makes the JAX-RS framework available for deployed applications to use. Applications then reference these shared-libraries using the relevant weblogic deployment descriptor.

What I'd like to do in this blog is to show JAX-RS working on WebLogic Server 10.3.4 and at the same time, how the NetBeans 7.0 Beta release supports WebLogic Server to make the development of JAX-RS based applications quick and efficient by removing some of the work required in deploying and referencing the libraries.  .

1. Launch NetBeans and register a WebLogic Server 10.3.4 instance.

I won't go through the individual steps as this is very straight forward. In my particular case, I have a brand new domain I am using, so there are no applications or shared-libraries deployed.

 

2. Create a new Java EE Web project

The next step is to create a new Java EE Web project using the NetBeans project wizards. This project will host our JAX-RS resource and is what we will deploy and test on WebLogic Server.

Create a new Java Web Project and fill in the project details.




For the Server, I specify the WebLogic Server domain that I registered earlier, leave the Context-Path and finish the project creation and click finish to create the new project.



3. Add a JAX-RS resource to the project.

With the Java Web project created, I can now add a new JAX-RS resource to it, again using a NetBeans wizard -- the simplest way to test this is to use the "RESTful Web Services from Patterns" wizard and select the "Simple Root Resource"option.

Select the “Simple Root Resource” option.



Fill in the details for the resource to be created. In this case, I am specifying a MIME Type of "text/html" to make the default end point easy to test from a browser.



On the last page of the wizard, I am presented with options for how to configure the project. NetBeans has knowledge of how WebLogic Server employs JAX-RS and presents them to you.

I select the option to have NetBeans automatically configure the JAX-RS servlet adapter in web.xml and then I select the "Use server bundled Jersey Library" option.




The JAX-RS resource is then created and added to the project.

Looking at the project, I can see a number of things have changed:

The existing web.xml descriptor has been modified to expose the Jersey Servlet adapter.



A new weblogic.xml deployment descriptor has been added, which references the required JAX-RS shared-library that will be deployed on the server.



And a new class has been added that represents the JAX-RS resource.



After editing the generated getHtml method to return a string I'll recognize, the project is ready to be deployed and tested.

4. Deploy and run the project

Selecting "Run" from the project menu, NetBeans will perform the task of compiling and deploying the project to the target WebLogic Server domain.



NetBeans performs the necessary deployment operations.




Now the interesting thing that happens as part of this "run" process (and why it takes 27 seconds most likely) is that NetBeans has recognized that the target WebLogic Server domain doesn't have the necessary shared-library that the project is using. To resolve this problem, it seamlessly deploys the required library from the $WL_HOME/common/deployable-libraries directory as part of the deployment process.

Once the deployment of the project has completed, looking at the registered WebLogic Server domain, I can now see the jersey-bundle#1.1.1@1.1.5.1 library present on the server.



We can now test the JAX-RS resource.

5. Test the JAX-RS Resource

Expanding the project, there is a "RESTful Web Services" folder that presents a view of the JAX-RS resources in the project. To test the end-point, I select the method and click the "Test Resource URI" option.



This opens a browser window and shows the results of successfully calling the getHtml method.



So there you have it, a JAX-RS resource created in NetBeans, deployed and running on WebLogic Server 10.3.4.

As a final piece to add to this blog, I'll also show off another new feature that NetBeans 7.0 has added to further support WebLogic Server. The new "local deployment" model deploys applications from an exploded, local directory. This means that deployment to WebLogic Server is now much better since a code change doesn't require a full packaging and "deployment" cycle to test. In fact, using NetBeans with WebLogic Server nows offer compile-on-save and test functionality!

6. Add another method and test

With the application deployed, I can now change the class to add more functionality. I'll add two new methods that sayHello and sayBye to a user. In these methods, I'll use the @PathParam and @QueryParam annotations respectively to extract the value from the URI and set it automatically on the method call.



To test these new methods, all I need to do is save the change, NetBeans automatically compiles the class and I can immediately test if from the browser, without needing to issue a redeployment operation!

First off, let's say hello. I use the path variable here to to specify my name:

http://localhost:7001/wls-rs-demo/resources/TestResource/hello/steve



Then I'll say goodbye, this time using a query parameter to specify my name:

http://localhost:7001/wls-rs-demo/resources/TestResource/bye?name=steve



And that's all there is to getting a basic JAX-RS resource up and running on WebLogic Server, developed and deployed in next to no time using NetBeans 7.0.