Tags: restlet
JSON Restful Web Service in Java
By MD on May 23, 2008 | In Ease Of Use | 5 feedbacks »
What kind of ways are available to get JSON Restful Web Service in Java?
Wait, what is JSON? Also Restful Web Service exactly?
Actually, I got to know them only a couple of weeks ago.
If you have tried XML Web Service with SOAP, you probably know how hard to get performance, and ease of use without complexity(especially about schema binding).
Then, JSON Restful Web Service must be what you will get interested in.
Let's go back to the first question. You can think of two providers. Sun and Apache. Here're options to go first.
In my opinion, they're just a topping on top of XML Web Service. That is the very basic mismatch. Feel free to try if you need to make sure
This is the one, with which you can get a true power of JSON Restful Web Service.
Take a look at Introduction on the site if you are not 100% sure about Restful Web Service(REST).
I'm going to show you an example to implement a service that returns DataTable compatible with one of Google Visualization API. The source of information is this thread in Google Visualization Discussion.
Code:
<CHUNK1> | |
google.visualization.Query.setResponse( | |
{ | |
requestId:'0', | |
status:'ok', | |
signature:'6173382439516707022', /* Changes when data changes */ | |
</CHUNK1> | |
So the timeseries gadget must download this JSON every so often and | |
check the new signature against it's own. If the signature is | |
different, it knows that the data on the "spreadsheet" has changed. | |
<CHUNK2> | |
table:{ | |
cols: | |
[ | |
{ | |
id:'A', | |
label:'Date', | |
type:'d', /* d=date */ | |
pattern:'M/d/yyyy' /* unique date pattern */ | |
}, | |
{ | |
id:'B', | |
label:'Budget', | |
type:'n', /* n=number */ | |
pattern:'#0.###############' /* unique number pattern */ | |
}, | |
{ | |
id:'C', | |
label:'Revenue', | |
type:'n', | |
pattern:'#0.###############' | |
}, | |
{ | |
id:'D', | |
label:'Movie', | |
type:'t', /* t=text */ | |
pattern:'' /* there is no text pattern */ | |
} | |
], | |
</CHUNK2> | |
Chunk2 shows the columns needed for a timeseries chart. (Date, | |
Value1, ..., ValueN, PopupText) | |
Note the type and pattern fields. d=date, n=number, t=text | |
<CHUNK3> | |
rows: | |
[ | |
[ | |
{ | |
v:new Date(1981,10,6), | |
f:'11/6/1981' | |
}, | |
{ | |
v:5000000.0, | |
f:'5000000' | |
}, | |
{ | |
v:4.2365581E7, | |
f:'42365581' | |
}, | |
{ | |
v:'Time Bandits' | |
} | |
], | |
</CHUNK3> |
To get this type of JSON Object is the goal. So how to do this?
In order to understand the following code, you may want to learn the tutorial how Restlet models the resource oriented Restfull world.
Restlet
Code:
import org.restlet.Application; | |
import org.restlet.Context; | |
import org.restlet.Restlet; | |
import org.restlet.Router; | |
| |
public class JSONApplication extends Application { | |
| |
public JSONApplication() { | |
super(); | |
} | |
| |
public JSONApplication(Context arg0) { | |
super(arg0); | |
} | |
| |
@Override | |
public Restlet createRoot() { | |
Router router = new Router(getContext()); | |
| |
router.attach("/table", JSONTableResource.class); | |
| |
return router; | |
} | |
| |
} |
Table Resource and JSON Representation
Code:
import org.json.JSONArray; | |
import org.json.JSONException; | |
import org.json.JSONObject; | |
import org.restlet.Context; | |
import org.restlet.data.CharacterSet; | |
import org.restlet.data.MediaType; | |
import org.restlet.data.Request; | |
import org.restlet.data.Response; | |
import org.restlet.data.Status; | |
import org.restlet.ext.json.JsonRepresentation; | |
import org.restlet.resource.Representation; | |
import org.restlet.resource.Resource; | |
import org.restlet.resource.ResourceException; | |
import org.restlet.resource.Variant; | |
| |
public class JSONTableResource extends Resource { | |
| |
private static final String JSON_NAME_TABLE = "table"; | |
| |
private static final String JSON_NAME_COLUMNS = "cols"; | |
private static final String JSON_NAME_COLUMNS_ID = "id"; | |
private static final String JSON_NAME_COLUMNS_LABEL = "label"; | |
private static final String JSON_NAME_COLUMNS_TYPE = "type"; | |
private static final String JSON_NAME_COLUMNS_PATTERN = "pattern"; | |
| |
private static final String JSON_NAME_ROWS = "rows"; | |
private static final String JSON_NAME_ROWS_V = "v"; | |
private static final String JSON_NAME_ROWS_F = "f"; | |
| |
public JSONTableResource(Context context, Request request, Response response) { | |
super(context, request, response); | |
| |
getVariants().add(new Variant(MediaType.APPLICATION_JSON)); | |
} | |
| |
@Override | |
public Representation represent(Variant variant) throws ResourceException { | |
JSONObject json = new JSONObject(); | |
| |
try { | |
| |
json.put("requestId", "0"); | |
json.put("status", "ok"); | |
json.put("signature", "6173382439516707022"); | |
| |
json.put(JSON_NAME_TABLE, this.createTable()); | |
| |
} catch (JSONException e) { | |
throw new ResourceException(Status.SERVER_ERROR_INTERNAL); | |
} | |
| |
JsonRepresentation jr = new JsonRepresentation(json); | |
| |
jr.setCharacterSet(CharacterSet.UTF_8); | |
| |
return jr; | |
} | |
| |
private JSONObject createTable() throws JSONException{ | |
JSONArray columns = new JSONArray(); | |
JSONArray rows = new JSONArray(); | |
JSONObject r_c = new JSONObject(); | |
r_c.put(JSON_NAME_COLUMNS, columns); | |
r_c.put(JSON_NAME_ROWS, rows); | |
| |
this.createColumns(columns); | |
this.createRows(rows); | |
| |
return r_c; | |
} | |
| |
private void createColumns(JSONArray columns) throws JSONException{ | |
| |
columns.put(this.createColumn("A", "Date", "d", "M/d/yyyy")); | |
columns.put(this.createColumn("B", "Budget", "n", "#0.###############")); | |
columns.put(this.createColumn("C", "Revenue", "n", "#0.###############")); | |
columns.put(this.createColumn("D", "Movie", "t", "")); | |
| |
} | |
| |
private void createRows(JSONArray rows) throws JSONException{ | |
| |
JSONArray row = new JSONArray(); | |
| |
row.put(this.createCell("new Date(1981,10,6)", "11/6/1981")); | |
row.put(this.createCell("5000000.0", "5000000")); | |
row.put(this.createCell("4.2365581E7", "42365581")); | |
row.put(this.createCell("Time Bandits", null)); | |
| |
rows.put(row); | |
| |
} | |
| |
private JSONObject createCell(String v, String f) throws JSONException{ | |
JSONObject jo = new JSONObject(); | |
jo.put(JSON_NAME_ROWS_V, v); | |
if(f != null) | |
jo.put(JSON_NAME_ROWS_F, f); | |
return jo; | |
} | |
| |
private JSONObject createColumn(String id, String label, String type, String pattern) throws JSONException{ | |
JSONObject jo = new JSONObject(); | |
jo.put(JSON_NAME_COLUMNS_ID, id); | |
jo.put(JSON_NAME_COLUMNS_LABEL, label); | |
jo.put(JSON_NAME_COLUMNS_TYPE, type); | |
jo.put(JSON_NAME_COLUMNS_PATTERN, pattern); | |
return jo; | |
} | |
| |
} |
web.xml
XML:
<?xml version="1.0" encoding="UTF-8"?> | |
<web-app id="WebApp_ID" version="2.4" | |
xmlns="http://java.sun.com/xml/ns/j2ee" | |
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee | |
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> | |
<display-name>first steps servlet</display-name> | |
<!−− Application class name −−> | |
<context-param> | |
<param-name>org.restlet.application</param-name> | |
<param-value> | |
firstSteps.JSONApplication | |
</param-value> | |
</context-param> | |
| |
<!−− Restlet adapter −−> | |
<servlet> | |
<servlet-name>RestletServlet</servlet-name> | |
<servlet-class> | |
com.noelios.restlet.ext.servlet.ServerServlet | |
</servlet-class> | |
</servlet> | |
| |
<!−− Catch all requests −−> | |
<servlet-mapping> | |
<servlet-name>RestletServlet</servlet-name> | |
<url-pattern>/json/*</url-pattern> | |
</servlet-mapping> | |
</web-app> |
You can get JSON Object in Java here.
Here's the JSON texts you'll get.
Code:
{"status":"ok","requestId":"0", | |
"table": | |
{"cols":[ | |
{"id":"A","pattern":"M/d/yyyy","label":"Date","type":"d"}, | |
{"id":"B","pattern":"#0.###############","label":"Budget","type":"n"}, | |
{"id":"C","pattern":"#0.###############","label":"Revenue","type":"n"}, | |
{"id":"D","pattern":"","label":"Movie","type":"t"} | |
], | |
"rows":[ | |
[ | |
{"f":"11/6/1981","v":"new Date(1981,10,6)"}, | |
{"f":"5000000","v":"5000000.0"}, | |
{"f":"42365581","v":"4.2365581E7"}, | |
{"v":"Time Bandits"} | |
] | |
] | |
}, | |
"signature":"6173382439516707022"} |
Then, you can call the service, get DataTable, then process to visualize. Here's an example to show a simple table in Ajax.
Code:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> | |
<html> | |
<head> | |
<script type="text/javascript"> | |
| |
var xhr; | |
try { xhr = new ActiveXObject('Msxml2.XMLHTTP'); } | |
catch (e) | |
{ | |
try { xhr = new ActiveXObject('Microsoft.XMLHTTP'); } | |
catch (e2) | |
{ | |
try { xhr = new XMLHttpRequest(); } | |
catch (e3) { xhr = false; } | |
} | |
} | |
| |
xhr.open("GET", JSON_RESTFULL_WEB_SERVICE_URL, true); | |
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); | |
xhr.send(null); | |
| |
xhr.onreadystatechange = function() | |
{ | |
if(xhr.readyState == 4) | |
{ | |
if(xhr.status == 200){ | |
the_object = eval( "(" + xhr.responseText + ")" ); | |
handleQueryResponse(the_object.table); | |
}else{ | |
| |
} | |
} | |
}; | |
| |
// Query response handler function. | |
function handleQueryResponse(table) { | |
| |
var html = []; | |
html.push('<table border="1">'); | |
| |
// Header row | |
html.push('<tr><th>Seq</th>'); | |
for (var col = 0; col < table.cols.length; col++) { | |
html.push('<th>' + escapeHtml(table.cols[col].label) + '</th>'); | |
} | |
html.push('</tr>'); | |
| |
for (var row = 0; row < table.rows.length; row++) { | |
html.push('<tr><td align="right">' + (row + 1) + '</td>'); | |
for (var col = 0; col < table.cols.length; col++) { | |
html.push(table.cols[col].type == 'number' ? '<td align="right">' : '<td>'); | |
html.push(escapeHtml(table.rows[row][col].f)); | |
html.push('</td>'); | |
} | |
html.push('</tr>'); | |
} | |
html.push('</table>'); | |
| |
document.getElementById('tablediv').innerHTML = html.join(''); | |
} | |
| |
function escapeHtml(text) { | |
if (text == null) | |
return ''; | |
| |
return text.replace(/&/g, '&') | |
.replace(/</g, '<') | |
.replace(/>/g, '>') | |
.replace(/"/g, '"'); | |
} | |
| |
</script> | |
</head> | |
| |
<body> | |
<div id="tablediv">Loading...</div> | |
</body> | |
</html> |
Simple, Fast, and Flexible. Experience JSON Restful Web Service!
REST リソースオリエンテッドな考え方
By MD on May 20, 2008 | In Database | Send feedback »
さて。
"REST"といえば?
今しばし考えてみてください。どのようなイメージを持っていますか?
- WebServiceが面倒くさいし複雑だから、端折って簡単にしたやつ?
- Ruby On Railsみたいなの?
- Ajax?
- Googleっぽい、なんでもURLでアクセスしちゃうやつ?
どうもよく分かっていないので、
まず用語の定義を探ってみましょう。
Representational State Transfer
Representational state transfer (REST) is a style of software architecture for distributed hypermedia systems such as the World Wide Web. The terms “representational state transfer” and “REST” were introduced in 2000 in the doctoral dissertation of Roy Fielding,[1] one of the principal authors of the Hypertext Transfer Protocol (HTTP) specification. The terms have since come into widespread use in the networking community.
Wikipediaではこのように紹介されています。何やら小難しいことが書いてありますが、どうやらHTTPの父が2000年に発表したアイデアのようです。
さらにこのRESTのアイデアを支えるコンセプト、Resourceについての説明が続きます。
REST's central principle: resources
An important concept in REST is the existence of resources (sources of specific information), each of which can be referred to using a global identifier (a URI).
...
For example, a resource which is a circle may accept and return a representation which specifies a center point and radius, formatted in SVG, but may also accept and return a representation which specifies any three distinct points along the curve as a comma-separated list.
「円」というのがリソースの例として挙がっていますが、”リソース”というのは、あんなものが欲しい、こんなものが欲しい、なんでもかんでもリソースと捉えることができます。問題は、それをどうやって表現するか、ですね。そこで、その表現をRepresentationと呼びます。
「円」のリソースの例で言うと、Representationとしてこんなものが挙がっています。
- 中心点と半径
- SVGフォーマット
- CSVファイル(円上の任意の3点を1レコードとする)
「円」が例に挙がっちゃったので若干困りましたが、こんな風に、リソースを、いろんな型で取れるわけです。
それで?
それでは、現実の世界にある、具体的な例を挙げてみましょう。Google Financeでトヨタ自動車という”リソース”を見てみるとこうなっています。
http://finance.google.com/finance?q=NYSE%3ATM
いろいろいじってみてみましょう。
このページでは、トヨタ自動車に関する情報を一挙にまとめています。このように、リソースは、いろんなリソースからできていることが多いです。ここ、大事です。
リソースは、いろんなリソースからできている。
役員データ、現在の株価、株価の推移、関連ニュース、どれもリソースであり、さらにそれらも、いろんなリソースからできています。
ここでいうリソースには、データベースにアクセスして取り出すデータも含まれますが、同じようにリソースとして捉えちゃいます。
つまり、リソースオリエンテッドなわけです。
これって何がすごいの?
さっきWikipediaで見たような定義自体がすごいとは思いませんが、このリソースオリエンテッドな発想、インターネットの揺籃期を生き抜いて、台頭してきていることがすごいんです。
・分かりやすい。使いやすい。
・スケーラビリティがある。
ユーザーから見ても、技術面から見ても、大変優れているわけです。
RPCではなく、リソースの交換。
ウェブの世界では、RESTfullでいきましょう。