Mercurial > hg > thermostat-ng > agent
changeset 2645:d58c740a1a0b
Remove remaining web storage implementation
Reviewed-by: neugens
Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-May/023015.html
author | Elliott Baron <ebaron@redhat.com> |
---|---|
date | Wed, 10 May 2017 16:02:18 -0400 |
parents | 13807543d358 |
children | 91412a25d6ec |
files | distribution/assembly/core-assembly-macosx.xml distribution/assembly/core-assembly-windows.xml distribution/assembly/core-assembly.xml distribution/config/commands/agent.properties distribution/pom.xml plugins/vm-byteman/common/pom.xml plugins/vm-byteman/common/src/test/java/com/redhat/thermostat/vm/byteman/common/BytemanMetricTest.java pom.xml web/client/pom.xml web/client/src/main/java/com/redhat/thermostat/web/client/internal/Activator.java web/client/src/main/java/com/redhat/thermostat/web/client/internal/EntityConsumingIOException.java web/client/src/main/java/com/redhat/thermostat/web/client/internal/ExpirableWebPreparedStatementCache.java web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebCursor.java web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebPreparedStatementCache.java web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebPreparedStatementHolder.java web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebStorage.java web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebStorageProvider.java web/client/src/test/java/com/redhat/thermostat/web/client/internal/EntityConsumingIOExceptionTest.java web/client/src/test/java/com/redhat/thermostat/web/client/internal/ExpirableWebPreparedStatementCacheTest.java web/client/src/test/java/com/redhat/thermostat/web/client/internal/TestObj.java web/client/src/test/java/com/redhat/thermostat/web/client/internal/WebCursorTest.java web/client/src/test/java/com/redhat/thermostat/web/client/internal/WebPreparedStatementCacheTest.java web/client/src/test/java/com/redhat/thermostat/web/client/internal/WebStorageProviderTest.java web/client/src/test/java/com/redhat/thermostat/web/client/internal/WebStorageTest.java web/common/pom.xml web/common/src/main/java/com/redhat/thermostat/web/common/PreparedStatementResponseCode.java web/common/src/main/java/com/redhat/thermostat/web/common/SharedStateId.java web/common/src/main/java/com/redhat/thermostat/web/common/WebPreparedStatement.java web/common/src/main/java/com/redhat/thermostat/web/common/WebPreparedStatementResponse.java web/common/src/main/java/com/redhat/thermostat/web/common/WebQueryResponse.java web/common/src/main/java/com/redhat/thermostat/web/common/typeadapters/PojoTypeAdapter.java web/common/src/main/java/com/redhat/thermostat/web/common/typeadapters/PojoTypeAdapterFactory.java web/common/src/main/java/com/redhat/thermostat/web/common/typeadapters/PreparedParameterTypeAdapter.java web/common/src/main/java/com/redhat/thermostat/web/common/typeadapters/PreparedParameterTypeAdapterFactory.java web/common/src/main/java/com/redhat/thermostat/web/common/typeadapters/PreparedParametersTypeAdapter.java web/common/src/main/java/com/redhat/thermostat/web/common/typeadapters/PreparedParametersTypeAdapterFactory.java web/common/src/main/java/com/redhat/thermostat/web/common/typeadapters/SharedStateIdTypeAdapter.java web/common/src/main/java/com/redhat/thermostat/web/common/typeadapters/SharedStateIdTypeAdapterFactory.java web/common/src/main/java/com/redhat/thermostat/web/common/typeadapters/WebPreparedStatementResponseTypeAdapter.java web/common/src/main/java/com/redhat/thermostat/web/common/typeadapters/WebPreparedStatementResponseTypeAdapterFactory.java web/common/src/main/java/com/redhat/thermostat/web/common/typeadapters/WebPreparedStatementTypeAdapter.java web/common/src/main/java/com/redhat/thermostat/web/common/typeadapters/WebPreparedStatementTypeAdapterFactory.java web/common/src/main/java/com/redhat/thermostat/web/common/typeadapters/WebQueryResponseTypeAdapter.java web/common/src/main/java/com/redhat/thermostat/web/common/typeadapters/WebQueryResponseTypeAdapterFactory.java web/common/src/test/java/com/redhat/thermostat/web/common/CategorySerializationTest.java web/common/src/test/java/com/redhat/thermostat/web/common/SharedStateIdTest.java web/common/src/test/java/com/redhat/thermostat/web/common/WebQueryResponseTest.java web/common/src/test/java/com/redhat/thermostat/web/common/typeadapters/JsonPerformanceTest.java web/common/src/test/java/com/redhat/thermostat/web/common/typeadapters/LegacyGSONConverter.java web/common/src/test/java/com/redhat/thermostat/web/common/typeadapters/LegacyPreparedParameterSerializer.java web/common/src/test/java/com/redhat/thermostat/web/common/typeadapters/LegacyWebPreparedStatementSerializer.java web/common/src/test/java/com/redhat/thermostat/web/common/typeadapters/LegacyWebQueryResponseSerializer.java web/common/src/test/java/com/redhat/thermostat/web/common/typeadapters/PojoTypeAdapterTest.java web/common/src/test/java/com/redhat/thermostat/web/common/typeadapters/PreparedParameterJSONPerformanceTest.java web/common/src/test/java/com/redhat/thermostat/web/common/typeadapters/PreparedParameterTypeAdapterTest.java web/common/src/test/java/com/redhat/thermostat/web/common/typeadapters/PreparedParametersJSONPerformanceTest.java web/common/src/test/java/com/redhat/thermostat/web/common/typeadapters/PreparedParametersTypeAdapterTest.java web/common/src/test/java/com/redhat/thermostat/web/common/typeadapters/SharedStateIdTypeAdapterTest.java web/common/src/test/java/com/redhat/thermostat/web/common/typeadapters/WebPreparedStatementJSONPerformanceTest.java web/common/src/test/java/com/redhat/thermostat/web/common/typeadapters/WebPreparedStatementResponseJSONPerformanceTest.java web/common/src/test/java/com/redhat/thermostat/web/common/typeadapters/WebPreparedStatementResponseTypeAdapterTest.java web/common/src/test/java/com/redhat/thermostat/web/common/typeadapters/WebPreparedStatementTypeAdapterTest.java web/common/src/test/java/com/redhat/thermostat/web/common/typeadapters/WebQueryResponseTypeAdapterTest.java web/pom.xml |
diffstat | 64 files changed, 1 insertions(+), 9524 deletions(-) [+] |
line wrap: on
line diff
--- a/distribution/assembly/core-assembly-macosx.xml Wed May 10 16:01:45 2017 -0400 +++ b/distribution/assembly/core-assembly-macosx.xml Wed May 10 16:02:18 2017 -0400 @@ -65,7 +65,6 @@ <include>com.redhat.thermostat:thermostat-common-portability</include> <include>com.redhat.thermostat:thermostat-process-handler</include> <include>com.redhat.thermostat:thermostat-storage-core</include> - <include>com.redhat.thermostat:thermostat-web-client</include> <include>com.redhat.thermostat:thermostat-system-backend</include> <include>org.osgi:org.osgi.compendium</include> <include>org.apache:org.apache.felix.scr</include>
--- a/distribution/assembly/core-assembly-windows.xml Wed May 10 16:01:45 2017 -0400 +++ b/distribution/assembly/core-assembly-windows.xml Wed May 10 16:02:18 2017 -0400 @@ -65,7 +65,6 @@ <include>com.redhat.thermostat:thermostat-common-portability</include> <include>com.redhat.thermostat:thermostat-process-handler</include> <include>com.redhat.thermostat:thermostat-storage-core</include> - <include>com.redhat.thermostat:thermostat-web-client</include> <include>com.redhat.thermostat:thermostat-system-backend</include> <include>org.osgi:org.osgi.compendium</include> <include>org.apache:org.apache.felix.scr</include>
--- a/distribution/assembly/core-assembly.xml Wed May 10 16:01:45 2017 -0400 +++ b/distribution/assembly/core-assembly.xml Wed May 10 16:02:18 2017 -0400 @@ -65,7 +65,6 @@ <include>com.redhat.thermostat:thermostat-common-portability</include> <include>com.redhat.thermostat:thermostat-process-handler</include> <include>com.redhat.thermostat:thermostat-storage-core</include> - <include>com.redhat.thermostat:thermostat-web-client</include> <include>com.redhat.thermostat:thermostat-system-backend</include> <include>org.osgi:org.osgi.compendium</include> <include>org.apache:org.apache.felix.scr</include>
--- a/distribution/config/commands/agent.properties Wed May 10 16:01:45 2017 -0400 +++ b/distribution/config/commands/agent.properties Wed May 10 16:02:18 2017 -0400 @@ -1,5 +1,4 @@ -bundles = com.redhat.thermostat.web.client=@project.version@, \ - com.redhat.thermostat.agent.cli=@project.version@, \ +bundles = com.redhat.thermostat.agent.cli=@project.version@, \ com.redhat.thermostat.backend.system=@project.version@, \ com.redhat.thermostat.agent.ipc.tcpsocket.server=@project.version@, \ com.redhat.thermostat.process=@project.version@ \
--- a/distribution/pom.xml Wed May 10 16:01:45 2017 -0400 +++ b/distribution/pom.xml Wed May 10 16:02:18 2017 -0400 @@ -483,11 +483,6 @@ </dependency> <dependency> <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-web-client</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>com.redhat.thermostat</groupId> <artifactId>thermostat-system-backend</artifactId> <version>${project.version}</version> </dependency>
--- a/plugins/vm-byteman/common/pom.xml Wed May 10 16:01:45 2017 -0400 +++ b/plugins/vm-byteman/common/pom.xml Wed May 10 16:02:18 2017 -0400 @@ -139,12 +139,6 @@ </dependency> <dependency> <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-web-common</artifactId> - <version>${project.version}</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>com.redhat.thermostat</groupId> <artifactId>thermostat-storage-testutils</artifactId> <version>${project.version}</version> <scope>test</scope>
--- a/plugins/vm-byteman/common/src/test/java/com/redhat/thermostat/vm/byteman/common/BytemanMetricTest.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,106 +0,0 @@ -/* - * Copyright 2012-2017 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.byteman.common; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - -import org.junit.Before; -import org.junit.Test; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.redhat.thermostat.web.common.typeadapters.PojoTypeAdapterFactory; -import com.redhat.thermostat.web.common.typeadapters.PreparedParameterTypeAdapterFactory; -import com.redhat.thermostat.web.common.typeadapters.PreparedParametersTypeAdapterFactory; -import com.redhat.thermostat.web.common.typeadapters.SharedStateIdTypeAdapterFactory; -import com.redhat.thermostat.web.common.typeadapters.WebPreparedStatementResponseTypeAdapterFactory; -import com.redhat.thermostat.web.common.typeadapters.WebPreparedStatementTypeAdapterFactory; -import com.redhat.thermostat.web.common.typeadapters.WebQueryResponseTypeAdapterFactory; - -public class BytemanMetricTest { - - private Gson gson; - - @Before - public void setup() { - gson = new GsonBuilder() - .registerTypeAdapterFactory(new PojoTypeAdapterFactory()) - .registerTypeAdapterFactory(new SharedStateIdTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebPreparedStatementResponseTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebQueryResponseTypeAdapterFactory()) - .registerTypeAdapterFactory(new PreparedParameterTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebPreparedStatementTypeAdapterFactory()) - .registerTypeAdapterFactory(new PreparedParametersTypeAdapterFactory()) - .create(); - } - - @Test - public void isTransformablefromPojo() { - BytemanMetric metric = new BytemanMetric(); - metric.setAgentId("foo-agent"); - metric.setData("{ \"key\": \"value\" }"); - metric.setMarker("foo-marker"); - metric.setTimeStamp(1L); - metric.setVmId("someVmId"); - String json = gson.toJson(metric, BytemanMetric.class); - String expectedJson = "{\"agentId\":\"foo-agent\"," + - "\"data\":\"{ \\\"key\\\": \\\"value\\\" }\"," + - "\"marker\":\"foo-marker\"," + - "\"timeStamp\":1," + - "\"vmId\":\"someVmId\"}"; - assertEquals(expectedJson, json); - } - - @Test - public void isTransformableToPojo() { - String json = "{ \"agentId\":\"foo-agent\"," + - "\"data\": \"{ \\\"key\\\": \\\"value\\\" }\"," + - "\"marker\": \"foo-marker\"," + - "\"timeStamp\":1," + - "\"vmId\":\"someVmId\"}"; - BytemanMetric metric = gson.fromJson(json, BytemanMetric.class); - assertNotNull(metric); - assertEquals("foo-agent", metric.getAgentId()); - assertEquals("foo-marker", metric.getMarker()); - assertEquals(1L, metric.getTimeStamp()); - String expectedData = "{ \"key\": \"value\" }"; - assertEquals(expectedData, metric.getData()); - assertEquals(expectedData, metric.getDataAsJson()); - assertEquals("someVmId", metric.getVmId()); - } -}
--- a/pom.xml Wed May 10 16:01:45 2017 -0400 +++ b/pom.xml Wed May 10 16:02:18 2017 -0400 @@ -340,7 +340,6 @@ <module>common</module> <module>agent</module> <module>process-handler</module> - <module>web</module> <module>system-backend</module> <module>storage</module> <module>thermostat-plugin-validator</module>
--- a/web/client/pom.xml Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,137 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - - Copyright 2012-2017 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. - ---> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> - - <parent> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-web</artifactId> - <version>1.99.12-SNAPSHOT</version> - </parent> - - <artifactId>thermostat-web-client</artifactId> - <packaging>bundle</packaging> - - <name>Thermostat Web Client</name> - - <dependencies> - - <dependency> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.mockito</groupId> - <artifactId>mockito-core</artifactId> - <scope>test</scope> - </dependency> - - <dependency> - <groupId>org.osgi</groupId> - <artifactId>org.osgi.core</artifactId> - <scope>provided</scope> - </dependency> - - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-server</artifactId> - <version>${jetty.version}</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-webapp</artifactId> - <version>${jetty.version}</version> - <scope>test</scope> - </dependency> - - <dependency> - <groupId>com.google.code.gson</groupId> - <artifactId>gson</artifactId> - </dependency> - - <dependency> - <groupId>org.apache.httpcomponents</groupId> - <artifactId>httpclient-osgi</artifactId> - <version>${httpcomponents.client.version}</version> - </dependency> - <!-- httpclient 4.3 needs this bundle, but does only - specify it's dep on it with scope provided --> - <dependency> - <groupId>org.osgi</groupId> - <artifactId>org.osgi.compendium</artifactId> - </dependency> - <dependency> - <groupId>org.apache.httpcomponents</groupId> - <artifactId>httpcore-osgi</artifactId> - <version>${httpcomponents.core.version}</version> - </dependency> - - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-web-common</artifactId> - <version>${project.version}</version> - </dependency> - - </dependencies> - - <build> - <plugins> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <extensions>true</extensions> - <configuration> - <instructions> - <Bundle-SymbolicName>com.redhat.thermostat.web.client</Bundle-SymbolicName> - <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor> - <Bundle-Activator>com.redhat.thermostat.web.client.internal.Activator</Bundle-Activator> - <Private-Package> - com.redhat.thermostat.web.client.internal - </Private-Package> - <!-- Do not autogenerate uses clauses in Manifests --> - <_nouses>true</_nouses> - </instructions> - </configuration> - </plugin> - </plugins> - </build> -</project> -
--- a/web/client/src/main/java/com/redhat/thermostat/web/client/internal/Activator.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -/* - * Copyright 2012-2017 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.client.internal; - -import org.osgi.framework.BundleActivator; -import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceRegistration; - -import com.redhat.thermostat.storage.core.StorageProvider; - -public class Activator implements BundleActivator { - - private ServiceRegistration reg; - - @Override - public void start(BundleContext context) throws Exception { - WebStorageProvider storage = new WebStorageProvider(); - this.reg = context.registerService(StorageProvider.class.getName(), storage, null); - } - - @Override - public void stop(BundleContext context) throws Exception { - reg.unregister(); - } - -} -
--- a/web/client/src/main/java/com/redhat/thermostat/web/client/internal/EntityConsumingIOException.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -/* - * Copyright 2012-2017 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.client.internal; - -import java.io.IOException; - -import org.apache.http.HttpEntity; -import org.apache.http.util.EntityUtils; - -/** - * Should be used for to-be-thrown IOExceptions which need to consume an - * {@link HttpEntity} prior to getting thrown. This avoids resource leaks. - * - */ -class EntityConsumingIOException extends IOException { - - private static final long serialVersionUID = 6822662292793556315L; - - EntityConsumingIOException(HttpEntity entity, String msg) { - super(msg); - consumeEntity(entity); - } - - private void consumeEntity(HttpEntity entity) { - try { - EntityUtils.consume(entity); - } catch (IOException e) { - // ignore, consuming failure since we are about to - // throw an IOException anyway. - } - } - -}
--- a/web/client/src/main/java/com/redhat/thermostat/web/client/internal/ExpirableWebPreparedStatementCache.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,96 +0,0 @@ -/* - * Copyright 2012-2017 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.client.internal; - -import com.redhat.thermostat.storage.core.StatementDescriptor; -import com.redhat.thermostat.storage.model.Pojo; -import com.redhat.thermostat.web.common.SharedStateId; - -/** - * A {@link WebPreparedStatementCache} with an expiration time. When that time - * has passed it will return null for all cache entries. Used as a read-only - * transition cache in {@link WebStorage} in order to recover from server - * component reloads. - * - */ -class ExpirableWebPreparedStatementCache extends WebPreparedStatementCache { - - private final long timeExpires; - private final WebPreparedStatementCache cache; - - ExpirableWebPreparedStatementCache(WebPreparedStatementCache cache, long timeExpires) { - this.timeExpires = timeExpires; - this.cache = cache; - } - - @Override - synchronized <T extends Pojo> WebPreparedStatementHolder get(StatementDescriptor<T> desc) { - WebPreparedStatementHolder holder = cache.get(desc); - if (holder == null) { - return null; - } - // check if corresponding cache entry has expired - long now = System.nanoTime(); - if (now > timeExpires) { - // remove cache entry and return null - SharedStateId id = holder.getStatementId(); - cache.remove(id); - return null; - } - return holder; - } - - @Override - synchronized <T extends Pojo> StatementDescriptor<T> get(SharedStateId id) { - StatementDescriptor<T> desc = cache.get(id); - if (desc == null) { - return null; - } - long now = System.nanoTime(); - if (now > timeExpires) { - // remove cache entry and return null - cache.remove(id); - return null; - } - return desc; - } - - boolean isExpired() { - return System.nanoTime() > timeExpires; - } - -}
--- a/web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebCursor.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,127 +0,0 @@ -/* - * Copyright 2012-2017 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.client.internal; - -import java.lang.reflect.Type; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.redhat.thermostat.common.utils.LoggingUtils; -import com.redhat.thermostat.storage.core.BasicBatchCursor; -import com.redhat.thermostat.storage.core.StorageException; -import com.redhat.thermostat.storage.model.Pojo; -import com.redhat.thermostat.web.common.PreparedStatementResponseCode; -import com.redhat.thermostat.web.common.WebPreparedStatement; -import com.redhat.thermostat.web.common.WebQueryResponse; - -import java.util.NoSuchElementException; - -class WebCursor<T extends Pojo> extends BasicBatchCursor<T> { - - private static final Logger logger = LoggingUtils.getLogger(WebCursor.class); - - private final Type parametrizedTypeToken; - private final WebStorage storage; - private final int cursorId; - private final WebPreparedStatement<T> stmt; - private int batchIndex; - private T[] dataBatch; - private boolean hasMoreBatches; - - // Main constructor called from doQueryExecute() - WebCursor(WebStorage storage, T[] dataBatch, boolean hasMoreBatches, int cursorId, Type parametrizedTypeToken, WebPreparedStatement<T> stmt) { - this.storage = storage; - this.cursorId = cursorId; - this.parametrizedTypeToken = parametrizedTypeToken; - this.stmt = stmt; - this.hasMoreBatches = hasMoreBatches; - this.dataBatch = dataBatch; - this.batchIndex = 0; - } - - @Override - public boolean hasNext() { - return batchIndex < dataBatch.length || hasMoreBatches; - } - - @Override - public T next() { - if (batchIndex >= dataBatch.length && !hasMoreBatches) { - throw new NoSuchElementException(); - } - T result = null; - // Check if we have still results left in batch, - // if not fetch a new batch. - if (batchIndex >= dataBatch.length) { - assert(hasMoreBatches); - // This updates batchIndex, dataBatch and - // hasMoreBatches - fetchBatchFromStorage(); - assert(batchIndex == 0); - assert(dataBatch.length > 0); - } - result = dataBatch[batchIndex]; - batchIndex++; - return result; - } - - private void fetchBatchFromStorage() throws StorageException { - logger.log(Level.FINEST, "Getting more results for cursorId: " + cursorId); - WebQueryResponse<T> nextBatchResponse = storage.getMore(cursorId, parametrizedTypeToken, getBatchSize(), stmt); - switch(nextBatchResponse.getResponseCode()) { - case PreparedStatementResponseCode.QUERY_SUCCESS: - this.batchIndex = 0; - this.hasMoreBatches = nextBatchResponse.hasMoreBatches(); - this.dataBatch = nextBatchResponse.getResultList(); - break; - case PreparedStatementResponseCode.GET_MORE_NULL_CURSOR: - // Advise user about potentially timed-out cursor - String msg = "[get-more] Failed to get more results for cursorId: " + cursorId + - " This may be caused because the cursor timed out." + - " Resubmitting the original query might be an approach to fix it." + - " See server logs for more details."; - throw new StorageException(msg); - default: - msg = "[get-more] Failed to get more results for cursorId: " + cursorId + - ". See server logs for details."; - throw new StorageException(msg); - } - } - -} -
--- a/web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebPreparedStatementCache.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,98 +0,0 @@ -/* - * Copyright 2012-2017 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.client.internal; - -import java.util.Map; -import java.util.WeakHashMap; - -import com.redhat.thermostat.storage.core.StatementDescriptor; -import com.redhat.thermostat.storage.model.Pojo; -import com.redhat.thermostat.web.common.SharedStateId; -import com.redhat.thermostat.web.common.WebPreparedStatement; - -/** - * A simple implementation of a cache for {@link WebPreparedStatement} - * in order to avoid unnecessary network round-trips if a statement - * has already been prepared and it's not out-of-sync with the server. - */ -class WebPreparedStatementCache { - - private final Map<StatementDescriptor<?>, WebPreparedStatementHolder> stmtCache; - private final Map<SharedStateId, StatementDescriptor<?>> reverseLookup; - - WebPreparedStatementCache() { - stmtCache = new WeakHashMap<>(); - reverseLookup = new WeakHashMap<>(); - } - - synchronized <T extends Pojo> void put(StatementDescriptor<T> desc, WebPreparedStatementHolder holder) { - SharedStateId id = holder.getStatementId(); - stmtCache.put(desc, holder); - reverseLookup.put(id, desc); - } - - synchronized <T extends Pojo> WebPreparedStatementHolder get(StatementDescriptor<T> desc) { - return stmtCache.get(desc); - } - - @SuppressWarnings("unchecked") - synchronized <T extends Pojo> StatementDescriptor<T> get(SharedStateId id) { - return (StatementDescriptor<T>)reverseLookup.get(id); - } - - synchronized void remove(SharedStateId id) { - StatementDescriptor<?> desc = reverseLookup.get(id); - if (desc != null) { - stmtCache.remove(desc); - } - reverseLookup.remove(id); - } - - /** - * Creates a snapshot of the current state of this cache. - * - * @return A copied snapshot of this cache. - */ - synchronized WebPreparedStatementCache createSnapshot() { - WebPreparedStatementCache copy = new WebPreparedStatementCache(); - for (StatementDescriptor<?> desc: stmtCache.keySet()) { - copy.put(desc, stmtCache.get(desc)); - } - return copy; - } - -} \ No newline at end of file
--- a/web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebPreparedStatementHolder.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +0,0 @@ -/* - * Copyright 2012-2017 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.client.internal; - -import java.lang.reflect.Type; - -import com.redhat.thermostat.web.common.SharedStateId; - -/** - * Container used for parameter caching in order to avoid unneccessary - * network overhead. - * - * @see {@link WebStorage} - * @see {@link WebPreparedStatementCache} - * - */ -class WebPreparedStatementHolder { - - private final Type typeToken; - private final int numParams; - private final SharedStateId statementId; - - WebPreparedStatementHolder(Type typeToken, int numParams, SharedStateId statementId) { - this.typeToken = typeToken; - this.numParams = numParams; - this.statementId = statementId; - } - - Type getTypeToken() { - return typeToken; - } - - int getNumParams() { - return numParams; - } - - SharedStateId getStatementId() { - return statementId; - } -} \ No newline at end of file
--- a/web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebStorage.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1032 +0,0 @@ -/* - * Copyright 2012-2017 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.client.internal; - -import java.io.Closeable; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.Reader; -import java.lang.reflect.Type; -import java.net.MalformedURLException; -import java.net.URL; -import java.security.SecureRandom; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.TimeUnit; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.net.ssl.SSLContext; - -import org.apache.commons.codec.binary.Base64; -import org.apache.http.Header; -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.NameValuePair; -import org.apache.http.StatusLine; -import org.apache.http.auth.AuthSchemeProvider; -import org.apache.http.auth.AuthScope; -import org.apache.http.auth.Credentials; -import org.apache.http.auth.UsernamePasswordCredentials; -import org.apache.http.client.HttpClient; -import org.apache.http.client.config.AuthSchemes; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.client.protocol.HttpClientContext; -import org.apache.http.config.Lookup; -import org.apache.http.config.Registry; -import org.apache.http.config.RegistryBuilder; -import org.apache.http.conn.socket.ConnectionSocketFactory; -import org.apache.http.conn.socket.PlainConnectionSocketFactory; -import org.apache.http.conn.ssl.SSLConnectionSocketFactory; -import org.apache.http.entity.mime.MultipartEntityBuilder; -import org.apache.http.entity.mime.content.InputStreamBody; -import org.apache.http.impl.auth.BasicSchemeFactory; -import org.apache.http.impl.client.BasicCredentialsProvider; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; -import org.apache.http.message.BasicNameValuePair; -import org.apache.http.util.EntityUtils; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.redhat.thermostat.common.ssl.SSLContextFactory; -import com.redhat.thermostat.common.ssl.SslInitException; -import com.redhat.thermostat.common.utils.LoggingUtils; -import com.redhat.thermostat.shared.config.SSLConfiguration; -import com.redhat.thermostat.storage.core.AuthToken; -import com.redhat.thermostat.storage.core.Categories; -import com.redhat.thermostat.storage.core.Category; -import com.redhat.thermostat.storage.core.Connection; -import com.redhat.thermostat.storage.core.Cursor; -import com.redhat.thermostat.storage.core.DescriptorParsingException; -import com.redhat.thermostat.storage.core.IllegalDescriptorException; -import com.redhat.thermostat.storage.core.IllegalPatchException; -import com.redhat.thermostat.storage.core.PreparedStatement; -import com.redhat.thermostat.storage.core.SaveFileListener; -import com.redhat.thermostat.storage.core.SecureStorage; -import com.redhat.thermostat.storage.core.StatementDescriptor; -import com.redhat.thermostat.storage.core.StatementExecutionException; -import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.core.StorageCredentials; -import com.redhat.thermostat.storage.core.StorageException; -import com.redhat.thermostat.storage.core.SaveFileListener.EventType; -import com.redhat.thermostat.storage.model.AggregateResult; -import com.redhat.thermostat.storage.model.Pojo; -import com.redhat.thermostat.web.common.PreparedStatementResponseCode; -import com.redhat.thermostat.web.common.SharedStateId; -import com.redhat.thermostat.web.common.WebPreparedStatement; -import com.redhat.thermostat.web.common.WebPreparedStatementResponse; -import com.redhat.thermostat.web.common.WebQueryResponse; -import com.redhat.thermostat.web.common.typeadapters.PojoTypeAdapterFactory; -import com.redhat.thermostat.web.common.typeadapters.PreparedParameterTypeAdapterFactory; -import com.redhat.thermostat.web.common.typeadapters.PreparedParametersTypeAdapterFactory; -import com.redhat.thermostat.web.common.typeadapters.SharedStateIdTypeAdapterFactory; -import com.redhat.thermostat.web.common.typeadapters.WebPreparedStatementResponseTypeAdapterFactory; -import com.redhat.thermostat.web.common.typeadapters.WebPreparedStatementTypeAdapterFactory; -import com.redhat.thermostat.web.common.typeadapters.WebQueryResponseTypeAdapterFactory; - -public class WebStorage implements Storage, SecureStorage { - - private static final int STATUS_OK = 200; - private static final int STATUS_NO_CONTENT = 204; - - private static final String HTTP_PREFIX = "http"; - private static final String HTTPS_PREFIX = "https"; - - // Transition cache is valid for 30 seconds starting from the current time. - private static final long TRANSITION_CACHE_OFFSET = TimeUnit.NANOSECONDS.convert(30, TimeUnit.SECONDS); - - static final Logger logger = LoggingUtils.getLogger(WebStorage.class); - - private static class CloseableHttpEntity implements Closeable, HttpEntity { - - private HttpEntity entity; - private int responseCode; - - CloseableHttpEntity(HttpEntity entity, int responseCode) { - this.entity = entity; - this.responseCode = responseCode; - } - - @Override - public void consumeContent() throws IOException { - EntityUtils.consume(entity); - } - - @Override - public InputStream getContent() throws IOException, - IllegalStateException { - return entity.getContent(); - } - - @Override - public Header getContentEncoding() { - return entity.getContentEncoding(); - } - - @Override - public long getContentLength() { - return entity.getContentLength(); - } - - @Override - public Header getContentType() { - return entity.getContentType(); - } - - @Override - public boolean isChunked() { - return entity.isChunked(); - } - - @Override - public boolean isRepeatable() { - return entity.isRepeatable(); - } - - @Override - public boolean isStreaming() { - return entity.isStreaming(); - } - - @Override - public void writeTo(OutputStream out) throws IOException { - entity.writeTo(out); - } - - @Override - public void close() { - try { - EntityUtils.consume(entity); - } catch (IOException ex) { - throw new StorageException(ex); - } - } - - int getResponseCode() { - return responseCode; - } - } - - private final class WebConnection extends Connection { - WebConnection() { - connected = true; - } - - @Override - public void disconnect() { - connected = false; - setUsername(Connection.UNSET_USERNAME); - fireChanged(ConnectionStatus.DISCONNECTED); - } - - @Override - public void connect() { - try { - initAuthentication(); - ping(); - connected = true; - logger.fine("Connected to storage"); - fireChanged(ConnectionStatus.CONNECTED); - } catch (Exception ex) { - logger.log(Level.WARNING, "Could not connect to storage!", ex); - setUsername(Connection.UNSET_USERNAME); - fireChanged(ConnectionStatus.FAILED_TO_CONNECT); - } - } - - private void initAuthentication() - throws MalformedURLException { - String username = creds.getUsername(); - setUsername(username); - char[] password = creds.getPassword(); - if (username != null && password != null) { - URL endpointURL = new URL(endpoint); - BasicCredentialsProvider credsProvider = new BasicCredentialsProvider(); - // FIXME Password as string? BAD. Limited by apache API here however. - Credentials creds = new UsernamePasswordCredentials(username, - new String(password)); - Arrays.fill(password, '\0'); - AuthScope scope = new AuthScope(endpointURL.getHost(), - endpointURL.getPort(), "Thermostat Realm"); - credsProvider.setCredentials(scope, creds); - synchronized (httpClientContextLock) { - httpClientContext.setCredentialsProvider(credsProvider); - } - } - } - - @Override - public void setUrl(String url) { - super.setUrl(url); - endpoint = url; - } - - @Override - public String getUrl() { - return endpoint; - } - } - - private static class WebDataStream extends InputStream { - - private CloseableHttpEntity entity; - private InputStream content; - - WebDataStream(CloseableHttpEntity entity) { - this.entity = entity; - try { - content = entity.getContent(); - } catch (IllegalStateException | IOException e) { - throw new StorageException(e); - } - } - - @Override - public void close() throws IOException { - content.close(); - entity.close(); - } - - @Override - public int read() throws IOException { - return content.read(); - } - - @Override - public int available() throws IOException { - return content.available(); - } - - @Override - public void mark(int readlimit) { - content.mark(readlimit); - } - - @Override - public boolean markSupported() { - return content.markSupported(); - } - - @Override - public int read(byte[] b) throws IOException { - return content.read(b); - } - - @Override - public int read(byte[] b, int off, int len) throws IOException { - return content.read(b, off, len); - } - - @Override - public void reset() throws IOException { - content.reset(); - } - - @Override - public long skip(long n) throws IOException { - return content.skip(n); - } - - } - - private class WebPreparedStatementImpl<T extends Pojo> extends WebPreparedStatement<T> { - - // The type of the query result objects we'd get back upon - // statement execution - private final transient Type parametrizedTypeToken; - - public WebPreparedStatementImpl(Type parametrizedTypeToken, int numParams, SharedStateId statementId) { - super(numParams, statementId); - this.parametrizedTypeToken = parametrizedTypeToken; - } - - @Override - public int execute() throws StatementExecutionException { - return doWriteExecute(this, 0); - } - - @Override - public Cursor<T> executeQuery() - throws StatementExecutionException { - return doExecuteQuery(this, parametrizedTypeToken, 0); - } - - } - - private String endpoint; - - private Map<Category<?>, SharedStateId> categoryIds; - private Gson gson; - // The shared http client we use for execution (uses the context below) - private HttpClient httpClient; - private Object httpClientContextLock = new Object(); - // Http client execution context. Protected via clientContext lock. - private HttpClientContext httpClientContext; - private StorageCredentials creds; - private SecureRandom random; - private WebConnection conn; - private WebPreparedStatementCache stmtCache; - // Temporary cache used for recovering after a server endpoint re-deployment. - // Will only be valid for 30 seconds for any server endpoint re-deployment. - private ExpirableWebPreparedStatementCache transitionStmtCache; - - // for testing - WebStorage(String url, StorageCredentials creds, HttpClient client) { - init(url, creds, client); - } - - // for testing - WebStorage(WebPreparedStatementCache stmtCache, ExpirableWebPreparedStatementCache transitionCache) { - this.stmtCache = stmtCache; - this.transitionStmtCache = transitionCache; - } - - // for testing - WebStorage(Map<Category<?>, SharedStateId> categoryIds) { - this.categoryIds = categoryIds; - } - - public WebStorage(String url, StorageCredentials creds, SSLConfiguration sslConf) throws StorageException { - PoolingHttpClientConnectionManager connManager = getPoolingHttpClientConnManager(sslConf, url); - HttpClientBuilder builder = HttpClients.custom(); - Lookup<AuthSchemeProvider> authProviders = RegistryBuilder.<AuthSchemeProvider>create() - .register(AuthSchemes.BASIC, new BasicSchemeFactory()) - .build(); - // Set up client with default basic-auth scheme and pooled - // connection manager. - HttpClient client = builder.setConnectionManager(connManager) - .setDefaultAuthSchemeRegistry(authProviders) - .build(); - init(url, creds, client); - } - - private void init(String url, StorageCredentials creds, HttpClient client) { - categoryIds = new HashMap<>(); - gson = new GsonBuilder() - .registerTypeAdapterFactory(new PojoTypeAdapterFactory()) - .registerTypeAdapterFactory(new SharedStateIdTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebPreparedStatementResponseTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebQueryResponseTypeAdapterFactory()) - .registerTypeAdapterFactory(new PreparedParameterTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebPreparedStatementTypeAdapterFactory()) - .registerTypeAdapterFactory(new PreparedParametersTypeAdapterFactory()) - .create(); - httpClient = client; - synchronized (httpClientContextLock) { - httpClientContext = HttpClientContext.create(); - } - random = new SecureRandom(); - conn = new WebConnection(); - - this.endpoint = url; - this.creds = creds; - this.stmtCache = new WebPreparedStatementCache(); - } - - // package private for testing - PoolingHttpClientConnectionManager getPoolingHttpClientConnManager(SSLConfiguration sslConf, String url) - throws StorageException { - ConnectionSocketFactory plainsf = new PlainConnectionSocketFactory(); - RegistryBuilder<ConnectionSocketFactory> regBuilder = RegistryBuilder.<ConnectionSocketFactory>create() - .register(HTTP_PREFIX, plainsf); - try { - // setup SSL if necessary - if (url.startsWith(HTTPS_PREFIX)) { - SSLContext sc = SSLContextFactory.getClientContext(sslConf); - SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sc); - regBuilder = regBuilder.register(HTTPS_PREFIX, socketFactory); - } - } catch ( SslInitException e) { - throw new StorageException(e); - } - Registry<ConnectionSocketFactory> r = regBuilder.build(); - return new PoolingHttpClientConnectionManager(r); - } - - private void ping() throws StorageException { - post(endpoint + "/ping", (HttpEntity) null).close(); - } - - private CloseableHttpEntity post(String url, List<NameValuePair> formparams) - throws StorageException { - try { - return postImpl(url, formparams); - } catch (IOException ex) { - throw new StorageException(ex); - } - } - - private CloseableHttpEntity postImpl(String url, - List<NameValuePair> formparams) throws IOException { - HttpEntity entity; - if (formparams != null) { - entity = new UrlEncodedFormEntity(formparams, "UTF-8"); - } else { - entity = null; - } - return postImpl(url, entity); - } - - private CloseableHttpEntity post(String url, HttpEntity entity) - throws StorageException { - try { - return postImpl(url, entity, null); - } catch (IOException ex) { - throw new StorageException(ex); - } - } - - private CloseableHttpEntity post(String url, HttpEntity entity, RequestConfig config) - throws StorageException { - try { - return postImpl(url, entity, config); - } catch (IOException ex) { - throw new StorageException(ex); - } - } - - private CloseableHttpEntity postImpl(String url, HttpEntity entity, RequestConfig config) - throws IOException { - HttpPost httpPost = new HttpPost(url); - if (entity != null) { - httpPost.setEntity(entity); - } - HttpResponse response = null; - // The client context is not thread-safe. Thus protect execution - // via the client context lock. - synchronized(httpClientContextLock) { - RequestConfig oldConfig = httpClientContext.getRequestConfig(); - if (config != null) { - httpClientContext.setRequestConfig(config); - } - try { - response = httpClient.execute(httpPost, httpClientContext); - } catch (Throwable e) { - throw e; - } finally { - if (config != null) { - httpClientContext.setRequestConfig(oldConfig); - } - } - } - StatusLine status = response.getStatusLine(); - int responseCode = status.getStatusCode(); - switch (responseCode) { - case (STATUS_NO_CONTENT): - // Let calling code handle STATUS_NO_CONTENT - break; - case (STATUS_OK): - // Let calling code handle STATUS_OK - break; - default: - // Properly consume the entity, thus closing the content stream, - // by throwing this IOException sub-class. This is important for the - // 403 and 500 status code cases. See: - // http://hc.apache.org/httpcomponents-core-4.3.x/httpcore/apidocs/org/apache/http/util/EntityUtils.html#consume%28org.apache.http.HttpEntity%29 - throw new EntityConsumingIOException(response.getEntity(), - "Server returned status: " + status); - } - - return new CloseableHttpEntity(response.getEntity(), responseCode); - } - - private CloseableHttpEntity postImpl(String url, HttpEntity entity) - throws StorageException { - try { - return postImpl(url, entity, null); - } catch (IOException ex) { - throw new StorageException(ex); - } - } - - private static InputStream getContent(HttpEntity entity) { - try { - return entity.getContent(); - } catch (IOException ex) { - throw new StorageException(ex); - } - } - - private static Reader getContentAsReader(HttpEntity entity) { - InputStream in = getContent(entity); - return new InputStreamReader(in); - } - - @Override - public void registerCategory(Category<?> category) throws StorageException { - NameValuePair nameParam = new BasicNameValuePair("name", - category.getName()); - NameValuePair dataClassParam = new BasicNameValuePair("data-class", - category.getDataClass().getName()); - - NameValuePair categoryParam = new BasicNameValuePair("category", - gson.toJson(category)); - List<NameValuePair> formparams = Arrays - .asList(nameParam, categoryParam, dataClassParam); - try (CloseableHttpEntity entity = post(endpoint + "/register-category", - formparams)) { - Reader reader = getContentAsReader(entity); - SharedStateId id = gson.fromJson(reader, SharedStateId.class); - categoryIds.put(category, id); - } - } - - /** - * Executes a prepared query - * - * @param stmt - * The prepared statement to execute - * @param parametrizedTypeToken - * The parametrized type token to use for deserialization. - * Example as to how this was created: - * <pre> - * Type parametrizedTypeToken = new - * TypeToken<WebQueryResponse<AgentInformation>>().getType(); - * </pre> - * @param invocationCount The number of recursive invocations performed so far. - * @return A cursor for the generic type. - * @throws StatementExecutionException - * If execution of the statement failed. In particular, if - * the state got out of sync, it tried to recover and then - * failed again. - */ - <T extends Pojo> Cursor<T> doExecuteQuery(final WebPreparedStatement<T> stmt, Type parametrizedTypeToken, final int invocationCount) throws StatementExecutionException { - checkRecursiveInvocationCount(invocationCount); - NameValuePair queryParam = new BasicNameValuePair("prepared-stmt", gson.toJson(stmt, WebPreparedStatement.class)); - List<NameValuePair> formparams = Arrays.asList(queryParam); - WebQueryResponse<T> qResp = null; - try (CloseableHttpEntity entity = post(endpoint + "/query-execute", formparams)) { - Reader reader = getContentAsReader(entity); - qResp = gson.fromJson(reader, parametrizedTypeToken); - } catch (Exception e) { - throw new StatementExecutionException(e); - } - switch(qResp.getResponseCode()) { - case PreparedStatementResponseCode.QUERY_SUCCESS: - return new WebCursor<T>(this, qResp.getResultList(), - qResp.hasMoreBatches(), - qResp.getCursorId(), parametrizedTypeToken, stmt); - case PreparedStatementResponseCode.ILLEGAL_PATCH: { - String msg = "Illegal statement argument. See server logs for details."; - IllegalArgumentException iae = new IllegalArgumentException(msg); - IllegalPatchException e = new IllegalPatchException(iae); - throw new StatementExecutionException(e); - } - case PreparedStatementResponseCode.PREP_STMT_BAD_STOKEN: { - // Try to recover from this situation. If this path is - // entered more than once than we'll fail on method entry. - try { - WebPreparedStatement<T> newStmt = handlePreparedStmtStateOutOfSync(stmt); - return doExecuteQuery(newStmt, parametrizedTypeToken, invocationCount + 1); - } catch (DescriptorParsingException e) { - throw new StatementExecutionException(e); - } - } - default: { - String msg = "[query-execute] Unknown response from storage endpoint!"; - IllegalStateException ise = new IllegalStateException(msg); - throw new StatementExecutionException(ise); - } - } - } - - private void checkRecursiveInvocationCount(int invocationCount) throws StatementExecutionException { - if (invocationCount > 1) { - // Initial invokation == 0, potential recovery-invocation == 1 - String msg = "Failed to recover from out-of-sync state with server"; - logger.log(Level.WARNING, msg); - throw new StatementExecutionException(new IllegalStateException(msg)); - } - } - - /** - * This method gets called from WebCursor in order to fetch more results - * or refresh the result set since parameters like limit or skip have - * changed since the original result set was fetched. - * - * @param cursorId - * @param parametrizedTypeToken The type token for the data class (Pojo). - * @param batchSize The desired batchSize or null. null means that the user - * did not set an explicit batch size. - * @param limit The desired limit for this cursor or null. null means that - * a user did not set an explicit limit. - * @param skip The desired skip value or null. null means no skip value has - * been specified by the user. - * @return - */ - <T extends Pojo> WebQueryResponse<T> getMore(int cursorId, Type parametrizedTypeToken, Integer batchSize, WebPreparedStatement<T> stmt) { - String stmtId = gson.toJson(stmt.getStatementId()); - NameValuePair preparedStmtIdParam = new BasicNameValuePair("prepared-stmt-id", stmtId); - NameValuePair cursorIdParam = new BasicNameValuePair("cursor-id", Integer.toString(cursorId)); - NameValuePair batchSizeParam = new BasicNameValuePair("batch-size", batchSize.toString()); - - List<NameValuePair> formparams = Arrays.asList(preparedStmtIdParam, - cursorIdParam, - batchSizeParam); - WebQueryResponse<T> qResp = null; - try (CloseableHttpEntity entity = post(endpoint + "/get-more", formparams)) { - Reader reader = getContentAsReader(entity); - qResp = gson.fromJson(reader, parametrizedTypeToken); - } catch (Exception e) { - throw new StorageException(e); - } - return qResp; - } - - /** - * Executes a prepared write - * - * @param stmt - * The prepared statement to execute - * @param invocationCount - * The number of times this method has been recursively called, - * starting at 0. - * @return The response code of executing the underlying data modifying - * statement. - * @throws StatementExecutionException - * If execution of the statement failed. For example if the - * values set as prepared parameters did not work or were - * partially missing for the prepared statement. - */ - <T extends Pojo> int doWriteExecute(final WebPreparedStatement<T> stmt, final int invocationCount) - throws StatementExecutionException { - checkRecursiveInvocationCount(invocationCount); - NameValuePair queryParam = new BasicNameValuePair("prepared-stmt", gson.toJson(stmt, WebPreparedStatement.class)); - List<NameValuePair> formparams = Arrays.asList(queryParam); - int responseCode = PreparedStatementResponseCode.WRITE_GENERIC_FAILURE; - try (CloseableHttpEntity entity = post(endpoint + "/write-execute", formparams)) { - Reader reader = getContentAsReader(entity); - responseCode = gson.fromJson(reader, int.class); - } catch (Exception e) { - throw new StatementExecutionException(e); - } - if (responseCode == PreparedStatementResponseCode.ILLEGAL_PATCH) { - String msg = "Illegal statement argument. See server logs for details. Invokation count: " + invocationCount; - IllegalArgumentException iae = new IllegalArgumentException(msg); - IllegalPatchException e = new IllegalPatchException(iae); - throw new StatementExecutionException(e); - } else if (responseCode == PreparedStatementResponseCode.PREP_STMT_BAD_STOKEN) { - // Try to recover from this situation. If this path is - // entered more than once than we'll fail on method entry. - try { - WebPreparedStatement<T> newStmt = handlePreparedStmtStateOutOfSync(stmt); - return doWriteExecute(newStmt, invocationCount + 1); - } catch (DescriptorParsingException e) { - throw new StatementExecutionException(e); - } - } - return responseCode; - } - - @Override - public Connection getConnection() { - return conn; - } - - @Override - public InputStream loadFile(String name) throws StorageException { - NameValuePair fileParam = new BasicNameValuePair("file", name); - List<NameValuePair> formparams = Arrays.asList(fileParam); - CloseableHttpEntity entity = post(endpoint + "/load-file", formparams); - if (entity.getResponseCode() == STATUS_NO_CONTENT) { - return null; - } - return new WebDataStream(entity); - } - - @Override - public void saveFile(String filename, InputStream data, SaveFileListener listener) { - Objects.requireNonNull(listener); - StorageException exceptionIfAny = null; - - try { - doSave(filename, data); - } catch (StorageException e) { - exceptionIfAny = e; - } - - if (exceptionIfAny != null) { - listener.notify(EventType.EXCEPTION_OCCURRED, exceptionIfAny); - } else { - listener.notify(EventType.SAVE_COMPLETE, null); - } - } - - private void doSave(String name, InputStream in) throws StorageException { - InputStreamBody body = new InputStreamBody(in, name); - MultipartEntityBuilder builder = MultipartEntityBuilder.create(); - HttpEntity mpEntity = builder.addPart("file", body).build(); - // See IcedTea bug #1314. For safe-file we need to do this: - // setExcpectContinueEnabled. However, - // doing this for other actions messes up authentication when using - // jetty (and possibly others). Hence, do this expect-continue thingy - // only for save-file. We achieve this via a single request configuration. - RequestConfig config = RequestConfig.custom().setExpectContinueEnabled(true).build(); - post(endpoint + "/save-file", mpEntity, config).close(); - } - - @Override - public void purge(String agentId) throws StorageException { - NameValuePair agentIdParam = new BasicNameValuePair("agentId", agentId); - List<NameValuePair> agentIdParams = Arrays.asList(agentIdParam); - post(endpoint + "/purge", agentIdParams).close(); - } - - @Override - public AuthToken generateToken(String actionName) throws StorageException { - byte[] clientToken = new byte[256]; - random.nextBytes(clientToken); - NameValuePair clientTokenParam = new BasicNameValuePair("client-token", Base64.encodeBase64String(clientToken)); - NameValuePair actionNameParam = new BasicNameValuePair("action-name", - Objects.requireNonNull(actionName)); - List<NameValuePair> formparams = Arrays.asList(clientTokenParam, actionNameParam); - try (CloseableHttpEntity entity = post(endpoint + "/generate-token", formparams)) { - byte[] authToken = EntityUtils.toByteArray(entity); - return new AuthToken(authToken, clientToken); - } catch (IOException ex) { - throw new StorageException(ex); - } - } - - @Override - public boolean verifyToken(AuthToken authToken, String actionName) { - byte[] clientToken = authToken.getClientToken(); - byte[] token = authToken.getToken(); - NameValuePair clientTokenParam = new BasicNameValuePair("client-token", Base64.encodeBase64String(clientToken)); - NameValuePair tokenParam = new BasicNameValuePair("token", Base64.encodeBase64String(token)); - NameValuePair actionNameParam = new BasicNameValuePair("action-name", - Objects.requireNonNull(actionName)); - List<NameValuePair> formparams = Arrays.asList(clientTokenParam, - tokenParam, actionNameParam); - HttpResponse response = null; - try { - HttpEntity entity = new UrlEncodedFormEntity(formparams, "UTF-8"); - HttpPost httpPost = new HttpPost(endpoint + "/verify-token"); - httpPost.setEntity(entity); - synchronized (httpClientContextLock) { - response = httpClient.execute(httpPost, httpClientContext); - } - StatusLine status = response.getStatusLine(); - return status.getStatusCode() == STATUS_OK; - } catch (IOException ex) { - throw new StorageException(ex); - } finally { - if (response != null) { - try { - EntityUtils.consume(response.getEntity()); - } catch (IOException ex) { - throw new StorageException(ex); - } - } - } - } - - @Override - public void shutdown() { - // Nothing to do here. - } - - SharedStateId getCategoryId(Category<?> category) { - return categoryIds.get(category); - } - - /** - * Package private for testing - * - * This method handles the recovery mechanism which needs to be done before - * an already failed {@link WebPreparedStatement} can be re-submitted - * because some state maintained in the client (here) and on the server - * need to be in agreement. - * - * Here is how the recovery mechanism works: - * - * Pre: client and server agree on an ID for every statement. Any single - * statement is uniquely identifiable via the (server-token, int-id) - * pair. When this method is called we already know that when we first - * tried to execute the statement we had an out-dated server-token in - * record. Thus, we need to refresh the local cache with updated - * statement IDs. - * - * Getting the local cache back in sync can be done by: - * 1. Removing the old values from the current statement cache and - * 2. Re-registering the underlying category and re-preparing the statement - * - * The above two steps will be done once per statement descriptor. This will - * update the statement cache accordingly. However, since there may be other - * statements in the local queue waiting to be executed. Those pending - * statements still have old statement IDs in record. This is where the - * transition cache comes into play. There is no need to re-register categories - * and re-prepare statements for the same descriptor. It was already done - * once and the main statement cache updated accordingly. The transition cache is then used - * to get the descriptor from an old statement ID. I.e. whenever the transition - * cache is used it is no longer equal to the main statement cache. In a way - * the transition cache is a tool to get a descriptor for an now out-dated - * statement ID. Once we have the descriptor again we can look it up in the - * regular statement cache in (which has been updated previously) in order - * to get the updated values for the statement ID. - * - * @param origStmt The original statement that failed to execute. - * @return A fixed-up statement which should succeed to execute if tried - * again. - * @throws DescriptorParsingException If re-preparing a statement failed. - */ - synchronized <T extends Pojo> WebPreparedStatement<T> handlePreparedStmtStateOutOfSync(final WebPreparedStatement<T> origStmt) throws DescriptorParsingException { - SharedStateId id = origStmt.getStatementId(); - String msg = "Prepared statement failed to execute. Server changed token. Trying to recover stmt with id: " + id; - logger.log(Level.FINE, msg); - // Transition stmt cache needs to be created in 2 cases: - // 1. It might be null if it was the first time the server - // re-deployed. - // 2. The server did re-deploy at least once and the time it happened - // is more than TRANSITION_CACHE_OFFSET in the past. Case for - // multiple re-deployments of the server parts. - if (transitionStmtCache == null || transitionStmtCache.isExpired()) { - // Create a transition cache which expires soon in the future - // in order to allow successful executions of queued statements which - // did not yet run and have old statement IDs in record. - logger.log(Level.FINE, "Re-creating transition cache"); - WebPreparedStatementCache cacheSnapshot = stmtCache.createSnapshot(); - long timeExpires = System.nanoTime() + TRANSITION_CACHE_OFFSET; - transitionStmtCache = new ExpirableWebPreparedStatementCache(cacheSnapshot, timeExpires); - } - StatementDescriptor<T> desc = stmtCache.get(id); - // If the above returned null we most likely tried to execute a statement - // with an old server token. Attempt to use the transition cache in order - // to still be able to execute it successfully. - if (desc == null) { - desc = transitionStmtCache.get(id); - if (desc == null) { - throw new IllegalStateException("Irrecoverable error. GC happened or transition cache expired."); - } - WebPreparedStatementHolder transCacheHolder = transitionStmtCache.get(desc); - WebPreparedStatementHolder cacheHolder = stmtCache.get(desc); - if (transCacheHolder.getStatementId().equals(cacheHolder.getStatementId())) { - throw new IllegalStateException("Should not happen!"); - } - // Transition case: - // - // Fetch the new mapping from the stmt cache since the statement id - // must have changed but category-registration and preparing the - // updated statement was done already. - SharedStateId stmtId = cacheHolder.getStatementId(); - logger.log(Level.FINE, "Returning fixed-up statement using updated statement id: " + stmtId); - origStmt.setStatementId(stmtId); - return origStmt; - } - // Base case: re-register category and re-prepare statement. This will - // be done *once* for every statement. - logger.log(Level.FINE, "Re-register category + prepareStatement + setting params: " + desc); - sendCategoryReRegistrationRequest(desc.getCategory()); - stmtCache.remove(id); - // prepareStatement() will return a raw statement (no parameters will be - // set in this new datastructure). In order to make it executable right - // away we need to set the params via the params we have in record in the - // original stmt. - WebPreparedStatement<T> newStmt = (WebPreparedStatement<T>)prepareStatement(desc); - newStmt.setParams(origStmt.getParams()); - return newStmt; - } - - @Override - public <T extends Pojo> PreparedStatement<T> prepareStatement(StatementDescriptor<T> desc) - throws DescriptorParsingException { - /* - * Avoid two network round-trips for statements which have already - * been prepared. Note that this makes preparing statements not entirely - * stateless, since the prepared statement ID might change if the - * web endpoint reloads. If those IDs get out-of-sync we do our best - * to correct this situation by clearing the relevant cache entry and - * preparing the statement again. - */ - WebPreparedStatementHolder holder = stmtCache.get(desc); - // note this is a WeakHashMap-backed cache and may return null - if (holder == null) { - // Cache-miss, send request over the wire and cache result. - holder = sendPrepareStmtRequest(desc, 0); - stmtCache.put(desc, holder); - } - return new WebPreparedStatementImpl<>(holder.getTypeToken(), holder.getNumParams(), holder.getStatementId()); - } - - // package-private for testing - <T extends Pojo> WebPreparedStatementHolder sendPrepareStmtRequest(StatementDescriptor<T> desc, final int invokationCount) - throws DescriptorParsingException { - if (invokationCount > 1) { - // Initial invokation == 0, potential recovery-invocation == 1 - String msg = "Failed to recover from out-of-sync state with server"; - logger.log(Level.WARNING, msg); - throw new DescriptorParsingException(msg); - } - String strDesc = desc.getDescriptor(); - SharedStateId categoryId = getCategoryId(desc.getCategory()); - NameValuePair nameParam = new BasicNameValuePair("query-descriptor", - strDesc); - NameValuePair categoryParam = new BasicNameValuePair("category-id", - gson.toJson(categoryId, SharedStateId.class)); - List<NameValuePair> formparams = Arrays - .asList(nameParam, categoryParam); - try (CloseableHttpEntity entity = post(endpoint + "/prepare-statement", - formparams)) { - Reader reader = getContentAsReader(entity); - WebPreparedStatementResponse result = gson.fromJson(reader, WebPreparedStatementResponse.class); - int numParams = result.getNumFreeVariables(); - SharedStateId statementId = result.getStatementId(); - int stmtId = statementId.getId(); - switch (stmtId) { - case 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!"; - throw new IllegalDescriptorException(msg, desc.getDescriptor()); - } - case WebPreparedStatementResponse.DESCRIPTOR_PARSE_FAILED: { - String msg = "Statement descriptor failed to parse. " + - "Please check server logs for details!"; - throw new DescriptorParsingException(msg); - } - case WebPreparedStatementResponse.CATEGORY_OUT_OF_SYNC: { - // We tried to prepare a statement and the server's - // representation of category IDs changed. Thus, be sure to - // clear the category state and get their new IDs. - String msg = "Preparing statement failed. Server changed category state. Clearing category ID for statement: " + - desc.getDescriptor() + " and trying to recover."; - logger.log(Level.FINE, msg); - sendCategoryReRegistrationRequest(desc.getCategory()); - return sendPrepareStmtRequest(desc, invokationCount + 1); - } - default: { - // Common case where stmtId is the actual ID of the statement - // and not an error code. - assert(stmtId >= 0); // negative values are error codes - // We need this ugly trick in order for WebQueryResponse - // deserialization to work properly. I.e. GSON needs this type - // info hint. - Class<T> dataClass = desc.getCategory().getDataClass(); - Type typeToken = new WebQueryResponse<T>().getRuntimeParametrizedType(dataClass); - return new WebPreparedStatementHolder(typeToken, numParams, statementId); - } - } - } - } - - // package private for testing - synchronized <T extends Pojo> void sendCategoryReRegistrationRequest(Category<T> category) { - // There are two possible cases. Category is an aggregate category or - // it is not. For aggregate categories we need to re-register the - // original first and then the aggregate category. - Class<T> dataClass = category.getDataClass(); - if (AggregateResult.class.isAssignableFrom(dataClass)) { - Category<?> nonAggregateCategory = Categories.getByName(category.getName()); - categoryIds.remove(nonAggregateCategory); - registerCategory(nonAggregateCategory); - } - categoryIds.remove(category); - registerCategory(category); - } - - -} -
--- a/web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebStorageProvider.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -/* - * Copyright 2012-2017 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.client.internal; - -import java.util.concurrent.TimeUnit; - -import com.redhat.thermostat.common.utils.LoggingUtils; -import com.redhat.thermostat.shared.config.SSLConfiguration; -import com.redhat.thermostat.shared.perflog.PerformanceLogFormatter; -import com.redhat.thermostat.shared.perflog.PerformanceLogFormatterBuilder; -import com.redhat.thermostat.storage.core.SecureQueuedStorage; -import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.core.StorageCredentials; -import com.redhat.thermostat.storage.core.StorageProvider; - -public class WebStorageProvider implements StorageProvider { - - private String url; - private StorageCredentials creds; - private SSLConfiguration sslConf; - - @Override - public Storage createStorage() { - WebStorage storage = new WebStorage(url, creds, sslConf); - if (LoggingUtils.getEffectiveLogLevel(LoggingUtils.getLogger(WebStorageProvider.class)).intValue() <= LoggingUtils.LogLevel.PERFLOG.getLevel().intValue()) { - PerformanceLogFormatterBuilder builder = PerformanceLogFormatterBuilder.create(); - PerformanceLogFormatter lf = builder.setLoggedTimeUnit(TimeUnit.MICROSECONDS) - .build(); - return new SecureQueuedStorage(storage, lf); - } - return new SecureQueuedStorage(storage); - } - - @Override - public void setConfig(String connectionURL, StorageCredentials creds, SSLConfiguration sslConf) { - this.url = connectionURL; - this.creds = creds; - this.sslConf = sslConf; - } - - @Override - public boolean canHandleProtocol() { - // use http since this might be https at some point - return url.startsWith("http"); - } - -} -
--- a/web/client/src/test/java/com/redhat/thermostat/web/client/internal/EntityConsumingIOExceptionTest.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -/* - * Copyright 2012-2017 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.client.internal; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.mockito.Mockito.verify; - -import java.io.IOException; -import java.io.InputStream; - -import org.apache.http.HttpEntity; -import org.junit.Test; - -public class EntityConsumingIOExceptionTest { - - @Test - public void verifyEntityIsConsumed() throws IllegalStateException, IOException { - HttpEntity entity = mock(HttpEntity.class); - InputStream stream = mock(InputStream.class); - when(entity.getContent()).thenReturn(stream); - when(entity.isStreaming()).thenReturn(true); - - // this should trigger consumption of entity - new EntityConsumingIOException(entity, "testing-consume"); - verify(stream).close(); - } -}
--- a/web/client/src/test/java/com/redhat/thermostat/web/client/internal/ExpirableWebPreparedStatementCacheTest.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,110 +0,0 @@ -/* - * Copyright 2012-2017 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.client.internal; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.util.UUID; -import java.util.concurrent.TimeUnit; - -import org.junit.Before; -import org.junit.Test; - -import com.redhat.thermostat.storage.core.Category; -import com.redhat.thermostat.storage.core.StatementDescriptor; -import com.redhat.thermostat.web.common.SharedStateId; - -public class ExpirableWebPreparedStatementCacheTest { - - private static final UUID SERVER_TOKEN = UUID.randomUUID(); - private static final SharedStateId STMT_ID = new SharedStateId(3, SERVER_TOKEN); - private WebPreparedStatementCache cache; - private StatementDescriptor<?> desc; - - @SuppressWarnings("unchecked") - @Before - public void setup() { - cache = new WebPreparedStatementCache(); - WebPreparedStatementHolder holder = mock(WebPreparedStatementHolder.class); - when(holder.getStatementId()).thenReturn(STMT_ID); - desc = new StatementDescriptor<>(mock(Category.class), "test-desc"); - cache.put(desc, holder); - } - - @Test - public void testGetByDesc() { - long expires = System.nanoTime() + TimeUnit.NANOSECONDS.convert(100, TimeUnit.MILLISECONDS); - ExpirableWebPreparedStatementCache expCache = new ExpirableWebPreparedStatementCache(cache, expires); - assertNotNull("should not yet be expired", expCache.get(desc)); - @SuppressWarnings("unchecked") - StatementDescriptor<?> notExisting = new StatementDescriptor<>(mock(Category.class), "testing"); - assertNull("entry does not exist", expCache.get(notExisting)); - - expires = System.nanoTime() - TimeUnit.NANOSECONDS.convert(100, TimeUnit.MILLISECONDS); - expCache = new ExpirableWebPreparedStatementCache(cache, expires); - assertNull("should have expired", expCache.get(desc)); - } - - @Test - public void testGetById() { - long expires = System.nanoTime() + TimeUnit.NANOSECONDS.convert(100, TimeUnit.MILLISECONDS); - ExpirableWebPreparedStatementCache expCache = new ExpirableWebPreparedStatementCache(cache, expires); - assertNotNull("should not yet be expired", expCache.get(STMT_ID)); - assertNull("entry does not exist", expCache.get(new SharedStateId(3, UUID.randomUUID()))); - - expires = System.nanoTime() - TimeUnit.NANOSECONDS.convert(100, TimeUnit.MILLISECONDS); - expCache = new ExpirableWebPreparedStatementCache(cache, expires); - assertNull("should have expired", expCache.get(STMT_ID)); - } - - @Test - public void testIsExpired() { - long expires = System.nanoTime() - TimeUnit.NANOSECONDS.convert(20, TimeUnit.MILLISECONDS); - ExpirableWebPreparedStatementCache cache = new ExpirableWebPreparedStatementCache(null, expires); - assertTrue(cache.isExpired()); - - expires = System.nanoTime() + TimeUnit.NANOSECONDS.convert(100, TimeUnit.MILLISECONDS); - cache = new ExpirableWebPreparedStatementCache(null, expires); - assertFalse(cache.isExpired()); - } - -}
--- a/web/client/src/test/java/com/redhat/thermostat/web/client/internal/TestObj.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/* - * Copyright 2012-2017 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.client.internal; - -import com.redhat.thermostat.storage.core.Entity; -import com.redhat.thermostat.storage.core.Persist; -import com.redhat.thermostat.storage.model.BasePojo; - -@Entity -public class TestObj extends BasePojo { - - public TestObj() { - super(null); - } - - private String property1; - - @Persist - public void setProperty1(String property1) { - this.property1 = property1; - } - - @Persist - public String getProperty1() { - return property1; - } - - public boolean equals(Object o) { - if (! (o instanceof TestObj)) { - return false; - } - TestObj other = (TestObj) o; - return property1.equals(other.property1); - } -} -
--- a/web/client/src/test/java/com/redhat/thermostat/web/client/internal/WebCursorTest.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,218 +0,0 @@ -/* - * Copyright 2012-2017 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.client.internal; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.lang.reflect.Type; -import java.util.NoSuchElementException; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -import com.redhat.thermostat.storage.core.Cursor; -import com.redhat.thermostat.storage.core.StorageException; -import com.redhat.thermostat.web.common.PreparedStatementResponseCode; -import com.redhat.thermostat.web.common.WebPreparedStatement; -import com.redhat.thermostat.web.common.WebQueryResponse; - -public class WebCursorTest { - - private WebStorage storage; - private int cursorId; - private Type fakeType; - private WebPreparedStatement<TestObj> stmt; - - @SuppressWarnings("unchecked") - @Before - public void setup() { - storage = mock(WebStorage.class); - cursorId = 4441; - fakeType = mock(Type.class); - stmt = mock(WebPreparedStatement.class); - } - - @Test - public void testHasNext() { - boolean hasMoreBatches = false; - TestObj[] dataBatch = new TestObj[] { }; - WebCursor<TestObj> cursor = new WebCursor<>(storage, dataBatch, hasMoreBatches, cursorId, fakeType, stmt); - assertFalse("no results and no more batches", cursor.hasNext()); - hasMoreBatches = true; - cursor = new WebCursor<>(storage, dataBatch, hasMoreBatches, cursorId, fakeType, stmt); - assertTrue("no results, but more batches", cursor.hasNext()); - TestObj o1 = new TestObj(); - dataBatch = new TestObj[] { o1 }; - hasMoreBatches = false; - cursor = new WebCursor<>(storage, dataBatch, hasMoreBatches, cursorId, fakeType, stmt); - assertTrue("one result, no more batches", cursor.hasNext()); - } - - @Test - public void testNext() { - // test empty results and no more batches - boolean hasMoreBatches = false; - TestObj[] dataBatch = new TestObj[] { }; - WebCursor<TestObj> cursor = new WebCursor<>(storage, dataBatch, hasMoreBatches, cursorId, fakeType, stmt); - try { - cursor.next(); - fail("Cursor should throw a NoSuchElementException!"); - } catch (NoSuchElementException e) { - // pass - } - - // test empty results but more batches - hasMoreBatches = true; - cursor = new WebCursor<>(storage, dataBatch, hasMoreBatches, cursorId, fakeType, stmt); - WebQueryResponse<TestObj> response = new WebQueryResponse<>(); - response.setResponseCode(PreparedStatementResponseCode.QUERY_SUCCESS); - response.setCursorId(cursorId); - response.setHasMoreBatches(false); - TestObj o1 = new TestObj(); - o1.setProperty1("next-test"); - response.setResultList(new TestObj[] { o1 } ); - WebQueryResponse<TestObj> second = new WebQueryResponse<>(); - assertNull(second.getResultList()); - // be sure to return a bad result should storage.getMore() be called - // more than once - when(storage.getMore(cursorId, fakeType, Cursor.DEFAULT_BATCH_SIZE, stmt)).thenReturn(response).thenReturn(second); - TestObj actual = cursor.next(); - assertEquals("next-test", actual.getProperty1()); - - // test non-empty results and no more batches - hasMoreBatches = false; - o1.setAgentId("foo-agent-123"); - dataBatch = new TestObj[] { o1 }; - cursor = new WebCursor<>(storage, dataBatch, hasMoreBatches, cursorId, fakeType, stmt); - actual = cursor.next(); - assertEquals("foo-agent-123", actual.getAgentId()); - } - - /** - * Tests next() calls where get-more fails due to an expired or missing - * cursor on the web endpoint. - */ - @Test - public void testNextGetMoreBadCursorFailure() { - boolean hasMoreBatches = true; - TestObj[] dataBatch = new TestObj[] { }; - WebCursor<TestObj> cursor = new WebCursor<>(storage, dataBatch, hasMoreBatches, cursorId, fakeType, stmt); - WebQueryResponse<TestObj> response = new WebQueryResponse<>(); - response.setResponseCode(PreparedStatementResponseCode.GET_MORE_NULL_CURSOR); - response.setCursorId(cursorId); - response.setHasMoreBatches(false); - when(storage.getMore(cursorId, fakeType, Cursor.DEFAULT_BATCH_SIZE, stmt)).thenReturn(response); - try { - cursor.next(); - fail("Expected StorageException to be thrown"); - } catch (StorageException e) { - assertEquals("[get-more] Failed to get more results for cursorId: 4441" + - " This may be caused because the cursor timed out. " + - "Resubmitting the original query might be an approach to fix it. " + - "See server logs for more details.", - e.getMessage()); - } - } - - /** - * Tests next() calls where get-more fails due to some unknown reason. - */ - @Test - public void testNextGenericGetMoreFailure() { - boolean hasMoreBatches = true; - TestObj[] dataBatch = new TestObj[] { }; - WebCursor<TestObj> cursor = new WebCursor<>(storage, dataBatch, hasMoreBatches, cursorId, fakeType, stmt); - WebQueryResponse<TestObj> response = new WebQueryResponse<>(); - response.setResponseCode(PreparedStatementResponseCode.QUERY_FAILURE); - response.setCursorId(cursorId); - response.setHasMoreBatches(false); - when(storage.getMore(cursorId, fakeType, Cursor.DEFAULT_BATCH_SIZE, stmt)).thenReturn(response); - try { - cursor.next(); - fail("Expected StorageException to be thrown"); - } catch (StorageException e) { - assertEquals("[get-more] Failed to get more results for cursorId: " + - "4441. See server logs for details.", - e.getMessage()); - } - } - - /** - * Verify that if a batch size is explicitly set it gets passed on to - * web storage on the next call to getMore. Default batch size is accounted - * for in other tests (e.g. testNext()). - */ - @Test - public void testSetBatchSize() { - boolean hasMoreBatches = true; - TestObj[] empty = new TestObj[] {}; - WebCursor<TestObj> cursor = new WebCursor<>(storage, empty, hasMoreBatches, cursorId, fakeType, stmt); - try { - cursor.setBatchSize(-1); - fail("expected IAE for batch size of -1"); - } catch (IllegalArgumentException e) { - // pass - assertEquals("Batch size must be > 0", e.getMessage()); - } - try { - cursor.setBatchSize(0); - fail("expected IAE for batch size of 0"); - } catch (IllegalArgumentException e) { - // pass - assertEquals("Batch size must be > 0", e.getMessage()); - } - cursor = new WebCursor<>(storage, empty, hasMoreBatches, cursorId, fakeType, stmt); - cursor.setBatchSize(128); - TestObj o1 = new TestObj(); - WebQueryResponse<TestObj> response = new WebQueryResponse<>(); - response.setResultList(new TestObj[] { o1 }); - response.setResponseCode(PreparedStatementResponseCode.QUERY_SUCCESS); - when(storage.getMore(cursorId, fakeType, 128, stmt)).thenReturn(response); - cursor.next(); - verify(storage).getMore(cursorId, fakeType, 128, stmt); - Mockito.verifyNoMoreInteractions(storage); - } - -}
--- a/web/client/src/test/java/com/redhat/thermostat/web/client/internal/WebPreparedStatementCacheTest.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,164 +0,0 @@ -/* - * Copyright 2012-2017 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.client.internal; - -import java.util.UUID; - -import org.junit.Before; -import org.junit.Test; - -import static org.junit.Assert.*; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import com.redhat.thermostat.storage.core.Category; -import com.redhat.thermostat.storage.core.StatementDescriptor; -import com.redhat.thermostat.storage.model.Pojo; -import com.redhat.thermostat.web.common.SharedStateId; - -public class WebPreparedStatementCacheTest { - - private WebPreparedStatementCache cache; - - @Before - public void setup() { - cache = new WebPreparedStatementCache(); - } - - @Test - public void testPut() { - SharedStateId id = new SharedStateId(3, UUID.randomUUID()); - WebPreparedStatementHolder holder = mock(WebPreparedStatementHolder.class); - when(holder.getStatementId()).thenReturn(id); - @SuppressWarnings("unchecked") - Category<TestPojo> cat = mock(Category.class); - StatementDescriptor<TestPojo> foo = new StatementDescriptor<>(cat, - "something"); - cache.put(foo, holder); - assertSame(holder, cache.get(foo)); - assertSame(foo, cache.get(id)); - WebPreparedStatementHolder holder2 = mock(WebPreparedStatementHolder.class); - when(holder2.getStatementId()).thenReturn(id); - cache.put(foo, holder2); - assertNotSame(holder, cache.get(foo)); - assertSame(holder2, cache.get(foo)); - assertSame(foo, cache.get(id)); - - // Different server token should not result in an look-up-by-id clash. - SharedStateId id2 = new SharedStateId(3, UUID.randomUUID()); - assertNull(cache.get(id2)); - } - - @Test - public void testGetByDesc() { - WebPreparedStatementHolder holder = mock(WebPreparedStatementHolder.class); - SharedStateId id = mock(SharedStateId.class); - when(holder.getStatementId()).thenReturn(id); - @SuppressWarnings("unchecked") - Category<TestPojo> cat = mock(Category.class); - StatementDescriptor<TestPojo> foo = new StatementDescriptor<>(cat, - "something"); - cache.put(foo, holder); - assertEquals(holder, cache.get(foo)); - StatementDescriptor<TestPojo> other = new StatementDescriptor<>(cat, - "something-else"); - assertNull(cache.get(other)); - } - - @Test - public void testGetById() { - WebPreparedStatementHolder holder = mock(WebPreparedStatementHolder.class); - SharedStateId id = mock(SharedStateId.class); - when(holder.getStatementId()).thenReturn(id); - @SuppressWarnings("unchecked") - Category<TestPojo> cat = mock(Category.class); - StatementDescriptor<TestPojo> foo = new StatementDescriptor<>(cat, - "something"); - cache.put(foo, holder); - assertEquals(foo, cache.get(id)); - assertNull(cache.get(mock(SharedStateId.class))); - } - - @Test - public void testRemove() { - WebPreparedStatementHolder holder = mock(WebPreparedStatementHolder.class); - SharedStateId id = mock(SharedStateId.class); - when(holder.getStatementId()).thenReturn(id); - @SuppressWarnings("unchecked") - Category<TestPojo> cat = mock(Category.class); - StatementDescriptor<TestPojo> foo = new StatementDescriptor<>(cat, - "something"); - cache.put(foo, holder); - assertEquals(holder, cache.get(foo)); - - cache.remove(id); - assertNull(cache.get(foo)); - assertNull(cache.get(id)); - } - - /** - * Verify that we are able to create a snapshot of a cache in order to be - * able to look up old ID mappings. - */ - @Test - public void verifyCreateSnapshot() { - WebPreparedStatementHolder holder = mock(WebPreparedStatementHolder.class); - SharedStateId id = mock(SharedStateId.class); - when(holder.getStatementId()).thenReturn(id); - @SuppressWarnings("unchecked") - Category<TestPojo> cat = mock(Category.class); - StatementDescriptor<TestPojo> foo = new StatementDescriptor<>(cat, - "something"); - cache.put(foo, holder); - assertEquals(holder, cache.get(foo)); - assertNotNull(cache.get(id)); - - WebPreparedStatementCache copy = cache.createSnapshot(); - - cache.remove(id); - - assertNull(cache.get(foo)); - assertNull(cache.get(id)); - - assertNotNull(copy.get(foo)); - assertNotNull(copy.get(id)); - } - - private static class TestPojo implements Pojo { - // nothing - } -}
--- a/web/client/src/test/java/com/redhat/thermostat/web/client/internal/WebStorageProviderTest.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,87 +0,0 @@ -/* - * Copyright 2012-2017 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.client.internal; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; - -import org.junit.Test; - -import com.redhat.thermostat.shared.config.SSLConfiguration; -import com.redhat.thermostat.storage.core.BackingStorage; -import com.redhat.thermostat.storage.core.QueuedStorage; -import com.redhat.thermostat.storage.core.SecureStorage; -import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.core.StorageCredentials; - -public class WebStorageProviderTest { - - @Test - public void createStorageCreatesSecureStorage() { - WebStorageProvider provider = new WebStorageProvider(); - SSLConfiguration sslConf = mock(SSLConfiguration.class); - StorageCredentials creds = mock(StorageCredentials.class); - provider.setConfig("http://something", creds, sslConf); - Storage storage = provider.createStorage(); - assertTrue(storage instanceof SecureStorage); - assertTrue(storage instanceof QueuedStorage); - assertFalse(storage instanceof BackingStorage); - } - - @Test - public void canHandleHttpProtocol() { - WebStorageProvider provider = new WebStorageProvider(); - provider.setConfig("http://something.com", null, null); - assertTrue(provider.canHandleProtocol()); - } - - @Test - public void canHandleHttpsProtocol() { - WebStorageProvider provider = new WebStorageProvider(); - provider.setConfig("https://something.com", null, null); - assertTrue(provider.canHandleProtocol()); - } - - @Test - public void cannotHandleNotWebProtocol() { - WebStorageProvider provider = new WebStorageProvider(); - provider.setConfig("ftp://something.com", null, null); - assertFalse(provider.canHandleProtocol()); - } -} -
--- a/web/client/src/test/java/com/redhat/thermostat/web/client/internal/WebStorageTest.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1321 +0,0 @@ -/* - * Copyright 2012-2017 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.client.internal; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; - -import java.io.BufferedReader; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.Reader; -import java.io.StringReader; -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.UUID; -import java.util.concurrent.CountDownLatch; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.codec.binary.Base64; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.protocol.HttpContext; -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.handler.AbstractHandler; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.mockito.Mockito; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.redhat.thermostat.common.internal.test.FreePortFinder; -import com.redhat.thermostat.common.internal.test.FreePortFinder.TryPort; -import com.redhat.thermostat.shared.config.SSLConfiguration; -import com.redhat.thermostat.storage.core.AuthToken; -import com.redhat.thermostat.storage.core.BackingStorage; -import com.redhat.thermostat.storage.core.Categories; -import com.redhat.thermostat.storage.core.Category; -import com.redhat.thermostat.storage.core.CategoryAdapter; -import com.redhat.thermostat.storage.core.Connection; -import com.redhat.thermostat.storage.core.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.Key; -import com.redhat.thermostat.storage.core.PreparedParameters; -import com.redhat.thermostat.storage.core.PreparedStatement; -import com.redhat.thermostat.storage.core.SaveFileListener; -import com.redhat.thermostat.storage.core.SaveFileListener.EventType; -import com.redhat.thermostat.storage.core.StatementDescriptor; -import com.redhat.thermostat.storage.core.StatementExecutionException; -import com.redhat.thermostat.storage.core.StorageCredentials; -import com.redhat.thermostat.storage.core.StorageException; -import com.redhat.thermostat.storage.model.AggregateResult; -import com.redhat.thermostat.storage.model.Pojo; -import com.redhat.thermostat.web.common.PreparedStatementResponseCode; -import com.redhat.thermostat.web.common.SharedStateId; -import com.redhat.thermostat.web.common.WebPreparedStatement; -import com.redhat.thermostat.web.common.WebPreparedStatementResponse; -import com.redhat.thermostat.web.common.WebQueryResponse; -import com.redhat.thermostat.web.common.typeadapters.PojoTypeAdapterFactory; -import com.redhat.thermostat.web.common.typeadapters.PreparedParameterTypeAdapterFactory; -import com.redhat.thermostat.web.common.typeadapters.SharedStateIdTypeAdapterFactory; -import com.redhat.thermostat.web.common.typeadapters.WebPreparedStatementResponseTypeAdapterFactory; -import com.redhat.thermostat.web.common.typeadapters.WebPreparedStatementTypeAdapterFactory; -import com.redhat.thermostat.web.common.typeadapters.WebQueryResponseTypeAdapterFactory; - -public class WebStorageTest { - - private Server server; - - private int port; - - // Set these in prepareServer() to determine server behaviour - private int responseStatus = HttpServletResponse.SC_OK; - private String responseBody; - - // These get set by test server handler (anonymous class in startServer()) - // Check them after WebStorage method call that should interact with server. - private String requestBody; - private Map<String,String> headers; - private String method; - private String requestURI; - private UUID serverNonce; - - private static Category<TestObj> category; - private static Key<String> key1; - - private WebStorage storage; - - - @BeforeClass - public static void setupCategory() { - key1 = new Key<>("property1"); - category = new Category<>("test", TestObj.class, key1); - } - - @AfterClass - public static void cleanupCategory() { - Categories.remove(category); - category = null; - key1 = null; - } - - @Before - public void setUp() throws Exception { - serverNonce = UUID.randomUUID(); - port = FreePortFinder.findFreePort(new TryPort() { - @Override - public void tryPort(int port) throws Exception { - startServer(port); - } - }); - - SSLConfiguration sslConf = mock(SSLConfiguration.class); - storage = new WebStorage("http://localhost:" + port + "/", - new TrivialStorageCredentials(null, null), sslConf); - headers = new HashMap<>(); - registerCategory(); - } - - private void startServer(int port) throws Exception { - server = new Server(port); - server.setHandler(new AbstractHandler() { - - @Override - public void handle(String target, Request baseRequest, - HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException { - Enumeration<String> headerNames = request.getHeaderNames(); - while (headerNames.hasMoreElements()) { - String headerName = headerNames.nextElement(); - headers.put(headerName, request.getHeader(headerName)); - } - - method = request.getMethod(); - requestURI = request.getRequestURI(); - - // Read request body. - StringBuilder body = new StringBuilder(); - Reader reader = request.getReader(); - while (true) { - int read = reader.read(); - if (read == -1) { - break; - } - body.append((char) read); - } - requestBody = body.toString(); - // Send response body. - response.setStatus(responseStatus); - if (responseBody != null) { - response.getWriter().write(responseBody); - } - baseRequest.setHandled(true); - } - }); - server.start(); - } - - // Specified status and response body. - private void prepareServer(int responseStatus, String responseBody) { - this.responseStatus = responseStatus; - this.responseBody = responseBody; - - requestBody = null; - requestURI = null; - method = null; - headers.clear(); - } - - // Specified status and null response body. - private void prepareServer(int responseStatus) { - prepareServer(responseStatus, null); - } - - // OK status and specified response body. - private void prepareServer(String responseBody) { - prepareServer(HttpServletResponse.SC_OK, responseBody); - } - - // OK status and null response body. - private void prepareServer() { - prepareServer(HttpServletResponse.SC_OK); - } - - @After - public void tearDown() throws Exception { - - headers = null; - requestURI = null; - method = null; - storage = null; - - server.stop(); - server.join(); - } - - private void registerCategory() { - - // Return 42 for categoryId. - Gson gson = new GsonBuilder().registerTypeAdapterFactory(new SharedStateIdTypeAdapterFactory()).create(); - responseBody = gson.toJson(new SharedStateId(42, serverNonce)); - - storage.registerCategory(category); - } - - // WebStorage is a proxy storage, no backing storage - @Test - public void isNoBackingStorage() { - assertFalse(storage instanceof BackingStorage); - } - - @Test - public void preparingFaultyDescriptorThrowsException() throws UnsupportedEncodingException, IOException { - Gson gson = new GsonBuilder() - .registerTypeAdapterFactory(new WebPreparedStatementTypeAdapterFactory()) - .registerTypeAdapterFactory(new SharedStateIdTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebPreparedStatementResponseTypeAdapterFactory()) - .create(); - - // missing quotes for LHS key - String strDesc = "QUERY test WHERE a = ?s"; - StatementDescriptor<TestObj> desc = new StatementDescriptor<>(category, strDesc); - - WebPreparedStatementResponse fakeResponse = new WebPreparedStatementResponse(); - SharedStateId id = new SharedStateId(WebPreparedStatementResponse.DESCRIPTOR_PARSE_FAILED, UUID.randomUUID()); - fakeResponse.setStatementId(id); - prepareServer(gson.toJson(fakeResponse)); - try { - storage.prepareStatement(desc); - fail("Should have refused to prepare the statement"); - } catch (IllegalDescriptorException e) { - // should have thrown superclass DescriptorParsingException - fail(e.getMessage()); - } catch (DescriptorParsingException e) { - // pass - } - } - - @Test - public void preparingUnknownDescriptorThrowsException() throws UnsupportedEncodingException, IOException { - Gson gson = new GsonBuilder() - .registerTypeAdapterFactory(new WebPreparedStatementTypeAdapterFactory()) - .registerTypeAdapterFactory(new SharedStateIdTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebPreparedStatementResponseTypeAdapterFactory()) - .create(); - - String strDesc = "QUERY test WHERE 'property1' = ?s"; - StatementDescriptor<TestObj> desc = new StatementDescriptor<>(category, strDesc); - - WebPreparedStatementResponse fakeResponse = new WebPreparedStatementResponse(); - SharedStateId id = new SharedStateId(WebPreparedStatementResponse.ILLEGAL_STATEMENT, UUID.randomUUID()); - fakeResponse.setStatementId(id); - prepareServer(gson.toJson(fakeResponse)); - try { - storage.prepareStatement(desc); - fail("Should have refused to prepare the statement"); - } catch (IllegalDescriptorException e) { - // pass - assertEquals(strDesc, e.getFailedDescriptor()); - } catch (DescriptorParsingException e) { - // should have thrown IllegalDescriptorException - fail(e.getMessage()); - } - } - - @Test - public void forbiddenExecuteQueryThrowsConsumingExcptn() throws UnsupportedEncodingException, IOException { - Gson gson = new GsonBuilder() - .registerTypeAdapterFactory(new PojoTypeAdapterFactory()) - .registerTypeAdapterFactory(new SharedStateIdTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebPreparedStatementResponseTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebQueryResponseTypeAdapterFactory()) - .registerTypeAdapterFactory(new PreparedParameterTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebPreparedStatementTypeAdapterFactory()) - .create(); - - String strDesc = "QUERY test WHERE 'property1' = ?s"; - StatementDescriptor<TestObj> desc = new StatementDescriptor<>(category, strDesc); - PreparedStatement<TestObj> stmt = null; - - int fakePrepStmtId = 5; - SharedStateId id = new SharedStateId(fakePrepStmtId, UUID.randomUUID()); - WebPreparedStatementResponse fakeResponse = new WebPreparedStatementResponse(); - fakeResponse.setNumFreeVariables(1); - fakeResponse.setStatementId(id); - prepareServer(gson.toJson(fakeResponse)); - try { - stmt = storage.prepareStatement(desc); - } catch (DescriptorParsingException e) { - // descriptor should parse fine and is trusted - fail(e.getMessage()); - } - assertTrue(stmt instanceof WebPreparedStatement); - WebPreparedStatement<TestObj> webStmt = (WebPreparedStatement<TestObj>)stmt; - assertEquals(id, webStmt.getStatementId()); - PreparedParameters params = webStmt.getParams(); - assertEquals(1, params.getParams().length); - assertNull(params.getParams()[0]); - - // now set a parameter - stmt.setString(0, "fluff"); - assertEquals("fluff", params.getParams()[0].getValue()); - assertEquals(String.class, params.getParams()[0].getType()); - - prepareServer(HttpServletResponse.SC_FORBIDDEN); - try { - stmt.executeQuery(); - fail("Forbidden should have thrown an exception!"); - } catch (StatementExecutionException e) { - Throwable t = e.getCause(); - assertTrue(t instanceof StorageException); - t = t.getCause(); - assertTrue("Wanted EntityConsumingIOException as root cause", t instanceof EntityConsumingIOException); - } - } - - @Test - public void prepareStatementCachesStatements() throws DescriptorParsingException { - String strDesc = "QUERY test WHERE 'property1' = ?s"; - StatementDescriptor<TestObj> desc = new StatementDescriptor<>(category, strDesc); - PrepareStatementWebStorage testStorage = new PrepareStatementWebStorage("foo", mock(StorageCredentials.class), mock(SSLConfiguration.class)); - // should fill the cache - WebPreparedStatement<TestObj> stmt = (WebPreparedStatement<TestObj>)testStorage.prepareStatement(desc); - int numParams = stmt.getParams().getParams().length; - SharedStateId stmtId = stmt.getStatementId(); - assertEquals(0, numParams); - assertEquals(1, stmtId.getId()); - // this one should be cached, same stmtId and numParams as previous - // one. - stmt = (WebPreparedStatement<TestObj>)testStorage.prepareStatement(desc); - numParams = stmt.getParams().getParams().length; - stmtId = stmt.getStatementId(); - assertEquals("PreparedStatementWebStorge increments a counter" + - " if it wasn't cached. Was it 2? Bad!", - 0, numParams); - assertEquals("PreparedStatementWebStorge increments a counter" + - " if it wasn't cached. Was it 3? Bad!", 1, stmtId.getId()); - // preparing a different descriptor should not be cached. - strDesc = "QUERY test WHERE 'foo' = ?l"; - desc = new StatementDescriptor<>(category, strDesc); - stmt = (WebPreparedStatement<TestObj>)testStorage.prepareStatement(desc); - numParams = stmt.getParams().getParams().length; - stmtId = stmt.getStatementId(); - assertEquals("PreparedStatementWebStorge increments a counter" + - " if it wasn't cached. Triggers e.g. if it was erronously cached!", - 2, numParams); - assertEquals("PreparedStatementWebStorge increments a counter" + - " if it wasn't cached. Triggers e.g. if it was erronously cached!", - 3, stmtId.getId()); - } - - @Test - public void prepareStatementCachesStatements2() throws DescriptorParsingException { - WebPreparedStatementCache cache = mock(WebPreparedStatementCache.class); - final WebPreparedStatementHolder holder = mock(WebPreparedStatementHolder.class); - WebStorage testStorage = new WebStorage(cache, null) { - <T extends Pojo> WebPreparedStatementHolder sendPrepareStmtRequest(StatementDescriptor<T> desc, final int invokationCount) - throws DescriptorParsingException { - if (invokationCount != 0) { - throw new AssertionError("expected invokation count 0 but was: " + invokationCount); - } - return holder; - } - }; - String strDesc = "QUERY test WHERE 'property1' = ?s"; - StatementDescriptor<TestObj> desc = new StatementDescriptor<>(category, strDesc); - testStorage.prepareStatement(desc); - verify(cache).get(desc); - verify(cache).put(desc, holder); - } - - @Test - public void verifySendCategoryReRegistrationRequest() { - @SuppressWarnings("unchecked") - Map<Category<?>, SharedStateId> categoryMap = mock(Map.class); - final List<Category<?>> interceptedCategories = new ArrayList<>(); - WebStorage testStorage = new WebStorage(categoryMap) { - @Override - public void registerCategory(Category<?> category) throws StorageException { - interceptedCategories.add(category); - } - }; - // verify aggregate categories - Category<TestAggregate> aggregateCategory = new CategoryAdapter<TestObj, TestAggregate>(category).getAdapted(TestAggregate.class); - testStorage.sendCategoryReRegistrationRequest(aggregateCategory); - verify(categoryMap).remove(aggregateCategory); - verify(categoryMap).remove(category); - assertEquals(2, interceptedCategories.size()); - assertEquals("Expected actual category to be re-registered first", category, interceptedCategories.get(0)); - assertEquals("Expected aggregate category to be re-registered second", aggregateCategory, interceptedCategories.get(1)); - - interceptedCategories.clear(); - - // verify regular categories - testStorage.sendCategoryReRegistrationRequest(category); - // earlier test above did invoke it already once - verify(categoryMap, times(2)).remove(category); - assertEquals(1, interceptedCategories.size()); - assertEquals(category, interceptedCategories.get(0)); - verifyNoMoreInteractions(categoryMap); - } - - /** - * Tests a query which returns results in a single batch. - * - * By setting hasMoreBatches to false in WebQueryResponse we signal that - * there are no more batches available via getMore(). - * - * @see {@link #canPrepareAndExecuteQueryMultiBatchFailure()} - * @see {@link #canPrepareAndExecuteQueryMultiBatchSuccess()} - */ - @Test - public void canPrepareAndExecuteQuerySingleBatch() { - WebQueryResponse<TestObj> fakeQueryResponse = new WebQueryResponse<>(); - fakeQueryResponse.setResponseCode(PreparedStatementResponseCode.QUERY_SUCCESS); - fakeQueryResponse.setResultList(getTwoTestObjects()); - fakeQueryResponse.setCursorId(444); - // Setting this to false makes Cursor.hasNext() return false after the - // current result list is exhausted. - fakeQueryResponse.setHasMoreBatches(false); - Cursor<TestObj> results = doBasicPrepareAndExecuteQueryTest(fakeQueryResponse); - assertFalse(results.hasNext()); - try { - results.next(); - fail("Cursor should throw a NoSuchElementException!"); - } catch (NoSuchElementException e) { - // pass - } - } - - /** - * Tests a query which returns results in multiple batches. The get-more - * call is successful in this test. - * - * By setting hasMoreBatches to true in WebQueryResponse we signal that - * there are more batches available via getMore(). - * @throws IOException - * @throws UnsupportedEncodingException - * - * @see {@link #canPrepareAndExecuteQueryMultiBatchFailure()} - */ - @Test - public void canPrepareAndExecuteQueryMultiBatchSuccess() throws UnsupportedEncodingException, IOException { - WebQueryResponse<TestObj> fakeQueryResponse = new WebQueryResponse<>(); - fakeQueryResponse.setResponseCode(PreparedStatementResponseCode.QUERY_SUCCESS); - fakeQueryResponse.setResultList(getTwoTestObjects()); - fakeQueryResponse.setCursorId(444); - // Setting this to true makes Cursor.hasNext() return true after the - // current result list is exhausted. - fakeQueryResponse.setHasMoreBatches(true); - // doBasicPrepareAndExecuteQueryTest performs two hasNext() and - // next() calls on the cursor. - Cursor<TestObj> results = doBasicPrepareAndExecuteQueryTest(fakeQueryResponse); - assertTrue("Expected cursor to return true, since there are more batches", results.hasNext()); - assertEquals("POST", method); - String path = requestURI.substring(requestURI.lastIndexOf('/')); - assertEquals("/query-execute", path); - - TestObj more = new TestObj(); - more.setProperty1("get-more-result"); - WebQueryResponse<TestObj> getMoreResults = new WebQueryResponse<>(); - getMoreResults.setResponseCode(PreparedStatementResponseCode.QUERY_SUCCESS); - getMoreResults.setCursorId(444); - getMoreResults.setHasMoreBatches(true); // one more batch - getMoreResults.setResultList(new TestObj[] {more}); - final Gson gson = getQueryGson(); - prepareServer(gson.toJson(getMoreResults)); - // the following next() call performs the get-more request - // for which we had to prepare the server - TestObj returnedGetMore = results.next(); - assertEquals("POST", method); - path = requestURI.substring(requestURI.lastIndexOf('/')); - assertEquals("/get-more", path); - // Verify correctly passed parameters - StringReader reader = new StringReader(requestBody); - BufferedReader bufRead = new BufferedReader(reader); - String line = URLDecoder.decode(bufRead.readLine(), "UTF-8"); - String[] requestParams = line.split("&"); - String prepStmtIdParam = requestParams[0]; - String cursorIdParam = requestParams[1]; - String batchSizeParam = requestParams[2]; - String[] prStmtArray = prepStmtIdParam.split("="); - String[] cursorIdArray = cursorIdParam.split("="); - String[] batchSizeArray = batchSizeParam.split("="); - assertEquals("prepared-stmt-id", prStmtArray[0]); - SharedStateId prStmtId = gson.fromJson(prStmtArray[1], SharedStateId.class); - assertEquals(5, prStmtId.getId()); - assertEquals("cursor-id", cursorIdArray[0]); - assertEquals("444", cursorIdArray[1]); - assertEquals("batch-size", batchSizeArray[0]); - assertEquals(Integer.toString(Cursor.DEFAULT_BATCH_SIZE), batchSizeArray[1]); - - assertEquals("get-more-result", returnedGetMore.getProperty1()); - - - // Do it again, this time with a non-default batch size: 5 - - results.setBatchSize(5); - - WebQueryResponse<TestObj> getMoreResults2 = new WebQueryResponse<>(); - getMoreResults2.setResponseCode(PreparedStatementResponseCode.QUERY_SUCCESS); - getMoreResults2.setCursorId(444); - getMoreResults2.setHasMoreBatches(false); // no more batches this time - getMoreResults2.setResultList(new TestObj[] { more }); - prepareServer(gson.toJson(getMoreResults2)); - results.next(); - - path = requestURI.substring(requestURI.lastIndexOf('/')); - assertEquals("/get-more", path); - - String[] batchSizeParamPair = requestBody.split("&")[2].split("="); - assertEquals("batch-size", batchSizeParamPair[0]); - assertEquals("5", batchSizeParamPair[1]); - } - - /** - * Tests a query which returns results in multiple batches. The get-more - * call fails on the server side, though. - * - * @see {@link #canPrepareAndExecuteQueryMultiBatchSuccess()} - */ - @Test - public void canPrepareAndExecuteQueryMultiBatchFailure() { - WebQueryResponse<TestObj> fakeQueryResponse = new WebQueryResponse<>(); - fakeQueryResponse.setResponseCode(PreparedStatementResponseCode.QUERY_SUCCESS); - fakeQueryResponse.setResultList(getTwoTestObjects()); - fakeQueryResponse.setCursorId(444); - fakeQueryResponse.setHasMoreBatches(true); - Cursor<TestObj> results = doBasicPrepareAndExecuteQueryTest(fakeQueryResponse); - assertTrue("Expected cursor to return true, since there are more batches", results.hasNext()); - - WebQueryResponse<TestObj> getMoreResults = new WebQueryResponse<>(); - getMoreResults.setResponseCode(PreparedStatementResponseCode.QUERY_FAILURE); - final Gson gson = getQueryGson(); - prepareServer(gson.toJson(getMoreResults)); - try { - results.next(); - fail(); // Expected storage exception - } catch (StorageException e) { - assertEquals("[get-more] Failed to get more results for cursorId: 444. See server logs for details.", e.getMessage()); - } - // Do it again with a generic failure code - getMoreResults.setResponseCode(-0xcafeBabe); // this should be unknown - prepareServer(gson.toJson(getMoreResults)); - try { - results.next(); - fail(); // Expected storage exception - } catch (StorageException e) { - assertEquals("[get-more] Failed to get more results for cursorId: 444. See server logs for details.", e.getMessage()); - } - } - - private TestObj[] getTwoTestObjects() { - TestObj obj1 = new TestObj(); - obj1.setProperty1("fluffor1"); - TestObj obj2 = new TestObj(); - obj2.setProperty1("fluffor2"); - return new TestObj[] { obj1, obj2 }; - } - - private Cursor<TestObj> doBasicPrepareAndExecuteQueryTest(WebQueryResponse<TestObj> fakeQueryResponse) { - Gson gson = getQueryGson(); - - String strDesc = "QUERY test WHERE 'property1' = ?s"; - StatementDescriptor<TestObj> desc = new StatementDescriptor<>(category, strDesc); - PreparedStatement<TestObj> stmt = null; - - int fakePrepStmtId = 5; - WebPreparedStatementResponse fakeResponse = new WebPreparedStatementResponse(); - fakeResponse.setNumFreeVariables(1); - SharedStateId id = new SharedStateId(fakePrepStmtId, UUID.randomUUID()); - fakeResponse.setStatementId(id); - prepareServer(gson.toJson(fakeResponse)); - try { - stmt = storage.prepareStatement(desc); - } catch (DescriptorParsingException e) { - // descriptor should parse fine and is trusted - fail(e.getMessage()); - } - assertTrue(stmt instanceof WebPreparedStatement); - WebPreparedStatement<TestObj> webStmt = (WebPreparedStatement<TestObj>)stmt; - assertEquals(fakePrepStmtId, webStmt.getStatementId().getId()); - PreparedParameters params = webStmt.getParams(); - assertEquals(1, params.getParams().length); - assertNull(params.getParams()[0]); - - // now set a parameter - stmt.setString(0, "fluff"); - assertEquals("fluff", params.getParams()[0].getValue()); - assertEquals(String.class, params.getParams()[0].getType()); - - prepareServer(gson.toJson(fakeQueryResponse)); - Cursor<TestObj> results = null; - try { - results = stmt.executeQuery(); - } catch (StatementExecutionException e) { - // should execute fine - e.printStackTrace(); - fail(e.getMessage()); - } - assertNotNull(results); - assertTrue(results instanceof WebCursor); - assertTrue(results.hasNext()); - assertEquals("fluffor1", results.next().getProperty1()); - assertTrue(results.hasNext()); - assertEquals("fluffor2", results.next().getProperty1()); - return results; - } - - private Gson getQueryGson() { - return new GsonBuilder() - .registerTypeAdapterFactory(new PojoTypeAdapterFactory()) - .registerTypeAdapterFactory(new SharedStateIdTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebPreparedStatementResponseTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebQueryResponseTypeAdapterFactory()) - .registerTypeAdapterFactory(new PreparedParameterTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebPreparedStatementTypeAdapterFactory()) - .create(); - } - - @Test - public void canPrepareAndExecuteWrite() { - TestObj obj1 = new TestObj(); - obj1.setProperty1("fluffor1"); - TestObj obj2 = new TestObj(); - obj2.setProperty1("fluffor2"); - Gson gson = new GsonBuilder() - .registerTypeAdapterFactory(new PojoTypeAdapterFactory()) - .registerTypeAdapterFactory(new SharedStateIdTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebPreparedStatementResponseTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebQueryResponseTypeAdapterFactory()) - .registerTypeAdapterFactory(new PreparedParameterTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebPreparedStatementTypeAdapterFactory()) - .create(); - - String strDesc = "ADD test SET 'property1' = ?s"; - StatementDescriptor<TestObj> desc = new StatementDescriptor<>(category, strDesc); - PreparedStatement<TestObj> stmt = null; - - int fakePrepStmtId = 3; - WebPreparedStatementResponse fakeResponse = new WebPreparedStatementResponse(); - fakeResponse.setNumFreeVariables(1); - SharedStateId id = new SharedStateId(fakePrepStmtId, UUID.randomUUID()); - fakeResponse.setStatementId(id); - prepareServer(gson.toJson(fakeResponse)); - try { - stmt = storage.prepareStatement(desc); - } catch (DescriptorParsingException e) { - // descriptor should parse fine and is trusted - fail(e.getMessage()); - } - assertTrue(stmt instanceof WebPreparedStatement); - WebPreparedStatement<TestObj> webStmt = (WebPreparedStatement<TestObj>)stmt; - assertEquals(fakePrepStmtId, webStmt.getStatementId().getId()); - PreparedParameters params = webStmt.getParams(); - assertEquals(1, params.getParams().length); - assertNull(params.getParams()[0]); - - // now set a parameter - stmt.setString(0, "fluff"); - assertEquals("fluff", params.getParams()[0].getValue()); - assertEquals(String.class, params.getParams()[0].getType()); - - prepareServer(gson.toJson(PreparedStatementResponseCode.WRITE_GENERIC_FAILURE)); - - int response = Integer.MAX_VALUE; - try { - response = stmt.execute(); - } catch (StatementExecutionException e) { - // should execute fine - e.printStackTrace(); - fail(e.getMessage()); - } - - assertEquals(PreparedStatementResponseCode.WRITE_GENERIC_FAILURE, response); - } - - @Test - public void forbiddenExecuteWriteReturnsGenericWriteFailure() { - Gson gson = new GsonBuilder() - .registerTypeAdapterFactory(new PojoTypeAdapterFactory()) - .registerTypeAdapterFactory(new SharedStateIdTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebPreparedStatementResponseTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebQueryResponseTypeAdapterFactory()) - .registerTypeAdapterFactory(new PreparedParameterTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebPreparedStatementTypeAdapterFactory()) - .create(); - - String strDesc = "ADD test SET 'property1' = ?s"; - StatementDescriptor<TestObj> desc = new StatementDescriptor<>(category, strDesc); - PreparedStatement<TestObj> stmt = null; - - int fakePrepStmtId = 3; - WebPreparedStatementResponse fakeResponse = new WebPreparedStatementResponse(); - fakeResponse.setNumFreeVariables(1); - SharedStateId id = new SharedStateId(fakePrepStmtId, UUID.randomUUID()); - fakeResponse.setStatementId(id); - prepareServer(gson.toJson(fakeResponse)); - try { - stmt = storage.prepareStatement(desc); - } catch (DescriptorParsingException e) { - // descriptor should parse fine and is trusted - fail(e.getMessage()); - } - assertTrue(stmt instanceof WebPreparedStatement); - WebPreparedStatement<TestObj> webStmt = (WebPreparedStatement<TestObj>)stmt; - assertEquals(fakePrepStmtId, webStmt.getStatementId().getId()); - PreparedParameters params = webStmt.getParams(); - assertEquals(1, params.getParams().length); - assertNull(params.getParams()[0]); - - // now set a parameter - stmt.setString(0, "fluff"); - assertEquals("fluff", params.getParams()[0].getValue()); - assertEquals(String.class, params.getParams()[0].getType()); - - prepareServer(HttpServletResponse.SC_FORBIDDEN); - try { - stmt.execute(); - fail("Forbidden should have thrown an exception!"); - } catch (StatementExecutionException e) { - Throwable t = e.getCause(); - assertTrue(t instanceof StorageException); - t = t.getCause(); - assertTrue("Wanted EntityConsumingIOException as root cause", t instanceof EntityConsumingIOException); - } - } - - @Test (expected=NullPointerException.class) - public void testSaveFileThrowsExceptionOnNullListener() throws Exception { - String data = "Hello World"; - ByteArrayInputStream in = new ByteArrayInputStream(data.getBytes()); - - storage.saveFile("fluff", in, null); - } - - @Test - public void testSaveFile() { - String data = "Hello World"; - ByteArrayInputStream in = new ByteArrayInputStream(data.getBytes()); - - SaveFileListener saveListener = mock(SaveFileListener.class); - prepareServer(); - storage.saveFile("fluff", in, saveListener); - - assertEquals("chunked", headers.get("Transfer-Encoding")); - String contentType = headers.get("Content-Type"); - assertTrue(contentType.startsWith("multipart/form-data; boundary=")); - String boundary = contentType.split("boundary=")[1]; - String[] lines = requestBody.split("\n"); - assertEquals("--" + boundary, lines[0].trim()); - assertEquals("Content-Disposition: form-data; name=\"file\"; filename=\"fluff\"", lines[1].trim()); - assertEquals("Content-Type: application/octet-stream", lines[2].trim()); - assertEquals("Content-Transfer-Encoding: binary", lines[3].trim()); - assertEquals("", lines[4].trim()); - assertEquals("Hello World", lines[5].trim()); - assertEquals("--" + boundary + "--", lines[6].trim()); - - verify(saveListener).notify(EventType.SAVE_COMPLETE, null); - } - - @Test - public void testLoadFile() throws IOException { - prepareServer(HttpServletResponse.SC_NO_CONTENT); - InputStream in = storage.loadFile("no_file_here"); - assertNull(in); - - prepareServer("Hello World"); - in = storage.loadFile("fluff"); - assertEquals("file=fluff", requestBody.trim()); - byte[] data = new byte[11]; - int totalRead = 0; - while (totalRead < 11) { - int read = in.read(data, totalRead, 11 - totalRead); - if (read < 0) { - fail(); - } - totalRead += read; - } - assertEquals("Hello World", new String(data)); - - } - - @Test - public void testPurge() throws UnsupportedEncodingException, IOException { - - prepareServer(); - storage.purge("fluff"); - - assertEquals("POST", method); - assertTrue(requestURI.endsWith("/purge")); - StringReader reader = new StringReader(requestBody); - BufferedReader bufRead = new BufferedReader(reader); - String line = URLDecoder.decode(bufRead.readLine(), "UTF-8"); - String[] parts = line.split("="); - assertEquals("agentId", parts[0]); - assertEquals("fluff", parts[1]); - } - - @Test - public void testGenerateToken() throws UnsupportedEncodingException { - - final String actionName = "some action"; - - prepareServer("flufftoken"); - AuthToken authToken = storage.generateToken(actionName); - - assertTrue(requestURI.endsWith("/generate-token")); - assertEquals("POST", method); - - String[] requestParts = requestBody.split("="); - assertEquals("client-token", requestParts[0]); - String clientTokenParam = URLDecoder.decode(requestParts[1], "UTF-8"); - byte[] clientToken = Base64.decodeBase64(clientTokenParam); - assertEquals(256, clientToken.length); - - byte[] tokenBytes = authToken.getToken(); - assertEquals("flufftoken", new String(tokenBytes)); - - assertTrue(Arrays.equals(clientToken, authToken.getClientToken())); - - // Send another request and verify that we send a different client-token every time. - prepareServer("flufftoken"); - storage.generateToken(actionName); - - requestParts = requestBody.split("="); - assertEquals("client-token", requestParts[0]); - clientTokenParam = URLDecoder.decode(requestParts[1], "UTF-8"); - byte[] clientToken2 = Base64.decodeBase64(clientTokenParam); - assertFalse(Arrays.equals(clientToken, clientToken2)); - - } - - @Test - public void enablesTLSforHttps() { - SSLConfiguration sslConf = mock(SSLConfiguration.class); - String httpsUrl = "https://onlyHttpsPrefixUsed.example.com"; - new WebStorage(httpsUrl, - new TrivialStorageCredentials(null, null), sslConf); - // should get called for HTTPS URLs - verify(sslConf).getKeystoreFile(); - verify(sslConf).getKeyStorePassword(); - } - - @Test - public void doesnotEnableTLSForHttp() { - SSLConfiguration sslConf = mock(SSLConfiguration.class); - String httpsUrl = "http://foo.example.com"; - new WebStorage(httpsUrl, - new TrivialStorageCredentials(null, null), sslConf); - verifyNoMoreInteractions(sslConf); - } - - @Test - public void testVerifyToken() throws UnsupportedEncodingException, NoSuchAlgorithmException { - byte[] token = "stuff".getBytes(); - String clientToken = "fluff"; - String someAction = "someAction"; - byte[] tokenDigest = getShaBytes(clientToken, someAction); - - AuthToken authToken = new AuthToken(token, tokenDigest); - - prepareServer(); - boolean ok = storage.verifyToken(authToken, someAction); - - assertTrue(ok); - assertTrue(requestURI.endsWith("/verify-token")); - assertEquals("POST", method); - String[] requestParts = requestBody.split("&"); - assertEquals(3, requestParts.length); - String[] clientTokenParts = requestParts[0].split("="); - assertEquals(2, clientTokenParts.length); - assertEquals("client-token", clientTokenParts[0]); - String urlDecoded = URLDecoder.decode(clientTokenParts[1], "UTF-8"); - assertTrue(Arrays.equals(tokenDigest, Base64.decodeBase64(urlDecoded))); - String[] authTokenParts = requestParts[1].split("="); - assertEquals(2, authTokenParts.length); - assertEquals("token", authTokenParts[0]); - String[] actionParts = requestParts[2].split("="); - assertEquals(2, actionParts.length); - assertEquals("action-name", actionParts[0]); - urlDecoded = URLDecoder.decode(authTokenParts[1], "UTF-8"); - String base64decoded = new String(Base64.decodeBase64(urlDecoded)); - assertEquals("stuff", base64decoded); - - // Try another one in which verification fails. - prepareServer(HttpServletResponse.SC_UNAUTHORIZED); - ok = storage.verifyToken(authToken, someAction); - assertFalse(ok); - - } - - private byte[] getShaBytes(String clientToken, String someAction) - throws NoSuchAlgorithmException, UnsupportedEncodingException { - MessageDigest digest = MessageDigest.getInstance("SHA-256"); - digest.update(clientToken.getBytes()); - digest.update(someAction.getBytes("UTF-8")); - byte[] tokenDigest = digest.digest(); - return tokenDigest; - } - - @Test - public void verifyConnectFiresEventOnConnectionFailure() throws Exception { - HttpClient client = mock(HttpClient.class); - // Execution of ping() will fail - Mockito.doThrow(RuntimeException.class).when(client).execute(any(HttpUriRequest.class), any(HttpContext.class)); - storage = new WebStorage("http://localhost:" + port + "/", new TrivialStorageCredentials(null, null), - client); - - CountDownLatch latch = new CountDownLatch(1); - MyListener listener = new MyListener(latch); - storage.getConnection().addListener(listener); - storage.getConnection().connect(); - // wait for connection to fail - try { - latch.await(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - assertFalse(listener.connectEvent); - assertTrue(listener.failedToConnectEvent); - } - - @Test - public void verifyConnectFiresEventOnSuccessfulConnect() { - CountDownLatch latch = new CountDownLatch(1); - MyListener listener = new MyListener(latch); - storage.getConnection().addListener(listener); - storage.getConnection().connect(); - // wait for connection to happen - try { - latch.await(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - assertTrue(listener.connectEvent); - assertFalse(listener.failedToConnectEvent); - } - - @Test - public void verifyDisconnectFiresDisconnectEvent() { - CountDownLatch latch = new CountDownLatch(1); - MyListener listener = new MyListener(latch); - storage.getConnection().addListener(listener); - storage.getConnection().disconnect(); - try { - latch.await(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - assertFalse(listener.connectEvent); - assertFalse(listener.failedToConnectEvent); - assertTrue(listener.disconnectEvent); - } - - @Test - public void verifyDoWriteExecuteMorethanOne() { - try { - storage.doWriteExecute(null, 2); - fail("Expected excecution exception since invoked count > 1"); - } catch (StatementExecutionException e) { - Throwable cause = e.getCause(); - // pass - assertEquals("Failed to recover from out-of-sync state with server", cause.getMessage()); - } - } - - @Test - public void verifyDoExecuteQueryMorethanOne() { - try { - storage.doExecuteQuery(null, null, 2); - fail("Expected descriptor parsing exception since invoked count > 1"); - } catch (StatementExecutionException e) { - Throwable cause = e.getCause(); - // pass - assertEquals("Failed to recover from out-of-sync state with server", cause.getMessage()); - } - } - - @Test - public void verifySendPreparedStatementRequestMoreThanOne() { - try { - storage.sendPrepareStmtRequest(null, 2); - fail("Expected descriptor parsing exception since invoked count > 1"); - } catch (DescriptorParsingException e) { - // pass - assertEquals("Failed to recover from out-of-sync state with server", e.getMessage()); - } - } - - /** - * Test the base case in {@link WebStorage#handlePreparedStmtStateOutOfSync(WebPreparedStatement)}. - * with null transition cache and non-null statement cache. This simulates the - * case where state got out of sync and handlePreparedStmtStateOutOfSync() is - * called the first time after that out-of-sync-event happened. In that case - * it is expected for prepareStatement() and sendCategoryReRegistrationRequest() - * to be called. - * - * @throws DescriptorParsingException - * - */ - @Test - public void testHandleStatementStateOutOfSyncBaseCase() throws DescriptorParsingException { - WebPreparedStatementHolder mockHolder = mock(WebPreparedStatementHolder.class); - SharedStateId id = new SharedStateId(300, UUID.randomUUID()); - when(mockHolder.getStatementId()).thenReturn(id); - @SuppressWarnings("unchecked") - Category<Pojo> foo = mock(Category.class); - StatementDescriptor<Pojo> desc = new StatementDescriptor<>(foo, "testing"); - WebPreparedStatementCache stmtCache = mock(WebPreparedStatementCache.class); - // this is called twice. Once for creating the snapshot and another time - // for getting the descriptor. - when(stmtCache.get(id)).thenReturn(desc).thenReturn(desc); - final boolean[] sendCategoryReRegistrationRequest = new boolean[1]; - final boolean[] prepareStatement = new boolean[1]; - final WebPreparedStatement<?> newStmt = mock(WebPreparedStatement.class); - WebStorage webStorage = new WebStorage(stmtCache, null) { - - @Override - protected synchronized <T extends Pojo> void sendCategoryReRegistrationRequest(Category<T> category) { - sendCategoryReRegistrationRequest[0] = true; - } - - @SuppressWarnings("unchecked") - @Override - public <T extends Pojo> PreparedStatement<T> prepareStatement(StatementDescriptor<T> desc) - throws DescriptorParsingException { - prepareStatement[0] = true; - return (PreparedStatement<T>)newStmt; - } - }; - @SuppressWarnings("unchecked") - WebPreparedStatement<Pojo> mockStmt = mock(WebPreparedStatement.class); - PreparedParameters mockParams = new PreparedParameters(3); - when(mockStmt.getParams()).thenReturn(mockParams); - when(mockStmt.getStatementId()).thenReturn(id); - - WebPreparedStatementCache stmtCacheSnapshot = mock(WebPreparedStatementCache.class); - when(stmtCache.createSnapshot()).thenReturn(stmtCacheSnapshot); - webStorage.handlePreparedStmtStateOutOfSync(mockStmt); - verify(stmtCache).createSnapshot(); - verify(stmtCache).get(id); - verify(stmtCache).remove(id); - assertTrue("expected sendCategoryReRegistrationRequest() to be called", sendCategoryReRegistrationRequest[0]); - assertTrue("expected prepareStatement() to be called", prepareStatement[0]); - verify(newStmt).setParams(mockParams); - verifyNoMoreInteractions(stmtCache); - } - - /** - * Test the transition case in {@link WebStorage#handlePreparedStmtStateOutOfSync(WebPreparedStatement)}. - * with non-null transition cache and non-null statement cache. - * - * This simulates the case where state got out of sync and handlePreparedStmtStateOutOfSync() is - * called <strong>not</strong> the first time after an out-of-sync-event happened. I.e. - * the base-case path has been entered first when a similar statement tried - * to execute, in turn, getting the statement id removed from the main - * statement cache. - * - * In that case it is expected for the transition cache to become active - * allowing the statement to execute successfully. - * - * @throws DescriptorParsingException - * - */ - @Test - public void testHandleStatementStateOutOfSyncTransitionCase() throws DescriptorParsingException { - WebPreparedStatementHolder mockHolder = mock(WebPreparedStatementHolder.class); - SharedStateId id = new SharedStateId(300, UUID.randomUUID()); - when(mockHolder.getStatementId()).thenReturn(id); - @SuppressWarnings("unchecked") - Category<Pojo> foo = mock(Category.class); - StatementDescriptor<Pojo> desc = new StatementDescriptor<>(foo, "testing"); - WebPreparedStatementCache stmtCache = mock(WebPreparedStatementCache.class); - // no setup for the id in stmtCache, however the transitionCache, - // a snapshot cache - created when the first call to handlePreparedStatementStateOutOfSync() - // came in - still "knows" about this record. - ExpirableWebPreparedStatementCache transitionCache = mock(ExpirableWebPreparedStatementCache.class); - when(transitionCache.isExpired()).thenReturn(false); - when(transitionCache.get(id)).thenReturn(desc); - when(transitionCache.get(desc)).thenReturn(mockHolder); - SharedStateId updatedId = new SharedStateId(301, UUID.randomUUID()); - WebPreparedStatementHolder newHolder = mock(WebPreparedStatementHolder.class); - when(mockHolder.getStatementId()).thenReturn(id); - // called twice. once for equality check. once for getting the id and - // using it to update the prepared statement id. - when(newHolder.getStatementId()).thenReturn(updatedId).thenReturn(updatedId); - when(stmtCache.get(desc)).thenReturn(newHolder); - WebStorage webStorage = new WebStorage(stmtCache, transitionCache); - @SuppressWarnings("unchecked") - WebPreparedStatement<Pojo> mockStmt = mock(WebPreparedStatement.class); - when(mockStmt.getStatementId()).thenReturn(id); - WebPreparedStatement<Pojo> result = webStorage.handlePreparedStmtStateOutOfSync(mockStmt); - verify(mockStmt).setStatementId(updatedId); - assertSame(mockStmt, result); - verify(stmtCache).get(id); - verify(stmtCache).get(desc); - verify(transitionCache).isExpired(); - verify(transitionCache).get(id); - verify(transitionCache).get(desc); - verifyNoMoreInteractions(stmtCache); - verifyNoMoreInteractions(transitionCache); - } - - @Test - public void testConnectedUsernameIsSet() { - String expected = "username"; - - storage = new WebStorage("http://localhost:" + port + "/", - new TrivialStorageCredentials(expected, new char[]{ 'p' }), mock(SSLConfiguration.class)); - - CountDownLatch latch = new CountDownLatch(1); - MyListener listener = new MyListener(latch); - storage.getConnection().addListener(listener); - - Connection c = storage.getConnection(); - c.connect(); - - // wait for connection to happen - try { - latch.await(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - assertTrue(listener.connectEvent); - assertFalse(listener.failedToConnectEvent); - - assertEquals(expected, c.getUsername()); - } - - @Test - public void testFailedConnectUsernameIsUnset() throws IOException { - String expected = Connection.UNSET_USERNAME; - - HttpClient client = mock(HttpClient.class); - Mockito.doThrow(RuntimeException.class).when(client).execute(any(HttpUriRequest.class), any(HttpContext.class)); - - storage = new WebStorage("http://localhost:" + port + "/", - new TrivialStorageCredentials("username", new char[]{ 'p' }), client); - - CountDownLatch latch = new CountDownLatch(1); - MyListener listener = new MyListener(latch); - storage.getConnection().addListener(listener); - - Connection c = storage.getConnection(); - c.connect(); - - // wait for connection to happen - try { - latch.await(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - assertTrue(listener.failedToConnectEvent); - assertFalse(listener.connectEvent); - - assertEquals(expected, c.getUsername()); - } - - @Test - public void testDisconnectedUsernameIsUnset() { - String expected = Connection.UNSET_USERNAME; - - storage = new WebStorage("http://localhost:" + port + "/", - new TrivialStorageCredentials("username", new char[]{ 'p' }), mock(SSLConfiguration.class)); - - CountDownLatch latch = new CountDownLatch(1); - MyListener listener = new MyListener(latch); - storage.getConnection().addListener(listener); - - Connection c = storage.getConnection(); - c.disconnect(); - - // wait for connections to finish - try { - latch.await(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - assertFalse(listener.connectEvent); - assertFalse(listener.failedToConnectEvent); - assertTrue(listener.disconnectEvent); - - assertEquals(expected, c.getUsername()); - } - - static class MyListener implements ConnectionListener { - - private CountDownLatch latch; - boolean failedToConnectEvent = false; - boolean connectEvent = false; - boolean disconnectEvent = false; - - MyListener(CountDownLatch latch) { - this.latch = latch; - } - - @Override - public void changed(ConnectionStatus newStatus) { - if (newStatus == ConnectionStatus.CONNECTED) { - connectEvent = true; - latch.countDown(); - } - if (newStatus == ConnectionStatus.FAILED_TO_CONNECT) { - failedToConnectEvent = true; - latch.countDown(); - } - if (newStatus == ConnectionStatus.DISCONNECTED) { - disconnectEvent = true; - latch.countDown(); - } - } - } - - private class TrivialStorageCredentials implements StorageCredentials { - private String user; - private char[] pw; - private TrivialStorageCredentials(String user, char[] password) { - this.user = user; - this.pw = password; - } - @Override - public String getUsername() { - return user; - } - @Override - public char[] getPassword() { - return pw; - } - } - - private static class PrepareStatementWebStorage extends WebStorage { - - private int counter; - - public PrepareStatementWebStorage(String url, StorageCredentials creds, - SSLConfiguration sslConf) throws StorageException { - super(url, creds, sslConf); - } - - @Override - <T extends Pojo> WebPreparedStatementHolder sendPrepareStmtRequest(StatementDescriptor<T> desc, int invokationCounter) - throws DescriptorParsingException { - int numParams = counter++; - int stmtId = counter++; - SharedStateId id = new SharedStateId(stmtId, UUID.randomUUID()); - return new WebPreparedStatementHolder(TestObj.class, numParams, id); - } - } - - private static class TestAggregate implements AggregateResult { - // nothing - } -} -
--- a/web/common/pom.xml Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,116 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - - Copyright 2012-2017 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. - ---> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> - - <parent> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-web</artifactId> - <version>1.99.12-SNAPSHOT</version> - </parent> - - <artifactId>thermostat-web-common</artifactId> - <packaging>bundle</packaging> - - <name>Thermostat Web Common</name> - - <dependencies> - - <dependency> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-common-test</artifactId> - <version>${project.version}</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>com.google.code.gson</groupId> - <artifactId>gson</artifactId> - </dependency> - <dependency> - <groupId>commons-beanutils</groupId> - <artifactId>commons-beanutils</artifactId> - </dependency> - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-common-core</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-storage-core</artifactId> - <version>${project.version}</version> - </dependency> - </dependencies> - - <build> - <plugins> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <extensions>true</extensions> - <configuration> - <instructions> - <Bundle-SymbolicName>com.redhat.thermostat.web.common</Bundle-SymbolicName> - <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor> - <Export-Package> - com.redhat.thermostat.web.common, - com.redhat.thermostat.web.common.typeadapters, - </Export-Package> - <!-- Do not autogenerate uses clauses in Manifests --> - <_nouses>true</_nouses> - </instructions> - </configuration> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-surefire-plugin</artifactId> - <configuration> - <excludedGroups>${surefire-perftests-exclusion}</excludedGroups> - </configuration> - </plugin> - </plugins> - </build> - -</project> -
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/PreparedStatementResponseCode.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.web.common; - -import com.redhat.thermostat.storage.core.PreparedStatement; - -/** - * Common response codes for prepared statement responses. - * - */ -public interface PreparedStatementResponseCode { - - /** - * Response code for successful prepared queries. - */ - public static final int QUERY_SUCCESS = 0; - - /** - * Generic error code for failed queries. Usually - * returned if get-more failed for an unknown reason. - */ - public static final int QUERY_FAILURE = -100; - - - /** - * Failure code for expired cursors. Usually returned if - * get-more requests failed because the underlying cursor - * was null. - */ - public static final int GET_MORE_NULL_CURSOR = -151; - - /** - * Response code if patching of a {@link PreparedStatement} failed during - * statement execution. - * <p> - * For example a patching failure could happen if there was a type mismatch - * between the descriptor and the parameter provided. Providing not all - * parameters and attempting execution of a {@link PreparedStatement} would - * be another example. - */ - public static final int ILLEGAL_PATCH = -1; - - /** - * Failure code for mismatching server tokens. This is usually happening if - * client and server get out of sync due to re-deployment or the like. - * Client should recover from this automatically by clearing the client - * cache and preparing statements again. - */ - public static final int PREP_STMT_BAD_STOKEN = -2; - - /** - * Failure to execute a prepared write statement for some unknown reason. - */ - public static final int WRITE_GENERIC_FAILURE = -200; - -} -
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/SharedStateId.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,85 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.web.common; - -import java.util.Objects; -import java.util.UUID; - -/** - * Simple data structure which uniquely identifies shared state between - * client (WebStorage) and server (WebStorageEndPoint). - * - */ -public class SharedStateId { - - // The id of the statement - private final int id; - // A unique token only used once per webapp deployment. - private final UUID serverToken; - - public SharedStateId(int id, UUID serverToken) { - this.id = id; - this.serverToken = serverToken; - } - - public int getId() { - return id; - } - - public UUID getServerToken() { - return serverToken; - } - - @Override - public boolean equals(Object other) { - if (other == null || other.getClass() != SharedStateId.class) { - return false; - } - SharedStateId o = (SharedStateId)other; - return id == o.id && serverToken.equals(o.serverToken); - } - - @Override - public int hashCode() { - return Objects.hash(id, serverToken); - } - - @Override - public String toString() { - return serverToken + ":" + id; - } -}
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/WebPreparedStatement.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,159 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.web.common; - -import com.redhat.thermostat.storage.core.Cursor; -import com.redhat.thermostat.storage.core.ParsedStatement; -import com.redhat.thermostat.storage.core.PreparedParameters; -import com.redhat.thermostat.storage.core.PreparedStatement; -import com.redhat.thermostat.storage.core.StatementExecutionException; -import com.redhat.thermostat.storage.model.Pojo; - -public class WebPreparedStatement<T extends Pojo> implements - PreparedStatement<T> { - - private PreparedParameters params; - private SharedStateId statementId; - - public WebPreparedStatement(int numParams, SharedStateId statementId) { - this.params = new PreparedParameters(numParams); - this.statementId = statementId; - } - - public WebPreparedStatement() { - // nothing. used for serialization - } - - public SharedStateId getStatementId() { - return statementId; - } - - public void setStatementId(SharedStateId statementId) { - this.statementId = statementId; - } - - public PreparedParameters getParams() { - return params; - } - - public void setParams(PreparedParameters params) { - this.params = params; - } - - @Override - public void setBoolean(int paramIndex, boolean paramValue) { - params.setBoolean(paramIndex, paramValue); - } - - @Override - public void setBooleanList(int paramIndex, boolean[] paramValue) { - params.setBooleanList(paramIndex, paramValue); - } - - @Override - public void setLong(int paramIndex, long paramValue) { - params.setLong(paramIndex, paramValue); - } - - @Override - public void setLongList(int paramIndex, long[] paramValue) { - params.setLongList(paramIndex, paramValue); - } - - @Override - public void setInt(int paramIndex, int paramValue) { - params.setInt(paramIndex, paramValue); - } - - @Override - public void setIntList(int paramIndex, int[] paramValue) { - params.setIntList(paramIndex, paramValue); - } - - @Override - public void setString(int paramIndex, String paramValue) { - params.setString(paramIndex, paramValue); - } - - @Override - public void setStringList(int paramIndex, String[] paramValue) { - params.setStringList(paramIndex, paramValue); - } - - @Override - public void setDouble(int paramIndex, double paramValue) { - params.setDouble(paramIndex, paramValue); - } - - @Override - public void setDoubleList(int paramIndex, double[] paramValue) { - params.setDoubleList(paramIndex, paramValue); - } - - @Override - public void setPojo(int paramIndex, Pojo paramValue) { - params.setPojo(paramIndex, paramValue); - } - - @Override - public void setPojoList(int paramIndex, Pojo[] paramValue) { - params.setPojoList(paramIndex, paramValue); - } - - @Override - public int execute() throws StatementExecutionException { - // actual implementation should override this - throw new IllegalStateException(); - } - - @Override - public Cursor<T> executeQuery() - throws StatementExecutionException { - // actual implementation should override this - throw new IllegalStateException(); - } - - @Override - public ParsedStatement<T> getParsedStatement() { - // Should never be called on WebPreparedStatement - // It should use the implementation of the backing - // storage implementation instead. - throw new IllegalStateException(); - } - -} -
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/WebPreparedStatementResponse.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,88 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.web.common; - -/** - * Model class as returned upon preparing statements. - */ -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; - - /** - * Response code indicating that the server token - * of the client and the token the server is using - * did not match. - */ - public static final int CATEGORY_OUT_OF_SYNC = -3; - - public WebPreparedStatementResponse() { - // Should always be set using the setter before it - // is retrieved. Since 0 is a bad default for this, - // we set it to -1 in order to make this an invalid - // value right away. - this.numFreeVariables = -1; - } - - private int numFreeVariables; - private SharedStateId statementId; - - public SharedStateId getStatementId() { - return statementId; - } - - public void setStatementId(SharedStateId statementId) { - this.statementId = statementId; - } - - public int getNumFreeVariables() { - return numFreeVariables; - } - - public void setNumFreeVariables(int freeVars) { - this.numFreeVariables = freeVars; - } -} -
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/WebQueryResponse.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,113 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.web.common; - -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; - -import com.redhat.thermostat.storage.model.Pojo; - -/** - * Model object for prepared query execution responses. - * - */ -public class WebQueryResponse<T extends Pojo> { - - private int cursorId; - private boolean hasMoreBatches; - private int responseCode; - private T[] resultList; - - public int getResponseCode() { - return responseCode; - } - - public void setResponseCode(int responseCode) { - this.responseCode = responseCode; - } - - public T[] getResultList() { - return resultList; - } - - public void setResultList(T[] resultList) { - this.resultList = resultList; - } - - public void setHasMoreBatches(boolean hasMoreBatches) { - this.hasMoreBatches = hasMoreBatches; - } - - public boolean hasMoreBatches() { - return hasMoreBatches; - } - - public int getCursorId() { - return cursorId; - } - - public void setCursorId(int cursorId) { - this.cursorId = cursorId; - } - - public ParameterizedType getRuntimeParametrizedType(final Class<T> dataClass) { - ParameterizedType webQueryResponseType = new ParameterizedType() { - - @Override - public Type getRawType() { - return WebQueryResponse.class; - } - - @Override - public Type getOwnerType() { - // top-level type, must return null - return null; - } - - @Override - public Type[] getActualTypeArguments() { - // WebQueryResponse has only one type parameter, which - // is the actual data class - return new Type[] { - dataClass - }; - } - }; - return webQueryResponseType; - } -} -
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/typeadapters/PojoTypeAdapter.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,230 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.web.common.typeadapters; - -import java.beans.PropertyDescriptor; -import java.io.IOException; -import java.lang.ref.SoftReference; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.Objects; - -import org.apache.commons.beanutils.PropertyUtils; - -import com.google.gson.Gson; -import com.google.gson.TypeAdapter; -import com.google.gson.TypeAdapterFactory; -import com.google.gson.reflect.TypeToken; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonToken; -import com.google.gson.stream.JsonWriter; -import com.redhat.thermostat.storage.core.Entity; -import com.redhat.thermostat.storage.core.Persist; -import com.redhat.thermostat.storage.model.Pojo; - -/** - * A generic type adapter for types implementing {@link Pojo}. It uses - * no special knowledge of the actual implementation types. - * - */ -class PojoTypeAdapter<T extends Pojo> extends TypeAdapter<Pojo> { - - private final Class<T> runtimeType; - private final Gson gson; - private final TypeAdapterFactory pojoFactory; - private SoftReference<HashMap<String, PropertyDescriptor>> propsCache; - - PojoTypeAdapter(TypeAdapterFactory factory, Gson gson, Class<T> runtimeType) { - assert(Pojo.class.isAssignableFrom(runtimeType)); - this.runtimeType = Objects.requireNonNull(runtimeType); - this.gson = gson; - this.pojoFactory = factory; - // cache will be filled once first used. - this.propsCache = new SoftReference<>(null); - } - - @SuppressWarnings("unchecked") - @Override - public void write(JsonWriter out, Pojo value) throws IOException { - // handle null - if (value == null) { - out.nullValue(); - return; - } - - Class<?> cls = value.getClass(); - if (! cls.isAnnotationPresent(Entity.class)) { - System.err.println("attempt to serialize non-Entity class: " + cls.getName()); - throw new IllegalArgumentException("attempt to serialize non-Entity class: " + cls.getName()); - } - - out.beginObject(); - - PropertyDescriptor[] descs = PropertyUtils.getPropertyDescriptors(value); - for (PropertyDescriptor desc : descs) { - Method readMethod = desc.getReadMethod(); - if (readMethod != null && readMethod.isAnnotationPresent(Persist.class)) { - String name = desc.getName(); - out.name(name); - try { - Object val = PropertyUtils.getProperty(value, name); - if (val == null) { - out.nullValue(); - } else { - // non-null member case - if (Pojo.class.isAssignableFrom(val.getClass())) { - // recursive case - PojoTypeAdapter<T> pojoMemAdapter= new PojoTypeAdapter<>(pojoFactory, gson, (Class<T>)val.getClass()); - pojoMemAdapter.write(out, (T)val); - } else { - // base case: non-pojo type - Class<?> valClass = val.getClass(); - @SuppressWarnings("rawtypes") - TypeToken memberTypeToken = TypeToken.get(valClass); - @SuppressWarnings({"rawtypes"}) - TypeAdapter memberTypeAdapter = getNonPojoTypeAdapter(memberTypeToken); - memberTypeAdapter.write(out, val); - } - } - } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { - throw new RuntimeException(e); - } - } else if (readMethod == null) { - System.err.println("WARNING: property without read method: " + value.getClass().getName() + "." + desc.getName()); - } - } - - out.endObject(); - } - - @Override - public Pojo read(JsonReader in) throws IOException { - // handle null - JsonToken token = in.peek(); - if (token == JsonToken.NULL) { - return null; - } - - - try { - in.beginObject(); - - Pojo pojo = runtimeType.newInstance(); - // loop over names in JSON - processNamesValues(pojo, in); - - in.endObject(); - - return pojo; - } catch (InstantiationException | IllegalAccessException e) { - throw new RuntimeException(e); - } - } - - private void processNamesValues(Pojo pojo, JsonReader in) throws IOException { - JsonToken token = in.peek(); - switch(token) { - case NAME: - String name = in.nextName(); - processValue(pojo, in, name); - // recursive case - processNamesValues(pojo, in); - break; - case END_OBJECT: - // Base case - return; - default: - throw new IllegalStateException("Expected NAME or END_OBJECT. Was: " + token); - } - } - - private void processValue(Pojo pojo, JsonReader in, String name) throws IOException { - try { - PropertyDescriptor desc = getPropDescriptor(pojo, name); - if (desc == null) { - throw new IllegalStateException("Property descriptor null for: " + name); - } - Method writeMethod = desc.getWriteMethod(); - Object value = null; - if (writeMethod != null && writeMethod.isAnnotationPresent(Persist.class)) { - Class<?> memberType = desc.getPropertyType(); - if (Pojo.class.isAssignableFrom(memberType)) { - // recursive case - @SuppressWarnings("unchecked") // We've just checked the cast to Class<T> works - PojoTypeAdapter<T> memberAdapter = new PojoTypeAdapter<>(pojoFactory, gson, (Class<T>)memberType); - value = (Pojo)memberAdapter.read(in); - } else { - // base case: non-pojo type - TypeToken<?> memberTypeToken = TypeToken.get(memberType); - TypeAdapter<?> memberTypeAdapter = getNonPojoTypeAdapter(memberTypeToken); - value = memberTypeAdapter.read(in); - } - PropertyUtils.setProperty(pojo, name, value); - } - } catch (IllegalAccessException | InvocationTargetException e) { - throw new RuntimeException(e); - } catch (NoSuchMethodException e) { - System.err.println("Setter for '" + name + "' not found. The value will be ignored."); - } - } - - private PropertyDescriptor getPropDescriptor(Pojo pojo, String name) { - if (propsCache.get() == null) { - // build cache - HashMap<String, PropertyDescriptor> propDescCache = new HashMap<>(); - PropertyDescriptor[] descs = PropertyUtils.getPropertyDescriptors(pojo); - PropertyDescriptor wanted = null; - for (PropertyDescriptor desc: descs) { - propDescCache.put(desc.getName(), desc); - if (desc.getName().equals(name)) { - wanted = desc; - } - } - propsCache = new SoftReference<>(propDescCache); - return wanted; - } else { - HashMap<String, PropertyDescriptor> cacheMap = propsCache.get(); - return cacheMap.get(name); - } - } - - private <S> TypeAdapter<S> getNonPojoTypeAdapter(TypeToken<S> nonPojoType) { - return gson.getDelegateAdapter(pojoFactory, nonPojoType); - } - -}
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/typeadapters/PojoTypeAdapterFactory.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.web.common.typeadapters; - -import com.google.gson.Gson; -import com.google.gson.TypeAdapter; -import com.google.gson.TypeAdapterFactory; -import com.google.gson.reflect.TypeToken; -import com.redhat.thermostat.storage.model.Pojo; - -public class PojoTypeAdapterFactory implements TypeAdapterFactory { - - @Override - public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) { - Class<?> rawType = type.getRawType(); - if (Pojo.class.isAssignableFrom(rawType)) { - // We've just verified that we have a Pojo type. The unchecked - // cast is safe. - @SuppressWarnings("unchecked") - Class<T> castedType = (Class<T>)rawType; - @SuppressWarnings({ "unchecked", "rawtypes" }) - TypeAdapter<T> ta = (TypeAdapter<T>)new PojoTypeAdapter(this, gson, castedType); - return ta; - } - return null; - } - -}
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/typeadapters/PreparedParameterTypeAdapter.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,368 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.web.common.typeadapters; - -import java.io.IOException; -import java.lang.reflect.Array; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import com.google.gson.Gson; -import com.google.gson.TypeAdapter; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonToken; -import com.google.gson.stream.JsonWriter; -import com.redhat.thermostat.storage.core.PreparedParameter; -import com.redhat.thermostat.storage.model.Pojo; - -/** - * GSON type adapter for {@link PreparedParameter}. - * - */ -class PreparedParameterTypeAdapter extends TypeAdapter<PreparedParameter> { - - private static final String PROP_TYPE = "type"; - private static final String PROP_VALUE = "value"; - private static final Set<Class<?>> VALID_CLASSES; - private static final Set<Class<?>> PRIMITIVES_NOT_ALLOWING_NULL_VAL; - private static final Set<Class<?>> BASIC_TYPES; - // maps type names to classes: - // "int" => int.class , "double" => double.class, "[I" => int[].class - // and so on. - private static final Map<String, Class<?>> CLASSES_LOOKUP_TABLE; - - private final Gson gson; - - static { - VALID_CLASSES = new HashSet<>(); - BASIC_TYPES = new HashSet<>(); - BASIC_TYPES.add(int.class); - BASIC_TYPES.add(long.class); - BASIC_TYPES.add(boolean.class); - BASIC_TYPES.add(double.class); - BASIC_TYPES.add(String.class); - CLASSES_LOOKUP_TABLE = new HashMap<>(); - CLASSES_LOOKUP_TABLE.put(int.class.getName(), int.class); - CLASSES_LOOKUP_TABLE.put(long.class.getName(), long.class); - CLASSES_LOOKUP_TABLE.put(boolean.class.getName(), boolean.class); - CLASSES_LOOKUP_TABLE.put(double.class.getName(), double.class); - CLASSES_LOOKUP_TABLE.put(String.class.getName(), String.class); - CLASSES_LOOKUP_TABLE.put(int[].class.getName(), int[].class); - CLASSES_LOOKUP_TABLE.put(long[].class.getName(), long[].class); - CLASSES_LOOKUP_TABLE.put(boolean[].class.getName(), boolean[].class); - CLASSES_LOOKUP_TABLE.put(double[].class.getName(), double[].class); - CLASSES_LOOKUP_TABLE.put(String[].class.getName(), String[].class); - VALID_CLASSES.addAll(CLASSES_LOOKUP_TABLE.values()); - PRIMITIVES_NOT_ALLOWING_NULL_VAL = new HashSet<>(); - PRIMITIVES_NOT_ALLOWING_NULL_VAL.add(int.class); - PRIMITIVES_NOT_ALLOWING_NULL_VAL.add(long.class); - PRIMITIVES_NOT_ALLOWING_NULL_VAL.add(boolean.class); - PRIMITIVES_NOT_ALLOWING_NULL_VAL.add(double.class); - } - - - PreparedParameterTypeAdapter(Gson gson) { - this.gson = gson; - } - - - private Class<?> deserializeTypeVal(String className) { - Class<?> typeVal = null; - if (CLASSES_LOOKUP_TABLE.containsKey(className)) { - typeVal = CLASSES_LOOKUP_TABLE.get(className); - } else { - try { - // We need this for Pojo + Pojo list type params. For pojo - // lists the name we get passed is the component type of the - // array. - typeVal = Class.forName(className); - } catch (ClassNotFoundException e) { - throw new IllegalStateException("Failed to resolve class type for '" - + className + "'."); - } - } - validateSaneClassName(typeVal); - return typeVal; - } - - private void validatePrimitivesForNull(Object value, Class<?> valType) { - if (PRIMITIVES_NOT_ALLOWING_NULL_VAL.contains(valType) && value == null) { - // illegal value for primitive type. according to JLS spec they all - // have default values and are never null. - throw new IllegalStateException( valType + " primitive" + - " does not accept a null value!"); - } - } - - // Allow valid classes + Pojo types, refuse everything else - private void validateSaneClassName(Class<?> clazz) { - // isAssignableFrom throws NPE if clazz is null. - if (VALID_CLASSES.contains(clazz) || - Pojo.class.isAssignableFrom(clazz)) { - return; - } - throw new IllegalStateException("Illegal type of parameter " + clazz.getCanonicalName()); - } - - @Override - public PreparedParameter read(JsonReader reader) throws IOException { - if (reader.peek() == JsonToken.NULL) { - reader.nextNull(); - return null; - } - reader.beginObject(); - - Class<?> type = readType(reader); - - assert(type != null); - assert(Pojo.class.isAssignableFrom(type) || VALID_CLASSES.contains(type)); - - Object val = readValue(reader, type); - reader.endObject(); - - PreparedParameter param = new PreparedParameter(); - param.setValue(val); - param.setType(type); - return param; - } - - private Class<?> readType(JsonReader reader) throws IOException { - String name = reader.nextName(); - if (!name.equals(PROP_TYPE)) { - throw new IllegalStateException("Expected " + PROP_VALUE + " but was " + name); - } - String className = reader.nextString(); - return deserializeTypeVal(className); - } - - private Object readValue(JsonReader reader, Class<?> valType) throws IOException { - // values may be null. In that case they are missing from the JSON - // string. Be sure to handle that case early. - if (reader.peek() == JsonToken.END_OBJECT) { - return null; // null parameter value - } - String name = reader.nextName(); - if (!name.equals(PROP_VALUE)) { - throw new IllegalStateException("Expected " + PROP_VALUE + " but was " + name); - } - - JsonToken token = reader.peek(); - if (token == JsonToken.NULL) { - reader.nextNull(); - // Be sure to not allow null values for primitives. Note: - // valType may be an array type for which null is fine. - validatePrimitivesForNull(null, valType); - return null; // null value - } - - // special case for Pojo/Pojo list types. In that case, the valType - // is the component type for arrays. In order to distinguish pojo - // lists from pojos, we use JSON's array info about the value element. - if (token == JsonToken.BEGIN_ARRAY && !valType.isArray()) { - assert(Pojo.class.isAssignableFrom(valType)); - Class<?> arrayType = Array.newInstance(valType, 0).getClass(); - TypeAdapter<?> pojoArrayTa = gson.getAdapter(arrayType); - Object val = pojoArrayTa.read(reader); - return val; - } else { - TypeAdapter<?> nonPojoTypeAdapter = gson.getAdapter(valType); - Object val = nonPojoTypeAdapter.read(reader); - validatePrimitivesForNull(val, valType); - return val; - } - } - - - @Override - public void write(JsonWriter writer, PreparedParameter param) - throws IOException { - if (param == null) { - writer.nullValue(); - return; - } - writer.beginObject(); - - // serialize type which must not be null - writer.name(PROP_TYPE); - if (param.getType() == null) { - throw new IllegalStateException("Type of prepared parameter must not be null"); - } - String typeStr = param.getType().getName(); - writer.value(typeStr); - - // serialize value - writer.name(PROP_VALUE); - serializeValue(writer, param); - - writer.endObject(); - } - - private void serializeValue(JsonWriter writer, PreparedParameter param) throws IOException { - if (param.getValue() == null) { - writer.nullValue(); - return; - } - - Object val = param.getValue(); - if (val.getClass().isArray()) { - serializeArrayValue(writer, param); - } else { - serializeBasicValue(writer, param); - } - } - - /* - * Serialize single basic type or Pojo. - */ - private void serializeBasicValue(JsonWriter writer, PreparedParameter param) throws IOException { - assert(param.getValue() != null); - - Class<?> type = param.getType(); - if (BASIC_TYPES.contains(type)) { - serializeSingleBasicValue(writer, param.getValue(), param.getType()); - } else { - assert(Pojo.class.isAssignableFrom(param.getType())); - serializeSinglePojo(writer, param); - } - } - - private void serializeSinglePojo(JsonWriter writer, PreparedParameter param) throws IOException { - assert(param.getValue() != null); - - serializeSinglePojoImpl(writer, param.getValue(), param.getType()); - } - - private void serializeSinglePojoImpl(JsonWriter writer, Object value, Class<?> type) throws IOException { - // precondition(s) - assert(Pojo.class.isAssignableFrom(type)); - assert(value instanceof Pojo); - assert(value != null && !value.getClass().isArray()); - - TypeAdapter<Pojo> pojoTypeAdapter = getTypeAdapter(Pojo.class); - pojoTypeAdapter.write(writer, (Pojo)value); - } - - /* - * Serialize an array of primitives or Pojos - */ - private void serializeArrayValue(JsonWriter writer, - PreparedParameter param) throws IOException { - Class<?> valType = param.getValue().getClass(); - Class<?> typeType = param.getType(); - // Special case pojo list types: the value class is of array type for - // them, but the type is the component type. - if (valType.isArray() && !typeType.isArray()) { - assert(Pojo.class.isAssignableFrom(typeType)); - serializePojoList(writer, param); - } else { - serializeBasicList(writer, param); - } - } - - /* - * Serialize a list of known primitives: boolean, int, long, double, String - */ - private void serializeBasicList(JsonWriter writer, - PreparedParameter param) throws IOException { - // preconditions - assert(param.getValue() != null); - assert(param.getValue().getClass().isArray()); - assert(param.getType().isArray()); - - writer.beginArray(); - int length = Array.getLength(param.getValue()); - for (int i = 0; i < length; i++) { - Object elemVal = Array.get(param.getValue(), i); - Class<?> elemType = param.getType().getComponentType(); - serializeSingleBasicValue(writer, elemVal, elemType); - } - writer.endArray(); - } - - private void serializeSingleBasicValue(JsonWriter writer, Object object, Class<?> type) throws IOException { - assert(!type.isArray()); - if (object == null) { - // must have been a String type - // as other primitive types won't allow null - writer.nullValue(); - return; - } - assert(!object.getClass().isArray()); - assert(BASIC_TYPES.contains(type)); - if (type.isPrimitive()) { - if (type == int.class) { - Integer intVal = (Integer)object; - writer.value(intVal); - } else if (type == long.class) { - writer.value((long)object); - } else if (type == double.class) { - writer.value((double)object); - } else if (type == boolean.class) { - writer.value((boolean)object); - } - } else { - assert(object instanceof String); - writer.value((String)object); - } - } - - /* - * Serialized an array of Pojo and only an array of Pojo - */ - private void serializePojoList(JsonWriter writer, PreparedParameter param) throws IOException { - // preconditions - assert(param.getValue() != null); - assert(Pojo.class.isAssignableFrom(param.getType())); - assert(param.getValue().getClass().isArray()); - - int length = Array.getLength(param.getValue()); - writer.beginArray(); - for (int i = 0; i < length; i++) { - Object value = Array.get(param.getValue(), i); - serializeSinglePojoImpl(writer, value, param.getType()); - } - writer.endArray(); - } - - private <T> TypeAdapter<T> getTypeAdapter(Class<T> typeClass) { - return gson.getAdapter(typeClass); - } - -} -
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/typeadapters/PreparedParameterTypeAdapterFactory.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.web.common.typeadapters; - -import com.google.gson.Gson; -import com.google.gson.TypeAdapter; -import com.google.gson.TypeAdapterFactory; -import com.google.gson.reflect.TypeToken; -import com.redhat.thermostat.storage.core.PreparedParameter; - -public class PreparedParameterTypeAdapterFactory implements TypeAdapterFactory { - - @Override - public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) { - Class<?> rawType = type.getRawType(); - if (rawType == PreparedParameter.class) { - @SuppressWarnings("unchecked") // we've just verified this will work - TypeAdapter<T> ta = (TypeAdapter<T>) new PreparedParameterTypeAdapter(gson); - return ta; - } else { - return null; - } - } - -}
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/typeadapters/PreparedParametersTypeAdapter.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,108 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.web.common.typeadapters; - -import java.io.IOException; -import java.lang.reflect.Field; - -import com.google.gson.Gson; -import com.google.gson.TypeAdapter; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonToken; -import com.google.gson.stream.JsonWriter; -import com.redhat.thermostat.storage.core.PreparedParameter; -import com.redhat.thermostat.storage.core.PreparedParameters; - -class PreparedParametersTypeAdapter extends TypeAdapter<PreparedParameters> { - - private final Gson gson; - private final Field paramsField; - - PreparedParametersTypeAdapter(Gson gson) { - this.gson = gson; - this.paramsField = getParametersField(); - } - - @Override - public void write(JsonWriter out, PreparedParameters value) - throws IOException { - // handle null - if (value == null) { - out.nullValue(); - return; - } - - TypeAdapter<PreparedParameter[]> paramsTa = gson.getAdapter(PreparedParameter[].class); - paramsTa.write(out, value.getParams()); - } - - @Override - public PreparedParameters read(JsonReader in) throws IOException { - // handle null - if (in.peek() == JsonToken.NULL) { - in.nextNull(); - return null; - } - - TypeAdapter<PreparedParameter[]> paramsTa = gson.getAdapter(PreparedParameter[].class); - PreparedParameters params = new PreparedParameters(0); - PreparedParameter[] payload = paramsTa.read(in); - setParamenters(params, payload); - return params; - } - - private void setParamenters(PreparedParameters params, PreparedParameter[] payload) { - // Set parameters via reflection in order to not be forced to - // introduce a public setter. - try { - paramsField.set(params, payload); - } catch (SecurityException | IllegalArgumentException | IllegalAccessException e) { - throw new IllegalStateException("Failed to set params field"); - } - } - - private Field getParametersField() { - try { - Field field = PreparedParameters.class.getDeclaredField("params"); - field.setAccessible(true); - return field; - } catch (NoSuchFieldException | SecurityException e) { - throw new IllegalStateException("params field not found"); - } - } - -}
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/typeadapters/PreparedParametersTypeAdapterFactory.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.web.common.typeadapters; - -import com.google.gson.Gson; -import com.google.gson.TypeAdapter; -import com.google.gson.TypeAdapterFactory; -import com.google.gson.reflect.TypeToken; -import com.redhat.thermostat.storage.core.PreparedParameters; - -public class PreparedParametersTypeAdapterFactory implements TypeAdapterFactory { - - @Override - public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) { - Class<?> rawType = type.getRawType(); - if (rawType == PreparedParameters.class) { - @SuppressWarnings("unchecked") - TypeAdapter<T> ta = (TypeAdapter<T>)new PreparedParametersTypeAdapter(gson); - return ta; - } - return null; - } - -}
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/typeadapters/SharedStateIdTypeAdapter.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,113 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.web.common.typeadapters; - -import java.io.IOException; -import java.util.UUID; - -import com.google.gson.TypeAdapter; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonToken; -import com.google.gson.stream.JsonWriter; -import com.redhat.thermostat.web.common.SharedStateId; - -class SharedStateIdTypeAdapter extends TypeAdapter<SharedStateId> { - - private static final String PROP_STMT_ID = "sid"; - private static final String PROP_SERVER_TOKEN = "stok"; - - @Override - public void write(JsonWriter out, SharedStateId value) throws IOException { - // handle null - if (value == null) { - out.nullValue(); - return; - } - - out.beginObject(); - - // statement id - out.name(PROP_STMT_ID); - out.value(value.getId()); - - // server token, may be null - if (value.getServerToken() != null) { - out.name(PROP_SERVER_TOKEN); - out.value(value.getServerToken().toString()); - } else { - out.name(PROP_SERVER_TOKEN); - out.nullValue(); - } - - out.endObject(); - - } - - @Override - public SharedStateId read(JsonReader in) throws IOException { - // handle null - if (in.peek() == JsonToken.NULL) { - in.nextNull(); - return null; - } - - in.beginObject(); - - - // statement id - String name = in.nextName(); - if (!name.equals(PROP_STMT_ID)) { - throw new IllegalStateException("Expected name " + PROP_STMT_ID + " but was " + name); - } - int stmtId = in.nextInt(); - - UUID serverToken = null; - if (in.peek() == JsonToken.NAME) { - name = in.nextName(); - if (!name.equals(PROP_SERVER_TOKEN)) { - throw new IllegalStateException("Expected name " + PROP_SERVER_TOKEN + " but was " + name); - } - String sToken = in.nextString(); - serverToken = UUID.fromString(sToken); - } - in.endObject(); - - return new SharedStateId(stmtId, serverToken); - } - - -}
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/typeadapters/SharedStateIdTypeAdapterFactory.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.web.common.typeadapters; - -import com.google.gson.Gson; -import com.google.gson.TypeAdapter; -import com.google.gson.TypeAdapterFactory; -import com.google.gson.reflect.TypeToken; -import com.redhat.thermostat.web.common.SharedStateId; - -public class SharedStateIdTypeAdapterFactory implements TypeAdapterFactory { - - @Override - public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) { - Class<?> rawType = type.getRawType(); - if (rawType == SharedStateId.class) { - @SuppressWarnings("unchecked") - TypeAdapter<T> ta = (TypeAdapter<T>)new SharedStateIdTypeAdapter(); - return ta; - } - return null; - } - -}
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/typeadapters/WebPreparedStatementResponseTypeAdapter.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,107 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.web.common.typeadapters; - -import java.io.IOException; - -import com.google.gson.TypeAdapter; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonToken; -import com.google.gson.stream.JsonWriter; -import com.redhat.thermostat.web.common.SharedStateId; -import com.redhat.thermostat.web.common.WebPreparedStatementResponse; - -class WebPreparedStatementResponseTypeAdapter extends - TypeAdapter<WebPreparedStatementResponse> { - - private static final String NUM_FREE_VARS_NAME = "numFreeVars"; - private static final String STMT_ID_NAME = "stmtId"; - private final TypeAdapter<SharedStateId> sharedStateTa; - - WebPreparedStatementResponseTypeAdapter(TypeAdapter<SharedStateId> sharedStateTa) { - this.sharedStateTa = sharedStateTa; - } - - @Override - public WebPreparedStatementResponse read(JsonReader reader) - throws IOException { - if (reader.peek() == JsonToken.NULL) { - reader.nextNull(); - return null; - } - - WebPreparedStatementResponse response = new WebPreparedStatementResponse(); - - reader.beginObject(); - String name = reader.nextName(); - if (name.equals(NUM_FREE_VARS_NAME)) { - response.setNumFreeVariables(reader.nextInt()); - } - name = reader.nextName(); - if (name.equals(STMT_ID_NAME)) { - SharedStateId id = sharedStateTa.read(reader); - response.setStatementId(id); - } - reader.endObject(); - - return response; - } - - @Override - public void write(JsonWriter writer, WebPreparedStatementResponse value) - throws IOException { - if (value == null) { - writer.nullValue(); - return; - } - - int freeVars = value.getNumFreeVariables(); - SharedStateId stmtId = value.getStatementId(); - - writer.beginObject(); - - // Free variables - writer.name(NUM_FREE_VARS_NAME); - writer.value(freeVars); - // stmt id - writer.name(STMT_ID_NAME); - sharedStateTa.write(writer, stmtId); - - writer.endObject(); - } - -}
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/typeadapters/WebPreparedStatementResponseTypeAdapterFactory.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.web.common.typeadapters; - -import com.google.gson.Gson; -import com.google.gson.TypeAdapter; -import com.google.gson.TypeAdapterFactory; -import com.google.gson.reflect.TypeToken; -import com.redhat.thermostat.web.common.SharedStateId; -import com.redhat.thermostat.web.common.WebPreparedStatementResponse; - -public class WebPreparedStatementResponseTypeAdapterFactory implements - TypeAdapterFactory { - - @Override - public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) { - Class<?> rawType = type.getRawType(); - if (rawType == WebPreparedStatementResponse.class) { - TypeAdapter<SharedStateId> sharedStateIdTa = gson.getAdapter(SharedStateId.class); - @SuppressWarnings("unchecked") - TypeAdapter<T> ta = (TypeAdapter<T>)new WebPreparedStatementResponseTypeAdapter(sharedStateIdTa); - return ta; - } - return null; - } - -}
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/typeadapters/WebPreparedStatementTypeAdapter.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,123 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.web.common.typeadapters; - -import java.io.IOException; - -import com.google.gson.Gson; -import com.google.gson.TypeAdapter; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonToken; -import com.google.gson.stream.JsonWriter; -import com.redhat.thermostat.storage.core.PreparedParameters; -import com.redhat.thermostat.web.common.SharedStateId; -import com.redhat.thermostat.web.common.WebPreparedStatement; - -@SuppressWarnings("rawtypes") -class WebPreparedStatementTypeAdapter extends TypeAdapter<WebPreparedStatement> { - - private static final String PROP_PARAMS = "p"; - private static final String PROP_STMT_ID = "sid"; - - private final TypeAdapter<SharedStateId> sharedStateTa; - private final TypeAdapter<PreparedParameters> prepParamsTa; - - WebPreparedStatementTypeAdapter(Gson gson) { - this.sharedStateTa = gson.getAdapter(SharedStateId.class); - this.prepParamsTa = gson.getAdapter(PreparedParameters.class); - } - - @Override - public void write(JsonWriter out, WebPreparedStatement value) - throws IOException { - // handle null - if (value == null) { - out.nullValue(); - return; - } - - out.beginObject(); - - // statement id - out.name(PROP_STMT_ID); - sharedStateTa.write(out, value.getStatementId()); - - // prepared parameters - out.name(PROP_PARAMS); - prepParamsTa.write(out, value.getParams()); - - out.endObject(); - } - - @Override - public WebPreparedStatement read(JsonReader in) throws IOException { - // handle null - if (in.peek() == JsonToken.NULL) { - in.nextNull(); - return null; - } - - in.beginObject(); - - - // statement id - String name = in.nextName(); - if (!name.equals(PROP_STMT_ID)) { - throw new IllegalStateException("Expected name " + PROP_STMT_ID + " but was " + name); - } - SharedStateId id = sharedStateTa.read(in); - - // params - PreparedParameters params = null; - // params value might be null and missing. - if (in.peek() == JsonToken.NAME) { - name = in.nextName(); - if (!name.equals(PROP_PARAMS)) { - throw new IllegalStateException("Expected name " + PROP_PARAMS + " but was " + name); - } - params = prepParamsTa.read(in); - } - - in.endObject(); - - WebPreparedStatement<?> stmt = new WebPreparedStatement<>(); - stmt.setParams(params); - stmt.setStatementId(id); - return stmt; - } - -}
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/typeadapters/WebPreparedStatementTypeAdapterFactory.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.web.common.typeadapters; - -import com.google.gson.Gson; -import com.google.gson.TypeAdapter; -import com.google.gson.TypeAdapterFactory; -import com.google.gson.reflect.TypeToken; -import com.redhat.thermostat.web.common.WebPreparedStatement; - -public class WebPreparedStatementTypeAdapterFactory implements - TypeAdapterFactory { - - @Override - public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) { - Class<?> rawType = type.getRawType(); - if (rawType == WebPreparedStatement.class) { - @SuppressWarnings("unchecked") // We've just checked the raw type - TypeAdapter<T> ta = (TypeAdapter<T>)new WebPreparedStatementTypeAdapter(gson); - return ta; - } - return null; - } - -}
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/typeadapters/WebQueryResponseTypeAdapter.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,178 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.web.common.typeadapters; - -import java.io.IOException; -import java.lang.reflect.Array; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; - -import com.google.gson.Gson; -import com.google.gson.TypeAdapter; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonToken; -import com.google.gson.stream.JsonWriter; -import com.redhat.thermostat.storage.model.Pojo; -import com.redhat.thermostat.web.common.WebQueryResponse; - -class WebQueryResponseTypeAdapter<T extends Pojo> extends TypeAdapter<WebQueryResponse<T>> { - - private static final String PROP_RESULT = "payload"; - private static final String PROP_ERROR_CODE = "errno"; - private static final String PROP_CURSOR_ID = "cId"; - private static final String PROP_CURSOR_HAS_MORE_BATCHES = "cHasMore"; - - // The runtime type of the Pojo - private final Class<T> runtimePojoType; - private final Gson gson; - - WebQueryResponseTypeAdapter(Type parameterizedType, Gson gson) { - this.runtimePojoType = extractPojoImplClassFromType(parameterizedType); - this.gson = gson; - } - - @Override - public void write(JsonWriter out, WebQueryResponse<T> value) - throws IOException { - // handle null - if (value == null) { - out.nullValue(); - return; - } - - out.beginObject(); - - // response code - out.name(PROP_ERROR_CODE); - out.value(value.getResponseCode()); - - // cursor id - out.name(PROP_CURSOR_ID); - out.value(value.getCursorId()); - - // has more batches property - out.name(PROP_CURSOR_HAS_MORE_BATCHES); - out.value(value.hasMoreBatches()); - - // payload - out.name(PROP_RESULT); - if (value.getResultList() == null) { - out.nullValue(); - } else { - @SuppressWarnings("unchecked") - TypeAdapter<T[]> pojoTa = (TypeAdapter<T[]>)gson.getAdapter(value.getResultList().getClass()); - pojoTa.write(out, value.getResultList()); - } - - out.endObject(); - } - - @Override - public WebQueryResponse<T> read(JsonReader in) throws IOException { - // handle null - if (in.peek() == JsonToken.NULL) { - in.nextNull(); - return null; - } - - in.beginObject(); - - // response code (can't be null) - int responseCode = 0; - String name = in.nextName(); - responseCode = in.nextInt(); - - // cursor ID (can't be null) - name = in.nextName(); - int cursorId = in.nextInt(); - - // Has more batches, boolean, can't be null - name = in.nextName(); - boolean hasMoreBatches = in.nextBoolean(); - - if (runtimePojoType == null) { - throw new IllegalStateException("Runtime pojo type unknown"); - } - // Result list may be null. If it's there we get a name, otherwise - // we are done deserializing - T[] resultList = null; - if (in.peek() == JsonToken.NAME) { - name = in.nextName(); - if (name.equals(PROP_RESULT)) { - @SuppressWarnings("unchecked") - T[] arrayType = (T[])Array.newInstance(runtimePojoType, 0); - @SuppressWarnings("unchecked") - Class<T[]> type = (Class<T[]>)arrayType.getClass(); - TypeAdapter<T[]> pojoTa = gson.getAdapter(type); - resultList = pojoTa.read(in); - } else { - throw new IllegalStateException("Expected " + PROP_RESULT + " but got " + name); - } - } - - in.endObject(); - - WebQueryResponse<T> qResponse = new WebQueryResponse<>(); - qResponse.setResponseCode(responseCode); - qResponse.setCursorId(cursorId); - qResponse.setHasMoreBatches(hasMoreBatches); - qResponse.setResultList(resultList); - return qResponse; - } - - private Class<T> extractPojoImplClassFromType(Type type) { - if (type instanceof ParameterizedType) { - // fromJson() calls need to pass in the right *parameterized* type token: - // example for AgentInformation as T: - // Type queryResponseType = new TypeToken<WebQueryResponse<AgentInformation>>() {}.getType(); - // gson.fromJson(jsonStr, queryResponseType) - Type[] typeParameters = ((ParameterizedType)type).getActualTypeArguments(); - Type queryResponseTypeParam = typeParameters[0]; // WebQueryResponse has only one parameterized type T - Class<?> pojoClass = (Class<?>)queryResponseTypeParam; - if (!Pojo.class.isAssignableFrom(pojoClass)) { - throw new IllegalStateException("WebQueryResponse parametrized with non-pojo class: " + pojoClass); - } else { - @SuppressWarnings("unchecked") // We've just verified it's Pojo assignable. - Class<T> retval = (Class<T>)pojoClass; - return retval; - } - } - // should-be: write() will be called and only write(). - return null; - } - -}
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/typeadapters/WebQueryResponseTypeAdapterFactory.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.web.common.typeadapters; - -import com.google.gson.Gson; -import com.google.gson.TypeAdapter; -import com.google.gson.TypeAdapterFactory; -import com.google.gson.reflect.TypeToken; -import com.redhat.thermostat.web.common.WebQueryResponse; - -public class WebQueryResponseTypeAdapterFactory implements TypeAdapterFactory { - - @Override - public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) { - Class<?> rawType = type.getRawType(); - if (rawType == WebQueryResponse.class) { - @SuppressWarnings({ "unchecked", "rawtypes" }) - TypeAdapter<T> ta = (TypeAdapter<T>)new WebQueryResponseTypeAdapter(type.getType(), gson); - return ta; - } - return null; - } - -}
--- a/web/common/src/test/java/com/redhat/thermostat/web/common/CategorySerializationTest.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,112 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.web.common; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.util.Arrays; - -import org.junit.Before; -import org.junit.Test; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.redhat.thermostat.storage.core.Category; -import com.redhat.thermostat.storage.core.Key; -import com.redhat.thermostat.storage.model.Pojo; - -public class CategorySerializationTest { - - private static class TestObj implements Pojo { - // Dummy class for testing. - } - - private Gson gson; - - @Before - public void setup() { - gson = new GsonBuilder().create(); - } - - @Test - public void canSerializeDeserializeCategory() { - Key<Boolean> barKey = new Key<>("bar-key"); - Category<TestObj> cat = new Category<>("foo-category", TestObj.class, barKey); - String str = gson.toJson(cat, Category.class); - @SuppressWarnings("unchecked") - Category<TestObj> cat2 = (Category<TestObj>)gson.fromJson(str, Category.class); - assertNotSame(cat, cat2); - assertTrue(cat.equals(cat2)); - assertEquals(cat.hashCode(), cat2.hashCode()); - try { - cat2.getKeys().add(new Key<>("testme")); - fail("keys must be immutable after deserialization"); - } catch (UnsupportedOperationException e) { - // pass - } - assertEquals(TestObj.class, cat2.getDataClass()); - assertEquals("foo-category", cat2.getName()); - assertEquals(barKey, cat2.getKey("bar-key")); - } - - @Test - public void canSerializeDeserializeCategoryWithIndexedKeys() { - Key<Boolean> barKey = new Key<>("bar-key"); - Category<TestObj> cat = new Category<>("foo-category2", TestObj.class, - Arrays.<Key<?>>asList(barKey), Arrays.<Key<?>>asList(barKey)); - String str = gson.toJson(cat, Category.class); - @SuppressWarnings("unchecked") - Category<TestObj> cat2 = (Category<TestObj>)gson.fromJson(str, Category.class); - assertNotSame(cat, cat2); - assertTrue(cat.equals(cat2)); - assertEquals(cat.hashCode(), cat2.hashCode()); - try { - cat2.getKeys().add(new Key<>("testme")); - fail("keys must be immutable after deserialization"); - } catch (UnsupportedOperationException e) { - // pass - } - assertEquals(TestObj.class, cat2.getDataClass()); - assertEquals("foo-category2", cat2.getName()); - assertEquals(barKey, cat2.getKey("bar-key")); - assertEquals(Arrays.asList(barKey), cat2.getIndexedKeys()); - } -} -
--- a/web/common/src/test/java/com/redhat/thermostat/web/common/SharedStateIdTest.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,87 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.web.common; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.util.UUID; - -import org.junit.Test; - -public class SharedStateIdTest { - - @Test - public void testEquals() { - UUID uuid = UUID.randomUUID(); - SharedStateId id = new SharedStateId(3200, uuid); - SharedStateId id2 = new SharedStateId(3200, UUID.randomUUID()); - SharedStateId id3 = new SharedStateId(300, uuid); - SharedStateId equals = new SharedStateId(3200, uuid); - - assertFalse(id.equals(null)); - assertTrue(id.equals(equals)); - assertFalse("Different uuid", id.equals(id2)); - assertFalse("Different id val", id.equals(id3)); - assertFalse("UUID and id val different", id3.equals(id2)); - assertTrue(id.equals(id)); - } - - @Test - public void testHashCode() { - UUID uuid = UUID.randomUUID(); - SharedStateId id = new SharedStateId(3200, uuid); - SharedStateId id2 = new SharedStateId(3200, UUID.randomUUID()); - SharedStateId id3 = new SharedStateId(300, uuid); - SharedStateId equals = new SharedStateId(3200, uuid); - - assertTrue(id.hashCode() == equals.hashCode()); - assertTrue("Different uuid", id.hashCode() != id2.hashCode()); - assertTrue("Different id val", id.hashCode() != id3.hashCode()); - assertTrue("UUID and id val different", id3.hashCode() != id2.hashCode()); - assertTrue(id.hashCode() == id.hashCode()); - } - - @Test - public void testBasic() { - UUID uuid = UUID.randomUUID(); - SharedStateId id = new SharedStateId(3200, uuid); - assertEquals(uuid, id.getServerToken()); - assertEquals(3200, id.getId()); - } -}
--- a/web/common/src/test/java/com/redhat/thermostat/web/common/WebQueryResponseTest.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.web.common; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - -import java.lang.reflect.ParameterizedType; - -import org.junit.Test; - -import com.redhat.thermostat.storage.model.Pojo; - -public class WebQueryResponseTest { - - /** - * Having this test is important since we need the type info for deserializing - * {@link WebQueryResponse}s. - */ - @Test - public void canGetCorrectParameterizedType() { - WebQueryResponse<TestPojo> response = new WebQueryResponse<>(); - ParameterizedType type = response - .getRuntimeParametrizedType(TestPojo.class); - assertNull(type.getOwnerType()); - assertEquals(1, type.getActualTypeArguments().length); - assertEquals(TestPojo.class, type.getActualTypeArguments()[0]); - assertEquals(WebQueryResponse.class, type.getRawType()); - } - - private static class TestPojo implements Pojo { - // nothing - } -} -
--- a/web/common/src/test/java/com/redhat/thermostat/web/common/typeadapters/JsonPerformanceTest.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,346 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.web.common.typeadapters; - -import static org.junit.Assert.assertTrue; - -import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.List; - -import org.junit.Test; - -import com.google.gson.Gson; -import com.google.gson.reflect.TypeToken; - -/** - * - * A generic GSON-based performance test for JSON serialization/deserialization. - * - * @param <T> The type which should get serialized/deserialized. - * - * @see PreparedParameterJSONPerformanceTest - */ -public abstract class JsonPerformanceTest<T> { - - public enum OperationType { - DESERIALIZATION, - SERIALIZATION - } - - public enum GsonContext { - SLOW, - FASTER - } - - private static final String EXPECTATION_FORMAT = " (>=%s)"; - private static final int ITERATIONS_FOR_CUMMULATIVE_AVG = 10; - - private final boolean debug; - private final String testClass; - private final Gson oldGson; - private final Gson newGson; - - protected JsonPerformanceTest(boolean debug, String testClass) { - this.debug = debug; - this.testClass = testClass; - this.oldGson = getSlowGson(); - this.newGson = getFasterGson(); - } - - /** - * - * @return The base Gson to measure performance against - */ - protected abstract Gson getSlowGson(); - - /** - * - * @return The "improved" Gson for which the improvement over the Gson as returned by {{@link #getSlowGson()} - * should be measured. - */ - protected abstract Gson getFasterGson(); - - /** - * The expected speedup used in asserts for the given iterations. - * - * @param type The type of operation: serialization or deserialization. - * @param iterations - * @return The expected speed-up. - */ - protected abstract double getExpectedSpeedup(OperationType type, int iterations); - - /** - * Formats the string to a valid json string by using - * {@code mutator}. - * - * @param context The Gson context for this mutation. - * @param mutator A unique number for a performance run. - * - * @return A valid JSON string representing an instance of type T. - */ - protected abstract String mutateJsonString(GsonContext context, int mutator); - - /** - * Creates a mutated instance of T using mutator - * {@code mutator}. - * - * @param mutator A unique number for this performance test run. - * - * @return The mutated instance. - */ - protected abstract T mutateToBeSerializedInstance(int mutator); - - /** - * - * @return The {@link TypeToken} for type T so that it can be properly - * deserialized. - */ - protected abstract TypeToken<T> getDeserializeTypeToken(); - - /** - * - * @return The number of iterations to run for the cold (not warmed-up) - * serialization performance test. - */ - protected abstract int getColdSerializationIterations(); - - /** - * - * @return The number of iterations to run for the "warmed-up" serialization - * performance test. - */ - protected abstract int getWarmSerializationIterations(); - - /** - * - * @return The number of iterations to run for the cold (not warmed-up) - * deserialization performance test. - */ - protected abstract int getColdDeserializationIterations(); - - /** - * - * @return The number of iterations to run for the "warmed-up" deserialization - * performance test. - */ - protected abstract int getWarmDeserializationIterations(); - - /** - * - * @return A delta to increase the "faster" gson serialization speed-up so - * that basic assertions such as {@code speed-up >= 1} work. This is - * useful for the base-case of comparing a gson instance to itself. - * Two performance runs of the same gson are expected to be - * approximately equally fast. Though, it will depend on the system. - */ - protected abstract double getSelfSerializationDelta(); - - /** - * - * @return A delta to increase the "faster" gson deserialization speed-up so - * that basic assertions such as {@code speed-up >= 1} work. This is - * useful for the base-case of comparing a gson instance to itself. - * Two performance runs of the same gson are expected to be - * approximately equally fast. Though, it will depend on the system. - */ - protected abstract double getSelfDeserializationDelta(); - - @Test - public void verifySerializationSpeedCold() { - int iterations = getColdSerializationIterations(); - double actualSpeedup = getAverageSerializationSpeedup(iterations); - final double expectedSpeedup = getExpectedSpeedup(OperationType.SERIALIZATION, iterations); - if (debug) { - System.out.println(testClass + ": actual cold serialization speed-up: " + - formatSpeedup(actualSpeedup) + String.format(EXPECTATION_FORMAT, formatSpeedup(expectedSpeedup))); - } - assertTrue("Performance regression? Expected a speed-up of > " + expectedSpeedup +". Speed-up was: " + actualSpeedup, actualSpeedup > expectedSpeedup); - } - - @Test - public void verifySerializationSpeedWarm() { - int iterations = getWarmSerializationIterations(); - double actualSpeedup = getAverageSerializationSpeedup(iterations); - final double expectedSpeedup = getExpectedSpeedup(OperationType.SERIALIZATION, iterations); - if (debug) { - System.out.println(testClass + ": actual warmed-up serialization speed-up: " + - formatSpeedup(actualSpeedup) + String.format(EXPECTATION_FORMAT, formatSpeedup(expectedSpeedup))); - } - assertTrue("Performance regression? Expected a speed-up of > " + expectedSpeedup +". Speed-up was: " + actualSpeedup, actualSpeedup > expectedSpeedup); - } - - @Test - public void verifyDeserializationSpeedCold() { - int iterations = getColdDeserializationIterations(); - double actualSpeedup = getAverageDeserializationSpeedup(iterations); - final double expectedSpeedup = getExpectedSpeedup(OperationType.DESERIALIZATION, iterations); - if (debug) { - System.out.println(testClass + ": actual cold deserialization speed-up: " + - formatSpeedup(actualSpeedup) + String.format(EXPECTATION_FORMAT, formatSpeedup(expectedSpeedup))); - } - assertTrue("Performance regression? Expected a speed-up of > " + expectedSpeedup +". Speed-up was: " + actualSpeedup, actualSpeedup > expectedSpeedup); - } - - @Test - public void verifyDeserializationSpeedWarm() { - int iterations = getWarmDeserializationIterations(); - double actualSpeedup = getAverageDeserializationSpeedup(iterations); - final double expectedSpeedup = getExpectedSpeedup(OperationType.DESERIALIZATION, iterations); - if (debug) { - System.out.println(testClass + ": actual warmed-up deserialization speed-up: " + - formatSpeedup(actualSpeedup) + String.format(EXPECTATION_FORMAT, formatSpeedup(expectedSpeedup))); - } - assertTrue("Performance regression? Expected a speed-up of > " + expectedSpeedup +". Speed-up was: " + actualSpeedup, actualSpeedup > expectedSpeedup); - } - - private double getAverageSerializationSpeedup(final int iterations) { - double sum = 0; - for (int i = 0; i < ITERATIONS_FOR_CUMMULATIVE_AVG; i++) { - sum += measureSerializationSpeed(iterations); - } - double speedup = sum/ITERATIONS_FOR_CUMMULATIVE_AVG; - double delta = getSelfSerializationDelta(); - assertTrue("Performance Regression? Expected a speed-up of >= 1, but was: " + (speedup + delta), - (speedup + delta) >= 1); - return speedup; - } - - private double measureSerializationSpeed(final int iterations) { - PerfTestResult result = runSerializationPerformanceTest(iterations); - return result.getSpeedup(); - } - - private double getAverageDeserializationSpeedup(final int iterations) { - double sum = 0; - for (int i = 0; i < ITERATIONS_FOR_CUMMULATIVE_AVG; i++) { - sum += measureDeserializationSpeed(iterations); - } - double speedup = sum/ITERATIONS_FOR_CUMMULATIVE_AVG; - double delta = getSelfDeserializationDelta(); - assertTrue("Performance Regression? Expected a speed-up of >= 1, but was: " + (speedup + delta), - (speedup + delta) >= 1); - return speedup; - } - - private double measureDeserializationSpeed(final int iterations) { - PerfTestResult result = runDeserializationPerformanceTest(iterations); - return result.getSpeedup(); - } - - private PerfTestResult runSerializationPerformanceTest(final int iterations) { - List<String> list = new ArrayList<>(); - double oldSum = 0; - double newSum = 0; - long start = -1; - long end = -1; - Gson gson = null; - for (int i = 0; i < iterations * 2; i++) { - T instance = mutateToBeSerializedInstance(i); - if (i % 2 != 0) { - gson = newGson; - } else { - gson = oldGson; - } - start = System.nanoTime(); - String json = gson.toJson(instance); - end = System.nanoTime(); - if (i % 2 != 0) { - newSum += (end - start); - } else { - oldSum += (end - start); - } - // Do something silly just so that the JIT does not optimize-out the - // toJson() call. - list.add(json); - } - PerfTestResult res = new PerfTestResult(); - res.oldPerf = oldSum/iterations; - res.newPerf = newSum/iterations; - return res; - } - - private PerfTestResult runDeserializationPerformanceTest(final int iterations) { - List<T> list = new ArrayList<>(); - - double oldSum = 0; - double newSum = 0; - long start = -1; - long end = -1; - Gson gson = null; - String json; - for (int i = 0; i < iterations * 2; i++) { - if (i % 2 != 0) { - json = mutateJsonString(GsonContext.FASTER, i); - gson = newGson; - } else { - json = mutateJsonString(GsonContext.SLOW, i); - gson = oldGson; - } - start = System.nanoTime(); - T instance = gson.fromJson(json, getDeserializeTypeToken().getType()); - end = System.nanoTime(); - if (i % 2 != 0) { - newSum += (end - start); - } else { - oldSum += (end - start); - } - // Do something silly just so that the JIT does not optimize-out the - // fromJson() call. - list.add(instance); - } - PerfTestResult res = new PerfTestResult(); - res.oldPerf = oldSum/iterations; - res.newPerf = newSum/iterations; - return res; - } - - private String formatSpeedup(double value) { - DecimalFormat format = new DecimalFormat("#.##"); - return format.format(value); - } - - private static class PerfTestResult { - private double oldPerf; - private double newPerf; - - private double getSpeedup() { - return oldPerf/newPerf; - } - } - -}
--- a/web/common/src/test/java/com/redhat/thermostat/web/common/typeadapters/LegacyGSONConverter.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,114 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - - -package com.redhat.thermostat.web.common.typeadapters; - -import java.beans.PropertyDescriptor; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Type; - -import org.apache.commons.beanutils.PropertyUtils; - -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonDeserializer; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; -import com.google.gson.JsonSerializationContext; -import com.google.gson.JsonSerializer; -import com.redhat.thermostat.storage.core.Entity; -import com.redhat.thermostat.storage.core.Persist; -import com.redhat.thermostat.storage.model.Pojo; - -/** - * Old non-stream GSON API serializer. Used only in performance tests. - */ -public class LegacyGSONConverter implements JsonSerializer<Pojo>, JsonDeserializer<Pojo> { - - @Override - public Pojo deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { - @SuppressWarnings("unchecked") - Class<? extends Pojo> targetType = (Class<Pojo>) typeOfT; - try { - Pojo pojo = targetType.newInstance(); - PropertyDescriptor[] descs = PropertyUtils.getPropertyDescriptors(pojo); - for (PropertyDescriptor desc : descs) { - Method writeMethod = desc.getWriteMethod(); - if (writeMethod != null && writeMethod.isAnnotationPresent(Persist.class)) { - String name = desc.getName(); - JsonElement child = json.getAsJsonObject().get(name); - Object value = context.deserialize(child, desc.getPropertyType()); - PropertyUtils.setProperty(pojo, name, value); - } - } - return pojo; - } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { - throw new RuntimeException(e); - } - } - - @Override - public JsonElement serialize(Pojo src, Type typeOfSrc, JsonSerializationContext context) { - Class<?> cls = (Class<?>) typeOfSrc; - if (! cls.isAnnotationPresent(Entity.class)) { - System.err.println("attempt to serialize non-Entity class: " + cls.getName()); - throw new IllegalArgumentException("attempt to serialize non-Entity class: " + cls.getName()); - } - JsonObject obj = new JsonObject(); - PropertyDescriptor[] descs = PropertyUtils.getPropertyDescriptors(src); - for (PropertyDescriptor desc : descs) { - Method readMethod = desc.getReadMethod(); - if (readMethod != null && readMethod.isAnnotationPresent(Persist.class)) { - String name = desc.getName(); - - try { - Object value = PropertyUtils.getProperty(src, name); - obj.add(name, context.serialize(value)); - } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { - throw new RuntimeException(e); - } - } else if (readMethod == null) { - System.err.println("WARNING: property without read method: " + src.getClass().getName() + "::" + desc.getName()); - } - } - return obj; - } - - -} -
--- a/web/common/src/test/java/com/redhat/thermostat/web/common/typeadapters/LegacyPreparedParameterSerializer.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,192 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.web.common.typeadapters; - -import java.lang.reflect.Array; -import java.lang.reflect.Type; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonDeserializer; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; -import com.google.gson.JsonPrimitive; -import com.google.gson.JsonSerializationContext; -import com.google.gson.JsonSerializer; -import com.redhat.thermostat.common.utils.LoggingUtils; -import com.redhat.thermostat.storage.core.PreparedParameter; -import com.redhat.thermostat.storage.model.Pojo; - -/** - * Old non-stream GSON API serializer. Used only in performance tests. - */ -public class LegacyPreparedParameterSerializer implements JsonSerializer<PreparedParameter>, - JsonDeserializer<PreparedParameter>{ - - private static final Logger logger = LoggingUtils.getLogger(LegacyPreparedParameterSerializer.class); - private static final String PROP_TYPE = "type"; - private static final String PROP_VALUE = "value"; - private static final Set<Class<?>> VALID_CLASSES; - private static final Set<Class<?>> PRIMITIVES_NOT_ALLOWING_NULL_VAL; - // maps type names to classes: - // "int" => int.class , "double" => double.class, "[I" => int[].class - // and so on. - private static final Map<String, Class<?>> CLASSES_LOOKUP_TABLE; - - static { - VALID_CLASSES = new HashSet<>(); - CLASSES_LOOKUP_TABLE = new HashMap<>(); - CLASSES_LOOKUP_TABLE.put(int.class.getName(), int.class); - CLASSES_LOOKUP_TABLE.put(long.class.getName(), long.class); - CLASSES_LOOKUP_TABLE.put(boolean.class.getName(), boolean.class); - CLASSES_LOOKUP_TABLE.put(double.class.getName(), double.class); - CLASSES_LOOKUP_TABLE.put(String.class.getName(), String.class); - CLASSES_LOOKUP_TABLE.put(int[].class.getName(), int[].class); - CLASSES_LOOKUP_TABLE.put(long[].class.getName(), long[].class); - CLASSES_LOOKUP_TABLE.put(boolean[].class.getName(), boolean[].class); - CLASSES_LOOKUP_TABLE.put(double[].class.getName(), double[].class); - CLASSES_LOOKUP_TABLE.put(String[].class.getName(), String[].class); - VALID_CLASSES.addAll(CLASSES_LOOKUP_TABLE.values()); - PRIMITIVES_NOT_ALLOWING_NULL_VAL = new HashSet<>(); - PRIMITIVES_NOT_ALLOWING_NULL_VAL.add(int.class); - PRIMITIVES_NOT_ALLOWING_NULL_VAL.add(long.class); - PRIMITIVES_NOT_ALLOWING_NULL_VAL.add(boolean.class); - PRIMITIVES_NOT_ALLOWING_NULL_VAL.add(double.class); - } - - @Override - public JsonElement serialize(PreparedParameter param, Type type, - JsonSerializationContext ctxt) { - JsonObject result = new JsonObject(); - JsonElement valueElem = serializeValue(ctxt, param.getValue(), param.getType()); - result.add(PROP_VALUE, valueElem); - JsonPrimitive typeElem = new JsonPrimitive(param.getType().getName()); - result.add(PROP_TYPE, typeElem); - return result; - } - - private JsonElement serializeValue(JsonSerializationContext ctxt, Object value, Class<?> type) { - JsonElement element; - // Special case pojo list types: the value class is of array type for - // them, but the type is the component type. - if (value != null && value.getClass().isArray() && !type.isArray()) { - assert(Pojo.class.isAssignableFrom(type)); - Class<?> arrayType = Array.newInstance(type, 0).getClass(); - element = ctxt.serialize(value, arrayType); - } else { - element = ctxt.serialize(value, type); - } - return element; - } - - @Override - public PreparedParameter deserialize(JsonElement jsonElem, Type type, - JsonDeserializationContext ctxt) throws JsonParseException { - JsonElement typeElem = jsonElem.getAsJsonObject().get(PROP_TYPE); - String className = typeElem.getAsString(); - // perform some sanity checking on the types of classes we actually - // de-serialize - Class<?> typeVal = deserializeTypeVal(className); - validateSaneClassName(typeVal); - JsonElement valueElement = jsonElem.getAsJsonObject().get(PROP_VALUE); - Object value = deserializeValue(ctxt, valueElement, typeVal); - PreparedParameter param = new PreparedParameter(); - param.setType(typeVal); - param.setValue(value); - return param; - } - - private Class<?> deserializeTypeVal(String className) { - Class<?> typeVal = null; - if (CLASSES_LOOKUP_TABLE.containsKey(className)) { - typeVal = CLASSES_LOOKUP_TABLE.get(className); - } else { - try { - // We need this for Pojo + Pojo list type params. For pojo - // lists the name we get passed is the component type of the - // array. - typeVal = Class.forName(className); - } catch (ClassNotFoundException e) { - logger.log(Level.WARNING, "Failed to resolve class type for '" - + className + "'."); - } - } - return typeVal; - } - - private Object deserializeValue(JsonDeserializationContext ctxt, - JsonElement valueElement, Class<?> valType) { - // special case for Pojo/Pojo list types. In that case, the valType - // is the component type for arrays. In order to distinguish pojo - // lists from pojos, we use JSON's array info about the value element. - if (valueElement != null && valueElement.isJsonArray() && !valType.isArray()) { - assert(Pojo.class.isAssignableFrom(valType)); - Class<?> arrayType = Array.newInstance(valType, 0).getClass(); - return ctxt.deserialize(valueElement, arrayType); - } else { - Object value = ctxt.deserialize(valueElement, valType); - validatePrimitivesForNull(value, valType); - return value; - } - } - - private void validatePrimitivesForNull(Object value, Class<?> valType) { - if (PRIMITIVES_NOT_ALLOWING_NULL_VAL.contains(valType) && value == null) { - // illegal value for primitive type. according to JLS spec they all - // have default values and are never null. - throw new IllegalStateException( valType + " primitive" + - " does not accept a null value!"); - } - } - - // Allow valid classes + Pojo types, refuse everything else - private void validateSaneClassName(Class<?> clazz) { - // isAssignableFrom throws NPE if clazz is null. - if (VALID_CLASSES.contains(clazz) || - Pojo.class.isAssignableFrom(clazz)) { - return; - } - throw new IllegalStateException("Illegal type of parameter " + clazz.getCanonicalName()); - } - -}
--- a/web/common/src/test/java/com/redhat/thermostat/web/common/typeadapters/LegacyWebPreparedStatementSerializer.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,89 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.web.common.typeadapters; - -import java.lang.reflect.Type; - -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonDeserializer; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; -import com.google.gson.JsonPrimitive; -import com.google.gson.JsonSerializationContext; -import com.google.gson.JsonSerializer; -import com.redhat.thermostat.storage.core.PreparedParameters; -import com.redhat.thermostat.web.common.SharedStateId; -import com.redhat.thermostat.web.common.WebPreparedStatement; - -/** - * Old non-stream GSON API serializer. Used only in performance tests. - * - */ -public class LegacyWebPreparedStatementSerializer implements - JsonDeserializer<WebPreparedStatement<?>>, - JsonSerializer<WebPreparedStatement<?>> { - - private static final String PROP_PARAMS = "p"; - private static final String PROP_STMT_ID = "sid"; - - @Override - public JsonElement serialize(WebPreparedStatement<?> stmt, Type type, - JsonSerializationContext ctxt) { - JsonObject result = new JsonObject(); - JsonElement parameters = ctxt.serialize(stmt.getParams(), PreparedParameters.class); - result.add(PROP_PARAMS, parameters); - JsonElement stmtIdElem = ctxt.serialize(stmt.getStatementId(), SharedStateId.class); - result.add(PROP_STMT_ID, stmtIdElem); - return result; - } - - @Override - public WebPreparedStatement<?> deserialize(JsonElement jsonElem, Type type, - JsonDeserializationContext ctxt) throws JsonParseException { - JsonElement paramsElem = jsonElem.getAsJsonObject().get(PROP_PARAMS); - JsonElement stmtIdElem = jsonElem.getAsJsonObject().get(PROP_STMT_ID); - PreparedParameters params = ctxt.deserialize(paramsElem, PreparedParameters.class); - SharedStateId stmtId = ctxt.deserialize(stmtIdElem, SharedStateId.class); - WebPreparedStatement<?> stmt = new WebPreparedStatement<>(); - stmt.setStatementId(stmtId); - stmt.setParams(params); - return stmt; - } - -} -
--- a/web/common/src/test/java/com/redhat/thermostat/web/common/typeadapters/LegacyWebQueryResponseSerializer.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,101 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.web.common.typeadapters; - -import java.lang.reflect.Array; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; - -import com.google.gson.JsonArray; -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonDeserializer; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; -import com.google.gson.JsonPrimitive; -import com.google.gson.JsonSerializationContext; -import com.google.gson.JsonSerializer; -import com.redhat.thermostat.storage.model.Pojo; -import com.redhat.thermostat.web.common.WebQueryResponse; - -/** - * Old non-stream GSON API serializer. Used only in performance tests. - */ -public class LegacyWebQueryResponseSerializer<T extends Pojo> implements - JsonDeserializer<WebQueryResponse<T>>, JsonSerializer<WebQueryResponse<T>> { - - private static final String PROP_RESULT = "payload"; - private static final String PROP_ERROR_CODE = "errno"; - - @Override - public JsonElement serialize(WebQueryResponse<T> qResponse, Type type, - JsonSerializationContext ctxt) { - JsonObject result = new JsonObject(); - JsonElement resultsElem = ctxt.serialize(qResponse.getResultList()); - result.add(PROP_RESULT, resultsElem); - JsonPrimitive errnoElem = new JsonPrimitive(qResponse.getResponseCode()); - result.add(PROP_ERROR_CODE, errnoElem); - return result; - } - - @SuppressWarnings("unchecked") - @Override - public WebQueryResponse<T> deserialize(JsonElement jsonElem, Type type, - JsonDeserializationContext ctxt) throws JsonParseException { - // fromJson() calls need to pass in the right *parameterized* type token: - // example for AgentInformation as T: - // Type queryResponseType = new TypeToken<WebQueryResponse<AgentInformation>>() {}.getType(); - // gson.fromJson(jsonStr, queryResponseType) - Type[] typeParameters = ((ParameterizedType)type).getActualTypeArguments(); - Type queryResponseTypeParam = typeParameters[0]; // WebQueryResponse has only one parameterized type T - JsonArray resultElem = jsonElem.getAsJsonObject().get(PROP_RESULT).getAsJsonArray(); - @SuppressWarnings("rawtypes") - Class typeOfGeneric = (Class)queryResponseTypeParam; - T[] array = (T[])Array.newInstance(typeOfGeneric, resultElem.size()); - for (int i = 0; i < resultElem.size(); i++) { - array[i] = ctxt.deserialize(resultElem.get(i), queryResponseTypeParam); - } - JsonElement errorCodeElem = jsonElem.getAsJsonObject().get(PROP_ERROR_CODE); - int errorCode = ctxt.deserialize(errorCodeElem, int.class); - WebQueryResponse<T> qResponse = new WebQueryResponse<>(); - qResponse.setResponseCode(errorCode); - qResponse.setResultList(array); - return qResponse; - } - -} -
--- a/web/common/src/test/java/com/redhat/thermostat/web/common/typeadapters/PojoTypeAdapterTest.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,319 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.web.common.typeadapters; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import org.junit.Before; -import org.junit.Test; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.redhat.thermostat.storage.core.Entity; -import com.redhat.thermostat.storage.core.Persist; -import com.redhat.thermostat.storage.model.AgentInformation; -import com.redhat.thermostat.storage.model.AggregateCount; -import com.redhat.thermostat.storage.model.Pojo; - -public class PojoTypeAdapterTest { - - private Gson gson; - - @Before - public void setup() { - gson = new GsonBuilder() - .registerTypeAdapterFactory(new PojoTypeAdapterFactory()) - .create(); - } - - @Test - public void canSerializePojoLists() { - String expectedJson = "[{\"AInt\":200,\"fooString\":\"bar\"}," + - "{\"AInt\":5,\"fooString\":\"baz\"}," + - "{\"AInt\":200,\"fooString\":\"bar\"}]"; - - FooPojo pojo1 = new FooPojo(); - pojo1.setAInt(200); - pojo1.setFooString("bar"); - - FooPojo pojo2 = new FooPojo(); - pojo2.setAInt(5); - pojo2.setFooString("baz"); - - FooPojo[] list = new FooPojo[] { - pojo1, pojo2, pojo1 - }; - String json = gson.toJson(list); - assertEquals(expectedJson, json); - } - - @Test - public void canDeserializePojoLists() { - String json = "[{\"AInt\":200,\"fooString\":\"bar\"}," + - "{\"AInt\":5,\"fooString\":\"baz\"}," + - "{\"AInt\":200,\"fooString\":\"bar\"}]"; - - FooPojo[] actual = gson.fromJson(json, FooPojo[].class); - assertEquals(3, actual.length); - assertEquals(200, actual[0].getAInt()); - assertEquals(5, actual[1].getAInt()); - assertEquals(200, actual[2].getAInt()); - assertEquals("bar", actual[0].getFooString()); - assertEquals("bar", actual[2].getFooString()); - assertEquals("baz", actual[1].getFooString()); - } - - @Test - public void canSerializeNullPojo() { - FooPojo foo = null; - String jsonStr = gson.toJson(foo); - assertEquals("null", jsonStr); - } - - // Null values won't show up in the JSON string. - @Test - public void canSerializeNullMember() { - String expectedJson = "{\"AInt\":200,\"fooString\":\"bar\"}"; - - FooPojo foo = new FooPojo(); - foo.setAInt(200); - foo.setFooString("bar"); - String jsonStr = gson.toJson(foo); - assertEquals(expectedJson, jsonStr); - } - - @Test - public void canDeserializeWithMembersUnset() { - String json = "{\"AInt\":200,\"boolArray\":null,\"fooString\":\"bar\"}"; - - FooPojo pojo = gson.fromJson(json, FooPojo.class); - assertNotNull(pojo); - assertEquals(200, pojo.getAInt()); - assertEquals("bar", pojo.getFooString()); - assertNull(pojo.getBoolArray()); - - // Do it again with unset values omitted. - json = "{\"fooString\":\"bar\"}"; - pojo = gson.fromJson(json, FooPojo.class); - assertNotNull(pojo); - assertEquals("bar", pojo.getFooString()); - assertNull(pojo.getBoolArray()); - assertEquals("0 is default int val", 0, pojo.getAInt()); - } - - @Test - public void canDeserializeBasic() { - String json = "{\"AInt\":1223,\"boolArray\":[false,true,false],\"fooString\":\"fooStringValue\"}"; - - FooPojo pojo = gson.fromJson(json, FooPojo.class); - assertEquals(1223, pojo.getAInt()); - assertEquals("fooStringValue", pojo.getFooString()); - assertEquals(3, pojo.getBoolArray().length); - assertFalse(pojo.getBoolArray()[0]); - assertTrue(pojo.getBoolArray()[1]); - assertFalse(pojo.getBoolArray()[2]); - } - - @Test - public void canDeserializeNullPojo() { - String nullStr = "null"; - FooPojo pojo = gson.fromJson(nullStr, FooPojo.class); - assertNull(pojo); - } - - @Test - public void canSerializeBasic() { - String expectedJson = "{\"AInt\":1223,\"boolArray\":[false,true,false],\"fooString\":\"fooStringValue\"}"; - - FooPojo fooPojo = new FooPojo(); - fooPojo.setBoolArray(new boolean[] { false, true, false }); - fooPojo.setAInt(1223); - fooPojo.setFooString("fooStringValue"); - String jsonStr = gson.toJson(fooPojo); - assertEquals(expectedJson, jsonStr); - } - - @Test - public void canSerializeRecursivePojo() { - FooPojo fooPojo = new FooPojo(); - fooPojo.setBoolArray(new boolean[] { false, true, false }); - fooPojo.setAInt(1223); - fooPojo.setFooString("fooStringValue"); - String fooPojoJson = gson.toJson(fooPojo); - - String expectedJson = "{\"myLong\":10000000000,\"pojo\":" + fooPojoJson + "}"; - RecPojo recursive = new RecPojo(); - recursive.setPojo(fooPojo); - recursive.setMyLong(10000000000L); - - String jsonStr = gson.toJson(recursive); - assertEquals(expectedJson, jsonStr); - } - - @Test - public void canDeserializeRecursivePojo() { - String json = "{\"myLong\":10000000000,\"pojo\":" + - "{\"AInt\":1223,\"boolArray\":[false,true,false],\"fooString\":\"fooStringValue\"}}"; - - RecPojo rec = gson.fromJson(json, RecPojo.class); - - assertEquals(10000000000L, rec.getMyLong()); - assertNotNull(rec.getPojo()); - - FooPojo pojo = rec.getPojo(); - assertEquals(1223, pojo.getAInt()); - assertEquals("fooStringValue", pojo.getFooString()); - assertEquals(3, pojo.getBoolArray().length); - assertFalse(pojo.getBoolArray()[0]); - assertTrue(pojo.getBoolArray()[1]); - assertFalse(pojo.getBoolArray()[2]); - } - - @Test - public void canSerializeDeserializeBasic() { - // Our test pojo - AgentInformation agentInfo = new AgentInformation("testing"); - agentInfo.setAlive(true); - - String jsonStr = gson.toJson(agentInfo); - - AgentInformation actual = gson.fromJson(jsonStr, AgentInformation.class); - - assertEquals("testing", actual.getAgentId()); - assertEquals(true, actual.isAlive()); - } - - @Test - public void canSerializeDeserializeArray() { - // Our test pojo - AgentInformation agentInfo = new AgentInformation("testing"); - agentInfo.setAlive(true); - AgentInformation[] agentInfos = new AgentInformation[] { - agentInfo - }; - - String jsonStr = gson.toJson(agentInfos); - - AgentInformation[] actual = gson.fromJson(jsonStr, AgentInformation[].class); - - assertEquals("testing", actual[0].getAgentId()); - assertEquals(true, actual[0].isAlive()); - } - - @Test - public void canSerializeDeserializeAggregateCount() { - long expectedCount = 3333000333L; - AggregateCount count = new AggregateCount(); - count.setCount(expectedCount); - String jsonStr = gson.toJson(count); - // now do the reverse - AggregateCount c2 = gson.fromJson(jsonStr, AggregateCount.class); - assertEquals(expectedCount, c2.getCount()); - } - - @Entity - public static class FooPojo implements Pojo { - - private String fooString; - private int fooInt; - private boolean[] boolArray; - - @Persist - public String getFooString() { - return fooString; - } - - @Persist - public void setFooString(String fooString) { - this.fooString = fooString; - } - - @Persist - public int getAInt() { - return fooInt; - } - - @Persist - public void setAInt(int fooInt) { - this.fooInt = fooInt; - } - - @Persist - public boolean[] getBoolArray() { - return boolArray; - } - - @Persist - public void setBoolArray(boolean[] boolArray) { - this.boolArray = boolArray; - } - - - } - - @Entity - public static class RecPojo implements Pojo { - - private long myLong; - private FooPojo pojo; - - @Persist - public long getMyLong() { - return myLong; - } - - @Persist - public void setMyLong(long myLong) { - this.myLong = myLong; - } - - @Persist - public FooPojo getPojo() { - return pojo; - } - - @Persist - public void setPojo(FooPojo pojo) { - this.pojo = pojo; - } - - } -}
--- a/web/common/src/test/java/com/redhat/thermostat/web/common/typeadapters/PreparedParameterJSONPerformanceTest.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,146 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.web.common.typeadapters; - -import org.junit.experimental.categories.Category; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.reflect.TypeToken; -import com.redhat.thermostat.storage.core.PreparedParameter; -import com.redhat.thermostat.testutils.PerformanceTest; -import com.redhat.thermostat.web.common.typeadapters.PojoTypeAdapterFactory; -import com.redhat.thermostat.web.common.typeadapters.PreparedParameterTypeAdapterFactory; - -/** - * JUnit categorized performance test. It'll be only run for - * the perf-tests profile during a full build. - */ -@Category(PerformanceTest.class) -public class PreparedParameterJSONPerformanceTest extends - JsonPerformanceTest<PreparedParameter> { - - private static final boolean DEBUG = true; - - public PreparedParameterJSONPerformanceTest() { - super(DEBUG, PreparedParameterJSONPerformanceTest.class.getSimpleName()); - } - - @Override - protected Gson getSlowGson() { - return new GsonBuilder() - .registerTypeAdapterFactory(new PojoTypeAdapterFactory()) - .registerTypeAdapter(PreparedParameter.class, new LegacyPreparedParameterSerializer()) - .create(); - } - - @Override - protected Gson getFasterGson() { - return new GsonBuilder() - .registerTypeAdapterFactory(new PojoTypeAdapterFactory()) - .registerTypeAdapterFactory(new PreparedParameterTypeAdapterFactory()) - .create(); - } - - @Override - protected double getExpectedSpeedup( - OperationType type, - int iterations) { - if (type == OperationType.SERIALIZATION && iterations == getColdSerializationIterations()) { - return 1.7; - } else if (type == OperationType.SERIALIZATION && iterations == getWarmSerializationIterations()) { - return 1.3; - } else if (type == OperationType.DESERIALIZATION && iterations == getColdDeserializationIterations()) { - return 1; - } else if (type == OperationType.DESERIALIZATION && iterations == getWarmDeserializationIterations()) { - return 1; - } else { - throw new IllegalStateException("bug"); - } - } - - @Override - protected String mutateJsonString( - GsonContext context, - int mutator) { - return String.format("{\"type\":\"int\",\"value\":%d}", mutator); - } - - @Override - protected PreparedParameter mutateToBeSerializedInstance(int mutator) { - PreparedParameter param = new PreparedParameter(); - param.setValue(mutator); - param.setType(int.class); - return param; - } - - @Override - protected TypeToken<PreparedParameter> getDeserializeTypeToken() { - return TypeToken.get(PreparedParameter.class); - } - - @Override - protected int getColdSerializationIterations() { - return 1; - } - - @Override - protected int getWarmSerializationIterations() { - return 1000; - } - - @Override - protected int getColdDeserializationIterations() { - return 1; - } - - @Override - protected int getWarmDeserializationIterations() { - return 1000; - } - - @Override - protected double getSelfSerializationDelta() { - return 0.1; - } - - @Override - protected double getSelfDeserializationDelta() { - return 0.1; - } - -}
--- a/web/common/src/test/java/com/redhat/thermostat/web/common/typeadapters/PreparedParameterTypeAdapterTest.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,481 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.web.common.typeadapters; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.lang.reflect.Array; - -import org.junit.Before; -import org.junit.Test; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.redhat.thermostat.storage.core.PreparedParameter; -import com.redhat.thermostat.storage.model.AgentInformation; -import com.redhat.thermostat.storage.model.VmInfo.KeyValuePair; - -public class PreparedParameterTypeAdapterTest { - - private Gson gson; - - @Before - public void setup() { - gson = new GsonBuilder() - .registerTypeAdapterFactory(new PojoTypeAdapterFactory()) - .registerTypeAdapterFactory(new PreparedParameterTypeAdapterFactory()) - .create(); - } - - @Test - public void canDeserializeBasic() { - // String - String jsonStr = "{ \"type\": \"java.lang.String\" , \"value\": \"testing\" }"; - PreparedParameter param = gson.fromJson(jsonStr, PreparedParameter.class); - assertEquals(String.class, param.getType()); - assertEquals("testing", param.getValue()); - // Integer - jsonStr = "{ \"type\": \"int\" , \"value\": -1}"; - param = gson.fromJson(jsonStr, PreparedParameter.class); - assertEquals(int.class, param.getType()); - assertEquals(-1, param.getValue()); - // Long - jsonStr = "{ \"type\": \"long\" , \"value\": -10}"; - param = gson.fromJson(jsonStr, PreparedParameter.class); - assertEquals(long.class, param.getType()); - assertEquals(-10L, param.getValue()); - jsonStr = "{ \"type\": \"long\" , \"value\": 30000000003}"; - param = gson.fromJson(jsonStr, PreparedParameter.class); - assertEquals(long.class, param.getType()); - assertEquals(30000000003L, param.getValue()); - // Boolean - jsonStr = "{ \"type\": \"boolean\" , \"value\": true}"; - param = gson.fromJson(jsonStr, PreparedParameter.class); - assertEquals(boolean.class, param.getType()); - assertEquals(true, param.getValue()); - // String[] - String strArrayVal = "[ \"testing1\", \"testing2\", \"3\" ]"; - jsonStr = "{ \"type\": \"[Ljava.lang.String;\" , \"value\": " + strArrayVal + "}"; - param = gson.fromJson(jsonStr, PreparedParameter.class); - assertEquals(String[].class, param.getType()); - assertTrue(param.getValue() instanceof String[]); - String[] vals = (String[])param.getValue(); - assertEquals(3, vals.length); - assertEquals("testing1", vals[0]); - assertEquals("testing2", vals[1]); - assertEquals("3", vals[2]); - } - - @Test - public void allowsBooleanListNullDeserialization() { - String jsonStr = "{ \"type\": \"[Z\" , \"value\": null}"; - PreparedParameter p = gson.fromJson(jsonStr, PreparedParameter.class); - assertEquals(boolean[].class, p.getType()); - assertEquals(null, p.getValue()); - } - - @Test - public void allowsIntListNullDeserialization() { - String jsonStr = "{ \"type\": \"[I\" , \"value\": null}"; - PreparedParameter p = gson.fromJson(jsonStr, PreparedParameter.class); - assertEquals(int[].class, p.getType()); - assertEquals(null, p.getValue()); - } - - @Test - public void allowsLongListNullDeserialization() { - String jsonStr = "{ \"type\": \"[J\" , \"value\": null}"; - PreparedParameter p = gson.fromJson(jsonStr, PreparedParameter.class); - assertEquals(long[].class, p.getType()); - assertEquals(null, p.getValue()); - } - - @Test - public void allowsDoubleListNullDeserialization() { - String jsonStr = "{ \"type\": \"[D\" , \"value\": null}"; - PreparedParameter p = gson.fromJson(jsonStr, PreparedParameter.class); - assertEquals(double[].class, p.getType()); - assertEquals(null, p.getValue()); - } - - @Test - public void allowsStringNullDeserialization() { - String jsonStr = "{ \"type\": \"java.lang.String\" , \"value\": null}"; - PreparedParameter p = gson.fromJson(jsonStr, PreparedParameter.class); - assertEquals(String.class, p.getType()); - assertEquals(null, p.getValue()); - } - - @Test - public void allowsStringListNullDeserialization() { - String jsonStr = "{ \"type\": \"[Ljava.lang.String;\" , \"value\": null}"; - PreparedParameter p = gson.fromJson(jsonStr, PreparedParameter.class); - assertEquals(String[].class, p.getType()); - assertEquals(null, p.getValue()); - } - - @Test - public void rejectNullForBooleanPrimitive() { - String jsonStr = "{ \"type\": \"boolean\" , \"value\": null}"; - doPrimitiveNullTest(jsonStr, "boolean"); - } - - @Test - public void rejectNullForIntPrimitive() { - String jsonStr = "{ \"type\": \"int\" , \"value\": null}"; - doPrimitiveNullTest(jsonStr, "int"); - } - - @Test - public void rejectNullForDoublePrimitive() { - String jsonStr = "{ \"type\": \"double\" , \"value\": null}"; - doPrimitiveNullTest(jsonStr, "double"); - } - - @Test - public void rejectNullForLongPrimitive() { - String jsonStr = "{ \"type\": \"long\" , \"value\": null}"; - doPrimitiveNullTest(jsonStr, "long"); - } - - private void doPrimitiveNullTest(String jsonStr, String typeName) { - try { - gson.fromJson(jsonStr, PreparedParameter.class); - // The Java language spec does not permit this - fail(typeName + " null primitive should not deserialize"); - } catch (Exception e) { - // pass - Throwable cause = e.getCause(); - assertEquals(typeName + " primitive does not accept a null value!", cause.getMessage()); - } - } - - @Test - public void failsDeserializationWrongTypeClass() { - String jsonStr = "{ \"type\": \"java.io.File\" , \"value\": true}"; - try { - gson.fromJson(jsonStr, PreparedParameter.class); - fail("should have failed to serialize"); - } catch (Exception e) { - // pass - Throwable cause = e.getCause(); - assertTrue(cause.getMessage().contains("Illegal type of parameter")); - } - } - - @Test - public void failsDeserializationIfStringForInt() { - String jsonStr = "{ \"type\": \"int\" , \"value\":\"testing\"}"; - try { - gson.fromJson(jsonStr, PreparedParameter.class); - fail("should have failed to serialize"); - } catch (Exception e) { - // pass - Throwable cause = e.getCause(); - assertTrue(cause instanceof NumberFormatException); - } - } - - @Test - public void failsDeserializationIfBooleanForInt() { - String jsonStr = "{ \"type\": \"int\" , \"value\": true}"; - try { - gson.fromJson(jsonStr, PreparedParameter.class); - fail("should have failed to serialize"); - } catch (Exception e) { - // pass - Throwable cause = e.getCause(); - assertTrue(cause instanceof IllegalStateException); - } - } - - @Test - public void failsDeserializationIfIntForIntList() { - String jsonStr = "{ \"type\": \"[I\" , \"value\": -1}"; - try { - gson.fromJson(jsonStr, PreparedParameter.class); - fail("should have failed to serialize"); - } catch (Exception e) { - // pass - Throwable cause = e.getCause(); - assertTrue(cause instanceof IllegalStateException); - } - } - - @Test - public void failsDeserializationIfDoubleForInt() { - String jsonStr = "{ \"type\": \"int\" , \"value\": -1.3}"; - try { - gson.fromJson(jsonStr, PreparedParameter.class); - fail("should have failed to serialize"); - } catch (Exception e) { - // pass - Throwable cause = e.getCause(); - assertTrue(cause instanceof NumberFormatException); - } - } - - @Test - public void canSerializeBasic() { - // String - String expected = "{\"type\":\"java.lang.String\",\"value\":\"testing\"}"; - PreparedParameter param = new PreparedParameter(); - param.setType(String.class); - param.setValue("testing"); - String actual = gson.toJson(param); - assertEquals(expected, actual); - // Integer - expected = "{\"type\":\"int\",\"value\":-1}"; - param.setType(int.class); - param.setValue(-1); - actual = gson.toJson(param); - assertEquals(expected, actual); - // Long - expected = "{\"type\":\"long\",\"value\":30000000003}"; - param.setType(long.class); - param.setValue(30000000003L); - actual = gson.toJson(param); - assertEquals(expected, actual); - // boolean - expected = "{\"type\":\"boolean\",\"value\":true}"; - param.setType(boolean.class); - param.setValue(true); - actual = gson.toJson(param); - assertEquals(expected, actual); - // String[] - String strArrayVal = "[\"testing1\",\"testing2\",\"3\"]"; - expected = "{\"type\":\"[Ljava.lang.String;\",\"value\":" + strArrayVal + "}"; - param.setType(String[].class); - String[] array = new String[] { - "testing1", "testing2", "3" - }; - param.setValue(array); - actual = gson.toJson(param); - assertEquals(expected, actual); - } - - @Test - public void canSerializeDeserializeInteger() { - PreparedParameter expected = new PreparedParameter(); - expected.setType(int.class); - expected.setValue(3); - String jsonStr = gson.toJson(expected, PreparedParameter.class); - assertParameterEquals(expected, jsonStr); - } - - @Test - public void canSerializeDeserializeIntegerArray() { - PreparedParameter expected = new PreparedParameter(); - expected.setType(int[].class); - expected.setValue(new int[] { 0, 3, 20 }); - String jsonStr = gson.toJson(expected, PreparedParameter.class); - assertParameterEquals(expected, jsonStr); - } - - @Test - public void canSerializeDeserializeDouble() { - PreparedParameter expected = new PreparedParameter(); - expected.setType(double.class); - expected.setValue(Math.E); - String jsonStr = gson.toJson(expected, PreparedParameter.class); - assertParameterEquals(expected, jsonStr); - } - - @Test - public void canSerializeDeserializeDoubleArray() { - PreparedParameter expected = new PreparedParameter(); - expected.setType(double[].class); - expected.setValue(new double[] { 3.3, 1.0, Math.PI }); - String jsonStr = gson.toJson(expected, PreparedParameter.class); - assertParameterEquals(expected, jsonStr); - } - - @Test - public void canSerializeDeserializeLong() { - PreparedParameter expected = new PreparedParameter(); - expected.setType(long.class); - expected.setValue(30000000003L); - String jsonStr = gson.toJson(expected, PreparedParameter.class); - assertParameterEquals(expected, jsonStr); - } - - @Test - public void canSerializeDeserializeLongArray() { - PreparedParameter expected = new PreparedParameter(); - expected.setType(long[].class); - expected.setValue(new long[] { 3000000000L, 3, 20 }); - String jsonStr = gson.toJson(expected, PreparedParameter.class); - assertParameterEquals(expected, jsonStr); - } - - @Test - public void canSerializeDeserializeString() { - PreparedParameter expected = new PreparedParameter(); - expected.setType(String.class); - expected.setValue("testing"); - String jsonStr = gson.toJson(expected, PreparedParameter.class); - assertParameterEquals(expected, jsonStr); - } - - @Test - public void canSerializeDeserializeStringArray() { - PreparedParameter expected = new PreparedParameter(); - expected.setType(String[].class); - String[] expectedArray = new String[] { - "one", "two", "three" - }; - expected.setValue(expectedArray); - String jsonStr = gson.toJson(expected, PreparedParameter.class); - assertParameterEquals(expected, jsonStr); - } - - @Test - public void canSerializeDeserializeBoolean() { - PreparedParameter expected = new PreparedParameter(); - expected.setType(boolean.class); - expected.setValue(false); - String jsonStr = gson.toJson(expected, PreparedParameter.class); - assertParameterEquals(expected, jsonStr); - - expected = new PreparedParameter(); - expected.setType(boolean.class); - expected.setValue(true); - jsonStr = gson.toJson(expected, PreparedParameter.class); - assertParameterEquals(expected, jsonStr); - } - - @Test - public void canSerializeDeserializeBooleanArray() { - PreparedParameter expected = new PreparedParameter(); - expected.setType(boolean[].class); - expected.setValue(new boolean[] { true, false, false, true }); - String jsonStr = gson.toJson(expected, PreparedParameter.class); - assertParameterEquals(expected, jsonStr); - } - - - @Test - public void canSerializeDeserializePojos() { - PreparedParameter expected = new PreparedParameter(); - AgentInformation info = new AgentInformation("foo-writer"); - expected.setType(info.getClass()); - expected.setValue(info); - String jsonStr = gson.toJson(expected, PreparedParameter.class); - assertParameterEquals(expected, jsonStr); - - info = new AgentInformation("some-writer"); - info.setAlive(true); - info.setConfigListenAddress("127.0.0.1:12000"); - info.setStartTime(System.currentTimeMillis()); - info.setStopTime(System.currentTimeMillis()); - expected = new PreparedParameter(); - expected.setType(info.getClass()); - expected.setValue(info); - jsonStr = gson.toJson(expected, PreparedParameter.class); - assertParameterEquals(expected, jsonStr); - - // null pojo - expected = new PreparedParameter(); - expected.setType(AgentInformation.class); - expected.setValue(null); - jsonStr = gson.toJson(expected, PreparedParameter.class); - assertParameterEquals(expected, jsonStr); - } - - @Test - public void canSerializeDeserializeInnerClassPojoTypes() { - PreparedParameter expected = new PreparedParameter(); - KeyValuePair pair = new KeyValuePair(); - pair.setKey("foo"); - pair.setValue("bar"); - expected.setType(pair.getClass()); - expected.setValue(pair); - String jsonStr = gson.toJson(expected, PreparedParameter.class); - - PreparedParameter actual = gson.fromJson(jsonStr, PreparedParameter.class); - - assertEquals(expected.getType(), actual.getType()); - assertTrue(actual.getValue() instanceof KeyValuePair); - KeyValuePair actualPair = (KeyValuePair)actual.getValue(); - assertEquals(pair.getKey(), actualPair.getKey()); - assertEquals(pair.getValue(), actualPair.getValue()); - } - - @Test - public void canSerializeDeserializePojoLists() { - AgentInformation info1 = new AgentInformation("foo-writer"); - AgentInformation info2 = new AgentInformation("some-writer"); - info2.setAlive(true); - info2.setConfigListenAddress("127.0.0.1:12000"); - info2.setStartTime(System.currentTimeMillis()); - info2.setStopTime(System.currentTimeMillis()); - AgentInformation[] infos = new AgentInformation[] { - info1, info2 - }; - PreparedParameter param = new PreparedParameter(); - param.setType(AgentInformation.class); - param.setValue(infos); - String jsonStr = gson.toJson(param, PreparedParameter.class); - assertParameterEquals(param, jsonStr); - } - - private void assertParameterEquals(PreparedParameter expected, - String jsonStr) { - PreparedParameter actual = gson.fromJson(jsonStr, PreparedParameter.class); - assertEquals(expected.getType(), actual.getType()); - if (actual.getValue() != null && actual.getValue().getClass().isArray()) { - // compare element by element - Object values = actual.getValue(); - Object expectedVals = expected.getValue(); - int expectedLength = Array.getLength(expectedVals); - int actualLength = Array.getLength(values); - assertEquals(expectedLength, actualLength); - // Make sure the deserialized array is of the correct expected type - assertEquals(expectedVals.getClass(), values.getClass()); - for (int i = 0; i < expectedLength; i++) { - Object exp = Array.get(expectedVals, i); - Object act = Array.get(values, i); - assertEquals(exp, act); - } - } else { - assertEquals(expected.getValue(), actual.getValue()); - } - } -} -
--- a/web/common/src/test/java/com/redhat/thermostat/web/common/typeadapters/PreparedParametersJSONPerformanceTest.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,151 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.web.common.typeadapters; - -import org.junit.experimental.categories.Category; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.reflect.TypeToken; -import com.redhat.thermostat.storage.core.PreparedParameters; -import com.redhat.thermostat.testutils.PerformanceTest; -import com.redhat.thermostat.web.common.typeadapters.PojoTypeAdapterFactory; -import com.redhat.thermostat.web.common.typeadapters.PreparedParameterTypeAdapterFactory; -import com.redhat.thermostat.web.common.typeadapters.PreparedParametersTypeAdapterFactory; - -/** - * JUnit categorized performance test. It'll be only run for - * the perf-tests profile. - */ -@Category(PerformanceTest.class) -public class PreparedParametersJSONPerformanceTest extends - JsonPerformanceTest<PreparedParameters> { - - private static final String OLD_JSON_FORMAT = "{\"params\":[]}"; - private static final String NEW_JSON_FORMAT = "[]"; - private static final boolean DEBUG = true; - - public PreparedParametersJSONPerformanceTest() { - super(DEBUG, PreparedParametersJSONPerformanceTest.class.getSimpleName()); - } - - @Override - protected Gson getSlowGson() { - return new GsonBuilder() - .registerTypeAdapterFactory(new PojoTypeAdapterFactory()) - .registerTypeAdapterFactory(new PreparedParameterTypeAdapterFactory()) - .create(); - } - - @Override - protected Gson getFasterGson() { - return new GsonBuilder() - .registerTypeAdapterFactory(new PojoTypeAdapterFactory()) - .registerTypeAdapterFactory(new PreparedParameterTypeAdapterFactory()) - .registerTypeAdapterFactory(new PreparedParametersTypeAdapterFactory()) - .create(); - } - - @Override - protected double getExpectedSpeedup(OperationType type, - int iterations) { - if (type == OperationType.SERIALIZATION && iterations == getColdSerializationIterations()) { - return 2; - } else if (type == OperationType.SERIALIZATION && iterations == getWarmSerializationIterations()) { - // actual should really be approaching 1.2. - return 0.95; - } else if (type == OperationType.DESERIALIZATION && iterations == getColdDeserializationIterations()) { - return 1.5; - } else if (type == OperationType.DESERIALIZATION && iterations == getWarmDeserializationIterations()) { - return 0.95; - } else { - throw new IllegalStateException("bug"); - } - } - - @Override - protected TypeToken<PreparedParameters> getDeserializeTypeToken() { - return TypeToken.get(PreparedParameters.class); - } - - @Override - protected int getColdSerializationIterations() { - return 1; - } - - @Override - protected int getWarmSerializationIterations() { - return 10000; - } - - @Override - protected int getColdDeserializationIterations() { - return 1; - } - - @Override - protected int getWarmDeserializationIterations() { - return 10000; - } - - @Override - protected double getSelfSerializationDelta() { - return 0.3; - } - - @Override - protected double getSelfDeserializationDelta() { - return 0.3; - } - - @Override - protected String mutateJsonString(GsonContext context, int mutator) { - if (context == GsonContext.FASTER) { - return NEW_JSON_FORMAT; - } else if (context == GsonContext.SLOW) { - return OLD_JSON_FORMAT; - } else { - throw new IllegalStateException("bug"); - } - } - - @Override - protected PreparedParameters mutateToBeSerializedInstance(int mutator) { - return new PreparedParameters(0); - } - -}
--- a/web/common/src/test/java/com/redhat/thermostat/web/common/typeadapters/PreparedParametersTypeAdapterTest.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,145 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.web.common.typeadapters; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import org.junit.Before; -import org.junit.Test; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.redhat.thermostat.storage.core.PreparedParameter; -import com.redhat.thermostat.storage.core.PreparedParameters; -import com.redhat.thermostat.storage.model.AgentInformation; -import com.redhat.thermostat.storage.model.Pojo; - -public class PreparedParametersTypeAdapterTest { - - private Gson gson; - - @Before - public void setup() { - gson = new GsonBuilder() - .registerTypeAdapterFactory(new PojoTypeAdapterFactory()) - .registerTypeAdapterFactory(new PreparedParameterTypeAdapterFactory()) - .registerTypeAdapterFactory(new PreparedParametersTypeAdapterFactory()) - .create(); - } - - @Test - public void canSerializeDeserializeBasic() { - PreparedParameters params = new PreparedParameters(5); - params.setBoolean(0, true); - params.setInt(1, 2300); - params.setLong(2, 2200000000L); - params.setString(3, "testing"); - String[] list = new String[] { - "a", "b", "c" - }; - params.setStringList(4, list); - - String jsonStr = gson.toJson(params, PreparedParameters.class); - PreparedParameters actualParams = gson.fromJson(jsonStr, PreparedParameters.class); - - PreparedParameter[] expected = params.getParams(); - PreparedParameter[] actual = actualParams.getParams(); - - // last element is the string array, which we check manually - for (int i = 0; i < expected.length - 1; i++) { - assertEquals(expected[i].getType(), actual[i].getType()); - assertEquals(expected[i].getValue(), actual[i].getValue()); - } - String actualList[] = (String[])actual[4].getValue(); - for (int i = 0; i < list.length; i++) { - assertEquals(list[i], actualList[i]); - } - } - - @Test - public void canSerializeDeserializeMixedTypesWithPojoList() { - AgentInformation info1 = new AgentInformation("foo-agent"); - info1.setAlive(true); - AgentInformation info2 = new AgentInformation("foo-agent"); - info2.setAlive(false); - info2.setStartTime(System.currentTimeMillis()); - info2.setStopTime(System.currentTimeMillis()); - info2.setConfigListenAddress("127.0.0.1:12000"); - AgentInformation[] infos = new AgentInformation[] { - info1, info2 - }; - long[] longs = new long[] { 3000000000L, -3, 300 }; - // String, long[], Pojo[] - PreparedParameters params = new PreparedParameters(3); - params.setString(0, "foo-param"); - params.setLongList(1, longs); - params.setPojoList(2, infos); - - String jsonStr = gson.toJson(params, PreparedParameters.class); - PreparedParameters actualParams = gson.fromJson(jsonStr, PreparedParameters.class); - - PreparedParameter[] expected = params.getParams(); - PreparedParameter[] actual = actualParams.getParams(); - - assertEquals(expected.length, actual.length); - - PreparedParameter param1 = actual[0]; - assertEquals("foo-param", param1.getValue()); - assertEquals(String.class, param1.getType()); - - PreparedParameter param2 = actual[1]; - assertEquals(long[].class, param2.getType()); - long[] twoActuals = (long[])param2.getValue(); - assertEquals(3, twoActuals.length); - assertEquals(3000000000L, (long)twoActuals[0]); - assertEquals(-3, (long)twoActuals[1]); - assertEquals(300, (long)twoActuals[2]); - - PreparedParameter param3 = actual[2]; - assertEquals(AgentInformation.class, param3.getType()); - assertTrue(param3.getValue().getClass().isArray()); - Pojo[] pojos = (Pojo[])param3.getValue(); - assertEquals(2, pojos.length); - for (int i = 0; i < pojos.length; i++) { - assertEquals(infos[i], pojos[i]); - } - } - - -} -
--- a/web/common/src/test/java/com/redhat/thermostat/web/common/typeadapters/SharedStateIdTypeAdapterTest.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,101 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.web.common.typeadapters; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - -import java.util.UUID; - -import org.junit.Before; -import org.junit.Test; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.redhat.thermostat.web.common.SharedStateId; - -public class SharedStateIdTypeAdapterTest { - -private Gson gson; - - @Before - public void setup() { - gson = new GsonBuilder() - .registerTypeAdapter(SharedStateId.class, new SharedStateIdTypeAdapter()) - .create(); - } - - @Test - public void canSerializeBasic() { - UUID uuid = UUID.randomUUID(); - SharedStateId id = new SharedStateId(3, uuid); - String gsonStr = gson.toJson(id); - String expectedJSON = "{\"sid\":3,\"stok\":\"" + uuid.toString() + "\"}"; - assertEquals(expectedJSON, gsonStr); - } - - @Test - public void canSerializeNull() { - SharedStateId id = new SharedStateId(3000, null); - String gsonStr = gson.toJson(id); - String expectedJSON = "{\"sid\":3000}"; - assertEquals(expectedJSON, gsonStr); - } - - @Test - public void canDeserializeBasic() { - UUID uuid = UUID.randomUUID(); - SharedStateId id = new SharedStateId(3, uuid); - String json = "{\"sid\":3,\"stok\":\"" + uuid.toString() + "\"}"; - SharedStateId deserialized = gson.fromJson(json, SharedStateId.class); - assertEquals(3, deserialized.getId()); - assertEquals(uuid, deserialized.getServerToken()); - assertEquals(id, deserialized); - } - - /** - * UUID string value might be null. Make sure deserialization works for - * those. - */ - @Test - public void canDeserializeNullServerNonce() { - String json = "{\"sid\":3}"; - SharedStateId deserialized = gson.fromJson(json, SharedStateId.class); - assertEquals(3, deserialized.getId()); - assertNull(deserialized.getServerToken()); - } -}
--- a/web/common/src/test/java/com/redhat/thermostat/web/common/typeadapters/WebPreparedStatementJSONPerformanceTest.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,148 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.web.common.typeadapters; - -import java.util.UUID; - -import org.junit.experimental.categories.Category; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.reflect.TypeToken; -import com.redhat.thermostat.storage.model.Pojo; -import com.redhat.thermostat.testutils.PerformanceTest; -import com.redhat.thermostat.web.common.SharedStateId; -import com.redhat.thermostat.web.common.WebPreparedStatement; -import com.redhat.thermostat.web.common.typeadapters.PojoTypeAdapterFactory; -import com.redhat.thermostat.web.common.typeadapters.WebPreparedStatementTypeAdapterFactory; - -/** - * JUnit categorized performance test. It'll be only run for - * the perf-tests profile during a full build. - */ -@Category(PerformanceTest.class) -@SuppressWarnings("rawtypes") -public class WebPreparedStatementJSONPerformanceTest extends - JsonPerformanceTest<WebPreparedStatement> { - - private static final boolean DEBUG = true; - - public WebPreparedStatementJSONPerformanceTest() { - super(DEBUG, WebPreparedStatementJSONPerformanceTest.class.getSimpleName()); - } - - @Override - protected Gson getSlowGson() { - return new GsonBuilder() - .registerTypeHierarchyAdapter(Pojo.class, new LegacyGSONConverter()) - .registerTypeAdapterFactory(new SharedStateIdTypeAdapterFactory()) - .registerTypeAdapter(WebPreparedStatement.class, new LegacyWebPreparedStatementSerializer()) - .create(); - } - - @Override - protected Gson getFasterGson() { - return new GsonBuilder() - .registerTypeAdapterFactory(new PojoTypeAdapterFactory()) - .registerTypeAdapterFactory(new SharedStateIdTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebPreparedStatementTypeAdapterFactory()) - .create(); - } - - @Override - protected double getExpectedSpeedup(OperationType type, int iterations) { - if (type == OperationType.SERIALIZATION && iterations == getColdSerializationIterations()) { - return 0.95; - } else if (type == OperationType.SERIALIZATION && iterations == getWarmSerializationIterations()) { - return 1.5; - } else if (type == OperationType.DESERIALIZATION && iterations == getColdDeserializationIterations()) { - return 0.95; - } else if (type == OperationType.DESERIALIZATION && iterations == getWarmDeserializationIterations()) { - return 2; - } else { - throw new IllegalStateException("Bug"); - } - } - - @Override - protected String mutateJsonString(GsonContext ctx, int mutator) { - return String.format("{\"sid\":{\"sid\":%d,\"stok\":\"" + UUID.randomUUID() + "\"},\"p\":{\"params\":[]}}", mutator); - } - - @Override - protected WebPreparedStatement mutateToBeSerializedInstance(int mutator) { - SharedStateId id = new SharedStateId(mutator, UUID.randomUUID()); - WebPreparedStatement retval = new WebPreparedStatement<>(0, id); - return retval; - } - - @Override - protected TypeToken<WebPreparedStatement> getDeserializeTypeToken() { - return TypeToken.get(WebPreparedStatement.class); - } - - @Override - protected int getColdSerializationIterations() { - return 1; - } - - @Override - protected int getWarmSerializationIterations() { - return 10000; - } - - @Override - protected int getColdDeserializationIterations() { - return 1; - } - - @Override - protected int getWarmDeserializationIterations() { - return 10000; - } - - @Override - protected double getSelfSerializationDelta() { - return 0.4; - } - - @Override - protected double getSelfDeserializationDelta() { - return 0.1; - } - -}
--- a/web/common/src/test/java/com/redhat/thermostat/web/common/typeadapters/WebPreparedStatementResponseJSONPerformanceTest.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,151 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.web.common.typeadapters; - -import java.util.UUID; - -import org.junit.experimental.categories.Category; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.reflect.TypeToken; -import com.redhat.thermostat.testutils.PerformanceTest; -import com.redhat.thermostat.web.common.SharedStateId; -import com.redhat.thermostat.web.common.WebPreparedStatementResponse; -import com.redhat.thermostat.web.common.typeadapters.WebPreparedStatementResponseTypeAdapterFactory; - -/** - * JUnit categorized performance test. It'll be only run for - * the perf-tests profile during a full build. - */ -@Category(PerformanceTest.class) -public class WebPreparedStatementResponseJSONPerformanceTest extends - JsonPerformanceTest<WebPreparedStatementResponse> { - - // Set to true in order to turn on debugging output - private static final boolean DEBUG = true; - - public WebPreparedStatementResponseJSONPerformanceTest() { - super(DEBUG, WebPreparedStatementResponseJSONPerformanceTest.class.getSimpleName()); - } - - @Override - protected Gson getSlowGson() { - return new GsonBuilder() - .registerTypeAdapterFactory(new SharedStateIdTypeAdapterFactory()) - .create(); - } - - @Override - protected Gson getFasterGson() { - return new GsonBuilder() - .registerTypeAdapterFactory(new SharedStateIdTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebPreparedStatementResponseTypeAdapterFactory()) - .create(); - } - - @Override - protected double getExpectedSpeedup(OperationType type, int iterations) { - if (type == OperationType.DESERIALIZATION && iterations == getColdDeserializationIterations()) { - return 4; - } else if (type == OperationType.DESERIALIZATION && iterations == getWarmDeserializationIterations()) { - // Actual speed-up of the warmed up scenario is roughly - // >= 1.0. However, there are cases where it falls below it. - // A lower bound of 0.95 should be adequate in order for tests to - // not fail spuriously (at least not as often). - return 0.95; - } else if (type == OperationType.SERIALIZATION && iterations == getColdSerializationIterations()) { - return 4; - } else if (type == OperationType.SERIALIZATION && iterations == getWarmSerializationIterations()) { - return 1.2; - } else { - throw new IllegalStateException("Bug!"); - } - } - - @Override - protected String mutateJsonString(GsonContext ctx, int mutator) { - int stmtId = (mutator + 1) * 20; - int numFreeVars = mutator; - return String.format("{\"numFreeVars\":%d,\"stmtId\":{\"sid\":%d,\"stok\":\"%s\"}}", numFreeVars, stmtId, UUID.randomUUID().toString()); - } - - @Override - protected WebPreparedStatementResponse mutateToBeSerializedInstance(int mutator) { - WebPreparedStatementResponse response = new WebPreparedStatementResponse(); - response.setNumFreeVariables(3); - SharedStateId id = new SharedStateId(mutator, UUID.randomUUID()); - response.setStatementId(id); - return response; - } - - @Override - protected TypeToken<WebPreparedStatementResponse> getDeserializeTypeToken() { - return TypeToken.get(WebPreparedStatementResponse.class); - } - - @Override - protected int getColdSerializationIterations() { - return 1; - } - - @Override - protected int getWarmSerializationIterations() { - return 10000; - } - - @Override - protected int getColdDeserializationIterations() { - return 1; - } - - @Override - protected int getWarmDeserializationIterations() { - return 2000; - } - - @Override - protected double getSelfSerializationDelta() { - return 0.1; - } - - @Override - protected double getSelfDeserializationDelta() { - return 0; - } - -}
--- a/web/common/src/test/java/com/redhat/thermostat/web/common/typeadapters/WebPreparedStatementResponseTypeAdapterTest.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,117 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.web.common.typeadapters; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - -import java.util.UUID; - -import org.junit.Before; -import org.junit.Test; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonSyntaxException; -import com.redhat.thermostat.web.common.SharedStateId; -import com.redhat.thermostat.web.common.WebPreparedStatementResponse; - -public class WebPreparedStatementResponseTypeAdapterTest { - - private Gson gson; - - @Before - public void setup() { - gson = new GsonBuilder() - .registerTypeAdapterFactory(new SharedStateIdTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebPreparedStatementResponseTypeAdapterFactory()) - .create(); - } - - @Test - public void testSerializationDeserializationBasic() { - WebPreparedStatementResponse response = new WebPreparedStatementResponse(); - response.setNumFreeVariables(6); - - UUID uuid = UUID.randomUUID(); - SharedStateId stmtId = new SharedStateId(WebPreparedStatementResponse.ILLEGAL_STATEMENT, uuid); - response.setStatementId(stmtId); - - String jsonStr = gson.toJson(response, WebPreparedStatementResponse.class); - String expectedString = "{\"numFreeVars\":6,\"stmtId\":{\"sid\":-1,\"stok\":\""+ uuid.toString() + "\"}}"; - assertEquals(expectedString, jsonStr); - - WebPreparedStatementResponse actual = gson.fromJson(jsonStr, WebPreparedStatementResponse.class); - - assertEquals(6, actual.getNumFreeVariables()); - assertEquals(stmtId, actual.getStatementId()); - } - - public void deserializeNull() { - String jsonString = "{\"numFreeVars\":11}"; - WebPreparedStatementResponse resp = gson.fromJson(jsonString, WebPreparedStatementResponse.class); - assertNull(resp.getStatementId()); - assertEquals(11, resp.getNumFreeVariables()); - } - - @Test - public void canDeserializeBasic() { - UUID uuid = UUID.randomUUID(); - SharedStateId stmtId = new SharedStateId(6, uuid); - String jsonString = "{\"numFreeVars\":11,\"stmtId\":{\"sid\":6,\"stok\":\""+ uuid.toString() + "\"}}"; - WebPreparedStatementResponse actual = gson.fromJson(jsonString, WebPreparedStatementResponse.class); - assertEquals(stmtId, actual.getStatementId()); - assertEquals(11, actual.getNumFreeVariables()); - } - - @Test(expected=JsonSyntaxException.class) - public void testDeserializationFail() { - String invalidString = "{\"forbar\":6,\"stmtId\":-1}"; - gson.fromJson(invalidString, WebPreparedStatementResponse.class); - } - - @Test - public void canSerializeDeserializeNull() { - WebPreparedStatementResponse response = null; - assertNull(response); - String json = gson.toJson(response, WebPreparedStatementResponse.class); - assertEquals("null", json); - WebPreparedStatementResponse actual = gson.fromJson(json, WebPreparedStatementResponse.class); - assertNull(actual); - } -} -
--- a/web/common/src/test/java/com/redhat/thermostat/web/common/typeadapters/WebPreparedStatementTypeAdapterTest.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,180 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.web.common.typeadapters; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; - -import java.util.UUID; - -import org.junit.Before; -import org.junit.Test; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.redhat.thermostat.storage.core.PreparedParameter; -import com.redhat.thermostat.storage.core.PreparedParameters; -import com.redhat.thermostat.storage.model.AgentInformation; -import com.redhat.thermostat.web.common.SharedStateId; -import com.redhat.thermostat.web.common.WebPreparedStatement; -import com.redhat.thermostat.web.common.WebPreparedStatementResponse; - -public class WebPreparedStatementTypeAdapterTest { - - private Gson gson; - - @Before - public void setup() { - gson = new GsonBuilder() - .registerTypeAdapterFactory(new WebPreparedStatementTypeAdapterFactory()) - .registerTypeAdapterFactory(new SharedStateIdTypeAdapterFactory()) - .registerTypeAdapterFactory(new PreparedParameterTypeAdapterFactory()) - .registerTypeAdapterFactory(new PojoTypeAdapterFactory()) - .create(); - } - - @Test - public void canSerializeNullParams() { - WebPreparedStatement<?> stmt = new WebPreparedStatement<>(); - UUID uuid = UUID.randomUUID(); - stmt.setStatementId(new SharedStateId(500, uuid)); - stmt.setParams(null); - - String expected = "{\"sid\":{\"sid\":500,\"stok\":\"" + uuid.toString() + "\"}}"; - - String actual = gson.toJson(stmt); - assertEquals(expected, actual); - } - - @Test - public void canDeserializeNullParams() { - UUID uuid = UUID.randomUUID(); - String json = "{\"sid\":{\"sid\":500,\"stok\":\"" + uuid.toString() + "\"}}"; - - WebPreparedStatement<?> stmt = gson.fromJson(json, WebPreparedStatement.class); - assertEquals(new SharedStateId(500, uuid), stmt.getStatementId()); - assertNull(stmt.getParams()); - } - - @Test - public void canSerializeEmptyParams() { - UUID uuid = UUID.randomUUID(); - SharedStateId id = new SharedStateId(555, uuid); - WebPreparedStatement<?> stmt = new WebPreparedStatement<>(0, id); - - String expected = "{\"sid\":{\"sid\":555,\"stok\":\"" + uuid.toString() + "\"},\"p\":{\"params\":[]}}"; - String actual = gson.toJson(stmt); - assertEquals(expected, actual); - } - - @Test - public void canDeserializeEmptyParams() { - UUID uuid = UUID.randomUUID(); - SharedStateId id = new SharedStateId(555, uuid); - String json = "{\"sid\":{\"sid\":555,\"stok\":\"" + uuid.toString() + "\"},\"p\":{\"params\":[]}}"; - - WebPreparedStatement<?> stmt = gson.fromJson(json, WebPreparedStatement.class); - assertEquals(id, stmt.getStatementId()); - assertNotNull(stmt.getParams()); - assertEquals(0, stmt.getParams().getParams().length); - } - - @Test - public void canSerializeAndDeserialize() { - PreparedParameters params = new PreparedParameters(5); - params.setInt(0, 2); - params.setString(1, "testing"); - params.setLong(2, 222L); - params.setStringList(3, new String[] { "one", "two" }); - params.setBoolean(4, true); - WebPreparedStatement<?> stmt = new WebPreparedStatement<>(); - stmt.setParams(params); - UUID uuid = UUID.randomUUID(); - SharedStateId id = new SharedStateId(WebPreparedStatementResponse.DESCRIPTOR_PARSE_FAILED, uuid); - stmt.setStatementId(id); - String jsonString = gson.toJson(stmt, WebPreparedStatement.class); - WebPreparedStatement<?> newStmt = gson.fromJson(jsonString, WebPreparedStatement.class); - assertNotNull(newStmt); - PreparedParameters newParams = newStmt.getParams(); - PreparedParameter[] parameters = newParams.getParams(); - assertEquals(5, parameters.length); - assertEquals(2, parameters[0].getValue()); - assertEquals(int.class, parameters[0].getType()); - assertEquals("testing", parameters[1].getValue()); - assertEquals(String.class, parameters[1].getType()); - assertEquals(222L, parameters[2].getValue()); - assertEquals(long.class, parameters[2].getType()); - String[] list = (String[])parameters[3].getValue(); - assertEquals(2, list.length); - assertEquals("one", list[0]); - assertEquals("two", list[1]); - assertEquals(String[].class, parameters[3].getType()); - assertEquals(true, parameters[4].getValue()); - assertEquals(boolean.class, parameters[4].getType()); - assertEquals(id, newStmt.getStatementId()); - } - - /* - * Writes need Pojo support for serialization. This is a basic test we do - * get Pojos across the wire in a prepared context. - */ - @Test - public void canSerializeDeserializePojoParameters() { - PreparedParameters params = new PreparedParameters(2); - params.setIntList(0, new int[] { 0, 300 }); - AgentInformation pojo1 = new AgentInformation("foo-agent"); - AgentInformation pojo2 = new AgentInformation("foo-agent"); - pojo2.setAlive(true); - pojo2.setConfigListenAddress("127.0.0.1:38822"); - params.setPojoList(1, new AgentInformation[] { pojo1, pojo2 }); - - WebPreparedStatement<?> stmt = new WebPreparedStatement<>(); - stmt.setParams(params); - UUID uuid = UUID.randomUUID(); - SharedStateId id = new SharedStateId(WebPreparedStatementResponse.DESCRIPTOR_PARSE_FAILED, uuid); - stmt.setStatementId(id); - - String jsonString = gson.toJson(stmt, WebPreparedStatement.class); - assertNotNull(jsonString); - - WebPreparedStatement<?> result = gson.fromJson(jsonString, WebPreparedStatement.class); - assertEquals(id, result.getStatementId()); - assertNotNull(result.getParams()); - } -} -
--- a/web/common/src/test/java/com/redhat/thermostat/web/common/typeadapters/WebQueryResponseTypeAdapterTest.java Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,191 +0,0 @@ -/* - * Copyright 2012-2017 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.web.common.typeadapters; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - -import java.lang.reflect.Type; - -import org.junit.Before; -import org.junit.Test; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.reflect.TypeToken; -import com.redhat.thermostat.storage.model.AgentInformation; -import com.redhat.thermostat.web.common.PreparedStatementResponseCode; -import com.redhat.thermostat.web.common.WebQueryResponse; - -public class WebQueryResponseTypeAdapterTest { - - private Gson gson; - - @Before - public void setup() { - gson = new GsonBuilder() - .registerTypeAdapterFactory(new PojoTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebQueryResponseTypeAdapterFactory()) - .create(); - } - - @Test - public void canSerializeBasic() { - // Our test pojo - AgentInformation agentInfo = new AgentInformation("testing"); - agentInfo.setAlive(false); - AgentInformation[] resultList = new AgentInformation[] { - agentInfo - }; - - // create the query response - WebQueryResponse<AgentInformation> response = new WebQueryResponse<>(); - response.setResultList(resultList); - response.setCursorId(300); - response.setResponseCode(PreparedStatementResponseCode.ILLEGAL_PATCH); - - String jsonStr = gson.toJson(response); - String expectedJson = "{\"errno\":-1,\"cId\":300,\"cHasMore\":false,\"payload\":[{\"agentId\":\"testing\",\"alive\":false,\"startTime\":0,\"stopTime\":0}]}"; - assertEquals(expectedJson, jsonStr); - } - - @Test - public void canSerializeNoResultList() { - // create the query response - WebQueryResponse<AgentInformation> response = new WebQueryResponse<>(); - response.setResultList(null); // should be left out from serialization - response.setCursorId(-0xdeadbeef); - response.setResponseCode(PreparedStatementResponseCode.ILLEGAL_PATCH); - - String jsonStr = gson.toJson(response); - String expectedJson = "{\"errno\":-1,\"cId\":559038737,\"cHasMore\":false}"; - assertEquals(expectedJson, jsonStr); - } - - @Test - public void canDeserializeNoResultList() { - String rawJson = "{\"errno\":-1,\"cId\":444,\"cHasMore\":true}"; - Type queryResponseType = new TypeToken<WebQueryResponse<AgentInformation>>() {}.getType(); - WebQueryResponse<AgentInformation> actual = gson.fromJson(rawJson, queryResponseType); - assertEquals(true, actual.hasMoreBatches()); - assertEquals(444, actual.getCursorId()); - - assertNull(actual.getResultList()); - - assertEquals(PreparedStatementResponseCode.ILLEGAL_PATCH, actual.getResponseCode()); - } - - @Test - public void canDeserializeBasic() { - String rawJson = "{\"errno\":-1,\"cId\":444,\"cHasMore\":true,\"payload\":[{\"startTime\":0,\"stopTime\":0,\"alive\":true,\"agentId\":\"testing\"}]}"; - Type queryResponseType = new TypeToken<WebQueryResponse<AgentInformation>>() {}.getType(); - WebQueryResponse<AgentInformation> actual = gson.fromJson(rawJson, queryResponseType); - assertEquals(true, actual.hasMoreBatches()); - assertEquals(444, actual.getCursorId()); - - AgentInformation[] actualList = actual.getResultList(); - - assertEquals(PreparedStatementResponseCode.ILLEGAL_PATCH, actual.getResponseCode()); - assertEquals(1, actualList.length); - AgentInformation actualInfo = actualList[0]; - assertEquals(true, actualInfo.isAlive()); - assertEquals("testing", actualInfo.getAgentId()); - } - - @Test - public void canSerializeAndDeserializeBasic() { - // Our test pojo - AgentInformation agentInfo = new AgentInformation("testing"); - agentInfo.setAlive(false); - AgentInformation[] resultList = new AgentInformation[] { - agentInfo - }; - - // create the query response - WebQueryResponse<AgentInformation> response = new WebQueryResponse<>(); - response.setResultList(resultList); - response.setResponseCode(PreparedStatementResponseCode.ILLEGAL_PATCH); - - String jsonStr = gson.toJson(response); - - // We need to tell GSON which parametrized type we want it to deserialize - // it to. - Type queryResponseType = new TypeToken<WebQueryResponse<AgentInformation>>() {}.getType(); - WebQueryResponse<AgentInformation> actual = gson.fromJson(jsonStr, queryResponseType); - - AgentInformation[] actualList = actual.getResultList(); - - assertEquals(PreparedStatementResponseCode.ILLEGAL_PATCH, actual.getResponseCode()); - assertEquals(1, actualList.length); - AgentInformation actualInfo = actualList[0]; - assertEquals(false, actualInfo.isAlive()); - assertEquals("testing", actualInfo.getAgentId()); - } - - @Test - public void canSerializeAndDeserializeVariousPojos() { - // Our test pojo - AgentInformation agentInfo = new AgentInformation("testing"); - agentInfo.setAlive(false); - AgentInformation[] resultList = new AgentInformation[] { - agentInfo - }; - - // create the query response - WebQueryResponse<AgentInformation> response = new WebQueryResponse<>(); - response.setResultList(resultList); - response.setResponseCode(PreparedStatementResponseCode.ILLEGAL_PATCH); - - String jsonStr = gson.toJson(response); - String expectedJson = "{\"errno\":-1,\"cId\":0,\"cHasMore\":false,\"payload\":[{\"agentId\":\"testing\",\"alive\":false,\"startTime\":0,\"stopTime\":0}]}"; - assertEquals(expectedJson, jsonStr); - - // We need to tell GSON which parametrized type we want it to deserialize - // it to. - Type queryResponseType = new TypeToken<WebQueryResponse<AgentInformation>>() {}.getType(); - WebQueryResponse<AgentInformation> actual = gson.fromJson(jsonStr, queryResponseType); - - AgentInformation[] actualList = actual.getResultList(); - - assertEquals(PreparedStatementResponseCode.ILLEGAL_PATCH, actual.getResponseCode()); - assertEquals(1, actualList.length); - AgentInformation actualInfo = actualList[0]; - assertEquals(false, actualInfo.isAlive()); - assertEquals("testing", actualInfo.getAgentId()); - } -} -
--- a/web/pom.xml Wed May 10 16:01:45 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - - Copyright 2012-2017 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. - ---> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> - - <parent> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat</artifactId> - <version>1.99.12-SNAPSHOT</version> - </parent> - - <artifactId>thermostat-web</artifactId> - <packaging>pom</packaging> - - <name>Thermostat Web</name> - - <modules> - <module>common</module> - <module>client</module> - </modules> - -</project> -