Posts Tagged ‘json

05
Mar
11

ExtJS Dynamic Grid Columns

This page describes the process of dynamically creating a ExtJS columnModel based on data from a Ajax call. Generating a data Grid when the columns can not be predefined requires a different approach. The data coming from the server is evaluated and the columnModel is constructed in a set of if-else conditions. Once the column model and store have been initialized they are passed to the gridpanel for display.

Requirements

  • Html Editor
  • HTTP Server to serve the pages from

Procedure

Create the following html page:

Procedure:

  1. Make an Ajax request using the Standard XMLHttpRequest browser object.
  2. Read the meta-data from the response
  3. Run thru a series of if-else conditions to create and insert columns into the dynamic column model
  4. Feed the GridPanel with the store and the column model.

The following html file sets up the styles and imports the core JavaScript libraries.

index.html

<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Stateful + Dynamic Grid Panel with Grouping and Totals</title>


    <!-- ** CSS ** -->
    <!-- base library -->
    <link rel="stylesheet" type="text/css" href="http://dev.sencha.com/deploy/ext-3.3.1/resources/css/ext-all.css" />

    <!-- overrides to base library -->

    <!-- page specific -->
    <link rel="stylesheet" type="text/css" href="http://dev.sencha.com/deploy/ext-3.3.1/examples/shared/examples.css" />

    <style type=text/css>
/*!
 * Ext JS Library 3.3.1
 * Copyright(c) 2006-2010 Sencha Inc.
 * licensing@sencha.com
 * http://www.sencha.com/license
 */
#grid-example .x-grid-col-1 {
	text-align: right;
}
#grid-example .x-grid-col-2{
	text-align: right;
}
#grid-example .x-grid-col-3 {
	text-align: right;
}
#grid-example .x-grid-col-4 {
	text-align: right;
}
#grid-example.x-grid-mso{
	border: 1px solid #6593cf;
}
#grid-example.x-grid-vista{
	border: 1px solid #b3bcc0;
}
#xml-grid-example{
	border: 1px solid #cbc7b8;
	left: 0;
	position: relative;
	top: 0;
}
#editor-grid .x-grid-col-2{
    text-align:right;
}
.x-grid3-td-topic b {
    font-family:tahoma, verdana;
    display:block;
}
.x-grid3-td-topic b i {
    font-weight:normal;
    font-style: normal;
    color:#000;
}
.x-grid3-td-topic .x-grid3-cell-inner {
    white-space:normal;
}
.x-grid3-td-topic a {
    color: #385F95;
    text-decoration:none;
}
.x-grid3-td-topic a:hover {
    text-decoration:underline;
}
.details .x-btn-text {
    background-image: url(details.gif);
}
.x-resizable-pinned .x-resizable-handle-south{
    background:url(../../resources/images/default/sizer/s-handle-dark.gif);
    background-position: top;
}
        /* style rows on mouseover */
        .x-grid3-row-over .x-grid3-cell-inner {
            font-weight: bold;
        }

        /* style for the "buy" ActionColumn icon */
        .x-action-col-cell img.buy-col {
            height: 16px;
            width: 16px;
            background-image: url(../shared/icons/fam/accept.png);
        }

        /* style for the "alert" ActionColumn icon */
        .x-action-col-cell img.alert-col {
            height: 16px;
            width: 16px;
            background-image: url(../shared/icons/fam/error.png);
        }

    </style>
    
    <!-- overrides to base library -->
    <link rel="stylesheet" type="text/css" href="http://dev.sencha.com/deploy/ext-3.3.1/examples/ux/css/GroupSummary.css" />

    <!-- ** Javascript ** -->

    <!-- ExtJS library: base/adapter -->
<script type="text/javascript"
    src="http://dev.sencha.com/deploy/ext-3.3.1/adapter/ext/ext-base-debug.js">
</script>
<script type="text/javascript"
    src="http://dev.sencha.com/deploy/ext-3.3.1/ext-all-debug.js">
</script>

    <!-- overrides to base library -->
    <!-- extensions -->
    <script type="text/javascript" src="http://dev.sencha.com/deploy/ext-3.3.1/examples/ux/GroupSummary.js"></script>

    <!-- page specific -->

    <script type="text/javascript" src="array-grid.js"></script>

</head>
<body>
    <h1>Stateful + Dynamic Grid Panel with Grouping and Totals</h1>
    <p>Note that the js is not minified so it is readable. See <a href="array-grid.js">array-grid.js</a>.</p>
    
    <div id="grid-example2"></div>

</body>
</html>

array-grid.js

Ext.onReady(function(){
    Ext.QuickTips.init();
    Ext.state.Manager.setProvider(new Ext.state.CookieProvider());

	// The columns are constructed dynamically here 
	// Ext.Ajax.request() introduces timing issues since it is asynchronous.
	// use XMLHttpRequest since it is synchronous in nature.
    var xmlhttp = {};
    if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari
      xmlhttp=new XMLHttpRequest();
    } else { // code for IE6, IE5
        xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
    }
    xmlhttp.open("GET",'response1.do',false); // make a synchronous request
    xmlhttp.send(null);

	var prefs = {};
    if(xmlhttp.status == 200) {
	    var ajaxReader = new Ext.data.JsonReader();
		var ajaxStore = new Ext.data.GroupingStore({
			groupField:'industry',
			reader: ajaxReader,
			data: Ext.decode(xmlhttp.responseText)
		});

		var myColumns = [];
		// create the column model dynamically.
		for (var i = 0, len = ajaxReader.meta.fields.length; i < len; i++) {
			var field = ajaxReader.meta.fields[i];
			if(field.name == 'company') {
 				var this_column = {};
                this_column['id'] = 'company';
                this_column['header'] = 'Company';
                this_column['width'] = 60;
                this_column['sortable'] = true;
                this_column['dataIndex'] = 'company';
                this_column['hideable'] = false;
                this_column['summaryType'] = 'max';                    
                myColumns.push(this_column); 					
			} else if(field.name == 'price') {
                var this_column = {};
                this_column['id'] = 'price';
                this_column['header'] = 'Price';
                this_column['width'] = 20;
                this_column['sortable'] = true;
                this_column['dataIndex'] = 'price';
				this_column['renderer'] = Ext.util.Format.usMoney;
                this_column['summaryType'] = 'average';
                myColumns.push(this_column); 				
			} else if (field.name == 'change') {
				// Change 				
                var this_column = {};
                this_column['id'] = 'change';
                this_column['header'] = 'Change';
                this_column['width'] = 20;
                this_column['sortable'] = true;
				this_column['renderer'] = Ext.util.Format.usMoney;
                this_column['dataIndex'] = 'change';
                this_column['summaryType'] = 'max';
                myColumns.push(this_column); 				
			} else if (field.name == 'industry') {                    
				// Industry
                var this_column = {};
                this_column['id'] = 'industry';
                this_column['header'] = 'Industry';
                this_column['width'] = 20;
                this_column['sortable'] = true;
                this_column['dataIndex'] = 'industry';
                myColumns.push(this_column);
			} else if (field.name == 'lastChange') {                    
				// Last Updated
                var this_column = {};
                this_column['id'] = 'lastChange';
                this_column['header'] = 'Last Change';
                this_column['width'] = 20;
                this_column['sortable'] = true;
                this_column['dataIndex'] = 'lastChange';
                this_column['summaryType'] = 'max';
                myColumns.push(this_column);
			}	 					 				
		}					
		var grid2 = new Ext.grid.GridPanel({
			store: ajaxStore,
			stripeRows: true,
			height: 350,
			width: 600,
			stateful: true,
			stateId: 'grid2',
	        plugins: new Ext.ux.grid.GroupSummary(),
	        title: 'Stateful + Dynamic Grid Panel with Grouping and Totals',				
			view: new Ext.grid.GroupingView({
			    forceFit:true,
			    groupTextTpl: '{text} ({[values.rs.length]} {[values.rs.length > 1 ? "Items" : "Item"]})'
			}),
			fbar  : ['->', {
			    text:'Clear Grouping',
			    iconCls: 'icon-clear-group',
			    handler : function(){
			        ajaxStore.clearGrouping();
			        grid2.fireEvent('groupchange', this);
			    }
			}],        
			cm: new Ext.grid.ColumnModel({
				defaults: {
					width: 120,
					sortable: true
				},
				columns: myColumns
			})		
		});
		grid2.render('grid-example2'); 				 				
		
    } else {
        // there was an error
//        console.error('there was an error getting data from the server');
    } 
});

The “metaData” in the response below allows the JsonReader to configure itself.

response1.do

{
"metaData" : {
	totalProperty : 'totalCount',
	root : 'records',
	successProperty : "success",
	fields : [
       {name: 'company', type : 'string'},
       {name: 'price', type: 'float'},
       {name: 'change', type: 'float'},
       {name: 'pctChange', type: 'float'},
       {name: 'lastChange', type: 'date', dateFormat: 'n/j h:ia'},
       {name: 'industry', type : 'string'}
	]
},
"success": true,
"totalCount" : "30",
"records" : [
    {company: '3m Co'								,price: 71.72,change: 0.02,pctChange: 0.03,lastChange: '4/2 12:00am', industry: 'Manufacturing'},
    {company: 'Alcoa Inc'							,price: 29.01,change: 0.42,pctChange: 1.47,lastChange: '4/1 12:00am', industry: 'Manufacturing'},
    {company: 'Altria Group Inc'					,price: 83.81,change: 0.28,pctChange: 0.34,lastChange: '4/3 12:00am', industry: 'Manufacturing'},
    {company: 'American Express Company'			,price: 52.55,change: 0.01,pctChange: 0.02,lastChange: '4/8 12:00am', industry: 'Finance'},
    {company: 'American International Group, Inc.'	,price: 64.13,change: 0.31,pctChange: 0.49,lastChange: '4/1 12:00am', industry: 'Services'},
    {company: 'AT&T Inc.'							,price: 31.61,change: -0.48,pctChange: -1.54,lastChange: '4/8 12:00am', industry: 'Services'},
    {company: 'Boeing Co.'							,price: 75.43,change: 0.53,pctChange: 0.71,lastChange: '4/8 12:00am', industry: 'Manufacturing'},
    {company: 'Caterpillar Inc.'					,price: 67.27,change: 0.92,pctChange: 1.39,lastChange: '4/1 12:00am', industry: 'Services'},
    {company: 'Citigroup, Inc.'						,price: 49.37,change: 0.02,pctChange: 0.04,lastChange: '4/4 12:00am', industry: 'Finance'},
    {company: 'E.I. du Pont de Nemours and Company'	,price: 40.48,change: 0.51,pctChange: 1.28,lastChange: '4/1 12:00am', industry: 'Manufacturing'},
    {company: 'Exxon Mobil Corp'					,price: 68.1,change: -0.43,pctChange: -0.64,lastChange: '4/3 12:00am', industry: 'Manufacturing'},
    {company: 'General Electric Company'			,price: 34.14,change: -0.08,pctChange: -0.23,lastChange: '4/3 12:00am', industry: 'Manufacturing'},
    {company: 'General Motors Corporation'			,price: 30.27,change: 1.09,pctChange: 3.74,lastChange: '4/3 12:00am', industry: 'Automotive'},
    {company: 'Hewlett-Packard Co.'					,price: 36.53,change: -0.03,pctChange: -0.08,lastChange: '4/3 12:00am', industry: 'Computer'},
    {company: 'Honeywell Intl Inc'					,price: 38.77,change: 0.05,pctChange: 0.13,lastChange: '4/3 12:00am', industry: 'Manufacturing'},
    {company: 'Intel Corporation'					,price: 19.88,change: 0.31,pctChange: 1.58,lastChange: '4/2 12:00am', industry: 'Computer'},
    {company: 'International Business Machines'		,price: 81.41,change: 0.44,pctChange: 0.54,lastChange: '4/1 12:00am', industry: 'Computer'},
    {company: 'Johnson & Johnson'					,price: 64.72,change: 0.06,pctChange: 0.09,lastChange: '4/2 12:00am', industry: 'Medical'},
    {company: 'JP Morgan & Chase & Co'				,price: 45.73,change: 0.07,pctChange: 0.15,lastChange: '4/2 12:00am', industry: 'Finance'},
    {company: 'McDonald\'s Corporation'				,price: 36.76,change: 0.86,pctChange: 2.40,lastChange: '4/2 12:00am', industry: 'Food'},
    {company: 'Merck & Co., Inc.'					,price: 40.96,change: 0.41,pctChange: 1.01,lastChange: '4/2 12:00am', industry: 'Medical'},
    {company: 'Microsoft Corporation'				,price: 25.84,change: 0.14,pctChange: 0.54,lastChange: '4/2 12:00am', industry: 'Computer'},
    {company: 'Pfizer Inc'							,price: 27.96,change: 0.4,pctChange: 1.45,lastChange: '4/8 12:00am', industry: 'Services'},
    {company: 'The Coca-Cola Company'				,price: 45.07,change: 0.26,pctChange: 0.58,lastChange: '4/1 12:00am', industry: 'Food'},
    {company: 'The Home Depot, Inc.'				,price: 34.64,change: 0.35,pctChange: 1.02,lastChange: '4/8 12:00am', industry: 'Retail'},
    {company: 'The Procter & Gamble Company'		,price: 61.91,change: 0.01,pctChange: 0.02,lastChange: '4/1 12:00am', industry: 'Manufacturing'},
    {company: 'United Technologies Corporation'		,price: 63.26,change: 0.55,pctChange: 0.88,lastChange: '4/1 12:00am', industry: 'Computer'},
    {company: 'Verizon Communications'				,price: 35.57,change: 0.39,pctChange: 1.11,lastChange: '4/3 12:00am', industry: 'Services'},
    {company: 'Wal-Mart Stores, Inc.'				,price: 45.45,change: 0.73,pctChange: 1.63,lastChange: '4/3 12:00am', industry: 'Retail'},
    {company: 'Walt Disney Company (The) (Holding Company)',price: 29.89,change: 0.24,pctChange: 0.81,lastChange: '4/1 12:00am', industry: 'Services'}
]
}

Test the page

The page will NOT work if you simply save the files to a local directory and point your browser there. The pages must be served by a HTTP Server. Setting up a server is beyond the scope of this page.

02
Mar
11

Spring Framework based RESTful Web Service

This page shows you how to quickly and easily create a read-only Spring based RESTful Web Service / Application.

To keep things simple I will not be covering the “front-end” view technologies. Please see one of my other pages on how to get Spring MVC, JSF, extJS or even standard Servlets/JSP’s running with the application discussed here.

You can drop in any “view technologies” once you have the below application running.

The application will retrieve a list of cities from a “mock” datamanager and display them in JSON format in a browser.

The page should take 10-15 minutes to implement.

Requirements

  • Basic understanding of Spring
  • Basic understanding of REST
  • Java 5
  • Maven 2

Procedure

Configure the project

Create a project using Maven archetype. Open up the command prompt and navigate to an empty directory.

mvn archetype:generate -DarchetypeArtifactId=maven-archetype-webapp

groupId: com.test
artifactId: springRestWeb

Answer the rest of the questions with defaults “Just hit the enter key”,

Cd to the project base folder.

cd springRestWeb

Since this is a web project maven does not create the java source foldder.

Create missing directory
mkdir -p src/main/java/com/test

Modify the project configuration file

Open up the pom.xml file and make sure it looks like the one below. In most cases you can just copy and paste the one below into your own.

pom.xml

<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>com.test</groupId>
  <artifactId>springRestWeb</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>springRestWeb</name>
  <url>http://maven.apache.org</url>
    <repositories>
        <repository>
           <id>maven-restlet</id>
           <name>Public online Restlet repository</name>
           <url>http://maven.restlet.org</url>
        </repository>
    </repositories>
 
  <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>

    <dependency>
        <groupId>org.json</groupId>
        <artifactId>json</artifactId>
        <version>20090211</version>
    </dependency>        
    <dependency>
      <groupId>cglib</groupId>
      <artifactId>cglib</artifactId>
      <version>2.2</version>
    </dependency>
        
    <dependency>
       <groupId>org.restlet.jee</groupId>
       <artifactId>org.restlet</artifactId>
       <version>2.0.5</version>
    </dependency>
    <dependency>
       <groupId>org.restlet.jse</groupId>
       <artifactId>org.restlet.ext.simple</artifactId>
       <version>2.0.5</version>
    </dependency>
    <dependency>
       <groupId>org.restlet.jee</groupId>
       <artifactId>org.restlet.ext.spring</artifactId>
       <version>2.0.5</version>
    </dependency>
    
    <dependency>
       <groupId>org.restlet.jee</groupId>
       <artifactId>org.restlet.ext.servlet</artifactId>
       <version>2.0.5</version>
    </dependency>
    
    <!-- spring framework -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>3.0.1.RELEASE</version>
    </dependency>
        
        <dependency>
            <groupId>org.apache.geronimo.specs</groupId>
            <artifactId>geronimo-servlet_2.5_spec</artifactId>
            <version>1.2</version>
            <scope>provided</scope>
        </dependency>
  </dependencies>
 
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.0.2</version>
                <configuration>
                    <source>1.5</source>
                    <target>1.5</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.mortbay.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
				<version>7.0.0.v20091005</version>
                <configuration>
                    <scanIntervalSeconds>2</scanIntervalSeconds>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Web Application Configuration

The application uses the “org.restlet.ext.spring.SpringServerServlet” to respond to HTTP Requests. This servlet responds to URL’s that begin with “/app/*” and delegates the handling of the requests to the Resources based on the routing logic specified in the ApplicationContext.xml.

src/main/webapp/WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    id="WebApp_ID" version="2.5">
  <display-name>Archetype Created Web Application</display-name>

<!-- The following is  used to initialize the spring framework when the web app starts. -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
 
     <servlet>
        <servlet-name>stateApplication</servlet-name>
        <servlet-class>
             org.restlet.ext.spring.SpringServerServlet
        </servlet-class>
        <init-param>
			<param-name>org.restlet.application</param-name>
			<param-value>stateApplication</param-value>
        </init-param>
    </servlet>

    <servlet-mapping>
        <servlet-name>stateApplication</servlet-name>
        <url-pattern>/app/*</url-pattern>
    </servlet-mapping>
 
 
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
 
</web-app>

Spring Configuration

The stateApplication uses a router that further checks the URL and calls the proper “Resource” based on the mappings. The routing logic consists of a “url pattern” that will cause the specified “Resource” to be called upon to respond to the request.

Each map entry uses a “SpringFinder” to create an instance of the Resource. The instance of the resource can have any number of beans injected into it (based on spring configuration).

src/main/webapp/WEB-INF/applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
 
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
 
http://www.springframework.org/schema/context
 
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
 
	<bean id="stateDataManager" class="com.test.StateDataManager"/>

	<bean id="stateApplication" class="org.restlet.Application" scope="singleton">
		<property name="root">
			<bean class="org.restlet.ext.spring.SpringRouter">
				<property name="attachments">
					<map>
						<entry key="/state/{name}">
							<bean class="org.restlet.ext.spring.SpringFinder">
								<lookup-method name="create" bean="stateResource" />
							</bean>
						</entry>
					</map>
				</property>
			</bean>
		</property>
	</bean>

	<bean id="stateResource" class="com.test.StateResource" scope="prototype">
		<property name="stateDataManager" ref="stateDataManager"/>
    </bean>
		
</beans>

Create the Resource

The “Resource” is called upon to respond to requests. The “stateDataManager” member will be injected using the spring configuration seen above.

src/main/java/com/test/StateResource.java

package com.test;

import org.json.JSONArray;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import org.restlet.resource.ResourceException;
import org.restlet.resource.ServerResource;
import org.springframework.beans.factory.annotation.Required;

public class StateResource extends ServerResource {
	// the stateDataManager is injected using Spring
	private StateDataManager stateDataManager;
	
	// ServerResources are thread safe (spring "prototype")
	private String state;
	
    public StateResource() {
        super();
    }
    @Override
    protected void doInit() throws ResourceException {
    	super.doInit();
    	state = (String)getRequestAttributes().get("name");
    }
    @Override
    protected Representation get() throws ResourceException {
    	
        JSONArray jsonArray = new JSONArray(stateDataManager.getCities(state));
        StringBuffer out = new StringBuffer();
        String cb = getQuery().getFirstValue("callback");
        out.append(cb + "(");
        out.append("{ \"totalCount\" : \"" + jsonArray.length() + "\",");
        out.append("\"records\" : ");
        out.append(jsonArray.toString());
        out.append("}");
        out.append(");");
        
        return new StringRepresentation(out.toString());
    }
    @Required
	public void setStateDataManager(StateDataManager stateDataManager) {
		this.stateDataManager = stateDataManager;
	}
	public StateDataManager getStateDataManager() {
		return stateDataManager;
	}
}

Data Manager

This is the dummy data manager. In your situation you would replace the hard coding with a connection to a real database. I have many examples where Spring is used to connect to a mySQL database. Please search for “SimpleJDBC” on the top right corner.

src/main/java/com/test/StateDataManager.java

package com.test;

import java.util.ArrayList;
import java.util.List;

/**
 * This is a test data manager that returns dummy data.
 */
public class StateDataManager {
	public List<String> getCities(String state) {
		// return the list of cities given a state		
		List<String> cityList = new ArrayList<String>();		
		if("TX".equals(state)) {
			cityList.add("Houston");
			cityList.add("San Antonio");
			cityList.add("Dallas");
			cityList.add("Austin");
			cityList.add("El Paso");
			cityList.add("Fort Worth");			
		} else if("NY".equals(state)) {
			cityList.add("New York City");
			cityList.add("Buffalo");
			cityList.add("Rochester");
			cityList.add("Yonkers");
			cityList.add("Syracuse");
		} else if("CA".equals(state)) {
			cityList.add("Los Angeles");
			cityList.add("San Diego");
			cityList.add("San Jose");
			cityList.add("San Francisco");
			cityList.add("Fresno");
		} else {
			// don't add any cities
		}
		return cityList;
	}
}

Test the Application

mvn clean compile jetty:run

Use your browser to navigate to the following URLs:
http://localhost:8080/app/state/CA
http://localhost:8080/app/state/NY
http://localhost:8080/app/state/TX

You should see something like this in your browser:

null({ "totalCount" : "5","records" : ["Los Angeles","San Diego","San Jose","San Francisco","Fresno"]});

The above format is designed to work with the extJS “Ext.data.ScriptTagProxy”. But you can use any number of view technologies to parse and display the data.

Creating a WAR file

If you want to run the application in another environment you can create a war file and drop it into a server of your choice. This method will also package up any runtime dependencies and put them in the /WEB-INF/lib folder of the WAR file.

mvn clean compile package

The war file should appear in the following location…

springRestWeb/target/springRestWeb-1.0-SNAPSHOT.war

24
Feb
11

extJS GridPanel using data from RESTlet Invocation

This page will describe an implementation of an extJS grid panel component being fed data in JSON format from a server side resource. In this case it will be the RESTlet however you can always use a standard Java Servlet as well. This page introduces you to ExtJS, JSON, and RESTlet technologies.

Requirements

  • Maven 2 – see my maven tutorial
  • Java 5
  • Basic understanding of extJS
  • Basic understanding of RESTlet framework
  • Basic understanding of JSON

Background

The data coming from the RESTlet looks like the following.

callbackName({ "totalCount" : "4","records" : [
	{"state":"NY","fullName":"John Allen"},
	{"state":"NJ","fullName":"Bob Smith"},
	{"state":"NY","fullName":"John Adams"},
	{"state":"CA","fullName":"John Doe"}
]});

Procedure

We will start by creating a new project using maven 2.

mvn archetype:generate -DarchetypeArtifactId=maven-archetype-webapp

For the group id enter: com.test
For the artifactId enter: extJSWeb

Answer the rest of the questions using defaults [Hit Enter].

cd to the project’s folder

Edit the pom.xml file to look like the following…

pom.xml

<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>com.test</groupId>
  <artifactId>extjsWeb</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>extjsWeb Maven Webapp</name>
  <url>http://maven.apache.org</url>
    <repositories>
        <repository>
           <id>maven-restlet</id>
           <name>Public online Restlet repository</name>
           <url>http://maven.restlet.org</url>
        </repository>
    </repositories>  
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
	<dependency>
	    <groupId>org.json</groupId>
	    <artifactId>json</artifactId>
	    <version>20090211</version>
	</dependency>    
    <dependency>
       <groupId>org.restlet.jse</groupId>
       <artifactId>org.restlet</artifactId>
       <version>2.0.0</version>
    </dependency>
    <dependency>
       <groupId>org.restlet.jse</groupId>
       <artifactId>org.restlet.ext.simple</artifactId>
       <version>2.0.0</version>
    </dependency>
    <dependency>
       <groupId>org.restlet.jse</groupId>
       <artifactId>org.restlet.ext.json</artifactId>
       <version>2.0.0</version>
    </dependency>
    <dependency>
       <groupId>org.restlet.jee</groupId>
       <artifactId>org.restlet.ext.servlet</artifactId>
       <version>2.0.0</version>
    </dependency>
        <dependency>
            <groupId>org.apache.geronimo.specs</groupId>
            <artifactId>geronimo-servlet_2.5_spec</artifactId>
            <version>1.2</version>
            <scope>provided</scope>
        </dependency>

  </dependencies>
  <build>
    <finalName>extjsWeb</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.0.2</version>
                <configuration>
                    <source>1.5</source>
                    <target>1.5</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.mortbay.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
				<version>7.0.0.v20091005</version>
                <configuration>
                    <scanIntervalSeconds>2</scanIntervalSeconds>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-eclipse-plugin</artifactId>
                <configuration>
                    <wtpapplicationxml>true</wtpapplicationxml>
                    <wtpversion>1.5</wtpversion>
                    <downloadSources>true</downloadSources>
                    <downloadJavadocs>true</downloadJavadocs>
                    <classpathContainers>
                        <classpathContainer>org.eclipse.jst.j2ee.internal.web.container</classpathContainer>
                        <classpathContainer>org.eclipse.jst.j2ee.internal.module.container</classpathContainer>
                    </classpathContainers>
                    <additionalProjectFacets>
                        <jst.web>2.5</jst.web>
                        <jst.jsf>1.2</jst.jsf>
                    </additionalProjectFacets>
                </configuration>
            </plugin>
        </plugins>
  </build>
</project>

JSP Page

The following page contains the “gridPanelRestletExample.js” file responsible for rendering the grid panel component. For the sake of simplicity I will link to the extJS css and js files directly from the Sencha site. This is not recommended for production code. In production the extJS library should be downloaded and installed onto your web or App server.

src/main/webapp/gridPanelRestlet.jsp

<html>
<head>
	<link rel="stylesheet" type="text/css"
		href="http://dev.sencha.com/deploy/ext-3.3.1/resources/css/ext-all.css"/>
		
	<script type="text/javascript"
		src="http://dev.sencha.com/deploy/ext-3.3.1/adapter/ext/ext-base-debug.js">
	</script>
	<script type="text/javascript"
		src="http://dev.sencha.com/deploy/ext-3.3.1/ext-all-debug.js">
	</script>
	
	<script type="text/javascript" src='gridPanelRestletExample.js'>
	</script>
	
</head>

<body>
</body>
</html>

Finally the javascript for the component.

src/main/webapp/gridPanelRestletExample.js

function buildWindow() {

	// The following calls the restlet to get the data
	var remoteProxy = new Ext.data.ScriptTagProxy( {
		url : 'app/addresses'
	});

	var recordFields = [ 'fullName', 'state' ];

	var store2 = new Ext.data.JsonStore( {
		proxy : remoteProxy,
		id : 'ourRemoteStore',
		root : 'records',
		autoLoad : true,
		totalProperty : 'totalCount',
		remoteSort : false,
		fields : recordFields
	});

	var cm = new Ext.grid.ColumnModel( [ {
		header : 'Full Name',
		sortable : true,
		dataIndex : 'fullName'
	}, {
		header : 'State',
		dataIndex : 'state'
	} ]);

	var gridView = new Ext.grid.GridView();
	var selModel = new Ext.grid.RowSelectionModel( {
		singleSelect : true
	});

	var grid = new Ext.grid.GridPanel( {
		title : 'Our first grid',
		renderTo : Ext.getBody(),
		autoHeight : true,
		width : 250,
		store : store2,
		view : gridView,
		colModel : cm,
		selModel : selModel
	});

}

Ext.onReady(buildWindow);

The following is a Plain Old Java Object that represents an Address. It will be used to generate the JSON response by the RESTlet.

src/main/java/com/test/Address.java

package com.test;
 
public class Address {
	private String fullName;
    private String state;

    public Address() {
    	super();
    }
    
    public Address(String fullName, String state) {
    	this.fullName = fullName;
    	this.state = state;    	
    }
    
    public String getState() {
        return state;
    }

	public void setFullName(String fullName) {
		this.fullName = fullName;
	}

	public String getFullName() {
		return fullName;
	}
}

The following is the RESTlet that will be performing all the work.

src/main/java/com/test/AddressResource.java

package com.test;

import java.util.ArrayList;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONObject;
import org.restlet.Context;
import org.restlet.Request;
import org.restlet.Response;
import org.restlet.data.MediaType;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import org.restlet.representation.Variant;
import org.restlet.resource.ResourceException;
import org.restlet.resource.ServerResource;

public class AddressResource extends ServerResource {

	public AddressResource() {
		super();
	}

	public AddressResource(Context context, Request request, Response response) {
		getVariants().add(new Variant(MediaType.TEXT_HTML));
	}

	@Override
	protected Representation get() throws ResourceException {
		List<JSONObject> addressList = new ArrayList<JSONObject>();

		addressList.add(new JSONObject(new Address("John Allen", "NY")));
		addressList.add(new JSONObject(new Address("Bob Smith", "NJ")));
		addressList.add(new JSONObject(new Address("John Adams", "NY")));
		addressList.add(new JSONObject(new Address("John Doe", "CA")));

		JSONArray jsonArray = new JSONArray(addressList);
		StringBuffer out = new StringBuffer();
		String cb = getQuery().getFirstValue("callback");
		out.append(cb + "(");
		out.append("{ \"totalCount\" : \"" + jsonArray.length() + "\",");
		out.append("\"records\" : ");

		out.append(jsonArray.toString());

		out.append("}");

		out.append(");");

		return new StringRepresentation(out.toString());
	}
}

The following is the RESTful Web Service that manages the Address Resource.

src/main/java/com/test/DemoApplication.java

package com.test;

import org.restlet.Application;
import org.restlet.Context;
import org.restlet.Restlet;
import org.restlet.routing.Router;

public class DemoApplication extends Application {

	public DemoApplication() {
		super();
	}

	public DemoApplication(Context parentContext) {
		super(parentContext);
	}

	public Restlet createRoot() {
		Router router = new Router(getContext());
		router.attach("/addresses", AddressResource.class);
		return router;
	}

}

src/main/webapp/WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    id="WebApp_ID" version="2.5">
  <display-name>Archetype Created Web Application</display-name>
 
         <servlet>
                 <servlet-name>Restlet</servlet-name>
                 <servlet-class>org.restlet.ext.servlet.ServerServlet</servlet-class>
                 <init-param>
                         <param-name>org.restlet.application</param-name>
                         <param-value>com.test.DemoApplication</param-value>
                 </init-param>
         </servlet>
 
    <servlet-mapping>
        <servlet-name>Restlet</servlet-name>
        <url-pattern>/app/*</url-pattern>
    </servlet-mapping>
 
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
 
</web-app>

Test the application

mvn jetty:run

Test the RESTlet:
Start up jetty and navigate to the following URL:

http://localhost:8080/app/addresses?callback=callbackName
Test the Page:
http://localhost:8080/gridPanelRestlet.jsp

25
Nov
10

Converting Java Object to JSON String

This page covers the process of converting Java Objects to JSON Strings. And JSON Strings back to Java Objects. I will also cover how to do the conversion with ArrayList of objects.

Background

JSON is becoming a popular way to transmit data between Web Applications and User Agents (Browsers, mobile apps etc…). I have gotten into Experimenting with Android applications so I thought it would be a nice idea to write some stuff about JSON and how its used with Java.

This page contains a working “Java Main” application that you can run from command line.

Requirements

  • Java 5 or above
  • Maven 2

Create the project

I will be creating this project using Maven but you can simply find the JSON libraries and install it in the classpath and follow along.

mvn archetype:generate -DarchetypeArtifactId=maven-archetype-quickstart

For the group id enter: com.test
For the artifactId enter: jsonTest

Answer the rest of the questions using defaults [Hit Enter].

cd to the project’s folder

Next we create the src/main/java folder since this is not done for us using the archetype.

on unix you type:

cd jsonTest
mkdir -p src/main/java
mkdir -p src/main/java/com/test

Project Configuration

Modify the configuration and verify that it looks something like this.

pom.xml

<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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.test</groupId>
  <artifactId>jsonTest</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>jsonTest</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
<dependency>
    <groupId>org.json</groupId>
    <artifactId>json</artifactId>
    <version>20090211</version>
</dependency>
  </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.0.2</version>
                <configuration>
                    <source>1.5</source>
                    <target>1.5</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Address Bean

We start by creating the Address Bean.

src/main/java/com/test/Address.java

package com.test;

public class Address {
	private String street;
	private String city;
	private String state;
	private String zip;
	
	public Address(String street, String city, String state, String zip) {
		this.street = street;
		this.city = city;
		this.state = state;
		this.zip = zip;
	}
	public String getStreet() {
		return street;
	}
	public String getCity() {
		return city;
	}
	public String getState() {
		return state;
	}
	public String getZip() {
		return zip;
	}
	public String toString() {
		return "Address [city=" + city + ", state=" + state + ", street="
				+ street + ", zip=" + zip + "]";
	}
}

Create the AddressDataManager

This class is responsible for managing instances of the address class. This class encapsulates all the JSON operations away from the Address Java Bean. It doesn’t exactly follow the “Spring Framework’s” way of doing things but it could be enhanced to work with the spring framework.

src/main/java/com/test/AddressDataManager.java

package com.test;

import java.util.ArrayList;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

public class AddressDataManager {
	public List<Address> parseJSONArrayAddressList(String jsonString) {
		List<Address> parsedAddressList = new ArrayList<Address>();

		try {
			JSONArray jsonArray2 = new JSONArray(jsonString);
			int length = jsonArray2.length();			
			for(int i=0; i< length; i++) {
				JSONObject a = (JSONObject)jsonArray2.get(1);
				parsedAddressList.add(parseJSONObject(a));
			}
			return parsedAddressList;
		} catch (JSONException e) {
			throw new RuntimeException(e);
		}
	}

	public Address parseJSONObject(JSONObject a) throws JSONException {
		Address address = new Address(
				a.getString("street"), 
				a.getString("city"), 
				a.getString("state"), 
				a.getString("zip"));
		return address;
	}
}

Test Class

Finally this is our test class that pretty much runs the show. Reading the comments is the best way to follow along.

src/main/java/com/test/TestActivity.java

package com.test;

import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

public class TestActivity {
	
	public static void main(String args[]) {
		
		AddressDataManager addressDataManager = new AddressDataManager();
		
		Address a1 = new Address("100 Main Street", "New York", "NY", "10010");
		Address a2 = new Address("110 Main Street", "New York", "NY", "12345");
		Address a3 = new Address("4 Chestnut Street", "New York", "NY", "54321");
		
		// convert a object into a string
		System.out.println("JSON String: " + new JSONObject(a1).toString());
		
		// convert a string into an object
		String singleAddressJSON = 
			"{\"zip\":\"10010\",\"street\":\"100 Main Street\",\"state\":\"NY\",\"city\":\"New York\"}";

		try {
			System.out.println("Address Object: " + 
					addressDataManager.parseJSONObject(new JSONObject(singleAddressJSON)));
		} catch (JSONException e) {
			throw new RuntimeException(e);
		}
		
		// convert an ArrayList into a json array
		java.util.List<JSONObject> addressList = 
			new java.util.ArrayList<JSONObject>();

		addressList.add(new JSONObject(a1));
		addressList.add(new JSONObject(a2));
		addressList.add(new JSONObject(a3));
		
		JSONArray jsonArray = new JSONArray(addressList);
		System.out.println(jsonArray.toString());
		
		// convert JSON array to ArrayList
		final String jsonString = 
			"[{\"zip\":\"10010\",\"street\":\"100 Main Street\",\"state\":\"NY\"" +
			",\"city\":\"New York\"},{\"zip\":\"12345\",\"street\":\"110 Main Street\"" +
			",\"state\":\"NY\",\"city\":\"New York\"},{\"zip\":\"54321\",\"street\"" +
			":\"4 Chestnut Street\",\"state\":\"NY\",\"city\":\"New York\"}]";

		List<Address> parsedAddressList = addressDataManager.parseJSONArrayAddressList(jsonString);		
		System.out.println("This is the arrayList: " + parsedAddressList);
	}
}

Run the project

mvn clean compile exec:java -Dexec.mainClass=com.test.TestActivity

You should see output like this…

JSON String: {"zip":"10010","street":"100 Main Street","state":"NY","city":"New York"}
Address Object: Address [city=New York, state=NY, street=100 Main Street, zip=10010]
[{"zip":"10010","street":"100 Main Street","state":"NY","city":"New York"},{"zip":"12345","street":"110 Main Street","state":"NY","city":"New York"},{"zip":"54321","street":"4 Chestnut Street","state":"NY","city":"New York"}]
This is the arrayList: [Address [city=New York, state=NY, street=110 Main Street, zip=12345], Address [city=New York, state=NY, street=110 Main Street, zip=12345], Address [city=New York, state=NY, street=110 Main Street, zip=12345]]

Thats all for now.




Enter your email address to subscribe to this blog and receive notifications of new posts by email.

Join 74 other followers

March 2017
S M T W T F S
« Mar    
 1234
567891011
12131415161718
19202122232425
262728293031  

Blog Stats

  • 801,397 hits