You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pivot.apache.org by tv...@apache.org on 2009/03/16 17:16:58 UTC
svn commit: r754926 [10/38] - in /incubator/pivot/tags/v1.0: ./ charts-test/
charts-test/src/ charts-test/src/pivot/ charts-test/src/pivot/charts/
charts-test/src/pivot/charts/test/ charts/ charts/lib/ charts/src/
charts/src/pivot/ charts/src/pivot/cha...
Added: incubator/pivot/tags/v1.0/tutorials/src/pivot/tutorials/trees.wtkx
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/tutorials/src/pivot/tutorials/trees.wtkx?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/tutorials/src/pivot/tutorials/trees.wtkx (added)
+++ incubator/pivot/tags/v1.0/tutorials/src/pivot/tutorials/trees.wtkx Mon Mar 16 16:16:40 2009
@@ -0,0 +1,282 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2008 VMware, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<Border xmlns:wtkx="http://pivot.dev.java.net/wtkx/2008"
+ xmlns:content="pivot.wtk.content" xmlns="pivot.wtk">
+ <content>
+ <FlowPane styles="{padding:4, spacing:10}">
+ <FlowPane orientation="vertical">
+ <Label text="Simple" styles="{fontBold:true}"/>
+ <Border styles="{padding:0, color:10}">
+ <content>
+ <ScrollPane preferredWidth="160" preferredHeight="240"
+ horizontalScrollBarPolicy="fillToCapacity"
+ styles="{backgroundColor:null}">
+ <view>
+ <TreeView>
+ <treeData>
+ <content:TreeBranch>
+ <content:TreeBranch text="Numbers">
+ <content:TreeNode text="0"/>
+ <content:TreeNode text="1"/>
+ <content:TreeNode text="2"/>
+ <content:TreeNode text="3"/>
+ <content:TreeNode text="4"/>
+ <content:TreeNode text="5"/>
+ <content:TreeNode text="6"/>
+ <content:TreeNode text="7"/>
+ <content:TreeNode text="8"/>
+ <content:TreeNode text="9"/>
+ </content:TreeBranch>
+ <content:TreeBranch text="Letters">
+ <content:TreeNode text="A"/>
+ <content:TreeNode text="B"/>
+ <content:TreeNode text="C"/>
+ <content:TreeNode text="D"/>
+ <content:TreeNode text="E"/>
+ <content:TreeNode text="F"/>
+ <content:TreeNode text="G"/>
+ <content:TreeNode text="H"/>
+ <content:TreeNode text="I"/>
+ <content:TreeNode text="J"/>
+ <content:TreeNode text="K"/>
+ <content:TreeNode text="L"/>
+ <content:TreeNode text="M"/>
+ <content:TreeNode text="N"/>
+ <content:TreeNode text="O"/>
+ <content:TreeNode text="P"/>
+ <content:TreeNode text="Q"/>
+ <content:TreeNode text="R"/>
+ <content:TreeNode text="S"/>
+ <content:TreeNode text="T"/>
+ <content:TreeNode text="U"/>
+ <content:TreeNode text="V"/>
+ <content:TreeNode text="W"/>
+ <content:TreeNode text="X"/>
+ <content:TreeNode text="Y"/>
+ <content:TreeNode text="Z"/>
+ </content:TreeBranch>
+ </content:TreeBranch>
+ </treeData>
+ <nodeRenderer>
+ <content:TreeViewNodeRenderer showIcon="false"/>
+ </nodeRenderer>
+ </TreeView>
+ </view>
+ </ScrollPane>
+ </content>
+ </Border>
+ </FlowPane>
+
+ <FlowPane orientation="vertical">
+ <Label text="Editable" styles="{fontBold:true}"/>
+ <Border styles="{padding:0, color:10}">
+ <content>
+ <ScrollPane wtkx:id="editableTreeViewScrollPane" preferredWidth="160" preferredHeight="240"
+ horizontalScrollBarPolicy="fillToCapacity"
+ styles="{backgroundColor:null}">
+ <view>
+ <TreeView wtkx:id="editableTreeView">
+ <treeData>
+ <content:TreeBranch>
+ <content:TreeBranch text="Activity" icon="@folder.png">
+ <content:TreeBranch text="Games" icon="@folder.png">
+ <content:TreeNode text="A very long game name that just serves to show how a wide tree node behaves" icon="@page_white.png"/>
+ <content:TreeNode text="Air Hockey" icon="@page_white.png"/>
+ <content:TreeNode text="Foosball" icon="@page_white.png"/>
+ <content:TreeNode text="Ping Pong" icon="@page_white.png"/>
+ </content:TreeBranch>
+ <content:TreeBranch text="Sports" icon="@folder.png">
+ <content:TreeNode text="Baseball" icon="@page_white.png"/>
+ <content:TreeNode text="Basketball" icon="@page_white.png"/>
+ <content:TreeNode text="Football" icon="@page_white.png"/>
+ <content:TreeNode text="Ice Hockey" icon="@page_white.png"/>
+ <content:TreeNode text="Soccer" icon="@page_white.png"/>
+ <content:TreeNode text="Softball" icon="@page_white.png"/>
+ </content:TreeBranch>
+ <content:TreeNode text="Camping" icon="@page_white.png"/>
+ <content:TreeNode text="Skiing" icon="@page_white.png"/>
+ </content:TreeBranch>
+ <content:TreeBranch text="Occasion" icon="@folder.png">
+ <content:TreeBranch text="Holidays" icon="@folder.png">
+ <content:TreeNode text="Christmas" icon="@page_white.png"/>
+ <content:TreeNode text="Independence Day" icon="@page_white.png"/>
+ <content:TreeNode text="Labor Day" icon="@page_white.png"/>
+ <content:TreeNode text="New Year's Day" icon="@page_white.png"/>
+ <content:TreeNode text="President's Day" icon="@page_white.png"/>
+ <content:TreeNode text="Thanksgiving" icon="@page_white.png"/>
+ <content:TreeNode text="Valentine's Day" icon="@page_white.png"/>
+ <content:TreeNode text="Veteran's Day" icon="@page_white.png"/>
+ </content:TreeBranch>
+ <content:TreeNode text="Anniversary" icon="@page_white.png"/>
+ <content:TreeNode text="Birthday" icon="@page_white.png"/>
+ <content:TreeNode text="Wedding" icon="@page_white.png"/>
+ </content:TreeBranch>
+ <content:TreeBranch text="Location" icon="@folder.png">
+ <content:TreeNode text="Africa" icon="@folder.png"/>
+ <content:TreeNode text="Antarctica" icon="@folder.png"/>
+ <content:TreeNode text="Asia" icon="@folder.png"/>
+ <content:TreeNode text="Australia" icon="@folder.png"/>
+ <content:TreeNode text="Europe" icon="@folder.png"/>
+ <content:TreeNode text="North America" icon="@folder.png"/>
+ <content:TreeBranch text="South America" icon="@folder.png">
+ <content:TreeNode text="Peru" icon="@page_white.png"/>
+ </content:TreeBranch>
+ </content:TreeBranch>
+ </content:TreeBranch>
+ </treeData>
+ <nodeRenderer>
+ <content:TreeViewNodeRenderer showIcon="true"/>
+ </nodeRenderer>
+ </TreeView>
+ </view>
+ </ScrollPane>
+ </content>
+ </Border>
+ </FlowPane>
+
+ <FlowPane orientation="vertical">
+ <Label text="Multi-Select" styles="{fontBold:true}"/>
+ <Border styles="{padding:0, color:10}">
+ <content>
+ <ScrollPane preferredWidth="160" preferredHeight="240"
+ horizontalScrollBarPolicy="fillToCapacity"
+ styles="{backgroundColor:null}">
+ <view>
+ <TreeView selectMode="multi">
+ <treeData>
+ <content:TreeBranch>
+ <content:TreeBranch text="Africa" icon="@folder.png"/>
+ <content:TreeBranch text="Antarctica" icon="@folder.png"/>
+ <content:TreeBranch text="Asia" icon="@folder.png"/>
+ <content:TreeBranch text="Australia" icon="@folder.png"/>
+ <content:TreeBranch text="Europe" icon="@folder.png">
+ <content:TreeNode text="Albania" icon="@page_white.png"/>
+ <content:TreeNode text="Andorra" icon="@page_white.png"/>
+ <content:TreeNode text="Armenia" icon="@page_white.png"/>
+ <content:TreeNode text="Austria" icon="@page_white.png"/>
+ <content:TreeNode text="Azerbaijan" icon="@page_white.png"/>
+ <content:TreeNode text="Belarus" icon="@page_white.png"/>
+ <content:TreeNode text="Belgium" icon="@page_white.png"/>
+ <content:TreeNode text="Bosnia and Herzegovina" icon="@page_white.png"/>
+ <content:TreeNode text="Bulgaria" icon="@page_white.png"/>
+ <content:TreeNode text="Croatia" icon="@page_white.png"/>
+ <content:TreeNode text="Cyprus" icon="@page_white.png"/>
+ <content:TreeNode text="Czech Republic" icon="@page_white.png"/>
+ <content:TreeNode text="Denmark" icon="@page_white.png"/>
+ <content:TreeNode text="Estonia" icon="@page_white.png"/>
+ <content:TreeNode text="Finland" icon="@page_white.png"/>
+ <content:TreeNode text="Former Yugoslav Republic of Macedonia" icon="@page_white.png"/>
+ <content:TreeNode text="France" icon="@page_white.png"/>
+ <content:TreeNode text="Georgia" icon="@page_white.png"/>
+ <content:TreeNode text="Germany" icon="@page_white.png"/>
+ <content:TreeNode text="Greece" icon="@page_white.png"/>
+ <content:TreeNode text="Hungary" icon="@page_white.png"/>
+ <content:TreeNode text="Iceland" icon="@page_white.png"/>
+ <content:TreeNode text="Ireland" icon="@page_white.png"/>
+ <content:TreeNode text="Italy" icon="@page_white.png"/>
+ <content:TreeNode text="Latvia" icon="@page_white.png"/>
+ <content:TreeNode text="Liechtenstein" icon="@page_white.png"/>
+ <content:TreeNode text="Lithuania" icon="@page_white.png"/>
+ <content:TreeNode text="Luxembourg" icon="@page_white.png"/>
+ <content:TreeNode text="Malta" icon="@page_white.png"/>
+ <content:TreeNode text="Moldova" icon="@page_white.png"/>
+ <content:TreeNode text="Monaco" icon="@page_white.png"/>
+ <content:TreeNode text="Montenegro" icon="@page_white.png"/>
+ <content:TreeNode text="Netherlands" icon="@page_white.png"/>
+ <content:TreeNode text="Norway" icon="@page_white.png"/>
+ <content:TreeNode text="Poland" icon="@page_white.png"/>
+ <content:TreeNode text="Portugal" icon="@page_white.png"/>
+ <content:TreeNode text="Romania" icon="@page_white.png"/>
+ <content:TreeNode text="Russia" icon="@page_white.png"/>
+ <content:TreeNode text="San Marino" icon="@page_white.png"/>
+ <content:TreeNode text="Serbia" icon="@page_white.png"/>
+ <content:TreeNode text="Slovakia" icon="@page_white.png"/>
+ <content:TreeNode text="Slovenia" icon="@page_white.png"/>
+ <content:TreeNode text="Spain" icon="@page_white.png"/>
+ <content:TreeNode text="Sweden" icon="@page_white.png"/>
+ <content:TreeNode text="Switzerland" icon="@page_white.png"/>
+ <content:TreeNode text="Turkey" icon="@page_white.png"/>
+ <content:TreeNode text="Ukraine" icon="@page_white.png"/>
+ <content:TreeNode text="United Kingdom" icon="@page_white.png"/>
+ <content:TreeNode text="Vatican City State" icon="@page_white.png"/>
+ </content:TreeBranch>
+ <content:TreeBranch text="North America" icon="@folder.png">
+ <content:TreeNode text="Alabama" icon="@page_white.png"/>
+ <content:TreeNode text="Alaska" icon="@page_white.png"/>
+ <content:TreeNode text="Arizona" icon="@page_white.png"/>
+ <content:TreeNode text="Arkansas" icon="@page_white.png"/>
+ <content:TreeNode text="California" icon="@page_white.png"/>
+ <content:TreeNode text="Colorado" icon="@page_white.png"/>
+ <content:TreeNode text="Connecticut" icon="@page_white.png"/>
+ <content:TreeNode text="Delaware" icon="@page_white.png"/>
+ <content:TreeNode text="District of Columbia" icon="@page_white.png"/>
+ <content:TreeNode text="Florida" icon="@page_white.png"/>
+ <content:TreeNode text="Georgia" icon="@page_white.png"/>
+ <content:TreeNode text="Hawaii" icon="@page_white.png"/>
+ <content:TreeNode text="Idaho" icon="@page_white.png"/>
+ <content:TreeNode text="Illinois" icon="@page_white.png"/>
+ <content:TreeNode text="Indiana" icon="@page_white.png"/>
+ <content:TreeNode text="Iowa" icon="@page_white.png"/>
+ <content:TreeNode text="Kansas" icon="@page_white.png"/>
+ <content:TreeNode text="Kentucky" icon="@page_white.png"/>
+ <content:TreeNode text="Louisiana" icon="@page_white.png"/>
+ <content:TreeNode text="Maine" icon="@page_white.png"/>
+ <content:TreeNode text="Maryland" icon="@page_white.png"/>
+ <content:TreeNode text="Massachusetts" icon="@page_white.png"/>
+ <content:TreeNode text="Michigan" icon="@page_white.png"/>
+ <content:TreeNode text="Minnesota" icon="@page_white.png"/>
+ <content:TreeNode text="Mississippi" icon="@page_white.png"/>
+ <content:TreeNode text="Missouri" icon="@page_white.png"/>
+ <content:TreeNode text="Montana" icon="@page_white.png"/>
+ <content:TreeNode text="Nebraska" icon="@page_white.png"/>
+ <content:TreeNode text="Nevada" icon="@page_white.png"/>
+ <content:TreeNode text="New Hampshire" icon="@page_white.png"/>
+ <content:TreeNode text="New Jersey" icon="@page_white.png"/>
+ <content:TreeNode text="New Mexico" icon="@page_white.png"/>
+ <content:TreeNode text="New York" icon="@page_white.png"/>
+ <content:TreeNode text="North Carolina" icon="@page_white.png"/>
+ <content:TreeNode text="North Dakota" icon="@page_white.png"/>
+ <content:TreeNode text="Ohio" icon="@page_white.png"/>
+ <content:TreeNode text="Oklahoma" icon="@page_white.png"/>
+ <content:TreeNode text="Oregon" icon="@page_white.png"/>
+ <content:TreeNode text="Pennsylvania" icon="@page_white.png"/>
+ <content:TreeNode text="Rhode Island" icon="@page_white.png"/>
+ <content:TreeNode text="South Carolina" icon="@page_white.png"/>
+ <content:TreeNode text="South Dakota" icon="@page_white.png"/>
+ <content:TreeNode text="Tennessee" icon="@page_white.png"/>
+ <content:TreeNode text="Texas" icon="@page_white.png"/>
+ <content:TreeNode text="Utah" icon="@page_white.png"/>
+ <content:TreeNode text="Vermont" icon="@page_white.png"/>
+ <content:TreeNode text="Virginia" icon="@page_white.png"/>
+ <content:TreeNode text="Washington" icon="@page_white.png"/>
+ <content:TreeNode text="West Virginia" icon="@page_white.png"/>
+ <content:TreeNode text="Wisconsin" icon="@page_white.png"/>
+ <content:TreeNode text="Wyoming" icon="@page_white.png"/>
+ </content:TreeBranch>
+ <content:TreeBranch text="South America" icon="@folder.png"/>
+ </content:TreeBranch>
+ </treeData>
+ </TreeView>
+ </view>
+ </ScrollPane>
+ </content>
+ </Border>
+ </FlowPane>
+ </FlowPane>
+ </content>
+</Border>
Added: incubator/pivot/tags/v1.0/tutorials/src/pivot/tutorials/weather-few-clouds.png
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/tutorials/src/pivot/tutorials/weather-few-clouds.png?rev=754926&view=auto
==============================================================================
Binary file - no diff available.
Propchange: incubator/pivot/tags/v1.0/tutorials/src/pivot/tutorials/weather-few-clouds.png
------------------------------------------------------------------------------
svn:mime-type = application/octet-stream
Added: incubator/pivot/tags/v1.0/tutorials/src/pivot/tutorials/x-office-document.png
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/tutorials/src/pivot/tutorials/x-office-document.png?rev=754926&view=auto
==============================================================================
Binary file - no diff available.
Propchange: incubator/pivot/tags/v1.0/tutorials/src/pivot/tutorials/x-office-document.png
------------------------------------------------------------------------------
svn:mime-type = application/octet-stream
Added: incubator/pivot/tags/v1.0/web-test/.classpath
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/web-test/.classpath?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/web-test/.classpath (added)
+++ incubator/pivot/tags/v1.0/web-test/.classpath Mon Mar 16 16:16:40 2009
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/core"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/web"/>
+ <classpathentry kind="lib" path="/web/lib/servlet-api.jar"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
Added: incubator/pivot/tags/v1.0/web-test/.project
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/web-test/.project?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/web-test/.project (added)
+++ incubator/pivot/tags/v1.0/web-test/.project Mon Mar 16 16:16:40 2009
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>web-test</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
Added: incubator/pivot/tags/v1.0/web-test/src/pivot/web/test/WebQueryTestClient.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/web-test/src/pivot/web/test/WebQueryTestClient.java?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/web-test/src/pivot/web/test/WebQueryTestClient.java (added)
+++ incubator/pivot/tags/v1.0/web-test/src/pivot/web/test/WebQueryTestClient.java Mon Mar 16 16:16:40 2009
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2008 VMware, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pivot.web.test;
+
+import java.net.URL;
+
+import pivot.collections.Dictionary;
+import pivot.serialization.BinarySerializer;
+import pivot.serialization.JSONSerializer;
+import pivot.util.concurrent.Task;
+import pivot.util.concurrent.TaskListener;
+import pivot.web.BasicAuthentication;
+import pivot.web.GetQuery;
+import pivot.web.DeleteQuery;
+import pivot.web.PostQuery;
+import pivot.web.PutQuery;
+
+public class WebQueryTestClient {
+ public static void main(String[] args) {
+ final boolean useProxy = true;
+
+ final String HOSTNAME = "localhost";
+ final String PATH = (useProxy ? "/pivot_web_test/proxy" : "/pivot_web_test/webquery") + "/bar/quux";
+ final int PORT = 8080;
+ final boolean SECURE = false;
+
+ BasicAuthentication authentication = new BasicAuthentication("foo", "bar");
+
+ // GET
+ GetQuery getQuery = new GetQuery(HOSTNAME, PORT, PATH, SECURE);
+ getQuery.getArguments().put("a", "b");
+ getQuery.setSerializer(new BinarySerializer());
+ authentication.authenticate(getQuery);
+
+ getQuery.execute(new TaskListener<Object>() {
+ @SuppressWarnings("unchecked")
+ public void taskExecuted(Task<Object> task) {
+ Dictionary<String, Object> result = (Dictionary<String, Object>)task.getResult();
+
+ System.out.println("GET result: "
+ + "username: " + result.get("username") + ", "
+ + "pathInfo: " + result.get("pathInfo") + ", "
+ + "queryString: " + result.get("queryString"));
+ }
+
+ public void executeFailed(Task<Object> task) {
+ System.out.println("GET fault: " + task.getFault());
+ }
+ });
+
+ // POST
+ PostQuery postQuery = new PostQuery(HOSTNAME, PORT, PATH, SECURE);
+ authentication.authenticate(postQuery);
+ postQuery.setValue(JSONSerializer.parseList("[1, 2, 3]"));
+
+ postQuery.execute(new TaskListener<URL>() {
+ public void taskExecuted(Task<URL> task) {
+ System.out.println("POST result: " + task.getResult());
+ }
+
+ public void executeFailed(Task<URL> task) {
+ System.out.println("POST fault: " + task.getFault());
+ }
+ });
+
+ // PUT
+ PutQuery putQuery = new PutQuery(HOSTNAME, PORT, PATH, SECURE);
+ authentication.authenticate(putQuery);
+ putQuery.setValue(JSONSerializer.parseMap("{a:100, b:200, c:300}"));
+
+ putQuery.execute(new TaskListener<Void>() {
+ public void taskExecuted(Task<Void> task) {
+ System.out.println("PUT result");
+ }
+
+ public void executeFailed(Task<Void> task) {
+ System.out.println("PUT fault: " + task.getFault());
+ }
+ });
+
+ // POST
+ DeleteQuery deleteQuery = new DeleteQuery(HOSTNAME, PORT, PATH, SECURE);
+ authentication.authenticate(deleteQuery);
+
+ deleteQuery.execute(new TaskListener<Void>() {
+ public void taskExecuted(Task<Void> task) {
+ System.out.println("DELETE result");
+ }
+
+ public void executeFailed(Task<Void> task) {
+ System.out.println("DELETE fault: " + task.getFault());
+ }
+ });
+
+ // Wait for the async. calls to complete
+ try {
+ Thread.sleep(10000);
+ } catch(InterruptedException exception) {
+ }
+ }
+}
Added: incubator/pivot/tags/v1.0/web-test/src/pivot/web/test/server/WebQueryTestServlet.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/web-test/src/pivot/web/test/server/WebQueryTestServlet.java?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/web-test/src/pivot/web/test/server/WebQueryTestServlet.java (added)
+++ incubator/pivot/tags/v1.0/web-test/src/pivot/web/test/server/WebQueryTestServlet.java Mon Mar 16 16:16:40 2009
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2008 VMware, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pivot.web.test.server;
+
+import java.io.IOException;
+import javax.servlet.ServletInputStream;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import pivot.collections.HashMap;
+import pivot.serialization.BinarySerializer;
+import pivot.serialization.JSONSerializer;
+import pivot.serialization.SerializationException;
+import pivot.serialization.Serializer;
+import pivot.util.Base64;
+
+public class WebQueryTestServlet extends HttpServlet {
+ public static final long serialVersionUID = 0;
+
+ private String username = null;
+ private static final String BASIC_AUTHENTICATION_TAG = "Basic";
+
+ @Override
+ public void init(ServletConfig config) {
+ }
+
+ @Override
+ public void destroy() {
+ }
+
+ @Override
+ protected void service(HttpServletRequest request, HttpServletResponse response)
+ throws IOException, ServletException {
+ String authorization = request.getHeader("Authorization");
+
+ if (authorization == null) {
+ response.setHeader("WWW-Authenticate", "BASIC realm=\""
+ + request.getServletPath() +"\"");
+ response.setStatus(401);
+ response.setContentLength(0);
+ response.flushBuffer();
+ } else {
+ String encodedCredentials = authorization.substring(BASIC_AUTHENTICATION_TAG.length() + 1);
+
+ String decodedCredentials = new String(Base64.decode(encodedCredentials));
+ String[] credentials = decodedCredentials.split(":");
+ username = credentials[0];
+
+ // TODO Parse query string
+
+ super.service(request, response);
+ }
+ }
+
+ @Override
+ protected void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws IOException, ServletException {
+ String pathInfo = request.getPathInfo();
+ String queryString = request.getQueryString();
+
+ HashMap<String, Object> map = new HashMap<String, Object>();
+ map.put("username", username);
+ map.put("pathInfo", pathInfo);
+ map.put("queryString", queryString);
+
+ response.setStatus(200);
+
+ Serializer serializer = new BinarySerializer();
+ response.setContentType(serializer.getMIMEType());
+
+ try {
+ serializer.writeObject(map, response.getOutputStream());
+ } catch(SerializationException exception) {
+ throw new ServletException(exception);
+ }
+ }
+
+ @Override
+ protected void doPost(HttpServletRequest request, HttpServletResponse response)
+ throws IOException, ServletException {
+ ServletInputStream inputStream = request.getInputStream();
+ JSONSerializer jsonSerializer = new JSONSerializer();
+
+ try {
+ Object value = jsonSerializer.readObject(inputStream);
+ jsonSerializer.writeObject(value, System.out);
+ response.setStatus(201);
+ response.setHeader("Location", request.getPathInfo() +"#101");
+ } catch(SerializationException exception) {
+ throw new ServletException(exception);
+ }
+
+ response.setContentLength(0);
+ response.flushBuffer();
+ }
+
+ @Override
+ protected void doPut(HttpServletRequest request, HttpServletResponse response)
+ throws IOException, ServletException {
+ ServletInputStream inputStream = request.getInputStream();
+ JSONSerializer jsonSerializer = new JSONSerializer();
+
+ try {
+ Object value = jsonSerializer.readObject(inputStream);
+ jsonSerializer.writeObject(value, System.out);
+ response.setStatus(200);
+ } catch(SerializationException exception) {
+ throw new ServletException(exception);
+ }
+
+ response.setContentLength(0);
+ response.flushBuffer();
+ }
+
+ @Override
+ protected void doDelete(HttpServletRequest request, HttpServletResponse response)
+ throws IOException, ServletException {
+ response.setStatus(200);
+ response.setContentLength(0);
+ response.flushBuffer();
+ }
+}
Added: incubator/pivot/tags/v1.0/web-test/web.xml
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/web-test/web.xml?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/web-test/web.xml (added)
+++ incubator/pivot/tags/v1.0/web-test/web.xml Mon Mar 16 16:16:40 2009
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+
+<web-app 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"
+ version="2.4">
+ <description>Pivot Web Query Test</description>
+ <display-name>Pivot Web Query Test</display-name>
+
+ <servlet>
+ <servlet-name>WebQueryTestServlet</servlet-name>
+ <servlet-class>pivot.web.test.server.WebQueryTestServlet</servlet-class>
+ </servlet>
+
+ <servlet>
+ <servlet-name>ProxyServlet</servlet-name>
+ <servlet-class>pivot.web.server.ProxyServlet</servlet-class>
+ <init-param>
+ <param-name>hostname</param-name>
+ <param-value>localhost</param-value>
+ </init-param>
+ <init-param>
+ <param-name>port</param-name>
+ <param-value>8080</param-value>
+ </init-param>
+ <init-param>
+ <param-name>path</param-name>
+ <param-value>/pivot_web_test/webquery</param-value>
+ </init-param>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>WebQueryTestServlet</servlet-name>
+ <url-pattern>/webquery/*</url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name>ProxyServlet</servlet-name>
+ <url-pattern>/proxy/*</url-pattern>
+ </servlet-mapping>
+</web-app>
+
Added: incubator/pivot/tags/v1.0/web/.classpath
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/web/.classpath?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/web/.classpath (added)
+++ incubator/pivot/tags/v1.0/web/.classpath Mon Mar 16 16:16:40 2009
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/core"/>
+ <classpathentry kind="lib" path="lib/servlet-api.jar"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
Added: incubator/pivot/tags/v1.0/web/.project
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/web/.project?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/web/.project (added)
+++ incubator/pivot/tags/v1.0/web/.project Mon Mar 16 16:16:40 2009
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>web</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
Added: incubator/pivot/tags/v1.0/web/lib/servlet-api.jar
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/web/lib/servlet-api.jar?rev=754926&view=auto
==============================================================================
Binary file - no diff available.
Propchange: incubator/pivot/tags/v1.0/web/lib/servlet-api.jar
------------------------------------------------------------------------------
svn:mime-type = application/octet-stream
Added: incubator/pivot/tags/v1.0/web/src/pivot/web/Authentication.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/web/src/pivot/web/Authentication.java?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/web/src/pivot/web/Authentication.java (added)
+++ incubator/pivot/tags/v1.0/web/src/pivot/web/Authentication.java Mon Mar 16 16:16:40 2009
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2008 VMware, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pivot.web;
+
+/**
+ * Interface for attaching authentication information to a web query.
+ *
+ * @author gbrown
+ */
+public interface Authentication {
+ public void authenticate(Query<?> query);
+}
Added: incubator/pivot/tags/v1.0/web/src/pivot/web/BasicAuthentication.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/web/src/pivot/web/BasicAuthentication.java?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/web/src/pivot/web/BasicAuthentication.java (added)
+++ incubator/pivot/tags/v1.0/web/src/pivot/web/BasicAuthentication.java Mon Mar 16 16:16:40 2009
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2008 VMware, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pivot.web;
+
+import pivot.util.Base64;
+
+/**
+ * Implementation of the {@link Authentication} interface supporting the
+ * HTTP <a href="http://tools.ietf.org/rfc/rfc2617.txt">Basic
+ * Authentication</a> scheme.
+ */
+public class BasicAuthentication implements Authentication {
+ private String username = null;
+ private String password = null;
+
+ public BasicAuthentication(String username, String password) {
+ this.username = (username == null) ? "" : username;
+ this.password = (password == null) ? "" : password;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void authenticate(Query<?> query) {
+ String credentials = username + ":" + password;
+ String encodedCredentials = Base64.encode(credentials.getBytes());
+
+ query.getRequestProperties().put("Authorization", "Basic " + encodedCredentials);
+ }
+}
Added: incubator/pivot/tags/v1.0/web/src/pivot/web/DeleteQuery.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/web/src/pivot/web/DeleteQuery.java?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/web/src/pivot/web/DeleteQuery.java (added)
+++ incubator/pivot/tags/v1.0/web/src/pivot/web/DeleteQuery.java Mon Mar 16 16:16:40 2009
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2008 VMware, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pivot.web;
+
+/**
+ * Executes an HTTP DELETE operation.
+ *
+ * @author gbrown
+ */
+public class DeleteQuery extends Query<Void> {
+ public DeleteQuery(String hostname, String path) {
+ this(hostname, DEFAULT_PORT, path, false);
+ }
+
+ public DeleteQuery(String hostname, int port, String path, boolean secure) {
+ super(hostname, port, path, secure);
+ }
+
+ /**
+ * Synchronously executes the DELETE operation.
+ */
+ @Override
+ public Void execute() throws QueryException {
+ execute(Method.DELETE, null);
+ return null;
+ }
+}
Added: incubator/pivot/tags/v1.0/web/src/pivot/web/GetQuery.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/web/src/pivot/web/GetQuery.java?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/web/src/pivot/web/GetQuery.java (added)
+++ incubator/pivot/tags/v1.0/web/src/pivot/web/GetQuery.java Mon Mar 16 16:16:40 2009
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2008 VMware, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pivot.web;
+
+/**
+ * Executes an HTTP GET operation.
+ *
+ * @author gbrown
+ */
+public class GetQuery extends Query<Object> {
+ public GetQuery(String hostname, String path) {
+ this(hostname, DEFAULT_PORT, path, false);
+ }
+
+ public GetQuery(String hostname, int port, String path, boolean secure) {
+ super(hostname, port, path, secure);
+ }
+
+ /**
+ * Synchronously executes the GET operation.
+ *
+ * @return
+ * The result of the operation, deserialized using the query's serializer.
+ */
+ @Override
+ public Object execute() throws QueryException {
+ return execute(Method.GET, null);
+ }
+}
Added: incubator/pivot/tags/v1.0/web/src/pivot/web/PostQuery.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/web/src/pivot/web/PostQuery.java?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/web/src/pivot/web/PostQuery.java (added)
+++ incubator/pivot/tags/v1.0/web/src/pivot/web/PostQuery.java Mon Mar 16 16:16:40 2009
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2008 VMware, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pivot.web;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+/**
+ * Executes an HTTP POST operation.
+ *
+ * @author gbrown
+ */
+public class PostQuery extends Query<URL> {
+ private Object value = null;
+
+ public PostQuery(String hostname, String path) {
+ this(hostname, DEFAULT_PORT, path, false);
+ }
+
+ public PostQuery(String hostname, int port, String path, boolean secure) {
+ super(hostname, port, path, secure);
+ }
+
+ /**
+ * Returns the value that will be POSTed to the server when the query is
+ * executed.
+ */
+ public Object getValue() {
+ return value;
+ }
+
+ /**
+ * Sets the value that will be POSTed to the server when the query is
+ * executed.
+ *
+ * @param value
+ * The value to POST to the server.
+ */
+ public void setValue(Object value) {
+ this.value = value;
+ }
+
+ /**
+ * Synchronously executes the POST operation.
+ *
+ * @return
+ * A URL that uniquely identifies the location of the resource created
+ * on the server by the operation, or <tt>null</tt> if the server did
+ * not return a location.
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public URL execute() throws QueryException {
+ URL valueLocation = null;
+
+ execute(Method.POST, value);
+
+ String location = getResponseProperties().get("Location");
+ if (location != null) {
+ try {
+ valueLocation = new URL(getLocation(), location);
+ } catch(MalformedURLException exception) {
+ }
+ }
+
+ return valueLocation;
+ }
+}
Added: incubator/pivot/tags/v1.0/web/src/pivot/web/PutQuery.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/web/src/pivot/web/PutQuery.java?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/web/src/pivot/web/PutQuery.java (added)
+++ incubator/pivot/tags/v1.0/web/src/pivot/web/PutQuery.java Mon Mar 16 16:16:40 2009
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2008 VMware, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pivot.web;
+
+/**
+ * Executes an HTTP PUT operation.
+ *
+ * @author gbrown
+ */
+public class PutQuery extends Query<Void> {
+ private Object value = null;
+
+ public PutQuery(String hostname, String path) {
+ this(hostname, DEFAULT_PORT, path, false);
+ }
+
+ public PutQuery(String hostname, int port, String path, boolean secure) {
+ super(hostname, port, path, secure);
+ }
+
+ /**
+ * Returns the value that will be PUT to the server when the query is
+ * executed.
+ */
+ public Object getValue() {
+ return value;
+ }
+
+ /**
+ * Sets the value that will be PUT to the server when the query is
+ * executed.
+ *
+ * @param value
+ * The value to PUT to the server.
+ */
+ public void setValue(Object value) {
+ this.value = value;
+ }
+
+ /**
+ * Synchronously executes the PUT operation.
+ */
+ @Override
+ public Void execute() throws QueryException {
+ execute(Method.PUT, value);
+ return null;
+ }
+}
Added: incubator/pivot/tags/v1.0/web/src/pivot/web/Query.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/web/src/pivot/web/Query.java?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/web/src/pivot/web/Query.java (added)
+++ incubator/pivot/tags/v1.0/web/src/pivot/web/Query.java Mon Mar 16 16:16:40 2009
@@ -0,0 +1,636 @@
+/*
+ * Copyright (c) 2008 VMware, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pivot.web;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.util.Iterator;
+
+import pivot.collections.Dictionary;
+import pivot.collections.HashMap;
+import pivot.serialization.JSONSerializer;
+import pivot.serialization.Serializer;
+import pivot.util.ListenerList;
+import pivot.util.concurrent.AbortException;
+import pivot.util.concurrent.Dispatcher;
+import pivot.util.concurrent.SynchronizedListenerList;
+import pivot.util.concurrent.Task;
+
+/**
+ * Abstract base class for web queries. A web query is an asynchronous
+ * operation that executes one of the following HTTP methods:
+ *
+ * <ul>
+ * <li>GET</li>
+ * <li>POST</li>
+ * <li>PUT</li>
+ * <li>DELETE</li>
+ * </ul>
+ *
+ * @param <V>
+ * The type of the value retrieved or sent via the query. For GET operations,
+ * it is {@link Object}; for POST operations, the type is {@link URL}. For PUT
+ * and DELETE, it is {@link Void}.
+ *
+ * @author gbrown
+ * @author tvolkert
+ */
+public abstract class Query<V> extends Task<V> {
+ /**
+ * The supported HTTP methods.
+ *
+ * @author gbrown
+ */
+ protected enum Method {
+ GET,
+ POST,
+ PUT,
+ DELETE
+ }
+
+ /**
+ * Arguments dictionary implementation.
+ */
+ public final class ArgumentsDictionary
+ implements Dictionary<String, String>, Iterable<String> {
+ public String get(String key) {
+ return arguments.get(key);
+ }
+
+ public String put(String key, String value) {
+ return arguments.put(key, value);
+ }
+
+ public String remove(String key) {
+ return arguments.remove(key);
+ }
+
+ public boolean containsKey(String key) {
+ return arguments.containsKey(key);
+ }
+
+ public boolean isEmpty() {
+ return arguments.isEmpty();
+ }
+
+ public Iterator<String> iterator() {
+ return arguments.iterator();
+ }
+ }
+
+ /**
+ * Request properties dictionary implementation.
+ */
+ public final class RequestPropertiesDictionary
+ implements Dictionary<String, String>, Iterable<String> {
+ public String get(String key) {
+ return requestProperties.get(key);
+ }
+
+ public String put(String key, String value) {
+ return requestProperties.put(key, value);
+ }
+
+ public String remove(String key) {
+ return requestProperties.remove(key);
+ }
+
+ public boolean containsKey(String key) {
+ return requestProperties.containsKey(key);
+ }
+
+ public boolean isEmpty() {
+ return requestProperties.isEmpty();
+ }
+
+ public Iterator<String> iterator() {
+ return requestProperties.iterator();
+ }
+ }
+
+ /**
+ * Response properties dictionary implementation.
+ */
+ public final class ResponsePropertiesDictionary
+ implements Dictionary<String, String>, Iterable<String> {
+ public String get(String key) {
+ return responseProperties.get(key);
+ }
+
+ public String put(String key, String value) {
+ throw new UnsupportedOperationException();
+ }
+
+ public String remove(String key) {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean containsKey(String key) {
+ return responseProperties.containsKey(key);
+ }
+
+ public boolean isEmpty() {
+ return responseProperties.isEmpty();
+ }
+
+ public Iterator<String> iterator() {
+ return responseProperties.iterator();
+ }
+ }
+
+ /**
+ * Output stream that monitors the bytes that are written to it by
+ * incrementing the <tt>bytesSent</tt> member variable.
+ *
+ * @author tvolkert
+ */
+ private class MonitoredOutputStream extends OutputStream {
+ private OutputStream outputStream;
+
+ public MonitoredOutputStream(OutputStream outputStream) {
+ this.outputStream = outputStream;
+ }
+
+ public void close() throws IOException {
+ outputStream.close();
+ }
+
+ public void flush() throws IOException {
+ if (abort) {
+ throw new AbortException();
+ }
+
+ outputStream.flush();
+ }
+
+ public void write(byte[] b) throws IOException {
+ if (abort) {
+ throw new AbortException();
+ }
+
+ outputStream.write(b);
+ bytesSent += b.length;
+ }
+
+ public void write(byte[] b, int off, int len) throws IOException {
+ if (abort) {
+ throw new AbortException();
+ }
+
+ outputStream.write(b, off, len);
+ bytesSent += len;
+ }
+
+ public void write(int b) throws IOException {
+ if (abort) {
+ throw new AbortException();
+ }
+
+ outputStream.write(b);
+ bytesSent++;
+ }
+ }
+
+ /**
+ * Input stream that monitors the bytes that are read from it by
+ * incrementing the <tt>bytesReceived</tt> member variable.
+ *
+ * @author tvolkert
+ */
+ private class MonitoredInputStream extends InputStream {
+ private InputStream inputStream;
+
+ long mark = 0;
+
+ public MonitoredInputStream(InputStream inputStream) {
+ this.inputStream = inputStream;
+ }
+
+ public int read() throws IOException {
+ if (abort) {
+ throw new AbortException();
+ }
+
+ int result = inputStream.read();
+
+ if (result != -1) {
+ bytesReceived++;
+ }
+
+ return result;
+ }
+
+ public int read(byte b[]) throws IOException {
+ if (abort) {
+ throw new AbortException();
+ }
+
+ int count = inputStream.read(b);
+
+ if (count != -1) {
+ bytesReceived += count;
+ }
+
+ return count;
+ }
+
+ public int read(byte b[], int off, int len) throws IOException {
+ if (abort) {
+ throw new AbortException();
+ }
+
+ int count = inputStream.read(b, off, len);
+
+ if (count != -1) {
+ bytesReceived += count;
+ }
+
+ return count;
+ }
+
+ public long skip(long n) throws IOException {
+ if (abort) {
+ throw new AbortException();
+ }
+
+ long count = inputStream.skip(n);
+ bytesReceived += count;
+ return count;
+ }
+
+ public int available() throws IOException {
+ if (abort) {
+ throw new AbortException();
+ }
+
+ return inputStream.available();
+ }
+
+ public void close() throws IOException {
+ inputStream.close();
+ }
+
+ public void mark(int readLimit) {
+ if (abort) {
+ throw new AbortException();
+ }
+
+ inputStream.mark(readLimit);
+ mark = bytesReceived;
+ }
+
+ public void reset() throws IOException {
+ if (abort) {
+ throw new AbortException();
+ }
+
+ inputStream.reset();
+ bytesReceived = mark;
+ }
+
+ public boolean markSupported() {
+ return inputStream.markSupported();
+ }
+ }
+
+ /**
+ * Query listener list.
+ *
+ * @author tvolkert
+ */
+ private static class QueryListenerList<V> extends SynchronizedListenerList<QueryListener<V>>
+ implements QueryListener<V> {
+ public synchronized void connected(Query<V> query) {
+ for (QueryListener<V> listener : this) {
+ listener.connected(query);
+ }
+ }
+
+ public synchronized void requestSent(Query<V> query) {
+ for (QueryListener<V> listener : this) {
+ listener.requestSent(query);
+ }
+ }
+
+ public synchronized void responseReceived(Query<V> query) {
+ for (QueryListener<V> listener : this) {
+ listener.responseReceived(query);
+ }
+ }
+
+ public synchronized void failed(Query<V> query) {
+ for (QueryListener<V> listener : this) {
+ listener.failed(query);
+ }
+ }
+ }
+
+ private URL locationContext = null;
+
+ private HashMap<String, String> arguments = new HashMap<String, String>();
+ private HashMap<String, String> requestProperties = new HashMap<String, String>();
+ private HashMap<String, String> responseProperties = new HashMap<String, String>();
+
+ private ArgumentsDictionary argumentsDictionary = new ArgumentsDictionary();
+ private RequestPropertiesDictionary requestPropertiesDictionary = new RequestPropertiesDictionary();
+ private ResponsePropertiesDictionary responsePropertiesDictionary = new ResponsePropertiesDictionary();
+
+ private Serializer serializer = new JSONSerializer();
+
+ private volatile long bytesSent = 0;
+ private volatile long bytesReceived = 0;
+ private volatile long bytesExpected = -1;
+
+ private QueryListenerList<V> queryListeners = new QueryListenerList<V>();
+
+ private static Dispatcher DEFAULT_DISPATCHER = new Dispatcher();
+
+ public static final int DEFAULT_PORT = -1;
+
+ private static final String HTTP_PROTOCOL = "http";
+ private static final String HTTPS_PROTOCOL = "https";
+ private static final String URL_ENCODING = "UTF-8";
+
+ /**
+ * Creates a new web query.
+ *
+ * @param hostname
+ * @param port
+ * @param path
+ * @param secure
+ */
+ public Query(String hostname, int port, String path, boolean secure) {
+ super(DEFAULT_DISPATCHER);
+
+ try {
+ locationContext = new URL(secure ? HTTPS_PROTOCOL : HTTP_PROTOCOL,
+ hostname, port, path);
+ } catch (MalformedURLException exception) {
+ throw new IllegalArgumentException("Unable to construct context URL.",
+ exception);
+ }
+ }
+
+ public String getHostname() {
+ return locationContext.getHost();
+ }
+
+ public String getPath() {
+ return locationContext.getFile();
+ }
+
+ public int getPort() {
+ return locationContext.getPort();
+ }
+
+ public boolean isSecure() {
+ String protocol = locationContext.getProtocol();
+ return protocol.equalsIgnoreCase(HTTPS_PROTOCOL);
+ }
+
+ public URL getLocation() {
+ StringBuilder queryStringBuilder = new StringBuilder();
+
+ for (String key : arguments) {
+ try {
+ if (queryStringBuilder.length() > 0) {
+ queryStringBuilder.append("&");
+ }
+
+ queryStringBuilder.append(URLEncoder.encode(key, URL_ENCODING)
+ + "=" + URLEncoder.encode(arguments.get(key), URL_ENCODING));
+ } catch (UnsupportedEncodingException exception) {
+ throw new IllegalStateException("Unable to construct query string.", exception);
+ }
+ }
+
+ URL location = null;
+ try {
+ String queryString = queryStringBuilder.length() > 0 ?
+ "?" + queryStringBuilder.toString() : "";
+
+ location = new URL(locationContext.getProtocol(),
+ locationContext.getHost(),
+ locationContext.getPort(),
+ locationContext.getPath() + queryString);
+ } catch (MalformedURLException exception) {
+ throw new IllegalStateException("Unable to construct query URL.", exception);
+ }
+
+ return location;
+ }
+
+ /**
+ * Returns the web query's arguments dictionary. Arguments are passed via
+ * the query string of the web query's URL.
+ */
+ public ArgumentsDictionary getArguments() {
+ return argumentsDictionary;
+ }
+
+ /**
+ * Returns the web query's request property dictionary. Request properties
+ * are passed via HTTP headers when the query is executed.
+ */
+ public RequestPropertiesDictionary getRequestProperties() {
+ return requestPropertiesDictionary;
+ }
+
+ /**
+ * Returns the web query's response property dictionary. Response properties
+ * are returned via HTTP headers when the query is executed.
+ */
+ public ResponsePropertiesDictionary getResponseProperties() {
+ return responsePropertiesDictionary;
+ }
+
+ /**
+ * Returns the serializer used to stream the value passed to or from the
+ * web query. By default, an instance of {@link JSONSerializer} is used.
+ */
+ public Serializer getSerializer() {
+ return serializer;
+ }
+
+ /**
+ * Sets the serializer used to stream the value passed to or from the
+ * web query.
+ *
+ * @param serializer
+ */
+ public void setSerializer(Serializer serializer) {
+ if (serializer == null) {
+ throw new IllegalArgumentException("serializer is null.");
+ }
+
+ this.serializer = serializer;
+ }
+
+ /**
+ * Gets the number of bytes that have been sent in the body of this
+ * query's HTTP request. This will only be non-zero for POST and PUT
+ * requests, as GET and DELETE requests send no content to the server.
+ * <p>
+ * For POST and PUT requests, this number will increment in between the
+ * {@link QueryListener#connected(Query) connected} and
+ * {@link QueryListener#requestSent(Query) requestSent} phases of the
+ * <tt>QueryListener</tt> lifecycle methods. Interested listeners can poll
+ * for this value during that phase.
+ */
+ public long getBytesSent() {
+ return bytesSent;
+ }
+
+ /**
+ * Gets the number of bytes that have been received from the server in the
+ * body of the server's HTTP response. This will generally only be non-zero
+ * for GET requests, as POST, PUT, and DELETE requests generally don't
+ * solicit response content from the server.
+ * <p>
+ * This number will increment in between the
+ * {@link QueryListener#requestSent(Query) requestSent} and
+ * {@link QueryListener#responseReceived(Query) responseReceived} phases of
+ * the <tt>QueryListener</tt> lifecycle methods. Interested listeners can
+ * poll for this value during that phase.
+ */
+ public long getBytesReceived() {
+ return bytesReceived;
+ }
+
+ /**
+ * Gets the number of bytes that are expected to be received from the
+ * server in the body of the server's HTTP response. This value reflects
+ * the <tt>Content-Length</tt> HTTP response header and is thus merely an
+ * expectation. The actual total number of bytes that will be received is
+ * not known for certain until the full response has been received.
+ * <p>
+ * If the server did not specify a <tt>Content-Length</tt> HTTP response
+ * header, a value of <tt>-1</tt> will be returned to indicate that this
+ * value is unknown.
+ */
+ public long getBytesExpected() {
+ return bytesExpected;
+ }
+
+ protected Object execute(Method method, Object value)
+ throws QueryException {
+ URL location = getLocation();
+ HttpURLConnection connection = null;
+
+ bytesSent = 0;
+ bytesReceived = 0;
+ bytesExpected = -1;
+
+ int status = -1;
+ String message = null;
+
+ try {
+ // Clear any properties from a previous response
+ responseProperties.clear();
+
+ // Open a connection
+ connection = (HttpURLConnection)location.openConnection();
+ connection.setRequestMethod(method.toString());
+ connection.setAllowUserInteraction(false);
+ connection.setInstanceFollowRedirects(false);
+ connection.setUseCaches(false);
+
+ // Set the request headers
+ for (String key : requestProperties) {
+ connection.addRequestProperty(key, requestProperties.get(key));
+ }
+
+ // Set the input/output state
+ connection.setDoInput(true);
+ connection.setDoOutput(method == Method.POST || method == Method.PUT);
+
+ // Connect to the server
+ connection.connect();
+ queryListeners.connected(this);
+
+ // Write the request body
+ if (method == Method.POST || method == Method.PUT) {
+ OutputStream outputStream = null;
+ try {
+ outputStream = connection.getOutputStream();
+ serializer.writeObject(value, new MonitoredOutputStream(outputStream));
+ } finally {
+ if (outputStream != null) {
+ outputStream.close();
+ }
+ }
+ }
+
+ // Notify listeners that the request has been sent
+ queryListeners.requestSent(this);
+
+ // Set the response info
+ status = connection.getResponseCode();
+ message = connection.getResponseMessage();
+
+ // If the response was anything other than 2xx, throw an exception
+ int statusPrefix = status / 100;
+ if (statusPrefix != 2) {
+ throw new QueryException(status, message);
+ }
+
+ // Record the content length
+ bytesExpected = connection.getContentLength();
+
+ // NOTE Header indexes start at 1, not 0
+ int i = 1;
+ for (String key = connection.getHeaderFieldKey(i);
+ key != null;
+ key = connection.getHeaderFieldKey(++i)) {
+ responseProperties.put(key, connection.getHeaderField(i));
+ }
+
+ // Read the response body
+ if (method == Method.GET) {
+ InputStream inputStream = null;
+ try {
+ inputStream = connection.getInputStream();
+ value = serializer.readObject(new MonitoredInputStream(inputStream));
+ } finally {
+ if (inputStream != null) {
+ inputStream.close();
+ }
+ }
+ }
+
+ // Notify listeners that the response has been received
+ queryListeners.responseReceived(this);
+ } catch (Exception exception) {
+ queryListeners.failed(this);
+ throw new QueryException(exception);
+ }
+
+ return value;
+ }
+
+ /**
+ * Gets the query's <tt>QueryListener</tt>s.
+ */
+ public ListenerList<QueryListener<V>> getQueryListeners() {
+ return queryListeners;
+ }
+}
Added: incubator/pivot/tags/v1.0/web/src/pivot/web/QueryException.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/web/src/pivot/web/QueryException.java?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/web/src/pivot/web/QueryException.java (added)
+++ incubator/pivot/tags/v1.0/web/src/pivot/web/QueryException.java Mon Mar 16 16:16:40 2009
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2008 VMware, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pivot.web;
+
+import pivot.util.concurrent.TaskExecutionException;
+
+/**
+ * Thrown when an error occurs while executing a web query.
+ */
+public class QueryException extends TaskExecutionException {
+ public static final long serialVersionUID = 0;
+
+ private int status = -1;
+
+ // TODO Define static constants for status codes
+
+ public QueryException(int status) {
+ this(status, null);
+ }
+
+ public QueryException(int status, String message) {
+ super(message);
+
+ this.status = status;
+ }
+
+ public QueryException(Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * Returns the HTTP status code corresponding to the exception.
+ *
+ * @return
+ * An HTTP status code reflecting the nature of the exception.
+ */
+ public int getStatus() {
+ return status;
+ }
+
+ @Override
+ public String getLocalizedMessage() {
+ String message = super.getLocalizedMessage();
+ return (message != null ? (status + " " + message) : String.valueOf(status));
+ }
+}
Added: incubator/pivot/tags/v1.0/web/src/pivot/web/QueryListener.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/web/src/pivot/web/QueryListener.java?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/web/src/pivot/web/QueryListener.java (added)
+++ incubator/pivot/tags/v1.0/web/src/pivot/web/QueryListener.java Mon Mar 16 16:16:40 2009
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2008 VMware, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pivot.web;
+
+/**
+ * Defines event listener methods that pertain to queries. Developers register
+ * for such events by adding themselves to a query's list of "query
+ * listeners" (see {@link Query#getQueryListeners()}).
+ * <p>
+ * Note that, like {@link pivot.util.concurrent.TaskListener task listeners},
+ * query listeners will be notified on the query's worker thread, not the thread
+ * that executed the query.
+ *
+ * @author tvolkert
+ */
+public interface QueryListener<V> {
+ /**
+ * Called when a query has connected to the server but the request has not
+ * yet been sent.
+ *
+ * @param query
+ */
+ public void connected(Query<V> query);
+
+ /**
+ * Called when the request has been sent to the server but the response has
+ * not yet been received.
+ *
+ * @param query
+ */
+ public void requestSent(Query<V> query);
+
+ /**
+ * Called when a response has been received from the server.
+ *
+ * @param query
+ */
+ public void responseReceived(Query<V> query);
+
+ /**
+ * Called when an error has occurred
+ *
+ * @param query
+ */
+ public void failed(Query<V> query);
+}
Added: incubator/pivot/tags/v1.0/web/src/pivot/web/package.html
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/web/src/pivot/web/package.html?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/web/src/pivot/web/package.html (added)
+++ incubator/pivot/tags/v1.0/web/src/pivot/web/package.html Mon Mar 16 16:16:40 2009
@@ -0,0 +1,38 @@
+<html>
+<head></head>
+<body>
+<p>Provides classes for communicating with HTTP-based web services.</p>
+
+<p>Fundamentally, a web query is simply an <a href="http://www.ietf.org/rfc/rfc2616.txt" target="_blank">HTTP</a> request. However, the default data format used by a web query is not HTML, but JSON. This allows a caller to effectively invoke database-like operations over the web - the HTTP methods are used in a manner that is very similar to their corresponding SQL equivalents:<p>
+
+<table style="border-collapse:collapse; border:solid 1px #999999">
+ <thead>
+ <td style="font-weight:bold">HTTP Method</td>
+ <td style="font-weight:bold">SQL Query</td>
+ <td style="font-weight:bold">Behavior</td>
+ </thead>
+ <tr>
+ <td><tt>POST</tt></td>
+ <td><tt>INSERT</tt></td>
+ <td>Create</td>
+ </tr>
+ <tr>
+ <td><tt>GET</tt></td>
+ <td><tt>SELECT</tt></td>
+ <td>Read</td>
+ </tr>
+ <tr>
+ <td><tt>PUT</tt></td>
+ <td><tt>UPDATE</tt></td>
+ <td>Update</td>
+ </tr>
+ <tr>
+ <td><tt>DELETE</tt></td>
+ <td><tt>DELETE</tt></td>
+ <td>Delete</td>
+ </tr>
+</table>
+
+<p>These operations, sometimes referred to as "CRUD", form the basis of the <a href="http://en.wikipedia.org/wiki/Representational_State_Transfer" target="_blank">Representational State Transfer</a> (REST) model of building web services. Pivot web queries are designed primarily to facilitate interaction with JSON-based REST services. However, they are sufficiently generic to support communication with any type of HTTP-based service, using any data format (for example, XML). This enables web queries to be used in a broad range of server communication scenarios.</p>
+</body>
+</html>
Added: incubator/pivot/tags/v1.0/web/src/pivot/web/server/ProxyServlet.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/web/src/pivot/web/server/ProxyServlet.java?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/web/src/pivot/web/server/ProxyServlet.java (added)
+++ incubator/pivot/tags/v1.0/web/src/pivot/web/server/ProxyServlet.java Mon Mar 16 16:16:40 2009
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2008 VMware, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pivot.web.server;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Enumeration;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * HTTP proxy that allows an unsigned applet to issue web queries to services
+ * outside of its origin server.
+ *
+ * @author gbrown
+ */
+public class ProxyServlet extends HttpServlet {
+ private String hostname = null;
+ private int port = -1;
+ private String path = null;
+
+ public static final long serialVersionUID = 0;
+
+ public static final String METHOD_GET = "GET";
+ public static final String METHOD_POST = "POST";
+ public static final String METHOD_PUT = "PUT";
+ public static final String METHOD_DELETE = "DELETE";
+
+ public static final String HOSTNAME_PARAM = "hostname";
+ public static final String PORT_PARAM = "port";
+ public static final String PATH_PARAM = "path";
+
+ public static final int BUFFER_SIZE = 1024;
+
+ @Override
+ public void init(ServletConfig config)
+ throws ServletException {
+ super.init();
+
+ hostname = config.getInitParameter(HOSTNAME_PARAM);
+ if (hostname == null) {
+ throw new ServletException("Hostname is required.");
+ }
+
+ String portHeader = config.getInitParameter(PORT_PARAM);
+ port = (portHeader == null) ? -1 : Integer.parseInt(portHeader);
+
+ path = config.getInitParameter(PATH_PARAM);
+ if (path == null) {
+ throw new ServletException("Path is required.");
+ }
+ }
+
+ @Override
+ public void destroy() {
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ protected void service(HttpServletRequest request, HttpServletResponse response)
+ throws IOException, ServletException {
+ // Construct the URL
+ String path = this.path;
+
+ String pathInfo = request.getPathInfo();
+ if (pathInfo != null) {
+ path += "/" + pathInfo;
+ }
+
+ String queryString = request.getQueryString();
+ if (queryString != null) {
+ path += "?" + queryString;
+ }
+
+ URL url = null;
+ try {
+ url = new URL(request.getScheme(), hostname, port, path);
+ } catch(MalformedURLException exception) {
+ throw new ServletException("Unable to construct URL.", exception);
+ }
+
+ String method = request.getMethod();
+
+ // Open a connection to the URL
+ HttpURLConnection connection = (HttpURLConnection)url.openConnection();
+ connection.setRequestMethod(method);
+ connection.setAllowUserInteraction(false);
+ connection.setInstanceFollowRedirects(false);
+ connection.setUseCaches(false);
+
+ // Write request headers to connection
+ System.out.println("[Request Headers]");
+ Enumeration<String> headerNames = (Enumeration<String>)request.getHeaderNames();
+
+ if (headerNames != null) {
+ while (headerNames.hasMoreElements()) {
+ String headerName = headerNames.nextElement();
+
+ Enumeration<String> headerValues =
+ (Enumeration<String>)request.getHeaders(headerName);
+
+ while (headerValues.hasMoreElements()) {
+ String headerValue = headerValues.nextElement();
+ System.out.println(headerName + ": " + headerValue);
+
+ if (connection.getRequestProperty(headerName) == null) {
+ connection.setRequestProperty(headerName, headerValue);
+ } else {
+ connection.addRequestProperty(headerName, headerValue);
+ }
+ }
+ }
+ }
+
+ // Set the input/output state
+ connection.setDoInput(true);
+ connection.setDoOutput(method.equalsIgnoreCase(METHOD_POST)
+ || method.equalsIgnoreCase(METHOD_PUT));
+
+ // Connect to the server
+ connection.connect();
+
+ // Write the request body
+ if (connection.getDoOutput()) {
+ OutputStream outputStream = null;
+
+ try {
+ InputStream inputStream = request.getInputStream();
+
+ outputStream = connection.getOutputStream();
+ outputStream = new BufferedOutputStream(outputStream, BUFFER_SIZE);
+ for (int data = inputStream.read(); data != -1; data = inputStream.read()) {
+ outputStream.write((byte)data);
+ }
+ } finally {
+ if (outputStream != null) {
+ outputStream.close();
+ }
+ }
+ }
+
+ // Set the response status
+ int status = connection.getResponseCode();
+ System.out.println("[Status] " + status);
+
+ int statusPrefix = status / 100;
+
+ if (statusPrefix == 1
+ || statusPrefix == 3) {
+ throw new ServletException("Unexpected server response: " + status);
+ }
+
+ response.setStatus(status);
+
+ // Write response headers
+ // NOTE Header indexes start at 1, not 0
+ System.out.println("[Response Headers]");
+
+ int i = 1;
+ for (String key = connection.getHeaderFieldKey(i);
+ key != null;
+ key = connection.getHeaderFieldKey(++i)) {
+ if (key != null) {
+ String value = connection.getHeaderField(i);
+ System.out.println(key + ": " + value);
+
+ if (response.containsHeader(key)) {
+ response.addHeader(key, value);
+ } else {
+ response.setHeader(key, value);
+ }
+ }
+ }
+
+ // Read the response body
+ if (method.equalsIgnoreCase(METHOD_GET)) {
+ InputStream inputStream = null;
+
+ try {
+ try {
+ // Response returned on input stream
+ inputStream = connection.getInputStream();
+ } catch(Exception exception) {
+ // Response returned on error stream
+ inputStream = connection.getErrorStream();
+ }
+
+ inputStream = new BufferedInputStream(inputStream, BUFFER_SIZE);
+
+ OutputStream outputStream = response.getOutputStream();
+ for (int data = inputStream.read(); data != -1; data = inputStream.read()) {
+ outputStream.write((byte)data);
+ }
+
+ response.flushBuffer();
+ } finally {
+ if (inputStream != null) {
+ inputStream.close();
+ }
+ }
+ }
+ }
+}