Monday, June 27, 2011

Weblogic 10.3.4+ Jersey JAX-RS + JSON + SlickGrid

I want to try some RESTful services returning JSON response and use response in JS widgets as part of POC to propose them as an alternative to SOAP based services. Many developers have implemented similar functionality before and we can find many examples on the web (google). But I wanted to try it out myself before I agree with other developers who advocate for REST bases services and to be honest I am convinced after building a simple example application in less than 2 hrs.

My goal is to deploy the example application in Oracle weblogic 10.3.4 and use Jersey JAX-RS 1.5 implementation as this implementation is supported by weblogic and comes as part of shared library. Below are the sequence of steps that I have followed:

1. Enable Jersey JAX-RS implementation in weblogic. Link

2. Setup Maven for weblogic 10.3.4. Link

3. Create a Dynamic webproject in MyEclipse and create a simple service that returns JSON array as response.

POM file

  <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>wlrestgrid</groupId>
 <artifactId>wlrestgrid</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <packaging>war</packaging>
 <name />
 <description />
 <dependencies>
  <dependency>
   <groupId>javax.xml.bind</groupId>
   <artifactId>jaxb-api</artifactId>
   <version>2.1</version>
  </dependency>
  <dependency>
   <groupId>com.sun.xml.bind</groupId>
   <artifactId>jaxb-impl</artifactId>
   <version>2.1.12</version>
  </dependency>
  <dependency>
   <groupId>javax.activation</groupId>
   <artifactId>activation</artifactId>
   <version>1.1</version>
  </dependency>
  <dependency>
   <groupId>javax.xml.stream</groupId>
   <artifactId>stax-api</artifactId>
   <version>1.0-2</version>
  </dependency>
  <dependency>
   <groupId>com.sun.jersey</groupId>
   <artifactId>jersey-core</artifactId>
   <version>1.4</version>
  </dependency>
  <dependency>
   <groupId>javax.ws.rs</groupId>
   <artifactId>jsr311-api</artifactId>
   <version>1.1.1</version>
  </dependency>
  <dependency>
   <groupId>com.sun.jersey</groupId>
   <artifactId>jersey-server</artifactId>
   <version>1.4</version>
  </dependency>
  <dependency>
   <groupId>asm</groupId>
   <artifactId>asm</artifactId>
   <version>3.1</version>
  </dependency>
  <dependency>
   <groupId>com.sun.jersey</groupId>
   <artifactId>jersey-client</artifactId>
   <version>1.4</version>
  </dependency>
  <dependency>
   <groupId>com.sun.jersey</groupId>
   <artifactId>jersey-json</artifactId>
   <version>1.4</version>
  </dependency>
  <dependency>
   <groupId>org.codehaus.jettison</groupId>
   <artifactId>jettison</artifactId>
   <version>1.1</version>
  </dependency>
 </dependencies>
 <build>
  <sourceDirectory>${basedir}/src</sourceDirectory>
  <outputDirectory>${basedir}/WebRoot/WEB-INF/classes</outputDirectory>
  <resources>
   <resource>
    <directory>${basedir}/src</directory>
    <excludes>
     <exclude>**/*.java</exclude>
    </excludes>
   </resource>
  </resources>
  <plugins>
   <plugin>
    <groupId>com.oracle.weblogic</groupId>
    <artifactId>weblogic-maven-plugin</artifactId>
    <version>10.3.4</version>
    <configuration>
     <adminurl>t3://localhost:7001</adminurl>
     <user>weblogic</user>
     <password>WEBLOGIC_PASSWORD</password>
     <upload>true</upload>
     <action>deploy</action>
     <remote>false</remote>
     <verbose>true</verbose>
     <source>${project.build.directory}/${project.build.finalName}.${project.packaging}</source>
     <name>${project.build.finalName}</name>
    </configuration>
    <executions>
     <execution>
      <phase>install</phase>
      <goals>
       <goal>deploy</goal>
      </goals>
     </execution>
    </executions>
   </plugin>
  </plugins>
 </build>a
</project>

web.xml will have JAX-RS servlet mapping

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
 http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
 <display-name></display-name>
 <servlet>
  <display-name>JAX-RS REST Servlet</display-name>
  <servlet-name>JAX-RS REST Servlet</servlet-name>
  <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
  <load-on-startup>1</load-on-startup>
 </servlet>
 <servlet-mapping>
  <servlet-name>JAX-RS REST Servlet</servlet-name>
  <url-pattern>/services/*</url-pattern>
 </servlet-mapping>
 <welcome-file-list>
  <welcome-file>index.jsp</welcome-file>
 </welcome-file-list>
</web-app>


HelloWorld.java

package com.rest;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriInfo;

import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;

import com.bean.GridObject;


@Path("/helloworld")
public class HelloWorld {
 @Context
 private UriInfo context;

 public HelloWorld() {
 }

 @GET
 @Path("getGridData")
 @Produces( { MediaType.APPLICATION_JSON})
 public JSONArray getGridByJson() throws JSONException{
  JSONArray arr = new JSONArray();
  for(int i=0; i< 100; i++){
      arr.put(new GridObject("Task "+i, "5 days", i * 1, "01/01/2009", "01/05/2009", i % 5==0).toJson());
    }
        return arr;
 }
 
}

GridObject.java is a simple POJO object with toJson() method to return json object

package com.bean;

import javax.xml.bind.annotation.XmlRootElement;

import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;

@XmlRootElement
public class GridObject {
 private String title, duration;
 private int percentComplete;
 private boolean effortDriven;
 private String start, finish;

 
 public GridObject() {
  super();
  // TODO Auto-generated constructor stub
 }

 public GridObject(String title, String duration, int percentComplete,
   String start, String finish, boolean effortDriven) {
  this.title = title;
  this.duration = duration;
  this.percentComplete = percentComplete;
  this.start = start;
  this.finish = finish;
  this.effortDriven = effortDriven;
 }

 public String getTitle() {
  return title;
 }

 public void setTitle(String title) {
  this.title = title;
 }

 public String getDuration() {
  return duration;
 }

 public void setDuration(String duration) {
  this.duration = duration;
 }

 public int getPercentComplete() {
  return percentComplete;
 }

 public void setPercentComplete(int percentComplete) {
  this.percentComplete = percentComplete;
 }

 public boolean isEffortDriven() {
  return effortDriven;
 }

 public void setEffortDriven(boolean effortDriven) {
  this.effortDriven = effortDriven;
 }

 public String getStart() {
  return start;
 }

 public void setStart(String start) {
  this.start = start;
 }

 public String getFinish() {
  return finish;
 }

 public void setFinish(String finish) {
  this.finish = finish;
 }

 public JSONObject toJson() throws JSONException {
  JSONObject obj = new JSONObject();
  obj.put("title", title);
  obj.put("duration", duration);
  obj.put("percentComplete", new Integer(percentComplete));
  obj.put("start", start);
  obj.put("finish", finish);
  obj.put("effortDriven", new Boolean(effortDriven));
  return obj;
 }

}



4. Create a JSP page that invokes the RESTful service using JQuery.getJSON() method to get the response and use this response to generate the slickgrid. Why slickgrid?? I like it after seeing the comprehensive exmaple.

Copy all necessary javascript, css and image files from slickgrid to your web applicaiton.

slickgrid.jsp

<html>
 <head>
  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
  <title>SlickGrid example 1: Basic grid</title>
  <link rel="stylesheet" href="css/slickgrid/slick.grid.css" type="text/css" media="screen" charset="utf-8" />
        <link rel="stylesheet" href="css/smoothness/jquery-ui-1.8.5.custom.css" type="text/css" media="screen" charset="utf-8" />
  <link rel="stylesheet" href="css/slickgrid/examples.css" type="text/css" media="screen" charset="utf-8" />
 </head>
 <body>
  <table width="100%">
  <tr>
   <td valign="top" width="50%">
    <div id="myGrid" style="width:600px;height:500px;"></div>
   </td>
   <td valign="top">
    <h2>Demonstrates:</h2>
    <ul>
     <li>basic grid with minimal configuration</li>
    </ul>
   </td>
  </tr>
  </table>

  <script language="JavaScript" src="lib/jquery-1.4.3.min.js"></script> 
  <script language="JavaScript" src="lib/jquery-ui-1.8.5.custom.min.js"></script> 
  <script language="JavaScript" src="lib/jquery.event.drag-2.0.min.js"></script> 
        
        <script language="JavaScript" src="javascripts/slickgrid/slick.core.js"></script> 
  <script language="JavaScript" src="javascripts/slickgrid/slick.editors.js"></script> 
  <script language="JavaScript" src="javascripts/slickgrid/slick.grid.js"></script> 
  <script>

  var grid;
  var data = [];
  var columns = [
   {id:"title", name:"Title", field:"title", width:120, cssClass:"cell-title"},
   {id:"duration", name:"Duration", field:"duration"},
   {id:"%", name:"% Complete", field:"percentComplete", width:80, resizable:false, formatter:GraphicalPercentCompleteCellFormatter},
   {id:"start", name:"Start", field:"start", minWidth:60},
   {id:"finish", name:"Finish", field:"finish", minWidth:60},
   {id:"effort-driven", name:"Effort Driven", sortable:false, width:80, minWidth:20, maxWidth:80, cssClass:"cell-effort-driven", field:"effortDriven", formatter:BoolCellFormatter}
  ];
 
  var options = {
   //editable: false,
   enableAddRow: false,
   enableCellNavigation: true
  };

  $(function() {
       //http://localhost:8080/wlrestgrid/services/helloworld/getGridData
             $.getJSON("services/helloworld/getGridData?timire="+Math.min(100, Math.round(Math.random() * 110)) , 
                function(vals){
                $.each(vals, function() { 
                    data.push(this); 
                }); 
                grid = new Slick.Grid($("#myGrid"), data, columns, options); 
            }); 
        });

  </script>

 </body>
</html>



5. Deploy the application to Oracle weblogic server using Maven and open the slickgrid.jsp file in the browser.

Tuesday, June 21, 2011

Oracle Weblogic 10.3.4

After installing Oracle Weblogic 10.3.4 zip installation on Window XP I was wondering how to create JNDI Data Source using the admin console and did not find a way. So finally I have to write my WLST script and after that I started to like WLST and was amazed with so many things that you can do with this little tool. Below is the WLST script to create Datasource using properties file.

1. Save WLST as CreateDataSource.py
2. Save the below properties file as domain.properties
3. For running WLST scripts follow this link

#Conditionally import wlstModule only when script is executed with jython
if __name__ == '__main__': 
    from wlstModule import *#@UnusedWildImport

from java.io import FileInputStream

propInputStream = FileInputStream("PATH_TO_PROP_FILES/domain.properties")
configProps = Properties()
configProps.load(propInputStream)

print 'starting the script ....'

connect(configProps.get("domain.admin.username"),
        configProps.get("domain.admin.password"), 
        configProps.get("domain.admin.url"))


edit()
startEdit()

server= configProps.get("domain.server.name")

print 'server is ' + server

cd("Servers/"+server)
target=cmo
cd("../..")

dsname=configProps.get("domain.ds.name")
jndiname=configProps.get("domain.jndi.name")
jdbc_url =configProps.get("domain.ds.jdbc.url")
jdbc_driver= configProps.get("domain.ds.jdbc.driver") 
jdbc_user=configProps.get("domain.ds.jdbc.user")
jdbc_pwd=configProps.get("domain.ds.jdbc.pwd")

# start creation
print 'Creating JDBCSystemResource with name '+dsname
jdbcSR = create(dsname,"JDBCSystemResource")
theJDBCResource = jdbcSR.getJDBCResource()
theJDBCResource.setName(dsname)

connectionPoolParams = theJDBCResource.getJDBCConnectionPoolParams()
connectionPoolParams.setConnectionReserveTimeoutSeconds(25)
connectionPoolParams.setMaxCapacity(100)
connectionPoolParams.setTestTableName("SQL SELECT 1 FROM DUAL")
connectionPoolParams.setConnectionCreationRetryFrequencySeconds(100);

dsParams = theJDBCResource.getJDBCDataSourceParams()
dsParams.addJNDIName(jndiname)


driverParams = theJDBCResource.getJDBCDriverParams()
driverParams.setUrl(jdbc_url)
driverParams.setDriverName(jdbc_driver)

driverParams.setPassword(jdbc_pwd)
driverProperties = driverParams.getProperties()

proper = driverProperties.createProperty("user")
proper.setValue(jdbc_user)

jdbcSR.addTarget(target)

save()
activate(block="true")

print 'Done configuring the data source'

Below are the properties files

###################
 Domain-1 Details
###################
domain.name=mydomain
domain.admin.url=t3://localhost:7001
domain.admin.username=weblogic
domain.admin.password=WL_PASSWORD
domain.server.name=myserver

domain.ds.name=JDBCDataSource
domain.jndi.name=jdbc.tempDS 


domain.ds.jdbc.url=jdbc:oracle:thin:@SERVER_NAME:1521:SERVER_INSTANCE
domain.ds.jdbc.driver=oracle.jdbc.driver.OracleDriver
domain.ds.jdbc.user=scott
domain.ds.jdbc.pwd=tiger

PF