# HG changeset patch # User Severin Gehwolf # Date 1380128998 -7200 # Node ID d387d381858b513e6402ce590010b976a117439f # Parent 0e0e2b6041adcea1c0fbfc26e34989768d3efa93 Make prepared writes work with WebStorage. Reviewed-by: omajid Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-September/008323.html diff -r 0e0e2b6041ad -r d387d381858b host-cpu/common/src/main/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOImplStatementDescriptorRegistration.java --- a/host-cpu/common/src/main/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOImplStatementDescriptorRegistration.java Mon Sep 16 15:28:13 2013 +0200 +++ b/host-cpu/common/src/main/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOImplStatementDescriptorRegistration.java Wed Sep 25 19:09:58 2013 +0200 @@ -61,6 +61,7 @@ public Set getStatementDescriptors() { Set descs = new HashSet<>(1); descs.add(DESCRIPTOR); + descs.add(CpuStatDAOImpl.DESC_ADD_CPU_STAT); return descs; } diff -r 0e0e2b6041ad -r d387d381858b host-cpu/common/src/test/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOImplStatementDescriptorRegistrationTest.java --- a/host-cpu/common/src/test/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOImplStatementDescriptorRegistrationTest.java Mon Sep 16 15:28:13 2013 +0200 +++ b/host-cpu/common/src/test/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOImplStatementDescriptorRegistrationTest.java Wed Sep 25 19:09:58 2013 +0200 @@ -61,10 +61,10 @@ public class CpuStatDAOImplStatementDescriptorRegistrationTest { @Test - public void registersAllQueries() { + public void registersAllDescriptors() { CpuStatDAOImplStatementDescriptorRegistration reg = new CpuStatDAOImplStatementDescriptorRegistration(); Set descriptors = reg.getStatementDescriptors(); - assertEquals(1, descriptors.size()); + assertEquals(2, descriptors.size()); assertFalse("null descriptor not allowed", descriptors.contains(null)); } @@ -92,7 +92,7 @@ // storage-core + this module assertEquals(2, registrations.size()); assertNotNull(cpuStatReg); - assertEquals(1, cpuStatReg.getStatementDescriptors().size()); + assertEquals(2, cpuStatReg.getStatementDescriptors().size()); } @Test diff -r 0e0e2b6041ad -r d387d381858b host-memory/common/src/main/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOImplStatementDescriptorRegistration.java --- a/host-memory/common/src/main/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOImplStatementDescriptorRegistration.java Mon Sep 16 15:28:13 2013 +0200 +++ b/host-memory/common/src/main/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOImplStatementDescriptorRegistration.java Wed Sep 25 19:09:58 2013 +0200 @@ -60,6 +60,7 @@ public Set getStatementDescriptors() { Set descs = new HashSet<>(1); descs.add(descriptor); + descs.add(MemoryStatDAOImpl.DESC_ADD_MEMORY_STAT); return descs; } diff -r 0e0e2b6041ad -r d387d381858b host-memory/common/src/test/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOImplStatementDescriptorRegistrationTest.java --- a/host-memory/common/src/test/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOImplStatementDescriptorRegistrationTest.java Mon Sep 16 15:28:13 2013 +0200 +++ b/host-memory/common/src/test/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOImplStatementDescriptorRegistrationTest.java Wed Sep 25 19:09:58 2013 +0200 @@ -61,10 +61,10 @@ public class MemoryStatDAOImplStatementDescriptorRegistrationTest { @Test - public void registersAllQueries() { + public void registersAllDescriptors() { MemoryStatDAOImplStatementDescriptorRegistration reg = new MemoryStatDAOImplStatementDescriptorRegistration(); Set descriptors = reg.getStatementDescriptors(); - assertEquals(1, descriptors.size()); + assertEquals(2, descriptors.size()); assertFalse("null descriptor not allowed", descriptors.contains(null)); } @@ -92,7 +92,7 @@ // storage-core + this module assertEquals(2, registrations.size()); assertNotNull(memoryStatReg); - assertEquals(1, memoryStatReg.getStatementDescriptors().size()); + assertEquals(2, memoryStatReg.getStatementDescriptors().size()); } @Test diff -r 0e0e2b6041ad -r d387d381858b integration-tests/src/test/java/com/redhat/thermostat/itest/MongoQueriesTest.java --- a/integration-tests/src/test/java/com/redhat/thermostat/itest/MongoQueriesTest.java Mon Sep 16 15:28:13 2013 +0200 +++ b/integration-tests/src/test/java/com/redhat/thermostat/itest/MongoQueriesTest.java Wed Sep 25 19:09:58 2013 +0200 @@ -153,7 +153,7 @@ private static void addCpuData(int numberOfItems) throws InterruptedException { CountDownLatch latch = new CountDownLatch(1); ConnectionListener listener = new CountdownConnectionListener(ConnectionStatus.CONNECTED, latch); - Storage storage = getAndConnectStorage(listener); + BackingStorage storage = getAndConnectStorage(listener); latch.await(); storage.getConnection().removeListener(listener); @@ -161,7 +161,7 @@ for (int i = 0; i < numberOfItems; i++) { CpuStat pojo = new CpuStat("test-agent-id", i, new double[] {i, i*2}); - Add add = storage.createAdd(CpuStatDAO.cpuStatCategory); + Add add = storage.createAdd(CpuStatDAO.cpuStatCategory); add.setPojo(pojo); add.apply(); } @@ -201,12 +201,12 @@ public void testMongoAdd() throws Exception { CountDownLatch latch = new CountDownLatch(1); ConnectionListener listener = new CountdownConnectionListener(ConnectionStatus.CONNECTED, latch); - Storage mongoStorage = getAndConnectStorage(listener); + BackingStorage mongoStorage = getAndConnectStorage(listener); latch.await(); mongoStorage.getConnection().removeListener(listener); mongoStorage.registerCategory(VmClassStatDAO.vmClassStatsCategory); - Add add = mongoStorage.createAdd(VmClassStatDAO.vmClassStatsCategory); + Add add = mongoStorage.createAdd(VmClassStatDAO.vmClassStatsCategory); VmClassStat pojo = new VmClassStat(); pojo.setAgentId("fluff"); pojo.setLoadedClasses(12345); @@ -513,7 +513,7 @@ long timeStamp = 5; double cpuLoad = 0.15; VmCpuStat pojo = new VmCpuStat(uuid.toString(), timeStamp, VM_ID1, cpuLoad); - Add add = mongoStorage.createAdd(VmCpuStatDAO.vmCpuStatCategory); + Add add = mongoStorage.createAdd(VmCpuStatDAO.vmCpuStatCategory); add.setPojo(pojo); add.apply(); diff -r 0e0e2b6041ad -r d387d381858b integration-tests/src/test/java/com/redhat/thermostat/itest/WebAppTest.java --- a/integration-tests/src/test/java/com/redhat/thermostat/itest/WebAppTest.java Mon Sep 16 15:28:13 2013 +0200 +++ b/integration-tests/src/test/java/com/redhat/thermostat/itest/WebAppTest.java Wed Sep 25 19:09:58 2013 +0200 @@ -78,6 +78,7 @@ import com.redhat.thermostat.storage.config.ConnectionConfiguration; import com.redhat.thermostat.storage.config.StartupConfiguration; import com.redhat.thermostat.storage.core.Add; +import com.redhat.thermostat.storage.core.BackingStorage; import com.redhat.thermostat.storage.core.Category; import com.redhat.thermostat.storage.core.CategoryAdapter; import com.redhat.thermostat.storage.core.Connection.ConnectionListener; @@ -97,6 +98,7 @@ import com.redhat.thermostat.storage.model.HostInfo; import com.redhat.thermostat.storage.dao.AgentInfoDAO; import com.redhat.thermostat.storage.model.AgentInformation; +import com.redhat.thermostat.storage.mongodb.internal.MongoStorage; import com.redhat.thermostat.storage.query.Expression; import com.redhat.thermostat.storage.query.ExpressionFactory; import com.redhat.thermostat.test.FreePortFinder; @@ -151,7 +153,7 @@ private static final String KEY_AUTHORIZED_QUERY_NOT = "authorizedQueryNot"; private static final String KEY_AUTHORIZED_QUERY_AND = "authorizedQueryAnd"; private static final String KEY_AUTHORIZED_QUERY_OR = "authorizedQueryOr"; - private static final String KEY_SET_DEFAULT_AGENT_ID = "setDefaultAgentID"; + private static final String KEY_STORAGE_PURGE = "storagePurge"; private static final String KEY_AUTHORIZED_FILTERED_QUERY = "authorizedFilteredQuerySubset"; static { @@ -167,7 +169,7 @@ descMap.put(KEY_AUTHORIZED_QUERY_NOT, "QUERY cpu-stats WHERE NOT 'timeStamp' > ?l SORT 'timeStamp' ASC"); descMap.put(KEY_AUTHORIZED_QUERY_AND, "QUERY cpu-stats WHERE 'timeStamp' > 0 AND 'timeStamp' < ?l SORT 'timeStamp' ASC"); descMap.put(KEY_AUTHORIZED_QUERY_OR, "QUERY cpu-stats WHERE 'timeStamp' > ?l OR 'timeStamp' < ?l SORT 'timeStamp' ASC"); - descMap.put(KEY_SET_DEFAULT_AGENT_ID, "QUERY vm-cpu-stats"); + descMap.put(KEY_STORAGE_PURGE, "QUERY vm-cpu-stats"); Set trustedDescriptors = new HashSet<>(); Map metadata = new HashMap<>(); DescriptorMetadata descMetadata = new DescriptorMetadata(); @@ -289,6 +291,19 @@ Files.copy(backupUsers, new File(THERMOSTAT_USERS_FILE).toPath(), StandardCopyOption.REPLACE_EXISTING); Files.copy(backupRoles, new File(THERMOSTAT_ROLES_FILE).toPath(), StandardCopyOption.REPLACE_EXISTING); } + + /* + * Queries tests use write operations to put things into storage. For them + * we don't want to go through the hassles of using prepared writes. Instead + * use mongo-storage directly (which is a BackingStorage). + */ + private static BackingStorage getAndConnectBackingStorage() { + String url = "mongodb://127.0.0.1:27518"; + StartupConfiguration config = new ConnectionConfiguration(url, "", ""); + BackingStorage storage = new MongoStorage(config); + storage.getConnection().connect(); + return storage; + } /* * Using the given username and password, set up a user for JAAS in the web app, @@ -386,13 +401,7 @@ } private static void addCpuData(int numberOfItems) throws IOException { - String[] roleNames = new String[] { - Roles.REGISTER_CATEGORY, - Roles.ACCESS_REALM, - Roles.LOGIN, - Roles.APPEND - }; - Storage storage = getAndConnectStorage(PREP_USER, PREP_PASSWORD, roleNames); + BackingStorage storage = getAndConnectBackingStorage(); storage.registerCategory(CpuStatDAO.cpuStatCategory); for (int i = 0; i < numberOfItems; i++) { @@ -406,13 +415,7 @@ } private static void addHostInfoData(int numberOfItems) throws IOException { - String[] roleNames = new String[] { - Roles.REGISTER_CATEGORY, - Roles.ACCESS_REALM, - Roles.LOGIN, - Roles.APPEND - }; - Storage storage = getAndConnectStorage(PREP_USER, PREP_PASSWORD, roleNames); + BackingStorage storage = getAndConnectBackingStorage(); storage.registerCategory(HostInfoDAO.hostInfoCategory); for (int i = 0; i < numberOfItems; i++) { @@ -426,13 +429,7 @@ } private static void addAgentConfigData(List items) throws IOException { - String[] roleNames = new String[] { - Roles.REGISTER_CATEGORY, - Roles.ACCESS_REALM, - Roles.LOGIN, - Roles.APPEND - }; - Storage storage = getAndConnectStorage(PREP_USER, PREP_PASSWORD, roleNames); + BackingStorage storage = getAndConnectBackingStorage(); storage.registerCategory(AgentInfoDAO.CATEGORY); for (AgentInformation info: items) { @@ -466,13 +463,7 @@ } private static void deleteAgentConfigData(List items) throws IOException { - String[] roleNames = new String[] { - Roles.REGISTER_CATEGORY, - Roles.ACCESS_REALM, - Roles.LOGIN, - Roles.DELETE - }; - Storage storage = getAndConnectStorage(PREP_USER, PREP_PASSWORD, roleNames); + BackingStorage storage = getAndConnectBackingStorage(); storage.registerCategory(AgentInfoDAO.CATEGORY); ExpressionFactory factory = new ExpressionFactory(); Remove remove = storage.createRemove(AgentInfoDAO.CATEGORY); @@ -503,47 +494,63 @@ } @Test - public void authorizedAdd() throws Exception { + public void authorizedPreparedAdd() throws Exception { String[] roleNames = new String[] { Roles.REGISTER_CATEGORY, - Roles.ACCESS_REALM, + Roles.WRITE, Roles.LOGIN, - Roles.APPEND + Roles.ACCESS_REALM, + Roles.PREPARE_STATEMENT, }; + Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames); webStorage.registerCategory(VmClassStatDAO.vmClassStatsCategory); - Add add = webStorage.createAdd(VmClassStatDAO.vmClassStatsCategory); + // This is the same descriptor as VmClassStatDAOImpl uses. It also + // gets registered automatically for that reason, no need to do it + // manually for this test. + String strDesc = "ADD vm-class-stats SET 'agentId' = ?s , " + + "'vmId' = ?s , " + + "'timeStamp' = ?l , " + + "'loadedClasses' = ?l"; + StatementDescriptor desc = new StatementDescriptor<>(VmClassStatDAO.vmClassStatsCategory, strDesc); VmClassStat pojo = new VmClassStat(); pojo.setAgentId("fluff"); pojo.setLoadedClasses(12345); pojo.setTimeStamp(42); pojo.setVmId(VM_ID1); - add.setPojo(pojo); - add.apply(); + PreparedStatement add; + add = webStorage.prepareStatement(desc); + addPreparedVmClassStat(pojo, add); // Add another couple of entries - add = webStorage.createAdd(VmClassStatDAO.vmClassStatsCategory); pojo = new VmClassStat(); pojo.setAgentId("fluff"); pojo.setLoadedClasses(67890); pojo.setTimeStamp(42); pojo.setVmId(VM_ID2); - add.setPojo(pojo); - add.apply(); + addPreparedVmClassStat(pojo, add); - add = webStorage.createAdd(VmClassStatDAO.vmClassStatsCategory); pojo = new VmClassStat(); pojo.setAgentId("fluff"); pojo.setLoadedClasses(34567); pojo.setTimeStamp(42); pojo.setVmId(VM_ID3); - add.setPojo(pojo); - add.apply(); - + addPreparedVmClassStat(pojo, add); + webStorage.getConnection().disconnect(); } + private void addPreparedVmClassStat(VmClassStat pojo, + PreparedStatement add) + throws StatementExecutionException { + add.setString(0, pojo.getAgentId()); + add.setString(1, pojo.getVmId()); + add.setLong(2, pojo.getTimeStamp()); + add.setLong(3, pojo.getLoadedClasses()); + add.execute(); + } + /* * Tests whether a query only returns results which a user is allowed to see. * @@ -697,7 +704,9 @@ }; Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames); Category adapted = new CategoryAdapter(HostInfoDAO.hostInfoCategory).getAdapted(AggregateCount.class); - // register adapted category. + // register non-adapted + adapted category in that order. Adapted + // category needs to be registered, since it gets it's own mapped id + webStorage.registerCategory(HostInfoDAO.hostInfoCategory); webStorage.registerCategory(adapted); // storage-core registers this descriptor. no need to do it in this @@ -1021,29 +1030,29 @@ @Test public void storagePurge() throws Exception { + // Add some data to purge (uses backing storage) + UUID uuid = new UUID(42, 24); + long timeStamp = 5; + double cpuLoad = 0.15; + VmCpuStat pojo = new VmCpuStat(uuid.toString(), timeStamp, VM_ID1, cpuLoad); + addVmCpuStat(pojo); + String[] roleNames = new String[] { Roles.ACCESS_REALM, Roles.LOGIN, - Roles.REGISTER_CATEGORY, - Roles.READ, - Roles.APPEND, Roles.PURGE, Roles.PREPARE_STATEMENT, - Roles.GRANT_READ_ALL + Roles.READ, + Roles.GRANT_READ_ALL, + Roles.REGISTER_CATEGORY }; - Storage storage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames); - UUID uuid = new UUID(42, 24); - storage.registerCategory(VmCpuStatDAO.vmCpuStatCategory); - long timeStamp = 5; - double cpuLoad = 0.15; - VmCpuStat pojo = new VmCpuStat(uuid.toString(), timeStamp, VM_ID1, cpuLoad); - Add add = storage.createAdd(VmCpuStatDAO.vmCpuStatCategory); - add.setPojo(pojo); - add.apply(); - - String strDesc = DESCRIPTOR_MAP.get(KEY_SET_DEFAULT_AGENT_ID); + + Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames); + webStorage.registerCategory(VmCpuStatDAO.vmCpuStatCategory); + + String strDesc = DESCRIPTOR_MAP.get(KEY_STORAGE_PURGE); StatementDescriptor queryDesc = new StatementDescriptor<>(VmCpuStatDAO.vmCpuStatCategory, strDesc); - PreparedStatement query = storage.prepareStatement(queryDesc); + PreparedStatement query = webStorage.prepareStatement(queryDesc); Cursor cursor = query.executeQuery(); assertTrue(cursor.hasNext()); pojo = cursor.next(); @@ -1054,6 +1063,15 @@ assertEquals(cpuLoad, pojo.getCpuLoad(), EQUALS_DELTA); assertEquals(uuid.toString(), pojo.getAgentId()); - storage.purge(uuid.toString()); + webStorage.purge(uuid.toString()); + } + + private void addVmCpuStat(VmCpuStat pojo) { + BackingStorage storage = getAndConnectBackingStorage(); + storage.registerCategory(VmCpuStatDAO.vmCpuStatCategory); + Add add = storage.createAdd(VmCpuStatDAO.vmCpuStatCategory); + add.setPojo(pojo); + add.apply(); + storage.getConnection().disconnect(); } } diff -r 0e0e2b6041ad -r d387d381858b numa/common/src/main/java/com/redhat/thermostat/numa/common/internal/NumaDAOImplStatementDescriptorRegistration.java --- a/numa/common/src/main/java/com/redhat/thermostat/numa/common/internal/NumaDAOImplStatementDescriptorRegistration.java Mon Sep 16 15:28:13 2013 +0200 +++ b/numa/common/src/main/java/com/redhat/thermostat/numa/common/internal/NumaDAOImplStatementDescriptorRegistration.java Wed Sep 25 19:09:58 2013 +0200 @@ -62,6 +62,8 @@ NumaDAO.numaStatCategory.getName()); descs.add(descriptor); descs.add(NumaDAOImpl.QUERY_NUMA_INFO); + descs.add(NumaDAOImpl.DESC_ADD_NUMA_HOST_INFO); + descs.add(NumaDAOImpl.DESC_ADD_NUMA_STAT); } @Override diff -r 0e0e2b6041ad -r d387d381858b numa/common/src/test/java/com/redhat/thermostat/numa/common/internal/NumaDAOImplStatementDescriptorRegistrationTest.java --- a/numa/common/src/test/java/com/redhat/thermostat/numa/common/internal/NumaDAOImplStatementDescriptorRegistrationTest.java Mon Sep 16 15:28:13 2013 +0200 +++ b/numa/common/src/test/java/com/redhat/thermostat/numa/common/internal/NumaDAOImplStatementDescriptorRegistrationTest.java Wed Sep 25 19:09:58 2013 +0200 @@ -63,10 +63,10 @@ public class NumaDAOImplStatementDescriptorRegistrationTest { @Test - public void registersAllQueries() { + public void registersAllDescriptors() { NumaDAOImplStatementDescriptorRegistration reg = new NumaDAOImplStatementDescriptorRegistration(); Set descriptors = reg.getStatementDescriptors(); - assertEquals(2, descriptors.size()); + assertEquals(4, descriptors.size()); assertFalse("null descriptor not allowed", descriptors.contains(null)); } @@ -94,7 +94,7 @@ // storage-core + this module assertEquals(2, registrations.size()); assertNotNull(numaReg); - assertEquals(2, numaReg.getStatementDescriptors().size()); + assertEquals(4, numaReg.getStatementDescriptors().size()); } @Test diff -r 0e0e2b6041ad -r d387d381858b storage/core/src/main/java/com/redhat/thermostat/storage/core/BackingStorage.java --- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/BackingStorage.java Mon Sep 16 15:28:13 2013 +0200 +++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/BackingStorage.java Wed Sep 25 19:09:58 2013 +0200 @@ -55,6 +55,12 @@ Query createAggregateQuery(AggregateFunction function, Category category); - // TODO Move createUpdate and createRemove here + Add createAdd(Category category); + + Replace createReplace(Category category); + + Update createUpdate(Category category); + + Remove createRemove(Category category); } diff -r 0e0e2b6041ad -r d387d381858b storage/core/src/main/java/com/redhat/thermostat/storage/core/PreparedParameter.java --- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/PreparedParameter.java Mon Sep 16 15:28:13 2013 +0200 +++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/PreparedParameter.java Wed Sep 25 19:09:58 2013 +0200 @@ -44,11 +44,16 @@ public class PreparedParameter { private Object value; + // The simple type of value. Even if value is an array. private Class type; + // true if and only if value is an array of simple types + // as specified by the type instance variable. + private boolean isArrayType; - PreparedParameter(Object value, Class type) { + PreparedParameter(Object value, Class type, boolean isArrayType) { this.value = value; this.type = type; + this.isArrayType = isArrayType; } public PreparedParameter() { @@ -70,4 +75,12 @@ public void setType(Class type) { this.type = type; } + + public boolean isArrayType() { + return isArrayType; + } + + public void setArrayType(boolean isArrayType) { + this.isArrayType = isArrayType; + } } diff -r 0e0e2b6041ad -r d387d381858b storage/core/src/main/java/com/redhat/thermostat/storage/core/PreparedParameters.java --- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/PreparedParameters.java Mon Sep 16 15:28:13 2013 +0200 +++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/PreparedParameters.java Wed Sep 25 19:09:58 2013 +0200 @@ -36,6 +36,8 @@ package com.redhat.thermostat.storage.core; +import java.lang.reflect.Modifier; + import com.redhat.thermostat.storage.model.Pojo; /** @@ -58,69 +60,83 @@ @Override public void setLong(int paramIndex, long paramValue) { - setType(paramIndex, paramValue, Long.class); + setType(paramIndex, paramValue, Long.class, false); } @Override public void setLongList(int paramIndex, long[] paramValue) { - setType(paramIndex, paramValue, Long[].class); + setType(paramIndex, paramValue, Long.class, true); } @Override public void setInt(int paramIndex, int paramValue) { - setType(paramIndex, paramValue, Integer.class); + setType(paramIndex, paramValue, Integer.class, false); } @Override public void setIntList(int paramIndex, int[] paramValue) { - setType(paramIndex, paramValue, Integer[].class); + setType(paramIndex, paramValue, Integer.class, true); } @Override public void setBoolean(int paramIndex, boolean paramValue) { - setType(paramIndex, paramValue, Boolean.class); + setType(paramIndex, paramValue, Boolean.class, false); } @Override public void setBooleanList(int paramIndex, boolean[] paramValue) { - setType(paramIndex, paramValue, Boolean[].class); + setType(paramIndex, paramValue, Boolean.class, true); } @Override public void setString(int paramIndex, String paramValue) { - setType(paramIndex, paramValue, String.class); + setType(paramIndex, paramValue, String.class, false); } @Override public void setStringList(int paramIndex, String[] paramValue) { - setType(paramIndex, paramValue, String[].class); + setType(paramIndex, paramValue, String.class, true); } @Override public void setDouble(int paramIndex, double paramValue) { - setType(paramIndex, paramValue, Double.class); + setType(paramIndex, paramValue, Double.class, false); } @Override public void setDoubleList(int paramIndex, double[] paramValue) { - setType(paramIndex, paramValue, Double[].class); + setType(paramIndex, paramValue, Double.class, true); } @Override public void setPojo(int paramIndex, Pojo paramValue) { - setType(paramIndex, paramValue, Pojo.class); + Class runtimeType = paramValue.getClass(); + performPojoChecks(runtimeType, "Type"); + setType(paramIndex, paramValue, runtimeType, false); } @Override public void setPojoList(int paramIndex, Pojo[] paramValue) { - setType(paramIndex, paramValue, Pojo[].class); + Class componentType = paramValue.getClass().getComponentType(); + performPojoChecks(componentType, "Component type"); + setType(paramIndex, paramValue, componentType, true); + } + + private void performPojoChecks(Class type, String errorMsgPrefix) { + if (type.isInterface() || Modifier.isAbstract(type.getModifiers())) { + // Due to serealization we only allow concrete instantiable types. + // Instantiation would fail later in ThermostatGSONConverter for this + // reason anyway. Let's do this check early. + throw new IllegalArgumentException(errorMsgPrefix + "'" + + type.getName() + "' not instantiable!"); + } } - private void setType(int paramIndex, Object paramValue, Class paramType) { + private void setType(int paramIndex, Object paramValue, Class paramType, boolean isArrayType) { if (paramIndex >= params.length) { throw new IllegalArgumentException("Parameter index '" + paramIndex + "' out of range."); } - PreparedParameter param = new PreparedParameter(paramValue, paramType); + PreparedParameter param = new PreparedParameter(paramValue, paramType, isArrayType); params[paramIndex] = param; } diff -r 0e0e2b6041ad -r d387d381858b storage/core/src/main/java/com/redhat/thermostat/storage/core/QueuedBackingStorage.java --- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/QueuedBackingStorage.java Mon Sep 16 15:28:13 2013 +0200 +++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/QueuedBackingStorage.java Wed Sep 25 19:09:58 2013 +0200 @@ -40,10 +40,133 @@ import com.redhat.thermostat.storage.core.AggregateQuery.AggregateFunction; import com.redhat.thermostat.storage.model.Pojo; +import com.redhat.thermostat.storage.query.Expression; public class QueuedBackingStorage extends QueuedStorage implements BackingStorage { + private class QueuedReplace implements Replace { + + private final Replace delegateReplace; + + private QueuedReplace(Replace delegateReplace) { + this.delegateReplace = delegateReplace; + } + + @Override + public int apply() { + executor.execute(new Runnable() { + + @Override + public void run() { + delegateReplace.apply(); + } + + }); + return DataModifyingStatement.DEFAULT_STATUS_SUCCESS; + } + + @Override + public void where(Expression expression) { + delegateReplace.where(expression); + } + + @Override + public void setPojo(Pojo pojo) { + delegateReplace.setPojo(pojo); + } + + } + + private class QueuedAdd implements Add { + + private final Add delegateAdd; + + private QueuedAdd(Add delegateAdd) { + this.delegateAdd = delegateAdd; + } + + @Override + public int apply() { + executor.execute(new Runnable() { + + @Override + public void run() { + delegateAdd.apply(); + } + + }); + return DataModifyingStatement.DEFAULT_STATUS_SUCCESS; + } + + @Override + public void setPojo(Pojo pojo) { + delegateAdd.setPojo(pojo); + } + + } + + private class QueuedUpdate implements Update { + + private final Update delegateUpdate; + + private QueuedUpdate(Update delegateUpdate) { + this.delegateUpdate = delegateUpdate; + } + + @Override + public void where(Expression expr) { + delegateUpdate.where(expr); + + } + + @Override + public void set(Key key, S value) { + delegateUpdate.set(key, value); + } + + @Override + public int apply() { + executor.execute(new Runnable() { + + @Override + public void run() { + delegateUpdate.apply(); + } + + }); + return DataModifyingStatement.DEFAULT_STATUS_SUCCESS; + } + + } + + private class QueuedRemove implements Remove { + + private final Remove delegateRemove; + + private QueuedRemove(Remove delegateRemove) { + this.delegateRemove = delegateRemove; + } + + @Override + public void where(Expression where) { + delegateRemove.where(where); + } + + @Override + public int apply() { + executor.execute(new Runnable() { + + @Override + public void run() { + delegateRemove.apply(); + } + + }); + return DataModifyingStatement.DEFAULT_STATUS_SUCCESS; + } + } + public QueuedBackingStorage(BackingStorage delegate) { super(delegate); } @@ -77,4 +200,32 @@ return ((BackingStorage) delegate).createAggregateQuery(function, category); } + @Override + public Add createAdd(Category category) { + Add delegateAdd = ((BackingStorage)delegate).createAdd(category); + QueuedAdd add = new QueuedAdd<>(delegateAdd); + return add; + } + + @Override + public Replace createReplace(Category category) { + Replace delegateReplace = ((BackingStorage)delegate).createReplace(category); + QueuedReplace replace = new QueuedReplace<>(delegateReplace); + return replace; + } + + @Override + public Update createUpdate(Category category) { + Update delegateUpdate = ((BackingStorage)delegate).createUpdate(category); + QueuedUpdate update = new QueuedUpdate<>(delegateUpdate); + return update; + } + + @Override + public Remove createRemove(Category category) { + Remove delegateRemove = ((BackingStorage) delegate).createRemove(category); + QueuedRemove remove = new QueuedRemove<>(delegateRemove); + return remove; + } + } diff -r 0e0e2b6041ad -r d387d381858b storage/core/src/main/java/com/redhat/thermostat/storage/core/QueuedStorage.java --- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/QueuedStorage.java Mon Sep 16 15:28:13 2013 +0200 +++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/QueuedStorage.java Wed Sep 25 19:09:58 2013 +0200 @@ -38,86 +38,16 @@ package com.redhat.thermostat.storage.core; import java.io.InputStream; -import java.util.Objects; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import com.redhat.thermostat.storage.model.Pojo; -import com.redhat.thermostat.storage.query.Expression; public class QueuedStorage implements Storage { private static final int SHUTDOWN_TIMEOUT_SECONDS = 3; - private class QueuedReplace extends AddReplaceHelper implements Replace { - - private Expression expression; - - private QueuedReplace(Category category) { - super(category); - } - - @Override - public int apply() { - replaceImpl(getCategory(), getPojo(), expression); - return DataModifyingStatement.DEFAULT_STATUS_SUCCESS; - } - - @Override - public void where(Expression expression) { - this.expression = Objects.requireNonNull(expression); - } - - } - - private class QueuedAdd extends AddReplaceHelper implements Add { - - private QueuedAdd(Category category) { - super(category); - } - - @Override - public int apply() { - addImpl(getCategory(), getPojo()); - return DataModifyingStatement.DEFAULT_STATUS_SUCCESS; - } - - } - - private class QueuedUpdate implements Update { - private Update delegateUpdate; - - QueuedUpdate(Update delegateUpdate) { - this.delegateUpdate = delegateUpdate; - } - - @Override - public void where(Expression expr) { - delegateUpdate.where(expr); - - } - - @Override - public void set(Key key, S value) { - delegateUpdate.set(key, value); - } - - @Override - public int apply() { - executor.execute(new Runnable() { - - @Override - public void run() { - delegateUpdate.apply(); - } - - }); - return DataModifyingStatement.DEFAULT_STATUS_SUCCESS; - } - - } - protected final Storage delegate; protected final ExecutorService executor; protected final ExecutorService fileExecutor; @@ -150,49 +80,6 @@ } @Override - public Add createAdd(Category into) { - QueuedAdd add = new QueuedAdd<>(into); - return add; - } - - @Override - public Replace createReplace(Category into) { - QueuedReplace replace = new QueuedReplace<>(into); - return replace; - } - - private void replaceImpl(final Category category, final Pojo pojo, final Expression expression) { - - executor.execute(new Runnable() { - - @Override - public void run() { - Replace replace = delegate.createReplace(category); - replace.setPojo(pojo); - replace.where(expression); - replace.apply(); - } - - }); - - } - - private void addImpl(final Category category, final Pojo pojo) { - - executor.execute(new Runnable() { - - @Override - public void run() { - Add add = delegate.createAdd(category); - add.setPojo(pojo); - add.apply(); - } - - }); - - } - - @Override public void purge(final String agentId) { executor.execute(new Runnable() { @@ -226,17 +113,6 @@ } @Override - public Update createUpdate(Category category) { - QueuedUpdate update = new QueuedUpdate<>(delegate.createUpdate(category)); - return update; - } - - @Override - public Remove createRemove(Category category) { - return delegate.createRemove(category); - } - - @Override public void registerCategory(final Category category) { delegate.registerCategory(category); } diff -r 0e0e2b6041ad -r d387d381858b storage/core/src/main/java/com/redhat/thermostat/storage/core/Storage.java --- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/Storage.java Mon Sep 16 15:28:13 2013 +0200 +++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/Storage.java Wed Sep 25 19:09:58 2013 +0200 @@ -75,9 +75,6 @@ */ Connection getConnection(); - Add createAdd(Category category); - Replace createReplace(Category category); - /** * Drop all data related to the specified agent. */ @@ -87,9 +84,6 @@ InputStream loadFile(String filename); - Update createUpdate(Category category); - Remove createRemove(Category category); - void shutdown(); } diff -r 0e0e2b6041ad -r d387d381858b storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/DAOImplStatementDescriptorRegistration.java --- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/DAOImplStatementDescriptorRegistration.java Mon Sep 16 15:28:13 2013 +0200 +++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/DAOImplStatementDescriptorRegistration.java Wed Sep 25 19:09:58 2013 +0200 @@ -59,15 +59,24 @@ daoDescs.add(AgentInfoDAOImpl.QUERY_ALIVE_AGENTS); daoDescs.add(AgentInfoDAOImpl.QUERY_ALL_AGENTS); daoDescs.add(AgentInfoDAOImpl.AGGREGATE_COUNT_ALL_AGENTS); + daoDescs.add(AgentInfoDAOImpl.DESC_ADD_AGENT_INFO); + daoDescs.add(AgentInfoDAOImpl.DESC_REMOVE_AGENT_INFO); + daoDescs.add(AgentInfoDAOImpl.DESC_UPDATE_AGENT_INFO); daoDescs.add(BackendInfoDAOImpl.QUERY_BACKEND_INFO); + daoDescs.add(BackendInfoDAOImpl.DESC_ADD_BACKEND_INFO); + daoDescs.add(BackendInfoDAOImpl.DESC_REMOVE_BACKEND_INFO); daoDescs.add(HostInfoDAOImpl.QUERY_HOST_INFO); daoDescs.add(HostInfoDAOImpl.QUERY_ALL_HOSTS); daoDescs.add(HostInfoDAOImpl.AGGREGATE_COUNT_ALL_HOSTS); + daoDescs.add(HostInfoDAOImpl.DESC_ADD_HOST_INFO); daoDescs.add(NetworkInterfaceInfoDAOImpl.QUERY_NETWORK_INFO); + daoDescs.add(NetworkInterfaceInfoDAOImpl.DESC_REPLACE_NETWORK_INFO); daoDescs.add(VmInfoDAOImpl.QUERY_ALL_VMS_FOR_HOST); daoDescs.add(VmInfoDAOImpl.QUERY_ALL_VMS); daoDescs.add(VmInfoDAOImpl.QUERY_VM_INFO); daoDescs.add(VmInfoDAOImpl.AGGREGATE_COUNT_ALL_VMS); + daoDescs.add(VmInfoDAOImpl.DESC_ADD_VM_INFO); + daoDescs.add(VmInfoDAOImpl.DESC_UPDATE_VM_STOP_TIME); return daoDescs; } diff -r 0e0e2b6041ad -r d387d381858b storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/LimitExpression.java --- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/LimitExpression.java Mon Sep 16 15:28:13 2013 +0200 +++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/LimitExpression.java Wed Sep 25 19:09:58 2013 +0200 @@ -68,7 +68,7 @@ try { PreparedParameter param = params[unfinished.getParameterIndex()]; Class typeClass = param.getType(); - if (typeClass != Integer.class) { + if (typeClass != Integer.class || param.isArrayType()) { String msg = "Invalid parameter type for limit expression. Expected integer!"; IllegalArgumentException e = new IllegalArgumentException(msg); throw e; diff -r 0e0e2b6041ad -r d387d381858b storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/SortMember.java --- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/SortMember.java Mon Sep 16 15:28:13 2013 +0200 +++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/SortMember.java Wed Sep 25 19:09:58 2013 +0200 @@ -81,7 +81,8 @@ if (getSortKey() instanceof Unfinished) { Unfinished unfinished = (Unfinished)getSortKey(); PreparedParameter p = params[unfinished.getParameterIndex()]; - if (p.getType() != String.class) { + // Should only allow patching of ?s type NOT ?s[ + if (p.getType() != String.class || p.isArrayType()) { String msg = "Illegal parameter type for index " + unfinished.getParameterIndex() + ". Expected String!"; diff -r 0e0e2b6041ad -r d387d381858b storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/StatementDescriptorParser.java --- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/StatementDescriptorParser.java Mon Sep 16 15:28:13 2013 +0200 +++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/StatementDescriptorParser.java Wed Sep 25 19:09:58 2013 +0200 @@ -595,11 +595,12 @@ patchNode.setParameterIndex(placeHolderCount - 1); patchNode.setLHS(isLHS); // figure out the expected type - Class expectedType = getType(term.substring(1)); + FreeVarTypeToken expectedType = getType(term.substring(1)); if (expectedType == null) { throw new DescriptorParsingException("Unknown type of free parameter: '" + term + "'"); } - patchNode.setType(expectedType); + patchNode.setType(expectedType.componentType); + patchNode.setArrayType(expectedType.isArrayType); node.setValue(patchNode); return; } @@ -659,7 +660,7 @@ return term.substring(1, term.length() - 1); } - private Class getType(String term) { + private FreeVarTypeToken getType(String term) { if (term.equals("")) { // illegal type return null; @@ -667,61 +668,61 @@ // free variable types can have 1 or 2 characters. assert(term.length() > 0 && term.length() < 3); char switchChar = term.charAt(0); - Class type = null; + FreeVarTypeToken typeToken = null; switch (switchChar) { case 'i': { if (term.length() == 1) { - type = Integer.class; + typeToken = new FreeVarTypeToken(Integer.class, false); } else if (term.length() == 2 && term.charAt(1) == '[') { - type = Integer[].class; + typeToken = new FreeVarTypeToken(Integer.class, true); } break; } case 'l': { if (term.length() == 1) { - type = Long.class; + typeToken = new FreeVarTypeToken(Long.class, false); } else if (term.length() == 2 && term.charAt(1) == '[') { - type = Long[].class; + typeToken = new FreeVarTypeToken(Long.class, true); } break; } case 's': { if (term.length() == 1) { - type = String.class; + typeToken = new FreeVarTypeToken(String.class, false); } else if (term.length() == 2 && term.charAt(1) == '[') { - type = String[].class; + typeToken = new FreeVarTypeToken(String.class, true); } break; } case 'b': { if (term.length() == 1) { - type = Boolean.class; + typeToken = new FreeVarTypeToken(Boolean.class, false); } else if (term.length() == 2 && term.charAt(1) == '[') { - type = Boolean[].class; + typeToken = new FreeVarTypeToken(Boolean.class, true); } break; } case 'd': { if (term.length() == 1) { - type = Double.class; + typeToken = new FreeVarTypeToken(Double.class, false); } else if (term.length() == 2 && term.charAt(1) == '[') { - type = Double[].class; + typeToken = new FreeVarTypeToken(Double.class, true); } break; } case 'p': { if (term.length() == 1) { - type = Pojo.class; + typeToken = new FreeVarTypeToken(Pojo.class, false); } else if (term.length() == 2 && term.charAt(1) == '[') { - type = Pojo[].class; + typeToken = new FreeVarTypeToken(Pojo.class, true); } break; } default: - assert(type == null); + assert(typeToken == null); break; } - return type; + return typeToken; } private String getTerm() throws DescriptorParsingException { @@ -873,4 +874,15 @@ throw new DescriptorParsingException("Unknown statement type: '" + tokens[currTokenIndex] + "'"); } } + + private static class FreeVarTypeToken { + + private final boolean isArrayType; + private final Class componentType; + + private FreeVarTypeToken(Class componentType, boolean isArrayType) { + this.isArrayType = isArrayType; + this.componentType = componentType; + } + } } diff -r 0e0e2b6041ad -r d387d381858b storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/TerminalNode.java --- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/TerminalNode.java Mon Sep 16 15:28:13 2013 +0200 +++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/TerminalNode.java Wed Sep 25 19:09:58 2013 +0200 @@ -41,6 +41,7 @@ import com.redhat.thermostat.storage.core.IllegalPatchException; import com.redhat.thermostat.storage.core.Key; import com.redhat.thermostat.storage.core.PreparedParameter; +import com.redhat.thermostat.storage.model.Pojo; import com.redhat.thermostat.storage.query.LiteralExpression; /** @@ -71,14 +72,8 @@ } catch (Exception e) { throw new IllegalPatchException(e); } - if (param.getType() != patch.getType()) { - String msg = TerminalNode.class.getSimpleName() - + " invalid type when attempting to patch. Expected " - + patch.getType().getName() + " but was " - + param.getType().getName(); - IllegalArgumentException iae = new IllegalArgumentException(msg); - throw new IllegalPatchException(iae); - } + // Do some type sanity checking for free parameters + ensureTypeCompatibility(patch, param); if (patch.isLHS()) { // LHS need to get patched to keys Key valueKey = new Key<>((String)param.getValue()); @@ -93,6 +88,39 @@ return new PatchedWhereExpressionImpl(literalExp); } + private void ensureTypeCompatibility(UnfinishedValueNode patch, + PreparedParameter param) throws IllegalPatchException { + if (patch.getType() == Pojo.class) { + // handle pojo case + if (Pojo.class.isAssignableFrom(param.getType()) && + patch.isArrayType() == param.isArrayType()) { + return; // pojo-type match: OK + } + // dead-end + IllegalArgumentException iae = constructIllegalArgumentException(patch, param); + throw new IllegalPatchException(iae); + } else { + // primitive types or primitive list types + if (param.getType() != patch.getType() || param.isArrayType() != patch.isArrayType()) { + IllegalArgumentException iae = constructIllegalArgumentException(patch, param); + throw new IllegalPatchException(iae); + } + // passed primitive (array) type check + } + } + + private IllegalArgumentException constructIllegalArgumentException( + UnfinishedValueNode patch, PreparedParameter param) { + String patchArrayPrefix = patch.isArrayType() ? "[" : ""; + String paramArrayPrefix = param.isArrayType() ? "[" : ""; + String msg = TerminalNode.class.getSimpleName() + + " invalid type when attempting to patch. Expected " + + patchArrayPrefix + patch.getType().getName() + " but was " + + paramArrayPrefix + param.getType().getName(); + IllegalArgumentException iae = new IllegalArgumentException(msg); + return iae; + } + @Override public boolean equals(Object other) { if (other == null) { diff -r 0e0e2b6041ad -r d387d381858b storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/UnfinishedValueNode.java --- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/UnfinishedValueNode.java Mon Sep 16 15:28:13 2013 +0200 +++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/UnfinishedValueNode.java Wed Sep 25 19:09:58 2013 +0200 @@ -52,8 +52,11 @@ // determines if this patched value is a LHS or if false a RHS of a // binary comparison. private boolean isLHS; - // Specifies the expected type of this free parameter. + // Specifies the expected (component) type of this free parameter. private Class type; + // Specifies if the free parameter is an array type. If so, the + // type instance variable represents the component type. + private boolean isArrayType; Class getType() { return type; @@ -81,6 +84,14 @@ this.parameterIndex = parameterIndex; } + public boolean isArrayType() { + return isArrayType; + } + + public void setArrayType(boolean isArrayType) { + this.isArrayType = isArrayType; + } + @Override public String toString() { return "Unfinished value (" + getParameterIndex() + ") " + getType() + @@ -98,12 +109,13 @@ } UnfinishedValueNode o = (UnfinishedValueNode)other; return basics && Objects.equals(isLHS(), o.isLHS) && - Objects.equals(getType(), o.getType()); + Objects.equals(getType(), o.getType()) && + isArrayType() == o.isArrayType(); } @Override public int hashCode() { - return Objects.hash(getParameterIndex(), isLHS(), getType()); + return Objects.hash(getParameterIndex(), isLHS(), getType(), isArrayType()); } } diff -r 0e0e2b6041ad -r d387d381858b storage/core/src/test/java/com/redhat/thermostat/storage/core/QueuedBackingStorageTest.java --- a/storage/core/src/test/java/com/redhat/thermostat/storage/core/QueuedBackingStorageTest.java Mon Sep 16 15:28:13 2013 +0200 +++ b/storage/core/src/test/java/com/redhat/thermostat/storage/core/QueuedBackingStorageTest.java Wed Sep 25 19:09:58 2013 +0200 @@ -159,6 +159,7 @@ private QueuedBackingStorage queuedStorage; private BackingStorage delegateStorage; private Query delegateQuery; + private Replace delegateReplace; private TestExecutor executor; private TestExecutor fileExecutor; @@ -172,10 +173,12 @@ fileExecutor = new TestExecutor(); delegateStorage = mock(BackingStorage.class); + delegateReplace = mock(Replace.class); delegateQuery = (Query) mock(Query.class); expectedResults = (Cursor) mock(Cursor.class); when(delegateStorage.createQuery(any(Category.class))).thenReturn(delegateQuery); when(delegateQuery.execute()).thenReturn(expectedResults); + when(delegateStorage.createReplace(any(Category.class))).thenReturn(delegateReplace); queuedStorage = new QueuedBackingStorage(delegateStorage, executor, fileExecutor); } diff -r 0e0e2b6041ad -r d387d381858b storage/core/src/test/java/com/redhat/thermostat/storage/core/QueuedStorageTest.java --- a/storage/core/src/test/java/com/redhat/thermostat/storage/core/QueuedStorageTest.java Mon Sep 16 15:28:13 2013 +0200 +++ b/storage/core/src/test/java/com/redhat/thermostat/storage/core/QueuedStorageTest.java Wed Sep 25 19:09:58 2013 +0200 @@ -42,7 +42,6 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Matchers.same; @@ -56,7 +55,6 @@ import java.io.InputStream; import java.util.Collection; import java.util.List; -import java.util.UUID; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; @@ -69,8 +67,6 @@ import org.junit.Test; import com.redhat.thermostat.storage.model.Pojo; -import com.redhat.thermostat.storage.query.Expression; -import com.redhat.thermostat.storage.query.ExpressionFactory; public class QueuedStorageTest { @@ -197,29 +193,19 @@ } private QueuedStorage queuedStorage; - private Storage delegateStorage; - private Add delegateAdd; - private Replace delegateReplace; + private BackingStorage delegateStorage; private TestExecutor executor; private TestExecutor fileExecutor; private InputStream expectedFile; - @SuppressWarnings("unchecked") @Before public void setUp() { executor = new TestExecutor(); fileExecutor = new TestExecutor(); - delegateStorage = mock(Storage.class); - - delegateAdd = mock(Add.class); - delegateReplace = mock(Replace.class); + delegateStorage = mock(BackingStorage.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); expectedFile = mock(InputStream.class); when(delegateStorage.loadFile(anyString())).thenReturn(expectedFile); queuedStorage = new QueuedStorage(delegateStorage, executor, fileExecutor); @@ -235,56 +221,6 @@ } @Test - public void testReplace() { - Category category = mock(Category.class); - Pojo pojo = mock(Pojo.class); - - Replace replace = queuedStorage.createReplace(category); - replace.setPojo(pojo); - Expression expression = new ExpressionFactory().equalTo(Key.AGENT_ID, "foo"); - replace.where(expression); - replace.apply(); - - Runnable r = executor.getTask(); - assertNotNull(r); - verifyZeroInteractions(delegateStorage); - verifyZeroInteractions(delegateReplace); - - r.run(); - verify(delegateStorage).createReplace(category); - verify(delegateReplace).setPojo(pojo); - verify(delegateReplace).where(expression); - verify(delegateReplace).apply(); - verifyNoMoreInteractions(delegateStorage); - - assertNull(fileExecutor.getTask()); - } - - @SuppressWarnings("unchecked") - @Test - public void testUpdatePojo() { - Update delegateUpdate = mock(Update.class); - when(delegateStorage.createUpdate(any(Category.class))).thenReturn(delegateUpdate); - - Category category = mock(Category.class); - - Update update = queuedStorage.createUpdate(category); - verify(delegateStorage).createUpdate(category); - verifyNoMoreInteractions(delegateStorage); - - update.apply(); - - Runnable r = executor.getTask(); - assertNotNull(r); - verifyZeroInteractions(delegateUpdate); - r.run(); - verify(delegateUpdate).apply(); - verifyNoMoreInteractions(delegateUpdate); - - assertNull(fileExecutor.getTask()); - } - - @Test public void testPurge() { queuedStorage.purge("fluff"); @@ -396,19 +332,7 @@ public Connection getConnection() { // not implemented throw new AssertionError(); - } - - @Override - public Add createAdd(Category category) { - // not implemented - throw new AssertionError(); - } - - @Override - public Replace createReplace(Category category) { - // not implemented - throw new AssertionError(); - } + } @Override public void purge(String agentId) { @@ -430,18 +354,6 @@ } @Override - public Update createUpdate(Category category) { - // not implemented - throw new AssertionError(); - } - - @Override - public Remove createRemove(Category category) { - // not implemented - throw new AssertionError(); - } - - @Override public void shutdown() { shutDownTime = System.currentTimeMillis(); // delay shutdown just a little diff -r 0e0e2b6041ad -r d387d381858b storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/DAOImplStatementDescriptorRegistrationTest.java --- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/DAOImplStatementDescriptorRegistrationTest.java Mon Sep 16 15:28:13 2013 +0200 +++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/DAOImplStatementDescriptorRegistrationTest.java Wed Sep 25 19:09:58 2013 +0200 @@ -62,7 +62,7 @@ public void registersAllQueries() { DAOImplStatementDescriptorRegistration reg = new DAOImplStatementDescriptorRegistration(); Set descriptors = reg.getStatementDescriptors(); - assertEquals(13, descriptors.size()); + assertEquals(22, descriptors.size()); assertFalse(descriptors.contains(null)); } @@ -80,7 +80,7 @@ registrations.add(r); } assertEquals(1, registrations.size()); - assertEquals(13, registrations.get(0).getStatementDescriptors().size()); + assertEquals(22, registrations.get(0).getStatementDescriptors().size()); } @Test @@ -98,9 +98,11 @@ DAOImplStatementDescriptorRegistration factory = new DAOImplStatementDescriptorRegistration(); List errorList = new ArrayList<>(); for (String desc: factory.getStatementDescriptors()) { - // should be able to get metadata for all descriptors + // should be able to get metadata for all query descriptors try { - factory.getDescriptorMetadata(desc, fakeParams); + if (desc.startsWith("QUERY")) { + factory.getDescriptorMetadata(desc, fakeParams); + } } catch (IllegalArgumentException e) { errorList.add(e.getMessage()); } diff -r 0e0e2b6041ad -r d387d381858b storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/LimitExpressionTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/LimitExpressionTest.java Wed Sep 25 19:09:58 2013 +0200 @@ -0,0 +1,111 @@ +/* + * Copyright 2012, 2013 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 + * . + * + * 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.storage.internal.statement; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import org.junit.Before; +import org.junit.Test; + +import com.redhat.thermostat.storage.core.IllegalPatchException; +import com.redhat.thermostat.storage.core.PreparedParameter; + +public class LimitExpressionTest { + + private LimitExpression expn; + + @Before + public void setup() { + expn = new LimitExpression(); + UnfinishedLimitValue unfinished = new UnfinishedLimitValue(); + unfinished.setParameterIndex(0); + expn.setValue(unfinished); + } + + @Test + public void canPatchWithInt() { + PreparedParameter p = new PreparedParameter(); + p.setType(Integer.class); + p.setArrayType(false); + p.setValue(3); + + PatchedLimitExpression pLimit = null; + try { + pLimit = expn.patch(new PreparedParameter[] { p }); + // pass + } catch (IllegalPatchException e) { + fail(e.getMessage()); + } + assertNotNull(pLimit); + assertEquals(3, pLimit.getLimitValue()); + } + + @Test + public void rejectPatchWithIntList() { + PreparedParameter p = new PreparedParameter(); + p.setType(Integer.class); + p.setArrayType(true); + p.setValue(new int[] { 3 }); + + try { + expn.patch(new PreparedParameter[] { p }); + fail("Should not be able to patch with int list"); + } catch (IllegalPatchException e) { + // pass + assertTrue(e.getMessage().contains("Invalid parameter type for limit expression.")); + } + } + + @Test + public void rejectPatchWithString() { + PreparedParameter p = new PreparedParameter(); + p.setType(String.class); + p.setArrayType(false); + p.setValue("foo"); + + try { + expn.patch(new PreparedParameter[] { p }); + fail("Should not be able to patch with wrong type"); + } catch (IllegalPatchException e) { + // pass + assertTrue(e.getMessage().contains("Invalid parameter type for limit expression.")); + } + } +} diff -r 0e0e2b6041ad -r d387d381858b storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/ParsedStatementImplTest.java --- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/ParsedStatementImplTest.java Mon Sep 16 15:28:13 2013 +0200 +++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/ParsedStatementImplTest.java Wed Sep 25 19:09:58 2013 +0200 @@ -395,7 +395,8 @@ TerminalNode somePropertyVal = new TerminalNode(null); UnfinishedValueNode unfinishedPojoList = new UnfinishedValueNode(); unfinishedPojoList.setLHS(false); - unfinishedPojoList.setType(Pojo[].class); + unfinishedPojoList.setType(Pojo.class); + unfinishedPojoList.setArrayType(true); unfinishedPojoList.setParameterIndex(0); somePropertyVal.setValue(unfinishedPojoList); SetListValue value = new SetListValue(); diff -r 0e0e2b6041ad -r d387d381858b storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/PatchedSetListPojoConverterTest.java --- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/PatchedSetListPojoConverterTest.java Mon Sep 16 15:28:13 2013 +0200 +++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/PatchedSetListPojoConverterTest.java Wed Sep 25 19:09:58 2013 +0200 @@ -36,14 +36,14 @@ package com.redhat.thermostat.storage.internal.statement; -import org.junit.Test; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import org.junit.Test; + import com.redhat.thermostat.storage.core.Key; import com.redhat.thermostat.storage.internal.statement.PatchedSetListPojoConverter.IllegalPojoException; import com.redhat.thermostat.storage.model.Pojo; @@ -67,6 +67,30 @@ } @Test + public void testConversionWithLists() throws IllegalPojoException { + PatchedSetListMember mem1 = new PatchedSetListMember(new Key<>("foo"), "foo-val"); + PatchedSetListMember mem2 = new PatchedSetListMember(new Key<>("barKey"), Long.MAX_VALUE); + double[] list = new double[] {Math.PI, 3.3}; + PatchedSetListMember mem3 = new PatchedSetListMember(new Key<>("doubleList"), list); + PatchedSetListMember[] members = new PatchedSetListMember[] { + mem1, + mem2, + mem3 + }; + PatchedSetList setList = mock(PatchedSetList.class); + when(setList.getSetListMembers()).thenReturn(members); + PatchedSetListPojoConverter converter = new PatchedSetListPojoConverter<>(setList, ListPojo.class); + ListPojo instance = converter.convertToPojo(); + assertEquals("foo-val", instance.getFoo()); + assertEquals(Long.MAX_VALUE, instance.getBarKey()); + double[] values = instance.getDoubleList(); + assertEquals(2, values.length); + double delta = 0.002; + assertEquals(Math.PI, values[0], delta); + assertEquals(3.3, values[1], delta); + } + + @Test public void testConversionFailBasic() { PatchedSetListMember mem1 = new PatchedSetListMember(new Key<>("wrong-Prop"), "foo-val"); PatchedSetListMember[] members = new PatchedSetListMember[] { @@ -102,4 +126,17 @@ this.barKey = barKey; } } + + public static class ListPojo extends TestMe { + + private double[] doubleList; + + public double[] getDoubleList() { + return doubleList; + } + public void setDoubleList(double[] doubleList) { + this.doubleList = doubleList; + } + + } } diff -r 0e0e2b6041ad -r d387d381858b storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/SortMemberTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/SortMemberTest.java Wed Sep 25 19:09:58 2013 +0200 @@ -0,0 +1,112 @@ +/* + * Copyright 2012, 2013 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 + * . + * + * 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.storage.internal.statement; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import org.junit.Before; +import org.junit.Test; + +import com.redhat.thermostat.storage.core.IllegalPatchException; +import com.redhat.thermostat.storage.core.Key; +import com.redhat.thermostat.storage.core.PreparedParameter; +import com.redhat.thermostat.storage.core.Query.SortDirection; + +public class SortMemberTest { + + private SortMember member; + + @Before + public void setup() { + member = new SortMember(); + member.setDirection(SortDirection.ASCENDING); + UnfinishedSortKey unfinished = new UnfinishedSortKey(); + unfinished.setParameterIndex(0); + member.setSortKey(unfinished); + } + + @Test + public void testPatchWithString() { + PreparedParameter p = new PreparedParameter(); + p.setType(String.class); + p.setArrayType(false); + p.setValue("foo"); + PatchedSortMemberExpression expn = null; + try { + // test patching + expn = member.patch(new PreparedParameter[] { p }); + // pass + } catch (IllegalPatchException e) { + fail(e.getMessage()); + } + assertNotNull(expn); + assertEquals(new Key<>("foo"), expn.getSortMember().getSortKey()); + } + + @Test + public void rejectPatchWithStringList() { + PreparedParameter p = new PreparedParameter(); + p.setType(String.class); + p.setArrayType(true); + p.setValue(new String[] { "foo" }); + try { + member.patch(new PreparedParameter[] { p }); + fail("Patching with string list should not be possible!"); + } catch (IllegalPatchException e) { + // pass + assertTrue(e.getMessage().contains("Illegal parameter type")); + } + } + + @Test + public void rejectPatchWithNumber() { + PreparedParameter p = new PreparedParameter(); + p.setType(Integer.class); + p.setArrayType(false); + p.setValue(1); + try { + member.patch(new PreparedParameter[] { p }); + fail("Patching with integer should not be possible!"); + } catch (IllegalPatchException e) { + // pass + assertTrue(e.getMessage().contains("Illegal parameter type")); + } + } +} diff -r 0e0e2b6041ad -r d387d381858b storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/StatementDescriptorParserTest.java --- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/StatementDescriptorParserTest.java Mon Sep 16 15:28:13 2013 +0200 +++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/StatementDescriptorParserTest.java Wed Sep 25 19:09:58 2013 +0200 @@ -247,7 +247,8 @@ String descString = "ADD " + AgentInfoDAO.CATEGORY.getName() + " SET 'a' = ?s["; UnfinishedValueNode unfinished = new UnfinishedValueNode(); unfinished.setLHS(false); - unfinished.setType(String[].class); + unfinished.setType(String.class); + unfinished.setArrayType(true); unfinished.setParameterIndex(0); doListTypeTest(descString, unfinished); } @@ -262,7 +263,8 @@ String descString = "ADD " + AgentInfoDAO.CATEGORY.getName() + " SET 'a' = ?d["; UnfinishedValueNode unfinished = new UnfinishedValueNode(); unfinished.setLHS(false); - unfinished.setType(Double[].class); + unfinished.setType(Double.class); + unfinished.setArrayType(true); unfinished.setParameterIndex(0); doListTypeTest(descString, unfinished); } @@ -277,7 +279,8 @@ String descString = "ADD " + AgentInfoDAO.CATEGORY.getName() + " SET 'a' = ?i["; UnfinishedValueNode unfinished = new UnfinishedValueNode(); unfinished.setLHS(false); - unfinished.setType(Integer[].class); + unfinished.setType(Integer.class); + unfinished.setArrayType(true); unfinished.setParameterIndex(0); doListTypeTest(descString, unfinished); } @@ -292,7 +295,8 @@ String descString = "ADD " + AgentInfoDAO.CATEGORY.getName() + " SET 'a' = ?b["; UnfinishedValueNode unfinished = new UnfinishedValueNode(); unfinished.setLHS(false); - unfinished.setType(Boolean[].class); + unfinished.setType(Boolean.class); + unfinished.setArrayType(true); unfinished.setParameterIndex(0); doListTypeTest(descString, unfinished); } @@ -307,7 +311,8 @@ String descString = "ADD " + AgentInfoDAO.CATEGORY.getName() + " SET 'a' = ?l["; UnfinishedValueNode unfinished = new UnfinishedValueNode(); unfinished.setLHS(false); - unfinished.setType(Long[].class); + unfinished.setType(Long.class); + unfinished.setArrayType(true); unfinished.setParameterIndex(0); doListTypeTest(descString, unfinished); } @@ -337,7 +342,8 @@ String descString = "ADD " + AgentInfoDAO.CATEGORY.getName() + " SET 'a' = ?p["; UnfinishedValueNode unfinished = new UnfinishedValueNode(); unfinished.setLHS(false); - unfinished.setType(Pojo[].class); + unfinished.setType(Pojo.class); + unfinished.setArrayType(true); unfinished.setParameterIndex(0); doListTypeTest(descString, unfinished); } diff -r 0e0e2b6041ad -r d387d381858b storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/TerminalNodeTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/TerminalNodeTest.java Wed Sep 25 19:09:58 2013 +0200 @@ -0,0 +1,186 @@ +/* + * Copyright 2012, 2013 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 + * . + * + * 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.storage.internal.statement; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import org.junit.Test; + +import com.redhat.thermostat.storage.core.IllegalPatchException; +import com.redhat.thermostat.storage.core.PreparedParameter; +import com.redhat.thermostat.storage.model.AgentInformation; +import com.redhat.thermostat.storage.model.Pojo; +import com.redhat.thermostat.storage.query.LiteralExpression; + +public class TerminalNodeTest { + + @Test + public void canPatchWithCorrectType() { + TerminalNode node = new TerminalNode(null); + UnfinishedValueNode unfinished = new UnfinishedValueNode(); + unfinished.setLHS(false); + unfinished.setParameterIndex(0); + unfinished.setType(String.class); + unfinished.setArrayType(false); + + node.setValue(unfinished); + + PreparedParameter p = new PreparedParameter(); + p.setType(String.class); + p.setArrayType(false); + p.setValue("foo-bar"); + + PatchedWhereExpression expn = null; + try { + expn = node.patch(new PreparedParameter[] { p }); + // pass + } catch (IllegalPatchException e) { + fail(e.getMessage()); + } + assertNotNull(expn); + LiteralExpression literal = (LiteralExpression)expn.getExpression(); + assertEquals("foo-bar", literal.getValue()); + } + + @Test + public void canPatchWithPojoType() { + TerminalNode node = new TerminalNode(null); + UnfinishedValueNode unfinished = new UnfinishedValueNode(); + unfinished.setLHS(false); + unfinished.setParameterIndex(0); + unfinished.setType(Pojo.class); + unfinished.setArrayType(false); + + node.setValue(unfinished); + + PreparedParameter p = new PreparedParameter(); + p.setType(AgentInformation.class); + p.setArrayType(false); + AgentInformation info = new AgentInformation("foo-bar"); + p.setValue(info); + + PatchedWhereExpression expn = null; + try { + expn = node.patch(new PreparedParameter[] { p }); + // pass + } catch (IllegalPatchException e) { + fail(e.getMessage()); + } + assertNotNull(expn); + LiteralExpression literal = (LiteralExpression)expn.getExpression(); + assertEquals(info, literal.getValue()); + } + + @Test + public void rejectPatchingWithIncorrectListType() { + TerminalNode node = new TerminalNode(null); + UnfinishedValueNode unfinished = new UnfinishedValueNode(); + unfinished.setLHS(false); + unfinished.setParameterIndex(0); + unfinished.setType(String.class); + unfinished.setArrayType(false); + + node.setValue(unfinished); + + PreparedParameter p = new PreparedParameter(); + p.setType(String.class); + p.setArrayType(true); + p.setValue(new String[] { "foo-bar" }); + + try { + node.patch(new PreparedParameter[] { p }); + fail("Should not be able to patch string with string list."); + } catch (IllegalPatchException e) { + // pass + assertTrue(e.getMessage().contains("invalid type when attempting to patch.")); + } + } + + @Test + public void rejectPatchingWithIncorrectPojoListType() { + TerminalNode node = new TerminalNode(null); + UnfinishedValueNode unfinished = new UnfinishedValueNode(); + unfinished.setLHS(false); + unfinished.setParameterIndex(0); + unfinished.setType(Pojo.class); + unfinished.setArrayType(false); + + node.setValue(unfinished); + + PreparedParameter p = new PreparedParameter(); + p.setType(AgentInformation.class); + p.setArrayType(true); + AgentInformation info = new AgentInformation("testing"); + p.setValue(new AgentInformation[] { info }); + + try { + node.patch(new PreparedParameter[] { p }); + fail("Should not be able to patch string with string list."); + } catch (IllegalPatchException e) { + // pass + assertTrue(e.getMessage().contains("invalid type when attempting to patch.")); + } + } + + @Test + public void rejectPatchingWithIncorrectType() { + TerminalNode node = new TerminalNode(null); + UnfinishedValueNode unfinished = new UnfinishedValueNode(); + unfinished.setLHS(false); + unfinished.setParameterIndex(0); + unfinished.setType(Integer.class); + unfinished.setArrayType(false); + + node.setValue(unfinished); + + PreparedParameter p = new PreparedParameter(); + p.setType(String.class); + p.setArrayType(true); + p.setValue(new String[] { "foo-bar" }); + + try { + node.patch(new PreparedParameter[] { p }); + fail("Should not be able to patch integer with string list."); + } catch (IllegalPatchException e) { + // pass + assertTrue(e.getMessage().contains("invalid type when attempting to patch.")); + } + } +} diff -r 0e0e2b6041ad -r d387d381858b storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorage.java --- a/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorage.java Mon Sep 16 15:28:13 2013 +0200 +++ b/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorage.java Wed Sep 25 19:09:58 2013 +0200 @@ -407,10 +407,9 @@ @Override public PreparedStatement prepareStatement(StatementDescriptor statementDesc) throws DescriptorParsingException { - // FIXME: Use some kind of cache in order to avoid parsing of - // descriptors each time this is called. At least if the descriptor - // class is the same we should be able to do something here. - return PreparedStatementFactory.getInstance(this, statementDesc); + // Queued storage decorator should override this. This should never + // be called. + throw new IllegalStateException(); } @Override diff -r 0e0e2b6041ad -r d387d381858b thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplStatementDescriptorRegistration.java --- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplStatementDescriptorRegistration.java Mon Sep 16 15:28:13 2013 +0200 +++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplStatementDescriptorRegistration.java Wed Sep 25 19:09:58 2013 +0200 @@ -62,6 +62,11 @@ descs.add(ThreadDaoImpl.QUERY_SUMMARY_SINCE); descs.add(ThreadDaoImpl.QUERY_THREAD_CAPS); descs.add(ThreadDaoImpl.QUERY_THREAD_INFO); + descs.add(ThreadDaoImpl.DESC_ADD_THREAD_DEADLOCK_DATA); + descs.add(ThreadDaoImpl.DESC_ADD_THREAD_HARVESTING_STATUS); + descs.add(ThreadDaoImpl.DESC_ADD_THREAD_INFO); + descs.add(ThreadDaoImpl.DESC_ADD_THREAD_SUMMARY); + descs.add(ThreadDaoImpl.DESC_REPLACE_THREAD_CAPS); } @Override diff -r 0e0e2b6041ad -r d387d381858b thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDAOImplStatementDescriptorRegistrationTest.java --- a/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDAOImplStatementDescriptorRegistrationTest.java Mon Sep 16 15:28:13 2013 +0200 +++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDAOImplStatementDescriptorRegistrationTest.java Wed Sep 25 19:09:58 2013 +0200 @@ -73,10 +73,10 @@ } @Test - public void registersAllQueries() { + public void registersAllDescriptors() { ThreadDaoImplStatementDescriptorRegistration reg = new ThreadDaoImplStatementDescriptorRegistration(); Set descriptors = reg.getStatementDescriptors(); - assertEquals(6, descriptors.size()); + assertEquals(11, descriptors.size()); assertFalse("null descriptor not allowed", descriptors.contains(null)); } @@ -104,7 +104,7 @@ // storage-core + this module assertEquals(2, registrations.size()); assertNotNull(threadDaoReg); - assertEquals(6, threadDaoReg.getStatementDescriptors().size()); + assertEquals(11, threadDaoReg.getStatementDescriptors().size()); } private Triple setupForMetaDataTest() { diff -r 0e0e2b6041ad -r d387d381858b vm-classstat/common/src/main/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOImplStatementDescriptorRegistration.java --- a/vm-classstat/common/src/main/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOImplStatementDescriptorRegistration.java Mon Sep 16 15:28:13 2013 +0200 +++ b/vm-classstat/common/src/main/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOImplStatementDescriptorRegistration.java Wed Sep 25 19:09:58 2013 +0200 @@ -60,6 +60,7 @@ public Set getStatementDescriptors() { Set descs = new HashSet<>(1); descs.add(QUERY); + descs.add(VmClassStatDAOImpl.DESC_ADD_VM_CLASS_STAT); return descs; } diff -r 0e0e2b6041ad -r d387d381858b vm-classstat/common/src/test/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOImplStatementDescriptorRegistrationTest.java --- a/vm-classstat/common/src/test/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOImplStatementDescriptorRegistrationTest.java Mon Sep 16 15:28:13 2013 +0200 +++ b/vm-classstat/common/src/test/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOImplStatementDescriptorRegistrationTest.java Wed Sep 25 19:09:58 2013 +0200 @@ -61,10 +61,10 @@ public class VmClassStatDAOImplStatementDescriptorRegistrationTest { @Test - public void registersAllQueries() { + public void registersAllDescriptors() { VmClassStatDAOImplStatementDescriptorRegistration reg = new VmClassStatDAOImplStatementDescriptorRegistration(); Set descriptors = reg.getStatementDescriptors(); - assertEquals(1, descriptors.size()); + assertEquals(2, descriptors.size()); assertFalse("null descriptor not allowed", descriptors.contains(null)); } @@ -92,7 +92,7 @@ // storage-core + this module assertEquals(2, registrations.size()); assertNotNull(vmClassStatReg); - assertEquals(1, vmClassStatReg.getStatementDescriptors().size()); + assertEquals(2, vmClassStatReg.getStatementDescriptors().size()); } @Test diff -r 0e0e2b6041ad -r d387d381858b vm-cpu/common/src/main/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOImplStatementDescriptorRegistration.java --- a/vm-cpu/common/src/main/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOImplStatementDescriptorRegistration.java Mon Sep 16 15:28:13 2013 +0200 +++ b/vm-cpu/common/src/main/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOImplStatementDescriptorRegistration.java Wed Sep 25 19:09:58 2013 +0200 @@ -59,6 +59,7 @@ @Override public Set getStatementDescriptors() { Set descs = new HashSet<>(); + descs.add(VmCpuStatDAOImpl.DESC_ADD_VM_CPU_STAT); descs.add(descriptor); return descs; } diff -r 0e0e2b6041ad -r d387d381858b vm-cpu/common/src/test/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOImplStatementDescriptorRegistrationTest.java --- a/vm-cpu/common/src/test/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOImplStatementDescriptorRegistrationTest.java Mon Sep 16 15:28:13 2013 +0200 +++ b/vm-cpu/common/src/test/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOImplStatementDescriptorRegistrationTest.java Wed Sep 25 19:09:58 2013 +0200 @@ -61,10 +61,10 @@ public class VmCpuStatDAOImplStatementDescriptorRegistrationTest { @Test - public void registersAllQueries() { + public void registersAllDescriptors() { VmCpuStatDAOImplStatementDescriptorRegistration reg = new VmCpuStatDAOImplStatementDescriptorRegistration(); Set descriptors = reg.getStatementDescriptors(); - assertEquals(1, descriptors.size()); + assertEquals(2, descriptors.size()); assertFalse("null descriptor not allowed", descriptors.contains(null)); } @@ -92,7 +92,7 @@ // storage-core + this module assertEquals(2, registrations.size()); assertNotNull(vmCpuStatReg); - assertEquals(1, vmCpuStatReg.getStatementDescriptors().size()); + assertEquals(2, vmCpuStatReg.getStatementDescriptors().size()); } @Test diff -r 0e0e2b6041ad -r d387d381858b vm-gc/common/src/main/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOImplStatementDescriptorRegistration.java --- a/vm-gc/common/src/main/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOImplStatementDescriptorRegistration.java Mon Sep 16 15:28:13 2013 +0200 +++ b/vm-gc/common/src/main/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOImplStatementDescriptorRegistration.java Wed Sep 25 19:09:58 2013 +0200 @@ -61,6 +61,7 @@ public Set getStatementDescriptors() { Set descs = new HashSet<>(); descs.add(descriptor); + descs.add(VmGcStatDAOImpl.DESC_ADD_VM_GC_STAT); return descs; } diff -r 0e0e2b6041ad -r d387d381858b vm-gc/common/src/test/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOImplStatementDescriptorRegistrationTest.java --- a/vm-gc/common/src/test/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOImplStatementDescriptorRegistrationTest.java Mon Sep 16 15:28:13 2013 +0200 +++ b/vm-gc/common/src/test/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOImplStatementDescriptorRegistrationTest.java Wed Sep 25 19:09:58 2013 +0200 @@ -61,10 +61,10 @@ public class VmGcStatDAOImplStatementDescriptorRegistrationTest { @Test - public void registersAllQueries() { + public void registersAllDescriptors() { VmGcStatDAOImplStatementDescriptorRegistration reg = new VmGcStatDAOImplStatementDescriptorRegistration(); Set descriptors = reg.getStatementDescriptors(); - assertEquals(1, descriptors.size()); + assertEquals(2, descriptors.size()); assertFalse("null descriptor not allowed", descriptors.contains(null)); } @@ -92,7 +92,7 @@ // storage-core + this module assertEquals(2, registrations.size()); assertNotNull(vmGcStatReg); - assertEquals(1, vmGcStatReg.getStatementDescriptors().size()); + assertEquals(2, vmGcStatReg.getStatementDescriptors().size()); } @Test diff -r 0e0e2b6041ad -r d387d381858b vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOImplStatementDescriptorRegistration.java --- a/vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOImplStatementDescriptorRegistration.java Mon Sep 16 15:28:13 2013 +0200 +++ b/vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOImplStatementDescriptorRegistration.java Wed Sep 25 19:09:58 2013 +0200 @@ -56,6 +56,7 @@ Set descs = new HashSet<>(2); descs.add(HeapDAOImpl.QUERY_ALL_HEAPS); descs.add(HeapDAOImpl.QUERY_HEAP_INFO); + descs.add(HeapDAOImpl.DESC_ADD_VM_HEAP_INFO); return descs; } diff -r 0e0e2b6041ad -r d387d381858b vm-heap-analysis/common/src/test/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOImplStatementDescriptorRegistrationTest.java --- a/vm-heap-analysis/common/src/test/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOImplStatementDescriptorRegistrationTest.java Mon Sep 16 15:28:13 2013 +0200 +++ b/vm-heap-analysis/common/src/test/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOImplStatementDescriptorRegistrationTest.java Wed Sep 25 19:09:58 2013 +0200 @@ -61,10 +61,10 @@ public class HeapDAOImplStatementDescriptorRegistrationTest { @Test - public void registersAllQueries() { + public void registersAllDescriptors() { HeapDAOImplStatementDescriptorRegistration reg = new HeapDAOImplStatementDescriptorRegistration(); Set descriptors = reg.getStatementDescriptors(); - assertEquals(2, descriptors.size()); + assertEquals(3, descriptors.size()); assertFalse("null descriptor not allowed", descriptors.contains(null)); } @@ -92,7 +92,7 @@ // storage-core + this module assertEquals(2, registrations.size()); assertNotNull(heapDaoReg); - assertEquals(2, heapDaoReg.getStatementDescriptors().size()); + assertEquals(3, heapDaoReg.getStatementDescriptors().size()); } @Test diff -r 0e0e2b6041ad -r d387d381858b vm-jmx/common/src/main/java/com/redhat/thermostat/vm/jmx/common/internal/JmxNotificationDAOImplStatementDescriptorRegistration.java --- a/vm-jmx/common/src/main/java/com/redhat/thermostat/vm/jmx/common/internal/JmxNotificationDAOImplStatementDescriptorRegistration.java Mon Sep 16 15:28:13 2013 +0200 +++ b/vm-jmx/common/src/main/java/com/redhat/thermostat/vm/jmx/common/internal/JmxNotificationDAOImplStatementDescriptorRegistration.java Wed Sep 25 19:09:58 2013 +0200 @@ -57,6 +57,8 @@ descs = new HashSet<>(2); descs.add(JmxNotificationDAOImpl.QUERY_LATEST_NOTIFICATION_STATUS); descs.add(JmxNotificationDAOImpl.QUERY_NOTIFICATIONS); + descs.add(JmxNotificationDAOImpl.DESC_ADD_NOTIFICATION); + descs.add(JmxNotificationDAOImpl.DESC_ADD_NOTIFICATION_STATUS); } @Override diff -r 0e0e2b6041ad -r d387d381858b vm-jmx/common/src/test/java/com/redhat/thermostat/vm/jmx/common/internal/JmxNotificationDAOImplStatementDescriptorRegistrationTest.java --- a/vm-jmx/common/src/test/java/com/redhat/thermostat/vm/jmx/common/internal/JmxNotificationDAOImplStatementDescriptorRegistrationTest.java Mon Sep 16 15:28:13 2013 +0200 +++ b/vm-jmx/common/src/test/java/com/redhat/thermostat/vm/jmx/common/internal/JmxNotificationDAOImplStatementDescriptorRegistrationTest.java Wed Sep 25 19:09:58 2013 +0200 @@ -61,10 +61,10 @@ public class JmxNotificationDAOImplStatementDescriptorRegistrationTest { @Test - public void registersAllQueries() { + public void registersAllDescriptors() { JmxNotificationDAOImplStatementDescriptorRegistration reg = new JmxNotificationDAOImplStatementDescriptorRegistration(); Set descriptors = reg.getStatementDescriptors(); - assertEquals(2, descriptors.size()); + assertEquals(4, descriptors.size()); assertFalse("null descriptor not allowed", descriptors.contains(null)); } @@ -92,7 +92,7 @@ // storage-core + this module assertEquals(2, registrations.size()); assertNotNull(jmxDaoReg); - assertEquals(2, jmxDaoReg.getStatementDescriptors().size()); + assertEquals(4, jmxDaoReg.getStatementDescriptors().size()); } @Test diff -r 0e0e2b6041ad -r d387d381858b vm-memory/common/src/main/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOImplStatementDescriptorRegistration.java --- a/vm-memory/common/src/main/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOImplStatementDescriptorRegistration.java Mon Sep 16 15:28:13 2013 +0200 +++ b/vm-memory/common/src/main/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOImplStatementDescriptorRegistration.java Wed Sep 25 19:09:58 2013 +0200 @@ -61,6 +61,7 @@ VmMemoryStatDAO.vmMemoryStatsCategory.getName()); descs.add(descriptor); descs.add(VmMemoryStatDAOImpl.QUERY_LATEST); + descs.add(VmMemoryStatDAOImpl.DESC_ADD_VM_MEMORY_STAT); } @Override diff -r 0e0e2b6041ad -r d387d381858b vm-memory/common/src/test/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOImplStatementDescriptorRegistrationTest.java --- a/vm-memory/common/src/test/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOImplStatementDescriptorRegistrationTest.java Mon Sep 16 15:28:13 2013 +0200 +++ b/vm-memory/common/src/test/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOImplStatementDescriptorRegistrationTest.java Wed Sep 25 19:09:58 2013 +0200 @@ -63,10 +63,10 @@ public class VmMemoryStatDAOImplStatementDescriptorRegistrationTest { @Test - public void registersAllQueries() { + public void registersAllDescriptors() { VmMemoryStatDAOImplStatementDescriptorRegistration reg = new VmMemoryStatDAOImplStatementDescriptorRegistration(); Set descriptors = reg.getStatementDescriptors(); - assertEquals(2, descriptors.size()); + assertEquals(3, descriptors.size()); assertFalse("null descriptor not allowed", descriptors.contains(null)); } @@ -94,7 +94,7 @@ // storage-core + this module assertEquals(2, registrations.size()); assertNotNull(vmMemoryDaoReg); - assertEquals(2, vmMemoryDaoReg.getStatementDescriptors().size()); + assertEquals(3, vmMemoryDaoReg.getStatementDescriptors().size()); } @Test diff -r 0e0e2b6041ad -r d387d381858b web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebStorage.java --- a/web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebStorage.java Mon Sep 16 15:28:13 2013 +0200 +++ b/web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebStorage.java Wed Sep 25 19:09:58 2013 +0200 @@ -42,12 +42,10 @@ import java.io.InputStreamReader; import java.io.OutputStream; import java.io.Reader; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Type; import java.net.MalformedURLException; import java.net.URL; import java.security.SecureRandom; -import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; @@ -59,7 +57,6 @@ import javax.net.ssl.SSLContext; import javax.servlet.http.HttpServletResponse; -import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.codec.binary.Base64; import org.apache.http.Header; import org.apache.http.HttpEntity; @@ -88,42 +85,29 @@ import com.redhat.thermostat.common.utils.LoggingUtils; import com.redhat.thermostat.storage.config.AuthenticationConfiguration; import com.redhat.thermostat.storage.config.StartupConfiguration; -import com.redhat.thermostat.storage.core.Add; import com.redhat.thermostat.storage.core.AuthToken; 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; -import com.redhat.thermostat.storage.core.Key; import com.redhat.thermostat.storage.core.PreparedParameter; import com.redhat.thermostat.storage.core.PreparedStatement; -import com.redhat.thermostat.storage.core.Remove; -import com.redhat.thermostat.storage.core.Replace; import com.redhat.thermostat.storage.core.SecureStorage; import com.redhat.thermostat.storage.core.StatementDescriptor; import com.redhat.thermostat.storage.core.StatementExecutionException; import com.redhat.thermostat.storage.core.Storage; import com.redhat.thermostat.storage.core.StorageException; -import com.redhat.thermostat.storage.core.Update; import com.redhat.thermostat.storage.model.Pojo; -import com.redhat.thermostat.storage.query.Expression; -import com.redhat.thermostat.storage.query.Operator; -import com.redhat.thermostat.web.common.ExpressionSerializer; -import com.redhat.thermostat.web.common.OperatorSerializer; import com.redhat.thermostat.web.common.PreparedParameterSerializer; +import com.redhat.thermostat.web.common.PreparedStatementResponseCode; import com.redhat.thermostat.web.common.ThermostatGSONConverter; -import com.redhat.thermostat.web.common.WebAdd; import com.redhat.thermostat.web.common.WebPreparedStatement; import com.redhat.thermostat.web.common.WebPreparedStatementResponse; import com.redhat.thermostat.web.common.WebPreparedStatementSerializer; import com.redhat.thermostat.web.common.WebQueryResponse; import com.redhat.thermostat.web.common.WebQueryResponseSerializer; -import com.redhat.thermostat.web.common.WebRemove; -import com.redhat.thermostat.web.common.WebReplace; -import com.redhat.thermostat.web.common.WebUpdate; public class WebStorage implements Storage, SecureStorage { @@ -299,53 +283,6 @@ } - private class WebAddImpl extends WebAdd { - - private WebAddImpl(int categoryId) { - super(categoryId); - } - - @Override - public int apply() { - return addImpl(this); - } - - } - - private class WebReplaceImpl extends WebReplace { - - private WebReplaceImpl(int categoryId) { - super(categoryId); - } - - @Override - public int apply() { - return replaceImpl(this); - } - - } - - private class WebUpdateImpl extends WebUpdate { - - @Override - public int apply() { - return updatePojo(this); - } - } - - private class WebRemoveImpl extends WebRemove { - - private WebRemoveImpl(int categoryId) { - super(categoryId); - } - - @Override - public int apply() { - return removePojo(this); - } - - } - private class WebPreparedStatementImpl extends WebPreparedStatement { // The type of the query result objects we'd get back upon @@ -359,7 +296,7 @@ @Override public int execute() throws StatementExecutionException { - throw new IllegalStateException("Not yet implemented!"); + return doWriteExecute(this); } @Override @@ -396,9 +333,6 @@ categoryIds = new HashMap<>(); gson = new GsonBuilder().registerTypeHierarchyAdapter(Pojo.class, new ThermostatGSONConverter()) - .registerTypeHierarchyAdapter(Expression.class, - new ExpressionSerializer()) - .registerTypeHierarchyAdapter(Operator.class, new OperatorSerializer()) .registerTypeAdapter(WebPreparedStatement.class, new WebPreparedStatementSerializer()) .registerTypeAdapter(WebQueryResponse.class, new WebQueryResponseSerializer<>()) .registerTypeAdapter(PreparedParameter.class, new PreparedParameterSerializer()) @@ -531,18 +465,6 @@ } } - @Override - public Remove createRemove(Category category) { - return new WebRemoveImpl<>(categoryIds.get(category)); - } - - @Override - public Update createUpdate(Category category) { - WebUpdateImpl updateImpl = new WebUpdateImpl<>(); - updateImpl.setCategoryId(categoryIds.get(category)); - return updateImpl; - } - /** * Executes a prepared query * @@ -569,10 +491,10 @@ } catch (Exception e) { throw new StatementExecutionException(e); } - if (qResp.getResponseCode() == WebQueryResponse.SUCCESS) { + if (qResp.getResponseCode() == PreparedStatementResponseCode.QUERY_SUCCESS) { T[] result = qResp.getResultList(); return new WebCursor(result); - } else if (qResp.getResponseCode() == WebQueryResponse.ILLEGAL_PATCH) { + } else if (qResp.getResponseCode() == PreparedStatementResponseCode.ILLEGAL_PATCH) { String msg = "Illegal statement argument. See server logs for details."; IllegalArgumentException iae = new IllegalArgumentException(msg); IllegalPatchException e = new IllegalPatchException(iae); @@ -586,6 +508,38 @@ throw new StatementExecutionException(ise); } } + + /** + * Executes a prepared write + * + * @param stmt + * The prepared statement to execute + * @return The response code of executing the underlying data modifying + * statement. + * @throws StatementExecutionException + * If execution of the statement failed. For example if the + * values set as prepared parameters did not work or were + * partially missing for the prepared statement. + */ + private int doWriteExecute(WebPreparedStatement stmt) + throws StatementExecutionException { + NameValuePair queryParam = new BasicNameValuePair("prepared-stmt", gson.toJson(stmt, WebPreparedStatement.class)); + List formparams = Arrays.asList(queryParam); + int responseCode = PreparedStatementResponseCode.WRITE_GENERIC_FAILURE; + try (CloseableHttpEntity entity = post(endpoint + "/write-execute", formparams)) { + Reader reader = getContentAsReader(entity); + responseCode = gson.fromJson(reader, int.class); + } catch (Exception e) { + throw new StatementExecutionException(e); + } + if (responseCode == PreparedStatementResponseCode.ILLEGAL_PATCH) { + String msg = "Illegal statement argument. See server logs for details."; + IllegalArgumentException iae = new IllegalArgumentException(msg); + IllegalPatchException e = new IllegalPatchException(iae); + throw new StatementExecutionException(e); + } + return responseCode; + } @Override public Connection getConnection() { @@ -628,80 +582,6 @@ post(endpoint + "/purge", agentIdParams).close(); } - @Override - public Add createAdd(Category into) { - int categoryId = getCategoryId(into); - WebAdd add = new WebAddImpl<>(categoryId); - return add; - } - - @Override - public Replace createReplace(Category into) { - int categoryId = getCategoryId(into); - WebReplace replace = new WebReplaceImpl<>(categoryId); - return replace; - } - - private int addImpl(final WebAdd add) throws StorageException { - Pojo pojo = add.getPojo(); - checkAgentIdIsSet(pojo); - NameValuePair pojoParam = new BasicNameValuePair("pojo", - gson.toJson(pojo)); - NameValuePair addParam = new BasicNameValuePair("add", - gson.toJson(add)); - List formParams = Arrays.asList(addParam, pojoParam); - post(endpoint + "/add-pojo", formParams).close(); - return DataModifyingStatement.DEFAULT_STATUS_SUCCESS; - } - - private int replaceImpl(final WebReplace replace) throws StorageException { - Pojo pojo = replace.getPojo(); - checkAgentIdIsSet(pojo); - NameValuePair replaceParam = new BasicNameValuePair("replace", - gson.toJson(replace)); - NameValuePair pojoParam = new BasicNameValuePair("pojo", - gson.toJson(pojo)); - List formParams = Arrays.asList(replaceParam, pojoParam); - post(endpoint + "/replace-pojo", formParams).close(); - return DataModifyingStatement.DEFAULT_STATUS_SUCCESS; - } - - private void checkAgentIdIsSet(final Pojo pojo) throws AssertionError { - try { - if (BeanUtils.getProperty(pojo, Key.AGENT_ID.getName()) == null) { - throw new AssertionError("agentId must be set!"); - } - } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { - throw new AssertionError("Pojo needs to have an agentId property"); - } - } - - private int removePojo(Remove remove) throws StorageException { - NameValuePair removeParam = new BasicNameValuePair("remove", - gson.toJson(remove)); - List formparams = Arrays.asList(removeParam); - post(endpoint + "/remove-pojo", formparams).close(); - return DataModifyingStatement.DEFAULT_STATUS_SUCCESS; - } - - private int updatePojo(Update update) throws StorageException { - WebUpdate webUp = (WebUpdate) update; - List updateValues = webUp.getUpdates(); - List values = new ArrayList<>(updateValues.size()); - for (WebUpdate.UpdateValue updateValue : updateValues) { - values.add(updateValue.getValue()); - } - - NameValuePair updateParam = new BasicNameValuePair("update", - gson.toJson(update)); - NameValuePair valuesParam = new BasicNameValuePair("values", - gson.toJson(values)); - List formparams = Arrays - .asList(updateParam, valuesParam); - post(endpoint + "/update-pojo", formparams).close(); - return DataModifyingStatement.DEFAULT_STATUS_SUCCESS; - } - public void setEndpoint(String endpoint) { this.endpoint = endpoint; } diff -r 0e0e2b6041ad -r d387d381858b web/client/src/test/java/com/redhat/thermostat/web/client/internal/WebStorageTest.java --- a/web/client/src/test/java/com/redhat/thermostat/web/client/internal/WebStorageTest.java Mon Sep 16 15:28:13 2013 +0200 +++ b/web/client/src/test/java/com/redhat/thermostat/web/client/internal/WebStorageTest.java Wed Sep 25 19:09:58 2013 +0200 @@ -58,10 +58,8 @@ import java.util.Arrays; import java.util.Enumeration; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.NoSuchElementException; -import java.util.UUID; import java.util.concurrent.CountDownLatch; import javax.servlet.ServletException; @@ -86,11 +84,7 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import com.google.gson.JsonArray; -import com.google.gson.JsonParser; -import com.google.gson.JsonSyntaxException; import com.redhat.thermostat.storage.config.StartupConfiguration; -import com.redhat.thermostat.storage.core.Add; import com.redhat.thermostat.storage.core.AuthToken; import com.redhat.thermostat.storage.core.Categories; import com.redhat.thermostat.storage.core.Category; @@ -103,30 +97,19 @@ import com.redhat.thermostat.storage.core.PreparedParameter; import com.redhat.thermostat.storage.core.PreparedParameters; import com.redhat.thermostat.storage.core.PreparedStatement; -import com.redhat.thermostat.storage.core.Remove; -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.Update; import com.redhat.thermostat.storage.model.Pojo; -import com.redhat.thermostat.storage.query.Expression; -import com.redhat.thermostat.storage.query.ExpressionFactory; -import com.redhat.thermostat.storage.query.Operator; import com.redhat.thermostat.test.FreePortFinder; import com.redhat.thermostat.test.FreePortFinder.TryPort; -import com.redhat.thermostat.web.common.ExpressionSerializer; -import com.redhat.thermostat.web.common.OperatorSerializer; import com.redhat.thermostat.web.common.PreparedParameterSerializer; +import com.redhat.thermostat.web.common.PreparedStatementResponseCode; import com.redhat.thermostat.web.common.ThermostatGSONConverter; -import com.redhat.thermostat.web.common.WebAdd; import com.redhat.thermostat.web.common.WebPreparedStatement; import com.redhat.thermostat.web.common.WebPreparedStatementResponse; import com.redhat.thermostat.web.common.WebPreparedStatementSerializer; import com.redhat.thermostat.web.common.WebQueryResponse; import com.redhat.thermostat.web.common.WebQueryResponseSerializer; -import com.redhat.thermostat.web.common.WebRemove; -import com.redhat.thermostat.web.common.WebReplace; -import com.redhat.thermostat.web.common.WebUpdate; public class WebStorageTest { @@ -147,16 +130,13 @@ private static Category category; private static Key key1; - private static Key key2; private WebStorage storage; - private ExpressionFactory factory; @BeforeClass public static void setupCategory() { key1 = new Key<>("property1"); - key2 = new Key<>("property2"); category = new Category<>("test", TestObj.class, key1); } @@ -188,7 +168,6 @@ storage.setEndpoint("http://localhost:" + port + "/"); headers = new HashMap<>(); registerCategory(); - factory = new ExpressionFactory(); } private void startServer(int port) throws Exception { @@ -365,7 +344,7 @@ assertEquals(String.class, params.getParams()[0].getType()); WebQueryResponse fakeQueryResponse = new WebQueryResponse<>(); - fakeQueryResponse.setResponseCode(WebQueryResponse.SUCCESS); + fakeQueryResponse.setResponseCode(PreparedStatementResponseCode.QUERY_SUCCESS); fakeQueryResponse.setResultList(new TestObj[] { obj1, obj2 }); prepareServer(gson.toJson(fakeQueryResponse)); Cursor results = null; @@ -392,181 +371,56 @@ } @Test - public void testAdd() throws IOException, JsonSyntaxException, ClassNotFoundException { - - UUID agentId = new UUID(1, 2); - TestObj obj = new TestObj(); - obj.setProperty1("fluff"); - obj.setAgentId(agentId.toString()); - - Add add = storage.createAdd(category); - add.setPojo(obj); - - prepareServer(); - add.apply(); - - 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("add", parts[0]); - @SuppressWarnings("unchecked") - WebAdd add2 = gson.fromJson(parts[1], WebAdd.class); - assertEquals(42, add2.getCategoryId()); - - parts = params[1].split("="); - assertEquals(2, parts.length); - assertEquals("pojo", parts[0]); - Object resultObj = gson.fromJson(parts[1], TestObj.class); - assertEquals(obj, resultObj); - } - - @Test - public void testReplace() throws IOException, JsonSyntaxException, ClassNotFoundException { - - // We need an agentId, so that we can check automatic insert of agentId. - UUID agentId = new UUID(1, 2); - TestObj obj = new TestObj(); - obj.setAgentId(agentId.toString()); - obj.setProperty1("fluff"); - - Replace replace = storage.createReplace(category); - Expression expr = new ExpressionFactory().equalTo(key1, "fluff"); - replace.setPojo(obj); - replace.where(expr); - - prepareServer(); - replace.apply(); - - Gson gson = new GsonBuilder() - .registerTypeHierarchyAdapter(Expression.class, - new ExpressionSerializer()) - .registerTypeHierarchyAdapter(Operator.class, - new OperatorSerializer()).create(); - 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("replace", parts[0]); - @SuppressWarnings("unchecked") - WebReplace insert = gson.fromJson(parts[1], WebReplace.class); - assertEquals(42, insert.getCategoryId()); - - parts = params[1].split("="); - assertEquals(2, parts.length); - assertEquals("pojo", parts[0]); - Object resultObj = gson.fromJson(parts[1], TestObj.class); - assertEquals(obj, resultObj); - } - - @Test - public void testCreateRemove() { - WebRemove remove = (WebRemove) storage.createRemove(category); - assertEquals(42, remove.getCategoryId()); - Expression expr = factory.equalTo(key1, "test"); - remove.where(expr); - assertEquals(expr, remove.getWhereExpression()); - } - - @Test - public void testRemovePojo() throws UnsupportedEncodingException, IOException { - Expression expr = factory.equalTo(key1, "test"); - Remove remove = storage.createRemove(category); - remove.where(expr); + public void canPrepareAndExecuteWrite() { + TestObj obj1 = new TestObj(); + obj1.setProperty1("fluffor1"); + TestObj obj2 = new TestObj(); + obj2.setProperty1("fluffor2"); + Gson gson = new GsonBuilder().registerTypeAdapter(PreparedParameter.class, new PreparedParameterSerializer()) + .registerTypeAdapter(WebPreparedStatement.class, new WebPreparedStatementSerializer()) + .registerTypeHierarchyAdapter(Pojo.class, new ThermostatGSONConverter()) + .create(); - prepareServer(); - remove.apply(); - - Gson gson = new GsonBuilder() - .registerTypeHierarchyAdapter(Expression.class, - new ExpressionSerializer()) - .registerTypeHierarchyAdapter(Operator.class, - new OperatorSerializer()).create(); - StringReader reader = new StringReader(requestBody); - BufferedReader bufRead = new BufferedReader(reader); - String line = URLDecoder.decode(bufRead.readLine(), "UTF-8"); - String[] parts = line.split("="); - assertEquals("remove", parts[0]); - WebRemove actualRemove = gson.fromJson(parts[1], WebRemove.class); + String strDesc = "ADD test SET 'property1' = ?s"; + StatementDescriptor desc = new StatementDescriptor<>(category, strDesc); + PreparedStatement stmt = null; - assertEquals(42, actualRemove.getCategoryId()); - assertEquals(expr, actualRemove.getWhereExpression()); - } - - @Test - public void testCreateUpdate() { - WebUpdate update = (WebUpdate) storage.createUpdate(category); - assertNotNull(update); - assertEquals(42, update.getCategoryId()); - - Expression expr = factory.equalTo(key1, "test"); - update.where(expr); - assertEquals(expr, update.getWhereExpression()); - - update.set(key1, "fluff"); - List 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 { - - Update update = storage.createUpdate(category); - Expression expr = factory.equalTo(key1, "test"); - update.where(expr); - update.set(key1, "fluff"); - update.set(key2, 42); - - prepareServer(); - update.apply(); - - Gson gson = new GsonBuilder() - .registerTypeHierarchyAdapter(Expression.class, - new ExpressionSerializer()) - .registerTypeHierarchyAdapter(Operator.class, - new OperatorSerializer()).create(); - 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 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()); - - assertEquals(expr, receivedUpdate.getWhereExpression()); - - 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); + int fakePrepStmtId = 3; + WebPreparedStatementResponse fakeResponse = new WebPreparedStatementResponse(); + fakeResponse.setNumFreeVariables(1); + fakeResponse.setStatementId(fakePrepStmtId); + prepareServer(gson.toJson(fakeResponse)); + try { + stmt = storage.prepareStatement(desc); + } catch (DescriptorParsingException e) { + // descriptor should parse fine and is trusted + fail(e.getMessage()); + } + assertTrue(stmt instanceof WebPreparedStatement); + WebPreparedStatement webStmt = (WebPreparedStatement)stmt; + assertEquals(fakePrepStmtId, webStmt.getStatementId()); + PreparedParameters params = webStmt.getParams(); + assertEquals(1, params.getParams().length); + assertNull(params.getParams()[0]); + + // now set a parameter + stmt.setString(0, "fluff"); + assertEquals("fluff", params.getParams()[0].getValue()); + assertEquals(String.class, params.getParams()[0].getType()); + assertFalse(params.getParams()[0].isArrayType()); + + prepareServer(gson.toJson(PreparedStatementResponseCode.WRITE_GENERIC_FAILURE)); + + int response = Integer.MAX_VALUE; + try { + response = stmt.execute(); + } catch (StatementExecutionException e) { + // should execute fine + e.printStackTrace(); + fail(e.getMessage()); + } + + assertEquals(PreparedStatementResponseCode.WRITE_GENERIC_FAILURE, response); } @Test diff -r 0e0e2b6041ad -r d387d381858b web/common/src/main/java/com/redhat/thermostat/web/common/ExpressionSerializer.java --- a/web/common/src/main/java/com/redhat/thermostat/web/common/ExpressionSerializer.java Mon Sep 16 15:28:13 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,286 +0,0 @@ -/* - * Copyright 2012, 2013 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 - * . - * - * 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.lang.reflect.Type; -import java.util.HashSet; -import java.util.Set; - -import com.google.gson.JsonArray; -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonDeserializer; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; -import com.google.gson.JsonSerializationContext; -import com.google.gson.JsonSerializer; -import com.redhat.thermostat.storage.core.Key; -import com.redhat.thermostat.storage.query.BinaryComparisonExpression; -import com.redhat.thermostat.storage.query.BinaryComparisonOperator; -import com.redhat.thermostat.storage.query.BinaryLogicalExpression; -import com.redhat.thermostat.storage.query.BinaryLogicalOperator; -import com.redhat.thermostat.storage.query.BinarySetMembershipExpression; -import com.redhat.thermostat.storage.query.BinarySetMembershipOperator; -import com.redhat.thermostat.storage.query.ComparisonExpression; -import com.redhat.thermostat.storage.query.Expression; -import com.redhat.thermostat.storage.query.LiteralExpression; -import com.redhat.thermostat.storage.query.LiteralSetExpression; -import com.redhat.thermostat.storage.query.Operator; -import com.redhat.thermostat.storage.query.UnaryLogicalExpression; -import com.redhat.thermostat.storage.query.UnaryLogicalOperator; - -public class ExpressionSerializer implements JsonSerializer, - JsonDeserializer { - /* The concrete Expression fully-qualified class name */ - static final String PROP_CLASS_NAME = "PROP_CLASS_NAME"; - /* Serialized operand for a UnaryExpression */ - static final String PROP_OPERAND = "PROP_OPERAND"; - /* Serialized left operand for a BinaryExpression */ - static final String PROP_OPERAND_LEFT = "PROP_OPERAND_LEFT"; - /* Serialized right operand for a BinaryExpression */ - static final String PROP_OPERAND_RIGHT = "PROP_OPERAND_RIGHT"; - /* Serialized operator for an Expression */ - static final String PROP_OPERATOR = "PROP_OPERATOR"; - /* Serialized value for a LiteralExpression */ - static final String PROP_VALUE = "PROP_VALUE"; - /* Fully-qualified class name of a LiteralExpression's value */ - static final String PROP_VALUE_CLASS = "PROP_VALUE_CLASS"; - - @Override - public Expression deserialize(JsonElement json, Type typeOfT, - JsonDeserializationContext context) throws JsonParseException { - JsonElement jsonClassName = json.getAsJsonObject().get(PROP_CLASS_NAME); - if (jsonClassName == null) { - throw new JsonParseException("No class name property provided"); - } - String className = jsonClassName.getAsString(); - Expression result; - try { - Class clazz = (Class) Class.forName(className); - // Deserialize using concrete implementations to avoid reflection - // and unchecked casts - if (BinaryComparisonExpression.class.isAssignableFrom(clazz)) { - result = deserializeBinaryComparisonExpression(json, context); - } - else if (BinarySetMembershipExpression.class.isAssignableFrom(clazz)) { - result = deserializeBinarySetMembershipExpression(json, context); - } - else if (BinaryLogicalExpression.class.isAssignableFrom(clazz)) { - result = deserializeBinaryLogicalExpression(json, context); - } - else if (UnaryLogicalExpression.class.isAssignableFrom(clazz)) { - result = deserializeUnaryLogicalExpression(json, context); - } - else if (LiteralExpression.class.isAssignableFrom(clazz)) { - result = deserializeLiteralExpression(json, context); - } - else if (LiteralSetExpression.class.isAssignableFrom(clazz)) { - result = deserializeLiteralArrayExpression(json, context); - } - else { - throw new JsonParseException("Unknown Expression of type " + className); - } - } catch (ClassNotFoundException e) { - throw new JsonParseException("Unable to deserialize Expression", e); - } - return result; - } - - private Expression deserializeBinaryComparisonExpression(JsonElement json, - JsonDeserializationContext context) { - JsonElement jsonLeft = json.getAsJsonObject().get(PROP_OPERAND_LEFT); - JsonElement jsonRight = json.getAsJsonObject().get(PROP_OPERAND_RIGHT); - JsonElement jsonOp = json.getAsJsonObject().get(PROP_OPERATOR); - - LiteralExpression> left = context.deserialize(jsonLeft, Expression.class); - LiteralExpression right = context.deserialize(jsonRight, Expression.class); - BinaryComparisonOperator op = context.deserialize(jsonOp, Operator.class); - return new BinaryComparisonExpression<>(left, op, right); - } - - private Expression deserializeBinarySetMembershipExpression(JsonElement json, - JsonDeserializationContext context) { - JsonElement jsonLeft = json.getAsJsonObject().get(PROP_OPERAND_LEFT); - JsonElement jsonRight = json.getAsJsonObject().get(PROP_OPERAND_RIGHT); - JsonElement jsonOp = json.getAsJsonObject().get(PROP_OPERATOR); - - LiteralExpression> left = context.deserialize(jsonLeft, Expression.class); - LiteralSetExpression right = context.deserialize(jsonRight, Expression.class); - BinarySetMembershipOperator op = context.deserialize(jsonOp, Operator.class); - return new BinarySetMembershipExpression<>(left, op, right); - } - - private Expression deserializeBinaryLogicalExpression(JsonElement json, - JsonDeserializationContext context) { - JsonElement jsonLeft = json.getAsJsonObject().get(PROP_OPERAND_LEFT); - JsonElement jsonRight = json.getAsJsonObject().get(PROP_OPERAND_RIGHT); - JsonElement jsonOp = json.getAsJsonObject().get(PROP_OPERATOR); - - S left = context.deserialize(jsonLeft, Expression.class); - T right = context.deserialize(jsonRight, Expression.class); - BinaryLogicalOperator op = context.deserialize(jsonOp, Operator.class); - return new BinaryLogicalExpression<>(left, op, right); - } - - private Expression deserializeUnaryLogicalExpression(JsonElement json, - JsonDeserializationContext context) { - JsonElement jsonOperand = json.getAsJsonObject().get(PROP_OPERAND); - JsonElement jsonOp = json.getAsJsonObject().get(PROP_OPERATOR); - - T operand = context.deserialize(jsonOperand, Expression.class); - UnaryLogicalOperator operator = context.deserialize(jsonOp, Operator.class); - return new UnaryLogicalExpression<>(operand, operator); - } - - private Expression deserializeLiteralExpression(JsonElement json, - JsonDeserializationContext context) throws ClassNotFoundException { - JsonElement jsonValue = json.getAsJsonObject().get(PROP_VALUE); - JsonElement jsonValueClass = json.getAsJsonObject().get(PROP_VALUE_CLASS); - String valueClassName = jsonValueClass.getAsString(); - Class valueClass = Class.forName(valueClassName); - return makeLiteralExpression(context, jsonValue, valueClass); - } - - private Expression makeLiteralExpression(JsonDeserializationContext context, - JsonElement jsonValue, Class valueClass) throws ClassNotFoundException { - T value = context.deserialize(jsonValue, valueClass); - return new LiteralExpression<>(value); - } - - private Expression deserializeLiteralArrayExpression(JsonElement json, - JsonDeserializationContext context) throws ClassNotFoundException { - JsonElement jsonValue = json.getAsJsonObject().get(PROP_VALUE); - if (jsonValue instanceof JsonArray) { - JsonElement jsonValueClass = json.getAsJsonObject().get(PROP_VALUE_CLASS); - String valueClassName = jsonValueClass.getAsString(); - Class type = Class.forName(valueClassName); - JsonArray jsonArr = (JsonArray) jsonValue; - return makeLiteralArrayExpression(context, jsonArr, type); - } - else { - throw new JsonParseException("No JsonArray supplied for " + PROP_VALUE); - } - } - - private Expression makeLiteralArrayExpression(JsonDeserializationContext context, - JsonArray jsonArr, Class valueClass) { - Set values = new HashSet<>(); - for (JsonElement element : jsonArr) { - T value = context.deserialize(element, valueClass); - values.add(value); - } - return new LiteralSetExpression<>(values, valueClass); - } - - @Override - public JsonElement serialize(Expression src, Type typeOfSrc, - JsonSerializationContext context) { - JsonObject result; - // Only concrete implementations are public - if (src instanceof BinaryLogicalExpression) { - BinaryLogicalExpression binExpr = (BinaryLogicalExpression) src; - JsonElement left = context.serialize(binExpr.getLeftOperand()); - JsonElement op = context.serialize(binExpr.getOperator()); - JsonElement right = context.serialize(binExpr.getRightOperand()); - result = new JsonObject(); - result.add(PROP_OPERAND_LEFT, left); - result.add(PROP_OPERATOR, op); - result.add(PROP_OPERAND_RIGHT, right); - } - else if (src instanceof BinaryComparisonExpression) { - BinaryComparisonExpression binExpr = (BinaryComparisonExpression) src; - JsonElement left = context.serialize(binExpr.getLeftOperand()); - JsonElement op = context.serialize(binExpr.getOperator()); - JsonElement right = context.serialize(binExpr.getRightOperand()); - result = new JsonObject(); - result.add(PROP_OPERAND_LEFT, left); - result.add(PROP_OPERATOR, op); - result.add(PROP_OPERAND_RIGHT, right); - } - else if (src instanceof BinarySetMembershipExpression) { - BinarySetMembershipExpression binExpr = (BinarySetMembershipExpression) src; - JsonElement left = context.serialize(binExpr.getLeftOperand()); - JsonElement op = context.serialize(binExpr.getOperator()); - JsonElement right = context.serialize(binExpr.getRightOperand()); - result = new JsonObject(); - result.add(PROP_OPERAND_LEFT, left); - result.add(PROP_OPERATOR, op); - result.add(PROP_OPERAND_RIGHT, right); - } - else if (src instanceof UnaryLogicalExpression) { - UnaryLogicalExpression unaryExpr = (UnaryLogicalExpression) src; - JsonElement operand = context.serialize(unaryExpr.getOperand()); - JsonElement operator = context.serialize(unaryExpr.getOperator()); - result = new JsonObject(); - result.add(PROP_OPERAND, operand); - result.add(PROP_OPERATOR, operator); - } - else if (src instanceof LiteralExpression) { - LiteralExpression litExpr = (LiteralExpression) src; - JsonElement value = context.serialize(litExpr.getValue()); - result = new JsonObject(); - result.add(PROP_VALUE, value); - // Store the type of value to properly deserialize it later - result.addProperty(PROP_VALUE_CLASS, litExpr.getValue().getClass().getCanonicalName()); - } - else if (src instanceof LiteralSetExpression) { - LiteralSetExpression litArrExpr = (LiteralSetExpression) src; - result = serializeLiteralArrayExpression(litArrExpr, context); - } - else { - throw new JsonParseException("Unknown expression of type " + src.getClass()); - } - result.addProperty(PROP_CLASS_NAME, src.getClass().getCanonicalName()); - return result; - } - - private JsonObject serializeLiteralArrayExpression(LiteralSetExpression expr, - JsonSerializationContext context) { - JsonObject result = new JsonObject(); - Set list = expr.getValues(); - Class type = expr.getType(); - JsonArray arr = new JsonArray(); - for (T element : list) { - arr.add(context.serialize(element, type)); - } - result.add(PROP_VALUE, arr); - // Store type of list elements - result.addProperty(PROP_VALUE_CLASS, type.getCanonicalName()); - return result; - } - -} diff -r 0e0e2b6041ad -r d387d381858b web/common/src/main/java/com/redhat/thermostat/web/common/OperatorSerializer.java --- a/web/common/src/main/java/com/redhat/thermostat/web/common/OperatorSerializer.java Mon Sep 16 15:28:13 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,104 +0,0 @@ -/* - * Copyright 2012, 2013 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 - * . - * - * 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.lang.reflect.Type; - -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonDeserializer; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; -import com.google.gson.JsonSerializationContext; -import com.google.gson.JsonSerializer; -import com.redhat.thermostat.storage.query.Operator; - -public class OperatorSerializer implements JsonDeserializer, - JsonSerializer { - /* The name of the enum constant */ - static final String PROP_CONST = "PROP_CONST"; - /* The Operator implementation fully-qualified class name */ - static final String PROP_CLASS_NAME = "PROP_CLASS_NAME"; - - @Override - public JsonElement serialize(Operator src, Type typeOfSrc, - JsonSerializationContext context) { - JsonObject result = new JsonObject(); - // All concrete Operators should be Enums - if (src instanceof Enum) { - Enum operator = (Enum) src; - result.addProperty(PROP_CONST, operator.name()); - result.addProperty(PROP_CLASS_NAME, operator.getDeclaringClass().getCanonicalName()); - } - else { - throw new JsonParseException("Concrete Operator must be an enum"); - } - return result; - } - - @Override - public Operator deserialize(JsonElement json, Type typeOfT, - JsonDeserializationContext context) throws JsonParseException { - JsonElement jsonClassName = json.getAsJsonObject().get(PROP_CLASS_NAME); - if (jsonClassName == null) { - throw new JsonParseException("Class name must be specified for Operator"); - } - String className = jsonClassName.getAsString(); - Operator result; - try { - Class clazz = Class.forName(className); - result = getEnum(json, clazz); - } catch (ClassNotFoundException e) { - throw new JsonParseException("Unable to deserialize Operator", e); - } - return result; - } - - private & Operator> Operator getEnum(JsonElement json, Class clazz) { - if (Operator.class.isAssignableFrom(clazz) && clazz.isEnum()) { - @SuppressWarnings("unchecked") // Checked with above condition - Class operatorClass = (Class) clazz; - JsonElement jsonConst = json.getAsJsonObject().get(PROP_CONST); - String enumConst = jsonConst.getAsString(); - return Enum.valueOf(operatorClass, enumConst); - } - else { - throw new JsonParseException(clazz.getName() + " must be an Enum implementing Operator"); - } - } - -} diff -r 0e0e2b6041ad -r d387d381858b web/common/src/main/java/com/redhat/thermostat/web/common/PreparedParameterSerializer.java --- a/web/common/src/main/java/com/redhat/thermostat/web/common/PreparedParameterSerializer.java Mon Sep 16 15:28:13 2013 +0200 +++ b/web/common/src/main/java/com/redhat/thermostat/web/common/PreparedParameterSerializer.java Wed Sep 25 19:09:58 2013 +0200 @@ -36,14 +36,15 @@ package com.redhat.thermostat.web.common; +import java.lang.reflect.Array; import java.lang.reflect.Type; -import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; -import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; -import com.google.gson.JsonArray; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; @@ -52,8 +53,9 @@ import com.google.gson.JsonPrimitive; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; +import com.redhat.thermostat.common.utils.LoggingUtils; import com.redhat.thermostat.storage.core.PreparedParameter; - +import com.redhat.thermostat.storage.model.Pojo; /** * GSON type adapter for {@link PreparedParameter}. @@ -61,54 +63,49 @@ */ public class PreparedParameterSerializer implements JsonDeserializer, JsonSerializer{ + private static final Logger logger = LoggingUtils.getLogger(PreparedParameterSerializer.class); private static final String PROP_TYPE = "type"; + private static final String PROP_IS_ARRAY_TYPE = "isArray"; private static final String PROP_VALUE = "value"; - // The set of valid classes for types - private static final Set VALID_CLASSNAMES; + private static final Set> WRAPPER_CLASSES; + // maps wrapper classes to primitives: + // Integer.class => int.class , Double.class => double.class, etc. + private static final Map, Class> TO_PRIMITIVE_ARRAY_MAP; static { - VALID_CLASSNAMES = new HashSet<>(); - VALID_CLASSNAMES.add(String.class.getCanonicalName()); - VALID_CLASSNAMES.add(String[].class.getCanonicalName()); - VALID_CLASSNAMES.add(Integer.class.getCanonicalName()); - VALID_CLASSNAMES.add(Long.class.getCanonicalName()); - VALID_CLASSNAMES.add(Boolean.class.getCanonicalName()); + WRAPPER_CLASSES = new HashSet<>(); + TO_PRIMITIVE_ARRAY_MAP = new HashMap<>(); + WRAPPER_CLASSES.add(Integer.class); + TO_PRIMITIVE_ARRAY_MAP.put(Integer.class, int.class); + WRAPPER_CLASSES.add(Long.class); + TO_PRIMITIVE_ARRAY_MAP.put(Long.class, long.class); + WRAPPER_CLASSES.add(Boolean.class); + TO_PRIMITIVE_ARRAY_MAP.put(Boolean.class, boolean.class); + WRAPPER_CLASSES.add(Double.class); + TO_PRIMITIVE_ARRAY_MAP.put(Double.class, double.class); + } @Override public JsonElement serialize(PreparedParameter param, Type type, JsonSerializationContext ctxt) { JsonObject result = new JsonObject(); - JsonElement valueElem = serializeValue(param.getValue()); + JsonElement valueElem = serializeValue(ctxt, param.getValue(), param.getType(), param.isArrayType()); result.add(PROP_VALUE, valueElem); - JsonPrimitive typeElem = new JsonPrimitive(param.getType().getCanonicalName()); + JsonPrimitive typeElem = new JsonPrimitive(param.getType().getName()); result.add(PROP_TYPE, typeElem); + JsonPrimitive arrayType = new JsonPrimitive(param.isArrayType()); + result.add(PROP_IS_ARRAY_TYPE, arrayType); return result; } - private JsonElement serializeValue(Object value) { + private JsonElement serializeValue(JsonSerializationContext ctxt, Object value, Class compType, boolean isArray) { JsonElement element; - if (value instanceof Integer) { - int val = ((Integer)value).intValue(); - element = new JsonPrimitive(val); - } else if (value instanceof Long) { - long val = ((Long)value).longValue(); - element = new JsonPrimitive(val); - } else if (value instanceof String) { - String val = (String)value; - element = new JsonPrimitive(val); - } else if (value instanceof String[]) { - String[] val = (String[])value; - JsonArray array = new JsonArray(); - for (int i = 0; i < val.length; i++) { - array.add(new JsonPrimitive(val[i])); - } - element = array; - } else if (value instanceof Boolean) { - Boolean val = (Boolean)value; - element = new JsonPrimitive(val.booleanValue()); + if (isArray) { + Class arrayType = Array.newInstance(compType, 0).getClass(); + element = ctxt.serialize(value, arrayType); } else { - throw new IllegalStateException("Unexpected value for serialization '" + value + "'"); + element = ctxt.serialize(value, compType); } return element; } @@ -118,57 +115,62 @@ JsonDeserializationContext ctxt) throws JsonParseException { JsonElement typeElem = jsonElem.getAsJsonObject().get(PROP_TYPE); String className = typeElem.getAsString(); - // perform some sanity checking on which classes we do forName() :) - validateSaneClassName(className); + // perform some sanity checking on the types of classes we actually + // de-serialize Class typeVal = deserializeTypeVal(className); + validateSaneClassName(typeVal); JsonElement valueElement = jsonElem.getAsJsonObject().get(PROP_VALUE); - Object value = deserializeValue(ctxt, valueElement, typeVal); + JsonElement isArrayElement = jsonElem.getAsJsonObject().get(PROP_IS_ARRAY_TYPE); + boolean isArray = isArrayElement.getAsBoolean(); + Object value = deserializeValue(ctxt, valueElement, typeVal, isArray); PreparedParameter param = new PreparedParameter(); param.setType(typeVal); param.setValue(value); + param.setArrayType(isArray); return param; } private Class deserializeTypeVal(String className) { Class typeVal = null; - if (className.equals(String[].class.getCanonicalName())) { - typeVal = String[].class; - } else { - try { - typeVal = Class.forName(className); - } catch (ClassNotFoundException ignored) { - // we only load valid classes that way - }; + try { + typeVal = Class.forName(className); + } catch (ClassNotFoundException e) { + logger.log(Level.WARNING, "Failed to resolve class type for '" + + className + "'."); } + ; return typeVal; } private Object deserializeValue(JsonDeserializationContext ctxt, - JsonElement valueElement, Class valType) { - if (valueElement.isJsonPrimitive()) { - // By telling GSON the type, we get the rightly casted + JsonElement valueElement, Class valType, boolean isArray) { + if (!isArray) { + // By telling GSON the type, we get the correctly casted // value back. return ctxt.deserialize(valueElement, valType); - } else if (valueElement.isJsonArray()) { - // Only string arrays are supported - List values = new ArrayList<>(); - JsonArray jsonArray = (JsonArray)valueElement; - Iterator it = jsonArray.iterator(); - while (it.hasNext()) { - JsonElement elem = it.next(); - String strElem = ctxt.deserialize(elem, String.class); - values.add(strElem); + } else { + Class arrayType = Array.newInstance(valType, 0).getClass(); + Object array; + // Make sure we get primitive type arrays if this is an array type + // of one of the wrapped primitives. + if (WRAPPER_CLASSES.contains(valType)) { + Class primType = Array.newInstance(TO_PRIMITIVE_ARRAY_MAP.get(valType), 0).getClass(); + array = ctxt.deserialize(valueElement, primType); + } else { + array = ctxt.deserialize(valueElement, arrayType); } - return values.toArray(new String[0]); - } else { - throw new IllegalStateException("Illegal json for parameter value"); + return array; } } - private void validateSaneClassName(String className) { - if (!VALID_CLASSNAMES.contains(className)) { - throw new IllegalStateException("Illegal type of parameter " + className); + // Allow wrapper classes, String + Pojo types, refuse everything else + private void validateSaneClassName(Class clazz) { + if (WRAPPER_CLASSES.contains(clazz) || + String.class == clazz || + Pojo.class.isAssignableFrom(clazz)) { + return; } + throw new IllegalStateException("Illegal type of parameter " + clazz.getCanonicalName()); } } diff -r 0e0e2b6041ad -r d387d381858b web/common/src/main/java/com/redhat/thermostat/web/common/PreparedStatementResponseCode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/common/src/main/java/com/redhat/thermostat/web/common/PreparedStatementResponseCode.java Wed Sep 25 19:09:58 2013 +0200 @@ -0,0 +1,68 @@ +/* + * Copyright 2012, 2013 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 + * . + * + * 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 com.redhat.thermostat.storage.core.PreparedStatement; + +/** + * Common response codes for prepared statement responses. + * + */ +public interface PreparedStatementResponseCode { + + /** + * Response code for successful prepared queries. + */ + public static final int QUERY_SUCCESS = 0; + + /** + * Response code if patching of a {@link PreparedStatement} failed during + * statement execution. + *

+ * For example a patching failure could happen if there was a type mismatch + * between the descriptor and the parameter provided. Providing not all + * parameters and attempting execution of a {@link PreparedStatement} would + * be another example. + */ + public static final int ILLEGAL_PATCH = -1; + + /** + * Failure to execute a prepared write statement for some unknown reason. + */ + public static final int WRITE_GENERIC_FAILURE = -200; + +} diff -r 0e0e2b6041ad -r d387d381858b web/common/src/main/java/com/redhat/thermostat/web/common/WebAdd.java --- a/web/common/src/main/java/com/redhat/thermostat/web/common/WebAdd.java Mon Sep 16 15:28:13 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -/* - * Copyright 2012, 2013 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 - * . - * - * 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 com.redhat.thermostat.storage.core.Add; -import com.redhat.thermostat.storage.model.Pojo; - - -public class WebAdd implements Add { - - private int categoryId; - private transient Pojo pojo; - - public WebAdd() { - } - - public WebAdd(int categoryId) { - this.categoryId = categoryId; - } - - public int getCategoryId() { - return categoryId; - } - - public void setCategoryId(int categoryId) { - this.categoryId = categoryId; - } - - - @Override - public void setPojo(Pojo pojo) { - this.pojo = pojo; - } - - public Pojo getPojo() { - return pojo; - } - - @Override - public int apply() { - // Should never be called directly, but overridden by - // the actual implementation. Here only so that it can be used - // for serialization. - throw new IllegalStateException(); - } -} - diff -r 0e0e2b6041ad -r d387d381858b web/common/src/main/java/com/redhat/thermostat/web/common/WebQueryResponse.java --- a/web/common/src/main/java/com/redhat/thermostat/web/common/WebQueryResponse.java Mon Sep 16 15:28:13 2013 +0200 +++ b/web/common/src/main/java/com/redhat/thermostat/web/common/WebQueryResponse.java Wed Sep 25 19:09:58 2013 +0200 @@ -47,9 +47,6 @@ */ public class WebQueryResponse { - public static final int SUCCESS = 0; - public static final int ILLEGAL_PATCH = -1; - private int responseCode; private T[] resultList; diff -r 0e0e2b6041ad -r d387d381858b web/common/src/main/java/com/redhat/thermostat/web/common/WebRemove.java --- a/web/common/src/main/java/com/redhat/thermostat/web/common/WebRemove.java Mon Sep 16 15:28:13 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/* - * Copyright 2012, 2013 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 - * . - * - * 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 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 { - - private final int categoryId; - private Expression whereExpression; - - public WebRemove(int categoryId) { - this.categoryId = categoryId; - } - - @Override - public void where(Expression expr) { - whereExpression = expr; - } - - public int getCategoryId() { - return categoryId; - } - - public Expression getWhereExpression() { - return whereExpression; - } - - @Override - public int apply() { - // This should never be called. Overridden by the actual - // implementation. - throw new IllegalStateException(); - } - -} - diff -r 0e0e2b6041ad -r d387d381858b web/common/src/main/java/com/redhat/thermostat/web/common/WebReplace.java --- a/web/common/src/main/java/com/redhat/thermostat/web/common/WebReplace.java Mon Sep 16 15:28:13 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +0,0 @@ -/* - * Copyright 2012, 2013 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 - * . - * - * 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 com.redhat.thermostat.storage.core.Replace; -import com.redhat.thermostat.storage.model.Pojo; -import com.redhat.thermostat.storage.query.Expression; - -public class WebReplace implements Replace { - - private int categoryId; - private transient Pojo pojo; - private Expression whereExpression; - - public WebReplace() { - // nothing - } - - public WebReplace(int categoryId) { - this.categoryId = categoryId; - } - - @Override - public void setPojo(Pojo pojo) { - this.pojo = pojo; - } - - @Override - public int apply() { - // Should never be called directly, but overridden by - // the actual implementation. Here only so that it can be used - // for serialization. - throw new IllegalStateException(); - } - - @Override - public void where(Expression expression) { - this.whereExpression = expression; - } - - public int getCategoryId() { - return categoryId; - } - - public void setCategoryId(int categoryId) { - this.categoryId = categoryId; - } - - public Pojo getPojo() { - return pojo; - } - - public Expression getWhereExpression() { - return whereExpression; - } - -} diff -r 0e0e2b6041ad -r d387d381858b web/common/src/main/java/com/redhat/thermostat/web/common/WebUpdate.java --- a/web/common/src/main/java/com/redhat/thermostat/web/common/WebUpdate.java Mon Sep 16 15:28:13 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,132 +0,0 @@ -/* - * Copyright 2012, 2013 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 - * . - * - * 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 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 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 int categoryId; - private Expression whereExpression; - private List updateValues; - - public WebUpdate() { - updateValues = new ArrayList<>(); - } - - public void where(Expression expr) { - whereExpression = expr; - } - - public void set(Key key, S value) { - updateValues.add(new UpdateValue(key, value)); - } - - public int getCategoryId() { - return categoryId; - } - - public void setCategoryId(int categoryId) { - this.categoryId = categoryId; - } - - public Expression getWhereExpression() { - return whereExpression; - } - - public List getUpdates() { - return updateValues; - } - - @Override - public int apply() { - // This should never be called. Overridden by the actual - // implementation. - throw new IllegalStateException(); - } - -} - diff -r 0e0e2b6041ad -r d387d381858b web/common/src/test/java/com/redhat/thermostat/web/common/ExpressionSerializerTest.java --- a/web/common/src/test/java/com/redhat/thermostat/web/common/ExpressionSerializerTest.java Mon Sep 16 15:28:13 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,269 +0,0 @@ -/* - * Copyright 2012, 2013 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 - * . - * - * 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 static org.junit.Assert.assertEquals; - -import java.util.Arrays; -import java.util.HashSet; - -import org.junit.Before; -import org.junit.Test; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; -import com.redhat.thermostat.storage.core.Key; -import com.redhat.thermostat.storage.query.BinaryComparisonExpression; -import com.redhat.thermostat.storage.query.BinaryLogicalExpression; -import com.redhat.thermostat.storage.query.BinarySetMembershipExpression; -import com.redhat.thermostat.storage.query.Expression; -import com.redhat.thermostat.storage.query.ExpressionFactory; -import com.redhat.thermostat.storage.query.LiteralSetExpression; -import com.redhat.thermostat.storage.query.LiteralExpression; -import com.redhat.thermostat.storage.query.Operator; -import com.redhat.thermostat.storage.query.UnaryLogicalExpression; - -public class ExpressionSerializerTest { - - private static final Key key = new Key<>("hello"); - private Gson gson; - - private static final class TestExpression implements Expression { - - } - - @Before - public void setUp() throws Exception { - gson = new GsonBuilder() - .registerTypeHierarchyAdapter(Expression.class, - new ExpressionSerializer()) - .registerTypeHierarchyAdapter(Operator.class, - new OperatorSerializer()).create(); - } - - @Test - public void testDeserializeLiteralExpression() { - Expression expr = new LiteralExpression("hello"); - - JsonObject json = new JsonObject(); - json.addProperty(ExpressionSerializer.PROP_VALUE, "hello"); - json.addProperty(ExpressionSerializer.PROP_VALUE_CLASS, String.class.getCanonicalName()); - json.addProperty(ExpressionSerializer.PROP_CLASS_NAME, LiteralExpression.class.getCanonicalName()); - - assertEquals(expr, gson.fromJson(json, Expression.class)); - } - - @Test - public void testDeserializeLiteralArrayExpression() { - Expression expr = new LiteralSetExpression(new HashSet<>(Arrays.asList("hello", "goodbye")), - String.class); - - JsonObject json = new JsonObject(); - JsonArray arr = new JsonArray(); - arr.add(gson.toJsonTree("hello")); - arr.add(gson.toJsonTree("goodbye")); - json.add(ExpressionSerializer.PROP_VALUE, arr); - json.addProperty(ExpressionSerializer.PROP_VALUE_CLASS, String.class.getCanonicalName()); - json.addProperty(ExpressionSerializer.PROP_CLASS_NAME, LiteralSetExpression.class.getCanonicalName()); - - assertEquals(expr, gson.fromJson(json, Expression.class)); - } - - @Test - public void testDeserializeBinaryComparisonExpression() { - ExpressionFactory factory = new ExpressionFactory(); - BinaryComparisonExpression expr = factory.equalTo(key, "world"); - - JsonObject json = new JsonObject(); - json.add(ExpressionSerializer.PROP_OPERAND_LEFT, gson.toJsonTree(expr.getLeftOperand())); - json.add(ExpressionSerializer.PROP_OPERATOR, gson.toJsonTree(expr.getOperator())); - json.add(ExpressionSerializer.PROP_OPERAND_RIGHT, gson.toJsonTree(expr.getRightOperand())); - json.addProperty(ExpressionSerializer.PROP_CLASS_NAME, BinaryComparisonExpression.class.getCanonicalName()); - - assertEquals(expr, gson.fromJson(json, Expression.class)); - } - - @Test - public void testDeserializeBinarySetMembershipExpression() { - ExpressionFactory factory = new ExpressionFactory(); - BinarySetMembershipExpression expr = factory.in(key, - new HashSet<>(Arrays.asList("world", "goodbye")), String.class); - - JsonObject json = new JsonObject(); - json.add(ExpressionSerializer.PROP_OPERAND_LEFT, gson.toJsonTree(expr.getLeftOperand())); - json.add(ExpressionSerializer.PROP_OPERATOR, gson.toJsonTree(expr.getOperator())); - json.add(ExpressionSerializer.PROP_OPERAND_RIGHT, gson.toJsonTree(expr.getRightOperand())); - json.addProperty(ExpressionSerializer.PROP_CLASS_NAME, BinarySetMembershipExpression.class.getCanonicalName()); - - assertEquals(expr, gson.fromJson(json, Expression.class)); - } - - @Test - public void testDeserializeBinaryLogicalExpression() { - ExpressionFactory factory = new ExpressionFactory(); - BinaryLogicalExpression, BinaryComparisonExpression> expr = factory.and(factory.equalTo(key, "world"), factory.greaterThan(key, "goodbye")); - - JsonObject json = new JsonObject(); - json.add(ExpressionSerializer.PROP_OPERAND_LEFT, gson.toJsonTree(expr.getLeftOperand())); - json.add(ExpressionSerializer.PROP_OPERATOR, gson.toJsonTree(expr.getOperator())); - json.add(ExpressionSerializer.PROP_OPERAND_RIGHT, gson.toJsonTree(expr.getRightOperand())); - json.addProperty(ExpressionSerializer.PROP_CLASS_NAME, BinaryLogicalExpression.class.getCanonicalName()); - - assertEquals(expr, gson.fromJson(json, Expression.class)); - } - - @Test - public void testDeserializeUnaryLogicalExpression() { - ExpressionFactory factory = new ExpressionFactory(); - UnaryLogicalExpression> expr = factory.not(factory.greaterThan(key, "goodbye")); - - JsonObject json = new JsonObject(); - json.add(ExpressionSerializer.PROP_OPERAND, gson.toJsonTree(expr.getOperand())); - json.add(ExpressionSerializer.PROP_OPERATOR, gson.toJsonTree(expr.getOperator())); - json.addProperty(ExpressionSerializer.PROP_CLASS_NAME, UnaryLogicalExpression.class.getCanonicalName()); - - assertEquals(expr, gson.fromJson(json, Expression.class)); - } - - @Test(expected=JsonParseException.class) - public void testDeserializeNoClassName() { - JsonObject json = new JsonObject(); - - gson.fromJson(json, Expression.class); - } - - @Test(expected=JsonParseException.class) - public void testDeserializeUnknownExpression() { - JsonObject json = new JsonObject(); - json.addProperty(ExpressionSerializer.PROP_CLASS_NAME, TestExpression.class.getCanonicalName()); - - gson.fromJson(json, Expression.class); - } - - @Test - public void testSerializeLiteralExpression() { - Expression expr = new LiteralExpression("hello"); - - JsonObject json = new JsonObject(); - json.addProperty(ExpressionSerializer.PROP_VALUE, "hello"); - json.addProperty(ExpressionSerializer.PROP_VALUE_CLASS, String.class.getCanonicalName()); - json.addProperty(ExpressionSerializer.PROP_CLASS_NAME, LiteralExpression.class.getCanonicalName()); - - assertEquals(gson.toJson(json), gson.toJson(expr)); - } - - @Test - public void testSerializeLiteralArrayExpression() { - Expression expr = new LiteralSetExpression(new HashSet<>(Arrays.asList("hello", "goodbye")), - String.class); - - JsonObject json = new JsonObject(); - JsonArray arr = new JsonArray(); - arr.add(gson.toJsonTree("hello")); - arr.add(gson.toJsonTree("goodbye")); - json.add(ExpressionSerializer.PROP_VALUE, arr); - json.addProperty(ExpressionSerializer.PROP_VALUE_CLASS, String.class.getCanonicalName()); - json.addProperty(ExpressionSerializer.PROP_CLASS_NAME, LiteralSetExpression.class.getCanonicalName()); - - assertEquals(gson.toJson(json), gson.toJson(expr)); - } - - @Test - public void testSerializeBinaryComparisonExpression() { - ExpressionFactory factory = new ExpressionFactory(); - BinaryComparisonExpression expr = factory.equalTo(key, "world"); - - JsonObject json = new JsonObject(); - json.add(ExpressionSerializer.PROP_OPERAND_LEFT, gson.toJsonTree(expr.getLeftOperand())); - json.add(ExpressionSerializer.PROP_OPERATOR, gson.toJsonTree(expr.getOperator())); - json.add(ExpressionSerializer.PROP_OPERAND_RIGHT, gson.toJsonTree(expr.getRightOperand())); - json.addProperty(ExpressionSerializer.PROP_CLASS_NAME, BinaryComparisonExpression.class.getCanonicalName()); - - assertEquals(gson.toJson(json), gson.toJson(expr)); - } - - @Test - public void testSerializeBinarySetMembershipExpression() { - ExpressionFactory factory = new ExpressionFactory(); - BinarySetMembershipExpression expr = factory.in(key, new HashSet<>(Arrays.asList("world", "goodbye")), - String.class); - - JsonObject json = new JsonObject(); - json.add(ExpressionSerializer.PROP_OPERAND_LEFT, gson.toJsonTree(expr.getLeftOperand())); - json.add(ExpressionSerializer.PROP_OPERATOR, gson.toJsonTree(expr.getOperator())); - json.add(ExpressionSerializer.PROP_OPERAND_RIGHT, gson.toJsonTree(expr.getRightOperand())); - json.addProperty(ExpressionSerializer.PROP_CLASS_NAME, BinarySetMembershipExpression.class.getCanonicalName()); - - assertEquals(gson.toJson(json), gson.toJson(expr)); - } - - @Test - public void testSerializeBinaryLogicalExpression() { - ExpressionFactory factory = new ExpressionFactory(); - BinaryLogicalExpression, BinaryComparisonExpression> expr = factory.and(factory.equalTo(key, "world"), factory.greaterThan(key, "goodbye")); - - JsonObject json = new JsonObject(); - json.add(ExpressionSerializer.PROP_OPERAND_LEFT, gson.toJsonTree(expr.getLeftOperand())); - json.add(ExpressionSerializer.PROP_OPERATOR, gson.toJsonTree(expr.getOperator())); - json.add(ExpressionSerializer.PROP_OPERAND_RIGHT, gson.toJsonTree(expr.getRightOperand())); - json.addProperty(ExpressionSerializer.PROP_CLASS_NAME, BinaryLogicalExpression.class.getCanonicalName()); - - assertEquals(gson.toJson(json), gson.toJson(expr)); - } - - @Test - public void testSerializeUnaryLogicalExpression() { - ExpressionFactory factory = new ExpressionFactory(); - UnaryLogicalExpression> expr = factory.not(factory.greaterThan(key, "goodbye")); - - JsonObject json = new JsonObject(); - json.add(ExpressionSerializer.PROP_OPERAND, gson.toJsonTree(expr.getOperand())); - json.add(ExpressionSerializer.PROP_OPERATOR, gson.toJsonTree(expr.getOperator())); - json.addProperty(ExpressionSerializer.PROP_CLASS_NAME, UnaryLogicalExpression.class.getCanonicalName()); - - assertEquals(gson.toJson(json), gson.toJson(expr)); - } - - @Test(expected=JsonParseException.class) - public void testSerializeUnknownExpression() { - gson.toJson(new TestExpression()); - } - -} diff -r 0e0e2b6041ad -r d387d381858b web/common/src/test/java/com/redhat/thermostat/web/common/OperatorSerializerTest.java --- a/web/common/src/test/java/com/redhat/thermostat/web/common/OperatorSerializerTest.java Mon Sep 16 15:28:13 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,154 +0,0 @@ -/* - * Copyright 2012, 2013 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 - * . - * - * 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 static org.junit.Assert.assertEquals; - -import org.junit.Before; -import org.junit.Test; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; -import com.redhat.thermostat.storage.query.BinaryComparisonOperator; -import com.redhat.thermostat.storage.query.BinaryLogicalOperator; -import com.redhat.thermostat.storage.query.Operator; -import com.redhat.thermostat.storage.query.UnaryLogicalOperator; - -public class OperatorSerializerTest { - - private Gson gson; - - private static final class TestOperator implements Operator { - - } - - @Before - public void setUp() throws Exception { - gson = new GsonBuilder() - .registerTypeHierarchyAdapter(Operator.class, - new OperatorSerializer()).create(); - } - - @Test - public void testDeserializeBinaryComparisonOperator() { - Operator op = BinaryComparisonOperator.EQUALS; - - JsonObject json = new JsonObject(); - json.addProperty(OperatorSerializer.PROP_CONST, BinaryComparisonOperator.EQUALS.name()); - json.addProperty(OperatorSerializer.PROP_CLASS_NAME, BinaryComparisonOperator.class.getCanonicalName()); - - assertEquals(op, gson.fromJson(json, Operator.class)); - } - - @Test - public void testDeserializeBinaryLogicalOperator() { - Operator op = BinaryLogicalOperator.AND; - - JsonObject json = new JsonObject(); - json.addProperty(OperatorSerializer.PROP_CONST, BinaryLogicalOperator.AND.name()); - json.addProperty(OperatorSerializer.PROP_CLASS_NAME, BinaryLogicalOperator.class.getCanonicalName()); - - assertEquals(op, gson.fromJson(json, Operator.class)); - } - - @Test - public void testDeserializeUnaryLogicalOperator() { - Operator op = UnaryLogicalOperator.NOT; - - JsonObject json = new JsonObject(); - json.addProperty(OperatorSerializer.PROP_CONST, UnaryLogicalOperator.NOT.name()); - json.addProperty(OperatorSerializer.PROP_CLASS_NAME, UnaryLogicalOperator.class.getCanonicalName()); - - assertEquals(op, gson.fromJson(json, Operator.class)); - } - - @Test(expected=JsonParseException.class) - public void testDeserializeNoClassName() { - JsonObject json = new JsonObject(); - - gson.fromJson(json, Operator.class); - } - - @Test(expected=JsonParseException.class) - public void testDeserializeUnknownOperator() { - JsonObject json = new JsonObject(); - json.addProperty(OperatorSerializer.PROP_CLASS_NAME, TestOperator.class.getCanonicalName()); - - gson.fromJson(json, Operator.class); - } - - @Test - public void testSerializeBinaryComparisonOperator() { - Operator op = BinaryComparisonOperator.EQUALS; - - JsonObject json = new JsonObject(); - json.addProperty(OperatorSerializer.PROP_CONST, BinaryComparisonOperator.EQUALS.name()); - json.addProperty(OperatorSerializer.PROP_CLASS_NAME, BinaryComparisonOperator.class.getCanonicalName()); - - assertEquals(gson.toJson(json), gson.toJson(op)); - } - - @Test - public void testSerializeBinaryLogicalOperator() { - Operator op = BinaryLogicalOperator.AND; - - JsonObject json = new JsonObject(); - json.addProperty(OperatorSerializer.PROP_CONST, BinaryLogicalOperator.AND.name()); - json.addProperty(OperatorSerializer.PROP_CLASS_NAME, BinaryLogicalOperator.class.getCanonicalName()); - - assertEquals(gson.toJson(json), gson.toJson(op)); - } - - @Test - public void testSerializeUnaryLogicalOperator() { - Operator op = UnaryLogicalOperator.NOT; - - JsonObject json = new JsonObject(); - json.addProperty(OperatorSerializer.PROP_CONST, UnaryLogicalOperator.NOT.name()); - json.addProperty(OperatorSerializer.PROP_CLASS_NAME, UnaryLogicalOperator.class.getCanonicalName()); - - assertEquals(gson.toJson(json), gson.toJson(op)); - } - - @Test(expected=JsonParseException.class) - public void testSerializeUnknownOperator() { - gson.toJson(new TestOperator()); - } - -} diff -r 0e0e2b6041ad -r d387d381858b web/common/src/test/java/com/redhat/thermostat/web/common/PreparedParameterSerializerTest.java --- a/web/common/src/test/java/com/redhat/thermostat/web/common/PreparedParameterSerializerTest.java Mon Sep 16 15:28:13 2013 +0200 +++ b/web/common/src/test/java/com/redhat/thermostat/web/common/PreparedParameterSerializerTest.java Wed Sep 25 19:09:58 2013 +0200 @@ -37,15 +37,21 @@ package com.redhat.thermostat.web.common; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import java.lang.reflect.Array; + import org.junit.Before; import org.junit.Test; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.redhat.thermostat.storage.core.PreparedParameter; +import com.redhat.thermostat.storage.model.AgentInformation; +import com.redhat.thermostat.storage.model.Pojo; +import com.redhat.thermostat.storage.model.VmInfo.KeyValuePair; public class PreparedParameterSerializerTest { @@ -53,7 +59,9 @@ @Before public void setup() { - gson = new GsonBuilder().registerTypeAdapter( + gson = new GsonBuilder() + .registerTypeHierarchyAdapter(Pojo.class, new ThermostatGSONConverter()) + .registerTypeAdapter( PreparedParameter.class, new PreparedParameterSerializer()).create(); } @@ -61,38 +69,44 @@ @Test public void canDeserializeBasic() { // String - String jsonStr = "{ \"type\": \"java.lang.String\" , \"value\": \"testing\"}"; + String jsonStr = "{ \"type\": \"java.lang.String\" , \"value\": \"testing\" , \"isArray\": false}"; PreparedParameter param = gson.fromJson(jsonStr, PreparedParameter.class); assertEquals(String.class, param.getType()); assertEquals("testing", param.getValue()); + assertFalse(param.isArrayType()); // Integer - jsonStr = "{ \"type\": \"java.lang.Integer\" , \"value\": -1}"; + jsonStr = "{ \"type\": \"java.lang.Integer\" , \"value\": -1 , \"isArray\": false}"; param = gson.fromJson(jsonStr, PreparedParameter.class); assertEquals(Integer.class, param.getType()); assertTrue(param.getValue() instanceof Integer); assertEquals(-1, param.getValue()); + assertFalse(param.isArrayType()); // Long - jsonStr = "{ \"type\": \"java.lang.Long\" , \"value\": -10}"; + jsonStr = "{ \"type\": \"java.lang.Long\" , \"value\": -10 , \"isArray\": false}"; param = gson.fromJson(jsonStr, PreparedParameter.class); assertEquals(Long.class, param.getType()); assertTrue(param.getValue() instanceof Long); assertEquals(-10L, param.getValue()); - jsonStr = "{ \"type\": \"java.lang.Long\" , \"value\": 30000000003}"; + assertFalse(param.isArrayType()); + jsonStr = "{ \"type\": \"java.lang.Long\" , \"value\": 30000000003 , \"isArray\": false}"; param = gson.fromJson(jsonStr, PreparedParameter.class); assertEquals(Long.class, param.getType()); assertTrue(param.getValue() instanceof Long); assertEquals(30000000003L, param.getValue()); + assertFalse(param.isArrayType()); // Boolean - jsonStr = "{ \"type\": \"java.lang.Boolean\" , \"value\": true}"; + jsonStr = "{ \"type\": \"java.lang.Boolean\" , \"value\": true , \"isArray\": false}"; param = gson.fromJson(jsonStr, PreparedParameter.class); assertEquals(Boolean.class, param.getType()); assertTrue(param.getValue() instanceof Boolean); assertEquals(true, param.getValue()); + assertFalse(param.isArrayType()); // String[] String strArrayVal = "[ \"testing1\", \"testing2\", \"3\" ]"; - jsonStr = "{ \"type\": \"java.lang.String[]\" , \"value\": " + strArrayVal + "}"; + jsonStr = "{ \"type\": \"java.lang.String\" , \"value\": " + strArrayVal + " , \"isArray\": true}"; param = gson.fromJson(jsonStr, PreparedParameter.class); - assertEquals(String[].class, param.getType()); + assertEquals(String.class, param.getType()); + assertTrue(param.isArrayType()); assertTrue(param.getValue() instanceof String[]); String[] vals = (String[])param.getValue(); assertEquals(3, vals.length); @@ -117,34 +131,39 @@ @Test public void canSerializeBasic() { // String - String expected = "{\"value\":\"testing\",\"type\":\"java.lang.String\"}"; + String expected = "{\"value\":\"testing\",\"type\":\"java.lang.String\",\"isArray\":false}"; PreparedParameter param = new PreparedParameter(); param.setType(String.class); param.setValue("testing"); + param.setArrayType(false); String actual = gson.toJson(param); assertEquals(expected, actual); // Integer - expected = "{\"value\":-1,\"type\":\"java.lang.Integer\"}"; + expected = "{\"value\":-1,\"type\":\"java.lang.Integer\",\"isArray\":false}"; param.setType(Integer.class); param.setValue(-1); + param.setArrayType(false); actual = gson.toJson(param); assertEquals(expected, actual); // Long - expected = "{\"value\":30000000003,\"type\":\"java.lang.Long\"}"; + expected = "{\"value\":30000000003,\"type\":\"java.lang.Long\",\"isArray\":false}"; param.setType(Long.class); param.setValue(30000000003L); + param.setArrayType(false); actual = gson.toJson(param); assertEquals(expected, actual); // boolean - expected = "{\"value\":true,\"type\":\"java.lang.Boolean\"}"; + expected = "{\"value\":true,\"type\":\"java.lang.Boolean\",\"isArray\":false}"; param.setType(Boolean.class); param.setValue(true); + param.setArrayType(false); actual = gson.toJson(param); assertEquals(expected, actual); // String[] String strArrayVal = "[\"testing1\",\"testing2\",\"3\"]"; - expected = "{\"value\":" + strArrayVal + ",\"type\":\"java.lang.String[]\"}"; - param.setType(String[].class); + expected = "{\"value\":" + strArrayVal + ",\"type\":\"java.lang.String\",\"isArray\":true}"; + param.setType(String.class); + param.setArrayType(true); String[] array = new String[] { "testing1", "testing2", "3" }; @@ -158,15 +177,69 @@ PreparedParameter expected = new PreparedParameter(); expected.setType(Integer.class); expected.setValue(3); + expected.setArrayType(false); + String jsonStr = gson.toJson(expected, PreparedParameter.class); + assertParameterEquals(expected, jsonStr); + } + + @Test + public void canSerializeDeserializeIntegerArray() { + PreparedParameter expected = new PreparedParameter(); + expected.setType(Integer.class); + // it's important for the expected type to be of primitive array type, + // rather than Integer[]. we want the serializer to deserialize to + // primitive types if possible. asserted in method assertParameterEquals() + // Note that model classes use primitive array types as well. + expected.setValue(new int[] { 0, 3, 20 }); + expected.setArrayType(true); String jsonStr = gson.toJson(expected, PreparedParameter.class); assertParameterEquals(expected, jsonStr); } - + + @Test + public void canSerializeDeserializeDouble() { + PreparedParameter expected = new PreparedParameter(); + expected.setType(Double.class); + expected.setValue(Math.E); + expected.setArrayType(false); + String jsonStr = gson.toJson(expected, PreparedParameter.class); + assertParameterEquals(expected, jsonStr); + } + + @Test + public void canSerializeDeserializeDoubleArray() { + PreparedParameter expected = new PreparedParameter(); + expected.setType(Double.class); + // it's important for the expected type to be of primitive array type, + // rather than Double[]. we want the serializer to deserialize to + // primitive types if possible. asserted in method assertParameterEquals() + // Note that model classes use primitive array types as well. + expected.setValue(new double[] { 3.3, 1.0, Math.PI }); + expected.setArrayType(true); + String jsonStr = gson.toJson(expected, PreparedParameter.class); + assertParameterEquals(expected, jsonStr); + } + @Test public void canSerializeDeserializeLong() { PreparedParameter expected = new PreparedParameter(); expected.setType(Long.class); expected.setValue(30000000003L); + expected.setArrayType(false); + String jsonStr = gson.toJson(expected, PreparedParameter.class); + assertParameterEquals(expected, jsonStr); + } + + @Test + public void canSerializeDeserializeLongArray() { + PreparedParameter expected = new PreparedParameter(); + expected.setType(Long.class); + // it's important for the expected type to be of primitive array type, + // rather than Long[]. we want the serializer to deserialize to + // primitive types if possible. asserted in method assertParameterEquals() + // Note that model classes use primitive array types as well. + expected.setValue(new long[] { 3000000000L, 3, 20 }); + expected.setArrayType(true); String jsonStr = gson.toJson(expected, PreparedParameter.class); assertParameterEquals(expected, jsonStr); } @@ -176,6 +249,20 @@ PreparedParameter expected = new PreparedParameter(); expected.setType(String.class); expected.setValue("testing"); + expected.setArrayType(false); + String jsonStr = gson.toJson(expected, PreparedParameter.class); + assertParameterEquals(expected, jsonStr); + } + + @Test + public void canSerializeDeserializeStringArray() { + PreparedParameter expected = new PreparedParameter(); + expected.setType(String.class); + expected.setArrayType(true); + String[] expectedArray = new String[] { + "one", "two", "three" + }; + expected.setValue(expectedArray); String jsonStr = gson.toJson(expected, PreparedParameter.class); assertParameterEquals(expected, jsonStr); } @@ -194,29 +281,108 @@ jsonStr = gson.toJson(expected, PreparedParameter.class); assertParameterEquals(expected, jsonStr); } - + + @Test + public void canSerializeDeserializeBooleanArray() { + PreparedParameter expected = new PreparedParameter(); + expected.setType(Boolean.class); + // it's important for the expected type to be of primitive array type, + // rather than Boolean[]. we want the serializer to deserialize to + // primitive types if possible. asserted in method assertParameterEquals() + // Note that model classes use primitive array types as well. + expected.setValue(new boolean[] { true, false, false, true }); + expected.setArrayType(true); + String jsonStr = gson.toJson(expected, PreparedParameter.class); + assertParameterEquals(expected, jsonStr); + } + + + @Test + public void canSerializeDeserializePojos() { + PreparedParameter expected = new PreparedParameter(); + AgentInformation info = new AgentInformation("foo-writer"); + expected.setType(info.getClass()); + expected.setValue(info); + expected.setArrayType(false); + String jsonStr = gson.toJson(expected, PreparedParameter.class); + assertParameterEquals(expected, jsonStr); + + info = new AgentInformation("some-writer"); + info.setAlive(true); + info.setConfigListenAddress("127.0.0.1:12000"); + info.setStartTime(System.currentTimeMillis()); + info.setStopTime(System.currentTimeMillis()); + expected = new PreparedParameter(); + expected.setType(info.getClass()); + expected.setValue(info); + expected.setArrayType(false); + jsonStr = gson.toJson(expected, PreparedParameter.class); + assertParameterEquals(expected, jsonStr); + } + + @Test + public void canSerializeDeserializeInnerClassPojoTypes() { + PreparedParameter expected = new PreparedParameter(); + KeyValuePair pair = new KeyValuePair(); + pair.setKey("foo"); + pair.setValue("bar"); + expected.setType(pair.getClass()); + expected.setValue(pair); + expected.setArrayType(false); + String jsonStr = gson.toJson(expected, PreparedParameter.class); + + PreparedParameter actual = gson.fromJson(jsonStr, PreparedParameter.class); + + assertEquals(expected.getType(), actual.getType()); + assertTrue(expected.isArrayType() == actual.isArrayType()); + assertTrue(actual.getValue() instanceof KeyValuePair); + KeyValuePair actualPair = (KeyValuePair)actual.getValue(); + assertEquals(pair.getKey(), actualPair.getKey()); + assertEquals(pair.getValue(), actualPair.getValue()); + } + + @Test + public void canSerializeDeserializePojoLists() { + AgentInformation info1 = new AgentInformation("foo-writer"); + AgentInformation info2 = new AgentInformation("some-writer"); + info2.setAlive(true); + info2.setConfigListenAddress("127.0.0.1:12000"); + info2.setStartTime(System.currentTimeMillis()); + info2.setStopTime(System.currentTimeMillis()); + AgentInformation[] infos = new AgentInformation[] { + info1, info2 + }; + PreparedParameter param = new PreparedParameter(); + param.setArrayType(true); + param.setType(AgentInformation.class); + param.setValue(infos); + String jsonStr = gson.toJson(param, PreparedParameter.class); + assertParameterEquals(param, jsonStr); + } + private void assertParameterEquals(PreparedParameter expected, String jsonStr) { PreparedParameter actual = gson.fromJson(jsonStr, PreparedParameter.class); assertEquals(expected.getType(), actual.getType()); - assertEquals(expected.getValue(), actual.getValue()); - } - - @Test - public void canSerializeDeserializeStringArray() { - PreparedParameter expected = new PreparedParameter(); - expected.setType(String[].class); - String[] expectedArray = new String[] { - "one", "two", "three" - }; - expected.setValue(expectedArray); - String jsonStr = gson.toJson(expected, PreparedParameter.class); - PreparedParameter actual = gson.fromJson(jsonStr, PreparedParameter.class); - assertEquals(expected.getType(), actual.getType()); - String[] actualArray = (String[])actual.getValue(); - for (int i = 0; i < expectedArray.length; i++) { - assertEquals(expectedArray[i], actualArray[i]); + assertEquals(expected.isArrayType(), actual.isArrayType()); + if (actual.isArrayType()) { + // compare element by element + Object values = actual.getValue(); + Object expectedVals = expected.getValue(); + Class expectedType = expectedVals.getClass(); + int expectedLength = Array.getLength(expectedVals); + int actualLength = Array.getLength(values); + assertEquals(expectedLength, actualLength); + // Make sure the deserialized array is of the correct expected type + assertTrue(values.getClass() == expectedType); + for (int i = 0; i < expectedLength; i++) { + Object exp = Array.get(expectedVals, i); + Object act = Array.get(values, i); + assertEquals(exp, act); + } + } else { + assertEquals(expected.getValue(), actual.getValue()); } } - } + diff -r 0e0e2b6041ad -r d387d381858b web/common/src/test/java/com/redhat/thermostat/web/common/PreparedParametersSerializerTest.java --- a/web/common/src/test/java/com/redhat/thermostat/web/common/PreparedParametersSerializerTest.java Mon Sep 16 15:28:13 2013 +0200 +++ b/web/common/src/test/java/com/redhat/thermostat/web/common/PreparedParametersSerializerTest.java Wed Sep 25 19:09:58 2013 +0200 @@ -45,6 +45,8 @@ import com.google.gson.GsonBuilder; import com.redhat.thermostat.storage.core.PreparedParameter; import com.redhat.thermostat.storage.core.PreparedParameters; +import com.redhat.thermostat.storage.model.AgentInformation; +import com.redhat.thermostat.storage.model.Pojo; public class PreparedParametersSerializerTest { @@ -52,13 +54,16 @@ @Before public void setup() { - gson = new GsonBuilder().registerTypeAdapter( - PreparedParameter.class, - new PreparedParameterSerializer()).create(); + gson = new GsonBuilder() + .registerTypeHierarchyAdapter(Pojo.class, + new ThermostatGSONConverter()) + .registerTypeAdapter( + PreparedParameter.class, + new PreparedParameterSerializer()).create(); } @Test - public void canSerializeDeserialize() { + public void canSerializeDeserializeBasic() { PreparedParameters params = new PreparedParameters(5); params.setBoolean(0, true); params.setInt(1, 2300); @@ -85,4 +90,55 @@ assertEquals(list[i], actualList[i]); } } + + @Test + public void canSerializeDeserializeMixedTypesWithPojoList() { + AgentInformation info1 = new AgentInformation("foo-agent"); + info1.setAlive(true); + AgentInformation info2 = new AgentInformation("foo-agent"); + info2.setAlive(false); + info2.setStartTime(System.currentTimeMillis()); + info2.setStopTime(System.currentTimeMillis()); + info2.setConfigListenAddress("127.0.0.1:12000"); + AgentInformation[] infos = new AgentInformation[] { + info1, info2 + }; + long[] longs = new long[] { 3000000000L, -3, 300 }; + // String, long[], Pojo[] + PreparedParameters params = new PreparedParameters(3); + params.setString(0, "foo-param"); + params.setLongList(1, longs); + params.setPojoList(2, infos); + + String jsonStr = gson.toJson(params, PreparedParameters.class); + PreparedParameters actualParams = gson.fromJson(jsonStr, PreparedParameters.class); + + PreparedParameter[] expected = params.getParams(); + PreparedParameter[] actual = actualParams.getParams(); + + assertEquals(expected.length, actual.length); + + PreparedParameter param1 = actual[0]; + assertEquals("foo-param", param1.getValue()); + assertEquals(String.class, param1.getType()); + assertEquals(false, param1.isArrayType()); + + PreparedParameter param2 = actual[1]; + assertEquals(Long.class, param2.getType()); + assertEquals(true, param2.isArrayType()); + long[] twoActuals = (long[])param2.getValue(); + assertEquals(3, twoActuals.length); + assertEquals(3000000000L, (long)twoActuals[0]); + assertEquals(-3, (long)twoActuals[1]); + assertEquals(300, (long)twoActuals[2]); + + PreparedParameter param3 = actual[2]; + assertEquals(AgentInformation.class, param3.getType()); + assertEquals(true, param3.isArrayType()); + Pojo[] pojos = (Pojo[])param3.getValue(); + assertEquals(2, pojos.length); + for (int i = 0; i < pojos.length; i++) { + assertEquals(infos[i], pojos[i]); + } + } } diff -r 0e0e2b6041ad -r d387d381858b web/common/src/test/java/com/redhat/thermostat/web/common/WebPreparedStatementSerializerTest.java --- a/web/common/src/test/java/com/redhat/thermostat/web/common/WebPreparedStatementSerializerTest.java Mon Sep 16 15:28:13 2013 +0200 +++ b/web/common/src/test/java/com/redhat/thermostat/web/common/WebPreparedStatementSerializerTest.java Wed Sep 25 19:09:58 2013 +0200 @@ -37,7 +37,9 @@ package com.redhat.thermostat.web.common; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import org.junit.Before; import org.junit.Test; @@ -46,6 +48,8 @@ import com.google.gson.GsonBuilder; import com.redhat.thermostat.storage.core.PreparedParameter; import com.redhat.thermostat.storage.core.PreparedParameters; +import com.redhat.thermostat.storage.model.AgentInformation; +import com.redhat.thermostat.storage.model.Pojo; public class WebPreparedStatementSerializerTest { @@ -56,6 +60,7 @@ gson = new GsonBuilder() .registerTypeAdapter(WebPreparedStatement.class, new WebPreparedStatementSerializer()) + .registerTypeHierarchyAdapter(Pojo.class, new ThermostatGSONConverter()) .registerTypeAdapter(PreparedParameter.class, new PreparedParameterSerializer()).create(); } @@ -81,15 +86,46 @@ assertEquals(Integer.class, parameters[0].getType()); assertEquals("testing", parameters[1].getValue()); assertEquals(String.class, parameters[1].getType()); + assertFalse(parameters[1].isArrayType()); assertEquals(222L, parameters[2].getValue()); assertEquals(Long.class, parameters[2].getType()); + assertFalse(parameters[2].isArrayType()); String[] list = (String[])parameters[3].getValue(); assertEquals(2, list.length); assertEquals("one", list[0]); assertEquals("two", list[1]); - assertEquals(String[].class, parameters[3].getType()); + assertEquals(String.class, parameters[3].getType()); + assertTrue(parameters[3].isArrayType()); assertEquals(true, parameters[4].getValue()); assertEquals(Boolean.class, parameters[4].getType()); + assertFalse(parameters[4].isArrayType()); assertEquals(WebPreparedStatementResponse.DESCRIPTOR_PARSE_FAILED, newStmt.getStatementId()); } + + /* + * Writes need Pojo support for serialization. This is a basic test we do + * get Pojos across the wire in a prepared context. + */ + @Test + public void canSerializeDeserializePojoParameters() { + PreparedParameters params = new PreparedParameters(2); + params.setIntList(0, new int[] { 0, 300 }); + AgentInformation pojo1 = new AgentInformation("foo-agent"); + AgentInformation pojo2 = new AgentInformation("foo-agent"); + pojo2.setAlive(true); + pojo2.setConfigListenAddress("127.0.0.1:38822"); + params.setPojoList(1, new AgentInformation[] { pojo1, pojo2 }); + + WebPreparedStatement stmt = new WebPreparedStatement<>(); + stmt.setParams(params); + stmt.setStatementId(WebPreparedStatementResponse.DESCRIPTOR_PARSE_FAILED); + + String jsonString = gson.toJson(stmt, WebPreparedStatement.class); + assertNotNull(jsonString); + + WebPreparedStatement result = gson.fromJson(jsonString, WebPreparedStatement.class); + assertEquals(WebPreparedStatementResponse.DESCRIPTOR_PARSE_FAILED, result.getStatementId()); + assertNotNull(result.getParams()); + + } } diff -r 0e0e2b6041ad -r d387d381858b web/common/src/test/java/com/redhat/thermostat/web/common/WebQueryResponseSerializerTest.java --- a/web/common/src/test/java/com/redhat/thermostat/web/common/WebQueryResponseSerializerTest.java Mon Sep 16 15:28:13 2013 +0200 +++ b/web/common/src/test/java/com/redhat/thermostat/web/common/WebQueryResponseSerializerTest.java Wed Sep 25 19:09:58 2013 +0200 @@ -75,7 +75,7 @@ // create the query response WebQueryResponse response = new WebQueryResponse<>(); response.setResultList(resultList); - response.setResponseCode(WebQueryResponse.ILLEGAL_PATCH); + response.setResponseCode(PreparedStatementResponseCode.ILLEGAL_PATCH); String jsonStr = gson.toJson(response); String expectedJson = "{\"payload\":[{\"startTime\":0,\"stopTime\":0,\"alive\":false,\"backends\":[],\"agentId\":\"testing\"}],\"errno\":-1}"; @@ -90,7 +90,7 @@ AgentInformation[] actualList = actual.getResultList(); - assertEquals(WebQueryResponse.ILLEGAL_PATCH, actual.getResponseCode()); + assertEquals(PreparedStatementResponseCode.ILLEGAL_PATCH, actual.getResponseCode()); assertEquals(1, actualList.length); AgentInformation actualInfo = actualList[0]; assertEquals(true, actualInfo.isAlive()); @@ -109,7 +109,7 @@ // create the query response WebQueryResponse response = new WebQueryResponse<>(); response.setResultList(resultList); - response.setResponseCode(WebQueryResponse.ILLEGAL_PATCH); + response.setResponseCode(PreparedStatementResponseCode.ILLEGAL_PATCH); String jsonStr = gson.toJson(response); @@ -120,7 +120,7 @@ AgentInformation[] actualList = actual.getResultList(); - assertEquals(WebQueryResponse.ILLEGAL_PATCH, actual.getResponseCode()); + assertEquals(PreparedStatementResponseCode.ILLEGAL_PATCH, actual.getResponseCode()); assertEquals(1, actualList.length); AgentInformation actualInfo = actualList[0]; assertEquals(false, actualInfo.isAlive()); @@ -139,7 +139,7 @@ // create the query response WebQueryResponse response = new WebQueryResponse<>(); response.setResultList(resultList); - response.setResponseCode(WebQueryResponse.ILLEGAL_PATCH); + response.setResponseCode(PreparedStatementResponseCode.ILLEGAL_PATCH); String jsonStr = gson.toJson(response); String expectedJson = "{\"payload\":[{\"startTime\":0,\"stopTime\":0,\"alive\":false,\"backends\":[],\"agentId\":\"testing\"}],\"errno\":-1}"; @@ -152,7 +152,7 @@ AgentInformation[] actualList = actual.getResultList(); - assertEquals(WebQueryResponse.ILLEGAL_PATCH, actual.getResponseCode()); + assertEquals(PreparedStatementResponseCode.ILLEGAL_PATCH, actual.getResponseCode()); assertEquals(1, actualList.length); AgentInformation actualInfo = actualList[0]; assertEquals(false, actualInfo.isAlive()); @@ -170,13 +170,13 @@ WebQueryResponse expected = new WebQueryResponse<>(); expected.setResultList(hostInfoResults); - expected.setResponseCode(WebQueryResponse.SUCCESS); + expected.setResponseCode(PreparedStatementResponseCode.QUERY_SUCCESS); jsonStr = gson.toJson(expected); Type hostinfoQueryResponseType = new TypeToken>() {}.getType(); WebQueryResponse actualResp = gson.fromJson(jsonStr, hostinfoQueryResponseType); - assertEquals(WebQueryResponse.SUCCESS, actualResp.getResponseCode()); + assertEquals(PreparedStatementResponseCode.QUERY_SUCCESS, actualResp.getResponseCode()); HostInfo[] hostInfoList = actualResp.getResultList(); assertEquals(1, hostInfoList.length); assertEquals("something", hostInfoList[0].getAgentId()); diff -r 0e0e2b6041ad -r d387d381858b web/server/src/main/java/com/redhat/thermostat/web/server/WebStorageEndPoint.java --- a/web/server/src/main/java/com/redhat/thermostat/web/server/WebStorageEndPoint.java Mon Sep 16 15:28:13 2013 +0200 +++ b/web/server/src/main/java/com/redhat/thermostat/web/server/WebStorageEndPoint.java Wed Sep 25 19:09:58 2013 +0200 @@ -69,17 +69,15 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import com.google.gson.JsonArray; -import com.google.gson.JsonParser; import com.redhat.thermostat.common.utils.LoggingUtils; import com.redhat.thermostat.shared.config.Configuration; import com.redhat.thermostat.shared.config.InvalidConfigurationException; -import com.redhat.thermostat.storage.core.Add; import com.redhat.thermostat.storage.core.Categories; import com.redhat.thermostat.storage.core.Category; import com.redhat.thermostat.storage.core.CategoryAdapter; 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.IllegalPatchException; import com.redhat.thermostat.storage.core.Key; @@ -88,11 +86,8 @@ import com.redhat.thermostat.storage.core.PreparedParameters; import com.redhat.thermostat.storage.core.PreparedStatement; import com.redhat.thermostat.storage.core.Query; -import com.redhat.thermostat.storage.core.Remove; -import com.redhat.thermostat.storage.core.Replace; import com.redhat.thermostat.storage.core.StatementDescriptor; import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.core.Update; import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; import com.redhat.thermostat.storage.core.auth.StatementDescriptorMetadataFactory; import com.redhat.thermostat.storage.model.AggregateResult; @@ -100,21 +95,15 @@ import com.redhat.thermostat.storage.query.BinaryLogicalExpression; import com.redhat.thermostat.storage.query.BinaryLogicalOperator; import com.redhat.thermostat.storage.query.Expression; -import com.redhat.thermostat.storage.query.Operator; -import com.redhat.thermostat.web.common.ExpressionSerializer; -import com.redhat.thermostat.web.common.OperatorSerializer; import com.redhat.thermostat.web.common.PreparedParameterSerializer; +import com.redhat.thermostat.web.common.PreparedStatementResponseCode; import com.redhat.thermostat.web.common.StorageWrapper; import com.redhat.thermostat.web.common.ThermostatGSONConverter; -import com.redhat.thermostat.web.common.WebAdd; import com.redhat.thermostat.web.common.WebPreparedStatement; import com.redhat.thermostat.web.common.WebPreparedStatementResponse; import com.redhat.thermostat.web.common.WebPreparedStatementSerializer; import com.redhat.thermostat.web.common.WebQueryResponse; import com.redhat.thermostat.web.common.WebQueryResponseSerializer; -import com.redhat.thermostat.web.common.WebRemove; -import com.redhat.thermostat.web.common.WebReplace; -import com.redhat.thermostat.web.common.WebUpdate; import com.redhat.thermostat.web.server.auth.FilterResult; import com.redhat.thermostat.web.server.auth.Roles; import com.redhat.thermostat.web.server.auth.UserPrincipal; @@ -174,10 +163,6 @@ gson = new GsonBuilder() .registerTypeHierarchyAdapter(Pojo.class, new ThermostatGSONConverter()) - .registerTypeHierarchyAdapter(Expression.class, - new ExpressionSerializer()) - .registerTypeHierarchyAdapter(Operator.class, - new OperatorSerializer()) .registerTypeAdapter(WebQueryResponse.class, new WebQueryResponseSerializer<>()) .registerTypeAdapter(PreparedParameter.class, new PreparedParameterSerializer()) .registerTypeAdapter(WebPreparedStatement.class, new WebPreparedStatementSerializer()) @@ -237,16 +222,10 @@ prepareStatement(req, resp); } else if (cmd.equals("query-execute")) { queryExecute(req, resp); - } else if (cmd.equals("add-pojo")) { - addPojo(req, resp); - } else if (cmd.equals("replace-pojo")) { - replacePojo(req, resp); + } else if (cmd.equals("write-execute")) { + writeExecute(req, resp); } else if (cmd.equals("register-category")) { registerCategory(req, resp); - } else if (cmd.equals("remove-pojo")) { - removePojo(req, resp); - } else if (cmd.equals("update-pojo")) { - updatePojo(req, resp); } else if (cmd.equals("save-file")) { saveFile(req, resp); } else if (cmd.equals("load-file")) { @@ -559,102 +538,6 @@ } } - @WebStoragePathHandler( path = "add-pojo" ) - private void addPojo(HttpServletRequest req, HttpServletResponse resp) { - if (! isAuthorized(req, resp, Roles.APPEND)) { - return; - } - String addParam = req.getParameter("add"); - WebAdd add = gson.fromJson(addParam, WebAdd.class); - int categoryId = add.getCategoryId(); - Category category = getCategoryFromId(categoryId); - Add targetAdd = storage.createAdd(category); - Class pojoCls = category.getDataClass(); - String pojoParam = req.getParameter("pojo"); - Pojo pojo = gson.fromJson(pojoParam, pojoCls); - targetAdd.setPojo(pojo); - targetAdd.apply(); - resp.setStatus(HttpServletResponse.SC_OK); - } - - @WebStoragePathHandler( path = "replace-pojo" ) - private void replacePojo(HttpServletRequest req, HttpServletResponse resp) { - if (! isAuthorized(req, resp, Roles.REPLACE)) { - return; - } - String replaceParam = req.getParameter("replace"); - WebReplace replace = gson.fromJson(replaceParam, WebReplace.class); - int categoryId = replace.getCategoryId(); - Category category = getCategoryFromId(categoryId); - Replace targetReplace = storage.createReplace(category); - Class pojoCls = category.getDataClass(); - String pojoParam = req.getParameter("pojo"); - Pojo pojo = gson.fromJson(pojoParam, pojoCls); - targetReplace.setPojo(pojo); - Expression expr = replace.getWhereExpression(); - targetReplace.where(expr); - targetReplace.apply(); - resp.setStatus(HttpServletResponse.SC_OK); - } - - @WebStoragePathHandler( path = "remove-pojo" ) - private void removePojo(HttpServletRequest req, HttpServletResponse resp) { - if (! isAuthorized(req, resp, Roles.DELETE)) { - return; - } - - String removeParam = req.getParameter("remove"); - WebRemove remove = gson.fromJson(removeParam, WebRemove.class); - Category targetCategory = getCategoryFromId(remove.getCategoryId()); - Remove targetRemove = storage.createRemove(targetCategory); - Expression expr = remove.getWhereExpression(); - if (expr != null) { - targetRemove.where(expr); - } - targetRemove.apply(); - resp.setStatus(HttpServletResponse.SC_OK); - } - - @WebStoragePathHandler( path = "update-pojo" ) - @SuppressWarnings({ "rawtypes", "unchecked" }) - private void updatePojo(HttpServletRequest req, HttpServletResponse resp) { - if (! isAuthorized(req, resp, Roles.UPDATE)) { - return; - } - - try { - String updateParam = req.getParameter("update"); - WebUpdate update = gson.fromJson(updateParam, WebUpdate.class); - Update targetUpdate = storage.createUpdate(getCategoryFromId(update.getCategoryId())); - Expression expr = update.getWhereExpression(); - if (expr != null) { - targetUpdate.where(expr); - } - List updates = update.getUpdates(); - if (updates != null) { - String valuesParam = req.getParameter("values"); - JsonParser parser = new JsonParser(); - JsonArray jsonArray = parser.parse(valuesParam) - .getAsJsonArray(); - 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); - } - } - targetUpdate.apply(); - resp.setStatus(HttpServletResponse.SC_OK); - } catch (ClassNotFoundException ex) { - ex.printStackTrace(); - resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - } - } - @SuppressWarnings("unchecked") @WebStoragePathHandler( path = "query-execute" ) private void queryExecute(HttpServletRequest req, HttpServletResponse resp) throws IOException { @@ -674,9 +557,10 @@ WebQueryResponse response = new WebQueryResponse<>(); try { targetQuery = (Query)parsed.patchStatement(params); - response.setResponseCode(WebQueryResponse.SUCCESS); + response.setResponseCode(PreparedStatementResponseCode.QUERY_SUCCESS); } catch (IllegalPatchException e) { - response.setResponseCode(WebQueryResponse.ILLEGAL_PATCH); + logger.log(Level.INFO, "Failed to execute query", e); + response.setResponseCode(PreparedStatementResponseCode.ILLEGAL_PATCH); writeResponse(resp, response, WebQueryResponse.class); return; } @@ -699,6 +583,36 @@ writeResponse(resp, response, WebQueryResponse.class); } + @SuppressWarnings("unchecked") + @WebStoragePathHandler( path = "write-execute" ) + private void writeExecute(HttpServletRequest req, HttpServletResponse resp) throws IOException { + if (! isAuthorized(req, resp, Roles.WRITE)) { + return; + } + String queryParam = req.getParameter("prepared-stmt"); + WebPreparedStatement stmt = gson.fromJson(queryParam, WebPreparedStatement.class); + + PreparedParameters p = stmt.getParams(); + PreparedParameter[] params = p.getParams(); + PreparedStatementHolder targetStmtHolder = getStatementHolderFromId(stmt.getStatementId()); + PreparedStatement targetStmt = targetStmtHolder.getStmt(); + ParsedStatement parsed = targetStmt.getParsedStatement(); + + DataModifyingStatement targetStatement = null; + try { + // perform the patching of the target statement. + targetStatement = (DataModifyingStatement)parsed.patchStatement(params); + } catch (IllegalPatchException e) { + logger.log(Level.INFO, "Failed to execute write", e); + writeResponse(resp, PreparedStatementResponseCode.ILLEGAL_PATCH, int.class); + return; + } + + // executes statement + int response = targetStatement.apply(); + writeResponse(resp, response, int.class); + } + private UserPrincipal getUserPrincipal(HttpServletRequest req) { // Since we use our own JAAS based auth module this cast is safe // for Tomcat and JBoss AS 7 since they allow for configuration of diff -r 0e0e2b6041ad -r d387d381858b web/server/src/main/java/com/redhat/thermostat/web/server/auth/Roles.java --- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/Roles.java Mon Sep 16 15:28:13 2013 +0200 +++ b/web/server/src/main/java/com/redhat/thermostat/web/server/auth/Roles.java Wed Sep 25 19:09:58 2013 +0200 @@ -72,12 +72,17 @@ */ final String GRANT_READ_ALL = "thermostat-grant-read-ALL"; + /* + * TODO: Not sure if we still want to use the following 4 stop-gap roles. + */ final String APPEND = "thermostat-add"; final String REPLACE = "thermostat-replace"; final String UPDATE = "thermostat-update"; final String DELETE = "thermostat-remove"; + final String PREPARE_STATEMENT = "thermostat-prepare-statement"; final String READ = "thermostat-query"; + final String WRITE = "thermostat-write"; final String LOAD_FILE = "thermostat-load-file"; final String SAVE_FILE = "thermostat-save-file"; final String PURGE = "thermostat-purge"; diff -r 0e0e2b6041ad -r d387d381858b web/server/src/test/java/com/redhat/thermostat/web/server/KnownDescriptorRegistryTest.java --- a/web/server/src/test/java/com/redhat/thermostat/web/server/KnownDescriptorRegistryTest.java Mon Sep 16 15:28:13 2013 +0200 +++ b/web/server/src/test/java/com/redhat/thermostat/web/server/KnownDescriptorRegistryTest.java Wed Sep 25 19:09:58 2013 +0200 @@ -78,10 +78,10 @@ KnownDescriptorRegistry reg = new KnownDescriptorRegistry(); Set trustedDescs = reg.getRegisteredDescriptors(); assertNotNull(trustedDescs); - // storage-core registers 9 queries; this module has + // storage-core registers 22 descriptors; this module has // only storage-core as maven dep which registers queries. // see DAOImplStatementDescriptorRegistration - assertEquals(13, trustedDescs.size()); + assertEquals(22, trustedDescs.size()); } @Test diff -r 0e0e2b6041ad -r d387d381858b web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndpointTest.java --- a/web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndpointTest.java Mon Sep 16 15:28:13 2013 +0200 +++ b/web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndpointTest.java Wed Sep 25 19:09:58 2013 +0200 @@ -109,10 +109,7 @@ import com.redhat.thermostat.storage.core.PreparedParameter; import com.redhat.thermostat.storage.core.PreparedStatement; import com.redhat.thermostat.storage.core.Query; -import com.redhat.thermostat.storage.core.Remove; -import com.redhat.thermostat.storage.core.Replace; import com.redhat.thermostat.storage.core.StatementDescriptor; -import com.redhat.thermostat.storage.core.Update; import com.redhat.thermostat.storage.core.auth.CategoryRegistration; import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; @@ -124,23 +121,17 @@ import com.redhat.thermostat.storage.query.BinarySetMembershipExpression; import com.redhat.thermostat.storage.query.Expression; import com.redhat.thermostat.storage.query.ExpressionFactory; -import com.redhat.thermostat.storage.query.Operator; import com.redhat.thermostat.test.FreePortFinder; import com.redhat.thermostat.test.FreePortFinder.TryPort; -import com.redhat.thermostat.web.common.ExpressionSerializer; -import com.redhat.thermostat.web.common.OperatorSerializer; import com.redhat.thermostat.web.common.PreparedParameterSerializer; +import com.redhat.thermostat.web.common.PreparedStatementResponseCode; import com.redhat.thermostat.web.common.StorageWrapper; import com.redhat.thermostat.web.common.ThermostatGSONConverter; -import com.redhat.thermostat.web.common.WebAdd; import com.redhat.thermostat.web.common.WebPreparedStatement; import com.redhat.thermostat.web.common.WebPreparedStatementResponse; import com.redhat.thermostat.web.common.WebPreparedStatementSerializer; import com.redhat.thermostat.web.common.WebQueryResponse; import com.redhat.thermostat.web.common.WebQueryResponseSerializer; -import com.redhat.thermostat.web.common.WebRemove; -import com.redhat.thermostat.web.common.WebReplace; -import com.redhat.thermostat.web.common.WebUpdate; import com.redhat.thermostat.web.server.auth.BasicRole; import com.redhat.thermostat.web.server.auth.RolePrincipal; import com.redhat.thermostat.web.server.auth.Roles; @@ -192,7 +183,6 @@ private static Key key2; private static Category category; private static String categoryName = "test"; - private ExpressionFactory factory; @BeforeClass public static void setupCategory() { @@ -221,8 +211,6 @@ mockStorage = mock(BackingStorage.class); StorageWrapper.setStorage(mockStorage); - - factory = new ExpressionFactory(); } private void startServer(int port, LoginService loginService) throws Exception { @@ -257,9 +245,8 @@ // manually maintained list of path handlers which should include // authorization checks final String[] authPaths = new String[] { - "prepare-statement", "query-execute", "add-pojo", "replace-pojo", "register-category", "remove-pojo", - "update-pojo", "save-file", "load-file", - "purge", "ping", "generate-token", "verify-token" + "prepare-statement", "query-execute", "write-execute", "register-category", + "save-file", "load-file", "purge", "ping", "generate-token", "verify-token" }; Map checkedAutPaths = new HashMap<>(); for (String path: authPaths) { @@ -736,6 +723,110 @@ KnownDescriptorRegistryFactory.setKnownDescriptorRegistry(registry); } + @SuppressWarnings("unchecked") + @Test + public void authorizedPreparedWrite() throws Exception { + Category oldCategory = category; + String categoryName = "test-authorizedPreparedWrite"; + // redefine category to include the agentId key in the category. + // undone via a the try-finally block. + category = new Category<>(categoryName, TestClass.class, key1, key2, Key.AGENT_ID); + try { + String strDescriptor = "ADD " + category.getName() + " SET '" + + key1.getName() + "' = ?s , '" + key2.getName() + "' = ?s"; + DescriptorMetadata metadata = new DescriptorMetadata(); + setupTrustedStatementRegistry(strDescriptor, metadata); + + Set roles = new HashSet<>(); + roles.add(new RolePrincipal(Roles.REGISTER_CATEGORY)); + roles.add(new RolePrincipal(Roles.PREPARE_STATEMENT)); + roles.add(new RolePrincipal(Roles.WRITE)); + roles.add(new RolePrincipal(Roles.ACCESS_REALM)); + UserPrincipal testUser = new UserPrincipal("ignored1"); + testUser.setRoles(roles); + + final LoginService loginService = new TestJAASLoginService(testUser); + port = FreePortFinder.findFreePort(new TryPort() { + + @Override + public void tryPort(int port) throws Exception { + startServer(port, loginService); + } + }); + // This makes register category work for the "test" category. + // Undone via @After + setupTrustedCategory(categoryName); + registerCategory("ignored1", "ignored2"); + + // prepare-statement does this under the hood + Add mockMongoAdd = mock(Add.class); + + when(mockStorage.createAdd(eq(category))).thenReturn(mockMongoAdd); + + PreparedStatement mockPreparedQuery = mock(PreparedStatement.class); + when(mockStorage.prepareStatement(any(StatementDescriptor.class))).thenReturn(mockPreparedQuery); + + ParsedStatement mockParsedStatement = mock(ParsedStatement.class); + when(mockParsedStatement.getNumParams()).thenReturn(2); + when(mockParsedStatement.patchStatement(any(PreparedParameter[].class))).thenReturn(mockMongoAdd); + when(mockPreparedQuery.getParsedStatement()).thenReturn(mockParsedStatement); + + // The web layer + when(mockPreparedQuery.execute()).thenReturn(PreparedStatementResponseCode.WRITE_GENERIC_FAILURE); + // And the mongo layer + when(mockMongoAdd.apply()).thenReturn(PreparedStatementResponseCode.WRITE_GENERIC_FAILURE); + + String endpoint = getEndpoint(); + URL url = new URL(endpoint + "/prepare-statement"); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("POST"); + sendAuthentication(conn, "ignored1", "ignored2"); + conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + conn.setDoInput(true); + conn.setDoOutput(true); + Gson gson = new GsonBuilder() + .registerTypeHierarchyAdapter(Pojo.class, new ThermostatGSONConverter()) + .registerTypeAdapter(WebPreparedStatement.class, new WebPreparedStatementSerializer()) + .registerTypeAdapter(PreparedParameter.class, new PreparedParameterSerializer()).create(); + OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream()); + String body = "query-descriptor=" + URLEncoder.encode(strDescriptor, "UTF-8") + "&category-id=" + categoryId; + out.write(body + "\n"); + out.flush(); + + Reader in = new InputStreamReader(conn.getInputStream()); + WebPreparedStatementResponse response = gson.fromJson(in, WebPreparedStatementResponse.class); + assertEquals(2, response.getNumFreeVariables()); + assertEquals(0, response.getStatementId()); + assertEquals("application/json; charset=UTF-8", conn.getContentType()); + + + + // now execute the ADD we've just prepared + WebPreparedStatement stmt = new WebPreparedStatement<>(2, 0); + stmt.setString(0, "fluff"); + stmt.setString(1, "test2"); + + url = new URL(endpoint + "/write-execute"); + HttpURLConnection conn2 = (HttpURLConnection) url.openConnection(); + conn2.setRequestMethod("POST"); + sendAuthentication(conn2, "ignored1", "ignored2"); + conn2.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + conn2.setDoInput(true); + conn2.setDoOutput(true); + + out = new OutputStreamWriter(conn2.getOutputStream()); + body = "prepared-stmt=" + gson.toJson(stmt, WebPreparedStatement.class); + out.write(body + "\n"); + out.flush(); + + in = new InputStreamReader(conn2.getInputStream()); + int result = gson.fromJson(in, int.class); + assertEquals(PreparedStatementResponseCode.WRITE_GENERIC_FAILURE, result); + } finally { + category = oldCategory; + } + } + @Test public void cannotRegisterCategoryWithoutRegistrationOnInit() throws Exception { // need this in order to pass basic permissions. @@ -878,215 +969,6 @@ return id; } - @Test - public void authorizedReplacePojo() throws Exception { - String[] roleNames = new String[] { - Roles.REPLACE, - Roles.REGISTER_CATEGORY, - Roles.ACCESS_REALM - }; - String testuser = "testuser"; - String password = "testpassword"; - final LoginService loginService = new TestLoginService(testuser, password, roleNames); - port = FreePortFinder.findFreePort(new TryPort() { - - @Override - public void tryPort(int port) throws Exception { - startServer(port, loginService); - } - }); - // This makes register category work for the "test" category. - // Undone via @After - setupTrustedCategory(categoryName); - registerCategory(testuser, password); - - @SuppressWarnings("unchecked") - Replace replace = mock(Replace.class); - when(mockStorage.createReplace(eq(category))).thenReturn(replace); - - TestClass expected1 = new TestClass(); - expected1.setKey1("fluff1"); - expected1.setKey2(42); - Expression expectedExpression = new ExpressionFactory().equalTo(key1, "fluff1"); - - String endpoint = getEndpoint(); - - URL url = new URL(endpoint + "/replace-pojo"); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setRequestMethod("POST"); - sendAuthentication(conn, testuser, password); - - conn.setDoOutput(true); - conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - WebReplace webReplace = new WebReplace<>(categoryId); - webReplace.where(expectedExpression); - Gson gson = new GsonBuilder() - .registerTypeHierarchyAdapter(Expression.class, - new ExpressionSerializer()) - .registerTypeHierarchyAdapter(Operator.class, - new OperatorSerializer()).create(); - OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream()); - out.write("replace="); - gson.toJson(webReplace, out); - out.flush(); - out.write("&pojo="); - gson.toJson(expected1, out); - out.write("\n"); - out.flush(); - assertEquals(200, conn.getResponseCode()); - verify(mockStorage).createReplace(category); - verify(replace).setPojo(expected1); - verify(replace).where(eq(expectedExpression)); - verify(replace).apply(); - } - - @Test - public void unauthorizedReplacePojo() throws Exception { - String[] insufficientRoleNames = new String[] { - Roles.REGISTER_CATEGORY, - Roles.ACCESS_REALM - }; - String testuser = "testuser"; - String password = "testpassword"; - final LoginService loginService = new TestLoginService(testuser, password, insufficientRoleNames); - port = FreePortFinder.findFreePort(new TryPort() { - - @Override - public void tryPort(int port) throws Exception { - startServer(port, loginService); - } - }); - // This makes register category work for the "test" category. - // Undone via @After - setupTrustedCategory(categoryName); - registerCategory(testuser, password); - - String endpoint = getEndpoint(); - URL url = new URL(endpoint + "/replace-pojo"); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setRequestMethod("POST"); - sendAuthentication(conn, testuser, password); - 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); - Gson gson = new GsonBuilder() - .registerTypeHierarchyAdapter(Expression.class, - new ExpressionSerializer()) - .registerTypeHierarchyAdapter(Operator.class, - new OperatorSerializer()).create(); - OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream()); - out.write("replace="); - gson.toJson(webReplace, out); - out.flush(); - out.write("&pojo="); - TestClass expected1 = new TestClass(); - gson.toJson(expected1, out); - out.write("\n"); - out.flush(); - - assertEquals("thermostat-replace role missing", HttpServletResponse.SC_FORBIDDEN, conn.getResponseCode()); - } - - @Test - public void authorizedAddPojo() throws Exception { - String[] roleNames = new String[] { - Roles.APPEND, - Roles.REGISTER_CATEGORY, - Roles.ACCESS_REALM - }; - String testuser = "testuser"; - String password = "testpassword"; - final LoginService loginService = new TestLoginService(testuser, password, roleNames); - port = FreePortFinder.findFreePort(new TryPort() { - - @Override - public void tryPort(int port) throws Exception { - startServer(port, loginService); - } - }); - // This makes register category work for the "test" category. - // Undone via @After - setupTrustedCategory(categoryName); - registerCategory(testuser, password); - - @SuppressWarnings("unchecked") - Add insert = mock(Add.class); - when(mockStorage.createAdd(eq(category))).thenReturn(insert); - - TestClass expected1 = new TestClass(); - expected1.setKey1("fluff1"); - expected1.setKey2(42); - - String endpoint = getEndpoint(); - - URL url = new URL(endpoint + "/add-pojo"); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setRequestMethod("POST"); - sendAuthentication(conn, testuser, password); - - conn.setDoOutput(true); - conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - WebAdd ins = new WebAdd<>(categoryId); - Gson gson = new Gson(); - OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream()); - out.write("add="); - gson.toJson(ins, out); - out.flush(); - out.write("&pojo="); - gson.toJson(expected1, out); - out.write("\n"); - out.flush(); - assertEquals(200, conn.getResponseCode()); - verify(mockStorage).createAdd(category); - verify(insert).setPojo(expected1); - verify(insert).apply(); - } - - @Test - public void unauthorizedAddPojo() throws Exception { - String[] insufficientRoleNames = new String[] { - Roles.REGISTER_CATEGORY, - Roles.ACCESS_REALM - }; - String testuser = "testuser"; - String password = "testpassword"; - final LoginService loginService = new TestLoginService(testuser, password, insufficientRoleNames); - port = FreePortFinder.findFreePort(new TryPort() { - - @Override - public void tryPort(int port) throws Exception { - startServer(port, loginService); - } - }); - // This makes register category work for the "test" category. - // Undone via @After - setupTrustedCategory(categoryName); - registerCategory(testuser, password); - - String endpoint = getEndpoint(); - URL url = new URL(endpoint + "/add-pojo"); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setRequestMethod("POST"); - sendAuthentication(conn, testuser, password); - 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); - Gson gson = new Gson(); - OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream()); - out.write("add="); - gson.toJson(insert, out); - out.flush(); - out.write("&pojo="); - TestClass expected1 = new TestClass(); - gson.toJson(expected1, out); - out.write("\n"); - out.flush(); - - assertEquals("thermostat-add role missing", HttpServletResponse.SC_FORBIDDEN, conn.getResponseCode()); - } - private void sendAuthentication(HttpURLConnection conn, String username, String passwd) { String userpassword = username + ":" + passwd; String encodedAuthorization = Base64.encodeBase64String(userpassword.getBytes()); @@ -1094,138 +976,6 @@ } @Test - public void authorizedRemovePojo() throws Exception { - String[] roleNames = new String[] { - Roles.DELETE, - Roles.REGISTER_CATEGORY, - Roles.ACCESS_REALM - }; - String testuser = "testuser"; - String password = "testpassword"; - final LoginService loginService = new TestLoginService(testuser, password, roleNames); - port = FreePortFinder.findFreePort(new TryPort() { - - @Override - public void tryPort(int port) throws Exception { - startServer(port, loginService); - } - }); - // This makes register category work for the "test" category. - // Undone via @After - setupTrustedCategory(categoryName); - registerCategory(testuser, password); - - - @SuppressWarnings("unchecked") - Remove mockRemove = mock(Remove.class); - - when(mockStorage.createRemove(category)).thenReturn(mockRemove); - - String endpoint = getEndpoint(); - - URL url = new URL(endpoint + "/remove-pojo"); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setRequestMethod("POST"); - sendAuthentication(conn, testuser, password); - conn.setDoOutput(true); - conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - Expression expr = factory.equalTo(key1, "test"); - WebRemove remove = new WebRemove<>(categoryId); - remove.where(expr); - Gson gson = new GsonBuilder() - .registerTypeHierarchyAdapter(Expression.class, - new ExpressionSerializer()) - .registerTypeHierarchyAdapter(Operator.class, - new OperatorSerializer()).create(); - OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream()); - out.write("remove="); - gson.toJson(remove, out); - out.write("\n"); - out.flush(); - - assertEquals(200, conn.getResponseCode()); - verify(mockStorage).createRemove(eq(category)); - verify(mockRemove).where(eq(expr)); - verify(mockRemove).apply(); - } - - @Test - public void unauthorizedRemovePojo() throws Exception { - String failMsg = "thermostat-remove role missing, expected Forbidden!"; - doUnauthorizedTest("remove-pojo", failMsg); - } - - @Test - public void authorizedUpdatePojo() throws Exception { - String[] roleNames = new String[] { - Roles.UPDATE, - Roles.REGISTER_CATEGORY, - Roles.ACCESS_REALM - }; - String testuser = "testuser"; - String password = "testpassword"; - final LoginService loginService = new TestLoginService(testuser, password, roleNames); - port = FreePortFinder.findFreePort(new TryPort() { - - @Override - public void tryPort(int port) throws Exception { - startServer(port, loginService); - } - }); - // This makes register category work for the "test" category. - // Undone via @After - setupTrustedCategory(categoryName); - registerCategory(testuser, password); - - @SuppressWarnings("unchecked") - Update mockUpdate = mock(Update.class); - when(mockStorage.createUpdate(eq(category))).thenReturn(mockUpdate); - - String endpoint = getEndpoint(); - - URL url = new URL(endpoint + "/update-pojo"); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setRequestMethod("POST"); - sendAuthentication(conn, testuser, password); - conn.setDoOutput(true); - conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - - WebUpdate update = new WebUpdate<>(); - update.setCategoryId(categoryId); - Expression expr = factory.equalTo(key1, "test"); - update.where(expr); - update.set(key1, "fluff"); - update.set(key2, 42); - - Gson gson = new GsonBuilder() - .registerTypeHierarchyAdapter(Expression.class, - new ExpressionSerializer()) - .registerTypeHierarchyAdapter(Operator.class, - new OperatorSerializer()).create(); - 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(category); - verify(mockUpdate).where(eq(expr)); - verify(mockUpdate).set(key1, "fluff"); - verify(mockUpdate).set(key2, 42); - verify(mockUpdate).apply(); - verifyNoMoreInteractions(mockUpdate); - } - - @Test - public void unauthorizedUpdatePojo() throws Exception { - String failMsg = "thermostat-update role missing, expected Forbidden!"; - doUnauthorizedTest("update-pojo", failMsg); - } - - @Test public void authorizedSaveFile() throws Exception { String filename = "fluff"; String[] roleNames = new String[] {