changeset 1239:cd020319d8ed

PR1524: DB write operations should return int on apply(). Reviewed-by: omajid Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-August/008021.html
author Severin Gehwolf <sgehwolf@redhat.com>
date Fri, 23 Aug 2013 17:08:35 +0200
parents 852cfb9a5fb9
children 85f78efc9db9
files client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/CleanDataCommand.java host-cpu/common/src/main/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOImpl.java host-cpu/common/src/test/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOTest.java host-memory/common/src/main/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOImpl.java host-memory/common/src/test/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOTest.java numa/common/src/main/java/com/redhat/thermostat/numa/common/internal/NumaDAOImpl.java numa/common/src/test/java/com/redhat/thermostat/numa/common/internal/NumaDAOImplTest.java storage/core/src/main/java/com/redhat/thermostat/storage/core/Add.java storage/core/src/main/java/com/redhat/thermostat/storage/core/Categories.java storage/core/src/main/java/com/redhat/thermostat/storage/core/DataModifyingStatement.java storage/core/src/main/java/com/redhat/thermostat/storage/core/QueuedStorage.java storage/core/src/main/java/com/redhat/thermostat/storage/core/Remove.java storage/core/src/main/java/com/redhat/thermostat/storage/core/Replace.java storage/core/src/main/java/com/redhat/thermostat/storage/core/Storage.java storage/core/src/main/java/com/redhat/thermostat/storage/core/Update.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/AgentInfoDAOImpl.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/BackendInfoDAOImpl.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/HostInfoDAOImpl.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/NetworkInterfaceInfoDAOImpl.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/VmInfoDAOImpl.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/PreparedStatementImpl.java storage/core/src/test/java/com/redhat/thermostat/storage/core/QueuedStorageTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/AgentInfoDAOTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/BackendInfoDAOTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/HostInfoDAOTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/NetworkInterfaceInfoDAOTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/VmInfoDAOTest.java storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorage.java storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoUpdate.java storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorageTest.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImpl.java thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplTest.java vm-classstat/common/src/main/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOImpl.java vm-classstat/common/src/test/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOTest.java vm-cpu/common/src/main/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOImpl.java vm-cpu/common/src/test/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOTest.java vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOImpl.java vm-heap-analysis/common/src/test/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOTest.java vm-jmx/common/src/main/java/com/redhat/thermostat/vm/jmx/common/internal/JmxNotificationDAOImpl.java vm-jmx/common/src/test/java/com/redhat/thermostat/vm/jmx/common/internal/JmxNotificationDAOImplTest.java vm-memory/common/src/main/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOImpl.java vm-memory/common/src/test/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOTest.java web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebStorage.java web/client/src/test/java/com/redhat/thermostat/web/client/internal/WebStorageTest.java web/common/src/main/java/com/redhat/thermostat/web/common/WebAdd.java web/common/src/main/java/com/redhat/thermostat/web/common/WebRemove.java web/common/src/main/java/com/redhat/thermostat/web/common/WebReplace.java web/common/src/main/java/com/redhat/thermostat/web/common/WebUpdate.java web/server/src/main/java/com/redhat/thermostat/web/server/WebStorageEndPoint.java web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndpointTest.java
diffstat 50 files changed, 313 insertions(+), 222 deletions(-) [+]
line wrap: on
line diff
--- a/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/CleanDataCommand.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/CleanDataCommand.java	Fri Aug 23 17:08:35 2013 +0200
@@ -173,7 +173,7 @@
     }
 
     private Set<String> getAllRegisteredAgents(Storage storage) {
-        List<Category> categories = Categories.getAllCategories();
+        List<Category<?>> categories = Categories.getAllCategories();
         Set<String> agents = new HashSet<>();
         PreparedStatement<BasePojo> prepared = null;
         Cursor<BasePojo> agentCursor = null;
--- a/host-cpu/common/src/main/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOImpl.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/host-cpu/common/src/main/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOImpl.java	Fri Aug 23 17:08:35 2013 +0200
@@ -64,7 +64,7 @@
 
     @Override
     public void putCpuStat(CpuStat stat) {
-        Add add = storage.createAdd(cpuStatCategory);
+        Add<CpuStat> add = storage.createAdd(cpuStatCategory);
         add.setPojo(stat);
         add.apply();
     }
--- a/host-cpu/common/src/test/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOTest.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/host-cpu/common/src/test/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOTest.java	Fri Aug 23 17:08:35 2013 +0200
@@ -40,6 +40,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
@@ -55,7 +56,6 @@
 import com.redhat.thermostat.host.cpu.common.CpuStatDAO;
 import com.redhat.thermostat.host.cpu.common.model.CpuStat;
 import com.redhat.thermostat.storage.core.Add;
-import com.redhat.thermostat.storage.core.Category;
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.DescriptorParsingException;
 import com.redhat.thermostat.storage.core.HostRef;
@@ -152,8 +152,9 @@
     @Test
     public void testPutCpuStat() {
         Storage storage = mock(Storage.class);
-        Add add = mock(Add.class);
-        when(storage.createAdd(any(Category.class))).thenReturn(add);
+        @SuppressWarnings("unchecked")
+        Add<CpuStat> add = mock(Add.class);
+        when(storage.createAdd(eq(CpuStatDAO.cpuStatCategory))).thenReturn(add);
         
         CpuStat stat = new CpuStat(1,  new double[] {5.0, 10.0, 15.0});
         CpuStatDAO dao = new CpuStatDAOImpl(storage);
--- a/host-memory/common/src/main/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOImpl.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/host-memory/common/src/main/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOImpl.java	Fri Aug 23 17:08:35 2013 +0200
@@ -64,7 +64,7 @@
 
     @Override
     public void putMemoryStat(MemoryStat stat) {
-        Add add = storage.createAdd(memoryStatCategory);
+        Add<MemoryStat> add = storage.createAdd(memoryStatCategory);
         add.setPojo(stat);
         add.apply();
     }
--- a/host-memory/common/src/test/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOTest.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/host-memory/common/src/test/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOTest.java	Fri Aug 23 17:08:35 2013 +0200
@@ -38,6 +38,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.eq;
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
@@ -52,7 +53,6 @@
 import com.redhat.thermostat.host.memory.common.MemoryStatDAO;
 import com.redhat.thermostat.host.memory.common.model.MemoryStat;
 import com.redhat.thermostat.storage.core.Add;
-import com.redhat.thermostat.storage.core.Category;
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.DescriptorParsingException;
 import com.redhat.thermostat.storage.core.HostRef;
@@ -138,8 +138,9 @@
     @Test
     public void testPutMemoryStat() {
         Storage storage = mock(Storage.class);
-        Add add = mock(Add.class);
-        when(storage.createAdd(any(Category.class))).thenReturn(add);
+        @SuppressWarnings("unchecked")
+        Add<MemoryStat> add = mock(Add.class);
+        when(storage.createAdd(eq(MemoryStatDAO.memoryStatCategory))).thenReturn(add);
 
         MemoryStat stat = new MemoryStat(TIMESTAMP, TOTAL, FREE, BUFFERS, CACHED, SWAP_TOTAL, SWAP_FREE, COMMIT_LIMIT);
         MemoryStatDAO dao = new MemoryStatDAOImpl(storage);
--- a/numa/common/src/main/java/com/redhat/thermostat/numa/common/internal/NumaDAOImpl.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/numa/common/src/main/java/com/redhat/thermostat/numa/common/internal/NumaDAOImpl.java	Fri Aug 23 17:08:35 2013 +0200
@@ -51,7 +51,6 @@
 import com.redhat.thermostat.storage.core.HostRef;
 import com.redhat.thermostat.storage.core.Key;
 import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.Replace;
 import com.redhat.thermostat.storage.core.StatementDescriptor;
 import com.redhat.thermostat.storage.core.StatementExecutionException;
 import com.redhat.thermostat.storage.core.Storage;
@@ -75,7 +74,7 @@
 
     @Override
     public void putNumaStat(NumaStat stat) {
-        Add add = storage.createAdd(numaStatCategory);
+        Add<NumaStat> add = storage.createAdd(numaStatCategory);
         add.setPojo(stat);
         add.apply();
     }
@@ -87,7 +86,7 @@
 
     @Override
     public void putNumberOfNumaNodes(int numNodes) {
-        Add replace = storage.createAdd(numaHostCategory);
+        Add<NumaHostInfo> replace = storage.createAdd(numaHostCategory);
         NumaHostInfo numaHostInfo = new NumaHostInfo();
         numaHostInfo.setNumNumaNodes(numNodes);
         replace.setPojo(numaHostInfo);
--- a/numa/common/src/test/java/com/redhat/thermostat/numa/common/internal/NumaDAOImplTest.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/numa/common/src/test/java/com/redhat/thermostat/numa/common/internal/NumaDAOImplTest.java	Fri Aug 23 17:08:35 2013 +0200
@@ -38,6 +38,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -53,7 +54,6 @@
 import com.redhat.thermostat.numa.common.NumaNodeStat;
 import com.redhat.thermostat.numa.common.NumaStat;
 import com.redhat.thermostat.storage.core.Add;
-import com.redhat.thermostat.storage.core.Category;
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.DescriptorParsingException;
 import com.redhat.thermostat.storage.core.HostRef;
@@ -93,7 +93,8 @@
     @Test
     public void testPutNumaStat() {
 
-        Add add = mock(Add.class);
+        @SuppressWarnings("unchecked")
+        Add<NumaStat> add = mock(Add.class);
         when(storage.createAdd(NumaDAO.numaStatCategory)).thenReturn(add);
 
         NumaNodeStat stat = new NumaNodeStat();
@@ -122,8 +123,9 @@
     @Test
     public void testPutNumberOfNumaNodes() {
         Storage storage = mock(Storage.class);
-        Add add = mock(Add.class);
-        when(storage.createAdd(any(Category.class))).thenReturn(add);
+        @SuppressWarnings("unchecked")
+        Add<NumaHostInfo> add = mock(Add.class);
+        when(storage.createAdd(eq(NumaDAO.numaHostCategory))).thenReturn(add);
 
         NumaDAOImpl dao = new NumaDAOImpl(storage);
 
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/Add.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/Add.java	Fri Aug 23 17:08:35 2013 +0200
@@ -47,18 +47,18 @@
  * @see Replace
  * @see Update
  */
-public interface Add {
+public interface Add<T extends Pojo> extends DataModifyingStatement<T> {
 
     /**
-     * Sets the POJO that is to be put into the storage.
+     * Sets the POJO that is to be added into storage.
      *
-     * @param pojo the pojo to be put into the storage
+     * @param pojo the pojo to be added into storage
      */
     void setPojo(Pojo pojo);
 
     /**
-     * Applies this {@code Add} operation to the storage.
+     * Applies this {@code Add} operation to storage.
      */
-    void apply();
+    int apply();
 }
 
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/Categories.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/Categories.java	Fri Aug 23 17:08:35 2013 +0200
@@ -44,29 +44,29 @@
 
 public class Categories {
 
-    private static final Map<String, Category> namesToCategories = new HashMap<>();
+    private static final Map<String, Category<?>> namesToCategories = new HashMap<>();
 
     public static synchronized boolean contains(String name) {
         return namesToCategories.containsKey(name);
     }
 
-    public static synchronized void add(Category category) {
+    public static synchronized void add(Category<?> category) {
         if (namesToCategories.containsKey(category.getName())) {
             throw new IllegalArgumentException("category already registered");
         }
         namesToCategories.put(category.getName(), category);
     }
 
-    public static synchronized void remove(Category category) {
+    public static synchronized void remove(Category<?> category) {
         namesToCategories.remove(category.getName());
     }
 
-    public static synchronized Category getByName(String categoryName) {
+    public static synchronized Category<?> getByName(String categoryName) {
         return namesToCategories.get(categoryName);
     }
 
-    public static synchronized List<Category> getAllCategories() {
-        return Collections.unmodifiableList(new ArrayList<Category>(namesToCategories.values()));
+    public static synchronized List<Category<?>> getAllCategories() {
+        return Collections.unmodifiableList(new ArrayList<Category<?>>(namesToCategories.values()));
     }
 
 }
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/DataModifyingStatement.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/DataModifyingStatement.java	Fri Aug 23 17:08:35 2013 +0200
@@ -11,10 +11,21 @@
 public interface DataModifyingStatement<T extends Pojo> extends Statement<T> {
 
     /**
+     * Default success status. The status code itself has no meaning other than
+     * indicating success. Suitable to be returned on {@link #apply()}.
+     */
+    public static final int DEFAULT_STATUS_SUCCESS = 0;
+    /**
+     * Default failure status. The status code itself has no meaning other than
+     * indicating failure. Suitable to be returned on {@link #apply()}.
+     */
+    public static final int DEFAULT_STATUS_FAILURE = -1;
+    
+    /**
      * Executes this statement.
      * 
-     * @return a number greater than zero on success. A negative failure code
-     *         otherwise.
+     * @return a number greater than or equal to zero on success. A negative
+     *         failure code otherwise.
      */
-    int execute();
+    int apply();
 }
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/QueuedStorage.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/QueuedStorage.java	Fri Aug 23 17:08:35 2013 +0200
@@ -51,7 +51,7 @@
 
     private static final int SHUTDOWN_TIMEOUT_SECONDS = 3;
 
-    private class QueuedReplace extends AddReplaceHelper implements Replace {
+    private class QueuedReplace<T extends Pojo> extends AddReplaceHelper implements Replace<T> {
 
         private Expression expression;
         
@@ -60,8 +60,9 @@
         }
         
         @Override
-        public void apply() {
+        public int apply() {
             replaceImpl(getCategory(), getPojo(), expression);
+            return DataModifyingStatement.DEFAULT_STATUS_SUCCESS;
         }
 
         @Override
@@ -71,23 +72,24 @@
         
     }
 
-    private class QueuedAdd extends AddReplaceHelper implements Add {
+    private class QueuedAdd<T extends Pojo> extends AddReplaceHelper implements Add<T> {
 
         private QueuedAdd(Category<?> category) {
             super(category);
         }
         
         @Override
-        public void apply() {
+        public int apply() {
             addImpl(getCategory(), getPojo());
+            return DataModifyingStatement.DEFAULT_STATUS_SUCCESS;
         }
         
     }
 
-    private class QueuedUpdate implements Update {
-        private Update delegateUpdate;
+    private class QueuedUpdate<T extends Pojo> implements Update<T> {
+        private Update<T> delegateUpdate;
 
-        QueuedUpdate(Update delegateUpdate) {
+        QueuedUpdate(Update<T> delegateUpdate) {
             this.delegateUpdate = delegateUpdate;
         }
 
@@ -98,12 +100,12 @@
         }
 
         @Override
-        public <T> void set(Key<T> key, T value) {
+        public <S> void set(Key<S> key, S value) {
             delegateUpdate.set(key, value);
         }
 
         @Override
-        public void apply() {
+        public int apply() {
             executor.execute(new Runnable() {
                 
                 @Override
@@ -112,6 +114,7 @@
                 }
 
             });
+            return DataModifyingStatement.DEFAULT_STATUS_SUCCESS;
         }
 
     }
@@ -148,14 +151,14 @@
     }
 
     @Override
-    public Add createAdd(Category<?> into) {
-        QueuedAdd add = new QueuedAdd(into);
+    public <T extends Pojo> Add<T> createAdd(Category<T> into) {
+        QueuedAdd<T> add = new QueuedAdd<>(into);
         return add;
     }
 
     @Override
-    public Replace createReplace(Category<?> into) {
-        QueuedReplace replace = new QueuedReplace(into);
+    public <T extends Pojo> Replace<T> createReplace(Category<T> into) {
+        QueuedReplace<T> replace = new QueuedReplace<>(into);
         return replace;
     }
 
@@ -165,7 +168,7 @@
             
             @Override
             public void run() {
-                Replace replace = delegate.createReplace(category);
+                Replace<?> replace = delegate.createReplace(category);
                 replace.setPojo(pojo);
                 replace.where(expression);
                 replace.apply();
@@ -181,7 +184,7 @@
             
             @Override
             public void run() {
-                Add add = delegate.createAdd(category);
+                Add<?> add = delegate.createAdd(category);
                 add.setPojo(pojo);
                 add.apply();
             }
@@ -224,13 +227,13 @@
     }
 
     @Override
-    public Update createUpdate(Category<?> category) {
-        QueuedUpdate update = new QueuedUpdate(delegate.createUpdate(category));
+    public <T extends Pojo> Update<T> createUpdate(Category<T> category) {
+        QueuedUpdate<T> update = new QueuedUpdate<>(delegate.createUpdate(category));
         return update;
     }
 
     @Override
-    public Remove createRemove(Category<?> category) {
+    public <T extends Pojo> Remove<T> createRemove(Category<T> category) {
         return delegate.createRemove(category);
     }
 
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/Remove.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/Remove.java	Fri Aug 23 17:08:35 2013 +0200
@@ -37,6 +37,7 @@
 
 package com.redhat.thermostat.storage.core;
 
+import com.redhat.thermostat.storage.model.Pojo;
 import com.redhat.thermostat.storage.query.Expression;
 
 /**
@@ -46,7 +47,7 @@
  * @see Update
  * @see Replace
  */
-public interface Remove {
+public interface Remove<T extends Pojo> extends DataModifyingStatement<T> {
 
     /**
      * Boolean expression in order to restrict the set of records to be removed
@@ -60,7 +61,7 @@
     /**
      * Applies this remove operation.
      */
-    void apply();
+    int apply();
 
 }
 
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/Replace.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/Replace.java	Fri Aug 23 17:08:35 2013 +0200
@@ -56,12 +56,13 @@
  * @see Remove
  * @see Update
  */
-public interface Replace {
+public interface Replace<T extends Pojo> extends DataModifyingStatement<T> {
 
     /**
      * Sets the POJO that will be used to replace the value in storage.
      *
-     * @param pojo the pojo to be put into the storage
+     * @param pojo the pojo which describes the updated values or the new
+     *             record to be added to storage.
      */
     void setPojo(Pojo pojo);
 
@@ -73,7 +74,7 @@
     /**
      * Applies this {@code Replace} operation to the storage.
      */
-    void apply();
+    int apply();
 
 }
 
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/Storage.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/Storage.java	Fri Aug 23 17:08:35 2013 +0200
@@ -80,8 +80,8 @@
      */
     Connection getConnection();
 
-    Add createAdd(Category<?> category);
-    Replace createReplace(Category<?> category);
+    <T extends Pojo> Add<T> createAdd(Category<T> category);
+    <T extends Pojo> Replace<T> createReplace(Category<T> category);
 
     /**
      * Drop all data related to the specified agent.
@@ -92,8 +92,8 @@
 
     InputStream loadFile(String filename);
 
-    Update createUpdate(Category<?> category);
-    Remove createRemove(Category<?> category);
+    <T extends Pojo> Update<T> createUpdate(Category<T> category);
+    <T extends Pojo> Remove<T> createRemove(Category<T> category);
 
     void shutdown();
 
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/Update.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/Update.java	Fri Aug 23 17:08:35 2013 +0200
@@ -36,6 +36,7 @@
 
 package com.redhat.thermostat.storage.core;
 
+import com.redhat.thermostat.storage.model.Pojo;
 import com.redhat.thermostat.storage.query.Expression;
 
 /**
@@ -45,7 +46,7 @@
  * @see Replace
  * @see Remove
  */
-public interface Update {
+public interface Update<T extends Pojo> extends DataModifyingStatement<T> {
 
     /**
      * Given a boolean expression, this method specifies a where condition for
@@ -67,11 +68,11 @@
      * @param value
      *            the value to set
      */
-    <T> void set(Key<T> key, T value);
+    <S> void set(Key<S> key, S value);
 
     /**
      * Applies this update operation.
      */
-    void apply();
+    int apply();
 }
 
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/AgentInfoDAOImpl.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/AgentInfoDAOImpl.java	Fri Aug 23 17:08:35 2013 +0200
@@ -182,7 +182,7 @@
 
     @Override
     public void addAgentInformation(AgentInformation agentInfo) {
-        Add replace = storage.createAdd(CATEGORY);
+        Add<AgentInformation> replace = storage.createAdd(CATEGORY);
         replace.setPojo(agentInfo);
         replace.apply();
     }
@@ -190,14 +190,14 @@
     @Override
     public void removeAgentInformation(AgentInformation agentInfo) {
         Expression expr = factory.equalTo(Key.AGENT_ID, agentInfo.getAgentId());
-        Remove remove = storage.createRemove(CATEGORY);
+        Remove<AgentInformation> remove = storage.createRemove(CATEGORY);
         remove.where(expr);
         remove.apply();
     }
 
     @Override
     public void updateAgentInformation(AgentInformation agentInfo) {
-        Update update = storage.createUpdate(CATEGORY);
+        Update<AgentInformation> update = storage.createUpdate(CATEGORY);
         Expression expr = factory.equalTo(Key.AGENT_ID, agentInfo.getAgentId());
         update.where(expr);
         update.set(START_TIME_KEY, agentInfo.getStartTime());
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/BackendInfoDAOImpl.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/BackendInfoDAOImpl.java	Fri Aug 23 17:08:35 2013 +0200
@@ -108,7 +108,7 @@
 
     @Override
     public void addBackendInformation(BackendInformation info) {
-        Add add = storage.createAdd(BackendInfoDAO.CATEGORY);
+        Add<BackendInformation> add = storage.createAdd(BackendInfoDAO.CATEGORY);
         add.setPojo(info);
         add.apply();
     }
@@ -116,7 +116,7 @@
     @Override
     public void removeBackendInformation(BackendInformation info) {
         Expression expr = factory.equalTo(BACKEND_NAME, info.getName());
-        Remove remove = storage.createRemove(CATEGORY);
+        Remove<BackendInformation> remove = storage.createRemove(CATEGORY);
         remove.where(expr);
         remove.apply();
     }
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/HostInfoDAOImpl.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/HostInfoDAOImpl.java	Fri Aug 23 17:08:35 2013 +0200
@@ -120,7 +120,7 @@
 
     @Override
     public void putHostInfo(HostInfo info) {
-        Add add = storage.createAdd(hostInfoCategory);
+        Add<HostInfo> add = storage.createAdd(hostInfoCategory);
         add.setPojo(info);
         add.apply();
     }
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/NetworkInterfaceInfoDAOImpl.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/NetworkInterfaceInfoDAOImpl.java	Fri Aug 23 17:08:35 2013 +0200
@@ -100,7 +100,7 @@
 
     @Override
     public void putNetworkInterfaceInfo(NetworkInterfaceInfo info) {
-        Replace replace = storage.createReplace(networkInfoCategory);
+        Replace<NetworkInterfaceInfo> replace = storage.createReplace(networkInfoCategory);
         ExpressionFactory factory = new ExpressionFactory();
         String agentId = info.getAgentId();
         if (agentId == null) {
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/VmInfoDAOImpl.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/VmInfoDAOImpl.java	Fri Aug 23 17:08:35 2013 +0200
@@ -173,14 +173,14 @@
 
     @Override
     public void putVmInfo(VmInfo info) {
-        Add replace = storage.createAdd(vmInfoCategory);
+        Add<VmInfo> replace = storage.createAdd(vmInfoCategory);
         replace.setPojo(info);
         replace.apply();
     }
 
     @Override
     public void putVmStoppedTime(String vmId, long timestamp) {
-        Update update = storage.createUpdate(vmInfoCategory);
+        Update<VmInfo> update = storage.createUpdate(vmInfoCategory);
         Expression expr = factory.equalTo(Key.VM_ID, vmId);
         update.where(expr);
         update.set(VmInfoDAO.stopTimeKey, timestamp);
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/PreparedStatementImpl.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/PreparedStatementImpl.java	Fri Aug 23 17:08:35 2013 +0200
@@ -115,7 +115,7 @@
         } catch (Exception e) {
             throw new StatementExecutionException(e);
         }
-        return dmlStatement.execute();
+        return dmlStatement.apply();
     }
 
     @Override
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/core/QueuedStorageTest.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/core/QueuedStorageTest.java	Fri Aug 23 17:08:35 2013 +0200
@@ -198,14 +198,15 @@
 
     private QueuedStorage queuedStorage;
     private Storage delegateStorage;
-    private Add delegateAdd;
-    private Replace delegateReplace;
+    private Add<?> delegateAdd;
+    private Replace<?> delegateReplace;
 
     private TestExecutor executor;
     private TestExecutor fileExecutor;
 
     private InputStream expectedFile;
 
+    @SuppressWarnings("unchecked")
     @Before
     public void setUp() {
         executor = new TestExecutor();
@@ -215,7 +216,7 @@
         delegateAdd = mock(Add.class);
         delegateReplace = mock(Replace.class);
 
-        Remove remove = mock(Remove.class);
+        Remove<?> remove = mock(Remove.class);
         when(delegateStorage.createAdd(any(Category.class))).thenReturn(delegateAdd);
         when(delegateStorage.createReplace(any(Category.class))).thenReturn(delegateReplace);
         when(delegateStorage.createRemove(any(Category.class))).thenReturn(remove);
@@ -239,7 +240,7 @@
         Category<?> category = mock(Category.class);
         Pojo pojo = mock(Pojo.class);
 
-        Replace replace = queuedStorage.createReplace(category);
+        Replace<?> replace = queuedStorage.createReplace(category);
         replace.setPojo(pojo);
         Expression expression = new ExpressionFactory().equalTo(Key.AGENT_ID, "foo");
         replace.where(expression);
@@ -260,14 +261,15 @@
         assertNull(fileExecutor.getTask());
     }
 
+    @SuppressWarnings("unchecked")
     @Test
     public void testUpdatePojo() {
-        Update delegateUpdate = mock(Update.class);
+        Update<?> delegateUpdate = mock(Update.class);
         when(delegateStorage.createUpdate(any(Category.class))).thenReturn(delegateUpdate);
 
         Category<?> category = mock(Category.class);
 
-        Update update = queuedStorage.createUpdate(category);
+        Update<?> update = queuedStorage.createUpdate(category);
         verify(delegateStorage).createUpdate(category);
         verifyNoMoreInteractions(delegateStorage);
 
@@ -435,13 +437,13 @@
         }
 
         @Override
-        public Add createAdd(Category<?> category) {
+        public <T extends Pojo> Add<T> createAdd(Category<T> category) {
             // not implemented
             throw new AssertionError();
         }
 
         @Override
-        public Replace createReplace(Category<?> category) {
+        public <T extends Pojo> Replace<T> createReplace(Category<T> category) {
             // not implemented
             throw new AssertionError();
         }
@@ -466,13 +468,13 @@
         }
 
         @Override
-        public Update createUpdate(Category<?> category) {
+        public <T extends Pojo> Update<T> createUpdate(Category<T> category) {
             // not implemented
             throw new AssertionError();
         }
 
         @Override
-        public Remove createRemove(Category<?> category) {
+        public <T extends Pojo> Remove<T> createRemove(Category<T> category) {
             // not implemented
             throw new AssertionError();
         }
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/AgentInfoDAOTest.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/AgentInfoDAOTest.java	Fri Aug 23 17:08:35 2013 +0200
@@ -261,8 +261,9 @@
     @Test
     public void verifyAddAgentInformation() {
         Storage storage = mock(Storage.class);
-        Add add = mock(Add.class);
-        when(storage.createAdd(any(Category.class))).thenReturn(add);
+        @SuppressWarnings("unchecked")
+        Add<AgentInformation> add = mock(Add.class);
+        when(storage.createAdd(eq(AgentInfoDAO.CATEGORY))).thenReturn(add);
 
         AgentInfoDAO dao = new AgentInfoDAOImpl(storage);
 
@@ -276,9 +277,10 @@
     @Test
     public void verifyUpdateAgentInformation() {
 
-        Update mockUpdate = mock(Update.class);
+        @SuppressWarnings("unchecked")
+        Update<AgentInformation> mockUpdate = mock(Update.class);
         Storage storage = mock(Storage.class);
-        when(storage.createUpdate(any(Category.class))).thenReturn(mockUpdate);
+        when(storage.createUpdate(eq(AgentInfoDAO.CATEGORY))).thenReturn(mockUpdate);
         AgentInfoDAO dao = new AgentInfoDAOImpl(storage);
 
         dao.updateAgentInformation(agentInfo1);
@@ -297,7 +299,8 @@
 
     @Test
     public void verifyRemoveAgentInformation() {
-        Remove mockRemove = mock(Remove.class);
+        @SuppressWarnings("unchecked")
+        Remove<AgentInformation> mockRemove = mock(Remove.class);
         Storage storage = mock(Storage.class);
         when(storage.createRemove(eq(AgentInfoDAO.CATEGORY))).thenReturn(mockRemove);
         AgentInfoDAO dao = new AgentInfoDAOImpl(storage);
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/BackendInfoDAOTest.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/BackendInfoDAOTest.java	Fri Aug 23 17:08:35 2013 +0200
@@ -128,8 +128,9 @@
     @Test
     public void verifyAddBackendInformation() {
         Storage storage = mock(Storage.class);
-        Add add = mock(Add.class);
-        when(storage.createAdd(any(Category.class))).thenReturn(add);
+        @SuppressWarnings("unchecked")
+        Add<BackendInformation> add = mock(Add.class);
+        when(storage.createAdd(eq(BackendInfoDAO.CATEGORY))).thenReturn(add);
 
         BackendInfoDAO dao = new BackendInfoDAOImpl(storage);
 
@@ -176,7 +177,8 @@
 
     @Test
     public void verifyRemoveBackendInformation() {
-        Remove remove = mock(Remove.class);
+        @SuppressWarnings("unchecked")
+        Remove<BackendInformation> remove = mock(Remove.class);
         Storage storage = mock(Storage.class);
         when(storage.createRemove(eq(BackendInfoDAO.CATEGORY))).thenReturn(remove);
         BackendInfoDAO dao = new BackendInfoDAOImpl(storage);
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/HostInfoDAOTest.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/HostInfoDAOTest.java	Fri Aug 23 17:08:35 2013 +0200
@@ -40,6 +40,7 @@
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
@@ -51,7 +52,6 @@
 import org.junit.Test;
 
 import com.redhat.thermostat.storage.core.Add;
-import com.redhat.thermostat.storage.core.Category;
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.DescriptorParsingException;
 import com.redhat.thermostat.storage.core.HostRef;
@@ -212,8 +212,9 @@
     @Test
     public void testPutHostInfo() {
         Storage storage = mock(Storage.class);
-        Add add = mock(Add.class);
-        when(storage.createAdd(any(Category.class))).thenReturn(add);
+        @SuppressWarnings("unchecked")
+        Add<HostInfo> add = mock(Add.class);
+        when(storage.createAdd(eq(HostInfoDAO.hostInfoCategory))).thenReturn(add);
 
         AgentInfoDAO agentInfo = mock(AgentInfoDAO.class);
 
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/NetworkInterfaceInfoDAOTest.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/NetworkInterfaceInfoDAOTest.java	Fri Aug 23 17:08:35 2013 +0200
@@ -40,6 +40,7 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -50,7 +51,6 @@
 
 import org.junit.Test;
 
-import com.redhat.thermostat.storage.core.Category;
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.DescriptorParsingException;
 import com.redhat.thermostat.storage.core.HostRef;
@@ -147,8 +147,9 @@
     
     private void doTestPutNetworkInerfaceInfo(boolean agentIdFromStorage, String agentId) {
         Storage storage = mock(Storage.class);
-        Replace replace = mock(Replace.class);
-        when(storage.createReplace(any(Category.class))).thenReturn(replace);
+        @SuppressWarnings("unchecked")
+        Replace<NetworkInterfaceInfo> replace = mock(Replace.class);
+        when(storage.createReplace(eq(NetworkInterfaceInfoDAO.networkInfoCategory))).thenReturn(replace);
         if (agentIdFromStorage) {
             when(storage.getAgentId()).thenReturn(agentId);
         }
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/VmInfoDAOTest.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/VmInfoDAOTest.java	Fri Aug 23 17:08:35 2013 +0200
@@ -40,6 +40,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -54,7 +55,6 @@
 import org.junit.Test;
 
 import com.redhat.thermostat.storage.core.Add;
-import com.redhat.thermostat.storage.core.Category;
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.DescriptorParsingException;
 import com.redhat.thermostat.storage.core.HostRef;
@@ -315,8 +315,9 @@
     public void testPutVmInfo() {
 
         Storage storage = mock(Storage.class);
-        Add add = mock(Add.class);
-        when(storage.createAdd(any(Category.class))).thenReturn(add);
+        @SuppressWarnings("unchecked")
+        Add<VmInfo> add = mock(Add.class);
+        when(storage.createAdd(eq(VmInfoDAO.vmInfoCategory))).thenReturn(add);
 
         VmInfo info = new VmInfo(vmId, vmPid, startTime, stopTime, jVersion, jHome,
                 mainClass, commandLine, vmName, vmInfo, vmVersion, vmArgs,
@@ -331,9 +332,10 @@
 
     @Test
     public void testPutVmStoppedTime() {
-        Update mockUpdate = mock(Update.class);
+        @SuppressWarnings("unchecked")
+        Update<VmInfo> mockUpdate = mock(Update.class);
         Storage storage = mock(Storage.class);
-        when(storage.createUpdate(any(Category.class))).thenReturn(mockUpdate);
+        when(storage.createUpdate(eq(VmInfoDAO.vmInfoCategory))).thenReturn(mockUpdate);
 
         VmInfoDAO dao = new VmInfoDAOImpl(storage);
         dao.putVmStoppedTime(vmId, stopTime);
--- a/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorage.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorage.java	Fri Aug 23 17:08:35 2013 +0200
@@ -49,6 +49,7 @@
 import com.mongodb.DBCollection;
 import com.mongodb.DBCursor;
 import com.mongodb.DBObject;
+import com.mongodb.WriteResult;
 import com.mongodb.gridfs.GridFS;
 import com.mongodb.gridfs.GridFSDBFile;
 import com.mongodb.gridfs.GridFSInputFile;
@@ -100,20 +101,20 @@
         }
     }
 
-    private class MongoAdd extends AddReplaceHelper implements Add {
+    private class MongoAdd<T extends Pojo> extends AddReplaceHelper implements Add<T> {
 
         private MongoAdd(Category<?> category) {
             super(category);
         }
         
         @Override
-        public void apply() {
-            addImpl(getCategory(), getPojo());
+        public int apply() {
+            return addImpl(getCategory(), getPojo());
         }
         
     }
 
-    private class MongoReplace extends AddReplaceHelper implements Replace {
+    private class MongoReplace<T extends Pojo> extends AddReplaceHelper implements Replace<T> {
         
         private DBObject query;
         private final MongoExpressionParser parser;
@@ -124,13 +125,13 @@
         }
         
         @Override
-        public void apply() {
+        public int apply() {
             if (query == null) {
                 String msg = "where expression must be set. " +
                              "Please call where() before apply().";
                 throw new IllegalStateException(msg);
             }
-            replaceImpl(getCategory(), getPojo(), query);
+            return replaceImpl(getCategory(), getPojo(), query);
         }
 
         @Override
@@ -140,7 +141,7 @@
         
     }
     
-    private class MongoRemove implements Remove {
+    private class MongoRemove<T extends Pojo> implements Remove<T> {
 
         @SuppressWarnings("rawtypes")
         private final Category category;
@@ -162,8 +163,8 @@
         }
         
         @Override
-        public void apply() {
-            removePojo(category, query);
+        public int apply() {
+            return removePojo(category, query);
         }
         
     }
@@ -228,27 +229,35 @@
     }
 
     @Override
-    public Add createAdd(Category<?> into) {
-        MongoAdd add = new MongoAdd(into);
+    public <T extends Pojo> Add<T> createAdd(Category<T> into) {
+        MongoAdd<T> add = new MongoAdd<>(into);
         return add;
     }
 
     @Override
-    public Replace createReplace(Category<?> into) {
-        MongoReplace replace = new MongoReplace(into);
+    public <T extends Pojo> Replace<T> createReplace(Category<T> into) {
+        MongoReplace<T> replace = new MongoReplace<>(into);
         return replace;
     }
 
-    private void addImpl(final Category<?> cat, final Pojo pojo) {
+    private int addImpl(final Category<?> cat, final Pojo pojo) {
         DBCollection coll = getCachedCollection(cat);
         DBObject toInsert = preparePut(pojo);
-        coll.insert(toInsert);
+        WriteResult result = coll.insert(toInsert);
+        return numAffectedRecords(result);
     }
 
-    private void replaceImpl(final Category<?> cat, final Pojo pojo, final DBObject query) {
+    private int replaceImpl(final Category<?> cat, final Pojo pojo, final DBObject query) {
         DBCollection coll = getCachedCollection(cat);
         DBObject toInsert = preparePut(pojo);
-        coll.update(query, toInsert, true, false);
+        WriteResult result = coll.update(query, toInsert, true, false);
+        return numAffectedRecords(result);
+    }
+    
+    private int numAffectedRecords(WriteResult result) {
+        // response code corresponds to the number of records affected.
+        int responseCode = result.getN();
+        return responseCode;
     }
 
     private DBObject preparePut(final Pojo pojo) {
@@ -260,17 +269,19 @@
         return toInsert;
     }
 
-    void updatePojo(MongoUpdate mongoUpdate) {
+    int updatePojo(MongoUpdate<?> mongoUpdate) {
         Category<?> cat = mongoUpdate.getCategory();
         DBCollection coll = getCachedCollection(cat);
         DBObject query = mongoUpdate.getQuery();
         DBObject values = mongoUpdate.getValues();
-        coll.update(query, values);
+        WriteResult result = coll.update(query, values);
+        return numAffectedRecords(result);
     }
 
-    private void removePojo(Category<?> category, DBObject query) {
+    private int removePojo(Category<?> category, DBObject query) {
         DBCollection coll = getCachedCollection(category);
-        coll.remove(query);
+        WriteResult result = coll.remove(query);
+        return numAffectedRecords(result);
     }
 
     private DBCollection getCachedCollection(Category<?> category) {
@@ -337,13 +348,13 @@
     }
 
     @Override
-    public Update createUpdate(Category<?> category) {
-        return new MongoUpdate(this, category);
+    public <T extends Pojo> Update<T> createUpdate(Category<T> category) {
+        return new MongoUpdate<>(this, category);
     }
 
     @Override
-    public Remove createRemove(Category<?> category) {
-        return new MongoRemove(category);
+    public <T extends Pojo> Remove<T> createRemove(Category<T> category) {
+        return new MongoRemove<>(category);
     }
 
     <T extends Pojo> Cursor<T> findAllPojos(MongoQuery<T> mongoQuery, Class<T> resultClass) {
--- a/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoUpdate.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoUpdate.java	Fri Aug 23 17:08:35 2013 +0200
@@ -42,29 +42,30 @@
 import com.redhat.thermostat.storage.core.Category;
 import com.redhat.thermostat.storage.core.Key;
 import com.redhat.thermostat.storage.core.Update;
+import com.redhat.thermostat.storage.model.Pojo;
 import com.redhat.thermostat.storage.query.Expression;
 
-class MongoUpdate implements Update {
+class MongoUpdate<T extends Pojo> implements Update<T> {
 
     private static final String SET_MODIFIER = "$set";
 
     private MongoStorage storage;
     private DBObject query;
     private DBObject values;
-    private Category category;
+    private Category<?> category;
     private MongoExpressionParser parser;
 
-    public MongoUpdate(MongoStorage storage, Category category) {
+    public MongoUpdate(MongoStorage storage, Category<?> category) {
         this(storage, category, new MongoExpressionParser());
     }
     
-    MongoUpdate(MongoStorage storage, Category category, MongoExpressionParser parser) {
+    MongoUpdate(MongoStorage storage, Category<?> category, MongoExpressionParser parser) {
         this.storage = storage;
         this.category = category;
         this.parser = parser;
     }
 
-    Category getCategory() {
+    Category<?> getCategory() {
         return category;
     }
 
@@ -78,7 +79,7 @@
     }
 
     @Override
-    public <T> void set(Key<T> key, T value) {
+    public <S> void set(Key<S> key, S value) {
         if (values == null) {
             values = new BasicDBObject();
         }
@@ -90,8 +91,8 @@
     }
 
     @Override
-    public void apply() {
-        storage.updatePojo(this);
+    public int apply() {
+        return storage.updatePojo(this);
     }
 }
 
--- a/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorageTest.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorageTest.java	Fri Aug 23 17:08:35 2013 +0200
@@ -77,6 +77,7 @@
 import com.mongodb.DBObject;
 import com.mongodb.Mongo;
 import com.mongodb.MongoURI;
+import com.mongodb.WriteResult;
 import com.mongodb.gridfs.GridFS;
 import com.mongodb.gridfs.GridFSDBFile;
 import com.mongodb.gridfs.GridFSInputFile;
@@ -206,6 +207,19 @@
         when(testCollection.find()).thenReturn(cursor);
         when(testCollection.findOne(any(DBObject.class))).thenReturn(value1);
         when(testCollection.getCount()).thenReturn(2L);
+        
+        WriteResult mockWriteResult = mock(WriteResult.class);
+        // fake that 1 record was affected for all db write ops.
+        when(mockWriteResult.getN()).thenReturn(1);
+        // mock for remove
+        when(testCollection.remove(any(DBObject.class))).thenReturn(mockWriteResult);
+        // mock for update
+        when(testCollection.update(any(DBObject.class), any(DBObject.class))).thenReturn(mockWriteResult);
+        // mock for replace
+        when(testCollection.update(any(DBObject.class), any(DBObject.class), eq(true), eq(false))).thenReturn(mockWriteResult);
+        // mock for add
+        when(testCollection.insert(any(DBObject.class))).thenReturn(mockWriteResult);
+        
         emptyTestCollection = PowerMockito.mock(DBCollection.class);
         when(emptyTestCollection.getCount()).thenReturn(0L);
         when(db.collectionExists(anyString())).thenReturn(false);
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImpl.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImpl.java	Fri Aug 23 17:08:35 2013 +0200
@@ -138,7 +138,8 @@
     
     @Override
     public void saveCapabilities(VMThreadCapabilities caps) {
-        Replace replace = storage.createReplace(THREAD_CAPABILITIES);
+        @SuppressWarnings("unchecked")
+        Replace<VMThreadCapabilities> replace = storage.createReplace(THREAD_CAPABILITIES);
         ExpressionFactory factory = new ExpressionFactory();
         String agentId = caps.getAgentId();
         if (agentId == null) {
@@ -154,7 +155,8 @@
     
     @Override
     public void saveSummary(ThreadSummary summary) {
-        Add add = storage.createAdd(THREAD_SUMMARY);
+        @SuppressWarnings("unchecked")
+        Add<ThreadSummary> add = storage.createAdd(THREAD_SUMMARY);
         add.setPojo(summary);
         add.apply();
     }
@@ -210,7 +212,8 @@
 
     @Override
     public void saveHarvestingStatus(ThreadHarvestingStatus status) {
-        Add add = storage.createAdd(THREAD_HARVESTING_STATUS);
+        @SuppressWarnings("unchecked")
+        Add<ThreadHarvestingStatus> add = storage.createAdd(THREAD_HARVESTING_STATUS);
         add.setPojo(status);
         add.apply();
     }
@@ -241,7 +244,8 @@
 
     @Override
     public void saveThreadInfo(ThreadInfoData info) {
-        Add add = storage.createAdd(THREAD_INFO);
+        @SuppressWarnings("unchecked")
+        Add<ThreadInfoData> add = storage.createAdd(THREAD_INFO);
         add.setPojo(info);
         add.apply();
     }
@@ -297,7 +301,8 @@
 
     @Override
     public void saveDeadLockStatus(VmDeadLockData deadLockInfo) {
-        Add add = storage.createAdd(DEADLOCK_INFO);
+        @SuppressWarnings("unchecked")
+        Add<VmDeadLockData> add = storage.createAdd(DEADLOCK_INFO);
         add.setPojo(deadLockInfo);
         add.apply();
     }
--- a/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplTest.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplTest.java	Fri Aug 23 17:08:35 2013 +0200
@@ -42,6 +42,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.assertNull;
 import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -52,7 +53,6 @@
 import org.junit.Test;
 
 import com.redhat.thermostat.storage.core.Add;
-import com.redhat.thermostat.storage.core.Category;
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.DescriptorParsingException;
 import com.redhat.thermostat.storage.core.HostRef;
@@ -200,8 +200,9 @@
     
     private void doTestSaveVMCaps(boolean agentIdFromStorage, String agentId) {
         Storage storage = mock(Storage.class);
-        Replace replace = mock(Replace.class);
-        when(storage.createReplace(any(Category.class))).thenReturn(replace);
+        @SuppressWarnings("unchecked")
+        Replace<VMThreadCapabilities> replace = mock(Replace.class);
+        when(storage.createReplace(eq(ThreadDao.THREAD_CAPABILITIES))).thenReturn(replace);
         if (agentIdFromStorage) {
             when(storage.getAgentId()).thenReturn(agentId);
         }
@@ -274,7 +275,8 @@
     @Test
     public void testSaveDeadLockStatus() {
         Storage storage = mock(Storage.class);
-        Add add = mock(Add.class);
+        @SuppressWarnings("unchecked")
+        Add<VmDeadLockData> add = mock(Add.class);
         when(storage.createAdd(ThreadDaoImpl.DEADLOCK_INFO)).thenReturn(add);
 
         VmDeadLockData status = mock(VmDeadLockData.class);
@@ -322,7 +324,8 @@
     @Test
     public void testSetHarvestingStatus() {
         Storage storage = mock(Storage.class);
-        Add add = mock(Add.class);
+        @SuppressWarnings("unchecked")
+        Add<ThreadHarvestingStatus> add = mock(Add.class);
         when(storage.createAdd(ThreadDaoImpl.THREAD_HARVESTING_STATUS)).thenReturn(add);
 
         ThreadHarvestingStatus status = mock(ThreadHarvestingStatus.class);
--- a/vm-classstat/common/src/main/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOImpl.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/vm-classstat/common/src/main/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOImpl.java	Fri Aug 23 17:08:35 2013 +0200
@@ -63,7 +63,7 @@
 
     @Override
     public void putVmClassStat(VmClassStat stat) {
-        Add add = storage.createAdd(vmClassStatsCategory);
+        Add<VmClassStat> add = storage.createAdd(vmClassStatsCategory);
         add.setPojo(stat);
         add.apply();
     }
--- a/vm-classstat/common/src/test/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOTest.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/vm-classstat/common/src/test/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOTest.java	Fri Aug 23 17:08:35 2013 +0200
@@ -39,6 +39,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -50,7 +51,6 @@
 import org.junit.Test;
 
 import com.redhat.thermostat.storage.core.Add;
-import com.redhat.thermostat.storage.core.Category;
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.DescriptorParsingException;
 import com.redhat.thermostat.storage.core.HostRef;
@@ -133,8 +133,9 @@
     public void testPutVmClassStat() {
 
         Storage storage = mock(Storage.class);
-        Add add = mock(Add.class);
-        when(storage.createAdd(any(Category.class))).thenReturn(add);
+        @SuppressWarnings("unchecked")
+        Add<VmClassStat> add = mock(Add.class);
+        when(storage.createAdd(eq(VmClassStatDAO.vmClassStatsCategory))).thenReturn(add);
 
         VmClassStat stat = new VmClassStat(VM_ID, TIMESTAMP, LOADED_CLASSES);
         VmClassStatDAO dao = new VmClassStatDAOImpl(storage);
--- a/vm-cpu/common/src/main/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOImpl.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/vm-cpu/common/src/main/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOImpl.java	Fri Aug 23 17:08:35 2013 +0200
@@ -63,7 +63,7 @@
 
     @Override
     public void putVmCpuStat(VmCpuStat stat) {
-        Add add = storage.createAdd(vmCpuStatCategory);
+        Add<VmCpuStat> add = storage.createAdd(vmCpuStatCategory);
         add.setPojo(stat);
         add.apply();
     }
--- a/vm-cpu/common/src/test/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOTest.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/vm-cpu/common/src/test/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOTest.java	Fri Aug 23 17:08:35 2013 +0200
@@ -39,6 +39,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -51,7 +52,6 @@
 import org.junit.Test;
 
 import com.redhat.thermostat.storage.core.Add;
-import com.redhat.thermostat.storage.core.Category;
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.DescriptorParsingException;
 import com.redhat.thermostat.storage.core.HostRef;
@@ -134,8 +134,9 @@
     @Test
     public void testPutVmCpuStat() {
         Storage storage = mock(Storage.class);
-        Add add = mock(Add.class);
-        when(storage.createAdd(any(Category.class))).thenReturn(add);
+        @SuppressWarnings("unchecked")
+        Add<VmCpuStat> add = mock(Add.class);
+        when(storage.createAdd(eq(VmCpuStatDAO.vmCpuStatCategory))).thenReturn(add);
         
         VmCpuStat stat = new VmCpuStat(TIMESTAMP, VM_ID, CPU_LOAD);
         VmCpuStatDAO dao = new VmCpuStatDAOImpl(storage);
--- a/vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOImpl.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOImpl.java	Fri Aug 23 17:08:35 2013 +0200
@@ -97,7 +97,7 @@
         if (histogramData != null) {
             heapInfo.setHistogramId(histogramId);
         }
-        Add add = storage.createAdd(heapInfoCategory);
+        Add<HeapInfo> add = storage.createAdd(heapInfoCategory);
         add.setPojo(heapInfo);
         add.apply();
 
--- a/vm-heap-analysis/common/src/test/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOTest.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/vm-heap-analysis/common/src/test/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOTest.java	Fri Aug 23 17:08:35 2013 +0200
@@ -85,7 +85,7 @@
 
     private HeapDAO dao;
     private Storage storage;
-    private Add add;
+    private Add<HeapInfo> add;
     private HeapInfo heapInfo;
     private File heapDumpData;
     private ObjectHistogram histogram;
--- a/vm-jmx/common/src/main/java/com/redhat/thermostat/vm/jmx/common/internal/JmxNotificationDAOImpl.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/vm-jmx/common/src/main/java/com/redhat/thermostat/vm/jmx/common/internal/JmxNotificationDAOImpl.java	Fri Aug 23 17:08:35 2013 +0200
@@ -96,7 +96,7 @@
 
     @Override
     public void addNotificationStatus(JmxNotificationStatus status) {
-        Add add = storage.createAdd(NOTIFICATION_STATUS);
+        Add<JmxNotificationStatus> add = storage.createAdd(NOTIFICATION_STATUS);
         add.setPojo(status);
         add.apply();
     }
@@ -132,7 +132,7 @@
 
     @Override
     public void addNotification(JmxNotification notification) {
-        Add add = storage.createAdd(NOTIFICATIONS);
+        Add<JmxNotification> add = storage.createAdd(NOTIFICATIONS);
         add.setPojo(notification);
         add.apply();
     }
--- a/vm-jmx/common/src/test/java/com/redhat/thermostat/vm/jmx/common/internal/JmxNotificationDAOImplTest.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/vm-jmx/common/src/test/java/com/redhat/thermostat/vm/jmx/common/internal/JmxNotificationDAOImplTest.java	Fri Aug 23 17:08:35 2013 +0200
@@ -98,7 +98,8 @@
 
     @Test
     public void verifyAddNotificationStatus() {
-        Add add = mock(Add.class);
+        @SuppressWarnings("unchecked")
+        Add<JmxNotificationStatus> add = mock(Add.class);
         when(storage.createAdd(JmxNotificationDAOImpl.NOTIFICATION_STATUS)).thenReturn(add);
 
         JmxNotificationStatus data = mock(JmxNotificationStatus.class);
@@ -143,7 +144,8 @@
 
     @Test
     public void verfiyAddNotification() {
-        Add add = mock(Add.class);
+        @SuppressWarnings("unchecked")
+        Add<JmxNotification> add = mock(Add.class);
         when(storage.createAdd(JmxNotificationDAOImpl.NOTIFICATIONS)).thenReturn(add);
 
         JmxNotification data = mock(JmxNotification.class);
--- a/vm-memory/common/src/main/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOImpl.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/vm-memory/common/src/main/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOImpl.java	Fri Aug 23 17:08:35 2013 +0200
@@ -101,7 +101,7 @@
 
     @Override
     public void putVmMemoryStat(VmMemoryStat stat) {
-        Add add = storage.createAdd(vmMemoryStatsCategory);
+        Add<VmMemoryStat> add = storage.createAdd(vmMemoryStatsCategory);
         add.setPojo(stat);
         add.apply();
     }
--- a/vm-memory/common/src/test/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOTest.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/vm-memory/common/src/test/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOTest.java	Fri Aug 23 17:08:35 2013 +0200
@@ -39,6 +39,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -53,7 +54,6 @@
 import org.junit.Test;
 
 import com.redhat.thermostat.storage.core.Add;
-import com.redhat.thermostat.storage.core.Category;
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.DescriptorParsingException;
 import com.redhat.thermostat.storage.core.HostRef;
@@ -205,8 +205,9 @@
         VmMemoryStat stat = new VmMemoryStat(1, "vmId", generations.toArray(new Generation[generations.size()]));
 
         Storage storage = mock(Storage.class);
-        Add add = mock(Add.class);
-        when(storage.createAdd(any(Category.class))).thenReturn(add);
+        @SuppressWarnings("unchecked")
+        Add<VmMemoryStat> add = mock(Add.class);
+        when(storage.createAdd(eq(VmMemoryStatDAO.vmMemoryStatsCategory))).thenReturn(add);
         
         VmMemoryStatDAO dao = new VmMemoryStatDAOImpl(storage);
         dao.putVmMemoryStat(stat);
--- a/web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebStorage.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebStorage.java	Fri Aug 23 17:08:35 2013 +0200
@@ -94,6 +94,7 @@
 import com.redhat.thermostat.storage.core.Category;
 import com.redhat.thermostat.storage.core.Connection;
 import com.redhat.thermostat.storage.core.Cursor;
+import com.redhat.thermostat.storage.core.DataModifyingStatement;
 import com.redhat.thermostat.storage.core.DescriptorParsingException;
 import com.redhat.thermostat.storage.core.IllegalDescriptorException;
 import com.redhat.thermostat.storage.core.IllegalPatchException;
@@ -299,49 +300,49 @@
 
     }
 
-    private class WebAddImpl extends WebAdd {
+    private class WebAddImpl<T extends Pojo> extends WebAdd<T> {
 
         private WebAddImpl(int categoryId) {
             super(categoryId);
         }
         
         @Override
-        public void apply() {
-            addImpl(this);
+        public int apply() {
+            return addImpl(this);
         }
         
     }
 
-    private class WebReplaceImpl extends WebReplace {
+    private class WebReplaceImpl<T extends Pojo> extends WebReplace<T> {
         
         private WebReplaceImpl(int categoryId) {
             super(categoryId);
         }
         
         @Override
-        public void apply() {
-            replaceImpl(this);
+        public int apply() {
+            return replaceImpl(this);
         }
         
     }
 
-    private class WebUpdateImpl extends WebUpdate implements Update {
+    private class WebUpdateImpl<T extends Pojo> extends WebUpdate<T> {
     
         @Override
-        public void apply() {
-            updatePojo(this);
+        public int apply() {
+            return updatePojo(this);
         }
     }
     
-    private class WebRemoveImpl extends WebRemove {
+    private class WebRemoveImpl<T extends Pojo> extends WebRemove<T> {
         
         private WebRemoveImpl(int categoryId) {
             super(categoryId);
         }
         
         @Override
-        public void apply() {
-            removePojo(this);
+        public int apply() {
+            return removePojo(this);
         }
         
     }
@@ -533,13 +534,13 @@
     }
 
     @Override
-    public Remove createRemove(Category<?> category) {
-        return new WebRemoveImpl(categoryIds.get(category));
+    public <T extends Pojo> Remove<T> createRemove(Category<T> category) {
+        return new WebRemoveImpl<>(categoryIds.get(category));
     }
 
     @Override
-    public Update createUpdate(Category<?> category) {
-        WebUpdateImpl updateImpl = new WebUpdateImpl();
+    public <T extends Pojo> Update<T> createUpdate(Category<T> category) {
+        WebUpdateImpl<T> updateImpl = new WebUpdateImpl<>();
         updateImpl.setCategoryId(categoryIds.get(category));
         return updateImpl;
     }
@@ -635,20 +636,20 @@
     }
 
     @Override
-    public Add createAdd(Category<?> into) {
+    public <T extends Pojo> Add<T> createAdd(Category<T> into) {
         int categoryId = getCategoryId(into);
-        WebAdd add = new WebAddImpl(categoryId);
+        WebAdd<T> add = new WebAddImpl<>(categoryId);
         return add;
     }
 
     @Override
-    public Replace createReplace(Category<?> into) {
+    public <T extends Pojo> Replace<T> createReplace(Category<T> into) {
         int categoryId = getCategoryId(into);
-        WebReplace replace = new WebReplaceImpl(categoryId);
+        WebReplace<T> replace = new WebReplaceImpl<>(categoryId);
         return replace;
     }
     
-    private void addImpl(final WebAdd add) throws StorageException {
+    private int addImpl(final WebAdd<?> add) throws StorageException {
         Pojo pojo = add.getPojo();
         maybeAddAgentId(pojo);
         NameValuePair pojoParam = new BasicNameValuePair("pojo",
@@ -657,9 +658,10 @@
                 gson.toJson(add));
         List<NameValuePair> formParams = Arrays.asList(addParam, pojoParam);
         post(endpoint + "/add-pojo", formParams).close();
+        return DataModifyingStatement.DEFAULT_STATUS_SUCCESS;
     }
 
-    private void replaceImpl(final WebReplace replace) throws StorageException {
+    private int replaceImpl(final WebReplace<?> replace) throws StorageException {
         Pojo pojo = replace.getPojo();
         maybeAddAgentId(pojo);
         NameValuePair replaceParam = new BasicNameValuePair("replace",
@@ -668,6 +670,7 @@
                 gson.toJson(pojo));
         List<NameValuePair> formParams = Arrays.asList(replaceParam, pojoParam);
         post(endpoint + "/replace-pojo", formParams).close();
+        return DataModifyingStatement.DEFAULT_STATUS_SUCCESS;
     }
 
     private void maybeAddAgentId(final Pojo pojo) throws AssertionError {
@@ -680,11 +683,12 @@
         }
     }
 
-    private void removePojo(Remove remove) throws StorageException {
+    private int removePojo(Remove<?> remove) throws StorageException {
         NameValuePair removeParam = new BasicNameValuePair("remove",
                 gson.toJson(remove));
         List<NameValuePair> formparams = Arrays.asList(removeParam);
         post(endpoint + "/remove-pojo", formparams).close();
+        return DataModifyingStatement.DEFAULT_STATUS_SUCCESS;
     }
 
     @Override
@@ -692,8 +696,8 @@
         this.agentId = agentId;
     }
 
-    private void updatePojo(Update update) throws StorageException {
-        WebUpdate webUp = (WebUpdate) update;
+    private int updatePojo(Update<?> update) throws StorageException {
+        WebUpdate<?> webUp = (WebUpdate<?>) update;
         List<WebUpdate.UpdateValue> updateValues = webUp.getUpdates();
         List<Object> values = new ArrayList<>(updateValues.size());
         for (WebUpdate.UpdateValue updateValue : updateValues) {
@@ -707,6 +711,7 @@
         List<NameValuePair> formparams = Arrays
                 .asList(updateParam, valuesParam);
         post(endpoint + "/update-pojo", formparams).close();
+        return DataModifyingStatement.DEFAULT_STATUS_SUCCESS;
     }
 
     public void setEndpoint(String endpoint) {
--- a/web/client/src/test/java/com/redhat/thermostat/web/client/internal/WebStorageTest.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/web/client/src/test/java/com/redhat/thermostat/web/client/internal/WebStorageTest.java	Fri Aug 23 17:08:35 2013 +0200
@@ -402,7 +402,7 @@
         UUID agentId = new UUID(1, 2);
         storage.setAgentId(agentId);
 
-        Add add = storage.createAdd(category);
+        Add<TestObj> add = storage.createAdd(category);
         add.setPojo(obj);
 
         prepareServer();
@@ -416,7 +416,8 @@
         assertEquals(2, params.length);
         String[] parts = params[0].split("=");
         assertEquals("add", parts[0]);
-        WebAdd add2 = gson.fromJson(parts[1], WebAdd.class);
+        @SuppressWarnings("unchecked")
+        WebAdd<TestObj> add2 = gson.fromJson(parts[1], WebAdd.class);
         assertEquals(42, add2.getCategoryId());
 
         parts = params[1].split("=");
@@ -439,7 +440,7 @@
         UUID agentId = new UUID(1, 2);
         storage.setAgentId(agentId);
 
-        Replace replace = storage.createReplace(category);
+        Replace<TestObj> replace = storage.createReplace(category);
         Expression expr = new ExpressionFactory().equalTo(key1, "fluff");
         replace.setPojo(obj);
         replace.where(expr);
@@ -459,7 +460,8 @@
         assertEquals(2, params.length);
         String[] parts = params[0].split("=");
         assertEquals("replace", parts[0]);
-        WebReplace insert = gson.fromJson(parts[1], WebReplace.class);
+        @SuppressWarnings("unchecked")
+        WebReplace<TestObj> insert = gson.fromJson(parts[1], WebReplace.class);
         assertEquals(42, insert.getCategoryId());
 
         parts = params[1].split("=");
@@ -474,7 +476,7 @@
 
     @Test
     public void testCreateRemove() {
-        WebRemove remove = (WebRemove) storage.createRemove(category);
+        WebRemove<?> remove = (WebRemove<?>) storage.createRemove(category);
         assertEquals(42, remove.getCategoryId());
         Expression expr = factory.equalTo(key1, "test");
         remove.where(expr);
@@ -484,7 +486,7 @@
     @Test
     public void testRemovePojo() throws UnsupportedEncodingException, IOException {
         Expression expr = factory.equalTo(key1, "test");
-        Remove remove = storage.createRemove(category);
+        Remove<?> remove = storage.createRemove(category);
         remove.where(expr);
 
         prepareServer();
@@ -500,7 +502,7 @@
         String line = URLDecoder.decode(bufRead.readLine(), "UTF-8");
         String[] parts = line.split("=");
         assertEquals("remove", parts[0]);
-        WebRemove actualRemove = gson.fromJson(parts[1], WebRemove.class);
+        WebRemove<?> actualRemove = gson.fromJson(parts[1], WebRemove.class);
         
         assertEquals(42, actualRemove.getCategoryId());
         assertEquals(expr, actualRemove.getWhereExpression());
@@ -508,7 +510,7 @@
 
     @Test
     public void testCreateUpdate() {
-        WebUpdate update = (WebUpdate) storage.createUpdate(category);
+        WebUpdate<?> update = (WebUpdate<?>) storage.createUpdate(category);
         assertNotNull(update);
         assertEquals(42, update.getCategoryId());
 
@@ -527,7 +529,7 @@
     @Test
     public void testUpdate() throws UnsupportedEncodingException, IOException, JsonSyntaxException, ClassNotFoundException {
 
-        Update update = storage.createUpdate(category);
+        Update<?> update = storage.createUpdate(category);
         Expression expr = factory.equalTo(key1, "test");
         update.where(expr);
         update.set(key1, "fluff");
@@ -548,7 +550,7 @@
         assertEquals(2, params.length);
         String[] parts = params[0].split("=");
         assertEquals("update", parts[0]);
-        WebUpdate receivedUpdate = gson.fromJson(parts[1], WebUpdate.class);
+        WebUpdate<?> receivedUpdate = gson.fromJson(parts[1], WebUpdate.class);
         assertEquals(42, receivedUpdate.getCategoryId());
 
         List<WebUpdate.UpdateValue> updates = receivedUpdate.getUpdates();
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/WebAdd.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/web/common/src/main/java/com/redhat/thermostat/web/common/WebAdd.java	Fri Aug 23 17:08:35 2013 +0200
@@ -41,7 +41,7 @@
 import com.redhat.thermostat.storage.model.Pojo;
 
 
-public class WebAdd implements Add {
+public class WebAdd<T extends Pojo> implements Add<T> {
 
     private int categoryId;
     private transient Pojo pojo;
@@ -72,7 +72,7 @@
     }
 
     @Override
-    public void apply() {
+    public int apply() {
         // Should never be called directly, but overridden by
         // the actual implementation. Here only so that it can be used
         // for serialization.
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/WebRemove.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/web/common/src/main/java/com/redhat/thermostat/web/common/WebRemove.java	Fri Aug 23 17:08:35 2013 +0200
@@ -37,9 +37,10 @@
 package com.redhat.thermostat.web.common;
 
 import com.redhat.thermostat.storage.core.Remove;
+import com.redhat.thermostat.storage.model.Pojo;
 import com.redhat.thermostat.storage.query.Expression;
 
-public class WebRemove implements Remove {
+public class WebRemove<T extends Pojo> implements Remove<T> {
 
     private final int categoryId;
     private Expression whereExpression;
@@ -62,7 +63,7 @@
     }
 
     @Override
-    public void apply() {
+    public int apply() {
         // This should never be called. Overridden by the actual
         // implementation.
         throw new IllegalStateException();
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/WebReplace.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/web/common/src/main/java/com/redhat/thermostat/web/common/WebReplace.java	Fri Aug 23 17:08:35 2013 +0200
@@ -40,7 +40,7 @@
 import com.redhat.thermostat.storage.model.Pojo;
 import com.redhat.thermostat.storage.query.Expression;
 
-public class WebReplace implements Replace {
+public class WebReplace<T extends Pojo> implements Replace<T> {
     
     private int categoryId;
     private transient Pojo pojo;
@@ -60,7 +60,7 @@
     }
 
     @Override
-    public void apply() {
+    public int apply() {
         // Should never be called directly, but overridden by
         // the actual implementation. Here only so that it can be used
         // for serialization.
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/WebUpdate.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/web/common/src/main/java/com/redhat/thermostat/web/common/WebUpdate.java	Fri Aug 23 17:08:35 2013 +0200
@@ -40,9 +40,11 @@
 import java.util.List;
 
 import com.redhat.thermostat.storage.core.Key;
+import com.redhat.thermostat.storage.core.Update;
+import com.redhat.thermostat.storage.model.Pojo;
 import com.redhat.thermostat.storage.query.Expression;
 
-public class WebUpdate {
+public class WebUpdate<T extends Pojo> implements Update<T> {
 
     public static class UpdateValue {
         private Key<?> key;
@@ -99,7 +101,7 @@
         whereExpression = expr;
     }
 
-    public <T> void set(Key<T> key, T value) {
+    public <S> void set(Key<S> key, S value) {
         updateValues.add(new UpdateValue(key, value));
     }
 
@@ -119,5 +121,12 @@
         return updateValues;
     }
 
+    @Override
+    public int apply() {
+        // This should never be called. Overridden by the actual
+        // implementation.
+        throw new IllegalStateException();
+    }
+
 }
 
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/WebStorageEndPoint.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/web/server/src/main/java/com/redhat/thermostat/web/server/WebStorageEndPoint.java	Fri Aug 23 17:08:35 2013 +0200
@@ -528,10 +528,10 @@
             return;
         }
         String addParam = req.getParameter("add");
-        WebAdd add = gson.fromJson(addParam, WebAdd.class);
+        WebAdd<?> add = gson.fromJson(addParam, WebAdd.class);
         int categoryId = add.getCategoryId();
         Category<?> category = getCategoryFromId(categoryId);
-        Add targetAdd = storage.createAdd(category);
+        Add<?> targetAdd = storage.createAdd(category);
         Class<? extends Pojo> pojoCls = category.getDataClass();
         String pojoParam = req.getParameter("pojo");
         Pojo pojo = gson.fromJson(pojoParam, pojoCls);
@@ -546,10 +546,10 @@
             return;
         }
         String replaceParam = req.getParameter("replace");
-        WebReplace replace = gson.fromJson(replaceParam, WebReplace.class);
+        WebReplace<?> replace = gson.fromJson(replaceParam, WebReplace.class);
         int categoryId = replace.getCategoryId();
         Category<?> category = getCategoryFromId(categoryId);
-        Replace targetReplace = storage.createReplace(category);
+        Replace<?> targetReplace = storage.createReplace(category);
         Class<? extends Pojo> pojoCls = category.getDataClass();
         String pojoParam = req.getParameter("pojo");
         Pojo pojo = gson.fromJson(pojoParam, pojoCls);
@@ -567,9 +567,9 @@
         }
         
         String removeParam = req.getParameter("remove");
-        WebRemove remove = gson.fromJson(removeParam, WebRemove.class);
+        WebRemove<?> remove = gson.fromJson(removeParam, WebRemove.class);
         Category<?> targetCategory = getCategoryFromId(remove.getCategoryId());
-        Remove targetRemove = storage.createRemove(targetCategory);
+        Remove<?> targetRemove = storage.createRemove(targetCategory);
         Expression expr = remove.getWhereExpression();
         if (expr != null) {
             targetRemove.where(expr);
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndpointTest.java	Mon Sep 02 11:07:54 2013 +0200
+++ b/web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndpointTest.java	Fri Aug 23 17:08:35 2013 +0200
@@ -895,8 +895,9 @@
         setupTrustedCategory(categoryName);
         registerCategory(testuser, password);
         
-        Replace replace = mock(Replace.class);
-        when(mockStorage.createReplace(any(Category.class))).thenReturn(replace);
+        @SuppressWarnings("unchecked")
+        Replace<TestClass> replace = mock(Replace.class);
+        when(mockStorage.createReplace(eq(category))).thenReturn(replace);
 
         TestClass expected1 = new TestClass();
         expected1.setKey1("fluff1");
@@ -912,7 +913,7 @@
 
         conn.setDoOutput(true);
         conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
-        WebReplace webReplace = new WebReplace(categoryId);
+        WebReplace<TestClass> webReplace = new WebReplace<>(categoryId);
         webReplace.where(expectedExpression);
         Gson gson = new GsonBuilder()
             .registerTypeHierarchyAdapter(Expression.class,
@@ -963,7 +964,7 @@
         conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
         conn.setDoOutput(true);
         conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
-        WebReplace webReplace = new WebReplace(categoryId);
+        WebReplace<TestClass> webReplace = new WebReplace<>(categoryId);
         Gson gson = new GsonBuilder()
             .registerTypeHierarchyAdapter(Expression.class,
                 new ExpressionSerializer())
@@ -1004,8 +1005,9 @@
         setupTrustedCategory(categoryName);
         registerCategory(testuser, password);
         
-        Add insert = mock(Add.class);
-        when(mockStorage.createAdd(any(Category.class))).thenReturn(insert);
+        @SuppressWarnings("unchecked")
+        Add<TestClass> insert = mock(Add.class);
+        when(mockStorage.createAdd(eq(category))).thenReturn(insert);
 
         TestClass expected1 = new TestClass();
         expected1.setKey1("fluff1");
@@ -1020,7 +1022,7 @@
 
         conn.setDoOutput(true);
         conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
-        WebAdd ins = new WebAdd(categoryId);
+        WebAdd<TestClass> ins = new WebAdd<>(categoryId);
         Gson gson = new Gson();
         OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream());
         out.write("add=");
@@ -1065,7 +1067,7 @@
         conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
         conn.setDoOutput(true);
         conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
-        WebAdd insert = new WebAdd(categoryId);
+        WebAdd<TestClass> insert = new WebAdd<>(categoryId);
         Gson gson = new Gson();
         OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream());
         out.write("add=");
@@ -1109,7 +1111,8 @@
         registerCategory(testuser, password);
         
         
-        Remove mockRemove = mock(Remove.class);
+        @SuppressWarnings("unchecked")
+        Remove<TestClass> mockRemove = mock(Remove.class);
 
         when(mockStorage.createRemove(category)).thenReturn(mockRemove);
 
@@ -1122,7 +1125,7 @@
         conn.setDoOutput(true);
         conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
         Expression expr = factory.equalTo(key1, "test");
-        WebRemove remove = new WebRemove(categoryId);
+        WebRemove<?> remove = new WebRemove<>(categoryId);
         remove.where(expr);
         Gson gson = new GsonBuilder()
                 .registerTypeHierarchyAdapter(Expression.class,
@@ -1169,8 +1172,9 @@
         setupTrustedCategory(categoryName);
         registerCategory(testuser, password);
         
-        Update mockUpdate = mock(Update.class);
-        when(mockStorage.createUpdate(any(Category.class))).thenReturn(mockUpdate);
+        @SuppressWarnings("unchecked")
+        Update<TestClass> mockUpdate = mock(Update.class);
+        when(mockStorage.createUpdate(eq(category))).thenReturn(mockUpdate);
 
         String endpoint = getEndpoint();
 
@@ -1181,7 +1185,7 @@
         conn.setDoOutput(true);
         conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
 
-        WebUpdate update = new WebUpdate();
+        WebUpdate<?> update = new WebUpdate<>();
         update.setCategoryId(categoryId);
         Expression expr = factory.equalTo(key1, "test");
         update.where(expr);