Added support in REST API for POSTing or PUTting multiple preferences and shared data in one request. See WOOKIE-414
git-svn-id: https://svn.apache.org/repos/asf/wookie/trunk@1575276 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/wookie-connector/java/src/main/java/org/apache/wookie/connector/framework/AbstractWookieConnectorService.java b/wookie-connector/java/src/main/java/org/apache/wookie/connector/framework/AbstractWookieConnectorService.java
index 692c2a3..ceab972 100644
--- a/wookie-connector/java/src/main/java/org/apache/wookie/connector/framework/AbstractWookieConnectorService.java
+++ b/wookie-connector/java/src/main/java/org/apache/wookie/connector/framework/AbstractWookieConnectorService.java
@@ -23,7 +23,6 @@
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
-import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -95,16 +94,18 @@
SignedApiRequest request = SignedApiRequest.POST(conn.getURL()+"/properties", conn.getApiKey(), conn.getSecret());
createInstanceParams(request, instance.id);
+
+ String json = "{";
if ( is_public ) {
- request.addParameter("is_public", "true");
+ json += "\"shareddata\":[{\"name\":\""+fName+"\", \"value\":\""+fValue+"\"}]";
}
else {
- request.addParameter("is_public", "false");
+ json += "\"preferences\":[{\"name\":\""+fName+"\", \"value\":\""+fValue+"\"}]";
}
- request.addParameter("propertyname", fName);
- request.addParameter("propertyvalue", fValue);
-
+ json += "}";
+
+ request.setRequestEntity(json);
request.execute();
if (request.getStatusCode() > 201) {
@@ -132,20 +133,22 @@
}
- public void updatePropertyForInstance (WidgetInstance instance, boolean is_public, String propertyName, String data ) throws WookieConnectorException, IOException {
+ public void updatePropertyForInstance (WidgetInstance instance, boolean is_public, String name, String value ) throws WookieConnectorException, IOException {
SignedApiRequest request = SignedApiRequest.PUT(conn.getURL()+"/properties", conn.getApiKey(), conn.getSecret());
createInstanceParams(request, instance.id);
+ String json = "{";
+
if ( is_public ) {
- request.addParameter("is_public", "true");
+ json += "\"shareddata\":[{\"name\":\""+name+"\", \"value\":\""+value+"\"}]";
}
else {
- request.addParameter("is_public", "false");
+ json += "\"preferences\":[{\"name\":\""+name+"\", \"value\":\""+value+"\"}]";
}
+ json += "}";
- request.addParameter("propertyname", propertyName);
- request.addParameter("propertyvalue", data);
+ request.setRequestEntity(json);
request.execute();
@@ -702,7 +705,7 @@
* @throws IOException
*/
public void deletePolicy ( Policy policy ) throws WookieConnectorException, IOException {
- SignedApiRequest request = SignedApiRequest.DELETE(conn.getURL()+"/policies"+URLEncoder.encode(policy.toString(), "UTF-8"), conn.getApiKey(), conn.getSecret());
+ SignedApiRequest request = SignedApiRequest.DELETE(conn.getURL()+"/policies/"+policy.toString(), conn.getApiKey(), conn.getSecret());
request.execute();
if (request.getStatusCode() != 200){
throw new WookieConnectorException("Problem DELETEing from /policies", new IOException("Error:"+request.getStatusCode()));
diff --git a/wookie-server/src/main/java/org/apache/wookie/controller/PropertiesController.java b/wookie-server/src/main/java/org/apache/wookie/controller/PropertiesController.java
index 780e6e9..9c4da1e 100644
--- a/wookie-server/src/main/java/org/apache/wookie/controller/PropertiesController.java
+++ b/wookie-server/src/main/java/org/apache/wookie/controller/PropertiesController.java
@@ -21,6 +21,7 @@
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
import org.apache.wookie.auth.AuthToken;
import org.apache.wookie.beans.ISharedData;
@@ -31,6 +32,8 @@
import org.apache.wookie.exceptions.UnauthorizedAccessException;
import org.apache.wookie.helpers.Notifier;
import org.apache.wookie.services.PreferencesService;
+import org.json.JSONArray;
+import org.json.JSONObject;
/**
* REST implementation for widgetInstance
@@ -45,35 +48,29 @@
private static final long serialVersionUID = 308590474406800659L;
static Logger _logger = Logger.getLogger(PropertiesController.class.getName());
- /**
- * We only override doGet to allow tunneling requests through GET
- * for legacy clients
+
+
+ /* (non-Javadoc)
+ * @see org.apache.wookie.controller.Controller#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
- String requestId = request.getParameter("requestid");//$NON-NLS-1$
- // If the request id is not null, show otherwise index
- if (requestId != null && requestId.length() > 0) {
- try {
- createOrUpdate(request);
- } catch (InvalidParametersException e) {
- response.sendError(HttpServletResponse.SC_BAD_REQUEST);
- } catch (UnauthorizedAccessException e){
- response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
- }
- } else {
- try {
- show(null, request, response);
- response.setStatus(HttpServletResponse.SC_OK);
- } catch (ResourceNotFoundException e) {
- response.sendError(HttpServletResponse.SC_NOT_FOUND);
- } catch (UnauthorizedAccessException e){
- response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
- }
+ //
+ // For now we just execute the show() method. In future we could return a JSON array of all properties
+ //
+ String name = request.getParameter("propertyname"); //$NON-NLS-1$
+ try {
+ show(name, request, response);
+ } catch (ResourceNotFoundException e) {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ } catch(UnauthorizedAccessException e1){
+ response.sendError(HttpServletResponse.SC_FORBIDDEN);
}
}
+
+
@Override
protected void show(String resourceId, HttpServletRequest request,
HttpServletResponse response) throws ResourceNotFoundException,
@@ -81,14 +78,13 @@
AuthToken authToken = getAuthTokenFromRequest(request);
if (authToken == null) throw new ResourceNotFoundException();
- String name = request.getParameter("propertyname"); //$NON-NLS-1$
- if (name == null || name.trim().equals("")) throw new ResourceNotFoundException();
+ if (resourceId == null || resourceId.trim().equals("")) throw new ResourceNotFoundException();
String value = null;
// Note that preferences and shared data keys may be the same!
// We let the shared data values override.
- value = PreferencesService.Factory.getInstance().getPreference(authToken.getApiKey(), authToken.getWidgetId(), authToken.getContextId(), authToken.getViewerId(), name);
- ISharedData data = new SharedContext(authToken).getSharedData(name);
+ value = PreferencesService.Factory.getInstance().getPreference(authToken.getApiKey(), authToken.getWidgetId(), authToken.getContextId(), authToken.getViewerId(), resourceId);
+ ISharedData data = new SharedContext(authToken).getSharedData(resourceId);
if (data != null) value = data.getDvalue();
if (value == null) throw new ResourceNotFoundException();
PrintWriter out = response.getWriter();
@@ -111,7 +107,7 @@
found = new SharedContext(authToken).removeSharedData(name);
Notifier.notifyWidgets(request.getSession(), authToken, Notifier.STATE_UPDATED);
} else {
- found = updatePreference(authToken, name, null);
+ found = updatePreference(authToken, name, null, false);
}
if (!found) throw new ResourceNotFoundException();
return true;
@@ -138,21 +134,68 @@
* @throws InvalidParametersException
* @throws UnauthorizedAccessException
*/
- public static void createOrUpdate(HttpServletRequest request)
+ private static void createOrUpdate(HttpServletRequest request)
throws InvalidParametersException,UnauthorizedAccessException {
- String name = request.getParameter("propertyname"); //$NON-NLS-1$
- String value = request.getParameter("propertyvalue"); //$NON-NLS-1$
-
+
AuthToken authToken = getAuthTokenFromRequest(request);
if (authToken == null) throw new InvalidParametersException();
+
+ //
+ // The data we need is in JSON in the request body, structured as:
+ //
+ // {
+ // {"preferences" {[
+ // {"name":"pref1", "value":"pass", "readOnly":0}
+ // ]},
+ // {"shareddata" {[
+ // {"name":"sd1", "value":"pass"}
+ // ]}
+ // }
+ //
+ //
- if (name == null || name.trim().equals("")) throw new InvalidParametersException();
-
- if (isPublic(request)){
- new SharedContext(authToken).updateSharedData(name, value, false);
- Notifier.notifyWidgets(request.getSession(), authToken, Notifier.STATE_UPDATED);
- } else {
- updatePreference(authToken, name, value);
+ try {
+ String body = IOUtils.toString(request.getInputStream());
+ JSONObject json = new JSONObject(body);
+ if (json != null){
+ if (json.has("preferences")){
+ JSONArray array = json.getJSONArray("preferences");
+ if (array != null){
+ for (int i=0;i<array.length();i++){
+ JSONObject property = array.getJSONObject(i);
+ if (!property.has("name")) throw new InvalidParametersException();
+ String name = property.getString("name");
+ if (name != null && !name.trim().equals("")){
+ String value = property.getString("value");
+ boolean readOnly = property.getBoolean("readOnly");
+ updatePreference(authToken, name, value, readOnly);
+ } else {
+ throw new InvalidParametersException();
+ }
+ }
+ }
+ }
+ if (json.has("shareddata")){
+ JSONArray array = json.getJSONArray("shareddata");
+ if (array != null){
+ for (int i=0;i<array.length();i++){
+ JSONObject property = array.getJSONObject(i);
+ if (!property.has("name")) throw new InvalidParametersException();
+ String name = property.getString("name");
+ if (name != null && !name.trim().equals("")){
+ String value = property.getString("value");
+ new SharedContext(authToken).updateSharedData(name, value, false);
+ Notifier.notifyWidgets(request.getSession(), authToken, Notifier.STATE_UPDATED);
+ } else {
+ throw new InvalidParametersException();
+ }
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new InvalidParametersException();
}
}
@@ -162,11 +205,11 @@
* @param name
* @param value
*/
- public static boolean updatePreference(AuthToken authToken, String name, String value){
+ private static boolean updatePreference(AuthToken authToken, String name, String value, boolean readOnly){
boolean found=false;
String preference = PreferencesService.Factory.getInstance().getPreference(authToken.getApiKey(), authToken.getWidgetId(), authToken.getContextId(), authToken.getViewerId(), name);
if (preference != null) found=true;
- PreferencesService.Factory.getInstance().setPreference(authToken.getApiKey(), authToken.getWidgetId(), authToken.getContextId(), authToken.getViewerId(), name, value);
+ PreferencesService.Factory.getInstance().setPreference(authToken.getApiKey(), authToken.getWidgetId(), authToken.getContextId(), authToken.getViewerId(), name, value, readOnly);
return found;
}
diff --git a/wookie-server/src/test/java/org/apache/wookie/tests/functional/PropertiesControllerTest.java b/wookie-server/src/test/java/org/apache/wookie/tests/functional/PropertiesControllerTest.java
index cc2c760..f746703 100644
--- a/wookie-server/src/test/java/org/apache/wookie/tests/functional/PropertiesControllerTest.java
+++ b/wookie-server/src/test/java/org/apache/wookie/tests/functional/PropertiesControllerTest.java
@@ -18,7 +18,11 @@
import java.io.IOException;
import org.apache.commons.httpclient.HttpException;
+import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.wookie.tests.helpers.Request;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -51,12 +55,12 @@
}
/**
- * Test that we can set preferences using post parameters
+ * Test that we can set preferences using POST
*
* @throws Exception
*/
@Test
- public void setPreferenceUsingPostParameters() throws Exception {
+ public void setPreferenceUsingPost() throws Exception {
//
// Set a property ("testpost=pass") using POST
//
@@ -64,10 +68,18 @@
post.addParameter("api_key", API_KEY_VALID);
post.addParameter("widgetid", WIDGET_ID_VALID);
post.addParameter("userid", "test");
- post.addParameter("is_public", "false");
post.addParameter("shareddatakey", "propstest");
- post.addParameter("propertyname", "testpost");
- post.addParameter("propertyvalue", "pass");
+
+ JSONObject pref = new JSONObject();
+ pref.put("name", "testpost");
+ pref.put("value", "pass");
+ pref.put("readOnly", false);
+ JSONObject json = new JSONObject();
+ JSONArray prefs = new JSONArray();
+ prefs.put(pref);
+ json.put("preferences", prefs);
+ StringRequestEntity entity = new StringRequestEntity(json.toString(), "application/json", "UTF-8");
+ post.setRequestEntity(entity);
post.execute(true, false);
int code = post.getStatusCode();
assertEquals(201, code);
@@ -88,14 +100,82 @@
assertEquals("pass", resp);
}
+
+ /**
+ * Test that we can set multiple preferences at the same time by POSTing JSON
+ *
+ * @throws Exception
+ */
+ @Test
+ public void setMultiplePreferencesUsingPost() throws Exception {
+ //
+ // Set a property ("testpost=pass") using POST
+ //
+ Request post = new Request("POST", TEST_PROPERTIES_SERVICE_URL_VALID);
+ post.addParameter("api_key", API_KEY_VALID);
+ post.addParameter("widgetid", WIDGET_ID_VALID);
+ post.addParameter("userid", "test");
+ post.addParameter("shareddatakey", "propstest");
+
+ JSONObject pref1 = new JSONObject();
+ pref1.put("name", "testpost1");
+ pref1.put("value", "pass1");
+ pref1.put("readOnly", false);
+
+ JSONObject pref2 = new JSONObject();
+ pref2.put("name", "testpost2");
+ pref2.put("value", "pass2");
+ pref2.put("readOnly", false);
+
+ JSONObject json = new JSONObject();
+ JSONArray prefs = new JSONArray();
+ prefs.put(pref1);
+ prefs.put(pref2);
+ json.put("preferences", prefs);
+ StringRequestEntity entity = new StringRequestEntity(json.toString(), "application/json", "UTF-8");
+ post.setRequestEntity(entity);
+ post.execute(true, false);
+ int code = post.getStatusCode();
+ assertEquals(201, code);
+
+ //
+ // Read back each property using GET
+ //
+ Request get = new Request("GET", TEST_PROPERTIES_SERVICE_URL_VALID);
+ get.addParameter("api_key", API_KEY_VALID);
+ get.addParameter("widgetid", WIDGET_ID_VALID);
+ get.addParameter("userid", "test");
+ get.addParameter("shareddatakey", "propstest");
+ get.addParameter("propertyname", "testpost1");
+ get.execute(true, false);
+ code = get.getStatusCode();
+ assertEquals(200, code);
+ String resp = get.getResponseBodyAsString();
+ assertEquals("pass1", resp);
+
+ get = new Request("GET", TEST_PROPERTIES_SERVICE_URL_VALID);
+ get.addParameter("api_key", API_KEY_VALID);
+ get.addParameter("widgetid", WIDGET_ID_VALID);
+ get.addParameter("userid", "test");
+ get.addParameter("shareddatakey", "propstest");
+ get.addParameter("propertyname", "testpost2");
+ get.execute(true, false);
+ code = get.getStatusCode();
+ assertEquals(200, code);
+ resp = get.getResponseBodyAsString();
+ assertEquals("pass2", resp);
+ }
+
+
/**
* Test we can set shared data values using querystring parameters
*
* @throws IOException
* @throws HttpException
+ * @throws JSONException
*/
@Test
- public void setSharedData() throws HttpException, IOException {
+ public void setSharedData() throws HttpException, IOException, JSONException {
//
// Set some shared data with POST
@@ -104,10 +184,17 @@
post.addParameter("api_key", API_KEY_VALID);
post.addParameter("widgetid", WIDGET_ID_VALID);
post.addParameter("userid", "test");
- post.addParameter("is_public", "false");
post.addParameter("shareddatakey", "propstest");
- post.addParameter("propertyname", "cat");
- post.addParameter("propertyvalue", "garfield");
+
+ JSONObject data = new JSONObject();
+ data.put("name", "cat");
+ data.put("value", "garfield");
+ JSONObject json = new JSONObject();
+ JSONArray set = new JSONArray();
+ set.put(data);
+ json.put("shareddata", set);
+ StringRequestEntity entity = new StringRequestEntity(json.toString(), "application/json", "UTF-8");
+ post.setRequestEntity(entity);
post.execute(true, false);
int code = post.getStatusCode();
assertEquals(201, code);
@@ -134,9 +221,10 @@
*
* @throws IOException
* @throws HttpException
+ * @throws JSONException
*/
@Test
- public void updateProperty() throws HttpException, IOException {
+ public void updateProperty() throws HttpException, IOException, JSONException {
//
// Set cat=felix using POST
@@ -145,10 +233,18 @@
put.addParameter("api_key", API_KEY_VALID);
put.addParameter("widgetid", WIDGET_ID_VALID);
put.addParameter("userid", "test");
- put.addParameter("is_public", "false");
put.addParameter("shareddatakey", "propstest");
- put.addParameter("propertyname", "cat");
- put.addParameter("propertyvalue", "felix");
+
+ JSONObject data = new JSONObject();
+ data.put("name", "cat");
+ data.put("value", "felix");
+ JSONObject json = new JSONObject();
+ JSONArray set = new JSONArray();
+ set.put(data);
+ json.put("shareddata", set);
+ StringRequestEntity entity = new StringRequestEntity(json.toString(), "application/json", "UTF-8");
+ put.setRequestEntity(entity);
+
put.execute(true, false);
int code = put.getStatusCode();
assertEquals(200, code);
@@ -186,6 +282,7 @@
delete.addParameter("api_key", API_KEY_VALID);
delete.addParameter("widgetid", WIDGET_ID_VALID);
delete.addParameter("userid", "test");
+ delete.addParameter("is_public", "true");
delete.addParameter("shareddatakey", "propstest");
delete.addParameter("propertyname", "cat");
delete.execute(true, false);
@@ -217,16 +314,25 @@
*
* @throws IOException
* @throws HttpException
+ * @throws JSONException
*/
@Test
- public void setPropertyNoName() throws HttpException, IOException {
+ public void setPropertyNoName() throws HttpException, IOException, JSONException {
Request post = new Request("POST", TEST_PROPERTIES_SERVICE_URL_VALID);
post.addParameter("api_key", API_KEY_VALID);
post.addParameter("widgetid", WIDGET_ID_VALID);
post.addParameter("userid", "test");
- post.addParameter("is_public", "false");
post.addParameter("shareddatakey", "propstest");
- post.addParameter("propertyvalue", "garfield");
+
+ JSONObject data = new JSONObject();
+ data.put("value", "garfield");
+ JSONObject json = new JSONObject();
+ JSONArray set = new JSONArray();
+ set.put(data);
+ json.put("shareddata", set);
+ StringRequestEntity entity = new StringRequestEntity(json.toString(), "application/json", "UTF-8");
+ post.setRequestEntity(entity);
+
post.execute(true, false);
int code = post.getStatusCode();
assertEquals(400, code);
@@ -238,17 +344,26 @@
*
* @throws IOException
* @throws HttpException
+ * @throws JSONException
*/
@Test
- public void setPropertyEmptyName() throws HttpException, IOException {
+ public void setPropertyEmptyName() throws HttpException, IOException, JSONException {
Request post = new Request("POST", TEST_PROPERTIES_SERVICE_URL_VALID);
post.addParameter("api_key", API_KEY_VALID);
post.addParameter("widgetid", WIDGET_ID_VALID);
post.addParameter("userid", "test");
- post.addParameter("is_public", "false");
post.addParameter("shareddatakey", "propstest");
- post.addParameter("propertyname", "");
- post.addParameter("propertyvalue", "garfield");
+
+ JSONObject data = new JSONObject();
+ data.put("name", "");
+ data.put("value", "garfield");
+ JSONObject json = new JSONObject();
+ JSONArray set = new JSONArray();
+ set.put(data);
+ json.put("shareddata", set);
+ StringRequestEntity entity = new StringRequestEntity(json.toString(), "application/json", "UTF-8");
+ post.setRequestEntity(entity);
+
post.execute(true, false);
int code = post.getStatusCode();
assertEquals(400, code);
@@ -259,17 +374,26 @@
*
* @throws IOException
* @throws HttpException
+ * @throws JSONException
*/
@Test
- public void setPropertyWhitespaceName() throws HttpException, IOException {
+ public void setPropertyWhitespaceName() throws HttpException, IOException, JSONException {
Request post = new Request("POST", TEST_PROPERTIES_SERVICE_URL_VALID);
post.addParameter("api_key", API_KEY_VALID);
post.addParameter("widgetid", WIDGET_ID_VALID);
post.addParameter("userid", "test");
- post.addParameter("is_public", "false");
post.addParameter("shareddatakey", "propstest");
- post.addParameter("propertyname", " ");
- post.addParameter("propertyvalue", "garfield");
+
+ JSONObject data = new JSONObject();
+ data.put("name", " ");
+ data.put("value", "garfield");
+ JSONObject json = new JSONObject();
+ JSONArray set = new JSONArray();
+ set.put(data);
+ json.put("shareddata", set);
+ StringRequestEntity entity = new StringRequestEntity(json.toString(), "application/json", "UTF-8");
+ post.setRequestEntity(entity);
+
post.execute(true, false);
int code = post.getStatusCode();
assertEquals(400, code);