changeset 704:77998c10737b

Implement WebUpdate. Reviewed-by: omajid Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2012-October/003764.html
author Roman Kennke <rkennke@redhat.com>
date Fri, 19 Oct 2012 19:53:15 +0200
parents 1dd0ea9aa8b4
children 498473c85300
files common/core/src/main/java/com/redhat/thermostat/common/storage/MongoStorage.java web/client/src/main/java/com/redhat/thermostat/web/client/RESTStorage.java web/client/src/test/java/com/redhat/thermostat/web/client/RESTStorageTest.java web/common/src/main/java/com/redhat/thermostat/web/common/WebUpdate.java web/server/src/main/java/com/redhat/thermostat/web/server/RESTStorageEndPoint.java web/server/src/test/java/com/redhat/thermostat/web/server/RESTStorageEndpointTest.java
diffstat 6 files changed, 324 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/common/core/src/main/java/com/redhat/thermostat/common/storage/MongoStorage.java	Thu Oct 18 00:25:04 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/storage/MongoStorage.java	Fri Oct 19 19:53:15 2012 +0200
@@ -332,11 +332,6 @@
         collectionCache.put(name, coll);
     }
 
-    private void createConnectionKey(Category category) {
-        // TODO: There is probably some better place to do this, perhaps related to the inner class
-        // idea mentioned below.
-    }
-
     @Override
     public Query createQuery() {
         return new MongoQuery();
--- a/web/client/src/main/java/com/redhat/thermostat/web/client/RESTStorage.java	Thu Oct 18 00:25:04 2012 +0200
+++ b/web/client/src/main/java/com/redhat/thermostat/web/client/RESTStorage.java	Fri Oct 19 19:53:15 2012 +0200
@@ -47,7 +47,9 @@
 import java.net.HttpURLConnection;
 import java.net.URL;
 import java.net.URLEncoder;
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 
@@ -63,6 +65,7 @@
 import com.redhat.thermostat.web.common.RESTQuery;
 import com.redhat.thermostat.web.common.WebInsert;
 import com.redhat.thermostat.web.common.WebRemove;
+import com.redhat.thermostat.web.common.WebUpdate;
 
 public class RESTStorage extends Storage {
 
@@ -83,7 +86,6 @@
         }
         @Override
         public String getUrl() {
-            // TODO Auto-generated method stub
             return endpoint;
         }
     }
@@ -138,9 +140,8 @@
     }
 
     @Override
-    public Update createUpdate() {
-        // TODO Auto-generated method stub
-        return null;
+    public WebUpdate createUpdate() {
+        return new WebUpdate(categoryIds);
     }
 
     @Override
@@ -283,9 +284,31 @@
     }
 
     @Override
-    public void updatePojo(Update arg0) {
-        // TODO Auto-generated method stub
-
+    public void updatePojo(Update update) {
+        WebUpdate webUp = (WebUpdate) update;
+        try {
+            URL url = new URL(endpoint + "/update-pojo");
+            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+            conn.setDoOutput(true);
+            conn.setDoInput(true);
+            conn.setRequestMethod("POST");
+            OutputStream out = conn.getOutputStream();
+            Gson gson = new Gson();
+            OutputStreamWriter writer = new OutputStreamWriter(out);
+            writer.write("update=");
+            writer.write(URLEncoder.encode(gson.toJson(webUp), "UTF-8"));
+            List<WebUpdate.UpdateValue> updateValues = webUp.getUpdates();
+            List<Object> values = new ArrayList<>(updateValues.size());
+            for (WebUpdate.UpdateValue updateValue : updateValues) {
+                values.add(updateValue.getValue());
+            }
+            writer.write("&values=");
+            writer.write(URLEncoder.encode(gson.toJson(values), "UTF-8"));
+            writer.flush();
+            checkResponseCode(conn);
+        } catch (IOException ex) {
+            throw new RuntimeException(ex);
+        }
     }
 
     public void setEndpoint(String endpoint) {
--- a/web/client/src/test/java/com/redhat/thermostat/web/client/RESTStorageTest.java	Thu Oct 18 00:25:04 2012 +0200
+++ b/web/client/src/test/java/com/redhat/thermostat/web/client/RESTStorageTest.java	Fri Oct 19 19:53:15 2012 +0200
@@ -40,6 +40,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 import java.io.BufferedReader;
@@ -66,6 +67,8 @@
 import org.junit.Test;
 
 import com.google.gson.Gson;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonParser;
 import com.google.gson.JsonSyntaxException;
 import com.redhat.thermostat.common.storage.Categories;
 import com.redhat.thermostat.common.storage.Category;
@@ -80,6 +83,7 @@
 import com.redhat.thermostat.web.common.RESTQuery;
 import com.redhat.thermostat.web.common.WebInsert;
 import com.redhat.thermostat.web.common.WebRemove;
+import com.redhat.thermostat.web.common.WebUpdate;
 
 public class RESTStorageTest {
 
@@ -93,12 +97,14 @@
 
     private static Category category;
     private static Key<String> key1;
+    private static Key<Integer> key2;
 
     private RESTStorage storage;
 
     @BeforeClass
     public static void setupCategory() {
         key1 = new Key<>("property1", true);
+        key2 = new Key<>("property2", true);
         category = new Category("test", key1);
     }
 
@@ -294,4 +300,76 @@
         assertEquals(Criteria.EQUALS, qualifier.getCriteria());
         assertEquals("test", qualifier.getValue());
     }
+
+    @Test
+    public void testCreateUpdate() {
+        WebUpdate update = (WebUpdate) storage.createUpdate();
+        assertNotNull(update);
+        update = update.from(category);
+        assertEquals(42, update.getCategoryId());
+        assertNotNull(update);
+        update = update.where(key1, "test");
+        assertNotNull(update);
+        List<Qualifier<?>> qualifiers = update.getQualifiers();
+        assertEquals(1, qualifiers.size());
+        Qualifier<?> qualifier = qualifiers.get(0);
+        assertEquals(key1, qualifier.getKey());
+        assertEquals(Criteria.EQUALS, qualifier.getCriteria());
+        assertEquals("test", qualifier.getValue());
+        update = update.set(key1, "fluff");
+        assertNotNull(update);
+        List<WebUpdate.UpdateValue> updates = update.getUpdates();
+        assertEquals(1, updates.size());
+        assertEquals("fluff", updates.get(0).getValue());
+        assertEquals(key1, updates.get(0).getKey());
+        assertEquals("java.lang.String", updates.get(0).getValueClass());
+    }
+
+    @Test
+    public void testUpdate() throws UnsupportedEncodingException, IOException, JsonSyntaxException, ClassNotFoundException {
+
+        WebUpdate update = storage.createUpdate().from(category).where(key1, "test").set(key1, "fluff").set(key2, 42);
+        storage.updatePojo(update);
+
+        Gson gson = new Gson();
+        StringReader reader = new StringReader(requestBody);
+        BufferedReader bufRead = new BufferedReader(reader);
+        String line = URLDecoder.decode(bufRead.readLine(), "UTF-8");
+        String [] params = line.split("&");
+        assertEquals(2, params.length);
+        String[] parts = params[0].split("=");
+        assertEquals("update", parts[0]);
+        WebUpdate receivedUpdate = gson.fromJson(parts[1], WebUpdate.class);
+        assertEquals(42, receivedUpdate.getCategoryId());
+
+        List<WebUpdate.UpdateValue> updates = receivedUpdate.getUpdates();
+        assertEquals(2, updates.size());
+
+        WebUpdate.UpdateValue update1 = updates.get(0);
+        assertEquals(key1, update1.getKey());
+        assertEquals("java.lang.String", update1.getValueClass());
+        assertNull(update1.getValue());
+
+        WebUpdate.UpdateValue update2 = updates.get(1);
+        assertEquals(key2, update2.getKey());
+        assertEquals("java.lang.Integer", update2.getValueClass());
+        assertNull(update2.getValue());
+
+        List<Qualifier<?>> qualifiers = receivedUpdate.getQualifiers();
+        assertEquals(1, qualifiers.size());
+        Qualifier<?> qualifier = qualifiers.get(0);
+        assertEquals(key1, qualifier.getKey());
+        assertEquals(Criteria.EQUALS, qualifier.getCriteria());
+        assertEquals("test", qualifier.getValue());
+
+        parts = params[1].split("=");
+        assertEquals(2, parts.length);
+        assertEquals("values", parts[0]);
+        JsonParser jsonParser = new JsonParser();
+        JsonArray jsonArray = jsonParser.parse(parts[1]).getAsJsonArray();
+        String value1 = gson.fromJson(jsonArray.get(0), String.class);
+        assertEquals("fluff", value1);
+        int value2 = gson.fromJson(jsonArray.get(1), Integer.class);
+        assertEquals(42, value2);
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/common/src/main/java/com/redhat/thermostat/web/common/WebUpdate.java	Fri Oct 19 19:53:15 2012 +0200
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.web.common;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import com.redhat.thermostat.common.storage.Category;
+import com.redhat.thermostat.common.storage.Key;
+import com.redhat.thermostat.common.storage.Update;
+import com.redhat.thermostat.common.storage.Query.Criteria;
+
+public class WebUpdate implements Update {
+
+    public static class UpdateValue {
+        private Key<?> key;
+        private transient Object value;
+        private String valueClass;
+
+        public UpdateValue() {
+            this(null, null);
+        }
+
+        public UpdateValue(Key<?> key, Object value) {
+            this.key = key;
+            this.value = value;
+            if (value != null) {
+                valueClass = value.getClass().getName();
+            }
+        }
+
+        public Key<?> getKey() {
+            return key;
+        }
+
+        public void setKey(Key<?> key) {
+            this.key = key;
+        }
+
+        public Object getValue() {
+            return value;
+        }
+
+        public void setValue(Object value) {
+            this.value = value;
+        }
+
+        public String getValueClass() {
+            return valueClass;
+        }
+
+        public void setValueClass(String valueClass) {
+            this.valueClass = valueClass;
+        }
+
+    }
+
+    private transient Map<Category, Integer> categoryIds;
+    private Integer categoryId;
+    private List<Qualifier<?>> qualifiers;
+    private List<UpdateValue> updateValues;
+
+    // NOTE: This is needed for de-serialization!
+    public WebUpdate() {
+        this(null);
+    }
+
+    public WebUpdate(Map<Category, Integer> categoryIds) {
+        qualifiers = new ArrayList<>();
+        updateValues = new ArrayList<>();
+        this.categoryIds = categoryIds;
+    }
+
+    @Override
+    public WebUpdate from(Category category) {
+        categoryId = categoryIds.get(category);
+        return this;
+    }
+
+    @Override
+    public <T> WebUpdate where(Key<T> key, T value) {
+        qualifiers.add(new Qualifier<T>(key, Criteria.EQUALS, value));
+        return this;
+    }
+
+    @Override
+    public <T> WebUpdate set(Key<T> key, T value) {
+        updateValues.add(new UpdateValue(key, value));
+        return this;
+    }
+
+    public int getCategoryId() {
+        return categoryId;
+    }
+
+    public List<Qualifier<?>> getQualifiers() {
+        return qualifiers;
+    }
+
+    public List<WebUpdate.UpdateValue> getUpdates() {
+        return updateValues;
+    }
+}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/RESTStorageEndPoint.java	Thu Oct 18 00:25:04 2012 +0200
+++ b/web/server/src/main/java/com/redhat/thermostat/web/server/RESTStorageEndPoint.java	Fri Oct 19 19:53:15 2012 +0200
@@ -13,18 +13,23 @@
 import javax.servlet.http.HttpServletResponse;
 
 import com.google.gson.Gson;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonParser;
 import com.redhat.thermostat.common.model.Pojo;
 import com.redhat.thermostat.common.storage.Category;
 import com.redhat.thermostat.common.storage.Cursor;
+import com.redhat.thermostat.common.storage.Key;
 import com.redhat.thermostat.common.storage.Query;
+import com.redhat.thermostat.common.storage.Query.Criteria;
 import com.redhat.thermostat.common.storage.Remove;
 import com.redhat.thermostat.common.storage.Storage;
-import com.redhat.thermostat.common.storage.Query.Criteria;
+import com.redhat.thermostat.common.storage.Update;
 import com.redhat.thermostat.web.common.Qualifier;
 import com.redhat.thermostat.web.common.RESTQuery;
 import com.redhat.thermostat.web.common.StorageWrapper;
 import com.redhat.thermostat.web.common.WebInsert;
 import com.redhat.thermostat.web.common.WebRemove;
+import com.redhat.thermostat.web.common.WebUpdate;
 
 @SuppressWarnings("serial")
 public class RESTStorageEndPoint extends HttpServlet {
@@ -61,6 +66,8 @@
             registerCategory(req, resp);
         } else if (cmd.equals("remove-pojo")) {
             removePojo(req, resp);
+        } else if (cmd.equals("update-pojo")) {
+            updatePojo(req, resp);
         }
     }
 
@@ -115,8 +122,40 @@
             targetRemove = targetRemove.where(qualifier.getKey(), qualifier.getValue());
         }
         storage.removePojo(targetRemove);
+        resp.setStatus(HttpServletResponse.SC_OK);
     }
 
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    private void updatePojo(HttpServletRequest req, HttpServletResponse resp) {
+        try {
+            String updateParam = req.getParameter("update");
+            WebUpdate update = gson.fromJson(updateParam, WebUpdate.class);
+            Update targetUpdate = storage.createUpdate();
+            targetUpdate = targetUpdate.from(getCategoryFromId(update.getCategoryId()));
+            List<Qualifier<?>> qualifiers = update.getQualifiers();
+            for (Qualifier qualifier : qualifiers) {
+                assert (qualifier.getCriteria() == Criteria.EQUALS);
+                targetUpdate = targetUpdate.where(qualifier.getKey(), qualifier.getValue());
+            }
+            String valuesParam = req.getParameter("values");
+            JsonParser parser = new JsonParser();
+            JsonArray jsonArray = parser.parse(valuesParam).getAsJsonArray();
+            List<WebUpdate.UpdateValue> updates = update.getUpdates();
+            int index = 0;
+            for (WebUpdate.UpdateValue updateValue : updates) {
+                Class valueClass = Class.forName(updateValue.getValueClass());
+                Object value = gson.fromJson(jsonArray.get(index), valueClass);
+                index++;
+                Key key = updateValue.getKey();
+                targetUpdate.set(key, value);
+            }
+            storage.updatePojo(targetUpdate);
+            resp.setStatus(HttpServletResponse.SC_OK);
+        } catch (ClassNotFoundException ex) {
+            ex.printStackTrace();
+            resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+        }
+    }
 
     @SuppressWarnings({ "rawtypes", "unchecked" })
     private void findPojo(HttpServletRequest req, HttpServletResponse resp) throws IOException {
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/RESTStorageEndpointTest.java	Thu Oct 18 00:25:04 2012 +0200
+++ b/web/server/src/test/java/com/redhat/thermostat/web/server/RESTStorageEndpointTest.java	Fri Oct 19 19:53:15 2012 +0200
@@ -73,6 +73,7 @@
 import com.redhat.thermostat.common.storage.Query.Criteria;
 import com.redhat.thermostat.common.storage.Remove;
 import com.redhat.thermostat.common.storage.Storage;
+import com.redhat.thermostat.common.storage.Update;
 import com.redhat.thermostat.test.FreePortFinder;
 import com.redhat.thermostat.test.FreePortFinder.TryPort;
 import com.redhat.thermostat.web.client.RESTStorage;
@@ -80,6 +81,7 @@
 import com.redhat.thermostat.web.common.StorageWrapper;
 import com.redhat.thermostat.web.common.WebInsert;
 import com.redhat.thermostat.web.common.WebRemove;
+import com.redhat.thermostat.web.common.WebUpdate;
 
 public class RESTStorageEndpointTest {
 
@@ -283,6 +285,42 @@
         verify(mockStorage).removePojo(mockRemove);
     }
 
+    @Test
+    public void testUpdatePojo() throws IOException {
+
+        Update mockUpdate = mock(Update.class);
+        when(mockUpdate.from(any(Category.class))).thenReturn(mockUpdate);
+        when(mockUpdate.where(any(Key.class), any())).thenReturn(mockUpdate);
+        when(mockUpdate.set(any(Key.class), any())).thenReturn(mockUpdate);
+        when(mockStorage.createUpdate()).thenReturn(mockUpdate);
+
+        String endpoint = getEndpoint();
+
+        URL url = new URL(endpoint + "/update-pojo");
+        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+        conn.setDoOutput(true);
+        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
+        Map<Category,Integer> categoryIds = new HashMap<>();
+        categoryIds.put(category, categoryId);
+        WebUpdate update = new WebUpdate(categoryIds).from(category).where(key1, "test").set(key1, "fluff").set(key2, 42);
+        Gson gson = new Gson();
+        OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream());
+        out.write("update=");
+        gson.toJson(update, out);
+        out.write("&values=");
+        gson.toJson(new Object[] {"fluff", 42 }, out);
+        out.write("\n");
+        out.flush();
+
+        assertEquals(200, conn.getResponseCode());
+        verify(mockStorage).createUpdate();
+        verify(mockUpdate).from(category);
+        verify(mockUpdate).where(key1, "test");
+        verify(mockUpdate).set(key1, "fluff");
+        verify(mockUpdate).set(key2, 42);
+        verify(mockStorage).updatePojo(mockUpdate);
+    }
+
 
     private void registerCategory() {
         try {