changeset 2281:80a866ff7e45

Make ThreadDaoImpl and NetworkInterfaceInfoDAOImpl countable Reviewed-by: jerboaa Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2016-April/018502.html
author James Aziz <jaziz@redhat.com>
date Fri, 29 Apr 2016 10:40:14 -0400
parents a814b1d058be
children 3b3a9e977dd1
files storage/core/src/main/java/com/redhat/thermostat/storage/dao/BaseCountable.java storage/core/src/main/java/com/redhat/thermostat/storage/dao/NetworkInterfaceInfoDAO.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/AgentInfoDAOImpl.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/BaseCountable.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/DAOImplStatementDescriptorRegistration.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/HostInfoDAOImpl.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/NetworkInterfaceInfoDAOImpl.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/VmInfoDAOImpl.java storage/core/src/test/java/com/redhat/thermostat/storage/dao/BaseCountableTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/BaseCountableTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/DAOImplStatementDescriptorRegistrationTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/NetworkInterfaceInfoDAOTest.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/ThreadDao.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/internal/ThreadDaoImpl.java thread/collector/src/main/java/com/redhat/thermostat/thread/dao/internal/ThreadDaoImplStatementDescriptorRegistration.java thread/collector/src/test/java/com/redhat/thermostat/thread/dao/internal/ThreadDaoImplStatementDescriptorRegistrationTest.java thread/collector/src/test/java/com/redhat/thermostat/thread/dao/internal/ThreadDaoImplTest.java web/server/src/test/java/com/redhat/thermostat/web/server/KnownDescriptorRegistryTest.java
diffstat 18 files changed, 302 insertions(+), 214 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/dao/BaseCountable.java	Fri Apr 29 10:40:14 2016 -0400
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2012-2016 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.dao;
+
+import java.util.logging.Logger;
+
+import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.storage.core.Category;
+import com.redhat.thermostat.storage.core.Storage;
+import com.redhat.thermostat.storage.model.AggregateCount;
+
+/**
+ * This class provides generic functionality for performing an aggregate count query.
+ */
+public class BaseCountable extends AbstractDao {
+    
+    private static final int ERROR_COUNT_RESULT = -1;
+    private static final Logger logger = LoggingUtils.getLogger(BaseCountable.class);
+
+    /**
+     * Performs an aggregate count query as described by the given descriptor.
+     * 
+     * @param storage the storage to use for preparing the descriptor.
+     * @param category the query category.
+     * @param descriptor the query descriptor.
+     * @return -1 if execution failed for some reason, the actual count of the
+     *         query results if successful.
+     */
+    protected long getCount(Storage storage, Category<AggregateCount> category, String descriptor) {
+        QueryResult<AggregateCount> result = executeQuery(new SimpleDaoQuery<>(storage, category, descriptor));
+        AggregateCount count = result.head();
+        if (count == null || result.hasExceptions()) {
+            return ERROR_COUNT_RESULT;
+        } else {
+            return count.getCount();
+        }
+    }
+
+    @Override
+    protected Logger getLogger() {
+        return logger;
+    }
+}
+
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/dao/NetworkInterfaceInfoDAO.java	Tue Apr 19 15:28:00 2016 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/dao/NetworkInterfaceInfoDAO.java	Fri Apr 29 10:40:14 2016 -0400
@@ -40,12 +40,13 @@
 
 import com.redhat.thermostat.annotations.Service;
 import com.redhat.thermostat.storage.core.Category;
+import com.redhat.thermostat.storage.core.Countable;
 import com.redhat.thermostat.storage.core.HostRef;
 import com.redhat.thermostat.storage.core.Key;
 import com.redhat.thermostat.storage.model.NetworkInterfaceInfo;
 
 @Service
-public interface NetworkInterfaceInfoDAO {
+public interface NetworkInterfaceInfoDAO extends Countable {
 
     static Key<String> ifaceKey = new Key<>("interfaceName");
     static Key<String> ip4AddrKey = new Key<>("ip4Addr");
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/AgentInfoDAOImpl.java	Tue Apr 19 15:28:00 2016 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/AgentInfoDAOImpl.java	Fri Apr 29 10:40:14 2016 -0400
@@ -52,6 +52,7 @@
 import com.redhat.thermostat.storage.dao.AbstractDaoQuery;
 import com.redhat.thermostat.storage.dao.AbstractDaoStatement;
 import com.redhat.thermostat.storage.dao.AgentInfoDAO;
+import com.redhat.thermostat.storage.dao.BaseCountable;
 import com.redhat.thermostat.storage.dao.SimpleDaoQuery;
 import com.redhat.thermostat.storage.model.AgentInformation;
 import com.redhat.thermostat.storage.model.AggregateCount;
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/BaseCountable.java	Tue Apr 19 15:28:00 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,87 +0,0 @@
-/*
- * Copyright 2012-2016 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.logging.Logger;
-
-import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.Cursor;
-import com.redhat.thermostat.storage.core.DescriptorParsingException;
-import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.core.StatementExecutionException;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.dao.AbstractDao;
-import com.redhat.thermostat.storage.dao.QueryResult;
-import com.redhat.thermostat.storage.dao.SimpleDaoQuery;
-import com.redhat.thermostat.storage.model.AggregateCount;
-import com.redhat.thermostat.storage.model.Pojo;
-
-import static com.redhat.thermostat.storage.internal.dao.LoggingUtil.logDescriptorParsingException;
-import static com.redhat.thermostat.storage.internal.dao.LoggingUtil.logStatementExecutionException;
-
-class BaseCountable extends AbstractDao {
-    
-    private static final int ERROR_COUNT_RESULT = -1;
-    private static final Logger logger = LoggingUtils.getLogger(BaseCountable.class);
-
-    /**
-     * Performs an aggregate count query as described by the given descriptor.
-     * 
-     * @param storage the storage to use for preparing the descriptor.
-     * @param category the query category.
-     * @param descriptor the query descriptor.
-     * @return -1 if execution failed for some reason, the actual count of the
-     *         query results if successful.
-     */
-    protected long getCount(Storage storage, Category<AggregateCount> category, String descriptor) {
-        QueryResult<AggregateCount> result = executeQuery(new SimpleDaoQuery<>(storage, category, descriptor));
-        AggregateCount count = result.head();
-        if (count == null || result.hasExceptions()) {
-            return ERROR_COUNT_RESULT;
-        } else {
-            return count.getCount();
-        }
-    }
-
-    @Override
-    protected Logger getLogger() {
-        return logger;
-    }
-}
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/DAOImplStatementDescriptorRegistration.java	Tue Apr 19 15:28:00 2016 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/DAOImplStatementDescriptorRegistration.java	Fri Apr 29 10:40:14 2016 -0400
@@ -39,7 +39,6 @@
 import java.util.HashSet;
 import java.util.Set;
 
-import com.redhat.thermostat.storage.core.PreparedParameter;
 import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration;
 
 /**
@@ -69,6 +68,7 @@
         daoDescs.add(HostInfoDAOImpl.DESC_ADD_HOST_INFO);
         daoDescs.add(NetworkInterfaceInfoDAOImpl.QUERY_NETWORK_INFO);
         daoDescs.add(NetworkInterfaceInfoDAOImpl.DESC_REPLACE_NETWORK_INFO);
+        daoDescs.add(NetworkInterfaceInfoDAOImpl.AGGREGATE_COUNT_ALL_NETWORK_INTERFACES);
         daoDescs.add(VmInfoDAOImpl.QUERY_ALL_VMS_FOR_HOST);
         daoDescs.add(VmInfoDAOImpl.QUERY_ALL_VMS);
         daoDescs.add(VmInfoDAOImpl.QUERY_VM_INFO);
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/HostInfoDAOImpl.java	Tue Apr 19 15:28:00 2016 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/HostInfoDAOImpl.java	Fri Apr 29 10:40:14 2016 -0400
@@ -52,6 +52,7 @@
 import com.redhat.thermostat.storage.dao.AbstractDaoQuery;
 import com.redhat.thermostat.storage.dao.AbstractDaoStatement;
 import com.redhat.thermostat.storage.dao.AgentInfoDAO;
+import com.redhat.thermostat.storage.dao.BaseCountable;
 import com.redhat.thermostat.storage.dao.HostInfoDAO;
 import com.redhat.thermostat.storage.dao.SimpleDaoQuery;
 import com.redhat.thermostat.storage.model.AgentInformation;
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/NetworkInterfaceInfoDAOImpl.java	Tue Apr 19 15:28:00 2016 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/NetworkInterfaceInfoDAOImpl.java	Fri Apr 29 10:40:14 2016 -0400
@@ -40,17 +40,20 @@
 import java.util.logging.Logger;
 
 import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.storage.core.Category;
+import com.redhat.thermostat.storage.core.CategoryAdapter;
 import com.redhat.thermostat.storage.core.HostRef;
 import com.redhat.thermostat.storage.core.Key;
 import com.redhat.thermostat.storage.core.PreparedStatement;
 import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.dao.AbstractDao;
 import com.redhat.thermostat.storage.dao.AbstractDaoQuery;
 import com.redhat.thermostat.storage.dao.AbstractDaoStatement;
+import com.redhat.thermostat.storage.dao.BaseCountable;
 import com.redhat.thermostat.storage.dao.NetworkInterfaceInfoDAO;
+import com.redhat.thermostat.storage.model.AggregateCount;
 import com.redhat.thermostat.storage.model.NetworkInterfaceInfo;
 
-public class NetworkInterfaceInfoDAOImpl extends AbstractDao implements NetworkInterfaceInfoDAO {
+public class NetworkInterfaceInfoDAOImpl extends BaseCountable implements NetworkInterfaceInfoDAO {
 
     private static final Logger logger = LoggingUtils.getLogger(NetworkInterfaceInfoDAOImpl.class);
     static final String QUERY_NETWORK_INFO = "QUERY "
@@ -69,14 +72,21 @@
                     "'" + ip4AddrKey.getName() + "' = ?s , " +
                     "'" + ip6AddrKey.getName() + "' = ?s " +
                  "WHERE '" + Key.AGENT_ID.getName() + "' = ?s AND " +
-                       "'" + ifaceKey.getName() + "' = ?s"; 
-                                
+                       "'" + ifaceKey.getName() + "' = ?s";
+    static final String AGGREGATE_COUNT_ALL_NETWORK_INTERFACES = "QUERY-COUNT " +
+            networkInfoCategory.getName();
 
+
+    private final Category<AggregateCount> aggregateCategory;
     private final Storage storage;
 
     public NetworkInterfaceInfoDAOImpl(Storage storage) {
         this.storage = storage;
         storage.registerCategory(networkInfoCategory);
+        CategoryAdapter<NetworkInterfaceInfo, AggregateCount> adapter =
+                new CategoryAdapter<>(networkInfoCategory);
+        aggregateCategory = adapter.getAdapted(AggregateCount.class);
+        storage.registerCategory(aggregateCategory);
     }
 
     @Override
@@ -111,6 +121,11 @@
     }
 
     @Override
+    public long getCount() {
+        return getCount(storage, aggregateCategory, AGGREGATE_COUNT_ALL_NETWORK_INTERFACES);
+    }
+
+    @Override
     protected Logger getLogger() {
         return logger;
     }
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/VmInfoDAOImpl.java	Tue Apr 19 15:28:00 2016 +0200
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/VmInfoDAOImpl.java	Fri Apr 29 10:40:14 2016 -0400
@@ -56,6 +56,7 @@
 import com.redhat.thermostat.storage.core.VmRef;
 import com.redhat.thermostat.storage.dao.AbstractDaoQuery;
 import com.redhat.thermostat.storage.dao.AbstractDaoStatement;
+import com.redhat.thermostat.storage.dao.BaseCountable;
 import com.redhat.thermostat.storage.dao.SimpleDaoQuery;
 import com.redhat.thermostat.storage.dao.VmInfoDAO;
 import com.redhat.thermostat.storage.model.AggregateCount;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/dao/BaseCountableTest.java	Fri Apr 29 10:40:14 2016 -0400
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2012-2016 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.dao;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.junit.Test;
+
+import com.redhat.thermostat.storage.core.Category;
+import com.redhat.thermostat.storage.core.Cursor;
+import com.redhat.thermostat.storage.core.DescriptorParsingException;
+import com.redhat.thermostat.storage.core.PreparedStatement;
+import com.redhat.thermostat.storage.core.StatementDescriptor;
+import com.redhat.thermostat.storage.core.StatementExecutionException;
+import com.redhat.thermostat.storage.core.Storage;
+import com.redhat.thermostat.storage.model.AggregateCount;
+
+public class BaseCountableTest {
+
+    @Test
+    public void testGetCountSuccessful() throws DescriptorParsingException, StatementExecutionException {
+        Storage storage = mock(Storage.class);
+        @SuppressWarnings("unchecked")
+        Category<AggregateCount> mockCategory = (Category<AggregateCount>)mock(Category.class);
+        BaseCountable countable = new BaseCountable();
+        String strDesc = "QUERY-COUNT vm-info";
+        StatementDescriptor<AggregateCount> desc = new StatementDescriptor<>(mockCategory, strDesc);
+        @SuppressWarnings("unchecked")
+        PreparedStatement<AggregateCount> prepared = (PreparedStatement<AggregateCount>)mock(PreparedStatement.class);
+        when(storage.prepareStatement(eq(desc))).thenReturn(prepared);
+        AggregateCount c = new AggregateCount();
+        c.setCount(3);
+        Cursor<AggregateCount> cursor = c.getCursor();
+        when(prepared.executeQuery()).thenReturn(cursor);
+        long count = countable.getCount(storage, mockCategory, strDesc);
+        assertEquals(3, count);
+    }
+    
+    @Test
+    public void testGetCountError() throws DescriptorParsingException, StatementExecutionException {
+        Storage storage = mock(Storage.class);
+        @SuppressWarnings("unchecked")
+        Category<AggregateCount> mockCategory = (Category<AggregateCount>)mock(Category.class);
+        BaseCountable countable = new BaseCountable();
+        String strDesc = "QUERY-COUNT vm-info";
+        StatementDescriptor<AggregateCount> desc = new StatementDescriptor<>(mockCategory, strDesc);
+        doThrow(DescriptorParsingException.class).when(storage).prepareStatement(eq(desc));
+        long count = countable.getCount(storage, mockCategory, strDesc);
+        assertEquals(-1, count);
+    }
+    
+    @Test
+    public void testGetCountError2() throws DescriptorParsingException, StatementExecutionException {
+        Storage storage = mock(Storage.class);
+        @SuppressWarnings("unchecked")
+        Category<AggregateCount> mockCategory = (Category<AggregateCount>)mock(Category.class);
+        BaseCountable countable = new BaseCountable();
+        String strDesc = "QUERY-COUNT vm-info";
+        StatementDescriptor<AggregateCount> desc = new StatementDescriptor<>(mockCategory, strDesc);
+        @SuppressWarnings("unchecked")
+        PreparedStatement<AggregateCount> prepared = (PreparedStatement<AggregateCount>)mock(PreparedStatement.class);
+        when(storage.prepareStatement(eq(desc))).thenReturn(prepared);
+        doThrow(StatementExecutionException.class).when(prepared).executeQuery();
+        long count = countable.getCount(storage, mockCategory, strDesc);
+        assertEquals(-1, count);
+    }
+}
+
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/BaseCountableTest.java	Tue Apr 19 15:28:00 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,106 +0,0 @@
-/*
- * Copyright 2012-2016 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.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-import static org.mockito.Mockito.doThrow;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.Cursor;
-import com.redhat.thermostat.storage.core.DescriptorParsingException;
-import com.redhat.thermostat.storage.core.PreparedStatement;
-import com.redhat.thermostat.storage.core.StatementDescriptor;
-import com.redhat.thermostat.storage.core.StatementExecutionException;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.model.AggregateCount;
-
-public class BaseCountableTest {
-
-    @Test
-    public void testGetCountSuccessful() throws DescriptorParsingException, StatementExecutionException {
-        Storage storage = mock(Storage.class);
-        @SuppressWarnings("unchecked")
-        Category<AggregateCount> mockCategory = (Category<AggregateCount>)mock(Category.class);
-        BaseCountable countable = new BaseCountable();
-        String strDesc = "QUERY-COUNT vm-info";
-        StatementDescriptor<AggregateCount> desc = new StatementDescriptor<>(mockCategory, strDesc);
-        @SuppressWarnings("unchecked")
-        PreparedStatement<AggregateCount> prepared = (PreparedStatement<AggregateCount>)mock(PreparedStatement.class);
-        when(storage.prepareStatement(eq(desc))).thenReturn(prepared);
-        AggregateCount c = new AggregateCount();
-        c.setCount(3);
-        Cursor<AggregateCount> cursor = c.getCursor();
-        when(prepared.executeQuery()).thenReturn(cursor);
-        long count = countable.getCount(storage, mockCategory, strDesc);
-        assertEquals(3, count);
-    }
-    
-    @Test
-    public void testGetCountError() throws DescriptorParsingException, StatementExecutionException {
-        Storage storage = mock(Storage.class);
-        @SuppressWarnings("unchecked")
-        Category<AggregateCount> mockCategory = (Category<AggregateCount>)mock(Category.class);
-        BaseCountable countable = new BaseCountable();
-        String strDesc = "QUERY-COUNT vm-info";
-        StatementDescriptor<AggregateCount> desc = new StatementDescriptor<>(mockCategory, strDesc);
-        doThrow(DescriptorParsingException.class).when(storage).prepareStatement(eq(desc));
-        long count = countable.getCount(storage, mockCategory, strDesc);
-        assertEquals(-1, count);
-    }
-    
-    @Test
-    public void testGetCountError2() throws DescriptorParsingException, StatementExecutionException {
-        Storage storage = mock(Storage.class);
-        @SuppressWarnings("unchecked")
-        Category<AggregateCount> mockCategory = (Category<AggregateCount>)mock(Category.class);
-        BaseCountable countable = new BaseCountable();
-        String strDesc = "QUERY-COUNT vm-info";
-        StatementDescriptor<AggregateCount> desc = new StatementDescriptor<>(mockCategory, strDesc);
-        @SuppressWarnings("unchecked")
-        PreparedStatement<AggregateCount> prepared = (PreparedStatement<AggregateCount>)mock(PreparedStatement.class);
-        when(storage.prepareStatement(eq(desc))).thenReturn(prepared);
-        doThrow(StatementExecutionException.class).when(prepared).executeQuery();
-        long count = countable.getCount(storage, mockCategory, strDesc);
-        assertEquals(-1, count);
-    }
-}
-
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/DAOImplStatementDescriptorRegistrationTest.java	Tue Apr 19 15:28:00 2016 +0200
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/DAOImplStatementDescriptorRegistrationTest.java	Fri Apr 29 10:40:14 2016 -0400
@@ -56,7 +56,7 @@
     public void registersAllQueries() {
         DAOImplStatementDescriptorRegistration reg = new DAOImplStatementDescriptorRegistration();
         Set<String> descriptors = reg.getStatementDescriptors();
-        assertEquals(24, descriptors.size());
+        assertEquals(25, descriptors.size());
         assertFalse(descriptors.contains(null));
     }
 
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/NetworkInterfaceInfoDAOTest.java	Tue Apr 19 15:28:00 2016 +0200
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/NetworkInterfaceInfoDAOTest.java	Fri Apr 29 10:40:14 2016 -0400
@@ -46,6 +46,7 @@
 
 import java.util.Collection;
 import java.util.List;
+import java.util.NoSuchElementException;
 
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
@@ -59,6 +60,7 @@
 import com.redhat.thermostat.storage.core.StatementExecutionException;
 import com.redhat.thermostat.storage.core.Storage;
 import com.redhat.thermostat.storage.dao.NetworkInterfaceInfoDAO;
+import com.redhat.thermostat.storage.model.AggregateCount;
 import com.redhat.thermostat.storage.model.NetworkInterfaceInfo;
 
 public class NetworkInterfaceInfoDAOTest {
@@ -84,6 +86,9 @@
     public void preparedQueryDescriptorsAreSane() {
         String expectedNetworkInfo = "QUERY network-info WHERE 'agentId' = ?s";
         assertEquals(expectedNetworkInfo, NetworkInterfaceInfoDAOImpl.QUERY_NETWORK_INFO);
+        String aggregateCountAllNetworkInterfaces = "QUERY-COUNT network-info";
+        assertEquals(aggregateCountAllNetworkInterfaces,
+                NetworkInterfaceInfoDAOImpl.AGGREGATE_COUNT_ALL_NETWORK_INTERFACES);
         String replaceNetworkInfo = "REPLACE network-info SET 'agentId' = ?s , " +
             "'interfaceName' = ?s , " +
             "'ip4Addr' = ?s , " +
@@ -168,6 +173,28 @@
         verify(replace).execute();
         verifyNoMoreInteractions(replace);
     }
-    
+
+    @Test
+    public void testGetCount()
+            throws DescriptorParsingException, StatementExecutionException {
+        AggregateCount count = new AggregateCount();
+        count.setCount(2);
+
+        @SuppressWarnings("unchecked")
+        Cursor<AggregateCount> c = (Cursor<AggregateCount>) mock(Cursor.class);
+        when(c.hasNext()).thenReturn(true).thenReturn(false);
+        when(c.next()).thenReturn(count).thenThrow(new NoSuchElementException());
+
+        Storage storage = mock(Storage.class);
+        @SuppressWarnings("unchecked")
+        PreparedStatement<AggregateCount> stmt = (PreparedStatement<AggregateCount>) mock(PreparedStatement.class);
+        @SuppressWarnings("unchecked")
+        StatementDescriptor<AggregateCount> desc = any(StatementDescriptor.class);
+        when(storage.prepareStatement(desc)).thenReturn(stmt);
+        when(stmt.executeQuery()).thenReturn(c);
+        NetworkInterfaceInfoDAOImpl dao = new NetworkInterfaceInfoDAOImpl(storage);
+
+        assertEquals(2, dao.getCount());
+    }
 }
 
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/ThreadDao.java	Tue Apr 19 15:28:00 2016 +0200
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/ThreadDao.java	Fri Apr 29 10:40:14 2016 -0400
@@ -36,6 +36,9 @@
 
 package com.redhat.thermostat.thread.dao;
 
+import java.util.Arrays;
+import java.util.List;
+
 import com.redhat.thermostat.common.model.Range;
 import com.redhat.thermostat.storage.core.Category;
 import com.redhat.thermostat.storage.core.Key;
@@ -49,8 +52,6 @@
 import com.redhat.thermostat.thread.model.ThreadState;
 import com.redhat.thermostat.thread.model.ThreadSummary;
 import com.redhat.thermostat.thread.model.VmDeadLockData;
-import java.util.Arrays;
-import java.util.List;
 
 public interface ThreadDao {
 
@@ -131,4 +132,6 @@
     void getThreadStates(VmRef ref, SessionID session,
                          ResultHandler<ThreadState> handler,
                          Range<Long> range, int limit, Sort order);
+
+    long getDeadLockCount();
 }
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/internal/ThreadDaoImpl.java	Tue Apr 19 15:28:00 2016 +0200
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/internal/ThreadDaoImpl.java	Fri Apr 29 10:40:14 2016 -0400
@@ -36,11 +36,20 @@
 
 package com.redhat.thermostat.thread.dao.internal;
 
+import static com.redhat.thermostat.common.utils.IteratorUtils.head;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
 import com.redhat.thermostat.common.model.Range;
 import com.redhat.thermostat.common.utils.LoggingUtils;
 import com.redhat.thermostat.storage.core.Category;
+import com.redhat.thermostat.storage.core.CategoryAdapter;
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.DescriptorParsingException;
+import com.redhat.thermostat.storage.core.Id;
 import com.redhat.thermostat.storage.core.Key;
 import com.redhat.thermostat.storage.core.PreparedStatement;
 import com.redhat.thermostat.storage.core.StatementDescriptor;
@@ -49,10 +58,11 @@
 import com.redhat.thermostat.storage.core.VmRef;
 import com.redhat.thermostat.storage.core.experimental.statement.BeanAdapter;
 import com.redhat.thermostat.storage.core.experimental.statement.BeanAdapterBuilder;
-import com.redhat.thermostat.storage.core.Id;
 import com.redhat.thermostat.storage.core.experimental.statement.Query;
 import com.redhat.thermostat.storage.core.experimental.statement.QueryValues;
 import com.redhat.thermostat.storage.core.experimental.statement.ResultHandler;
+import com.redhat.thermostat.storage.dao.BaseCountable;
+import com.redhat.thermostat.storage.model.AggregateCount;
 import com.redhat.thermostat.storage.model.Pojo;
 import com.redhat.thermostat.thread.dao.ThreadDao;
 import com.redhat.thermostat.thread.dao.internal.statement.SessionQueries;
@@ -64,14 +74,8 @@
 import com.redhat.thermostat.thread.model.ThreadState;
 import com.redhat.thermostat.thread.model.ThreadSummary;
 import com.redhat.thermostat.thread.model.VmDeadLockData;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.logging.Level;
-import java.util.logging.Logger;
 
-import static com.redhat.thermostat.common.utils.IteratorUtils.head;
-
-public class ThreadDaoImpl implements ThreadDao {
+public class ThreadDaoImpl extends BaseCountable implements ThreadDao {
     
     private static final Logger logger = LoggingUtils.getLogger(ThreadDaoImpl.class);
 
@@ -91,6 +95,9 @@
             + Key.VM_ID.getName() + "' = ?s SORT '" 
             + Key.TIMESTAMP.getName() + "' DSC LIMIT 1";
 
+    static final String AGGREGATE_COUNT_ALL_DEADLOCKS = "QUERY-COUNT " +
+            DEADLOCK_INFO.getName();
+
     static final String DESC_ADD_THREAD_HARVESTING_STATUS = "ADD " + THREAD_HARVESTING_STATUS.getName() +
             " SET '" + Key.AGENT_ID.getName() + "' = ?s , " +
                  "'" + Key.VM_ID.getName() + "' = ?s , " +
@@ -120,6 +127,7 @@
             + ThreadDaoKeys.THREAD_HEADER_UUID.getName() + "' = ?s SORT '"
             + Key.TIMESTAMP.getName() + "' DSC LIMIT 1";
 
+    private final Category<AggregateCount> aggregateCategory;
     private Storage storage;
     
     public ThreadDaoImpl(Storage storage) {
@@ -131,6 +139,10 @@
         storage.registerCategory(THREAD_CONTENTION_SAMPLE);
 
         storage.registerCategory(DEADLOCK_INFO);
+
+        CategoryAdapter<VmDeadLockData, AggregateCount> adapter = new CategoryAdapter<>(DEADLOCK_INFO);
+        aggregateCategory = adapter.getAdapted(AggregateCount.class);
+        storage.registerCategory(aggregateCategory);
     }
 
     @Override
@@ -311,6 +323,11 @@
         }
     }
 
+    @Override
+    public long getDeadLockCount() {
+        return getCount(storage, aggregateCategory, AGGREGATE_COUNT_ALL_DEADLOCKS);
+    }
+
 
     /**************************************************************************/
 
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/internal/ThreadDaoImplStatementDescriptorRegistration.java	Tue Apr 19 15:28:00 2016 +0200
+++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/internal/ThreadDaoImplStatementDescriptorRegistration.java	Fri Apr 29 10:40:14 2016 -0400
@@ -55,6 +55,7 @@
         descs = new HashSet<>();
         descs.add(ThreadDaoImpl.QUERY_LATEST_DEADLOCK_INFO);
         descs.add(ThreadDaoImpl.QUERY_LATEST_HARVESTING_STATUS);
+        descs.add(ThreadDaoImpl.AGGREGATE_COUNT_ALL_DEADLOCKS);
 
         // TODO: this needs to go in an helper class
         descs.addAll(ThreadDaoImpl.ThreadSummaryAdapter.describeStatements());
--- a/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/internal/ThreadDaoImplStatementDescriptorRegistrationTest.java	Tue Apr 19 15:28:00 2016 +0200
+++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/internal/ThreadDaoImplStatementDescriptorRegistrationTest.java	Fri Apr 29 10:40:14 2016 -0400
@@ -56,7 +56,7 @@
     public void registersAllDescriptors() {
         ThreadDaoImplStatementDescriptorRegistration reg = new ThreadDaoImplStatementDescriptorRegistration();
         Set<String> descriptors = reg.getStatementDescriptors();
-        assertEquals(14, descriptors.size());
+        assertEquals(15, descriptors.size());
         assertFalse("null statement not allowed", descriptors.contains(null));
     }
 
--- a/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/internal/ThreadDaoImplTest.java	Tue Apr 19 15:28:00 2016 +0200
+++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/internal/ThreadDaoImplTest.java	Fri Apr 29 10:40:14 2016 -0400
@@ -45,6 +45,8 @@
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
+import java.util.NoSuchElementException;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
@@ -58,6 +60,7 @@
 import com.redhat.thermostat.storage.core.StatementExecutionException;
 import com.redhat.thermostat.storage.core.Storage;
 import com.redhat.thermostat.storage.core.VmRef;
+import com.redhat.thermostat.storage.model.AggregateCount;
 import com.redhat.thermostat.storage.model.Pojo;
 import com.redhat.thermostat.thread.dao.ThreadDao;
 import com.redhat.thermostat.thread.model.ThreadHarvestingStatus;
@@ -90,6 +93,9 @@
         String expectedQueryThreadLatestDeadlockInfo = "QUERY vm-deadlock-data WHERE 'agentId' = ?s AND 'vmId' = ?s SORT 'timeStamp' DSC LIMIT 1";
         assertEquals(expectedQueryThreadLatestDeadlockInfo, ThreadDaoImpl.QUERY_LATEST_DEADLOCK_INFO);
 
+        String aggregateCountAllDeadLocks = "QUERY-COUNT vm-deadlock-data";
+        assertEquals(aggregateCountAllDeadLocks, ThreadDaoImpl.AGGREGATE_COUNT_ALL_DEADLOCKS);
+
         String addThreadHarvesting = "ADD vm-thread-harvesting SET 'agentId' = ?s , " +
                                                     "'vmId' = ?s , " +
                                                     "'timeStamp' = ?l , " +
@@ -259,5 +265,29 @@
         verifyNoMoreInteractions(add);
     }
 
+    @Test
+    public void testGetDeadLockCount()
+            throws DescriptorParsingException, StatementExecutionException {
+
+        AggregateCount count = new AggregateCount();
+        count.setCount(2);
+
+        @SuppressWarnings("unchecked")
+        Cursor<AggregateCount> c = (Cursor<AggregateCount>) mock(Cursor.class);
+        when(c.hasNext()).thenReturn(true).thenReturn(false);
+        when(c.next()).thenReturn(count).thenThrow(new NoSuchElementException());
+
+        Storage storage = mock(Storage.class);
+        @SuppressWarnings("unchecked")
+        PreparedStatement<AggregateCount> stmt = (PreparedStatement<AggregateCount>) mock(PreparedStatement.class);
+        @SuppressWarnings("unchecked")
+        StatementDescriptor<AggregateCount> desc = any(StatementDescriptor.class);
+        when(storage.prepareStatement(desc)).thenReturn(stmt);
+        when(stmt.executeQuery()).thenReturn(c);
+        ThreadDaoImpl dao = new ThreadDaoImpl(storage);
+
+        assertEquals(2, dao.getDeadLockCount());
+    }
+
 }
 
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/KnownDescriptorRegistryTest.java	Tue Apr 19 15:28:00 2016 +0200
+++ b/web/server/src/test/java/com/redhat/thermostat/web/server/KnownDescriptorRegistryTest.java	Fri Apr 29 10:40:14 2016 -0400
@@ -76,10 +76,10 @@
         KnownDescriptorRegistry reg = new KnownDescriptorRegistry();
         Set<String> trustedDescs = reg.getRegisteredDescriptors();
         assertNotNull(trustedDescs);
-        // storage-core registers 24 descriptors; this module has
+        // storage-core registers 25 descriptors; this module has
         // only storage-core as maven dep which registers queries.
         // see DAOImplStatementDescriptorRegistration
-        assertEquals(24, trustedDescs.size());
+        assertEquals(25, trustedDescs.size());
     }
     
     /**