changeset 1183:9ec44cd38946

Implement mechanism so as to allow only trusted stmt descriptors. Reviewed-by: ebaron Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-July/007598.html
author Severin Gehwolf <sgehwolf@redhat.com>
date Mon, 22 Jul 2013 20:01:46 +0200
parents cb2842943f60
children d448210350bf
files host-cpu/common/src/main/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOImplStatementDescriptorRegistration.java host-cpu/common/src/main/resources/META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration host-cpu/common/src/test/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOImplStatementDescriptorRegistrationTest.java host-memory/common/src/main/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOImplStatementDescriptorRegistration.java host-memory/common/src/main/resources/META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration host-memory/common/src/test/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOImplStatementDescriptorRegistrationTest.java integration-tests/src/test/java/com/redhat/thermostat/itest/WebAppTest.java integration-tests/src/test/java/com/redhat/thermostat/itest/WebAppTestStatementDescriptorRegistration.java integration-tests/src/test/resources/META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration numa/common/src/main/java/com/redhat/thermostat/numa/common/internal/NumaDAOImplStatementDescriptorRegistration.java numa/common/src/main/resources/META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration numa/common/src/test/java/com/redhat/thermostat/numa/common/internal/NumaDAOImplStatementDescriptorRegistrationTest.java storage/core/pom.xml storage/core/src/main/java/com/redhat/thermostat/storage/core/HostLatestPojoListGetter.java storage/core/src/main/java/com/redhat/thermostat/storage/core/Storage.java storage/core/src/main/java/com/redhat/thermostat/storage/core/VmLatestPojoListGetter.java storage/core/src/main/java/com/redhat/thermostat/storage/core/auth/StatementDescriptorRegistration.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/DAOImplStatementDescriptorRegistration.java storage/core/src/main/resources/META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration storage/core/src/test/java/com/redhat/thermostat/storage/core/HostLatestPojoListGetterTest.java storage/core/src/test/java/com/redhat/thermostat/storage/core/VmLatestPojoListGetterTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/DAOImplStatementDescriptorRegistrationTest.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplStatementDescriptorRegistration.java thread/collector/src/main/resources/META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDAOImplStatementDescriptorRegistrationTest.java vm-classstat/common/src/main/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOImplStatementDescriptorRegistration.java vm-classstat/common/src/main/resources/META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration vm-classstat/common/src/test/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOImplStatementDescriptorRegistrationTest.java vm-cpu/common/src/main/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOImplStatementDescriptorRegistration.java vm-cpu/common/src/main/resources/META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration vm-cpu/common/src/test/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOImplStatementDescriptorRegistrationTest.java vm-gc/common/src/main/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOImplStatementDescriptorRegistration.java vm-gc/common/src/main/resources/META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration vm-gc/common/src/test/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOImplStatementDescriptorRegistrationTest.java vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOImplStatementDescriptorRegistration.java vm-heap-analysis/common/src/main/resources/META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration vm-heap-analysis/common/src/test/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOImplStatementDescriptorRegistrationTest.java vm-jmx/common/src/main/java/com/redhat/thermostat/vm/jmx/common/internal/JmxNotificationDAOImplStatementDescriptorRegistration.java vm-jmx/common/src/main/resources/META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration vm-jmx/common/src/test/java/com/redhat/thermostat/vm/jmx/common/internal/JmxNotificationDAOImplStatementDescriptorRegistrationTest.java vm-memory/common/src/main/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOImplStatementDescriptorRegistration.java vm-memory/common/src/main/resources/META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration vm-memory/common/src/test/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOImplStatementDescriptorRegistrationTest.java web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebStorage.java web/common/src/main/java/com/redhat/thermostat/web/common/WebPreparedStatementResponse.java web/server/src/main/java/com/redhat/thermostat/web/server/KnownDescriptorRegistry.java web/server/src/main/java/com/redhat/thermostat/web/server/KnownDescriptorRegistryFactory.java web/server/src/main/java/com/redhat/thermostat/web/server/WebStorageEndPoint.java web/server/src/test/java/com/redhat/thermostat/web/server/KnownDescriptorRegistryTest.java web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndpointTest.java
diffstat 50 files changed, 2287 insertions(+), 30 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/host-cpu/common/src/main/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOImplStatementDescriptorRegistration.java	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,64 @@
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.host.cpu.common.internal;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import com.redhat.thermostat.host.cpu.common.CpuStatDAO;
+import com.redhat.thermostat.storage.core.HostLatestPojoListGetter;
+import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration;
+
+/**
+ * Registers the prepared query issued by this maven module via
+ * {@link HostLatestPojoListGetter}.
+ *
+ */
+public class CpuStatDAOImplStatementDescriptorRegistration implements
+        StatementDescriptorRegistration {
+
+    @Override
+    public Set<String> getStatementDescriptors() {
+        Set<String> descs = new HashSet<>();
+        String descriptor = String.format(
+                HostLatestPojoListGetter.HOST_LATEST_QUERY_FORMAT,
+                CpuStatDAO.cpuStatCategory.getName());
+        descs.add(descriptor);
+        return descs;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/host-cpu/common/src/main/resources/META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,1 @@
+com.redhat.thermostat.host.cpu.common.internal.CpuStatDAOImplStatementDescriptorRegistration
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/host-cpu/common/src/test/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOImplStatementDescriptorRegistrationTest.java	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,91 @@
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.host.cpu.common.internal;
+
+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 java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ServiceLoader;
+import java.util.Set;
+
+import org.junit.Test;
+
+import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration;
+import com.redhat.thermostat.storage.internal.dao.DAOImplStatementDescriptorRegistration;
+
+public class CpuStatDAOImplStatementDescriptorRegistrationTest {
+
+    @Test
+    public void registersAllQueries() {
+        CpuStatDAOImplStatementDescriptorRegistration reg = new CpuStatDAOImplStatementDescriptorRegistration();
+        Set<String> descriptors = reg.getStatementDescriptors();
+        assertEquals(1, descriptors.size());
+        assertFalse("null descriptor not allowed", descriptors.contains(null));
+    }
+    
+    /*
+     * The web storage end-point uses service loader in order to determine the
+     * list of trusted/known registrations. This test is to ensure service loading
+     * works for this module's regs. E.g. renaming of the impl class without
+     * changing META-INF/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration
+     */
+    @Test
+    public void serviceLoaderCanLoadRegistration() {
+        Set<String> expectedClassNames = new HashSet<>();
+        expectedClassNames.add(DAOImplStatementDescriptorRegistration.class.getName());
+        expectedClassNames.add(CpuStatDAOImplStatementDescriptorRegistration.class.getName());
+        ServiceLoader<StatementDescriptorRegistration> loader = ServiceLoader.load(StatementDescriptorRegistration.class, CpuStatDAOImplStatementDescriptorRegistration.class.getClassLoader());
+        List<StatementDescriptorRegistration> registrations = new ArrayList<>(1);
+        StatementDescriptorRegistration cpuStatReg = null;
+        for (StatementDescriptorRegistration r: loader) {
+            assertTrue(expectedClassNames.contains(r.getClass().getName()));
+            if (r.getClass().getName().equals(CpuStatDAOImplStatementDescriptorRegistration.class.getName())) {
+                cpuStatReg = r;
+            }
+            registrations.add(r);
+        }
+        // storage-core + this module
+        assertEquals(2, registrations.size());
+        assertNotNull(cpuStatReg);
+        assertEquals(1, cpuStatReg.getStatementDescriptors().size());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/host-memory/common/src/main/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOImplStatementDescriptorRegistration.java	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,63 @@
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.host.memory.common.internal;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import com.redhat.thermostat.host.memory.common.MemoryStatDAO;
+import com.redhat.thermostat.storage.core.HostLatestPojoListGetter;
+import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration;
+
+/**
+ * Registers the prepared query issued by this maven module via
+ * {@link HostLatestPojoListGetter}.
+ *
+ */
+public class MemoryStatDAOImplStatementDescriptorRegistration implements
+        StatementDescriptorRegistration {
+
+    @Override
+    public Set<String> getStatementDescriptors() {
+        Set<String> descs = new HashSet<>(1);
+        String descriptor = String.format(HostLatestPojoListGetter.HOST_LATEST_QUERY_FORMAT, 
+                MemoryStatDAO.memoryStatCategory.getName());
+        descs.add(descriptor);
+        return descs;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/host-memory/common/src/main/resources/META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,1 @@
+com.redhat.thermostat.host.memory.common.internal.MemoryStatDAOImplStatementDescriptorRegistration
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/host-memory/common/src/test/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOImplStatementDescriptorRegistrationTest.java	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,91 @@
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.host.memory.common.internal;
+
+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 java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ServiceLoader;
+import java.util.Set;
+
+import org.junit.Test;
+
+import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration;
+import com.redhat.thermostat.storage.internal.dao.DAOImplStatementDescriptorRegistration;
+
+public class MemoryStatDAOImplStatementDescriptorRegistrationTest {
+
+    @Test
+    public void registersAllQueries() {
+        MemoryStatDAOImplStatementDescriptorRegistration reg = new MemoryStatDAOImplStatementDescriptorRegistration();
+        Set<String> descriptors = reg.getStatementDescriptors();
+        assertEquals(1, descriptors.size());
+        assertFalse("null descriptor not allowed", descriptors.contains(null));
+    }
+    
+    /*
+     * The web storage end-point uses service loader in order to determine the
+     * list of trusted/known registrations. This test is to ensure service loading
+     * works for this module's regs. E.g. renaming of the impl class without
+     * changing META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration
+     */
+    @Test
+    public void serviceLoaderCanLoadRegistration() {
+        Set<String> expectedClassNames = new HashSet<>();
+        expectedClassNames.add(DAOImplStatementDescriptorRegistration.class.getName());
+        expectedClassNames.add(MemoryStatDAOImplStatementDescriptorRegistration.class.getName());
+        ServiceLoader<StatementDescriptorRegistration> loader = ServiceLoader.load(StatementDescriptorRegistration.class, MemoryStatDAOImplStatementDescriptorRegistration.class.getClassLoader());
+        List<StatementDescriptorRegistration> registrations = new ArrayList<>(1);
+        StatementDescriptorRegistration memoryStatReg = null;
+        for (StatementDescriptorRegistration r: loader) {
+            assertTrue(expectedClassNames.contains(r.getClass().getName()));
+            if (r.getClass().getName().equals(MemoryStatDAOImplStatementDescriptorRegistration.class.getName())) {
+                memoryStatReg = r;
+            }
+            registrations.add(r);
+        }
+        // storage-core + this module
+        assertEquals(2, registrations.size());
+        assertNotNull(memoryStatReg);
+        assertEquals(1, memoryStatReg.getStatementDescriptors().size());
+    }
+}
--- a/integration-tests/src/test/java/com/redhat/thermostat/itest/WebAppTest.java	Wed Jul 24 13:56:13 2013 -0400
+++ b/integration-tests/src/test/java/com/redhat/thermostat/itest/WebAppTest.java	Mon Jul 22 20:01:46 2013 +0200
@@ -40,6 +40,7 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import java.io.ByteArrayInputStream;
 import java.io.File;
@@ -50,8 +51,12 @@
 import java.nio.file.Path;
 import java.nio.file.StandardCopyOption;
 import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Properties;
+import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -73,6 +78,8 @@
 import com.redhat.thermostat.storage.core.Connection.ConnectionListener;
 import com.redhat.thermostat.storage.core.Connection.ConnectionStatus;
 import com.redhat.thermostat.storage.core.Cursor;
+import com.redhat.thermostat.storage.core.DescriptorParsingException;
+import com.redhat.thermostat.storage.core.IllegalDescriptorException;
 import com.redhat.thermostat.storage.core.PreparedStatement;
 import com.redhat.thermostat.storage.core.StatementDescriptor;
 import com.redhat.thermostat.storage.core.StatementExecutionException;
@@ -106,6 +113,49 @@
  */
 public class WebAppTest extends IntegrationTest {
 
+    /*
+     * Registry of descriptors this test needs to allow in order to avoid
+     * illegal statement descriptor exceptions being thrown. See also:
+     * WebAppTestStatementDescriptorRegistration
+     */
+    public static final Set<String> TRUSTED_DESCRIPTORS;
+    // descriptive name -> descriptor mapping
+    private static final Map<String, String> DESCRIPTOR_MAP;
+    
+    private static final String KEY_AUTHORIZED_QUERY = "authorizedQuery";
+    private static final String KEY_AUTHORIZED_QUERY_EQUAL_TO = "authorizedQueryEqualTo";
+    private static final String KEY_AUTHORIZED_QUERY_NOT_EQUAL_TO = "authorizedQueryNotEqualTo";
+    private static final String KEY_AUTHORIZED_QUERY_GREATER_THAN = "authorizedQueryGreaterThan";
+    private static final String KEY_AUTHORIZED_QUERY_GREATER_THAN_OR_EQUAL_TO = "authorizedQueryGreaterThanOrEqualTo";
+    private static final String KEY_AUTHORIZED_QUERY_LESS_THAN = "authorizedQueryLessThan";
+    private static final String KEY_AUTHORIZED_QUERY_LESS_THAN_OR_EQUAL_TO = "authorizedQueryLessThanOrEqualTo";
+    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";
+    
+    static {
+        Map<String, String> descMap = new HashMap<>();
+        descMap.put(KEY_AUTHORIZED_QUERY, "QUERY cpu-stats SORT ?s ASC");
+        descMap.put(KEY_AUTHORIZED_QUERY_EQUAL_TO, "QUERY cpu-stats WHERE 'timeStamp' = ?l SORT 'timeStamp' ASC");
+        descMap.put(KEY_AUTHORIZED_QUERY_NOT_EQUAL_TO, "QUERY cpu-stats WHERE 'timeStamp' != ?l SORT 'timeStamp' ASC");
+        descMap.put(KEY_AUTHORIZED_QUERY_GREATER_THAN, "QUERY cpu-stats WHERE 'timeStamp' > ?l SORT 'timeStamp' ASC");
+        descMap.put(KEY_AUTHORIZED_QUERY_GREATER_THAN_OR_EQUAL_TO, "QUERY cpu-stats WHERE 'timeStamp' >= ?l SORT 'timeStamp' ASC");
+        descMap.put(KEY_AUTHORIZED_QUERY_LESS_THAN, "QUERY cpu-stats WHERE 'timeStamp' < ?l SORT 'timeStamp' ASC");
+        descMap.put(KEY_AUTHORIZED_QUERY_LESS_THAN_OR_EQUAL_TO, "QUERY cpu-stats WHERE 'timeStamp' <= ?l SORT 'timeStamp' ASC");
+        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");
+        Set<String> trustedDescriptors = new HashSet<>();
+        for (String val: descMap.values()) {
+            trustedDescriptors.add(val);
+        }
+        TRUSTED_DESCRIPTORS = trustedDescriptors;
+        DESCRIPTOR_MAP = descMap;
+    }
+    
+    
     private static class CountdownConnectionListener implements ConnectionListener {
 
         private final ConnectionStatus target;
@@ -287,6 +337,14 @@
         String version = appInfo.getMavenVersion();
         String warfile = "target/libs/thermostat-web-war-" + version + ".war";
         WebAppContext ctx = new WebAppContext(warfile, "/thermostat");
+        
+        // We need to set this to true in order for WebStorageEndPoint to pick
+        // up the descriptor registrations from WebAppTestStatementDescriptorRegistration
+        // which would result in 
+        // "java.util.ServiceConfigurationError: com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration: Provider com.redhat.thermostat.itest.WebAppTestStatementDescriptorRegistration not a subtype"
+        // errors.
+        ctx.setParentLoaderPriority(true);
+        
         WebAppContextListener listener = new WebAppContextListener(contextStartedLatch);
         ctx.addLifeCycleListener(listener);
         /* The web archive has a jetty-web.xml config file which sets up the
@@ -404,7 +462,7 @@
 
         webStorage.getConnection().disconnect();
     }
-
+    
     @Test
     public void authorizedQuery() throws Exception {
 
@@ -418,7 +476,7 @@
         Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames);
         webStorage.registerCategory(CpuStatDAO.cpuStatCategory);
         
-        String strDesc = "QUERY cpu-stats SORT ?s ASC";
+        String strDesc = DESCRIPTOR_MAP.get(KEY_AUTHORIZED_QUERY);
         StatementDescriptor<CpuStat> queryDesc = new StatementDescriptor<>(CpuStatDAO.cpuStatCategory, strDesc);
         PreparedStatement<CpuStat> query = webStorage.prepareStatement(queryDesc);
 
@@ -442,7 +500,7 @@
         Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames);
         webStorage.registerCategory(CpuStatDAO.cpuStatCategory);
 
-        String strDesc = "QUERY cpu-stats WHERE 'timeStamp' = ?l SORT 'timeStamp' ASC";
+        String strDesc = DESCRIPTOR_MAP.get(KEY_AUTHORIZED_QUERY_EQUAL_TO);
         StatementDescriptor<CpuStat> queryDesc = new StatementDescriptor<>(CpuStatDAO.cpuStatCategory, strDesc);
         PreparedStatement<CpuStat> query = webStorage.prepareStatement(queryDesc);
         query.setLong(0, 2l);
@@ -465,7 +523,7 @@
         Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames);
         webStorage.registerCategory(CpuStatDAO.cpuStatCategory);
 
-        String strDesc = "QUERY cpu-stats WHERE 'timeStamp' != ?l SORT 'timeStamp' ASC";
+        String strDesc = DESCRIPTOR_MAP.get(KEY_AUTHORIZED_QUERY_NOT_EQUAL_TO);
         StatementDescriptor<CpuStat> queryDesc = new StatementDescriptor<>(CpuStatDAO.cpuStatCategory, strDesc);
         PreparedStatement<CpuStat> query = webStorage.prepareStatement(queryDesc);
         query.setLong(0, 2l);
@@ -488,7 +546,7 @@
         Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames);
         webStorage.registerCategory(CpuStatDAO.cpuStatCategory);
 
-        String strDesc = "QUERY cpu-stats WHERE 'timeStamp' > ?l SORT 'timeStamp' ASC";
+        String strDesc = DESCRIPTOR_MAP.get(KEY_AUTHORIZED_QUERY_GREATER_THAN);
         StatementDescriptor<CpuStat> queryDesc = new StatementDescriptor<>(CpuStatDAO.cpuStatCategory, strDesc);
         PreparedStatement<CpuStat> query = webStorage.prepareStatement(queryDesc);
         query.setLong(0, 2l);
@@ -511,7 +569,7 @@
         Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames);
         webStorage.registerCategory(CpuStatDAO.cpuStatCategory);
 
-        String strDesc = "QUERY cpu-stats WHERE 'timeStamp' >= ?l SORT 'timeStamp' ASC";
+        String strDesc = DESCRIPTOR_MAP.get(KEY_AUTHORIZED_QUERY_GREATER_THAN_OR_EQUAL_TO);
         StatementDescriptor<CpuStat> queryDesc = new StatementDescriptor<>(CpuStatDAO.cpuStatCategory, strDesc);
         PreparedStatement<CpuStat> query = webStorage.prepareStatement(queryDesc);
         query.setLong(0, 2l);
@@ -534,7 +592,7 @@
         Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames);
         webStorage.registerCategory(CpuStatDAO.cpuStatCategory);
 
-        String strDesc = "QUERY cpu-stats WHERE 'timeStamp' < ?l SORT 'timeStamp' ASC";
+        String strDesc = DESCRIPTOR_MAP.get(KEY_AUTHORIZED_QUERY_LESS_THAN);
         StatementDescriptor<CpuStat> queryDesc = new StatementDescriptor<>(CpuStatDAO.cpuStatCategory, strDesc);
         PreparedStatement<CpuStat> query = webStorage.prepareStatement(queryDesc);
         query.setLong(0, 2l);
@@ -557,7 +615,7 @@
         Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames);
         webStorage.registerCategory(CpuStatDAO.cpuStatCategory);
 
-        String strDesc = "QUERY cpu-stats WHERE 'timeStamp' <= ?l SORT 'timeStamp' ASC";
+        String strDesc = DESCRIPTOR_MAP.get(KEY_AUTHORIZED_QUERY_LESS_THAN_OR_EQUAL_TO);
         StatementDescriptor<CpuStat> queryDesc = new StatementDescriptor<>(CpuStatDAO.cpuStatCategory, strDesc);
         PreparedStatement<CpuStat> query = webStorage.prepareStatement(queryDesc);
         query.setLong(0, 2l);
@@ -580,7 +638,7 @@
         Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames);
         webStorage.registerCategory(CpuStatDAO.cpuStatCategory);
 
-        String strDesc = "QUERY cpu-stats WHERE NOT 'timeStamp' > ?l SORT 'timeStamp' ASC";
+        String strDesc = DESCRIPTOR_MAP.get(KEY_AUTHORIZED_QUERY_NOT);
         StatementDescriptor<CpuStat> queryDesc = new StatementDescriptor<>(CpuStatDAO.cpuStatCategory, strDesc);
         PreparedStatement<CpuStat> query = webStorage.prepareStatement(queryDesc);
         query.setLong(0, 2l);
@@ -603,7 +661,7 @@
         Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames);
         webStorage.registerCategory(CpuStatDAO.cpuStatCategory);
 
-        String strDesc = "QUERY cpu-stats WHERE 'timeStamp' > 0 AND 'timeStamp' < ?l SORT 'timeStamp' ASC";
+        String strDesc = DESCRIPTOR_MAP.get(KEY_AUTHORIZED_QUERY_AND);
         StatementDescriptor<CpuStat> queryDesc = new StatementDescriptor<>(CpuStatDAO.cpuStatCategory, strDesc);
         PreparedStatement<CpuStat> query = webStorage.prepareStatement(queryDesc);
         query.setLong(0, 2l);
@@ -626,7 +684,7 @@
         Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames);
         webStorage.registerCategory(CpuStatDAO.cpuStatCategory);
 
-        String strDesc = "QUERY cpu-stats WHERE 'timeStamp' > ?l OR 'timeStamp' < ?l SORT 'timeStamp' ASC";
+        String strDesc = DESCRIPTOR_MAP.get(KEY_AUTHORIZED_QUERY_OR);
         StatementDescriptor<CpuStat> queryDesc = new StatementDescriptor<>(CpuStatDAO.cpuStatCategory, strDesc);
         PreparedStatement<CpuStat> query = webStorage.prepareStatement(queryDesc);
         query.setLong(0, 2);
@@ -636,6 +694,37 @@
 
         webStorage.getConnection().disconnect();
     }
+    
+    @Test
+    public void refuseUnknownQueryDescriptor() throws IOException {
+
+        String[] roleNames = new String[] {
+                Roles.REGISTER_CATEGORY,
+                Roles.READ,
+                Roles.LOGIN,
+                Roles.ACCESS_REALM,
+                Roles.PREPARE_STATEMENT
+        };
+        Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames);
+        webStorage.registerCategory(CpuStatDAO.cpuStatCategory);
+
+        String strDesc = "QUERY cpu-stats WHERE 'fooBarTest' = ?s";
+        assertFalse("wanted this descriptor to be untrusted!", TRUSTED_DESCRIPTORS.contains(strDesc));
+        StatementDescriptor<CpuStat> queryDesc = new StatementDescriptor<>(CpuStatDAO.cpuStatCategory, strDesc);
+        
+        try {
+            webStorage.prepareStatement(queryDesc);
+        } catch (IllegalDescriptorException e) {
+            // pass
+            String expectedMsg = "Unknown query descriptor which endpoint of com.redhat.thermostat.web.client.internal.WebStorage refused to accept!";
+            assertEquals(expectedMsg, e.getMessage());
+        } catch (DescriptorParsingException e) {
+            // should have been able to parse the descriptor
+            fail(e.getMessage());
+        }
+        
+        webStorage.getConnection().disconnect();
+    }
 
     @Test
     public void authorizedLoadSave() throws Exception {
@@ -712,7 +801,7 @@
         add.setPojo(pojo);
         add.apply();
 
-        String strDesc = "QUERY vm-cpu-stats";
+        String strDesc = DESCRIPTOR_MAP.get(KEY_SET_DEFAULT_AGENT_ID);
         StatementDescriptor<VmCpuStat> queryDesc = new StatementDescriptor<>(VmCpuStatDAO.vmCpuStatCategory, strDesc);
         PreparedStatement<VmCpuStat> query = storage.prepareStatement(queryDesc);
         Cursor<VmCpuStat> cursor = query.executeQuery();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/integration-tests/src/test/java/com/redhat/thermostat/itest/WebAppTestStatementDescriptorRegistration.java	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,51 @@
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.itest;
+
+import java.util.Set;
+
+import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration;
+
+public class WebAppTestStatementDescriptorRegistration implements
+        StatementDescriptorRegistration {
+
+    @Override
+    public Set<String> getStatementDescriptors() {
+        return WebAppTest.TRUSTED_DESCRIPTORS;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/integration-tests/src/test/resources/META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,1 @@
+com.redhat.thermostat.itest.WebAppTestStatementDescriptorRegistration
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/numa/common/src/main/java/com/redhat/thermostat/numa/common/internal/NumaDAOImplStatementDescriptorRegistration.java	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,65 @@
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.numa.common.internal;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import com.redhat.thermostat.numa.common.NumaDAO;
+import com.redhat.thermostat.storage.core.HostLatestPojoListGetter;
+import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration;
+
+/**
+ * Registers prepared queries issued by this maven module via
+ * {@link HostLatestPojoListGetter} and via {@link NumaDAOImpl}.
+ *
+ */
+public class NumaDAOImplStatementDescriptorRegistration implements
+        StatementDescriptorRegistration {
+
+    @Override
+    public Set<String> getStatementDescriptors() {
+        Set<String> descs = new HashSet<>(2);
+        String descriptor = String.format(
+                HostLatestPojoListGetter.HOST_LATEST_QUERY_FORMAT,
+                NumaDAO.numaStatCategory.getName());
+        descs.add(descriptor);
+        descs.add(NumaDAOImpl.QUERY_NUMA_INFO);
+        return descs;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/numa/common/src/main/resources/META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,1 @@
+com.redhat.thermostat.numa.common.internal.NumaDAOImplStatementDescriptorRegistration
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/numa/common/src/test/java/com/redhat/thermostat/numa/common/internal/NumaDAOImplStatementDescriptorRegistrationTest.java	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,91 @@
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.numa.common.internal;
+
+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 java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ServiceLoader;
+import java.util.Set;
+
+import org.junit.Test;
+
+import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration;
+import com.redhat.thermostat.storage.internal.dao.DAOImplStatementDescriptorRegistration;
+
+public class NumaDAOImplStatementDescriptorRegistrationTest {
+
+    @Test
+    public void registersAllQueries() {
+        NumaDAOImplStatementDescriptorRegistration reg = new NumaDAOImplStatementDescriptorRegistration();
+        Set<String> descriptors = reg.getStatementDescriptors();
+        assertEquals(2, descriptors.size());
+        assertFalse("null descriptor not allowed", descriptors.contains(null));
+    }
+    
+    /*
+     * The web storage end-point uses service loader in order to determine the
+     * list of trusted/known registrations. This test is to ensure service loading
+     * works for this module's regs. E.g. renaming of the impl class without
+     * changing META-INF/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration
+     */
+    @Test
+    public void serviceLoaderCanLoadRegistration() {
+        Set<String> expectedClassNames = new HashSet<>();
+        expectedClassNames.add(DAOImplStatementDescriptorRegistration.class.getName());
+        expectedClassNames.add(NumaDAOImplStatementDescriptorRegistration.class.getName());
+        ServiceLoader<StatementDescriptorRegistration> loader = ServiceLoader.load(StatementDescriptorRegistration.class, NumaDAOImplStatementDescriptorRegistration.class.getClassLoader());
+        List<StatementDescriptorRegistration> registrations = new ArrayList<>(1);
+        StatementDescriptorRegistration numaReg = null;
+        for (StatementDescriptorRegistration r: loader) {
+            assertTrue(expectedClassNames.contains(r.getClass().getName()));
+            if (r.getClass().getName().equals(NumaDAOImplStatementDescriptorRegistration.class.getName())) {
+                numaReg = r;
+            }
+            registrations.add(r);
+        }
+        // storage-core + this module
+        assertEquals(2, registrations.size());
+        assertNotNull(numaReg);
+        assertEquals(2, numaReg.getStatementDescriptors().size());
+    }
+}
--- a/storage/core/pom.xml	Wed Jul 24 13:56:13 2013 -0400
+++ b/storage/core/pom.xml	Mon Jul 22 20:01:46 2013 +0200
@@ -64,6 +64,7 @@
             <Bundle-Activator>com.redhat.thermostat.storage.internal.Activator</Bundle-Activator>
             <Export-Package>
               com.redhat.thermostat.storage.core,
+              com.redhat.thermostat.storage.core.auth,
               com.redhat.thermostat.storage.config,
               com.redhat.thermostat.storage.model,
               com.redhat.thermostat.storage.dao,
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/HostLatestPojoListGetter.java	Wed Jul 24 13:56:13 2013 -0400
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/HostLatestPojoListGetter.java	Mon Jul 22 20:01:46 2013 +0200
@@ -47,6 +47,10 @@
 
 public class HostLatestPojoListGetter<T extends TimeStampedPojo> {
 
+    public static final String HOST_LATEST_QUERY_FORMAT = "QUERY %s WHERE '"
+            + Key.AGENT_ID.getName() + "' = ?s AND '"
+            + Key.TIMESTAMP.getName() + "' > ?l SORT '"
+            + Key.TIMESTAMP.getName() + "' DSC";
     private static final Logger logger = LoggingUtils.getLogger(HostLatestPojoListGetter.class);
     
     private final Storage storage;
@@ -56,10 +60,7 @@
     public HostLatestPojoListGetter(Storage storage, Category<T> cat) {
         this.storage = storage;
         this.cat = cat;
-        this.queryLatest = "QUERY " + cat.getName() + " WHERE '"
-                + Key.AGENT_ID.getName() + "' = ?s AND '"
-                + Key.TIMESTAMP.getName() + "' > ?l SORT '"
-                + Key.TIMESTAMP.getName() + "' DSC";
+        this.queryLatest = String.format(HOST_LATEST_QUERY_FORMAT, cat.getName());
     }
 
     public List<T> getLatest(HostRef hostRef, long since) {
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/Storage.java	Wed Jul 24 13:56:13 2013 -0400
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/Storage.java	Mon Jul 22 20:01:46 2013 +0200
@@ -59,10 +59,15 @@
     /**
      * Prepares the given statement for execution.
      * 
-     * @param desc The statement descriptor to prepare.
-     * @return A {@link PreparedStatement} if the given statement was
-     *         something Storage knows about, {@code null} otherwise.
-     * @throws DescriptorParsingException If the descriptor string was invalid.
+     * @param desc
+     *            The statement descriptor to prepare.
+     * @return A {@link PreparedStatement} if the given statement descriptor was
+     *         known and did not fail to parse.
+     * @throws DescriptorParsingException
+     *             If the descriptor string failed to parse.
+     * @throws IllegalDescriptorException
+     *             If storage refused to prepare a statement descriptor for
+     *             security reasons.
      */
     <T extends Pojo> PreparedStatement<T> prepareStatement(StatementDescriptor<T> desc)
             throws DescriptorParsingException;
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/VmLatestPojoListGetter.java	Wed Jul 24 13:56:13 2013 -0400
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/VmLatestPojoListGetter.java	Mon Jul 22 20:01:46 2013 +0200
@@ -47,8 +47,13 @@
 
 public class VmLatestPojoListGetter<T extends TimeStampedPojo> {
     
+    public static final String VM_LATEST_QUERY_FORMAT = "QUERY %s WHERE '"
+            + Key.AGENT_ID.getName() + "' = ?s AND '"
+            + Key.VM_ID.getName() + "' = ?s AND '" 
+            + Key.TIMESTAMP.getName() + "' > ?l SORT '"
+            + Key.TIMESTAMP.getName() + "' DSC";
     private static final Logger logger = LoggingUtils.getLogger(VmLatestPojoListGetter.class);
-
+    
     private final Storage storage;
     private final Category<T> cat;
     private final String queryLatest;
@@ -56,11 +61,7 @@
     public VmLatestPojoListGetter(Storage storage, Category<T> cat) {
         this.storage = storage;
         this.cat = cat;
-        this.queryLatest = "QUERY " + cat.getName() + " WHERE '"
-                + Key.AGENT_ID.getName() + "' = ?s AND '"
-                + Key.VM_ID.getName() + "' = ?s AND '" 
-                + Key.TIMESTAMP.getName() + "' > ?l SORT '"
-                + Key.TIMESTAMP.getName() + "' DSC";
+        this.queryLatest = String.format(VM_LATEST_QUERY_FORMAT, cat.getName());
     }
 
     public List<T> getLatest(VmRef vmRef, long since) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/auth/StatementDescriptorRegistration.java	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,58 @@
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.storage.core.auth;
+
+import java.util.ServiceLoader;
+import java.util.Set;
+
+
+/**
+ * {@link ServiceLoader} interface used for registering
+ * trusted statement descriptors. The web storage endpoint
+ * uses implementations of this interface in order to collect
+ * the set of all trusted statement descriptors.
+ *
+ */
+public interface StatementDescriptorRegistration {
+
+    /**
+     * 
+     * @return A set of string descriptors which should get
+     *         added to the trusted registry.
+     */
+    Set<String> getStatementDescriptors();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/DAOImplStatementDescriptorRegistration.java	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,67 @@
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.storage.internal.dao;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration;
+
+/**
+ * Registers prepared queries issued by this maven module
+ * via various DAOs.
+ *
+ */
+public class DAOImplStatementDescriptorRegistration implements
+        StatementDescriptorRegistration {
+
+    @Override
+    public Set<String> getStatementDescriptors() {
+        Set<String> daoDescs = new HashSet<>();
+        daoDescs.add(AgentInfoDAOImpl.QUERY_AGENT_INFO);
+        daoDescs.add(AgentInfoDAOImpl.QUERY_ALIVE_AGENTS);
+        daoDescs.add(AgentInfoDAOImpl.QUERY_ALL_AGENTS);
+        daoDescs.add(BackendInfoDAOImpl.QUERY_BACKEND_INFO);
+        daoDescs.add(HostInfoDAOImpl.QUERY_HOST_INFO);
+        daoDescs.add(HostInfoDAOImpl.QUERY_ALL_HOSTS);
+        daoDescs.add(NetworkInterfaceInfoDAOImpl.QUERY_NETWORK_INFO);
+        daoDescs.add(VmInfoDAOImpl.QUERY_ALL_VMS);
+        daoDescs.add(VmInfoDAOImpl.QUERY_VM_INFO);
+        return daoDescs;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/storage/core/src/main/resources/META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,1 @@
+com.redhat.thermostat.storage.internal.dao.DAOImplStatementDescriptorRegistration
\ No newline at end of file
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/core/HostLatestPojoListGetterTest.java	Wed Jul 24 13:56:13 2013 -0400
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/core/HostLatestPojoListGetterTest.java	Mon Jul 22 20:01:46 2013 +0200
@@ -99,6 +99,13 @@
     }
     
     @Test
+    public void verifyQueryDescriptorFormat() {
+        String expected = "QUERY %s WHERE 'agentId' = ?s AND " +
+         "'timeStamp' > ?l SORT 'timeStamp' DSC";
+        assertEquals(expected, HostLatestPojoListGetter.HOST_LATEST_QUERY_FORMAT);
+    }
+    
+    @Test
     public void verifyQueryDescriptorIsSane() {
         Storage storage = mock(Storage.class);
         HostLatestPojoListGetter<TestPojo> getter = new HostLatestPojoListGetter<>(storage, cat);
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/core/VmLatestPojoListGetterTest.java	Wed Jul 24 13:56:13 2013 -0400
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/core/VmLatestPojoListGetterTest.java	Mon Jul 22 20:01:46 2013 +0200
@@ -91,6 +91,13 @@
     }
     
     @Test
+    public void verifyQueryDescriptorFormat() {
+        String expected = "QUERY %s WHERE 'agentId' = ?s AND " +
+         "'vmId' = ?s AND 'timeStamp' > ?l SORT 'timeStamp' DSC";
+        assertEquals(expected, VmLatestPojoListGetter.VM_LATEST_QUERY_FORMAT);
+    }
+    
+    @Test
     public void verifyQueryDescriptorIsSane() {
         Storage storage = mock(Storage.class);
         VmLatestPojoListGetter<TestPojo> getter = new VmLatestPojoListGetter<>(storage, cat);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/DAOImplStatementDescriptorRegistrationTest.java	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,77 @@
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.storage.internal.dao;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ServiceLoader;
+import java.util.Set;
+
+import org.junit.Test;
+
+import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration;
+
+public class DAOImplStatementDescriptorRegistrationTest {
+
+    @Test
+    public void registersAllQueries() {
+        DAOImplStatementDescriptorRegistration reg = new DAOImplStatementDescriptorRegistration();
+        Set<String> descriptors = reg.getStatementDescriptors();
+        assertEquals(9, descriptors.size());
+        assertFalse(descriptors.contains(null));
+    }
+    
+    /*
+     * The web storage end-point uses service loader in order to determine the
+     * list of trusted/known registrations. This test is to ensure service loading
+     * works for this module's regs. E.g. renaming of the impl class without
+     * changing META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration
+     */
+    @Test
+    public void serviceLoaderCanLoadRegistration() {
+        ServiceLoader<StatementDescriptorRegistration> loader = ServiceLoader.load(StatementDescriptorRegistration.class, DAOImplStatementDescriptorRegistration.class.getClassLoader());
+        List<StatementDescriptorRegistration> registrations = new ArrayList<>(1);
+        for (StatementDescriptorRegistration r: loader) {
+            registrations.add(r);
+        }
+        assertEquals(1, registrations.size());
+        assertEquals(9, registrations.get(0).getStatementDescriptors().size());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplStatementDescriptorRegistration.java	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,64 @@
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.thread.dao.impl;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration;
+
+/**
+ * Registers prepared queries issued by this maven module via
+ * via {@link ThreadDaoImpl}.
+ *
+ */
+public class ThreadDaoImplStatementDescriptorRegistration implements
+        StatementDescriptorRegistration {
+
+    @Override
+    public Set<String> getStatementDescriptors() {
+        Set<String> descs = new HashSet<>(6);
+        descs.add(ThreadDaoImpl.QUERY_LATEST_DEADLOCK_INFO);
+        descs.add(ThreadDaoImpl.QUERY_LATEST_HARVESTING_STATUS);
+        descs.add(ThreadDaoImpl.QUERY_LATEST_SUMMARY);
+        descs.add(ThreadDaoImpl.QUERY_SUMMARY_SINCE);
+        descs.add(ThreadDaoImpl.QUERY_THREAD_CAPS);
+        descs.add(ThreadDaoImpl.QUERY_THREAD_INFO);
+        return descs;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/main/resources/META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,1 @@
+com.redhat.thermostat.thread.dao.impl.ThreadDaoImplStatementDescriptorRegistration
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDAOImplStatementDescriptorRegistrationTest.java	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,91 @@
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.thread.dao.impl;
+
+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 java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ServiceLoader;
+import java.util.Set;
+
+import org.junit.Test;
+
+import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration;
+import com.redhat.thermostat.storage.internal.dao.DAOImplStatementDescriptorRegistration;
+
+public class ThreadDAOImplStatementDescriptorRegistrationTest {
+
+    @Test
+    public void registersAllQueries() {
+        ThreadDaoImplStatementDescriptorRegistration reg = new ThreadDaoImplStatementDescriptorRegistration();
+        Set<String> descriptors = reg.getStatementDescriptors();
+        assertEquals(6, descriptors.size());
+        assertFalse("null descriptor not allowed", descriptors.contains(null));
+    }
+    
+    /*
+     * The web storage end-point uses service loader in order to determine the
+     * list of trusted/known registrations. This test is to ensure service loading
+     * works for this module's regs. E.g. renaming of the impl class without
+     * changing META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration
+     */
+    @Test
+    public void serviceLoaderCanLoadRegistration() {
+        Set<String> expectedClassNames = new HashSet<>();
+        expectedClassNames.add(DAOImplStatementDescriptorRegistration.class.getName());
+        expectedClassNames.add(ThreadDaoImplStatementDescriptorRegistration.class.getName());
+        ServiceLoader<StatementDescriptorRegistration> loader = ServiceLoader.load(StatementDescriptorRegistration.class, ThreadDaoImplStatementDescriptorRegistration.class.getClassLoader());
+        List<StatementDescriptorRegistration> registrations = new ArrayList<>(1);
+        StatementDescriptorRegistration threadDaoReg = null;
+        for (StatementDescriptorRegistration r: loader) {
+            assertTrue(expectedClassNames.contains(r.getClass().getName()));
+            if (r.getClass().getName().equals(ThreadDaoImplStatementDescriptorRegistration.class.getName())) {
+                threadDaoReg = r;
+            }
+            registrations.add(r);
+        }
+        // storage-core + this module
+        assertEquals(2, registrations.size());
+        assertNotNull(threadDaoReg);
+        assertEquals(6, threadDaoReg.getStatementDescriptors().size());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-classstat/common/src/main/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOImplStatementDescriptorRegistration.java	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,63 @@
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.vm.classstat.common.internal;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import com.redhat.thermostat.storage.core.VmLatestPojoListGetter;
+import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration;
+import com.redhat.thermostat.vm.classstat.common.VmClassStatDAO;
+
+/**
+ * Registers the prepared query issued by this maven module via
+ * {@link VmLatestPojoListGetter}.
+ *
+ */
+public class VmClassStatDAOImplStatementDescriptorRegistration implements
+        StatementDescriptorRegistration {
+
+    @Override
+    public Set<String> getStatementDescriptors() {
+        Set<String> descs = new HashSet<>();
+        String vmLatestClassStatQuery = String.format(VmLatestPojoListGetter.VM_LATEST_QUERY_FORMAT,
+                VmClassStatDAO.vmClassStatsCategory.getName());
+        descs.add(vmLatestClassStatQuery);
+        return descs;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-classstat/common/src/main/resources/META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,1 @@
+com.redhat.thermostat.vm.classstat.common.internal.VmClassStatDAOImplStatementDescriptorRegistration
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-classstat/common/src/test/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOImplStatementDescriptorRegistrationTest.java	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,92 @@
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.vm.classstat.common.internal;
+
+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 java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ServiceLoader;
+import java.util.Set;
+
+import org.junit.Test;
+
+import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration;
+import com.redhat.thermostat.storage.internal.dao.DAOImplStatementDescriptorRegistration;
+
+public class VmClassStatDAOImplStatementDescriptorRegistrationTest {
+
+    @Test
+    public void registersAllQueries() {
+        VmClassStatDAOImplStatementDescriptorRegistration reg = new VmClassStatDAOImplStatementDescriptorRegistration();
+        Set<String> descriptors = reg.getStatementDescriptors();
+        assertEquals(1, descriptors.size());
+        assertFalse("null descriptor not allowed", descriptors.contains(null));
+    }
+    
+    /*
+     * The web storage end-point uses service loader in order to determine the
+     * list of trusted/known registrations. This test is to ensure service loading
+     * works for this module's regs. E.g. renaming of the impl class without
+     * changing META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration
+     */
+    @Test
+    public void serviceLoaderCanLoadRegistration() {
+        Set<String> expectedClassNames = new HashSet<>();
+        expectedClassNames.add(DAOImplStatementDescriptorRegistration.class.getName());
+        expectedClassNames.add(VmClassStatDAOImplStatementDescriptorRegistration.class.getName());
+        ServiceLoader<StatementDescriptorRegistration> loader = ServiceLoader.load(StatementDescriptorRegistration.class, VmClassStatDAOImplStatementDescriptorRegistration.class.getClassLoader());
+        List<StatementDescriptorRegistration> registrations = new ArrayList<>(1);
+        StatementDescriptorRegistration vmClassStatReg = null;
+        for (StatementDescriptorRegistration r: loader) {
+            assertTrue(expectedClassNames.contains(r.getClass().getName()));
+            if (r.getClass().getName().equals(VmClassStatDAOImplStatementDescriptorRegistration.class.getName())) {
+                vmClassStatReg = r;
+            }
+            registrations.add(r);
+        }
+        // storage-core + this module
+        assertEquals(2, registrations.size());
+        assertNotNull(vmClassStatReg);
+        assertEquals(1, vmClassStatReg.getStatementDescriptors().size());
+    }
+    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-cpu/common/src/main/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOImplStatementDescriptorRegistration.java	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,63 @@
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.vm.cpu.common.internal;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import com.redhat.thermostat.storage.core.VmLatestPojoListGetter;
+import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration;
+import com.redhat.thermostat.vm.cpu.common.VmCpuStatDAO;
+
+/**
+ * Registers the prepared query issued by this maven module via
+ * {@link VmLatestPojoListGetter}.
+ *
+ */
+public class VmCpuStatDAOImplStatementDescriptorRegistration implements
+        StatementDescriptorRegistration {
+
+    @Override
+    public Set<String> getStatementDescriptors() {
+        Set<String> descs = new HashSet<>();
+        String descriptor = String.format(VmLatestPojoListGetter.VM_LATEST_QUERY_FORMAT,
+                VmCpuStatDAO.vmCpuStatCategory.getName());
+        descs.add(descriptor);
+        return descs;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-cpu/common/src/main/resources/META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,1 @@
+com.redhat.thermostat.vm.cpu.common.internal.VmCpuStatDAOImplStatementDescriptorRegistration
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-cpu/common/src/test/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOImplStatementDescriptorRegistrationTest.java	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,91 @@
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.vm.cpu.common.internal;
+
+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 java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ServiceLoader;
+import java.util.Set;
+
+import org.junit.Test;
+
+import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration;
+import com.redhat.thermostat.storage.internal.dao.DAOImplStatementDescriptorRegistration;
+
+public class VmCpuStatDAOImplStatementDescriptorRegistrationTest {
+
+    @Test
+    public void registersAllQueries() {
+        VmCpuStatDAOImplStatementDescriptorRegistration reg = new VmCpuStatDAOImplStatementDescriptorRegistration();
+        Set<String> descriptors = reg.getStatementDescriptors();
+        assertEquals(1, descriptors.size());
+        assertFalse("null descriptor not allowed", descriptors.contains(null));
+    }
+    
+    /*
+     * The web storage end-point uses service loader in order to determine the
+     * list of trusted/known registrations. This test is to ensure service loading
+     * works for this module's regs. E.g. renaming of the impl class without
+     * changing META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration
+     */
+    @Test
+    public void serviceLoaderCanLoadRegistration() {
+        Set<String> expectedClassNames = new HashSet<>();
+        expectedClassNames.add(DAOImplStatementDescriptorRegistration.class.getName());
+        expectedClassNames.add(VmCpuStatDAOImplStatementDescriptorRegistration.class.getName());
+        ServiceLoader<StatementDescriptorRegistration> loader = ServiceLoader.load(StatementDescriptorRegistration.class, VmCpuStatDAOImplStatementDescriptorRegistration.class.getClassLoader());
+        List<StatementDescriptorRegistration> registrations = new ArrayList<>(1);
+        StatementDescriptorRegistration vmCpuStatReg = null;
+        for (StatementDescriptorRegistration r: loader) {
+            assertTrue(expectedClassNames.contains(r.getClass().getName()));
+            if (r.getClass().getName().equals(VmCpuStatDAOImplStatementDescriptorRegistration.class.getName())) {
+                vmCpuStatReg = r;
+            }
+            registrations.add(r);
+        }
+        // storage-core + this module
+        assertEquals(2, registrations.size());
+        assertNotNull(vmCpuStatReg);
+        assertEquals(1, vmCpuStatReg.getStatementDescriptors().size());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-gc/common/src/main/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOImplStatementDescriptorRegistration.java	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,63 @@
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.vm.gc.common.internal;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import com.redhat.thermostat.storage.core.VmLatestPojoListGetter;
+import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration;
+import com.redhat.thermostat.vm.gc.common.VmGcStatDAO;
+
+/**
+ * Registers the prepared query issued by this maven module via
+ * {@link VmLatestPojoListGetter}.
+ *
+ */
+public class VmGcStatDAOImplStatementDescriptorRegistration implements
+        StatementDescriptorRegistration {
+
+    @Override
+    public Set<String> getStatementDescriptors() {
+        Set<String> descs = new HashSet<>();
+        String descriptor = String.format(VmLatestPojoListGetter.VM_LATEST_QUERY_FORMAT,
+                VmGcStatDAO.vmGcStatCategory.getName());
+        descs.add(descriptor);
+        return descs;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-gc/common/src/main/resources/META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,1 @@
+com.redhat.thermostat.vm.gc.common.internal.VmGcStatDAOImplStatementDescriptorRegistration
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-gc/common/src/test/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOImplStatementDescriptorRegistrationTest.java	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,91 @@
+package com.redhat.thermostat.vm.gc.common.internal;
+
+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 java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ServiceLoader;
+import java.util.Set;
+
+import org.junit.Test;
+
+import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration;
+import com.redhat.thermostat.storage.internal.dao.DAOImplStatementDescriptorRegistration;
+
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+public class VmGcStatDAOImplStatementDescriptorRegistrationTest {
+
+    @Test
+    public void registersAllQueries() {
+        VmGcStatDAOImplStatementDescriptorRegistration reg = new VmGcStatDAOImplStatementDescriptorRegistration();
+        Set<String> descriptors = reg.getStatementDescriptors();
+        assertEquals(1, descriptors.size());
+        assertFalse("null descriptor not allowed", descriptors.contains(null));
+    }
+    
+    /*
+     * The web storage end-point uses service loader in order to determine the
+     * list of trusted/known registrations. This test is to ensure service loading
+     * works for this module's regs. E.g. renaming of the impl class without
+     * changing META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration
+     */
+    @Test
+    public void serviceLoaderCanLoadRegistration() {
+        Set<String> expectedClassNames = new HashSet<>();
+        expectedClassNames.add(DAOImplStatementDescriptorRegistration.class.getName());
+        expectedClassNames.add(VmGcStatDAOImplStatementDescriptorRegistration.class.getName());
+        ServiceLoader<StatementDescriptorRegistration> loader = ServiceLoader.load(StatementDescriptorRegistration.class, VmGcStatDAOImplStatementDescriptorRegistration.class.getClassLoader());
+        List<StatementDescriptorRegistration> registrations = new ArrayList<>(1);
+        StatementDescriptorRegistration vmGcStatReg = null;
+        for (StatementDescriptorRegistration r: loader) {
+            assertTrue(expectedClassNames.contains(r.getClass().getName()));
+            if (r.getClass().getName().equals(VmGcStatDAOImplStatementDescriptorRegistration.class.getName())) {
+                vmGcStatReg = r;
+            }
+            registrations.add(r);
+        }
+        // storage-core + this module
+        assertEquals(2, registrations.size());
+        assertNotNull(vmGcStatReg);
+        assertEquals(1, vmGcStatReg.getStatementDescriptors().size());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOImplStatementDescriptorRegistration.java	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,60 @@
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.vm.heap.analysis.common.internal;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration;
+
+/**
+ * Registers prepared queries issued by this maven module
+ * via {@link HeapDAOImpl}.
+ *
+ */
+public class HeapDAOImplStatementDescriptorRegistration implements
+        StatementDescriptorRegistration {
+
+    @Override
+    public Set<String> getStatementDescriptors() {
+        Set<String> descs = new HashSet<>(2);
+        descs.add(HeapDAOImpl.QUERY_ALL_HEAPS);
+        descs.add(HeapDAOImpl.QUERY_HEAP_INFO);
+        return descs;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/common/src/main/resources/META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,1 @@
+com.redhat.thermostat.vm.heap.analysis.common.internal.HeapDAOImplStatementDescriptorRegistration
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/common/src/test/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOImplStatementDescriptorRegistrationTest.java	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,91 @@
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.vm.heap.analysis.common.internal;
+
+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 java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ServiceLoader;
+import java.util.Set;
+
+import org.junit.Test;
+
+import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration;
+import com.redhat.thermostat.storage.internal.dao.DAOImplStatementDescriptorRegistration;
+
+public class HeapDAOImplStatementDescriptorRegistrationTest {
+
+    @Test
+    public void registersAllQueries() {
+        HeapDAOImplStatementDescriptorRegistration reg = new HeapDAOImplStatementDescriptorRegistration();
+        Set<String> descriptors = reg.getStatementDescriptors();
+        assertEquals(2, descriptors.size());
+        assertFalse("null descriptor not allowed", descriptors.contains(null));
+    }
+    
+    /*
+     * The web storage end-point uses service loader in order to determine the
+     * list of trusted/known registrations. This test is to ensure service loading
+     * works for this module's regs. E.g. renaming of the impl class without
+     * changing META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration
+     */
+    @Test
+    public void serviceLoaderCanLoadRegistration() {
+        Set<String> expectedClassNames = new HashSet<>();
+        expectedClassNames.add(DAOImplStatementDescriptorRegistration.class.getName());
+        expectedClassNames.add(HeapDAOImplStatementDescriptorRegistration.class.getName());
+        ServiceLoader<StatementDescriptorRegistration> loader = ServiceLoader.load(StatementDescriptorRegistration.class, HeapDAOImplStatementDescriptorRegistration.class.getClassLoader());
+        List<StatementDescriptorRegistration> registrations = new ArrayList<>(1);
+        StatementDescriptorRegistration heapDaoReg = null;
+        for (StatementDescriptorRegistration r: loader) {
+            assertTrue(expectedClassNames.contains(r.getClass().getName()));
+            if (r.getClass().getName().equals(HeapDAOImplStatementDescriptorRegistration.class.getName())) {
+                heapDaoReg = r;
+            }
+            registrations.add(r);
+        }
+        // storage-core + this module
+        assertEquals(2, registrations.size());
+        assertNotNull(heapDaoReg);
+        assertEquals(2, heapDaoReg.getStatementDescriptors().size());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-jmx/common/src/main/java/com/redhat/thermostat/vm/jmx/common/internal/JmxNotificationDAOImplStatementDescriptorRegistration.java	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,60 @@
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.vm.jmx.common.internal;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration;
+
+/**
+ * Registers prepared queries issued by this maven module
+ * via {@link JmxNotificationDAOImpl}.
+ *
+ */
+public class JmxNotificationDAOImplStatementDescriptorRegistration implements
+        StatementDescriptorRegistration {
+
+    @Override
+    public Set<String> getStatementDescriptors() {
+        Set<String> descs = new HashSet<>(2);
+        descs.add(JmxNotificationDAOImpl.QUERY_LATEST_NOTIFICATION_STATUS);
+        descs.add(JmxNotificationDAOImpl.QUERY_NOTIFICATIONS);
+        return descs;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-jmx/common/src/main/resources/META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,1 @@
+com.redhat.thermostat.vm.jmx.common.internal.JmxNotificationDAOImplStatementDescriptorRegistration
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-jmx/common/src/test/java/com/redhat/thermostat/vm/jmx/common/internal/JmxNotificationDAOImplStatementDescriptorRegistrationTest.java	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,91 @@
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.vm.jmx.common.internal;
+
+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 java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ServiceLoader;
+import java.util.Set;
+
+import org.junit.Test;
+
+import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration;
+import com.redhat.thermostat.storage.internal.dao.DAOImplStatementDescriptorRegistration;
+
+public class JmxNotificationDAOImplStatementDescriptorRegistrationTest {
+
+    @Test
+    public void registersAllQueries() {
+        JmxNotificationDAOImplStatementDescriptorRegistration reg = new JmxNotificationDAOImplStatementDescriptorRegistration();
+        Set<String> descriptors = reg.getStatementDescriptors();
+        assertEquals(2, descriptors.size());
+        assertFalse("null descriptor not allowed", descriptors.contains(null));
+    }
+    
+    /*
+     * The web storage end-point uses service loader in order to determine the
+     * list of trusted/known registrations. This test is to ensure service loading
+     * works for this module's regs. E.g. renaming of the impl class without
+     * changing META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration
+     */
+    @Test
+    public void serviceLoaderCanLoadRegistration() {
+        Set<String> expectedClassNames = new HashSet<>();
+        expectedClassNames.add(DAOImplStatementDescriptorRegistration.class.getName());
+        expectedClassNames.add(JmxNotificationDAOImplStatementDescriptorRegistration.class.getName());
+        ServiceLoader<StatementDescriptorRegistration> loader = ServiceLoader.load(StatementDescriptorRegistration.class, JmxNotificationDAOImplStatementDescriptorRegistration.class.getClassLoader());
+        List<StatementDescriptorRegistration> registrations = new ArrayList<>(1);
+        StatementDescriptorRegistration jmxDaoReg = null;
+        for (StatementDescriptorRegistration r: loader) {
+            assertTrue(expectedClassNames.contains(r.getClass().getName()));
+            if (r.getClass().getName().equals(JmxNotificationDAOImplStatementDescriptorRegistration.class.getName())) {
+                jmxDaoReg = r;
+            }
+            registrations.add(r);
+        }
+        // storage-core + this module
+        assertEquals(2, registrations.size());
+        assertNotNull(jmxDaoReg);
+        assertEquals(2, jmxDaoReg.getStatementDescriptors().size());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-memory/common/src/main/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOImplStatementDescriptorRegistration.java	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,64 @@
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.vm.memory.common.internal;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import com.redhat.thermostat.storage.core.VmLatestPojoListGetter;
+import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration;
+import com.redhat.thermostat.vm.memory.common.VmMemoryStatDAO;
+
+/**
+ * Registers prepared queries issued by this maven module via
+ * {@link VmLatestPojoListGetter} and {@link VmMemoryStatDAOImpl}.
+ *
+ */
+public class VmMemoryStatDAOImplStatementDescriptorRegistration implements
+        StatementDescriptorRegistration {
+
+    @Override
+    public Set<String> getStatementDescriptors() {
+        Set<String> descs = new HashSet<>(2);
+        String descriptor = String.format(VmLatestPojoListGetter.VM_LATEST_QUERY_FORMAT, 
+                VmMemoryStatDAO.vmMemoryStatsCategory.getName());
+        descs.add(descriptor);
+        descs.add(VmMemoryStatDAOImpl.QUERY_LATEST);
+        return descs;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-memory/common/src/main/resources/META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,1 @@
+com.redhat.thermostat.vm.memory.common.internal.VmMemoryStatDAOImplStatementDescriptorRegistration
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-memory/common/src/test/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOImplStatementDescriptorRegistrationTest.java	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,91 @@
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.vm.memory.common.internal;
+
+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 java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ServiceLoader;
+import java.util.Set;
+
+import org.junit.Test;
+
+import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration;
+import com.redhat.thermostat.storage.internal.dao.DAOImplStatementDescriptorRegistration;
+
+public class VmMemoryStatDAOImplStatementDescriptorRegistrationTest {
+
+    @Test
+    public void registersAllQueries() {
+        VmMemoryStatDAOImplStatementDescriptorRegistration reg = new VmMemoryStatDAOImplStatementDescriptorRegistration();
+        Set<String> descriptors = reg.getStatementDescriptors();
+        assertEquals(2, descriptors.size());
+        assertFalse("null descriptor not allowed", descriptors.contains(null));
+    }
+    
+    /*
+     * The web storage end-point uses service loader in order to determine the
+     * list of trusted/known registrations. This test is to ensure service loading
+     * works for this module's regs. E.g. renaming of the impl class without
+     * changing META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration
+     */
+    @Test
+    public void serviceLoaderCanLoadRegistration() {
+        Set<String> expectedClassNames = new HashSet<>();
+        expectedClassNames.add(DAOImplStatementDescriptorRegistration.class.getName());
+        expectedClassNames.add(VmMemoryStatDAOImplStatementDescriptorRegistration.class.getName());
+        ServiceLoader<StatementDescriptorRegistration> loader = ServiceLoader.load(StatementDescriptorRegistration.class, VmMemoryStatDAOImplStatementDescriptorRegistration.class.getClassLoader());
+        List<StatementDescriptorRegistration> registrations = new ArrayList<>(1);
+        StatementDescriptorRegistration vmMemoryDaoReg = null;
+        for (StatementDescriptorRegistration r: loader) {
+            assertTrue(expectedClassNames.contains(r.getClass().getName()));
+            if (r.getClass().getName().equals(VmMemoryStatDAOImplStatementDescriptorRegistration.class.getName())) {
+                vmMemoryDaoReg = r;
+            }
+            registrations.add(r);
+        }
+        // storage-core + this module
+        assertEquals(2, registrations.size());
+        assertNotNull(vmMemoryDaoReg);
+        assertEquals(2, vmMemoryDaoReg.getStatementDescriptors().size());
+    }
+}
--- a/web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebStorage.java	Wed Jul 24 13:56:13 2013 -0400
+++ b/web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebStorage.java	Mon Jul 22 20:01:46 2013 +0200
@@ -784,7 +784,7 @@
             if (statementId == WebPreparedStatementResponse.ILLEGAL_STATEMENT) {
                 // we've got a descriptor the endpoint doesn't know about or
                 // refuses to accept for security reasons.
-                String msg = "Unknown query descriptor which endpoint of " + WebStorage.class.getName() + "refused to accept!";
+                String msg = "Unknown query descriptor which endpoint of " + WebStorage.class.getName() + " refused to accept!";
                 throw new IllegalDescriptorException(msg, desc.getQueryDescriptor());
             } else if (statementId == WebPreparedStatementResponse.DESCRIPTOR_PARSE_FAILED) {
                 String msg = "Statement descriptor failed to parse. " +
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/WebPreparedStatementResponse.java	Wed Jul 24 13:56:13 2013 -0400
+++ b/web/common/src/main/java/com/redhat/thermostat/web/common/WebPreparedStatementResponse.java	Mon Jul 22 20:01:46 2013 +0200
@@ -41,7 +41,14 @@
  */
 public class WebPreparedStatementResponse {
     
+    /**
+     * Response code for untrusted/unknown descriptors.
+     */
     public static final int ILLEGAL_STATEMENT = -1;
+    
+    /**
+     * Response code for descriptor parsing exceptions.
+     */
     public static final int DESCRIPTOR_PARSE_FAILED = -2;
     
     public WebPreparedStatementResponse() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/server/src/main/java/com/redhat/thermostat/web/server/KnownDescriptorRegistry.java	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,76 @@
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.web.server;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.ServiceLoader;
+import java.util.Set;
+
+import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration;
+
+/**
+ * Registers trusted statement descriptors.
+ *
+ */
+final class KnownDescriptorRegistry {
+
+    private static final ServiceLoader<StatementDescriptorRegistration> TRUSTED_DESCS = ServiceLoader
+            .load(StatementDescriptorRegistration.class);
+    private final Iterable<StatementDescriptorRegistration> actualTrustedDescs;
+    
+    KnownDescriptorRegistry() {
+        this.actualTrustedDescs = TRUSTED_DESCS;
+    }
+    
+    KnownDescriptorRegistry(Iterable<StatementDescriptorRegistration> trustedDescs) {
+        this.actualTrustedDescs = trustedDescs;
+    }
+    
+    final Set<String> getRegisteredDescriptors() {
+        Set<String> trustedSet = new HashSet<>();
+        for (StatementDescriptorRegistration reg: actualTrustedDescs) {
+            Set<String> newCandidates = reg.getStatementDescriptors();
+            if (newCandidates.contains(null)) {
+                throw new IllegalStateException("null statement descriptor not acceptable!");
+            }
+            trustedSet.addAll(newCandidates);
+        }
+        // return a read-only set of all descriptors
+        return Collections.unmodifiableSet(trustedSet);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/server/src/main/java/com/redhat/thermostat/web/server/KnownDescriptorRegistryFactory.java	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,55 @@
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.web.server;
+
+final class KnownDescriptorRegistryFactory {
+    
+    private static KnownDescriptorRegistry reg;
+    
+    final static KnownDescriptorRegistry getInstance() {
+        if (reg == null) {
+            return new KnownDescriptorRegistry();
+        } else {
+            return reg;
+        }
+    }
+    
+    final static void setKnownDescriptorRegistry(KnownDescriptorRegistry reg) {
+        KnownDescriptorRegistryFactory.reg = reg;
+    }
+
+}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/WebStorageEndPoint.java	Wed Jul 24 13:56:13 2013 -0400
+++ b/web/server/src/main/java/com/redhat/thermostat/web/server/WebStorageEndPoint.java	Mon Jul 22 20:01:46 2013 +0200
@@ -46,6 +46,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -135,6 +136,9 @@
     // Lock to be held for setting/getting prepared queries in the above maps
     private Object preparedStmtLock = new Object();
     private int currentPreparedStmtId;
+    
+    // read-only set of all known statement descriptors we trust and allow
+    private Set<String> knownStatementDescriptors;
 
     @Override
     public void init(ServletConfig config) throws ServletException {
@@ -165,6 +169,10 @@
             tokenManager.setTimeout(Integer.parseInt(timeoutParam));
         }
         getServletContext().setAttribute(TOKEN_MANAGER_KEY, tokenManager);
+        
+        // Set the set of statement descriptors which we trust
+        KnownDescriptorRegistry descRegistry = KnownDescriptorRegistryFactory.getInstance();
+        knownStatementDescriptors = descRegistry.getRegisteredDescriptors();
     }
     
     @Override
@@ -290,6 +298,16 @@
             return;
         }
         StatementDescriptor<?> desc = new StatementDescriptor<>(cat, queryDescrParam);
+        // Check if descriptor is trusted (i.e. known)
+        if (!knownStatementDescriptors.contains(desc.getQueryDescriptor())) {
+            String msg = "Attempted to prepare a statement descriptor which we " +
+            		"don't trust! Descriptor was: ->" + desc.getQueryDescriptor() + "<-";
+            logger.log(Level.WARNING, msg);
+            response.setStatementId(WebPreparedStatementResponse.ILLEGAL_STATEMENT);
+            writeResponse(resp, response, WebPreparedStatementResponse.class);
+            return;
+        }
+        
         synchronized (preparedStmtLock) {
             // see if we've prepared this query already
             if (preparedStmts.containsKey(desc)) {
@@ -304,7 +322,6 @@
                         WebPreparedStatementResponse.class);
                 return;
             }
-            // TODO: Check if descriptor is trusted (i.e. known)
             
             // Prepare the target statement and put it into our prepared statement
             // maps.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/server/src/test/java/com/redhat/thermostat/web/server/KnownDescriptorRegistryTest.java	Mon Jul 22 20:01:46 2013 +0200
@@ -0,0 +1,120 @@
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.web.server;
+
+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 java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.junit.Test;
+
+import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration;
+
+public class KnownDescriptorRegistryTest {
+
+    @Test
+    public void canAddDescriptors() {
+        Set<String> descs = new HashSet<>();
+        descs.add("QUERY test WHERE 'a' = ?s");
+        descs.add("QUERY agent-config");
+        Iterable<StatementDescriptorRegistration> regs = getRegs(descs);
+        KnownDescriptorRegistry reg = new KnownDescriptorRegistry(regs);
+        Set<String> registeredDescs = null;
+        try {
+            registeredDescs = reg.getRegisteredDescriptors();
+        } catch (IllegalStateException e) {
+            fail(e.getMessage());
+        }
+        assertNotNull(registeredDescs);
+        for (String d: registeredDescs) {
+            assertTrue(descs.contains(d));
+        }
+    }
+    
+    @Test
+    public void testServiceLoadersInClassPath() {
+        KnownDescriptorRegistry reg = new KnownDescriptorRegistry();
+        Set<String> trustedDescs = reg.getRegisteredDescriptors();
+        assertNotNull(trustedDescs);
+        // storage-core registers 9 queries; this module has
+        // only storage-core as maven dep which registers queries.
+        // see DAOImplStatementDescriptorRegistration
+        assertEquals(9, trustedDescs.size());
+    }
+    
+    @Test
+    public void cannotAddNullDescriptors() {
+        Set<String> descs = new HashSet<>();
+        descs.add("QUERY test WHERE 'a' = ?s");
+        descs.add(null);
+        Iterable<StatementDescriptorRegistration> regs = getRegs(descs);
+        KnownDescriptorRegistry reg = new KnownDescriptorRegistry(regs);
+        try {
+            reg.getRegisteredDescriptors();
+            fail("Should not have accepted null descriptor");
+        } catch (IllegalStateException e) {
+            assertEquals("null statement descriptor not acceptable!", e.getMessage());
+        }
+    }
+
+    private Iterable<StatementDescriptorRegistration> getRegs(Set<String> descs) {
+        StatementDescriptorRegistration reg = new TestStatementDescriptorRegistration(
+                descs);
+        StatementDescriptorRegistration[] regs = new StatementDescriptorRegistration[] { reg };
+        return Arrays.asList(regs);
+    }
+    
+    private static class TestStatementDescriptorRegistration implements StatementDescriptorRegistration {
+
+        private final Set<String> descs;
+        
+        private TestStatementDescriptorRegistration(Set<String> descs) {
+            this.descs = descs;
+        }
+        
+        @Override
+        public Set<String> getStatementDescriptors() {
+            return descs;
+        }
+        
+    }
+}
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndpointTest.java	Wed Jul 24 13:56:13 2013 -0400
+++ b/web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndpointTest.java	Mon Jul 22 20:01:46 2013 +0200
@@ -62,8 +62,12 @@
 import java.net.ProtocolException;
 import java.net.URL;
 import java.net.URLEncoder;
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import javax.servlet.ServletConfig;
 import javax.servlet.ServletException;
@@ -103,6 +107,7 @@
 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.StatementDescriptorRegistration;
 import com.redhat.thermostat.storage.model.BasePojo;
 import com.redhat.thermostat.storage.model.Pojo;
 import com.redhat.thermostat.storage.query.Expression;
@@ -272,10 +277,61 @@
         }
         assertEquals(authPaths.length, methodsReqAuthorization);
     }
+    
+    @Test
+    public void authorizedPrepareQueryWithUnTrustedDescriptor() throws Exception {
+        String strDescriptor = "QUERY " + category.getName() + " WHERE '" + key1.getName() + "' = ?s SORT '" + key1.getName() + "' DSC LIMIT 42";
+        // setup a statement descriptor set so as to mimic a not trusted desc
+        String wrongDescriptor = "QUERY something-other WHERE 'a' = true";
+        setupTrustedStatementRegistry(wrongDescriptor);
+        
+        String[] roleNames = new String[] {
+                Roles.REGISTER_CATEGORY,
+                Roles.PREPARE_STATEMENT
+        };
+        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);
+            }
+        });
+        registerCategory(testuser, password);
+        
+        String endpoint = getEndpoint();
+        URL url = new URL(endpoint + "/prepare-statement");
+        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+        conn.setRequestMethod("POST");
+        sendAuthentication(conn, testuser, password);
+        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
+        conn.setDoInput(true);
+        conn.setDoOutput(true);
+        Gson gson = new GsonBuilder()
+                .registerTypeHierarchyAdapter(WebQueryResponse.class, new WebQueryResponseSerializer<>())
+                .registerTypeAdapter(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("descriptor not trusted, so expected number should be negative!", -1, response.getNumFreeVariables());
+        assertEquals(WebPreparedStatementResponse.ILLEGAL_STATEMENT, response.getStatementId());
+        assertEquals("application/json; charset=UTF-8", conn.getContentType());
+    }
 
     @SuppressWarnings({ "unchecked", "rawtypes" })
     @Test
-    public void authorizedPrepareQuery() throws Exception {
+    public void authorizedPrepareQueryWithTrustedDescriptor() throws Exception {
+        String strDescriptor = "QUERY " + category.getName() + " WHERE '" + key1.getName() + "' = ?s SORT '" + key1.getName() + "' DSC LIMIT 42";
+        setupTrustedStatementRegistry(strDescriptor);
+        
         String[] roleNames = new String[] {
                 Roles.REGISTER_CATEGORY,
                 Roles.PREPARE_STATEMENT,
@@ -320,7 +376,6 @@
         // And the mongo layer
         when(mockMongoQuery.execute()).thenReturn(cursor);
 
-        String strDescriptor = "QUERY " + category.getName() + " WHERE '" + key1.getName() + "' = ?s SORT '" + key1.getName() + "' DSC LIMIT 42";
         String endpoint = getEndpoint();
         URL url = new URL(endpoint + "/prepare-statement");
         HttpURLConnection conn = (HttpURLConnection) url.openConnection();
@@ -379,6 +434,17 @@
         verifyNoMoreInteractions(mockMongoQuery);
     }
     
+    private void setupTrustedStatementRegistry(String strDescriptor) {
+        Set<String> descs = new HashSet<>();
+        descs.add(strDescriptor);
+        StatementDescriptorRegistration reg = mock(StatementDescriptorRegistration.class);
+        when(reg.getStatementDescriptors()).thenReturn(descs);
+        List<StatementDescriptorRegistration> regs = new ArrayList<>(1);
+        regs.add(reg);
+        KnownDescriptorRegistry registry = new KnownDescriptorRegistry(regs);
+        KnownDescriptorRegistryFactory.setKnownDescriptorRegistry(registry);
+    }
+
     @Test
     public void unauthorizedPrepareStmt() throws Exception {
         String failMsg = "thermostat-prepare-statement role missing, expected Forbidden!";