Mercurial > hg > thermostat-ng > agent
changeset 2691:c4ea301ff07b
Remove old netty-based command channel.
Reviewed-by: ebaron
Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-June/023634.html
author | Severin Gehwolf <sgehwolf@redhat.com> |
---|---|
date | Mon, 12 Jun 2017 20:50:03 +0200 |
parents | eaa1ff0bf5b9 |
children | a5425acc4260 |
files | agent/cli/pom.xml agent/cli/src/main/java/com/redhat/thermostat/agent/cli/internal/AgentApplication.java agent/cli/src/test/java/com/redhat/thermostat/agent/cli/internal/AgentApplicationTest.java agent/command-server/pom.xml agent/command-server/src/main/java/com/redhat/thermostat/agent/command/server/internal/CommandChannelConstants.java agent/command-server/src/main/java/com/redhat/thermostat/agent/command/server/internal/CommandChannelRequestDecoder.java agent/command-server/src/main/java/com/redhat/thermostat/agent/command/server/internal/CommandChannelSSLConfiguration.java agent/command-server/src/main/java/com/redhat/thermostat/agent/command/server/internal/CommandChannelServerContext.java agent/command-server/src/main/java/com/redhat/thermostat/agent/command/server/internal/CommandChannelServerImpl.java agent/command-server/src/main/java/com/redhat/thermostat/agent/command/server/internal/CommandChannelServerMain.java agent/command-server/src/main/java/com/redhat/thermostat/agent/command/server/internal/JsonRequestEncoder.java agent/command-server/src/main/java/com/redhat/thermostat/agent/command/server/internal/JsonResponseParser.java agent/command-server/src/main/java/com/redhat/thermostat/agent/command/server/internal/ResponseEncoder.java agent/command-server/src/main/java/com/redhat/thermostat/agent/command/server/internal/SSLConfigurationParser.java agent/command-server/src/main/java/com/redhat/thermostat/agent/command/server/internal/ServerHandler.java agent/command-server/src/test/java/com/redhat/thermostat/agent/command/server/internal/CommandChannelRequestDecoderTest.java agent/command-server/src/test/java/com/redhat/thermostat/agent/command/server/internal/CommandChannelServerContextTest.java agent/command-server/src/test/java/com/redhat/thermostat/agent/command/server/internal/CommandChannelServerImplTest.java agent/command-server/src/test/java/com/redhat/thermostat/agent/command/server/internal/CommandChannelServerMainTest.java agent/command-server/src/test/java/com/redhat/thermostat/agent/command/server/internal/JsonResponseParserTest.java agent/command-server/src/test/java/com/redhat/thermostat/agent/command/server/internal/ResponseEncoderTest.java agent/command-server/src/test/java/com/redhat/thermostat/agent/command/server/internal/SSLConfigurationParserTest.java agent/command-server/src/test/java/com/redhat/thermostat/agent/command/server/internal/ServerHandlerTest.java agent/command/pom.xml agent/command/src/main/java/com/redhat/thermostat/agent/command/ConfigurationServer.java agent/command/src/main/java/com/redhat/thermostat/agent/command/internal/Activator.java agent/command/src/main/java/com/redhat/thermostat/agent/command/internal/AgentRequestDecoder.java agent/command/src/main/java/com/redhat/thermostat/agent/command/internal/AgentResponseEncoder.java agent/command/src/main/java/com/redhat/thermostat/agent/command/internal/CommandChannelConstants.java agent/command/src/main/java/com/redhat/thermostat/agent/command/internal/CommandChannelDelegate.java agent/command/src/main/java/com/redhat/thermostat/agent/command/internal/ProcessUserInfoBuilder.java agent/command/src/main/java/com/redhat/thermostat/agent/command/internal/SSLConfigurationEncoder.java agent/command/src/main/java/com/redhat/thermostat/agent/command/package-info.java agent/command/src/test/java/com/redhat/thermostat/agent/command/internal/AgentRequestDecoderTest.java agent/command/src/test/java/com/redhat/thermostat/agent/command/internal/AgentResponseEncoderTest.java agent/command/src/test/java/com/redhat/thermostat/agent/command/internal/CommandChannelDelegateTest.java agent/command/src/test/java/com/redhat/thermostat/agent/command/internal/SSLConfigurationEncoderTest.java agent/core/src/main/java/com/redhat/thermostat/agent/Agent.java agent/core/src/main/java/com/redhat/thermostat/agent/config/AgentConfigsUtils.java agent/core/src/main/java/com/redhat/thermostat/agent/config/AgentProperties.java agent/core/src/main/java/com/redhat/thermostat/agent/config/AgentStartupConfiguration.java agent/core/src/test/java/com/redhat/thermostat/agent/AgentTest.java agent/core/src/test/java/com/redhat/thermostat/agent/config/AgentConfigsUtilsTest.java agent/core/src/test/java/com/redhat/thermostat/agent/config/AgentStartupConfigurationTest.java agent/pom.xml common/command/pom.xml common/command/src/main/java/com/redhat/thermostat/common/command/InvalidMessageException.java common/command/src/main/java/com/redhat/thermostat/common/command/Message.java common/command/src/main/java/com/redhat/thermostat/common/command/Messages.java common/command/src/main/java/com/redhat/thermostat/common/command/Request.java common/command/src/main/java/com/redhat/thermostat/common/command/RequestResponseListener.java common/command/src/main/java/com/redhat/thermostat/common/command/Response.java common/command/src/main/java/com/redhat/thermostat/common/command/noapi/ConfigurationCommandContext.java common/command/src/main/java/com/redhat/thermostat/common/command/noapi/DecodingHelper.java common/command/src/main/java/com/redhat/thermostat/common/command/noapi/EncodingHelper.java common/command/src/main/java/com/redhat/thermostat/common/command/noapi/MessageEncoder.java common/command/src/main/java/com/redhat/thermostat/common/command/noapi/ParameterDecodingContext.java common/command/src/main/java/com/redhat/thermostat/common/command/noapi/ParameterDecodingState.java common/command/src/main/java/com/redhat/thermostat/common/command/noapi/RequestEncoder.java common/command/src/main/java/com/redhat/thermostat/common/command/noapi/StringDecodingContext.java common/command/src/main/java/com/redhat/thermostat/common/command/noapi/StringDecodingState.java common/command/src/test/java/com/redhat/thermostat/common/command/MessagesTest.java common/command/src/test/java/com/redhat/thermostat/common/command/RequestTest.java common/command/src/test/java/com/redhat/thermostat/common/command/ResponseTest.java common/command/src/test/java/com/redhat/thermostat/common/command/noapi/DecodingHelperTest.java common/command/src/test/java/com/redhat/thermostat/common/command/noapi/EncodingHelperTest.java common/command/src/test/java/com/redhat/thermostat/common/command/noapi/RequestEncoderTest.java common/pom.xml distribution/assembly/core-assembly.xml distribution/config/agent.properties distribution/pom.xml plugins/killvm/agent/pom.xml plugins/killvm/agent/src/main/java/com/redhat/thermostat/killvm/agent/internal/Activator.java plugins/killvm/agent/src/main/java/com/redhat/thermostat/killvm/agent/internal/KillVmReceiver.java plugins/killvm/agent/src/test/java/com/redhat/thermostat/killvm/agent/internal/ActivatorTest.java plugins/killvm/agent/src/test/java/com/redhat/thermostat/killvm/agent/internal/KillVmReceiverTest.java plugins/vm-gc/remote-collector-command/pom.xml plugins/vm-gc/remote-collector-command/src/main/java/com/redhat/thermostat/gc/remote/command/GCRequestReceiver.java plugins/vm-gc/remote-collector-command/src/main/java/com/redhat/thermostat/gc/remote/command/internal/Activator.java plugins/vm-gc/remote-collector-command/src/test/java/com/redhat/thermostat/gc/remote/command/internal/ActivatorTest.java pom.xml |
diffstat | 81 files changed, 158 insertions(+), 8241 deletions(-) [+] |
line wrap: on
line diff
--- a/agent/cli/pom.xml Tue Jun 13 12:02:12 2017 +0200 +++ b/agent/cli/pom.xml Mon Jun 12 20:50:03 2017 +0200 @@ -78,11 +78,6 @@ </dependency> <dependency> <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-agent-command</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>com.redhat.thermostat</groupId> <artifactId>thermostat-common-core</artifactId> <version>${project.version}</version> </dependency>
--- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/internal/AgentApplication.java Tue Jun 13 12:02:12 2017 +0200 +++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/internal/AgentApplication.java Mon Jun 12 20:50:03 2017 +0200 @@ -36,17 +36,14 @@ package com.redhat.thermostat.agent.cli.internal; -import java.io.IOException; import java.util.concurrent.CountDownLatch; import java.util.logging.Level; import java.util.logging.Logger; import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceReference; import org.osgi.util.tracker.ServiceTracker; import com.redhat.thermostat.agent.Agent; -import com.redhat.thermostat.agent.command.ConfigurationServer; import com.redhat.thermostat.agent.config.AgentConfigsUtils; import com.redhat.thermostat.agent.config.AgentOptionParser; import com.redhat.thermostat.agent.config.AgentStartupConfiguration; @@ -62,7 +59,6 @@ import com.redhat.thermostat.common.cli.CommandContext; import com.redhat.thermostat.common.cli.CommandException; import com.redhat.thermostat.common.tools.ApplicationState; -import com.redhat.thermostat.common.utils.HostPortPair; import com.redhat.thermostat.common.utils.LoggingUtils; import com.redhat.thermostat.shared.config.InvalidConfigurationException; import com.redhat.thermostat.storage.core.WriterID; @@ -120,45 +116,12 @@ parser.parse(); } - @SuppressWarnings({ "rawtypes", "unchecked" }) private void runAgent(CommandContext ctx) throws CommandException { long startTime = System.currentTimeMillis(); configuration.setStartTime(startTime); shutdownLatch = new CountDownLatch(1); - - configServerTracker = new ServiceTracker(bundleContext, ConfigurationServer.class.getName(), null) { - @Override - public Object addingService(ServiceReference reference) { - final ConfigurationServer configServer = (ConfigurationServer) super.addingService(reference); - final HostPortPair hostPort = configuration.getConfigListenAddress(); - - try { - configServer.startListening(hostPort.getHost(), hostPort.getPort()); - prepareAgent(configServer); - } catch (IOException e) { - logger.log(Level.SEVERE, e.getMessage()); - // log stack trace as info only - logger.log(Level.INFO, e.getMessage(), e); - shutdown(ExitStatus.EXIT_ERROR); - } - - return configServer; - } - - @Override - public void removedService(ServiceReference reference, Object service) { - if (shutdownLatch.getCount() > 0) { - // Lost config server while still running - logger.warning("ConfigurationServer unexpectedly became unavailable"); - } - // Stop listening on command channel - ConfigurationServer server = (ConfigurationServer) service; - server.stopListening(); - super.removedService(reference, service); - } - }; - configServerTracker.open(); + prepareAgent(); try { // Wait for either SIGINT or SIGTERM @@ -204,16 +167,13 @@ private class CustomSignalHandler implements SignalHandler { private Agent agent; - private ConfigurationServer configServer; - public CustomSignalHandler(Agent agent, ConfigurationServer configServer) { + public CustomSignalHandler(Agent agent) { this.agent = agent; - this.configServer = configServer; } @Override public void handle(Signal arg0) { - configServer.stopListening(); try { agent.stop(); } catch (Exception ex) { @@ -270,7 +230,7 @@ return agent; } - private void prepareAgent(final ConfigurationServer configServer) { + private void prepareAgent() { Class<?>[] deps = new Class<?>[] { AgentInfoDAO.class, BackendInfoDAO.class @@ -283,7 +243,7 @@ BackendInfoDAO backendInfoDAO = services.get(BackendInfoDAO.class); Agent agent = startAgent(agentInfoDAO, backendInfoDAO); - handler = new CustomSignalHandler(agent, configServer); + handler = new CustomSignalHandler(agent); Signal.handle(new Signal(SIGINT_NAME), handler); Signal.handle(new Signal(SIGTERM_NAME), handler); }
--- a/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/internal/AgentApplicationTest.java Tue Jun 13 12:02:12 2017 +0200 +++ b/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/internal/AgentApplicationTest.java Mon Jun 12 20:50:03 2017 +0200 @@ -39,14 +39,12 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.mockito.Matchers.any; -import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.powermock.api.mockito.PowerMockito.whenNew; -import java.io.IOException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -54,39 +52,37 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; +import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; +import org.osgi.framework.Filter; +import org.osgi.framework.FrameworkUtil; import org.osgi.framework.InvalidSyntaxException; +import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import com.redhat.thermostat.agent.Agent; import com.redhat.thermostat.agent.cli.internal.AgentApplication.ConfigurationCreator; -import com.redhat.thermostat.agent.command.ConfigurationServer; import com.redhat.thermostat.agent.config.AgentStartupConfiguration; import com.redhat.thermostat.backend.BackendRegistry; import com.redhat.thermostat.common.ExitStatus; import com.redhat.thermostat.common.LaunchException; +import com.redhat.thermostat.common.Version; import com.redhat.thermostat.common.cli.Arguments; import com.redhat.thermostat.common.cli.CommandContext; import com.redhat.thermostat.common.cli.CommandException; -import com.redhat.thermostat.common.utils.HostPortPair; import com.redhat.thermostat.shared.config.InvalidConfigurationException; import com.redhat.thermostat.storage.core.WriterID; import com.redhat.thermostat.storage.dao.AgentInfoDAO; import com.redhat.thermostat.storage.dao.BackendInfoDAO; import com.redhat.thermostat.testutils.StubBundleContext; +import com.redhat.thermostat.utils.management.internal.MXBeanConnectionPoolControl; @RunWith(PowerMockRunner.class) public class AgentApplicationTest { - private static final String COMMAND_CHANNLE_BIND_HOST = "test"; - private static final int COMMAND_CHANNEL_BIND_PORT = 10101; - private StubBundleContext context; - private ConfigurationServer configServer; private ConfigurationCreator configCreator; private ExitStatus exitStatus; private WriterID writerId; @@ -98,8 +94,6 @@ AgentStartupConfiguration config = mock(AgentStartupConfiguration.class); when(config.getDBConnectionString()).thenReturn("test string; please ignore"); - HostPortPair hostPort = new HostPortPair(COMMAND_CHANNLE_BIND_HOST, COMMAND_CHANNEL_BIND_PORT); - when(config.getConfigListenAddress()).thenReturn(hostPort); configCreator = mock(ConfigurationCreator.class); when(configCreator.create()).thenReturn(config); @@ -108,8 +102,7 @@ context.registerService(AgentInfoDAO.class.getName(), agentInfoDAO, null); BackendInfoDAO backendInfoDAO = mock(BackendInfoDAO.class); context.registerService(BackendInfoDAO.class.getName(), backendInfoDAO, null); - configServer = mock(ConfigurationServer.class); - context.registerService(ConfigurationServer.class.getName(), configServer, null); + context.registerService(MXBeanConnectionPoolControl.class, mock(MXBeanConnectionPoolControl.class), null); writerId = mock(WriterID.class); exitStatus = mock(ExitStatus.class); @@ -118,18 +111,23 @@ @After public void tearDown() { context = null; - configServer = null; configCreator = null; exitStatus = null; } + @PrepareForTest({ FrameworkUtil.class, Agent.class }) @Test - public void testAgentStartup() throws CommandException, InterruptedException { + public void testAgentStartup() throws CommandException, InterruptedException, InvalidSyntaxException { final AgentApplication agent = new AgentApplication(context, exitStatus, writerId, configCreator); final CountDownLatch latch = new CountDownLatch(1); final CommandException[] ce = new CommandException[1]; final long timeoutMillis = 5000L; + Bundle mockBundle = createBundle(); + PowerMockito.mockStatic(FrameworkUtil.class); + when(FrameworkUtil.getBundle(Agent.class)).thenReturn(mockBundle); + when(FrameworkUtil.createFilter(any(String.class))).thenReturn(mock(Filter.class)); + startAgentRunThread(timeoutMillis, agent, ce, latch); boolean ret = latch.await(timeoutMillis, TimeUnit.MILLISECONDS); @@ -141,6 +139,17 @@ } } + private Bundle createBundle() { + String qualifier = "201207241700"; + Bundle sysBundle = mock(Bundle.class); + org.osgi.framework.Version ver = org.osgi.framework.Version + .parseVersion(String.format(Version.VERSION_NUMBER_FORMAT, + 1, 2, 3) + "." + qualifier); + when(sysBundle.getVersion()).thenReturn(ver); + when(sysBundle.getBundleContext()).thenReturn(context); + return sysBundle; + } + /* * Having the PrepareForTest annotation on method level does not seem to * deadlock the test, which seems to be more or less reliably reproducible @@ -195,7 +204,7 @@ verify(exitStatus).setExitStatus(ExitStatus.EXIT_ERROR); } - private void startAgentRunThread(final long timoutMillis, final AgentApplication agent, final CommandException[] ce, final CountDownLatch latch) { + private void startAgentRunThread(final long timoutMillis, final AgentApplication agent, final CommandException[] ce, final CountDownLatch latch) throws InterruptedException { Arguments args = mock(Arguments.class); final CommandContext commandContext = mock(CommandContext.class); when(commandContext.getArguments()).thenReturn(args); @@ -205,21 +214,8 @@ @Override public void run() { - // Finish when config server starts listening try { - doAnswer(new Answer<Void>() { - - @Override - public Void answer(InvocationOnMock invocation) throws Throwable { - latch.countDown(); - return null; - } - }).when(configServer).startListening(COMMAND_CHANNLE_BIND_HOST, COMMAND_CHANNEL_BIND_PORT); - } catch (IOException e1) { - fail("a mock should not throw an exception"); - } - - try { + latch.countDown(); agent.run(commandContext); } catch (CommandException e) { ce[0] = e;
--- a/agent/command-server/pom.xml Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,122 +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-agent</artifactId> - <version>1.99.12-SNAPSHOT</version> - </parent> - - <artifactId>thermostat-agent-command-server</artifactId> - <packaging>bundle</packaging> - - <name>Thermostat Command Channel Server (Process)</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.powermock</groupId> - <artifactId>powermock-api-mockito</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.powermock</groupId> - <artifactId>powermock-module-junit4</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>io.netty</groupId> - <artifactId>netty-handler</artifactId> - </dependency> - <dependency> - <groupId>commons-codec</groupId> - <artifactId>commons-codec</artifactId> - <version>${commons-codec.version}</version> - </dependency> - <dependency> - <groupId>com.google.code.gson</groupId> - <artifactId>gson</artifactId> - </dependency> - - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-agent-command</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-agent-ipc-client</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-Vendor>Red Hat, Inc.</Bundle-Vendor> - <Bundle-SymbolicName>com.redhat.thermostat.agent.command.server</Bundle-SymbolicName> - <Private-Package> - com.redhat.thermostat.agent.command.server.internal - </Private-Package> - <!-- Do not autogenerate uses clauses in Manifests --> - <_nouses>true</_nouses> - </instructions> - </configuration> - </plugin> - </plugins> - </build> - -</project> -
--- a/agent/command-server/src/main/java/com/redhat/thermostat/agent/command/server/internal/CommandChannelConstants.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +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.agent.command.server.internal; - -import java.nio.charset.Charset; - -interface CommandChannelConstants { - - // Server startup state tokens - byte[] SERVER_STARTED_TOKEN = "<SERVER STARTED>".getBytes(Charset.forName("UTF-8")); - byte[] SERVER_READY_TOKEN = "<SERVER READY>".getBytes(Charset.forName("UTF-8")); - - // SSLConfiguration JSON members - String SSL_JSON_ROOT = "sslConfiguration"; - String SSL_JSON_KEYSTORE_FILE = "keystoreFile"; - String SSL_JSON_KEYSTORE_PASS = "keystorePass"; - String SSL_JSON_COMMAND_CHANNEL = "enabledCommandChannel"; - String SSL_JSON_BACKING_STORAGE = "enabledBackingStorage"; - String SSL_JSON_HOSTNAME_VERIFICATION = "disableHostnameVerification"; - - // Request JSON members - String REQUEST_JSON_TOP = "request"; - String REQUEST_JSON_TYPE = "type"; - String REQUEST_JSON_HOST = "targetHost"; - String REQUEST_JSON_PORT = "targetPort"; - String REQUEST_JSON_PARAMS = "parameters"; - - // Response JSON members - String RESPONSE_JSON_TOP = "response"; - String RESPONSE_JSON_TYPE = "type"; - -}
--- a/agent/command-server/src/main/java/com/redhat/thermostat/agent/command/server/internal/CommandChannelRequestDecoder.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,140 +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.agent.command.server.internal; - -import java.net.InetSocketAddress; -import java.util.List; -import java.util.Map.Entry; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.redhat.thermostat.common.command.InvalidMessageException; -import com.redhat.thermostat.common.command.Request; -import com.redhat.thermostat.common.command.Request.RequestType; -import com.redhat.thermostat.common.command.noapi.DecodingHelper; -import com.redhat.thermostat.common.command.noapi.ParameterDecodingContext; -import com.redhat.thermostat.common.command.noapi.ParameterDecodingState; -import com.redhat.thermostat.common.command.noapi.StringDecodingContext; -import com.redhat.thermostat.common.command.noapi.StringDecodingState; -import com.redhat.thermostat.common.utils.LoggingUtils; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.ByteToMessageDecoder; - -/** - * <p> - * {@link Request} objects are serialized over the command channel in the - * following format: - * <pre> - * ------------------------- - * | A | TYPE | B | PARAMS | - * ------------------------- - * - * A is an 32 bit integer representing the length - in bytes - of TYPE. TYPE - * is a byte array representing the string of the request type (e.g. - * "RESPONSE_EXPECTED") B is a 32 bit integer representing the number of - * request parameters which follow. - * - * PARAMS (if B > 0) is a variable length stream of the following format: - * - * It is a simple encoding of name => value pairs. - * - * ----------------------------------------------------------------------------------------------- - * | I_1 | K_1 | P_1 | V_1 | ... | I_(n-1) | K_(n-1) | P_(n-1) | V_(n-1) | I_n | K_n | P_n | V_n | - * ----------------------------------------------------------------------------------------------- - * - * I_n A 32 bit integer representing the length - in bytes - of the n'th - * parameter name. - * K_n A 32 bit integer representing the length - in bytes - of the n'th - * parameter value. - * P_n A byte array representing the string of the n'th parameter name. - * V_n A byte array representing the string of the n'th parameter value. - * </pre> - * </p> - */ -class CommandChannelRequestDecoder extends ByteToMessageDecoder { - - private static final Logger logger = LoggingUtils.getLogger(CommandChannelRequestDecoder.class); - - @Override - protected void decode(ChannelHandlerContext ctx, ByteBuf buf, List<Object> out) throws Exception { - logger.log(Level.FINEST, "Command channel server: decoding Request object"); - StringDecodingContext stringDecCtx = DecodingHelper.decodeString(buf); - if (stringDecCtx.getState() != StringDecodingState.VALUE_READ) { - // insufficient data, return - return; - } - String typeAsString = stringDecCtx.getValue(); - if (typeAsString == null) { - throw new InvalidMessageException("Could not decode message: " + ByteBufUtil.hexDump(buf)); - } - // Netty javadoc tells us it's safe to downcast to more concrete type. - InetSocketAddress addr = (InetSocketAddress)ctx.channel().remoteAddress(); - Request request = new Request(RequestType.valueOf(typeAsString), addr); - int remainingLength = buf.readableBytes() - stringDecCtx.getBytesRead(); - ByteBuf adjustedBuffer = buf.slice(stringDecCtx.getBytesRead(), remainingLength); - ParameterDecodingContext paramCtx = DecodingHelper.decodeParameters(adjustedBuffer); - if (paramCtx.getState() != ParameterDecodingState.ALL_PARAMETERS_READ) { - // insufficient data - return; - } - // clean up resources from the request type + parameters - int totalBytesRead = stringDecCtx.getBytesRead() + - paramCtx.getBytesRead(); - buf.readerIndex(buf.readerIndex() + totalBytesRead); - buf.discardReadBytes(); - for (Entry<String, String> kv: paramCtx.getValues().entrySet()) { - request.setParameter(kv.getKey(), kv.getValue()); - } - out.add(request); - } - - @Override - public void channelActive(ChannelHandlerContext ctx) throws Exception { - logger.log(Level.FINEST, "Channel active!"); - } - - @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { - logger.log(Level.WARNING, "Exception caught", cause); - ctx.close(); - } - -} -
--- a/agent/command-server/src/main/java/com/redhat/thermostat/agent/command/server/internal/CommandChannelSSLConfiguration.java Tue Jun 13 12:02:12 2017 +0200 +++ /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.agent.command.server.internal; - -import java.io.File; - -import com.redhat.thermostat.shared.config.SSLConfiguration; - -class CommandChannelSSLConfiguration implements SSLConfiguration { - - private File keystoreFile; - private String keystorePass; - private boolean cmdChannel; - private boolean backingStorage; - private boolean disableVerification; - - public CommandChannelSSLConfiguration(File keystoreFile, String keystorePass, boolean cmdChannel, - boolean backingStorage, boolean disableVerification) { - this.keystoreFile = keystoreFile; - this.keystorePass = keystorePass; - this.cmdChannel = cmdChannel; - this.backingStorage = backingStorage; - this.disableVerification = disableVerification; - } - - @Override - public File getKeystoreFile() { - return keystoreFile; - } - - @Override - public String getKeyStorePassword() { - return keystorePass; - } - - @Override - public boolean enableForCmdChannel() { - return cmdChannel; - } - - @Override - public boolean enableForBackingStorage() { - return backingStorage; - } - - @Override - public boolean disableHostnameVerification() { - return disableVerification; - } - -}
--- a/agent/command-server/src/main/java/com/redhat/thermostat/agent/command/server/internal/CommandChannelServerContext.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,147 +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.agent.command.server.internal; - -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLEngine; - -import com.redhat.thermostat.agent.ipc.client.IPCMessageChannel; -import com.redhat.thermostat.common.command.noapi.ConfigurationCommandContext; -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.InvalidConfigurationException; -import com.redhat.thermostat.shared.config.SSLConfiguration; - -import io.netty.bootstrap.AbstractBootstrap; -import io.netty.bootstrap.ServerBootstrap; -import io.netty.channel.ChannelInitializer; -import io.netty.channel.ChannelOption; -import io.netty.channel.ChannelPipeline; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.channel.socket.SocketChannel; -import io.netty.channel.socket.nio.NioServerSocketChannel; -import io.netty.handler.ssl.SslHandler; - -class CommandChannelServerContext implements ConfigurationCommandContext { - - private static final Logger logger = LoggingUtils.getLogger(CommandChannelServerContext.class); - - private final ServerBootstrap bootstrap; - private final SSLConfiguration sslConf; - - - CommandChannelServerContext(SSLConfiguration sslConf, IPCMessageChannel agentChannel) { - this(sslConf, agentChannel, new ServerChannelPipelineInitializerCreator()); - } - - CommandChannelServerContext(SSLConfiguration sslConf, IPCMessageChannel agentChannel, ServerChannelPipelineInitializerCreator initCreator) { - this.sslConf = sslConf; - bootstrap = createBootstrap(sslConf, agentChannel, initCreator); - } - - @Override - public AbstractBootstrap<?, ?> getBootstrap() { - return bootstrap; - } - - @Override - public SSLConfiguration getSSLConfiguration() { - return sslConf; - } - - private ServerBootstrap createBootstrap(SSLConfiguration conf, IPCMessageChannel agentChannel, ServerChannelPipelineInitializerCreator initCreator) { - ServerBootstrap bootstrap = new ServerBootstrap(); - EventLoopGroup bossGroup = new NioEventLoopGroup(); - EventLoopGroup workerGroup = new NioEventLoopGroup(); - bootstrap.group(bossGroup, workerGroup) - .channel(NioServerSocketChannel.class) - .childHandler(initCreator.createInitializer(conf, agentChannel)) - .childOption(ChannelOption.TCP_NODELAY, true) - .childOption(ChannelOption.SO_KEEPALIVE, true) - .childOption(ChannelOption.SO_REUSEADDR, true); - - return bootstrap; - } - - static class ServerChannelInitializer extends ChannelInitializer<SocketChannel> { - - private final SSLConfiguration sslConf; - private final IPCMessageChannel agentChannel; - - ServerChannelInitializer(SSLConfiguration sslConf, IPCMessageChannel agentChannel) { - this.sslConf = sslConf; - this.agentChannel = agentChannel; - } - - @Override - public void initChannel(SocketChannel ch) throws Exception { - ChannelPipeline pipeline = ch.pipeline(); - if (sslConf.enableForCmdChannel()) { - SSLEngine engine = null; - try { - SSLContext ctxt = SSLContextFactory.getServerContext(sslConf); - engine = ctxt.createSSLEngine(); - engine.setUseClientMode(false); - } catch (SslInitException | InvalidConfigurationException e) { - logger.log(Level.SEVERE, - "Failed to initiate command channel endpoint", e); - } - pipeline.addLast("ssl", new SslHandler(engine)); - logger.log(Level.FINE, "Added SSL handler for command channel endpoint"); - } - pipeline.addLast("decoder", new CommandChannelRequestDecoder()); - pipeline.addLast("encoder", new ResponseEncoder()); - pipeline.addLast("handler", new ServerHandler(sslConf, agentChannel)); - } - - } - - // Testing hook - static class ServerChannelPipelineInitializerCreator { - - ServerChannelInitializer createInitializer(SSLConfiguration sslConf, IPCMessageChannel agentChannel) { - return new ServerChannelInitializer(sslConf, agentChannel); - } - } - -} -
--- a/agent/command-server/src/main/java/com/redhat/thermostat/agent/command/server/internal/CommandChannelServerImpl.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,80 +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.agent.command.server.internal; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.redhat.thermostat.agent.command.ConfigurationServer; -import com.redhat.thermostat.common.utils.LoggingUtils; - -import io.netty.bootstrap.ServerBootstrap; - -class CommandChannelServerImpl implements ConfigurationServer { - - private static final Logger logger = LoggingUtils.getLogger(CommandChannelServerImpl.class); - private final CommandChannelServerContext ctx; - - CommandChannelServerImpl(CommandChannelServerContext ctx) { - this.ctx = ctx; - } - - @Override - public void startListening(String hostname, int port) throws IOException { - ServerBootstrap bootstrap = (ServerBootstrap) ctx.getBootstrap(); - - InetSocketAddress addr = new InetSocketAddress(hostname, port); - - logger.log(Level.FINE, "Starting command channel server on " + addr.toString()); - // Bind and start to accept incoming connections. - try { - bootstrap.bind(addr).sync(); - } catch (InterruptedException e) { - logger.log(Level.WARNING, "Cmd channel server bind was interrupted!"); - } - logger.log(Level.FINEST, "Bound command channel server to " + addr.toString()); - } - - @Override - public void stopListening() { - logger.log(Level.FINE, "Stopping command channel server"); - ctx.getBootstrap().group().shutdownGracefully(); - } -} -
--- a/agent/command-server/src/main/java/com/redhat/thermostat/agent/command/server/internal/CommandChannelServerMain.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,202 +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.agent.command.server.internal; - -import java.io.File; -import java.io.IOException; -import java.nio.ByteBuffer; - -import com.redhat.thermostat.agent.ipc.client.ClientIPCService; -import com.redhat.thermostat.agent.ipc.client.ClientIPCServiceFactory; -import com.redhat.thermostat.agent.ipc.client.IPCMessageChannel; -import com.redhat.thermostat.common.portability.ProcessWatcher; -import com.redhat.thermostat.shared.config.NativeLibraryResolver; -import com.redhat.thermostat.shared.config.OS; -import com.redhat.thermostat.shared.config.SSLConfiguration; -import com.redhat.thermostat.shared.config.internal.CommonPathsImpl; - -public class CommandChannelServerMain { - - static final String IPC_SERVER_NAME = "command-channel"; - static final String CONFIG_FILE_PROP = "ipcConfigFile"; - - private static final int HOSTNAME_ARG_POS = 0; - private static final int HOSTPORT_ARG_POS = 1; - private static final int PARENT_PID_ARG_POS = 2; - - private static SSLConfigurationParser sslConfParser = new SSLConfigurationParser(); - private static ServerCreator serverCreator = new ServerCreator(); - private static ShutdownHookHandler shutdownHandler = new ShutdownHookHandler(); - private static Sleeper sleeper = new Sleeper(); - private static CommandChannelServerImpl impl = null; - private static ClientIPCService ipcService = null; - - // TODO Add some keep alive check - public static void main(String[] args) throws IOException { - if (args.length != 2 && args.length != 3) { - throw new IOException("usage: thermostat-command-channel <hostname> <port> [<parent pid>]"); - } - String hostname = args[HOSTNAME_ARG_POS]; - Integer port; - try { - port = Integer.valueOf(args[HOSTPORT_ARG_POS]); - } catch (NumberFormatException e) { - throw new IOException("Port number must be a valid integer"); - } - - // Windows named pipes has some native code - must set paths to find the DLL - if (OS.IS_WINDOWS) { - NativeLibraryResolver.setCommonPaths(new CommonPathsImpl()); - } - - // Get IPC configuration file location from system property - String configFileStr = System.getProperty(CONFIG_FILE_PROP); - if (configFileStr == null) { - throw new IOException("Unknown IPC configuration file location"); - } - File configFile = new File(configFileStr); - if (ipcService == null) { // Only non-null for testing - ipcService = ClientIPCServiceFactory.getIPCService(configFile); - } - // Connect to IPC server - IPCMessageChannel channel = ipcService.connectToServer(IPC_SERVER_NAME); - - - // if there's a parent pid, watch for it to exit and then shutdown. - final int parentPid = (args.length == 3) ? Integer.parseInt(args[PARENT_PID_ARG_POS]) : 0; - final int SLEEP_TIME_MS = 5000; // 5 seconds between checks - if (parentPid > 0) { - final ProcessWatcher watcher = new ProcessWatcher(parentPid, SLEEP_TIME_MS) { - @Override - public void onProcessExit() { - // tell myself to exit - System.exit(1); - } - }; - watcher.start(); - } - - try { - // Notify server has started - sendMessage(channel, CommandChannelConstants.SERVER_STARTED_TOKEN); - - SSLConfiguration config = sslConfParser.parseSSLConfiguration(channel); - - impl = serverCreator.createServer(config, channel); - - // Start listening on server - impl.startListening(hostname, port); - // Notify server is ready to accept requests - sendMessage(channel, CommandChannelConstants.SERVER_READY_TOKEN); - - shutdownHandler.addShutdownHook(new Thread(new Runnable() { - @Override - public void run() { - impl.stopListening(); - } - })); - - sleeper.sleepWait(); - } catch (IOException e) { - // Shut down server - if (impl != null) { - impl.stopListening(); - } - throw new IOException("Failed to start command channel server", e); - } finally { - channel.close(); - } - } - - private static void sendMessage(IPCMessageChannel channel, byte[] message) throws IOException { - // Don't interleave with other messages or requests - synchronized (channel) { - ByteBuffer buf = ByteBuffer.wrap(message); - channel.writeMessage(buf); - } - } - - static class ServerCreator { - CommandChannelServerImpl createServer(SSLConfiguration sslConf, IPCMessageChannel agentChannel) { - CommandChannelServerContext ctx = new CommandChannelServerContext(sslConf, agentChannel); - return new CommandChannelServerImpl(ctx); - } - } - - static class ShutdownHookHandler { - void addShutdownHook(Thread hook) { - Runtime.getRuntime().addShutdownHook(hook); - } - } - - static class Sleeper { - void sleepWait() { - while (!Thread.interrupted()) { - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - } - } - - /* For testing purposes only */ - static void setSSLConfigurationParser(SSLConfigurationParser parser) { - CommandChannelServerMain.sslConfParser = parser; - } - - /* For testing purposes only */ - static void setServerCreator(ServerCreator creator) { - CommandChannelServerMain.serverCreator = creator; - } - - /* For testing purposes only */ - static void setShutdownHookHandler(ShutdownHookHandler handler) { - CommandChannelServerMain.shutdownHandler = handler; - } - - /* For testing purposes only */ - static void setSleeper(Sleeper sleeper) { - CommandChannelServerMain.sleeper = sleeper; - } - - /* For testing purposes only */ - static void setIPCService(ClientIPCService ipcService) { - CommandChannelServerMain.ipcService = ipcService; - } -}
--- a/agent/command-server/src/main/java/com/redhat/thermostat/agent/command/server/internal/JsonRequestEncoder.java Tue Jun 13 12:02:12 2017 +0200 +++ /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.agent.command.server.internal; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.nio.ByteBuffer; -import java.nio.charset.Charset; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonObject; -import com.redhat.thermostat.agent.ipc.client.IPCMessageChannel; -import com.redhat.thermostat.common.command.Request; -import com.redhat.thermostat.common.command.Request.RequestType; - -// Encodes a Request as JSON and sends the result to the agent -class JsonRequestEncoder { - - void encodeRequestAndSend(IPCMessageChannel agentChannel, Request request) throws IOException { - GsonBuilder builder = new GsonBuilder(); - builder.serializeNulls(); // In case null parameter values are permitted - Gson gson = builder.create(); - - JsonObject requestObj = new JsonObject(); - InetSocketAddress addr = request.getTarget(); - requestObj.addProperty(CommandChannelConstants.REQUEST_JSON_HOST, addr.getHostString()); - requestObj.addProperty(CommandChannelConstants.REQUEST_JSON_PORT, addr.getPort()); - - // CommandChannelRequestDecoder ensures this is a safe cast - RequestType type = (RequestType) request.getType(); - requestObj.addProperty(CommandChannelConstants.REQUEST_JSON_TYPE, type.name()); - - JsonObject paramsObj = new JsonObject(); - for (String param : request.getParameterNames()) { - // Don't allow null parameter names - if (param == null) { - throw new IOException("Null parameter names are not allowed"); - } - String value = request.getParameter(param); - paramsObj.addProperty(param, value); - } - requestObj.add(CommandChannelConstants.REQUEST_JSON_PARAMS, paramsObj); - JsonObject requestRoot = new JsonObject(); - requestRoot.add(CommandChannelConstants.REQUEST_JSON_TOP, requestObj); - - String jsonRequest = gson.toJson(requestRoot); - byte[] jsonRequestBytes = jsonRequest.getBytes(Charset.forName("UTF-8")); - - // Write request - ByteBuffer buf = ByteBuffer.wrap(jsonRequestBytes); - agentChannel.writeMessage(buf); - } -} -
--- a/agent/command-server/src/main/java/com/redhat/thermostat/agent/command/server/internal/JsonResponseParser.java Tue Jun 13 12:02:12 2017 +0200 +++ /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.agent.command.server.internal; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.charset.Charset; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; -import com.google.gson.JsonParser; -import com.redhat.thermostat.agent.ipc.client.IPCMessageChannel; -import com.redhat.thermostat.common.command.Response; -import com.redhat.thermostat.common.command.Response.ResponseType; - -// Parses a Response encoded as JSON received from the agent -class JsonResponseParser { - - Response parseResponse(IPCMessageChannel agentChannel) throws IOException { - ByteBuffer buf = agentChannel.readMessage(); - byte[] jsonResponse = new byte[buf.remaining()]; - buf.get(jsonResponse); - - GsonBuilder builder = new GsonBuilder(); - Gson gson = builder.create(); - JsonParser parser = new JsonParser(); - - try { - // Get root of JsonObject tree - String jsonResponseString = new String(jsonResponse, Charset.forName("UTF-8")); - JsonElement rootElement = parser.parse(jsonResponseString); - requireNonNull(rootElement, "Entire response missing"); - JsonObject rootObj = toJsonObject(rootElement); - - JsonElement responseElement = rootObj.get(CommandChannelConstants.RESPONSE_JSON_TOP); - requireNonNull(responseElement, "Response data missing"); - JsonObject responseObj = toJsonObject(responseElement); - - // Get response type - JsonElement typeElement = responseObj.get(CommandChannelConstants.RESPONSE_JSON_TYPE); - requireNonNull(typeElement, "Response type missing"); - String typeString = gson.fromJson(typeElement, String.class); - - // Get enum value - ResponseType type; - try { - type = ResponseType.valueOf(typeString); - } catch (IllegalArgumentException e) { - throw new IOException("Invalid ResponseType: " + typeString); - } - - return new Response(type); - } catch (JsonParseException e) { - throw new IOException("Failed to parse response from agent", e); - } - } - - private void requireNonNull(JsonElement element, String errorMessage) throws IOException { - if (element == null || element.isJsonNull()) { - throw new IOException(errorMessage); - } - } - - private JsonObject toJsonObject(JsonElement element) throws IOException { - if (!element.isJsonObject()) { - throw new IOException("Malformed data received"); - } - return element.getAsJsonObject(); - } -}
--- a/agent/command-server/src/main/java/com/redhat/thermostat/agent/command/server/internal/ResponseEncoder.java Tue Jun 13 12:02:12 2017 +0200 +++ /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.agent.command.server.internal; - -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.redhat.thermostat.common.command.Message; -import com.redhat.thermostat.common.command.Response; -import com.redhat.thermostat.common.command.noapi.EncodingHelper; -import com.redhat.thermostat.common.command.noapi.MessageEncoder; -import com.redhat.thermostat.common.utils.LoggingUtils; - -import io.netty.buffer.ByteBuf; - - -class ResponseEncoder extends MessageEncoder { - - private static final Logger logger = LoggingUtils.getLogger(ResponseEncoder.class); - - /* - * See javadoc of Response for a description of the encoding. - */ - @Override - protected ByteBuf encode(Message msg) { - // At this point we are only getting Messages. Since our only - // registered MessageEncoder is the one for Responses a cast - // to Response should be safe. - logger.log(Level.FINEST, "Command channel server: encoding Response object"); - Response response = (Response) msg; - - // Response Type - String responseType = EncodingHelper.trimType(response.getType().toString()); - ByteBuf typeBuffer = EncodingHelper.encode(responseType); - - return typeBuffer; - } - -} -
--- a/agent/command-server/src/main/java/com/redhat/thermostat/agent/command/server/internal/SSLConfigurationParser.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,125 +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.agent.command.server.internal; - -import java.io.File; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.charset.Charset; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; -import com.google.gson.JsonParser; -import com.redhat.thermostat.agent.ipc.client.IPCMessageChannel; -import com.redhat.thermostat.shared.config.SSLConfiguration; - -class SSLConfigurationParser { - - SSLConfiguration parseSSLConfiguration(IPCMessageChannel channel) throws IOException { - ByteBuffer buf = channel.readMessage(); - byte[] jsonSslConf = new byte[buf.remaining()]; - buf.get(jsonSslConf); - - GsonBuilder builder = new GsonBuilder(); - Gson gson = builder.create(); - JsonParser parser = new JsonParser(); - - try { - String jsonSslConfString = new String(jsonSslConf, Charset.forName("UTF-8")); - JsonElement parsed = parser.parse(jsonSslConfString); - requireNonNull(parsed, "Entire SSL configuration missing"); - JsonObject root = toJsonObject(parsed); - - JsonElement sslConfigElement = root.get(CommandChannelConstants.SSL_JSON_ROOT); - requireNonNull(sslConfigElement, "SSL configuration parameters missing"); - JsonObject sslConfigObj = toJsonObject(sslConfigElement); - - // Construct SSLConfiguration from parameters - String keystorePath = getStringOrNull(gson, sslConfigObj, CommandChannelConstants.SSL_JSON_KEYSTORE_FILE); - File keystoreFile = null; - if (keystorePath != null) { - keystoreFile = new File(keystorePath); - } - String keystorePass = getStringOrNull(gson, sslConfigObj, CommandChannelConstants.SSL_JSON_KEYSTORE_PASS); - boolean cmdChannel = getBoolean(gson, sslConfigObj, CommandChannelConstants.SSL_JSON_COMMAND_CHANNEL); - boolean backingStorage = getBoolean(gson, sslConfigObj, CommandChannelConstants.SSL_JSON_BACKING_STORAGE); - boolean disableVerification = getBoolean(gson, sslConfigObj, CommandChannelConstants.SSL_JSON_HOSTNAME_VERIFICATION); - - return new CommandChannelSSLConfiguration(keystoreFile, keystorePass, cmdChannel, - backingStorage, disableVerification); - } catch (JsonParseException e) { - throw new IOException("Invalid encoded SSL configuration", e); - } - } - - private String getStringOrNull(Gson gson, JsonObject sslConfigObj, String member) throws IOException { - String value = null; - // May be null value, but parameter must be specified - if (!sslConfigObj.has(member)) { - throw new IOException(member + " parameter missing"); - } - JsonElement element = sslConfigObj.get(member); - if (element != null) { - value = gson.fromJson(element, String.class); - } - return value; - } - - private boolean getBoolean(Gson gson, JsonObject sslConfigObj, String member) throws IOException { - JsonElement element = sslConfigObj.get(member); - requireNonNull(element, member + " parameter missing"); - boolean value = gson.fromJson(element, Boolean.class); - return value; - } - - private void requireNonNull(JsonElement element, String errorMessage) throws IOException { - if (element == null || element.isJsonNull()) { - throw new IOException(errorMessage); - } - } - - private JsonObject toJsonObject(JsonElement element) throws IOException { - if (!element.isJsonObject()) { - throw new IOException("Malformed data received"); - } - return element.getAsJsonObject(); - } - -}
--- a/agent/command-server/src/main/java/com/redhat/thermostat/agent/command/server/internal/ServerHandler.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,162 +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.agent.command.server.internal; - -import java.io.IOException; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.redhat.thermostat.agent.ipc.client.IPCMessageChannel; -import com.redhat.thermostat.common.command.Message.MessageType; -import com.redhat.thermostat.common.command.Request; -import com.redhat.thermostat.common.command.Response; -import com.redhat.thermostat.common.command.Response.ResponseType; -import com.redhat.thermostat.common.utils.LoggingUtils; -import com.redhat.thermostat.shared.config.SSLConfiguration; - -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.SimpleChannelInboundHandler; -import io.netty.handler.ssl.SslHandler; -import io.netty.util.concurrent.Future; -import io.netty.util.concurrent.GenericFutureListener; - -class ServerHandler extends SimpleChannelInboundHandler<Request> { - - private static final Logger logger = LoggingUtils.getLogger(ServerHandler.class); - - private final SSLConfiguration sslConf; - private final IPCMessageChannel agentChannel; - private final JsonRequestEncoder requestEncoder; - private final JsonResponseParser responseParser; - - ServerHandler(SSLConfiguration sslConf, IPCMessageChannel agentChannel) { - this(sslConf, agentChannel, new JsonRequestEncoder(), new JsonResponseParser()); - } - - ServerHandler(SSLConfiguration sslConf, IPCMessageChannel agentChannel, JsonRequestEncoder requestEncoder, JsonResponseParser responseParser) { - this.sslConf = sslConf; - this.agentChannel = agentChannel; - this.requestEncoder = requestEncoder; - this.responseParser = responseParser; - } - - @Override - public void channelActive(ChannelHandlerContext ctx) throws Exception { - logger.log(Level.FINEST, "Channel active!"); - if (sslConf.enableForCmdChannel()) { - // Get the SslHandler in the current pipeline. - // We added it in ConfigurationServerContext$ServerPipelineFactory. - final SslHandler sslHandler = ctx.pipeline().get( - SslHandler.class); - - // Get notified when SSL handshake is done. - Future<Channel> handshakeFuture = sslHandler.handshakeFuture(); - handshakeFuture.addListener(new SSLHandshakeDoneListener(ctx)); - } - } - - /* - * 1. Read request from command channel - * 2. Write request to agent encoded as JSON - * 3. Wait on agent for response (maybe add timeout here) - * 4. Read JSON-encoded response from agent - * 5. Write response to command channel - */ - @Override - protected void channelRead0(ChannelHandlerContext ctx, Request request) - throws Exception { - Response response; - String receiverName = request.getReceiver(); - MessageType requestType = request.getType(); - if (requestType == null || receiverName == null) { - logger.warning("Invalid Request"); - response = new Response(ResponseType.ERROR); - } else { - // Reading/writing to agent should be synchronized - logger.info("Request received: '" + requestType + "' for '" + receiverName + "'"); - synchronized (agentChannel) { - try { - // Ensure channel is still open - if (!agentChannel.isOpen()) { - throw new IOException("Communication channel with agent is closed"); - } - requestEncoder.encodeRequestAndSend(agentChannel, request); - response = responseParser.parseResponse(agentChannel); - } catch (IOException ex) { - logger.log(Level.WARNING, "Failed to communicate with agent", ex); - response = new Response(ResponseType.ERROR); - } - } - } - - Channel channel = ctx.channel(); - logger.info("Sending response: " + response.getType().toString()); - channel.pipeline().writeAndFlush(response); - ctx.close(); - } - - @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { - logger.log(Level.WARNING, "Unexpected exception from downstream.", cause); - ctx.close(); - } - - /* - * Only registered if SSL is enabled - */ - static final class SSLHandshakeDoneListener implements GenericFutureListener<Future<Channel>> { - - private final ChannelHandlerContext ctx; - - SSLHandshakeDoneListener(ChannelHandlerContext ctx) { - this.ctx = ctx; - } - - @Override - public void operationComplete(Future<Channel> future) throws Exception { - if (future.isSuccess()) { - logger.log(Level.FINE, "Finished SSL handshake."); - } else { - logger.log(Level.WARNING, "SSL handshake failed!"); - ctx.close(); - } - } - } - -} -
--- a/agent/command-server/src/test/java/com/redhat/thermostat/agent/command/server/internal/CommandChannelRequestDecoderTest.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,580 +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.agent.command.server.internal; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import org.junit.Before; -import org.junit.Test; - -import com.redhat.thermostat.common.command.Message; -import com.redhat.thermostat.common.command.Messages; -import com.redhat.thermostat.common.command.Request; -import com.redhat.thermostat.common.command.Request.RequestType; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; - -public class CommandChannelRequestDecoderTest { - - private static final String LONG_PARAM_VALUE = "RULE count sleep method invocations\n" + - "CLASS com.redhat.thermostat.byteman.test.InfiniteLoop\n" + - "METHOD sleep\n" + - "AT ENTRY\n" + - "IF true\n" + - "DO\n" + - "incrementCounter(\"sleep-counter\")\n" + - "ENDRULE\n" + - "\n" + - "RULE send sleep method invocations to thermostat\n" + - "CLASS com.redhat.thermostat.byteman.test.InfiniteLoop\n" + - "METHOD sleep\n" + - "HELPER org.jboss.byteman.thermostat.helper.ThermostatHelper\n" + - "AT ENTRY\n" + - "BIND counterValue: int = readCounter(\"sleep-counter\")\n" + - "IF counterValue % 10 == 0\n" + - "DO\n" + - "send(\"com.redhat.thermostat.byteman.test.InfiniteLoop\", \"method sleep() count\", counterValue);\n" + - "ENDRULE\n"; - - /* - * This is serialized format for - * req = new Request(RequestType.RESPONSE_EXPECTED, blah); - * req.setParameter("param1", "value1"); - * req.setParameter("param2", "value2"); - */ - private static final byte[] ENCODED_REQUEST_WITH_PARAMS = new byte[] { - 0x00, 0x00, 0x00, 0x11, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45, - 0x5f, 0x45, 0x58, 0x50, 0x45, 0x43, 0x54, 0x45, 0x44, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x70, 0x61, 0x72, - 0x61, 0x6d, 0x31, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x32, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x32 - }; - - /* - * This is serialized format for: - * - * Request req = new Request(RequestType.RESPONSE_EXPECTED, blah); - * req.setReceiver("com.redhat.thermostat.vm.byteman.agent.internal.BytemanRequestReceiver"); - * req.setParameter("action-name", "vm-byteman-instrument"); - * req.setParameter("vm-id", "f5b4cc44-06f2-4847-97d3-b5b0b198f843"); - * req.setParameter("byteman-action", Integer.toString(0)); - * req.setParameter("listen-port", Integer.toString(listenPort)); - * req.setParameter("auth-token", "/UFDv9PT3nLMW1lEJUyTxfIHfU8bRxcAw4IdVYL7JzHROruzNvIpuvqrLUN01f0hGIGMmzc58iylrbpgY1wkUA04YL5WOF66ysfwLWwDA8M2R7khrK0xY6+DLSA1nOUT+ihmvGsrlk51x5aqH7Vvqqj+TDyj8Z3Gl3dMp6KEngtBxxhxO/pI9euQGUiwWGcY7CdTAoTSx2wh8bOsmDUllwOE7978ZhTRsSN0bd57eynDaae23TwInhez5iHOxuWlByjEv4RyDPSc0fASoKwH7IAj7VYMzuj72/c9xLOA54XuyruaMdqi0zlA4v/af7xJ90XVMWdW96EGBGkIlo33fA=="); - * req.setParameter("client-token", "MdJ08lQ4+4H9asOQaYxV6XDXbICi3njI7JmZ9W8WgN7LW8RIYZ0aCFpaHQIHsG38mOLvZRzLNwI45NG/qoxVu+BA8ekEBpLlHCotxLk+1F7yZonmkEfXq6o4imsVU/8EU36Dh7YRd5qOnerJ7NItrw/kBuVaAlsVL2Bbj7ryvVVE01GgMJlBLQjnjb21eO2yg2w4AKDOggHMwcCAaZl1wW1pKQJAvlT0FYHrwSUJQ51JrZEUJjFxZ38xxYHA0HMffUiDczqkFj08w59G/652JY/hWpoM9uzwZP+tV4sCWXFF5IuBB8PFwaeqgXDwrbxgYMjCgk9nNZuvdsdaV1bGRQ=="); - * req.setParameter("byteman-rule", LONG_PARAM_VALUE); - */ - private static final byte[] ENCODED_REQUEST_WITH_MANY_PARAMS = new byte[] { - 0x00, 0x00, 0x00, 0x11, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45, - 0x5f, 0x45, 0x58, 0x50, 0x45, 0x43, 0x54, 0x45, 0x44, - 0x00, 0x00, 0x00, 0x08, // 8 parameters, slice A end - 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x15, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x2d, 0x6e, 0x61, 0x6d, 0x65, 0x76, 0x6d, 0x2d, 0x62, 0x79, - 0x74, 0x65, 0x6d, 0x61, 0x6e, 0x2d, 0x69, 0x6e, 0x73, 0x74, 0x72, 0x75, - 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x01, 0x58, - 0x61, 0x75, 0x74, 0x68, 0x2d, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2f, 0x55, - 0x46, 0x44, 0x76, 0x39, 0x50, 0x54, 0x33, 0x6e, 0x4c, 0x4d, 0x57, 0x31, - 0x6c, 0x45, 0x4a, 0x55, 0x79, 0x54, 0x78, 0x66, 0x49, 0x48, 0x66, 0x55, - 0x38, 0x62, 0x52, 0x78, 0x63, 0x41, 0x77, 0x34, 0x49, 0x64, 0x56, 0x59, - 0x4c, 0x37, 0x4a, 0x7a, 0x48, 0x52, 0x4f, 0x72, 0x75, 0x7a, 0x4e, 0x76, - 0x49, 0x70, 0x75, 0x76, 0x71, 0x72, 0x4c, 0x55, 0x4e, 0x30, 0x31, 0x66, - 0x30, 0x68, 0x47, 0x49, 0x47, 0x4d, 0x6d, 0x7a, 0x63, 0x35, 0x38, 0x69, - 0x79, 0x6c, 0x72, 0x62, 0x70, 0x67, 0x59, 0x31, 0x77, 0x6b, 0x55, 0x41, - 0x30, 0x34, 0x59, 0x4c, 0x35, 0x57, 0x4f, 0x46, 0x36, 0x36, 0x79, 0x73, - 0x66, 0x77, 0x4c, 0x57, 0x77, 0x44, 0x41, 0x38, 0x4d, 0x32, 0x52, 0x37, - 0x6b, 0x68, 0x72, 0x4b, 0x30, 0x78, 0x59, 0x36, 0x2b, 0x44, 0x4c, 0x53, - 0x41, 0x31, 0x6e, 0x4f, 0x55, 0x54, 0x2b, 0x69, 0x68, 0x6d, 0x76, 0x47, - 0x73, 0x72, 0x6c, 0x6b, 0x35, 0x31, 0x78, 0x35, 0x61, 0x71, 0x48, 0x37, - 0x56, 0x76, 0x71, 0x71, 0x6a, 0x2b, 0x54, 0x44, 0x79, 0x6a, 0x38, 0x5a, - 0x33, 0x47, 0x6c, 0x33, 0x64, 0x4d, 0x70, 0x36, 0x4b, 0x45, 0x6e, 0x67, - 0x74, 0x42, 0x78, 0x78, 0x68, 0x78, 0x4f, 0x2f, 0x70, 0x49, 0x39, 0x65, - 0x75, 0x51, 0x47, 0x55, 0x69, 0x77, 0x57, 0x47, 0x63, 0x59, 0x37, 0x43, - 0x64, 0x54, 0x41, 0x6f, 0x54, 0x53, 0x78, 0x32, 0x77, 0x68, 0x38, 0x62, - 0x4f, 0x73, 0x6d, 0x44, 0x55, 0x6c, 0x6c, 0x77, 0x4f, 0x45, 0x37, 0x39, - 0x37, 0x38, 0x5a, 0x68, 0x54, 0x52, 0x73, 0x53, 0x4e, 0x30, 0x62, 0x64, - 0x35, 0x37, 0x65, 0x79, 0x6e, 0x44, 0x61, 0x61, 0x65, 0x32, 0x33, 0x54, - 0x77, 0x49, 0x6e, 0x68, 0x65, 0x7a, 0x35, 0x69, 0x48, 0x4f, 0x78, 0x75, - 0x57, 0x6c, 0x42, 0x79, 0x6a, 0x45, 0x76, 0x34, 0x52, 0x79, 0x44, 0x50, - 0x53, 0x63, 0x30, 0x66, 0x41, 0x53, 0x6f, 0x4b, 0x77, 0x48, 0x37, 0x49, - 0x41, 0x6a, 0x37, 0x56, 0x59, 0x4d, 0x7a, 0x75, 0x6a, 0x37, 0x32, 0x2f, - 0x63, 0x39, 0x78, 0x4c, 0x4f, 0x41, 0x35, 0x34, 0x58, 0x75, 0x79, 0x72, - 0x75, 0x61, 0x4d, 0x64, 0x71, 0x69, 0x30, 0x7a, 0x6c, 0x41, 0x34, 0x76, - 0x2f, 0x61, 0x66, 0x37, 0x78, 0x4a, 0x39, 0x30, 0x58, 0x56, 0x4d, 0x57, - 0x64, 0x57, 0x39, 0x36, 0x45, 0x47, 0x42, 0x47, 0x6b, 0x49, 0x6c, 0x6f, - 0x33, 0x33, 0x66, 0x41, 0x3d, 0x3d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, - 0x00, 0x01, 0x62, 0x79, 0x74, 0x65, 0x6d, 0x61, 0x6e, 0x2d, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x30, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x02, - 0x1a, 0x62, 0x79, 0x74, 0x65, 0x6d, 0x61, 0x6e, 0x2d, 0x72, 0x75, 0x6c, - 0x65, 0x52, 0x55, 0x4c, 0x45, 0x20, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x20, - 0x73, 0x6c, 0x65, 0x65, 0x70, 0x20, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, - 0x20, 0x69, 0x6e, 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x0a, 0x43, 0x4c, 0x41, 0x53, 0x53, 0x20, 0x63, 0x6f, 0x6d, 0x2e, 0x72, - 0x65, 0x64, 0x68, 0x61, 0x74, 0x2e, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x6f, - 0x73, 0x74, 0x61, 0x74, 0x2e, 0x62, 0x79, 0x74, 0x65, 0x6d, 0x61, 0x6e, - 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x49, 0x6e, 0x66, 0x69, 0x6e, 0x69, - 0x74, 0x65, 0x4c, 0x6f, 0x6f, 0x70, 0x0a, 0x4d, 0x45, 0x54, 0x48, 0x4f, - 0x44, 0x20, 0x73, 0x6c, 0x65, 0x65, 0x70, 0x0a, 0x41, 0x54, 0x20, 0x45, - 0x4e, 0x54, 0x52, 0x59, 0x0a, 0x49, 0x46, 0x20, 0x74, 0x72, 0x75, 0x65, - 0x0a, 0x44, 0x4f, 0x0a, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, - 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x28, 0x22, 0x73, 0x6c, - 0x65, 0x65, 0x70, 0x2d, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x22, - 0x29, 0x0a, 0x45, 0x4e, 0x44, 0x52, 0x55, 0x4c, 0x45, 0x0a, 0x0a, 0x52, - 0x55, 0x4c, 0x45, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x73, 0x6c, 0x65, - 0x65, 0x70, 0x20, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x20, 0x69, 0x6e, - 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x74, 0x6f, - 0x20, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x6f, 0x73, 0x74, 0x61, 0x74, 0x0a, - 0x43, 0x4c, 0x41, 0x53, 0x53, 0x20, 0x63, 0x6f, 0x6d, 0x2e, 0x72, 0x65, - 0x64, 0x68, 0x61, 0x74, 0x2e, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x6f, 0x73, - 0x74, 0x61, 0x74, 0x2e, 0x62, 0x79, 0x74, 0x65, 0x6d, 0x61, 0x6e, 0x2e, - 0x74, 0x65, 0x73, 0x74, 0x2e, 0x49, 0x6e, 0x66, 0x69, 0x6e, 0x69, 0x74, - 0x65, 0x4c, 0x6f, 0x6f, 0x70, 0x0a, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, // slice B end - 0x20, 0x73, 0x6c, 0x65, 0x65, 0x70, 0x0a, 0x48, 0x45, 0x4c, 0x50, 0x45, - 0x52, 0x20, 0x6f, 0x72, 0x67, 0x2e, 0x6a, 0x62, 0x6f, 0x73, 0x73, 0x2e, - 0x62, 0x79, 0x74, 0x65, 0x6d, 0x61, 0x6e, 0x2e, 0x74, 0x68, 0x65, 0x72, - 0x6d, 0x6f, 0x73, 0x74, 0x61, 0x74, 0x2e, 0x68, 0x65, 0x6c, 0x70, 0x65, - 0x72, 0x2e, 0x54, 0x68, 0x65, 0x72, 0x6d, 0x6f, 0x73, 0x74, 0x61, 0x74, - 0x48, 0x65, 0x6c, 0x70, 0x65, 0x72, 0x0a, 0x41, 0x54, 0x20, 0x45, 0x4e, - 0x54, 0x52, 0x59, 0x0a, 0x42, 0x49, 0x4e, 0x44, 0x20, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x20, 0x69, - 0x6e, 0x74, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75, - 0x6e, 0x74, 0x65, 0x72, 0x28, 0x22, 0x73, 0x6c, 0x65, 0x65, 0x70, 0x2d, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x22, 0x29, 0x0a, 0x49, 0x46, - 0x20, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, - 0x65, 0x20, 0x25, 0x20, 0x31, 0x30, 0x20, 0x3d, 0x3d, 0x20, 0x30, 0x0a, - 0x44, 0x4f, 0x0a, 0x73, 0x65, 0x6e, 0x64, 0x28, 0x22, 0x63, 0x6f, 0x6d, - 0x2e, 0x72, 0x65, 0x64, 0x68, 0x61, 0x74, 0x2e, 0x74, 0x68, 0x65, 0x72, - 0x6d, 0x6f, 0x73, 0x74, 0x61, 0x74, 0x2e, 0x62, 0x79, 0x74, 0x65, 0x6d, - 0x61, 0x6e, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x49, 0x6e, 0x66, 0x69, - 0x6e, 0x69, 0x74, 0x65, 0x4c, 0x6f, 0x6f, 0x70, 0x22, 0x2c, 0x20, 0x20, - 0x22, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x20, 0x73, 0x6c, 0x65, 0x65, - 0x70, 0x28, 0x29, 0x20, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x2c, 0x20, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x29, 0x3b, 0x0a, 0x45, 0x4e, 0x44, 0x52, 0x55, 0x4c, 0x45, 0x0a, 0x00, - 0x00, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x58, 0x63, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x2d, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x4d, 0x64, 0x4a, 0x30, 0x38, - 0x6c, 0x51, 0x34, 0x2b, 0x34, 0x48, 0x39, 0x61, 0x73, 0x4f, 0x51, 0x61, - 0x59, 0x78, 0x56, 0x36, 0x58, 0x44, 0x58, 0x62, 0x49, 0x43, 0x69, 0x33, - 0x6e, 0x6a, 0x49, 0x37, 0x4a, 0x6d, 0x5a, 0x39, 0x57, 0x38, 0x57, 0x67, - 0x4e, 0x37, 0x4c, 0x57, 0x38, 0x52, 0x49, 0x59, 0x5a, 0x30, 0x61, 0x43, - 0x46, 0x70, 0x61, 0x48, 0x51, 0x49, 0x48, 0x73, 0x47, 0x33, 0x38, 0x6d, - 0x4f, 0x4c, 0x76, 0x5a, 0x52, 0x7a, 0x4c, 0x4e, 0x77, 0x49, 0x34, 0x35, - 0x4e, 0x47, 0x2f, 0x71, 0x6f, 0x78, 0x56, 0x75, 0x2b, 0x42, 0x41, 0x38, - 0x65, 0x6b, 0x45, 0x42, 0x70, 0x4c, 0x6c, 0x48, 0x43, 0x6f, 0x74, 0x78, - 0x4c, 0x6b, 0x2b, 0x31, 0x46, 0x37, 0x79, 0x5a, 0x6f, 0x6e, 0x6d, 0x6b, - 0x45, 0x66, 0x58, 0x71, 0x36, 0x6f, 0x34, 0x69, 0x6d, 0x73, 0x56, 0x55, - 0x2f, 0x38, 0x45, 0x55, 0x33, 0x36, 0x44, 0x68, 0x37, 0x59, 0x52, 0x64, - 0x35, 0x71, 0x4f, 0x6e, 0x65, 0x72, 0x4a, 0x37, 0x4e, 0x49, 0x74, 0x72, - 0x77, 0x2f, 0x6b, 0x42, 0x75, 0x56, 0x61, 0x41, 0x6c, 0x73, 0x56, 0x4c, - 0x32, 0x42, 0x62, 0x6a, 0x37, 0x72, 0x79, 0x76, 0x56, 0x56, 0x45, 0x30, - 0x31, 0x47, 0x67, 0x4d, 0x4a, 0x6c, 0x42, 0x4c, 0x51, 0x6a, 0x6e, 0x6a, - 0x62, 0x32, 0x31, 0x65, 0x4f, 0x32, 0x79, 0x67, 0x32, 0x77, 0x34, 0x41, - 0x4b, 0x44, 0x4f, 0x67, 0x67, 0x48, 0x4d, 0x77, 0x63, 0x43, 0x41, 0x61, - 0x5a, 0x6c, 0x31, 0x77, 0x57, 0x31, 0x70, 0x4b, 0x51, 0x4a, 0x41, 0x76, - 0x6c, 0x54, 0x30, 0x46, 0x59, 0x48, 0x72, 0x77, 0x53, 0x55, 0x4a, 0x51, - 0x35, 0x31, 0x4a, 0x72, 0x5a, 0x45, 0x55, 0x4a, 0x6a, 0x46, 0x78, 0x5a, - 0x33, 0x38, 0x78, 0x78, 0x59, 0x48, 0x41, 0x30, 0x48, 0x4d, 0x66, 0x66, - 0x55, 0x69, 0x44, 0x63, 0x7a, 0x71, 0x6b, 0x46, 0x6a, 0x30, 0x38, 0x77, - 0x35, 0x39, 0x47, 0x2f, 0x36, 0x35, 0x32, 0x4a, 0x59, 0x2f, 0x68, 0x57, - 0x70, 0x6f, 0x4d, 0x39, 0x75, 0x7a, 0x77, 0x5a, 0x50, 0x2b, 0x74, 0x56, - 0x34, 0x73, 0x43, 0x57, 0x58, 0x46, 0x46, 0x35, 0x49, 0x75, 0x42, 0x42, - 0x38, 0x50, 0x46, 0x77, 0x61, 0x65, 0x71, 0x67, 0x58, 0x44, 0x77, 0x72, - 0x62, 0x78, 0x67, 0x59, 0x4d, 0x6a, 0x43, 0x67, 0x6b, 0x39, 0x6e, 0x4e, - 0x5a, 0x75, 0x76, 0x64, 0x73, 0x64, 0x61, 0x56, 0x31, 0x62, 0x47, 0x52, - 0x51, 0x3d, 0x3d, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x05, 0x6c, - 0x69, 0x73, 0x74, 0x65, 0x6e, 0x2d, 0x70, 0x6f, 0x72, 0x74, 0x31, 0x33, - 0x33, 0x30, 0x30, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x46, 0x72, - 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x63, 0x6f, 0x6d, 0x2e, 0x72, - 0x65, 0x64, 0x68, 0x61, 0x74, 0x2e, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x6f, - 0x73, 0x74, 0x61, 0x74, 0x2e, 0x76, 0x6d, 0x2e, 0x62, 0x79, 0x74, 0x65, - 0x6d, 0x61, 0x6e, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x42, 0x79, 0x74, 0x65, 0x6d, - 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x63, - 0x65, 0x69, 0x76, 0x65, 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x24, 0x76, 0x6d, 0x2d, 0x69, 0x64, 0x66, 0x35, 0x62, 0x34, 0x63, 0x63, - 0x34, 0x34, 0x2d, 0x30, 0x36, 0x66, 0x32, 0x2d, 0x34, 0x38, 0x34, 0x37, - 0x2d, 0x39, 0x37, 0x64, 0x33, 0x2d, 0x62, 0x35, 0x62, 0x30, 0x62, 0x31, - 0x39, 0x38, 0x66, 0x38, 0x34, 0x33 // slice C end - }; - - private static final byte[] ENCODED_INCOMPLETE_REQUEST_WITH_MANY_PARAMS_A = new byte[] { - 0x00, 0x00, 0x00, 0x11, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45, - 0x5f, 0x45, 0x58, 0x50, 0x45, 0x43, 0x54, 0x45, 0x44, - 0x00, 0x00, 0x00, 0x08, // 8 parameters - }; - - private static final byte[] ENCODED_INCOMPLETE_REQUEST_WITH_MANY_PARAMS_B = new byte[] { - 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x15, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x2d, 0x6e, 0x61, 0x6d, 0x65, 0x76, 0x6d, 0x2d, 0x62, 0x79, - 0x74, 0x65, 0x6d, 0x61, 0x6e, 0x2d, 0x69, 0x6e, 0x73, 0x74, 0x72, 0x75, - 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x01, 0x58, - 0x61, 0x75, 0x74, 0x68, 0x2d, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2f, 0x55, - 0x46, 0x44, 0x76, 0x39, 0x50, 0x54, 0x33, 0x6e, 0x4c, 0x4d, 0x57, 0x31, - 0x6c, 0x45, 0x4a, 0x55, 0x79, 0x54, 0x78, 0x66, 0x49, 0x48, 0x66, 0x55, - 0x38, 0x62, 0x52, 0x78, 0x63, 0x41, 0x77, 0x34, 0x49, 0x64, 0x56, 0x59, - 0x4c, 0x37, 0x4a, 0x7a, 0x48, 0x52, 0x4f, 0x72, 0x75, 0x7a, 0x4e, 0x76, - 0x49, 0x70, 0x75, 0x76, 0x71, 0x72, 0x4c, 0x55, 0x4e, 0x30, 0x31, 0x66, - 0x30, 0x68, 0x47, 0x49, 0x47, 0x4d, 0x6d, 0x7a, 0x63, 0x35, 0x38, 0x69, - 0x79, 0x6c, 0x72, 0x62, 0x70, 0x67, 0x59, 0x31, 0x77, 0x6b, 0x55, 0x41, - 0x30, 0x34, 0x59, 0x4c, 0x35, 0x57, 0x4f, 0x46, 0x36, 0x36, 0x79, 0x73, - 0x66, 0x77, 0x4c, 0x57, 0x77, 0x44, 0x41, 0x38, 0x4d, 0x32, 0x52, 0x37, - 0x6b, 0x68, 0x72, 0x4b, 0x30, 0x78, 0x59, 0x36, 0x2b, 0x44, 0x4c, 0x53, - 0x41, 0x31, 0x6e, 0x4f, 0x55, 0x54, 0x2b, 0x69, 0x68, 0x6d, 0x76, 0x47, - 0x73, 0x72, 0x6c, 0x6b, 0x35, 0x31, 0x78, 0x35, 0x61, 0x71, 0x48, 0x37, - 0x56, 0x76, 0x71, 0x71, 0x6a, 0x2b, 0x54, 0x44, 0x79, 0x6a, 0x38, 0x5a, - 0x33, 0x47, 0x6c, 0x33, 0x64, 0x4d, 0x70, 0x36, 0x4b, 0x45, 0x6e, 0x67, - 0x74, 0x42, 0x78, 0x78, 0x68, 0x78, 0x4f, 0x2f, 0x70, 0x49, 0x39, 0x65, - 0x75, 0x51, 0x47, 0x55, 0x69, 0x77, 0x57, 0x47, 0x63, 0x59, 0x37, 0x43, - 0x64, 0x54, 0x41, 0x6f, 0x54, 0x53, 0x78, 0x32, 0x77, 0x68, 0x38, 0x62, - 0x4f, 0x73, 0x6d, 0x44, 0x55, 0x6c, 0x6c, 0x77, 0x4f, 0x45, 0x37, 0x39, - 0x37, 0x38, 0x5a, 0x68, 0x54, 0x52, 0x73, 0x53, 0x4e, 0x30, 0x62, 0x64, - 0x35, 0x37, 0x65, 0x79, 0x6e, 0x44, 0x61, 0x61, 0x65, 0x32, 0x33, 0x54, - 0x77, 0x49, 0x6e, 0x68, 0x65, 0x7a, 0x35, 0x69, 0x48, 0x4f, 0x78, 0x75, - 0x57, 0x6c, 0x42, 0x79, 0x6a, 0x45, 0x76, 0x34, 0x52, 0x79, 0x44, 0x50, - 0x53, 0x63, 0x30, 0x66, 0x41, 0x53, 0x6f, 0x4b, 0x77, 0x48, 0x37, 0x49, - 0x41, 0x6a, 0x37, 0x56, 0x59, 0x4d, 0x7a, 0x75, 0x6a, 0x37, 0x32, 0x2f, - 0x63, 0x39, 0x78, 0x4c, 0x4f, 0x41, 0x35, 0x34, 0x58, 0x75, 0x79, 0x72, - 0x75, 0x61, 0x4d, 0x64, 0x71, 0x69, 0x30, 0x7a, 0x6c, 0x41, 0x34, 0x76, - 0x2f, 0x61, 0x66, 0x37, 0x78, 0x4a, 0x39, 0x30, 0x58, 0x56, 0x4d, 0x57, - 0x64, 0x57, 0x39, 0x36, 0x45, 0x47, 0x42, 0x47, 0x6b, 0x49, 0x6c, 0x6f, - 0x33, 0x33, 0x66, 0x41, 0x3d, 0x3d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, - 0x00, 0x01, 0x62, 0x79, 0x74, 0x65, 0x6d, 0x61, 0x6e, 0x2d, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x30, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x02, - 0x1a, 0x62, 0x79, 0x74, 0x65, 0x6d, 0x61, 0x6e, 0x2d, 0x72, 0x75, 0x6c, - 0x65, 0x52, 0x55, 0x4c, 0x45, 0x20, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x20, - 0x73, 0x6c, 0x65, 0x65, 0x70, 0x20, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, - 0x20, 0x69, 0x6e, 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x0a, 0x43, 0x4c, 0x41, 0x53, 0x53, 0x20, 0x63, 0x6f, 0x6d, 0x2e, 0x72, - 0x65, 0x64, 0x68, 0x61, 0x74, 0x2e, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x6f, - 0x73, 0x74, 0x61, 0x74, 0x2e, 0x62, 0x79, 0x74, 0x65, 0x6d, 0x61, 0x6e, - 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x49, 0x6e, 0x66, 0x69, 0x6e, 0x69, - 0x74, 0x65, 0x4c, 0x6f, 0x6f, 0x70, 0x0a, 0x4d, 0x45, 0x54, 0x48, 0x4f, - 0x44, 0x20, 0x73, 0x6c, 0x65, 0x65, 0x70, 0x0a, 0x41, 0x54, 0x20, 0x45, - 0x4e, 0x54, 0x52, 0x59, 0x0a, 0x49, 0x46, 0x20, 0x74, 0x72, 0x75, 0x65, - 0x0a, 0x44, 0x4f, 0x0a, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, - 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x28, 0x22, 0x73, 0x6c, - 0x65, 0x65, 0x70, 0x2d, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x22, - 0x29, 0x0a, 0x45, 0x4e, 0x44, 0x52, 0x55, 0x4c, 0x45, 0x0a, 0x0a, 0x52, - 0x55, 0x4c, 0x45, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x73, 0x6c, 0x65, - 0x65, 0x70, 0x20, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x20, 0x69, 0x6e, - 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x74, 0x6f, - 0x20, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x6f, 0x73, 0x74, 0x61, 0x74, 0x0a, - 0x43, 0x4c, 0x41, 0x53, 0x53, 0x20, 0x63, 0x6f, 0x6d, 0x2e, 0x72, 0x65, - 0x64, 0x68, 0x61, 0x74, 0x2e, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x6f, 0x73, - 0x74, 0x61, 0x74, 0x2e, 0x62, 0x79, 0x74, 0x65, 0x6d, 0x61, 0x6e, 0x2e, - 0x74, 0x65, 0x73, 0x74, 0x2e, 0x49, 0x6e, 0x66, 0x69, 0x6e, 0x69, 0x74, - 0x65, 0x4c, 0x6f, 0x6f, 0x70, 0x0a, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, - }; - - private static final byte[] ENCODED_INCOMPLETE_REQUEST_WITH_MANY_PARAMS_C = new byte[] { - 0x20, 0x73, 0x6c, 0x65, 0x65, 0x70, 0x0a, 0x48, 0x45, 0x4c, 0x50, 0x45, - 0x52, 0x20, 0x6f, 0x72, 0x67, 0x2e, 0x6a, 0x62, 0x6f, 0x73, 0x73, 0x2e, - 0x62, 0x79, 0x74, 0x65, 0x6d, 0x61, 0x6e, 0x2e, 0x74, 0x68, 0x65, 0x72, - 0x6d, 0x6f, 0x73, 0x74, 0x61, 0x74, 0x2e, 0x68, 0x65, 0x6c, 0x70, 0x65, - 0x72, 0x2e, 0x54, 0x68, 0x65, 0x72, 0x6d, 0x6f, 0x73, 0x74, 0x61, 0x74, - 0x48, 0x65, 0x6c, 0x70, 0x65, 0x72, 0x0a, 0x41, 0x54, 0x20, 0x45, 0x4e, - 0x54, 0x52, 0x59, 0x0a, 0x42, 0x49, 0x4e, 0x44, 0x20, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x20, 0x69, - 0x6e, 0x74, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75, - 0x6e, 0x74, 0x65, 0x72, 0x28, 0x22, 0x73, 0x6c, 0x65, 0x65, 0x70, 0x2d, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x22, 0x29, 0x0a, 0x49, 0x46, - 0x20, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, - 0x65, 0x20, 0x25, 0x20, 0x31, 0x30, 0x20, 0x3d, 0x3d, 0x20, 0x30, 0x0a, - 0x44, 0x4f, 0x0a, 0x73, 0x65, 0x6e, 0x64, 0x28, 0x22, 0x63, 0x6f, 0x6d, - 0x2e, 0x72, 0x65, 0x64, 0x68, 0x61, 0x74, 0x2e, 0x74, 0x68, 0x65, 0x72, - 0x6d, 0x6f, 0x73, 0x74, 0x61, 0x74, 0x2e, 0x62, 0x79, 0x74, 0x65, 0x6d, - 0x61, 0x6e, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x49, 0x6e, 0x66, 0x69, - 0x6e, 0x69, 0x74, 0x65, 0x4c, 0x6f, 0x6f, 0x70, 0x22, 0x2c, 0x20, 0x20, - 0x22, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x20, 0x73, 0x6c, 0x65, 0x65, - 0x70, 0x28, 0x29, 0x20, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x2c, 0x20, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x29, 0x3b, 0x0a, 0x45, 0x4e, 0x44, 0x52, 0x55, 0x4c, 0x45, 0x0a, 0x00, - 0x00, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x58, 0x63, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x2d, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x4d, 0x64, 0x4a, 0x30, 0x38, - 0x6c, 0x51, 0x34, 0x2b, 0x34, 0x48, 0x39, 0x61, 0x73, 0x4f, 0x51, 0x61, - 0x59, 0x78, 0x56, 0x36, 0x58, 0x44, 0x58, 0x62, 0x49, 0x43, 0x69, 0x33, - 0x6e, 0x6a, 0x49, 0x37, 0x4a, 0x6d, 0x5a, 0x39, 0x57, 0x38, 0x57, 0x67, - 0x4e, 0x37, 0x4c, 0x57, 0x38, 0x52, 0x49, 0x59, 0x5a, 0x30, 0x61, 0x43, - 0x46, 0x70, 0x61, 0x48, 0x51, 0x49, 0x48, 0x73, 0x47, 0x33, 0x38, 0x6d, - 0x4f, 0x4c, 0x76, 0x5a, 0x52, 0x7a, 0x4c, 0x4e, 0x77, 0x49, 0x34, 0x35, - 0x4e, 0x47, 0x2f, 0x71, 0x6f, 0x78, 0x56, 0x75, 0x2b, 0x42, 0x41, 0x38, - 0x65, 0x6b, 0x45, 0x42, 0x70, 0x4c, 0x6c, 0x48, 0x43, 0x6f, 0x74, 0x78, - 0x4c, 0x6b, 0x2b, 0x31, 0x46, 0x37, 0x79, 0x5a, 0x6f, 0x6e, 0x6d, 0x6b, - 0x45, 0x66, 0x58, 0x71, 0x36, 0x6f, 0x34, 0x69, 0x6d, 0x73, 0x56, 0x55, - 0x2f, 0x38, 0x45, 0x55, 0x33, 0x36, 0x44, 0x68, 0x37, 0x59, 0x52, 0x64, - 0x35, 0x71, 0x4f, 0x6e, 0x65, 0x72, 0x4a, 0x37, 0x4e, 0x49, 0x74, 0x72, - 0x77, 0x2f, 0x6b, 0x42, 0x75, 0x56, 0x61, 0x41, 0x6c, 0x73, 0x56, 0x4c, - 0x32, 0x42, 0x62, 0x6a, 0x37, 0x72, 0x79, 0x76, 0x56, 0x56, 0x45, 0x30, - 0x31, 0x47, 0x67, 0x4d, 0x4a, 0x6c, 0x42, 0x4c, 0x51, 0x6a, 0x6e, 0x6a, - 0x62, 0x32, 0x31, 0x65, 0x4f, 0x32, 0x79, 0x67, 0x32, 0x77, 0x34, 0x41, - 0x4b, 0x44, 0x4f, 0x67, 0x67, 0x48, 0x4d, 0x77, 0x63, 0x43, 0x41, 0x61, - 0x5a, 0x6c, 0x31, 0x77, 0x57, 0x31, 0x70, 0x4b, 0x51, 0x4a, 0x41, 0x76, - 0x6c, 0x54, 0x30, 0x46, 0x59, 0x48, 0x72, 0x77, 0x53, 0x55, 0x4a, 0x51, - 0x35, 0x31, 0x4a, 0x72, 0x5a, 0x45, 0x55, 0x4a, 0x6a, 0x46, 0x78, 0x5a, - 0x33, 0x38, 0x78, 0x78, 0x59, 0x48, 0x41, 0x30, 0x48, 0x4d, 0x66, 0x66, - 0x55, 0x69, 0x44, 0x63, 0x7a, 0x71, 0x6b, 0x46, 0x6a, 0x30, 0x38, 0x77, - 0x35, 0x39, 0x47, 0x2f, 0x36, 0x35, 0x32, 0x4a, 0x59, 0x2f, 0x68, 0x57, - 0x70, 0x6f, 0x4d, 0x39, 0x75, 0x7a, 0x77, 0x5a, 0x50, 0x2b, 0x74, 0x56, - 0x34, 0x73, 0x43, 0x57, 0x58, 0x46, 0x46, 0x35, 0x49, 0x75, 0x42, 0x42, - 0x38, 0x50, 0x46, 0x77, 0x61, 0x65, 0x71, 0x67, 0x58, 0x44, 0x77, 0x72, - 0x62, 0x78, 0x67, 0x59, 0x4d, 0x6a, 0x43, 0x67, 0x6b, 0x39, 0x6e, 0x4e, - 0x5a, 0x75, 0x76, 0x64, 0x73, 0x64, 0x61, 0x56, 0x31, 0x62, 0x47, 0x52, - 0x51, 0x3d, 0x3d, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x05, 0x6c, - 0x69, 0x73, 0x74, 0x65, 0x6e, 0x2d, 0x70, 0x6f, 0x72, 0x74, 0x31, 0x33, - 0x33, 0x30, 0x30, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x46, 0x72, - 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x63, 0x6f, 0x6d, 0x2e, 0x72, - 0x65, 0x64, 0x68, 0x61, 0x74, 0x2e, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x6f, - 0x73, 0x74, 0x61, 0x74, 0x2e, 0x76, 0x6d, 0x2e, 0x62, 0x79, 0x74, 0x65, - 0x6d, 0x61, 0x6e, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x42, 0x79, 0x74, 0x65, 0x6d, - 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x63, - 0x65, 0x69, 0x76, 0x65, 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x24, 0x76, 0x6d, 0x2d, 0x69, 0x64, 0x66, 0x35, 0x62, 0x34, 0x63, 0x63, - 0x34, 0x34, 0x2d, 0x30, 0x36, 0x66, 0x32, 0x2d, 0x34, 0x38, 0x34, 0x37, - 0x2d, 0x39, 0x37, 0x64, 0x33, 0x2d, 0x62, 0x35, 0x62, 0x30, 0x62, 0x31, - 0x39, 0x38, 0x66, 0x38, 0x34, 0x33 - }; - - /* - * This is serialized format for - * req = new Request(RequestType.RESPONSE_EXPECTED, blah) - */ - private static final byte[] ENCODED_REQUEST_WITH_NO_PARAMS = new byte[] { - 0x00, 0x00, 0x00, 0x11, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45, - 0x5f, 0x45, 0x58, 0x50, 0x45, 0x43, 0x54, 0x45, 0x44, 0x00, 0x00, 0x00, - 0x00 - }; - - private static final byte[][] GARBAGE_AS_REQUEST = new byte[][] { - // general garbage - { 0x0d, 0x0b, 0x0e, 0x0e, 0x0f }, - // first two bytes are broken - { 0x0f, 0x0d, 0x00, 0x11, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, - 0x45, 0x5f, 0x45, 0x58, 0x50, 0x45, 0x43, 0x54, 0x45, 0x44, - 0x00, 0x00, 0x00, 0x00 }, - // last byte indicates params, which are missing - { 0x00, 0x00, 0x00, 0x11, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, - 0x45, 0x5f, 0x45, 0x58, 0x50, 0x45, 0x43, 0x54, 0x45, 0x44, - 0x00, 0x00, 0x00, 0x0f } }; - - - private static final byte[] TYPE = RequestType.RESPONSE_EXPECTED.toString().getBytes(); - - private ChannelHandlerContext ctx; - private CommandChannelRequestDecoder decoder; - - @Before - public void setUp() { - ctx = mock(ChannelHandlerContext.class); - when(ctx.channel()).thenReturn(mock(Channel.class)); - decoder = new CommandChannelRequestDecoder(); - } - - @Test - public void testDecode() throws Exception { - ByteBuf buffer = Unpooled.buffer(); - buffer.writeInt(TYPE.length); - buffer.writeBytes(TYPE); - buffer.writeInt(0); - - List<Object> resultList = new ArrayList<>(); - decoder.decode(ctx, buffer, resultList); - assertEquals(1, resultList.size()); - Request request = (Request)resultList.get(0); - assertTrue(RequestType.RESPONSE_EXPECTED == (RequestType) request.getType()); - } - - @Test - public void testDecodeWithParameters() throws Exception { - String parmName = "parameter"; - String parmValue = "hello"; - ByteBuf buffer = Unpooled.buffer(); - buffer.writeInt(TYPE.length); - buffer.writeBytes(TYPE); - buffer.writeInt(1); - buffer.writeInt(parmName.getBytes().length); - buffer.writeInt(parmValue.getBytes().length); - buffer.writeBytes(parmName.getBytes()); - buffer.writeBytes(parmValue.getBytes()); - - List<Object> resultList = new ArrayList<>(); - decoder.decode(ctx, buffer, resultList); - assertEquals(1, resultList.size()); - Request request = (Request) resultList.get(0); - Collection<String> parmNames = request.getParameterNames(); - - assertEquals(1, parmNames.size()); - assertTrue(parmNames.contains(parmName)); - String decodedValue = request.getParameter(parmName); - assertEquals(parmValue, decodedValue); - } - - @Test - public void testDecodeWithLongParams() throws Exception { - String parmName = "parameter"; - String param2Name = "foo-bar"; - String param2Value = "RESPONSE_EXPECTED"; - ByteBuf buffer = Unpooled.buffer(); - buffer.writeInt(TYPE.length); - buffer.writeBytes(TYPE); - buffer.writeInt(2); - buffer.writeInt(parmName.getBytes().length); - buffer.writeInt(LONG_PARAM_VALUE.getBytes().length); - buffer.writeBytes(parmName.getBytes()); - buffer.writeBytes(LONG_PARAM_VALUE.getBytes()); - buffer.writeInt(param2Name.getBytes().length); - buffer.writeInt(param2Value.getBytes().length); - buffer.writeBytes(param2Name.getBytes()); - buffer.writeBytes(param2Value.getBytes()); - - List<Object> resultList = new ArrayList<>(); - decoder.decode(ctx, buffer, resultList); - assertEquals(1, resultList.size()); - Request request = (Request) resultList.get(0); - Collection<String> parmNames = request.getParameterNames(); - - assertEquals(2, parmNames.size()); - assertTrue(parmNames.contains(parmName)); - String decodedValue = request.getParameter(parmName); - assertEquals(LONG_PARAM_VALUE, decodedValue); - } - - @Test - public void testDecodeWithParametersFromBytesArray() throws Exception { - ByteBuf buffer = Unpooled.copiedBuffer(ENCODED_REQUEST_WITH_PARAMS); - Request expected = new Request(RequestType.RESPONSE_EXPECTED, null); - expected.setParameter("param1", "value1"); - expected.setParameter("param2", "value2"); - List<Object> resultList = new ArrayList<>(); - new CommandChannelRequestDecoder().decode(ctx, buffer, resultList); - assertEquals(1, resultList.size()); - Message actual = (Message)resultList.get(0); - assertTrue(actual instanceof Request); - assertTrue(Messages.equal(expected, (Request)actual)); - InetSocketAddress addr = new InetSocketAddress(1234); - buffer = Unpooled.copiedBuffer(ENCODED_REQUEST_WITH_NO_PARAMS); - expected = new Request(RequestType.RESPONSE_EXPECTED, addr); - resultList = new ArrayList<>(); - new CommandChannelRequestDecoder().decode(ctx, buffer, resultList); - assertEquals(1, resultList.size()); - actual = (Message)resultList.get(0); - assertTrue(actual instanceof Request); - assertTrue(Messages.equal(expected, (Request)actual)); - } - - /** - * Tests the case where the decode() method is called multiple times due - * to some data not yet available so as to be able to decode the request in - * it's entirety. - * - * @throws Exception - */ - @Test - public void testDecodeWithParamsFromBytes() throws Exception { - CommandChannelRequestDecoder decoder = new CommandChannelRequestDecoder(); - - // First decode all-at-once - List<Object> allAtOnceResultList = new ArrayList<>(); - ByteBuf firstBuffer = Unpooled.copiedBuffer(ENCODED_REQUEST_WITH_MANY_PARAMS); - decoder.decode(ctx, firstBuffer, allAtOnceResultList); - assertEquals(1, allAtOnceResultList.size()); - Message firstActual = (Message)allAtOnceResultList.get(0); - assertTrue(firstActual instanceof Request); - Request firstRequest = (Request)firstActual; - - List<Object> resultList = new ArrayList<>(); - ByteBuf buffer = Unpooled.copiedBuffer(ENCODED_INCOMPLETE_REQUEST_WITH_MANY_PARAMS_A); - int bytesAvailable = ENCODED_INCOMPLETE_REQUEST_WITH_MANY_PARAMS_A.length; - assertEquals(bytesAvailable, buffer.readableBytes()); - decoder.decode(ctx, buffer, resultList); // request type got decoded - assertEquals(bytesAvailable, buffer.readableBytes()); - assertEquals(0, resultList.size()); - ByteBuf remaining = Unpooled.copiedBuffer(buffer); - assertEquals(bytesAvailable, remaining.array().length); - buffer = Unpooled.copiedBuffer(remaining.array(), ENCODED_INCOMPLETE_REQUEST_WITH_MANY_PARAMS_B); - bytesAvailable = remaining.array().length + ENCODED_INCOMPLETE_REQUEST_WITH_MANY_PARAMS_B.length; - assertEquals(bytesAvailable, buffer.readableBytes()); - decoder.decode(ctx, buffer, resultList); // nothing additional should get decoded - assertEquals(bytesAvailable, buffer.readableBytes()); - assertEquals(0, resultList.size()); - buffer = Unpooled.copiedBuffer(remaining.array(), - ENCODED_INCOMPLETE_REQUEST_WITH_MANY_PARAMS_B, - ENCODED_INCOMPLETE_REQUEST_WITH_MANY_PARAMS_C); - bytesAvailable = remaining.array().length + - ENCODED_INCOMPLETE_REQUEST_WITH_MANY_PARAMS_B.length + - ENCODED_INCOMPLETE_REQUEST_WITH_MANY_PARAMS_C.length; - assertEquals(bytesAvailable, buffer.readableBytes()); - decoder.decode(ctx, buffer, resultList); // this time decoding should complete - assertEquals(0, buffer.readableBytes()); - assertEquals(1, resultList.size()); - Message actual = (Message)resultList.get(0); - assertTrue(actual instanceof Request); - Request actualReq = (Request) actual; - assertEquals(RequestType.RESPONSE_EXPECTED, actualReq.getType()); - assertEquals("Expected 8 parameters", 8, actualReq.getParameterNames().size()); - assertEquals(Integer.toString(0), actualReq.getParameter("byteman-action")); - String rule = actualReq.getParameter("byteman-rule"); - assertNotNull(rule); - assertEquals(538, rule.length()); - assertTrue(Messages.equal(firstRequest, actualReq)); - } - - @Test - public void decodingOfGarbageDoesNotAddToResultList() - throws Exception { - for (int i = 0; i < GARBAGE_AS_REQUEST.length; i++) { - ByteBuf buffer = Unpooled - .copiedBuffer(GARBAGE_AS_REQUEST[0]); - CommandChannelRequestDecoder decoder = new CommandChannelRequestDecoder(); - List<Object> outList = new ArrayList<>(); - decoder.decode(ctx, buffer, outList); - assertEquals(0, outList.size()); - } - } -} -
--- a/agent/command-server/src/test/java/com/redhat/thermostat/agent/command/server/internal/CommandChannelServerContextTest.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,150 +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.agent.command.server.internal; - -import static org.junit.Assert.assertNotNull; -import static org.mockito.Matchers.eq; -import static org.mockito.Matchers.isA; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLSession; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.InOrder; -import org.mockito.Mockito; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; - -import com.redhat.thermostat.agent.command.server.internal.CommandChannelServerContext.ServerChannelInitializer; -import com.redhat.thermostat.agent.command.server.internal.CommandChannelServerContext.ServerChannelPipelineInitializerCreator; -import com.redhat.thermostat.agent.ipc.client.IPCMessageChannel; -import com.redhat.thermostat.common.ssl.SSLContextFactory; -import com.redhat.thermostat.shared.config.SSLConfiguration; - -import io.netty.bootstrap.AbstractBootstrap; -import io.netty.channel.ChannelPipeline; -import io.netty.channel.socket.SocketChannel; -import io.netty.handler.ssl.SslHandler; - -@RunWith(PowerMockRunner.class) -@PrepareForTest({ SSLContextFactory.class, - SSLEngine.class, SSLContext.class }) -public class CommandChannelServerContextTest { - - private CommandChannelServerContext ctx; - private SSLConfiguration mockSSLConf; - private TestServerChannelPipelineInitializerCreator creator; - - @Before - public void setUp() { - creator = new TestServerChannelPipelineInitializerCreator(); - mockSSLConf = mock(SSLConfiguration.class); - when(mockSSLConf.enableForCmdChannel()).thenReturn(false); - IPCMessageChannel agentChannel = mock(IPCMessageChannel.class); - ctx = new CommandChannelServerContext(mockSSLConf, agentChannel, creator); - } - - @Test - public void testBootstrap() throws Exception { - AbstractBootstrap<?, ?> bootstrap = ctx.getBootstrap(); - assertNotNull(bootstrap); - SocketChannel channel = mock(SocketChannel.class); - ChannelPipeline mockPipeline = mock(ChannelPipeline.class); - when(channel.pipeline()).thenReturn(mockPipeline); - creator.initializer.initChannel(channel); - InOrder inOrder = Mockito.inOrder(mockPipeline); - inOrder.verify(mockPipeline).addLast(eq("decoder"), isA(CommandChannelRequestDecoder.class)); - inOrder.verify(mockPipeline).addLast(eq("encoder"), isA(ResponseEncoder.class)); - inOrder.verify(mockPipeline).addLast(eq("handler"), isA(ServerHandler.class)); - } - - @Test - public void testBootstrapSSL() throws Exception { - when(mockSSLConf.enableForCmdChannel()).thenReturn(true); - PowerMockito.mockStatic(SSLContextFactory.class); - // SSL classes need to be mocked with PowerMockito - SSLContext context = PowerMockito.mock(SSLContext.class); - when(SSLContextFactory.getServerContext(isA(SSLConfiguration.class))).thenReturn(context); - SSLEngine engine = PowerMockito.mock(SSLEngine.class); - when(context.createSSLEngine()).thenReturn(engine); - when(engine.getSession()).thenReturn(mock(SSLSession.class)); - - AbstractBootstrap<?, ?> bootstrap = ctx.getBootstrap(); - assertNotNull(bootstrap); - SocketChannel channel = mock(SocketChannel.class); - ChannelPipeline mockPipeline = mock(ChannelPipeline.class); - when(channel.pipeline()).thenReturn(mockPipeline); - creator.initializer.initChannel(channel); - InOrder inOrder = Mockito.inOrder(mockPipeline); - inOrder.verify(mockPipeline).addLast(eq("ssl"), isA(SslHandler.class)); - inOrder.verify(mockPipeline).addLast(eq("decoder"), isA(CommandChannelRequestDecoder.class)); - inOrder.verify(mockPipeline).addLast(eq("encoder"), isA(ResponseEncoder.class)); - inOrder.verify(mockPipeline).addLast(eq("handler"), isA(ServerHandler.class)); - Mockito.verify(engine).setUseClientMode(false); - } - - static class TestServerChannelPipelineInitializerCreator extends ServerChannelPipelineInitializerCreator { - - TestServerPipelineInitializer initializer; - - @Override - ServerChannelInitializer createInitializer(SSLConfiguration sslConf, IPCMessageChannel agentChannel) { - initializer = new TestServerPipelineInitializer(sslConf, agentChannel); - return initializer; - } - } - - static class TestServerPipelineInitializer extends ServerChannelInitializer { - - - TestServerPipelineInitializer(SSLConfiguration config, IPCMessageChannel agentChannel) { - super(config, agentChannel); - } - - SocketChannel getInitializedChannel(SocketChannel ch) throws Exception { - super.initChannel(ch); - return ch; - } - } -} -
--- a/agent/command-server/src/test/java/com/redhat/thermostat/agent/command/server/internal/CommandChannelServerImplTest.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,111 +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.agent.command.server.internal; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.io.IOException; -import java.net.InetSocketAddress; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; - -import io.netty.bootstrap.AbstractBootstrap; -import io.netty.bootstrap.ServerBootstrap; -import io.netty.channel.ChannelFuture; -import io.netty.channel.EventLoopGroup; - -public class CommandChannelServerImplTest { - - private CommandChannelServerContext ctx; - private ServerBootstrap bootstrap; - private EventLoopGroup group; - - @SuppressWarnings({ "rawtypes", "unchecked" }) - @Before - public void setUp() { - bootstrap = mock(ServerBootstrap.class); - when(bootstrap.bind(any(InetSocketAddress.class))).thenReturn(mock(ChannelFuture.class)); - group = mock(EventLoopGroup.class); - when(bootstrap.group()).thenReturn(group); - ctx = mock(CommandChannelServerContext.class); - when(ctx.getBootstrap()).thenReturn((AbstractBootstrap) bootstrap); - } - - @Test - public void testStartListening() throws IOException { - CommandChannelServerImpl server = new CommandChannelServerImpl(ctx); - server.startListening("127.0.0.1", 123); - - ArgumentCaptor<InetSocketAddress> argument = ArgumentCaptor.forClass(InetSocketAddress.class); - verify(bootstrap).bind(argument.capture()); - - InetSocketAddress addr = new InetSocketAddress("127.0.0.1", 123); - assertEquals(addr, argument.getValue()); - } - - @SuppressWarnings("unchecked") - @Test - public void startListeningFailureThrowsException() { - CommandChannelServerImpl server = new CommandChannelServerImpl(ctx); - - when(bootstrap.bind(any(InetSocketAddress.class))).thenThrow(IOException.class); - - try { - server.startListening("does-not-resolve.example.com", 123); - fail("Should have thrown exception"); - } catch (IOException e) { - // pass - } - } - - @Test - public void testStopListening() { - CommandChannelServerImpl server = new CommandChannelServerImpl(ctx); - server.stopListening(); - - verify(group).shutdownGracefully(); - } - -} -
--- a/agent/command-server/src/test/java/com/redhat/thermostat/agent/command/server/internal/CommandChannelServerMainTest.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,212 +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.agent.command.server.internal; - -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.io.IOException; -import java.nio.ByteBuffer; - -import com.redhat.thermostat.shared.config.OS; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; - -import com.redhat.thermostat.agent.command.server.internal.CommandChannelServerMain.ServerCreator; -import com.redhat.thermostat.agent.command.server.internal.CommandChannelServerMain.ShutdownHookHandler; -import com.redhat.thermostat.agent.command.server.internal.CommandChannelServerMain.Sleeper; -import com.redhat.thermostat.agent.ipc.client.ClientIPCService; -import com.redhat.thermostat.agent.ipc.client.IPCMessageChannel; -import com.redhat.thermostat.shared.config.SSLConfiguration; - -public class CommandChannelServerMainTest { - - private static final String IGNORED_ROOT = "/"; - private CommandChannelServerImpl server; - private ClientIPCService ipcService; - private IPCMessageChannel agentChannel; - private SSLConfigurationParser parser; - private ShutdownHookHandler shutdownHandler; - private Sleeper sleeper; - - @Before - public void setUpOnce() throws IOException { - System.setProperty(CommandChannelServerMain.CONFIG_FILE_PROP, "/path/to/ipc/config"); - ipcService = mock(ClientIPCService.class); - agentChannel = mock(IPCMessageChannel.class); - when(ipcService.connectToServer(CommandChannelServerMain.IPC_SERVER_NAME)).thenReturn(agentChannel); - - SSLConfiguration config = mock(SSLConfiguration.class); - parser = mock(SSLConfigurationParser.class); - when(parser.parseSSLConfiguration(agentChannel)).thenReturn(config); - - server = mock(CommandChannelServerImpl.class); - ServerCreator creator = mock(ServerCreator.class); - when(creator.createServer(config, agentChannel)).thenReturn(server); - - shutdownHandler = mock(ShutdownHookHandler.class); - sleeper = mock(Sleeper.class); - - if (OS.IS_WINDOWS) { - // Command Channel now uses a native DLL for Windows named pipes on Windows - // because of this, CommonPathsImpl tries to initialize. - System.setProperty("THERMOSTAT_HOME", IGNORED_ROOT); - System.setProperty("USER_THERMOSTAT_HOME", IGNORED_ROOT); - } - - CommandChannelServerMain.setIPCService(ipcService); - CommandChannelServerMain.setSSLConfigurationParser(parser); - CommandChannelServerMain.setServerCreator(creator); - CommandChannelServerMain.setShutdownHookHandler(shutdownHandler); - CommandChannelServerMain.setSleeper(sleeper); - } - - @After - public void tearDownOnce() { - System.clearProperty("THERMOSTAT_HOME"); - System.clearProperty("USER_THERMOSTAT_HOME"); - System.clearProperty(CommandChannelServerMain.CONFIG_FILE_PROP); - CommandChannelServerMain.setIPCService(null); - CommandChannelServerMain.setSSLConfigurationParser(new SSLConfigurationParser()); - CommandChannelServerMain.setServerCreator(new ServerCreator()); - CommandChannelServerMain.setShutdownHookHandler(new ShutdownHookHandler()); - CommandChannelServerMain.setSleeper(new Sleeper()); - } - - @Test - public void testNotEnoughArgs() throws IOException { - try { - CommandChannelServerMain.main(new String[] { "hello" }); - fail("Expected IOException"); - } catch (IOException e) { - verify(server, never()).startListening(any(String.class), anyInt()); - verify(sleeper, never()).sleepWait(); - } - } - - @Test - public void testBadPort() throws IOException { - try { - CommandChannelServerMain.main(new String[] { "hello", "world" }); - fail("Expected IOException"); - } catch (IOException e) { - verify(server, never()).startListening(any(String.class), anyInt()); - verify(sleeper, never()).sleepWait(); - } - } - - @Test - public void testSSLConfigParseFailed() throws IOException { - when(parser.parseSSLConfiguration(agentChannel)).thenThrow(new IOException("TEST")); - try { - CommandChannelServerMain.main(new String[] { "hello", "123" }); - fail("Expected IOException"); - } catch (IOException e) { - verify(server, never()).startListening(any(String.class), anyInt()); - verify(sleeper, never()).sleepWait(); - } - } - - @Test - public void testStartListeningFailed() throws IOException { - doThrow(new IOException("TEST")).when(server).startListening(any(String.class), anyInt()); - try { - CommandChannelServerMain.main(new String[] { "hello", "123" }); - fail("Expected IOException"); - } catch (IOException e) { - verify(shutdownHandler, never()).addShutdownHook(any(Thread.class)); - verify(sleeper, never()).sleepWait(); - verify(server).stopListening(); - } - } - - @Test - public void testStartedMessageException() throws IOException { - doThrow(new IOException("TEST")).when(agentChannel).writeMessage(any(ByteBuffer.class)); - try { - CommandChannelServerMain.main(new String[] { "hello", "123" }); - fail("Expected IOException"); - } catch (IOException e) { - verify(shutdownHandler, never()).addShutdownHook(any(Thread.class)); - verify(sleeper, never()).sleepWait(); - } - } - - @Test - public void testReadyMessageException() throws IOException { - doNothing().doThrow(new IOException("TEST")).when(agentChannel).writeMessage(any(ByteBuffer.class)); - try { - CommandChannelServerMain.main(new String[] { "hello", "123" }); - fail("Expected IOException"); - } catch (IOException e) { - verify(shutdownHandler, never()).addShutdownHook(any(Thread.class)); - verify(sleeper, never()).sleepWait(); - } - } - - @Test - public void testSuccess() throws IOException { - CommandChannelServerMain.main(new String[] { "hello", "123" }); - - verify(server).startListening("hello", 123); - verify(sleeper).sleepWait(); - } - - @Test - public void testShutdownHook() throws IOException, InterruptedException { - CommandChannelServerMain.main(new String[] { "hello", "123" }); - - ArgumentCaptor<Thread> hookCaptor = ArgumentCaptor.forClass(Thread.class); - verify(shutdownHandler).addShutdownHook(hookCaptor.capture()); - Thread hook = hookCaptor.getValue(); - - hook.start(); - hook.join(); - - verify(server).stopListening(); - } - -}
--- a/agent/command-server/src/test/java/com/redhat/thermostat/agent/command/server/internal/JsonResponseParserTest.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,188 +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.agent.command.server.internal; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.charset.Charset; - -import org.junit.Before; -import org.junit.Test; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.redhat.thermostat.agent.ipc.client.IPCMessageChannel; -import com.redhat.thermostat.common.command.Response; -import com.redhat.thermostat.common.command.Response.ResponseType; - -public class JsonResponseParserTest { - - private IPCMessageChannel agentChannel; - private JsonResponseParser parser; - - @Before - public void setUp() { - agentChannel = mock(IPCMessageChannel.class); - parser = new JsonResponseParser(); - } - - @Test - public void testSuccess() throws IOException { - JsonObject jsonResponse = createResponse(); - byte[] encoded = toJson(jsonResponse); - mockByteChannel(encoded); - - Response response = parser.parseResponse(agentChannel); - assertEquals(ResponseType.OK, response.getType()); - } - - @Test(expected=IOException.class) - public void testEmpty() throws IOException { - mockByteChannel(new byte[0]); - parser.parseResponse(agentChannel); - } - - @Test(expected=IOException.class) - public void testNotJson() throws IOException { - mockByteChannel("Not JSON".getBytes(Charset.forName("UTF-8"))); - parser.parseResponse(agentChannel); - } - - @Test(expected=IOException.class) - public void testBadResponseRoot() throws IOException { - byte[] encoded = toJson(new JsonArray()); - mockByteChannel(encoded); - parser.parseResponse(agentChannel); - } - - @Test(expected=IOException.class) - public void testParamsMissing() throws IOException { - byte[] encoded = toJson(new JsonObject()); - mockByteChannel(encoded); - parser.parseResponse(agentChannel); - } - - @Test(expected=IOException.class) - public void testBadParams() throws IOException { - JsonObject jsonResponse = createResponse(); - jsonResponse.add(CommandChannelConstants.RESPONSE_JSON_TOP, new JsonArray()); - - byte[] encoded = toJson(new JsonObject()); - mockByteChannel(encoded); - parser.parseResponse(agentChannel); - } - - @Test(expected=IOException.class) - public void testNullParams() throws IOException { - JsonObject jsonResponse = createResponse(); - jsonResponse.add(CommandChannelConstants.RESPONSE_JSON_TOP, null); - - byte[] encoded = toJson(new JsonObject()); - mockByteChannel(encoded); - parser.parseResponse(agentChannel); - } - - @Test(expected=IOException.class) - public void testResponseTypeMissing() throws IOException { - JsonObject root = createResponse(); - JsonObject jsonResponse = root.get(CommandChannelConstants.RESPONSE_JSON_TOP).getAsJsonObject(); - jsonResponse.remove(CommandChannelConstants.RESPONSE_JSON_TYPE); - - byte[] encoded = toJson(root); - mockByteChannel(encoded); - parser.parseResponse(agentChannel); - } - - @Test(expected=IOException.class) - public void testResponseTypeNotString() throws IOException { - JsonObject root = createResponse(); - JsonObject jsonResponse = root.get(CommandChannelConstants.RESPONSE_JSON_TOP).getAsJsonObject(); - jsonResponse.add(CommandChannelConstants.RESPONSE_JSON_TYPE, new JsonArray()); - - byte[] encoded = toJson(root); - mockByteChannel(encoded); - parser.parseResponse(agentChannel); - } - - @Test(expected=IOException.class) - public void testResponseTypeNull() throws IOException { - JsonObject root = createResponse(); - JsonObject jsonResponse = root.get(CommandChannelConstants.RESPONSE_JSON_TOP).getAsJsonObject(); - jsonResponse.addProperty(CommandChannelConstants.RESPONSE_JSON_TYPE, (String) null); - - byte[] encoded = toJson(root); - mockByteChannel(encoded); - parser.parseResponse(agentChannel); - } - - @Test(expected=IOException.class) - public void testResponseTypeNotEnum() throws IOException { - JsonObject root = createResponse(); - JsonObject jsonResponse = root.get(CommandChannelConstants.RESPONSE_JSON_TOP).getAsJsonObject(); - jsonResponse.addProperty(CommandChannelConstants.RESPONSE_JSON_TYPE, "Not a ResponseType"); - - byte[] encoded = toJson(root); - mockByteChannel(encoded); - parser.parseResponse(agentChannel); - } - - private JsonObject createResponse() { - JsonObject params = new JsonObject(); - params.addProperty(CommandChannelConstants.RESPONSE_JSON_TYPE, ResponseType.OK.name()); - JsonObject root = new JsonObject(); - root.add(CommandChannelConstants.RESPONSE_JSON_TOP, params); - return root; - } - - private byte[] toJson(JsonElement element) { - Gson gson = new GsonBuilder().serializeNulls().create(); - String jsonString = gson.toJson(element); - return jsonString.getBytes(Charset.forName("UTF-8")); - } - - private void mockByteChannel(final byte[] encoded) throws IOException { - when(agentChannel.readMessage()).thenReturn(ByteBuffer.wrap(encoded)); - } - -}
--- a/agent/command-server/src/test/java/com/redhat/thermostat/agent/command/server/internal/ResponseEncoderTest.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,80 +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.agent.command.server.internal; - -import static org.junit.Assert.assertEquals; - -import java.nio.charset.Charset; - -import org.junit.Test; - -import com.redhat.thermostat.agent.command.server.internal.ResponseEncoder; -import com.redhat.thermostat.common.command.Response; -import com.redhat.thermostat.common.command.Response.ResponseType; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.buffer.Unpooled; - -public class ResponseEncoderTest { - - private static final boolean DEBUG = false; - - @Test - public void testEncode() throws Exception { - ResponseEncoder encoder = new ResponseEncoder(); - String responseExp = "OK"; - ByteBuf stringBuf = Unpooled.copiedBuffer(responseExp, Charset.defaultCharset()); - ByteBuf buf = Unpooled.buffer(4); - buf.writeInt(responseExp.getBytes().length); - ByteBuf expected = Unpooled.wrappedBuffer(buf, stringBuf); - Response ok = new Response(ResponseType.OK); - ByteBuf actual = (ByteBuf)encoder.encode(ok); - if (DEBUG) { - printBuffers(actual, expected); - } - assertEquals(0, ByteBufUtil.compare(expected, actual)); - } - - private void printBuffers(ByteBuf actual, ByteBuf expected) { - System.out.println("hexdump expected\n-------------------------------------"); - System.out.println(ByteBufUtil.hexDump(expected)); - System.out.println("\nhexdump actual\n-------------------------------------"); - System.out.println(ByteBufUtil.hexDump(actual) + "\n\n"); - } -} -
--- a/agent/command-server/src/test/java/com/redhat/thermostat/agent/command/server/internal/SSLConfigurationParserTest.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,330 +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.agent.command.server.internal; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.io.File; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.charset.Charset; - -import org.junit.Before; -import org.junit.Test; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.redhat.thermostat.agent.ipc.client.IPCMessageChannel; -import com.redhat.thermostat.shared.config.SSLConfiguration; - -public class SSLConfigurationParserTest { - - private SSLConfigurationParser parser; - private IPCMessageChannel agentChannel; - - @Before - public void setUp() throws Exception { - parser = new SSLConfigurationParser(); - agentChannel = mock(IPCMessageChannel.class); - } - - @Test - public void testSuccess() throws Exception { - JsonObject root = createConfig(); - byte[] encoded = toJson(root); - mockByteChannel(encoded); - - SSLConfiguration config = parser.parseSSLConfiguration(agentChannel); - assertEquals(new File("/path/to/keystore").getAbsolutePath(), config.getKeystoreFile().getAbsolutePath()); - assertEquals("My Keystore Password", config.getKeyStorePassword()); - assertEquals(true, config.enableForCmdChannel()); - assertEquals(true, config.enableForBackingStorage()); - assertEquals(false, config.disableHostnameVerification()); - } - - @Test - public void testSuccessNoKeystore() throws IOException { - JsonObject root = createConfig(); - JsonObject params = root.get(CommandChannelConstants.SSL_JSON_ROOT).getAsJsonObject(); - params.addProperty(CommandChannelConstants.SSL_JSON_KEYSTORE_FILE, (String) null); - - byte[] encoded = toJson(root); - mockByteChannel(encoded); - - SSLConfiguration config = parser.parseSSLConfiguration(agentChannel); - assertNull(config.getKeystoreFile()); - assertEquals("My Keystore Password", config.getKeyStorePassword()); - assertEquals(true, config.enableForCmdChannel()); - assertEquals(true, config.enableForBackingStorage()); - assertEquals(false, config.disableHostnameVerification()); - } - - @Test - public void testSuccessNoKeystorePass() throws IOException { - JsonObject root = createConfig(); - JsonObject params = root.get(CommandChannelConstants.SSL_JSON_ROOT).getAsJsonObject(); - params.addProperty(CommandChannelConstants.SSL_JSON_KEYSTORE_PASS, (String) null); - - byte[] encoded = toJson(root); - mockByteChannel(encoded); - - SSLConfiguration config = parser.parseSSLConfiguration(agentChannel); - assertEquals(new File("/path/to/keystore").getAbsolutePath(), config.getKeystoreFile().getAbsolutePath()); - assertNull(config.getKeyStorePassword()); - assertEquals(true, config.enableForCmdChannel()); - assertEquals(true, config.enableForBackingStorage()); - assertEquals(false, config.disableHostnameVerification()); - } - - @Test(expected=IOException.class) - public void testConfigMissing() throws IOException { - mockByteChannel(new byte[0]); - parser.parseSSLConfiguration(agentChannel); - } - - @Test(expected=IOException.class) - public void testBadConfigNotJson() throws IOException { - mockByteChannel("Not JSON".getBytes(Charset.forName("UTF-8"))); - parser.parseSSLConfiguration(agentChannel); - } - - @Test(expected=IOException.class) - public void testBadConfigRoot() throws IOException { - byte[] encoded = toJson(new JsonArray()); - mockByteChannel(encoded); - parser.parseSSLConfiguration(agentChannel); - } - - @Test(expected=IOException.class) - public void testParamsMissing() throws IOException { - byte[] encoded = toJson(new JsonObject()); - mockByteChannel(encoded); - parser.parseSSLConfiguration(agentChannel); - } - - @Test(expected=IOException.class) - public void testBadParams() throws IOException { - JsonObject root = createConfig(); - root.add(CommandChannelConstants.SSL_JSON_ROOT, new JsonArray()); - - byte[] encoded = toJson(root); - mockByteChannel(encoded); - parser.parseSSLConfiguration(agentChannel); - } - - @Test(expected=IOException.class) - public void testNullParams() throws IOException { - JsonObject root = createConfig(); - root.add(CommandChannelConstants.SSL_JSON_ROOT, null); - - byte[] encoded = toJson(root); - mockByteChannel(encoded); - parser.parseSSLConfiguration(agentChannel); - } - - @Test(expected=IOException.class) - public void testKeystoreFileMissing() throws IOException { - JsonObject root = createConfig(); - JsonObject params = root.get(CommandChannelConstants.SSL_JSON_ROOT).getAsJsonObject(); - params.remove(CommandChannelConstants.SSL_JSON_KEYSTORE_FILE); - - byte[] encoded = toJson(root); - mockByteChannel(encoded); - parser.parseSSLConfiguration(agentChannel); - } - - @Test(expected=IOException.class) - public void testKeystoreFileBad() throws IOException { - JsonObject root = createConfig(); - JsonObject params = root.get(CommandChannelConstants.SSL_JSON_ROOT).getAsJsonObject(); - params.add(CommandChannelConstants.SSL_JSON_KEYSTORE_FILE, new JsonArray()); - - byte[] encoded = toJson(root); - mockByteChannel(encoded); - parser.parseSSLConfiguration(agentChannel); - } - - @Test(expected=IOException.class) - public void testKeystorePassMissing() throws IOException { - JsonObject root = createConfig(); - JsonObject params = root.get(CommandChannelConstants.SSL_JSON_ROOT).getAsJsonObject(); - params.remove(CommandChannelConstants.SSL_JSON_KEYSTORE_PASS); - - byte[] encoded = toJson(root); - mockByteChannel(encoded); - parser.parseSSLConfiguration(agentChannel); - } - - @Test(expected=IOException.class) - public void testKeystorePassBad() throws IOException { - JsonObject root = createConfig(); - JsonObject params = root.get(CommandChannelConstants.SSL_JSON_ROOT).getAsJsonObject(); - params.add(CommandChannelConstants.SSL_JSON_KEYSTORE_PASS, new JsonArray()); - - byte[] encoded = toJson(root); - mockByteChannel(encoded); - parser.parseSSLConfiguration(agentChannel); - } - - @Test(expected=IOException.class) - public void testCmdChannelMissing() throws IOException { - JsonObject root = createConfig(); - JsonObject params = root.get(CommandChannelConstants.SSL_JSON_ROOT).getAsJsonObject(); - params.remove(CommandChannelConstants.SSL_JSON_COMMAND_CHANNEL); - - byte[] encoded = toJson(root); - mockByteChannel(encoded); - parser.parseSSLConfiguration(agentChannel); - } - - @Test(expected=IOException.class) - public void testCmdChannelBad() throws IOException { - JsonObject root = createConfig(); - JsonObject params = root.get(CommandChannelConstants.SSL_JSON_ROOT).getAsJsonObject(); - params.add(CommandChannelConstants.SSL_JSON_COMMAND_CHANNEL, new JsonArray()); - - byte[] encoded = toJson(root); - mockByteChannel(encoded); - parser.parseSSLConfiguration(agentChannel); - } - - @Test(expected=IOException.class) - public void testCmdChannelNull() throws IOException { - JsonObject root = createConfig(); - JsonObject params = root.get(CommandChannelConstants.SSL_JSON_ROOT).getAsJsonObject(); - params.addProperty(CommandChannelConstants.SSL_JSON_COMMAND_CHANNEL, (String) null); - - byte[] encoded = toJson(root); - mockByteChannel(encoded); - parser.parseSSLConfiguration(agentChannel); - } - - @Test(expected=IOException.class) - public void testBackingStorageMissing() throws IOException { - JsonObject root = createConfig(); - JsonObject params = root.get(CommandChannelConstants.SSL_JSON_ROOT).getAsJsonObject(); - params.remove(CommandChannelConstants.SSL_JSON_BACKING_STORAGE); - - byte[] encoded = toJson(root); - mockByteChannel(encoded); - parser.parseSSLConfiguration(agentChannel); - } - - @Test(expected=IOException.class) - public void testBackingStorageBad() throws IOException { - JsonObject root = createConfig(); - JsonObject params = root.get(CommandChannelConstants.SSL_JSON_ROOT).getAsJsonObject(); - params.add(CommandChannelConstants.SSL_JSON_BACKING_STORAGE, new JsonArray()); - - byte[] encoded = toJson(root); - mockByteChannel(encoded); - parser.parseSSLConfiguration(agentChannel); - } - - @Test(expected=IOException.class) - public void testBackingStorageNull() throws IOException { - JsonObject root = createConfig(); - JsonObject params = root.get(CommandChannelConstants.SSL_JSON_ROOT).getAsJsonObject(); - params.addProperty(CommandChannelConstants.SSL_JSON_BACKING_STORAGE, (String) null); - - byte[] encoded = toJson(root); - mockByteChannel(encoded); - parser.parseSSLConfiguration(agentChannel); - } - - @Test(expected=IOException.class) - public void testHostnameVerifyMissing() throws IOException { - JsonObject root = createConfig(); - JsonObject params = root.get(CommandChannelConstants.SSL_JSON_ROOT).getAsJsonObject(); - params.remove(CommandChannelConstants.SSL_JSON_HOSTNAME_VERIFICATION); - - byte[] encoded = toJson(root); - mockByteChannel(encoded); - parser.parseSSLConfiguration(agentChannel); - } - - @Test(expected=IOException.class) - public void testHostnameVerifyBad() throws IOException { - JsonObject root = createConfig(); - JsonObject params = root.get(CommandChannelConstants.SSL_JSON_ROOT).getAsJsonObject(); - params.add(CommandChannelConstants.SSL_JSON_HOSTNAME_VERIFICATION, new JsonArray()); - - byte[] encoded = toJson(root); - mockByteChannel(encoded); - parser.parseSSLConfiguration(agentChannel); - } - - @Test(expected=IOException.class) - public void testHostnameVerifyNull() throws IOException { - JsonObject root = createConfig(); - JsonObject params = root.get(CommandChannelConstants.SSL_JSON_ROOT).getAsJsonObject(); - params.addProperty(CommandChannelConstants.SSL_JSON_HOSTNAME_VERIFICATION, (String) null); - - byte[] encoded = toJson(root); - mockByteChannel(encoded); - parser.parseSSLConfiguration(agentChannel); - } - - private JsonObject createConfig() { - JsonObject params = new JsonObject(); - params.addProperty(CommandChannelConstants.SSL_JSON_KEYSTORE_FILE, "/path/to/keystore"); - params.addProperty(CommandChannelConstants.SSL_JSON_KEYSTORE_PASS, "My Keystore Password"); - params.addProperty(CommandChannelConstants.SSL_JSON_COMMAND_CHANNEL, true); - params.addProperty(CommandChannelConstants.SSL_JSON_BACKING_STORAGE, true); - params.addProperty(CommandChannelConstants.SSL_JSON_HOSTNAME_VERIFICATION, false); - - JsonObject root = new JsonObject(); - root.add(CommandChannelConstants.SSL_JSON_ROOT, params); - return root; - } - - private byte[] toJson(JsonElement element) { - Gson gson = new GsonBuilder().serializeNulls().create(); - String jsonString = gson.toJson(element); - return jsonString.getBytes(Charset.forName("UTF-8")); - } - - private void mockByteChannel(final byte[] encoded) throws IOException { - when(agentChannel.readMessage()).thenReturn(ByteBuffer.wrap(encoded)); - } -}
--- a/agent/command-server/src/test/java/com/redhat/thermostat/agent/command/server/internal/ServerHandlerTest.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,154 +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.agent.command.server.internal; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.isA; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.net.InetSocketAddress; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; - -import com.redhat.thermostat.agent.command.server.internal.ServerHandler.SSLHandshakeDoneListener; -import com.redhat.thermostat.agent.ipc.client.IPCMessageChannel; -import com.redhat.thermostat.common.command.Request; -import com.redhat.thermostat.common.command.Request.RequestType; -import com.redhat.thermostat.common.command.Response; -import com.redhat.thermostat.common.command.Response.ResponseType; -import com.redhat.thermostat.shared.config.SSLConfiguration; - -import io.netty.channel.Channel; -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelPipeline; -import io.netty.handler.ssl.SslHandler; -import io.netty.util.concurrent.Future; - -public class ServerHandlerTest { - - private ChannelPipeline pipeline; - private ChannelHandlerContext ctx; - private ServerHandler handler; - private IPCMessageChannel agentChannel; - private JsonResponseParser responseParser; - private JsonRequestEncoder requestEncoder; - - @Before - public void setup() { - Channel channel = mock(Channel.class); - pipeline = mock(ChannelPipeline.class); - ChannelFuture channelFuture = mock(ChannelFuture.class); - when(pipeline.write(isA(Response.class))).thenReturn(channelFuture); - - when(channel.pipeline()).thenReturn(pipeline); - ctx = mock(ChannelHandlerContext.class); - when(ctx.channel()).thenReturn(channel); - - SSLConfiguration mockSSLConf = mock(SSLConfiguration.class); - when(mockSSLConf.enableForCmdChannel()).thenReturn(true); - agentChannel = mock(IPCMessageChannel.class); - when(agentChannel.isOpen()).thenReturn(true); - - requestEncoder = mock(JsonRequestEncoder.class); - responseParser = mock(JsonResponseParser.class); - handler = new ServerHandler(mockSSLConf, agentChannel, requestEncoder, responseParser); - } - - @Test - public void channelActiveAddsSSLListener() throws Exception { - ChannelPipeline pipeline = mock(ChannelPipeline.class); - when(ctx.pipeline()).thenReturn(pipeline); - SslHandler sslHandler = mock(SslHandler.class); - when(pipeline.get(SslHandler.class)).thenReturn(sslHandler); - @SuppressWarnings("unchecked") - Future<Channel> handshakeFuture = mock(Future.class); - when(sslHandler.handshakeFuture()).thenReturn(handshakeFuture); - - handler.channelActive(ctx); - verify(handshakeFuture).addListener(any(SSLHandshakeDoneListener.class)); - } - - @Test - public void invalidRequestReturnsAnErrorResponse() throws Exception { - // target and receiver are null - Request request = mock(Request.class); - handler.channelRead0(ctx, request); - verify(requestEncoder, never()).encodeRequestAndSend(agentChannel, request); - - ArgumentCaptor<Response> responseCaptor = ArgumentCaptor.forClass(Response.class); - verify(pipeline).writeAndFlush(responseCaptor.capture()); - assertEquals(ResponseType.ERROR, responseCaptor.getValue().getType()); - } - - @Test - public void testRequestReceived() throws Exception { - Request request = new Request(RequestType.RESPONSE_EXPECTED, new InetSocketAddress("127.0.0.1", 123)); - request.setReceiver("com.example.MyReceiver"); - request.setParameter("hello", "world"); - - Response response = new Response(ResponseType.OK); - when(responseParser.parseResponse(agentChannel)).thenReturn(response); - - handler.channelRead0(ctx, request); - - verify(requestEncoder).encodeRequestAndSend(agentChannel, request); - verify(pipeline).writeAndFlush(response); - } - - @Test - public void testRequestReceivedChannelClosed() throws Exception { - Request request = new Request(RequestType.RESPONSE_EXPECTED, new InetSocketAddress("127.0.0.1", 123)); - request.setReceiver("com.example.MyReceiver"); - request.setParameter("hello", "world"); - - when(agentChannel.isOpen()).thenReturn(false); - handler.channelRead0(ctx, request); - verify(requestEncoder, never()).encodeRequestAndSend(agentChannel, request); - - ArgumentCaptor<Response> responseCaptor = ArgumentCaptor.forClass(Response.class); - verify(pipeline).writeAndFlush(responseCaptor.capture()); - assertEquals(ResponseType.ERROR, responseCaptor.getValue().getType()); - } - -} \ No newline at end of file
--- a/agent/command/pom.xml Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,175 +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-agent</artifactId> - <version>1.99.12-SNAPSHOT</version> - </parent> - - <artifactId>thermostat-agent-command</artifactId> - <packaging>bundle</packaging> - - <name>Thermostat Command Channel Server</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.powermock</groupId> - <artifactId>powermock-api-mockito</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.powermock</groupId> - <artifactId>powermock-module-junit4</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.osgi</groupId> - <artifactId>org.osgi.core</artifactId> - </dependency> - - <dependency> - <groupId>commons-codec</groupId> - <artifactId>commons-codec</artifactId> - <version>${commons-codec.version}</version> - </dependency> - <dependency> - <groupId>com.google.code.gson</groupId> - <artifactId>gson</artifactId> - </dependency> - - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-common-command</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-agent-ipc-server</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-storage-core</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-common-test</artifactId> - <version>${project.version}</version> - <scope>test</scope> - </dependency> - </dependencies> - - <build> - <plugins> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <extensions>true</extensions> - <configuration> - <instructions> - <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor> - <Bundle-Activator>com.redhat.thermostat.agent.command.internal.Activator</Bundle-Activator> - <Bundle-SymbolicName>com.redhat.thermostat.agent.command</Bundle-SymbolicName> - <Export-Package> - com.redhat.thermostat.agent.command - </Export-Package> - <Private-Package> - com.redhat.thermostat.agent.command.internal - </Private-Package> - <!-- Do not autogenerate uses clauses in Manifests --> - <_nouses>true</_nouses> - </instructions> - </configuration> - </plugin> - - - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-resources-plugin</artifactId> - <executions> - <execution> - <id>copy</id> - <phase>generate-resources</phase> - <goals> - <goal>copy-resources</goal> - </goals> - <configuration> - <overwrite>true</overwrite> - <outputDirectory>${project.build.directory}</outputDirectory> - <resources> - <resource> - <directory>../../common/portability/target</directory> - <includes> - <include>${sharedlib.prefix}thermostat-common-portability${sharedlib.suffix}</include> - </includes> - </resource> - </resources> - </configuration> - </execution> - </executions> - </plugin> - - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-surefire-plugin</artifactId> - <configuration> - <systemPropertyVariables> - <com.redhat.thermostat.shared.loader.testNativesHome>${project.build.directory}</com.redhat.thermostat.shared.loader.testNativesHome> - </systemPropertyVariables> - </configuration> - </plugin> - </plugins> - </build> - -</project> -
--- a/agent/command/src/main/java/com/redhat/thermostat/agent/command/ConfigurationServer.java Tue Jun 13 12:02:12 2017 +0200 +++ /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.agent.command; - -import java.io.IOException; - -import com.redhat.thermostat.annotations.Service; -import com.redhat.thermostat.common.command.Request; - -/** - * An agent-side service that allows starting and stopping the command-channel - * server. - * - * The command-channel server allows the agent to receive and process - * {@link Request}s. - */ -@Service -public interface ConfigurationServer { - - /** - * Starts the configuration server so it listens at the interface specified - * by the {@code host} and {@code port}. - * @throws IOException if it fails to listen - */ - void startListening(String host, int port) throws IOException; - - /** - * Shuts down the configuration server. No additional {@link Request}s will - * be accepted after this is called, but existing ones may be processed to - * completion. - */ - void stopListening(); - -} -
--- a/agent/command/src/main/java/com/redhat/thermostat/agent/command/internal/Activator.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,102 +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.agent.command.internal; - -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.osgi.framework.BundleActivator; -import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceRegistration; - -import com.redhat.thermostat.agent.command.ConfigurationServer; -import com.redhat.thermostat.agent.command.ReceiverRegistry; -import com.redhat.thermostat.agent.ipc.server.AgentIPCService; -import com.redhat.thermostat.common.MultipleServiceTracker; -import com.redhat.thermostat.common.MultipleServiceTracker.Action; -import com.redhat.thermostat.common.MultipleServiceTracker.DependencyProvider; -import com.redhat.thermostat.common.utils.LoggingUtils; -import com.redhat.thermostat.shared.config.CommonPaths; -import com.redhat.thermostat.shared.config.SSLConfiguration; - -public class Activator implements BundleActivator { - - private static final Logger logger = LoggingUtils.getLogger(Activator.class); - - @SuppressWarnings("rawtypes") - private ServiceRegistration confServerRegistration; - private ReceiverRegistry receivers; - private MultipleServiceTracker sslConfigTracker; - - @Override - public void start(final BundleContext context) throws Exception { - logger.log(Level.INFO, "activating thermostat-agent-confserver"); - receivers = new ReceiverRegistry(context); - receivers.registerReceiver(new PingReceiver()); - - Class<?>[] deps = { CommonPaths.class, SSLConfiguration.class, AgentIPCService.class }; - sslConfigTracker = new MultipleServiceTracker(context, deps, new Action() { - - @Override - public void dependenciesAvailable(DependencyProvider services) { - CommonPaths paths = services.get(CommonPaths.class); - SSLConfiguration sslConf = services.get(SSLConfiguration.class); - AgentIPCService ipcService = services.get(AgentIPCService.class); - CommandChannelDelegate confServer = new CommandChannelDelegate(receivers, sslConf, - paths.getSystemBinRoot(), ipcService); - confServerRegistration = context.registerService(ConfigurationServer.class.getName(), confServer, null); - } - - @Override - public void dependenciesUnavailable() { - confServerRegistration.unregister(); - confServerRegistration = null; - } - }); - sslConfigTracker.open(); - } - - @Override - public void stop(BundleContext context) throws Exception { - sslConfigTracker.close(); - if (confServerRegistration != null) { - confServerRegistration.unregister(); - } - } - -} -
--- a/agent/command/src/main/java/com/redhat/thermostat/agent/command/internal/AgentRequestDecoder.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,147 +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.agent.command.internal; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.nio.charset.Charset; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; -import com.google.gson.JsonParser; -import com.redhat.thermostat.common.command.Request; -import com.redhat.thermostat.common.command.Request.RequestType; -import com.redhat.thermostat.common.utils.LoggingUtils; - -class AgentRequestDecoder { - - private static final Logger logger = LoggingUtils.getLogger(AgentRequestDecoder.class); - - Request decodeRequest(byte[] jsonRequest) throws IOException { - logger.log(Level.FINEST, "Agent: decoding request received from command channel"); - - String jsonRequestString = new String(jsonRequest, Charset.forName("UTF-8")); - Request request; - try { - GsonBuilder builder = new GsonBuilder(); - Gson gson = builder.create(); - JsonParser parser = new JsonParser(); - JsonElement parsed = parser.parse(jsonRequestString); - - // Get root of JsonObject tree - JsonObject root = toJsonObject(parsed); - JsonElement requestElement = root.get(CommandChannelConstants.REQUEST_JSON_TOP); - requireNonJsonNull(requestElement, "Request data missing"); - JsonObject requestObj = toJsonObject(requestElement); - - // Create Request - RequestType requestType = parseRequestType(gson, requestObj); - InetSocketAddress target = parseTargetAddress(gson, requestObj); - request = new Request(requestType, target); - - // Add parameters to Request - JsonElement paramsElement = requestObj.get(CommandChannelConstants.REQUEST_JSON_PARAMS); - requireNonJsonNull(paramsElement, "Request parameters missing"); - JsonObject paramsObj = toJsonObject(paramsElement); - for (Map.Entry<String, JsonElement> param : paramsObj.entrySet()) { - String paramName = param.getKey(); - - JsonElement value = param.getValue(); - // Parameter value should be a string (JsonPrimitive) or null (JsonNull) - if (!value.isJsonPrimitive() && !value.isJsonNull()) { - throw new IOException("Malformed parameter value"); - } - String paramValue = gson.fromJson(value, String.class); - - request.setParameter(paramName, paramValue); - } - } catch (JsonParseException e) { - throw new IOException("Failed to parse request", e); - } - - return request; - } - - private RequestType parseRequestType(Gson gson, JsonObject requestObj) throws IOException { - JsonElement requestTypeObj = requestObj.get(CommandChannelConstants.REQUEST_JSON_TYPE); - requireNonJsonNull(requestTypeObj, "Request type missing"); - String requestTypeString = gson.fromJson(requestTypeObj, String.class); - try { - return RequestType.valueOf(requestTypeString); - } catch (IllegalArgumentException e) { - throw new IOException("Invalid request type: " + requestTypeString); - } - } - - private InetSocketAddress parseTargetAddress(Gson gson, JsonObject requestObj) throws IOException { - JsonElement hostnameObj = requestObj.get(CommandChannelConstants.REQUEST_JSON_HOST); - requireNonJsonNull(hostnameObj, "Target hostname missing"); - String hostname = gson.fromJson(hostnameObj, String.class); - - JsonElement portObj = requestObj.get(CommandChannelConstants.REQUEST_JSON_PORT); - requireNonJsonNull(portObj, "Target port number missing"); - int port = gson.fromJson(portObj, int.class); - - // Ensure address is a valid one - try { - return new InetSocketAddress(hostname, port); - } catch (IllegalArgumentException e) { - throw new IOException("Invalid target address"); - } - } - - private JsonObject toJsonObject(JsonElement element) throws IOException { - if (!element.isJsonObject()) { - throw new IOException("Malformed data received"); - } - return element.getAsJsonObject(); - } - - private void requireNonJsonNull(JsonElement element, String errorMessage) throws IOException { - if (element == null || element.isJsonNull()) { - throw new IOException(errorMessage); - } - } - -} -
--- a/agent/command/src/main/java/com/redhat/thermostat/agent/command/internal/AgentResponseEncoder.java Tue Jun 13 12:02:12 2017 +0200 +++ /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.agent.command.internal; - -import java.nio.charset.Charset; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonObject; -import com.redhat.thermostat.common.command.Response; - -class AgentResponseEncoder { - - byte[] encodeResponse(Response response) { - GsonBuilder builder = new GsonBuilder(); - Gson gson = builder.create(); - - JsonObject responseTypeObj = new JsonObject(); - responseTypeObj.addProperty(CommandChannelConstants.RESPONSE_JSON_TYPE, response.getType().name()); - JsonObject responseRoot = new JsonObject(); - responseRoot.add(CommandChannelConstants.RESPONSE_JSON_TOP, responseTypeObj); - - String jsonResponse = gson.toJson(responseRoot); - return jsonResponse.getBytes(Charset.forName("UTF-8")); - } - -}
--- a/agent/command/src/main/java/com/redhat/thermostat/agent/command/internal/CommandChannelConstants.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +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.agent.command.internal; - -import java.nio.charset.Charset; - -interface CommandChannelConstants { - - // Server startup state tokens - byte[] SERVER_STARTED_TOKEN = "<SERVER STARTED>".getBytes(Charset.forName("UTF-8")); - byte[] SERVER_READY_TOKEN = "<SERVER READY>".getBytes(Charset.forName("UTF-8")); - - // SSLConfiguration JSON members - String SSL_JSON_ROOT = "sslConfiguration"; - String SSL_JSON_KEYSTORE_FILE = "keystoreFile"; - String SSL_JSON_KEYSTORE_PASS = "keystorePass"; - String SSL_JSON_COMMAND_CHANNEL = "enabledCommandChannel"; - String SSL_JSON_BACKING_STORAGE = "enabledBackingStorage"; - String SSL_JSON_HOSTNAME_VERIFICATION = "disableHostnameVerification"; - - // Request JSON members - String REQUEST_JSON_TOP = "request"; - String REQUEST_JSON_TYPE = "type"; - String REQUEST_JSON_HOST = "targetHost"; - String REQUEST_JSON_PORT = "targetPort"; - String REQUEST_JSON_PARAMS = "parameters"; - - // Response JSON members - String RESPONSE_JSON_TOP = "response"; - String RESPONSE_JSON_TYPE = "type"; - -}
--- a/agent/command/src/main/java/com/redhat/thermostat/agent/command/internal/CommandChannelDelegate.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,348 +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.agent.command.internal; - -import java.io.File; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.charset.Charset; -import java.nio.file.FileSystems; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.attribute.UserPrincipal; -import java.util.Arrays; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.redhat.thermostat.common.portability.PortableProcessFactory; -import com.redhat.thermostat.agent.command.ConfigurationServer; -import com.redhat.thermostat.agent.command.ReceiverRegistry; -import com.redhat.thermostat.agent.command.RequestReceiver; -import com.redhat.thermostat.agent.ipc.server.AgentIPCService; -import com.redhat.thermostat.agent.ipc.server.IPCMessage; -import com.redhat.thermostat.agent.ipc.server.ThermostatIPCCallbacks; -import com.redhat.thermostat.common.command.Message.MessageType; -import com.redhat.thermostat.common.command.Request; -import com.redhat.thermostat.common.command.Response; -import com.redhat.thermostat.common.command.Response.ResponseType; -import com.redhat.thermostat.common.utils.LoggingUtils; -import com.redhat.thermostat.shared.config.SSLConfiguration; -import com.redhat.thermostat.shared.config.OS; - -class CommandChannelDelegate implements ConfigurationServer, ThermostatIPCCallbacks { - - private static final Logger logger = LoggingUtils.getLogger(CommandChannelDelegate.class); - private static final String CMD_NAME = "thermostat-command-channel"; - private static final String IPC_SERVER_NAME = "command-channel"; - - // States for 'state' field - private static final int STATE_NOT_STARTED = 0; - private static final int STATE_STARTED = 1; - private static final int STATE_READY = 2; - private static final int STATE_ERROR = -1; - - private final ReceiverRegistry receivers; - private final SSLConfiguration sslConf; - private final File binPath; - private final AgentIPCService ipcService; - private final CountDownLatch readyLatch; - private final SSLConfigurationEncoder sslEncoder; - private final AgentRequestDecoder requestDecoder; - private final AgentResponseEncoder responseEncoder; - private final ProcessCreator procCreator; - private final ProcessUserInfoBuilder userInfoBuilder; - private final FileSystemUtils fsUtils; - private Process process; - private AtomicInteger state; - - CommandChannelDelegate(ReceiverRegistry receivers, SSLConfiguration sslConf, File binPath, - AgentIPCService ipcService) { - this(receivers, sslConf, binPath, ipcService, new CountDownLatch(1), new SSLConfigurationEncoder(), - new AgentRequestDecoder(), new AgentResponseEncoder(), new ProcessUserInfoBuilder(), - new FileSystemUtils(), new ProcessCreator()); - } - - /** For testing only */ - CommandChannelDelegate(ReceiverRegistry receivers, SSLConfiguration sslConf, File binPath, - AgentIPCService ipcService, CountDownLatch readyLatch, SSLConfigurationEncoder sslEncoder, - AgentRequestDecoder requestDecoder, AgentResponseEncoder responseEncoder, - ProcessUserInfoBuilder userInfoBuilder, FileSystemUtils fsUtils, ProcessCreator procCreator) { - this.receivers = receivers; - this.sslConf = sslConf; - this.binPath = binPath; - this.ipcService = ipcService; - this.readyLatch = readyLatch; - this.sslEncoder = sslEncoder; - this.requestDecoder = requestDecoder; - this.responseEncoder = responseEncoder; - this.procCreator = procCreator; - this.userInfoBuilder = userInfoBuilder; - this.fsUtils = fsUtils; - this.state = new AtomicInteger(); - } - - @Override - public void startListening(String hostname, int port) throws IOException { - // Determine if this process is running as a privileged user - // NOTE: on Windows, security is handled by permission bits, not userid. - if (OS.IS_UNIX && userInfoBuilder.isPrivilegedUser()) { - // Get owner of command channel script, which will also be the user running it - Path cmdPath = fsUtils.getPath(binPath.getAbsolutePath(), CMD_NAME); - UserPrincipal unprivilegedPrincipal = fsUtils.getOwner(cmdPath); - // Create IPC server owned by user running command channel script - ipcService.createServer(IPC_SERVER_NAME, this, unprivilegedPrincipal); - } else { - // Create IPC server owned by current user - ipcService.createServer(IPC_SERVER_NAME, this); - } - - startServer(hostname, port); - } - - @Override - public void stopListening() { - try { - killServer(); - // Clean up IPC server - destroyIPCServerIfExists(); - } catch (IOException e) { - logger.log(Level.WARNING, "Error occurred while stopping command channel server", e); - } - } - - private void destroyIPCServerIfExists() throws IOException { - if (ipcService.serverExists(IPC_SERVER_NAME)) { - ipcService.destroyServer(IPC_SERVER_NAME); - } - } - - @Override - public void messageReceived(IPCMessage message) { - byte[] result = null; - ByteBuffer buf = message.get(); - byte[] data = new byte[buf.limit()]; - buf.get(data); - - switch (state.get()) { - case STATE_NOT_STARTED: - // First message from server just tells us it's started - boolean started = checkStart(data); - if (started) { - // Return SSL Configuration - try { - result = sslEncoder.encodeAsJson(sslConf); - } catch (IOException e) { - logger.log(Level.SEVERE, "Unable to encode SSL configuration", e); - state.set(STATE_ERROR); - } - } - break; - case STATE_STARTED: - // Second message from server indicates that it has processed - // the SSL configuration and is ready to receive requests - checkReady(data); - readyLatch.countDown(); - // No response - break; - case STATE_READY: - // Parse requests - Request request; - try { - request = parseRequest(data); - // Return response as bytes - result = requestReceived(request); - } catch (IOException e) { - logger.log(Level.WARNING, "Unable to process request from command channel", e); - // Send error response - Response error = new Response(ResponseType.ERROR); - result = encodeResponse(error); - } - break; - default: // STATE_ERROR - // Do nothing - } - - if (state.get() == STATE_ERROR && readyLatch.getCount() > 0) { - // Will never become ready, so throw exception - readyLatch.countDown(); - } - - // Send reply using IPC service - if (result != null) { - ByteBuffer reply = ByteBuffer.wrap(result); - try { - message.reply(reply); - } catch (IOException e) { - logger.log(Level.WARNING, "Failed to send reply via command channel", e); - } - } - } - - private void startServer(String hostname, int port) throws IOException { - File ipcConfig = ipcService.getConfigurationFile(); - String[] processArgs = OS.IS_UNIX - ? new String[]{ binPath.getAbsolutePath() + File.separator + CMD_NAME, hostname, - String.valueOf(port), ipcConfig.getAbsolutePath() } - : new String[] { "cmd", "/c", binPath.getAbsolutePath() + File.separator + CMD_NAME + ".cmd", hostname, - String.valueOf(port), ipcConfig.getAbsolutePath(), "" + PortableProcessFactory.getInstance().getCurrentProcessPid()}; - - ProcessBuilder builder = new ProcessBuilder(processArgs); - // This has the problem of some messages/Exceptions not - // showing up in the parent's stderr stream if used together - // with JUL-logging. One such example is CNFE in - // the child process. In that case your best bet is - // Redirect.to(File). - builder.inheritIO(); - logger.info("Starting command channel server process"); - process = procCreator.startProcess(builder); - - // Wait for started notification - try { - waitForStarted(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - - private void waitForStarted() throws IOException, InterruptedException { - // Wait for started token - readyLatch.await(); - // If not started at this point, there was a token mismatch - if (state.get() != STATE_READY) { - throw new IOException("Command channel server failed to start"); - } - logger.info("Command channel server ready to accept requests"); - } - - private void killServer() { - if (process != null) { - logger.info("Stopping command channel server process"); - process.destroy(); - } - } - - private byte[] requestReceived(Request request) { - String receiverName = request.getReceiver(); - MessageType requestType = request.getType(); - logger.info("Request received: '" + requestType + "' for '" + receiverName + "'"); - boolean authSucceeded = authenticateRequestIfNecessary(request); - Response response = null; - if (! authSucceeded) { - logger.info("Authentication for request failed"); - response = new Response(ResponseType.AUTH_FAILED); - } else { - if (receiverName != null && requestType != null) { - RequestReceiver receiver = receivers.getReceiver(receiverName); - if (receiver != null) { - response = receiver.receive(request); - } - } - - if (response == null) { - logger.info("Receiver with name '" + receiverName + "' not found "); - response = new Response(ResponseType.ERROR); - } - } - - return encodeResponse(response); - } - - private Request parseRequest(byte[] data) throws IOException { - return requestDecoder.decodeRequest(data); - } - - private byte[] encodeResponse(Response response) { - return responseEncoder.encodeResponse(response); - } - - private boolean authenticateRequestIfNecessary(Request request) { - /* - * FIXME Authentication no longer works after the introduction of the - * web gateway. For now, we bypass authentication until the new - * WebSockets command channel is integrated. - */ - return true; - } - - private boolean checkStart(byte[] data) { - boolean tokenMatch = Arrays.equals(CommandChannelConstants.SERVER_STARTED_TOKEN, data); - if (!tokenMatch) { - String message = new String(data, Charset.forName("UTF-8")); - logger.severe("Unexpected start message from command channel: " + message); - state.set(STATE_ERROR); - } else { - // Set state to indicate started - state.set(STATE_STARTED); - } - return tokenMatch; - } - - private void checkReady(byte[] data) { - boolean tokenMatch = Arrays.equals(CommandChannelConstants.SERVER_READY_TOKEN, data); - if (!tokenMatch) { - String message = new String(data, Charset.forName("UTF-8")); - logger.severe("Unexpected ready message from command channel: " + message); - state.set(STATE_ERROR); - } else { - // Set state to indicate ready - state.set(STATE_READY); - } - } - - /** for testing only */ - static class ProcessCreator { - Process startProcess(ProcessBuilder builder) throws IOException { - return builder.start(); - } - } - - /** for testing only */ - static class FileSystemUtils { - Path getPath(String first, String... more) { - return FileSystems.getDefault().getPath(first, more); - } - - UserPrincipal getOwner(Path path) throws IOException { - return Files.getOwner(path); - } - } - -} - -
--- a/agent/command/src/main/java/com/redhat/thermostat/agent/command/internal/ProcessUserInfoBuilder.java Tue Jun 13 12:02:12 2017 +0200 +++ /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.agent.command.internal; - -import com.redhat.thermostat.shared.config.OS; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; - -/* - * FIXME: This class was copied from system-backend. - * Replace when this information is available from an API. - */ -class ProcessUserInfoBuilder { - - private static final String PROC_STATUS_SELF_PATH = "/proc/self/status"; - private static final String PROC_STATUS_UID = "Uid:"; - private final FileReaderCreator readerCreator; - - ProcessUserInfoBuilder() { - this(new FileReaderCreator()); - } - - ProcessUserInfoBuilder(FileReaderCreator readerCreator) { - this.readerCreator = readerCreator; - } - - private long getUid() throws IOException { - FileReader reader = readerCreator.create(PROC_STATUS_SELF_PATH); - long uid = getUidFromProcfs(new BufferedReader(reader)); - return uid; - } - - boolean isPrivilegedUser() throws IOException { - return OS.IS_LINUX ? (getUid() == 0) : false; - } - - /* - * Look for the following line: - * Uid: <RealUid> <EffectiveUid> <SavedUid> <FSUid> - */ - private long getUidFromProcfs(BufferedReader br) throws IOException { - long uid = -1; - String line; - while ((line = br.readLine()) != null) { - line = line.trim(); - if (line.startsWith(PROC_STATUS_UID)) { - String[] parts = line.split("\\s+"); - if (parts.length == 5) { - try { - // Use Real UID - uid = Long.parseLong(parts[1]); - } catch (NumberFormatException e) { - throw new IOException("Unexpected output from ps command", e); - } - } - else { - throw new IOException("Expected 5 parts from split /proc/${pid}/status output, got " + parts.length); - } - } - } - if (uid < 0) { - throw new IOException("Unable to determine UID from /proc/${pid}/status"); - } - return uid; - } - - // For testing purposes - static class FileReaderCreator { - FileReader create(String path) throws IOException { - return new FileReader(new File(path)); - } - } - -} -
--- a/agent/command/src/main/java/com/redhat/thermostat/agent/command/internal/SSLConfigurationEncoder.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +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.agent.command.internal; - -import java.io.File; -import java.io.IOException; -import java.nio.charset.Charset; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonObject; -import com.redhat.thermostat.shared.config.SSLConfiguration; - -class SSLConfigurationEncoder { - - // Total size of JSON encoded SSLConfiguration should be no more than this size in bytes - private static final int SSL_CONF_MAX_BYTES = 8192; - - byte[] encodeAsJson(SSLConfiguration sslConf) throws IOException { - GsonBuilder builder = new GsonBuilder(); - builder.serializeNulls(); // Necessary since keystore file/password can be null - Gson gson = builder.create(); - - JsonObject paramsObj = new JsonObject(); - File keystoreFile = sslConf.getKeystoreFile(); - String keystorePath = null; - if (keystoreFile != null) { - keystorePath = keystoreFile.getAbsolutePath(); - } - paramsObj.addProperty(CommandChannelConstants.SSL_JSON_KEYSTORE_FILE, keystorePath); - paramsObj.addProperty(CommandChannelConstants.SSL_JSON_KEYSTORE_PASS, sslConf.getKeyStorePassword()); - paramsObj.addProperty(CommandChannelConstants.SSL_JSON_COMMAND_CHANNEL, sslConf.enableForCmdChannel()); - paramsObj.addProperty(CommandChannelConstants.SSL_JSON_BACKING_STORAGE, sslConf.enableForBackingStorage()); - paramsObj.addProperty(CommandChannelConstants.SSL_JSON_HOSTNAME_VERIFICATION, sslConf.disableHostnameVerification()); - - JsonObject sslConfigRoot = new JsonObject(); - sslConfigRoot.add(CommandChannelConstants.SSL_JSON_ROOT, paramsObj); - - String jsonSslConf = gson.toJson(sslConfigRoot); - byte[] jsonSslConfBytes = jsonSslConf.getBytes(Charset.forName("UTF-8")); - if (jsonSslConfBytes.length > SSL_CONF_MAX_BYTES) { - throw new IOException("JSON-encoded SSL configuration larger than maximum of " - + SSL_CONF_MAX_BYTES + " bytes"); - } - return jsonSslConfBytes; - } - - - -}
--- a/agent/command/src/main/java/com/redhat/thermostat/agent/command/package-info.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +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. - */ - - -/** - * Access the command-channel / Request API on the agent-side - */ -package com.redhat.thermostat.agent.command;
--- a/agent/command/src/test/java/com/redhat/thermostat/agent/command/internal/AgentRequestDecoderTest.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,307 +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.agent.command.internal; - -import static org.junit.Assert.*; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.nio.charset.Charset; -import java.util.Collection; - -import org.junit.Before; -import org.junit.Test; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.redhat.thermostat.common.command.Request; -import com.redhat.thermostat.common.command.Request.RequestType; - -public class AgentRequestDecoderTest { - - private AgentRequestDecoder decoder; - - @Before - public void setUp() throws Exception { - decoder = new AgentRequestDecoder(); - } - - @Test(expected=IOException.class) - public void testEmptyString() throws IOException { - decoder.decodeRequest(new byte[0]); - } - - @Test(expected=IOException.class) - public void testNotJson() throws IOException { - decoder.decodeRequest("Not JSON".getBytes(Charset.forName("UTF-8"))); - } - - @Test(expected=IOException.class) - public void testNotJsonObject() throws IOException { - byte[] json = toJson(new JsonArray()); - decoder.decodeRequest(json); - } - - @Test(expected=IOException.class) - public void testRequestMissing() throws IOException { - byte[] json = toJson(new JsonObject()); - decoder.decodeRequest(json); - } - - @Test(expected=IOException.class) - public void testBadRequestObject() throws IOException { - JsonObject root = createRequest(); - root.add(CommandChannelConstants.REQUEST_JSON_TOP, new JsonArray()); - - byte[] json = toJson(root); - decoder.decodeRequest(json); - } - - @Test(expected=IOException.class) - public void testNullRequestObject() throws IOException { - JsonObject root = createRequest(); - root.add(CommandChannelConstants.REQUEST_JSON_TOP, null); - - byte[] json = toJson(root); - decoder.decodeRequest(json); - } - - @Test(expected=IOException.class) - public void testRequestTypeMissing() throws IOException { - JsonObject root = createRequest(); - JsonObject jsonRequest = root.get(CommandChannelConstants.REQUEST_JSON_TOP).getAsJsonObject(); - jsonRequest.remove(CommandChannelConstants.REQUEST_JSON_TYPE); - - byte[] json = toJson(root); - decoder.decodeRequest(json); - } - - @Test(expected=IOException.class) - public void testRequestTypeNotString() throws IOException { - JsonObject root = createRequest(); - JsonObject jsonRequest = root.get(CommandChannelConstants.REQUEST_JSON_TOP).getAsJsonObject(); - jsonRequest.add(CommandChannelConstants.REQUEST_JSON_TYPE, new JsonArray()); - - byte[] json = toJson(root); - decoder.decodeRequest(json); - } - - @Test(expected=IOException.class) - public void testRequestTypeNull() throws IOException { - JsonObject root = createRequest(); - JsonObject jsonRequest = root.get(CommandChannelConstants.REQUEST_JSON_TOP).getAsJsonObject(); - jsonRequest.addProperty(CommandChannelConstants.REQUEST_JSON_TYPE, (String) null); - - byte[] json = toJson(root); - decoder.decodeRequest(json); - } - - @Test(expected=IOException.class) - public void testRequestTypeNotEnum() throws IOException { - JsonObject root = createRequest(); - JsonObject jsonRequest = root.get(CommandChannelConstants.REQUEST_JSON_TOP).getAsJsonObject(); - jsonRequest.addProperty(CommandChannelConstants.REQUEST_JSON_TYPE, "Not a RequestType"); - - byte[] json = toJson(root); - decoder.decodeRequest(json); - } - - @Test(expected=IOException.class) - public void testHostnameMissing() throws IOException { - JsonObject root = createRequest(); - JsonObject jsonRequest = root.get(CommandChannelConstants.REQUEST_JSON_TOP).getAsJsonObject(); - jsonRequest.remove(CommandChannelConstants.REQUEST_JSON_HOST); - - byte[] json = toJson(root); - decoder.decodeRequest(json); - } - - @Test(expected=IOException.class) - public void testHostnameNotString() throws IOException { - JsonObject root = createRequest(); - JsonObject jsonRequest = root.get(CommandChannelConstants.REQUEST_JSON_TOP).getAsJsonObject(); - jsonRequest.add(CommandChannelConstants.REQUEST_JSON_HOST, new JsonArray()); - - byte[] json = toJson(root); - decoder.decodeRequest(json); - } - - @Test(expected=IOException.class) - public void testHostnameNull() throws IOException { - JsonObject root = createRequest(); - JsonObject jsonRequest = root.get(CommandChannelConstants.REQUEST_JSON_TOP).getAsJsonObject(); - jsonRequest.addProperty(CommandChannelConstants.REQUEST_JSON_HOST, (String) null); - - byte[] json = toJson(root); - decoder.decodeRequest(json); - } - - @Test(expected=IOException.class) - public void testPortMissing() throws IOException { - JsonObject root = createRequest(); - JsonObject jsonRequest = root.get(CommandChannelConstants.REQUEST_JSON_TOP).getAsJsonObject(); - jsonRequest.remove(CommandChannelConstants.REQUEST_JSON_PORT); - - byte[] json = toJson(root); - decoder.decodeRequest(json); - } - - @Test(expected=IOException.class) - public void testPortNotInt() throws IOException { - JsonObject root = createRequest(); - JsonObject jsonRequest = root.get(CommandChannelConstants.REQUEST_JSON_TOP).getAsJsonObject(); - jsonRequest.addProperty(CommandChannelConstants.REQUEST_JSON_PORT, "Not a Port"); - - byte[] json = toJson(root); - decoder.decodeRequest(json); - } - - @Test(expected=IOException.class) - public void testPortNull() throws IOException { - JsonObject root = createRequest(); - JsonObject jsonRequest = root.get(CommandChannelConstants.REQUEST_JSON_TOP).getAsJsonObject(); - jsonRequest.addProperty(CommandChannelConstants.REQUEST_JSON_PORT, (String) null); - - byte[] json = toJson(root); - decoder.decodeRequest(json); - } - - @Test(expected=IOException.class) - public void testParamsMissing() throws IOException { - JsonObject root = createRequest(); - JsonObject jsonRequest = root.get(CommandChannelConstants.REQUEST_JSON_TOP).getAsJsonObject(); - jsonRequest.remove(CommandChannelConstants.REQUEST_JSON_PARAMS); - - byte[] json = toJson(root); - decoder.decodeRequest(json); - } - - @Test(expected=IOException.class) - public void testBadParams() throws IOException { - JsonObject root = createRequest(); - JsonObject jsonRequest = root.get(CommandChannelConstants.REQUEST_JSON_TOP).getAsJsonObject(); - jsonRequest.add(CommandChannelConstants.REQUEST_JSON_PARAMS, new JsonArray()); - - byte[] json = toJson(root); - decoder.decodeRequest(json); - } - - @Test(expected=IOException.class) - public void testParamsNull() throws IOException { - JsonObject root = createRequest(); - JsonObject jsonRequest = root.get(CommandChannelConstants.REQUEST_JSON_TOP).getAsJsonObject(); - jsonRequest.add(CommandChannelConstants.REQUEST_JSON_PARAMS, null); - - byte[] json = toJson(root); - decoder.decodeRequest(json); - } - - @Test(expected=IOException.class) - public void testParamsValueNotString() throws IOException { - JsonObject root = createRequest(); - JsonObject jsonRequest = root.get(CommandChannelConstants.REQUEST_JSON_TOP).getAsJsonObject(); - JsonObject params = jsonRequest.get(CommandChannelConstants.REQUEST_JSON_PARAMS).getAsJsonObject(); - params.add("name", new JsonArray()); - - byte[] json = toJson(root); - decoder.decodeRequest(json); - } - - @Test - public void testSuccess() throws IOException { - JsonObject root = createRequest(); - byte[] json = toJson(root); - Request request = decoder.decodeRequest(json); - - assertEquals(RequestType.NO_RESPONSE_EXPECTED, request.getType()); - assertEquals(new InetSocketAddress("127.0.0.1", 12000), request.getTarget()); - - Collection<String> parameterNames = request.getParameterNames(); - assertEquals(2, parameterNames.size()); - assertTrue(parameterNames.contains("name1")); - assertTrue(parameterNames.contains("name2")); - assertEquals("value1", request.getParameter("name1")); - assertEquals("value2", request.getParameter("name2")); - } - - @Test - public void testSuccessNullValue() throws IOException { - JsonObject root = createRequest(); - JsonObject jsonRequest = root.get(CommandChannelConstants.REQUEST_JSON_TOP).getAsJsonObject(); - JsonObject params = jsonRequest.get(CommandChannelConstants.REQUEST_JSON_PARAMS).getAsJsonObject(); - params.addProperty("name1", (String) null); - - byte[] json = toJson(root); - Request request = decoder.decodeRequest(json); - - assertEquals(RequestType.NO_RESPONSE_EXPECTED, request.getType()); - assertEquals(new InetSocketAddress("127.0.0.1", 12000), request.getTarget()); - - Collection<String> parameterNames = request.getParameterNames(); - assertEquals(2, parameterNames.size()); - assertTrue(parameterNames.contains("name1")); - assertTrue(parameterNames.contains("name2")); - assertNull(request.getParameter("name1")); - assertEquals("value2", request.getParameter("name2")); - } - - private JsonObject createRequest() { - JsonObject jsonRequest = new JsonObject(); - jsonRequest.addProperty(CommandChannelConstants.REQUEST_JSON_TYPE, RequestType.NO_RESPONSE_EXPECTED.name()); - jsonRequest.addProperty(CommandChannelConstants.REQUEST_JSON_HOST, "127.0.0.1"); - jsonRequest.addProperty(CommandChannelConstants.REQUEST_JSON_PORT, "12000"); - - JsonObject params = new JsonObject(); - params.addProperty("name1", "value1"); - params.addProperty("name2", "value2"); - jsonRequest.add(CommandChannelConstants.REQUEST_JSON_PARAMS, params); - - JsonObject root = new JsonObject(); - root.add(CommandChannelConstants.REQUEST_JSON_TOP, jsonRequest); - return root; - } - - private byte[] toJson(JsonElement element) { - Gson gson = new GsonBuilder().serializeNulls().create(); - String jsonString = gson.toJson(element); - return jsonString.getBytes(Charset.forName("UTF-8")); - } - -}
--- a/agent/command/src/test/java/com/redhat/thermostat/agent/command/internal/AgentResponseEncoderTest.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +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.agent.command.internal; - -import static org.junit.Assert.assertArrayEquals; - -import java.nio.charset.Charset; - -import org.junit.Test; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonObject; -import com.redhat.thermostat.common.command.Response; -import com.redhat.thermostat.common.command.Response.ResponseType; - -public class AgentResponseEncoderTest { - - @Test - public void testEncodedResponse() { - Gson gson = new GsonBuilder().create(); - JsonObject jsonResponse = new JsonObject(); - jsonResponse.addProperty(CommandChannelConstants.RESPONSE_JSON_TYPE, ResponseType.OK.name()); - JsonObject jsonRoot = new JsonObject(); - jsonRoot.add(CommandChannelConstants.RESPONSE_JSON_TOP, jsonResponse); - String expected = gson.toJson(jsonRoot); - byte[] expectedBytes = expected.getBytes(Charset.forName("UTF-8")); - - AgentResponseEncoder encoder = new AgentResponseEncoder(); - Response response = new Response(ResponseType.OK); - byte[] result = encoder.encodeResponse(response); - - assertArrayEquals(expectedBytes, result); - } - -}
--- a/agent/command/src/test/java/com/redhat/thermostat/agent/command/internal/CommandChannelDelegateTest.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,406 +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.agent.command.internal; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.io.File; -import java.io.IOException; -import java.lang.ProcessBuilder.Redirect; -import java.nio.ByteBuffer; -import java.nio.charset.Charset; -import java.nio.file.Path; -import java.nio.file.attribute.UserPrincipal; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.CountDownLatch; - -import com.redhat.thermostat.common.portability.PortableProcessFactory; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; - -import com.redhat.thermostat.agent.command.ReceiverRegistry; -import com.redhat.thermostat.agent.command.RequestReceiver; -import com.redhat.thermostat.agent.command.internal.CommandChannelDelegate.FileSystemUtils; -import com.redhat.thermostat.agent.command.internal.CommandChannelDelegate.ProcessCreator; -import com.redhat.thermostat.agent.ipc.server.AgentIPCService; -import com.redhat.thermostat.agent.ipc.server.IPCMessage; -import com.redhat.thermostat.common.command.Request; -import com.redhat.thermostat.common.command.Request.RequestType; -import com.redhat.thermostat.common.command.Response; -import com.redhat.thermostat.common.command.Response.ResponseType; -import com.redhat.thermostat.shared.config.OS; -import com.redhat.thermostat.shared.config.SSLConfiguration; - -public class CommandChannelDelegateTest { - - private static final String IPC_SERVER_NAME = "command-channel"; - private static final byte[] ENCODED_SSL_CONFIG = { 'S', 'S', 'L' }; - private static final byte[] ENCODED_REQUEST = { 'R', 'E', 'Q' }; - private static final byte[] ENCODED_RESPONSE_OK = { 'O', 'K' }; - private static final byte[] ENCODED_RESPONSE_AUTH_FAILED = { 'A', 'U', 'T', 'H' }; - private static final byte[] ENCODED_RESPONSE_ERROR = { 'E', 'R', 'R' }; - - private ProcessCreator processCreator; - private ReceiverRegistry receivers; - private File binPath; - private CommandChannelDelegate delegate; - private Process process; - private AgentIPCService ipcService; - private File ipcConfig; - private AgentRequestDecoder requestDecoder; - private AgentResponseEncoder responseEncoder; - private SSLConfigurationEncoder sslConfEncoder; - private CountDownLatch latch; - private SSLConfiguration sslConf; - private IPCMessage startedMessage; - private FileSystemUtils fsUtils; - private ProcessUserInfoBuilder userInfoBuilder; - - @Before - public void setUp() throws Exception { - receivers = mock(ReceiverRegistry.class); - sslConf = mock(SSLConfiguration.class); - binPath = new File("/path/to/thermostat/home/"); - processCreator = mock(ProcessCreator.class); - process = mock(Process.class); - ipcService = mock(AgentIPCService.class); - ipcConfig = new File("/path/to/ipc/config"); - - requestDecoder = mock(AgentRequestDecoder.class); - responseEncoder = mock(AgentResponseEncoder.class); - // Return different encoded response for different response types - when(responseEncoder.encodeResponse(any(Response.class))).thenAnswer(new Answer<Object>() { - @Override - public Object answer(InvocationOnMock invocation) throws Throwable { - Response resp = (Response) invocation.getArguments()[0]; - ResponseType type = resp.getType(); - switch (type) { - case OK: - return ENCODED_RESPONSE_OK; - case AUTH_FAILED: - return ENCODED_RESPONSE_AUTH_FAILED; - case ERROR: - return ENCODED_RESPONSE_ERROR; - default: - throw new IOException("Unexpected ResponseType: " + type.name()); - } - } - }); - sslConfEncoder = mock(SSLConfigurationEncoder.class); - when(sslConfEncoder.encodeAsJson(sslConf)).thenReturn(ENCODED_SSL_CONFIG); - - when(processCreator.startProcess(any(ProcessBuilder.class))).thenReturn(process); - when(ipcService.getConfigurationFile()).thenReturn(ipcConfig); - - latch = mock(CountDownLatch.class); - fsUtils = mock(FileSystemUtils.class); - userInfoBuilder = mock(ProcessUserInfoBuilder.class); - delegate = new CommandChannelDelegate(receivers, sslConf, binPath, ipcService, - latch, sslConfEncoder, requestDecoder, responseEncoder, userInfoBuilder, - fsUtils, processCreator); - - startedMessage = mock(IPCMessage.class); - when(startedMessage.get()).thenReturn(ByteBuffer.wrap(CommandChannelConstants.SERVER_STARTED_TOKEN)); - final IPCMessage readyMessage = mock(IPCMessage.class); - when(readyMessage.get()).thenReturn(ByteBuffer.wrap(CommandChannelConstants.SERVER_READY_TOKEN)); - doAnswer(new Answer<Void>() { - @Override - public Void answer(InvocationOnMock invocation) throws Throwable { - // Invoke callbacks with started message - delegate.messageReceived(startedMessage); - verify(startedMessage).reply(eq(ByteBuffer.wrap(ENCODED_SSL_CONFIG))); - // Invoke callbacks with ready message - delegate.messageReceived(readyMessage); - verify(readyMessage, never()).reply(any(ByteBuffer.class)); - return null; - } - }).when(latch).await(); - } - - @Test - public void testServerStarted() throws Exception { - delegate.startListening("127.0.0.1", 123); - - verify(ipcService).createServer(IPC_SERVER_NAME, delegate); - verify(processCreator).startProcess(any(ProcessBuilder.class)); - } - - @Test - public void testServerStartedPrivUser() throws Exception { - when(userInfoBuilder.isPrivilegedUser()).thenReturn(true); - Path scriptPath = mock(Path.class); - when(fsUtils.getPath(binPath.getAbsolutePath(), "thermostat-command-channel")).thenReturn(scriptPath); - UserPrincipal principal = mock(UserPrincipal.class); - when(fsUtils.getOwner(scriptPath)).thenReturn(principal); - delegate.startListening("127.0.0.1", 123); - - if (OS.IS_WINDOWS) { - verify(ipcService).createServer(IPC_SERVER_NAME, delegate); - } else { // Unix and macOS - verify(ipcService).createServer(IPC_SERVER_NAME, delegate, principal); - } - verify(processCreator).startProcess(any(ProcessBuilder.class)); - } - - @Test - public void testServerFailsToStart() throws Exception { - doAnswer(new Answer<Void>() { - @Override - public Void answer(InvocationOnMock invocation) throws Throwable { - // Invoke callbacks with wrong started message - IPCMessage message = mock(IPCMessage.class); - ByteBuffer badData = ByteBuffer.wrap("not the server started message".getBytes(Charset.forName("UTF-8"))); - when(message.get()).thenReturn(badData); - delegate.messageReceived(message); - verify(message, never()).reply(any(ByteBuffer.class)); - return null; - } - }).when(latch).await(); - - try { - delegate.startListening("127.0.0.1", 123); - fail("Expected IOException"); - } catch (IOException e) { - verify(ipcService).createServer(IPC_SERVER_NAME, delegate); - verify(processCreator).startProcess(any(ProcessBuilder.class)); - } - } - - @Test - public void testServerFailsToStartParseFail() throws Exception { - when(sslConfEncoder.encodeAsJson(sslConf)).thenThrow(new IOException("TEST")); - doAnswer(new Answer<Void>() { - @Override - public Void answer(InvocationOnMock invocation) throws Throwable { - // Invoke callbacks with started message - delegate.messageReceived(startedMessage); - return null; - } - }).when(latch).await(); - - try { - delegate.startListening("127.0.0.1", 123); - fail("Expected IOException"); - } catch (IOException e) { - verify(ipcService).createServer(IPC_SERVER_NAME, delegate); - verify(processCreator).startProcess(any(ProcessBuilder.class)); - } - } - - @Test - public void testServerFailsToBecomeReady() throws Exception { - doAnswer(new Answer<Void>() { - @Override - public Void answer(InvocationOnMock invocation) throws Throwable { - // Invoke callbacks with started message - delegate.messageReceived(startedMessage); - // Invoke callbacks with wrong ready message - IPCMessage message = mock(IPCMessage.class); - ByteBuffer badData = ByteBuffer.wrap("not the server started message".getBytes(Charset.forName("UTF-8"))); - when(message.get()).thenReturn(badData); - delegate.messageReceived(message); - verify(message, never()).reply(any(ByteBuffer.class)); - return null; - } - }).when(latch).await(); - - try { - delegate.startListening("127.0.0.1", 123); - fail("Expected IOException"); - } catch (IOException e) { - verify(ipcService).createServer(IPC_SERVER_NAME, delegate); - verify(processCreator).startProcess(any(ProcessBuilder.class)); - } - } - - @Test - public void testProcessCmdLine() throws IOException { - delegate.startListening("127.0.0.1", 123); - - String[] linuxArgs = new String[] { - "/path/to/thermostat/home/thermostat-command-channel", - "127.0.0.1", - "123", - "/path/to/ipc/config" - }; - - // in Windows we need to ensure the drive letter appears - by calling getAbsolutePath() - // avoid this call in non-windows to simplify test setup - String[] winArgs = OS.IS_WINDOWS ? new String[] { - "cmd", - "/c", - new File("/path/to/thermostat/home/thermostat-command-channel.cmd").getAbsolutePath(), - "127.0.0.1", - "123", - new File("/path/to/ipc/config").getAbsolutePath(), - Integer.toString(PortableProcessFactory.getInstance().getCurrentProcessPid()) - } : null; - - final String[] expectedArgs = OS.IS_UNIX ? linuxArgs : winArgs; - - ArgumentCaptor<ProcessBuilder> builderCaptor = ArgumentCaptor.forClass(ProcessBuilder.class); - verify(processCreator).startProcess(builderCaptor.capture()); - ProcessBuilder builder = builderCaptor.getValue(); - final List<String> actualArgs = builder.command(); - - assertEquals(Arrays.asList(expectedArgs), actualArgs); - assertEquals(Redirect.INHERIT, builder.redirectError()); - assertEquals(Redirect.INHERIT, builder.redirectOutput()); - assertEquals(Redirect.INHERIT, builder.redirectInput()); - } - - @Test - public void testStopListening() throws IOException { - delegate.startListening("127.0.0.1", 123); - when(ipcService.serverExists(IPC_SERVER_NAME)).thenReturn(true); - delegate.stopListening(); - - verify(process).destroy(); - verify(ipcService).destroyServer(IPC_SERVER_NAME); - } - - @Test - public void testStopListeningNotExist() throws IOException { - delegate.startListening("127.0.0.1", 123); - delegate.stopListening(); - - verify(process).destroy(); - verify(ipcService, never()).destroyServer(IPC_SERVER_NAME); - } - - @Test - public void testRequestReceived() throws IOException { - RequestReceiver receiver = mock(RequestReceiver.class); - Request request = createRequest(receiver); - - byte[] result = receiveRequestAndReturnResponse(request); - verify(receivers).getReceiver("com.example.MyReceiver"); - verify(receiver).receive(request); - - assertArrayEquals(ENCODED_RESPONSE_OK, result); - } - - private byte[] receiveRequestAndReturnResponse(Request request) throws IOException { - delegate.startListening("127.0.0.1", 123); - - // Receive encoded request - when(requestDecoder.decodeRequest(ENCODED_REQUEST)).thenReturn(request); - IPCMessage message = mock(IPCMessage.class); - ByteBuffer data = ByteBuffer.wrap(ENCODED_REQUEST); - when(message.get()).thenReturn(data); - delegate.messageReceived(message); - - return getReply(message); - } - - private byte[] getReply(IPCMessage message) throws IOException { - ArgumentCaptor<ByteBuffer> replyCaptor = ArgumentCaptor.forClass(ByteBuffer.class); - verify(message).reply(replyCaptor.capture()); - ByteBuffer reply = replyCaptor.getValue(); - return reply.array(); - } - - @Test - public void testRequestReceivedParseFail() throws IOException { - delegate.startListening("127.0.0.1", 123); - - RequestReceiver receiver = mock(RequestReceiver.class); - Request request = createRequest(receiver); - - // Should catch exception and return error response - when(requestDecoder.decodeRequest(ENCODED_REQUEST)).thenThrow(new IOException("TEST")); - - IPCMessage message = mock(IPCMessage.class); - ByteBuffer data = ByteBuffer.wrap(ENCODED_REQUEST); - when(message.get()).thenReturn(data); - delegate.messageReceived(message); - - byte[] result = getReply(message); - verify(receivers, never()).getReceiver("com.example.MyReceiver"); - verify(receiver, never()).receive(request); - - assertArrayEquals(ENCODED_RESPONSE_ERROR, result); - } - - @Test - public void testRequestReceivedNoReceiver() throws IOException { - Request request = mock(Request.class); - when(request.getType()).thenReturn(RequestType.RESPONSE_EXPECTED); - - byte[] result = receiveRequestAndReturnResponse(request); - assertArrayEquals(ENCODED_RESPONSE_ERROR, result); - } - - @Test - public void testRequestReceivedNoType() throws IOException { - Request request = mock(Request.class); - - when(request.getReceiver()).thenReturn("com.example.MyReceiver"); - RequestReceiver receiver = mock(RequestReceiver.class); - when(receivers.getReceiver("com.example.MyReceiver")).thenReturn(receiver); - when(receiver.receive(request)).thenReturn(new Response(ResponseType.OK)); - - byte[] result = receiveRequestAndReturnResponse(request); - verify(receiver, never()).receive(request); - assertArrayEquals(ENCODED_RESPONSE_ERROR, result); - } - - private Request createRequest(RequestReceiver receiver) { - Request request = mock(Request.class); - when(request.getType()).thenReturn(RequestType.RESPONSE_EXPECTED); - - when(request.getReceiver()).thenReturn("com.example.MyReceiver"); - when(receivers.getReceiver("com.example.MyReceiver")).thenReturn(receiver); - when(receiver.receive(request)).thenReturn(new Response(ResponseType.OK)); - return request; - } - -} -
--- a/agent/command/src/test/java/com/redhat/thermostat/agent/command/internal/SSLConfigurationEncoderTest.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,140 +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.agent.command.internal; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.io.File; -import java.io.IOException; -import java.nio.charset.Charset; - -import com.google.gson.JsonElement; -import com.google.gson.JsonParser; -import com.redhat.thermostat.shared.config.OS; -import com.redhat.thermostat.testutils.TestUtils; -import org.junit.Before; -import org.junit.Test; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonObject; -import com.redhat.thermostat.shared.config.SSLConfiguration; - -public class SSLConfigurationEncoderTest { - - private static final String KEYSTORE_PASS = "My Keystore Password"; - private static final String KEYSTORE_FILE = "/path/to/keystore"; - private SSLConfiguration sslConf; - - @Before - public void setUp() { - sslConf = mock(SSLConfiguration.class); - File keystore = new File(KEYSTORE_FILE); - when(sslConf.getKeystoreFile()).thenReturn(keystore); - when(sslConf.getKeyStorePassword()).thenReturn(KEYSTORE_PASS); - when(sslConf.enableForBackingStorage()).thenReturn(true); - when(sslConf.enableForCmdChannel()).thenReturn(true); - when(sslConf.disableHostnameVerification()).thenReturn(false); - } - - @Test - public void testSSLConfig() throws IOException { - String expected = getJsonString(KEYSTORE_FILE, KEYSTORE_PASS); - String result = getEncodedSSLConfiguration(); - result = fixKeystorePath(result); - assertEquals(expected, result); - } - - @Test - public void testSSLConfigNoKeystoreFile() throws IOException { - when(sslConf.getKeystoreFile()).thenReturn(null); - - String expected = getJsonString(null, KEYSTORE_PASS); - String result = getEncodedSSLConfiguration(); - // no need to fix the keystore path here, because the path is NULL - assertEquals(expected, result); - } - - @Test - public void testSSLConfigNoKeystorePass() throws IOException { - when(sslConf.getKeyStorePassword()).thenReturn(null); - - String expected = getJsonString(KEYSTORE_FILE, null); - String result = getEncodedSSLConfiguration(); - result = fixKeystorePath(result); - assertEquals(expected, result); - } - - private String getEncodedSSLConfiguration() throws IOException { - SSLConfigurationEncoder encoder = new SSLConfigurationEncoder(); - byte[] encoded = encoder.encodeAsJson(sslConf); - return new String(encoded, Charset.forName("UTF-8")); - } - - private String getJsonString(String keystoreFile, String keystorePass) { - GsonBuilder builder = new GsonBuilder(); - builder.serializeNulls(); - Gson gson = builder.create(); - - JsonObject params = new JsonObject(); - params.addProperty(CommandChannelConstants.SSL_JSON_KEYSTORE_FILE, keystoreFile); - params.addProperty(CommandChannelConstants.SSL_JSON_KEYSTORE_PASS, keystorePass); - params.addProperty(CommandChannelConstants.SSL_JSON_COMMAND_CHANNEL, true); - params.addProperty(CommandChannelConstants.SSL_JSON_BACKING_STORAGE, true); - params.addProperty(CommandChannelConstants.SSL_JSON_HOSTNAME_VERIFICATION, false); - - JsonObject sslConfigJson = new JsonObject(); - sslConfigJson.add(CommandChannelConstants.SSL_JSON_ROOT, params); - return gson.toJson(sslConfigJson); - } - - private String fixKeystorePath( final String json ) { - if (OS.IS_UNIX) { - return json; - } - else { - // on Windows, patch the filename to appear in Unix format - JsonElement je = new JsonParser().parse(json); - JsonObject jo = je.getAsJsonObject(); - final String fn = jo.get("sslConfiguration").getAsJsonObject().get("keystoreFile").getAsString(); - jo.get("sslConfiguration").getAsJsonObject().addProperty("keystoreFile", TestUtils.convertWinPathToUnixPath(fn)); - return je.toString(); - } - } -}
--- a/agent/core/src/main/java/com/redhat/thermostat/agent/Agent.java Tue Jun 13 12:02:12 2017 +0200 +++ b/agent/core/src/main/java/com/redhat/thermostat/agent/Agent.java Mon Jun 12 20:50:03 2017 +0200 @@ -49,7 +49,6 @@ import com.redhat.thermostat.common.ActionListener; import com.redhat.thermostat.common.LaunchException; import com.redhat.thermostat.common.ThermostatExtensionRegistry; -import com.redhat.thermostat.common.utils.HostPortPair; import com.redhat.thermostat.common.utils.LoggingUtils; import com.redhat.thermostat.storage.core.WriterID; import com.redhat.thermostat.storage.dao.AgentInfoDAO; @@ -175,10 +174,6 @@ AgentInformation agentInfo = new AgentInformation(writerId); agentInfo.setStartTime(config.getStartTime()); agentInfo.setAlive(true); - // Report the configured publish address if any. Otherwise, - // defaults to (agent-local) configured listen address. - HostPortPair publishAddress = config.getConfigPublishAddress(); - agentInfo.setConfigListenAddress(publishAddress.toExternalForm()); return agentInfo; }
--- a/agent/core/src/main/java/com/redhat/thermostat/agent/config/AgentConfigsUtils.java Tue Jun 13 12:02:12 2017 +0200 +++ b/agent/core/src/main/java/com/redhat/thermostat/agent/config/AgentConfigsUtils.java Mon Jun 12 20:50:03 2017 +0200 @@ -92,19 +92,6 @@ configuration.setPurge(true); } - String configListenAddress = properties.getProperty(AgentProperties.CONFIG_LISTEN_ADDRESS.name()); - if (configListenAddress != null) { - configuration.setConfigListenAddress(configListenAddress); - } else { - // TODO: we could avoid this, which means the agent doesn't want to - // accept any connection - configuration.setConfigListenAddress("127.0.0.1:12000"); - } - - String configPublishAddress = properties.getProperty(AgentProperties.CONFIG_PUBLISH_ADDRESS.name()); - if (configPublishAddress != null) { - configuration.setConfigPublishAddress(configPublishAddress); - } } }
--- a/agent/core/src/main/java/com/redhat/thermostat/agent/config/AgentProperties.java Tue Jun 13 12:02:12 2017 +0200 +++ b/agent/core/src/main/java/com/redhat/thermostat/agent/config/AgentProperties.java Mon Jun 12 20:50:03 2017 +0200 @@ -40,7 +40,5 @@ DB_URL, SAVE_ON_EXIT, - CONFIG_LISTEN_ADDRESS, - CONFIG_PUBLISH_ADDRESS, }
--- a/agent/core/src/main/java/com/redhat/thermostat/agent/config/AgentStartupConfiguration.java Tue Jun 13 12:02:12 2017 +0200 +++ b/agent/core/src/main/java/com/redhat/thermostat/agent/config/AgentStartupConfiguration.java Mon Jun 12 20:50:03 2017 +0200 @@ -36,10 +36,6 @@ package com.redhat.thermostat.agent.config; -import java.util.List; - -import com.redhat.thermostat.common.utils.HostPortPair; -import com.redhat.thermostat.common.utils.HostPortsParser; import com.redhat.thermostat.storage.config.StartupConfiguration; public class AgentStartupConfiguration implements StartupConfiguration { @@ -47,8 +43,6 @@ private boolean purge; private String url; private long startTime; - private HostPortPair listenAddr; - private HostPortPair publishAddr; AgentStartupConfiguration() { } @@ -78,36 +72,5 @@ public boolean purge() { return purge; } - - public void setConfigListenAddress(String address) { - this.listenAddr = parseAddress(address); - } - - public HostPortPair getConfigListenAddress() { - return listenAddr; - } - - public void setConfigPublishAddress(String address) { - this.publishAddr = parseAddress(address); - } - - public HostPortPair getConfigPublishAddress() { - if (publishAddr != null) { - return publishAddr; - } - // Otherwise default to configured listen address - // as the publish address for backwards compat reasons. - return listenAddr; - } - - private HostPortPair parseAddress(String address) throws AssertionError { - HostPortsParser parser = new HostPortsParser(address); - parser.parse(); - List<HostPortPair> list = parser.getHostsPorts(); - if (list.size() != 1) { - throw new AssertionError("Multiple listen addresses not supported! Got: " + address); - } - return parser.getHostsPorts().get(0); - } }
--- a/agent/core/src/test/java/com/redhat/thermostat/agent/AgentTest.java Tue Jun 13 12:02:12 2017 +0200 +++ b/agent/core/src/test/java/com/redhat/thermostat/agent/AgentTest.java Mon Jun 12 20:50:03 2017 +0200 @@ -58,7 +58,6 @@ import com.redhat.thermostat.common.ActionEvent; import com.redhat.thermostat.common.ActionListener; import com.redhat.thermostat.common.ThermostatExtensionRegistry; -import com.redhat.thermostat.common.utils.HostPortPair; import com.redhat.thermostat.storage.core.WriterID; import com.redhat.thermostat.storage.dao.AgentInfoDAO; import com.redhat.thermostat.storage.dao.BackendInfoDAO; @@ -84,7 +83,6 @@ config = mock(AgentStartupConfiguration.class); when(config.getStartTime()).thenReturn(123L); when(config.purge()).thenReturn(true); - when(config.getConfigPublishAddress()).thenReturn(new HostPortPair("foo", 23)); agentInfoDao = mock(AgentInfoDAO.class); backendInfoDao = mock(BackendInfoDAO.class); @@ -208,7 +206,6 @@ AgentStartupConfiguration config = mock(AgentStartupConfiguration.class); when(config.getStartTime()).thenReturn(123L); when(config.purge()).thenReturn(false); - when(config.getConfigPublishAddress()).thenReturn(new HostPortPair("foo", 23)); WriterID id = mock(WriterID.class); Agent agent = new Agent(backendRegistry, config, agentInfoDao, backendInfoDao, id, poolTracker);
--- a/agent/core/src/test/java/com/redhat/thermostat/agent/config/AgentConfigsUtilsTest.java Tue Jun 13 12:02:12 2017 +0200 +++ b/agent/core/src/test/java/com/redhat/thermostat/agent/config/AgentConfigsUtilsTest.java Mon Jun 12 20:50:03 2017 +0200 @@ -44,7 +44,6 @@ import org.junit.Assert; import org.junit.Test; -import com.redhat.thermostat.common.utils.HostPortPair; import com.redhat.thermostat.shared.config.InvalidConfigurationException; import com.redhat.thermostat.testutils.TestUtils; @@ -80,22 +79,6 @@ } @Test - public void testSystemAddressProp() { - Properties sysProps = createSystemProperties(); - setConfigs(sysProps, new Properties()); - AgentStartupConfiguration config = AgentConfigsUtils.createAgentConfigs(); - - HostPortPair hostPorts = config.getConfigListenAddress(); - Assert.assertEquals("42.42.42.42", hostPorts.getHost()); - Assert.assertEquals(42, hostPorts.getPort()); - - // Not explicitly set, should default to config listen address - HostPortPair publishAddr = config.getConfigPublishAddress(); - Assert.assertEquals("42.42.42.42", publishAddr.getHost()); - Assert.assertEquals(42, publishAddr.getPort()); - } - - @Test public void testUserDbUrl() throws InvalidConfigurationException, IOException { Properties sysProps = createSystemProperties(); Properties userProps = createUserProperties(); @@ -115,69 +98,6 @@ Assert.assertTrue(config.purge()); } - @Test - public void testUserAddressProp() { - Properties sysProps = createSystemProperties(); - Properties userProps = createUserProperties(); - setConfigs(sysProps, userProps); - AgentStartupConfiguration config = AgentConfigsUtils.createAgentConfigs(); - - HostPortPair hostPorts = config.getConfigListenAddress(); - Assert.assertEquals("24.24.24.24", hostPorts.getHost()); - Assert.assertEquals(24, hostPorts.getPort()); - - // Not explicitly set, should default to config listen address - HostPortPair publishAddr = config.getConfigPublishAddress(); - Assert.assertEquals("24.24.24.24", publishAddr.getHost()); - Assert.assertEquals(24, publishAddr.getPort()); - } - - @Test - public void canParseIpv6ConfigAddress() { - String ipV6AddressPair = "[::1]:12000"; - Properties sysProps = createSystemProperties(ipV6AddressPair); - setConfigs(sysProps, new Properties()); - AgentStartupConfiguration config = AgentConfigsUtils.createAgentConfigs(); - - HostPortPair listenAddr = config.getConfigListenAddress(); - Assert.assertEquals("::1", listenAddr.getHost()); - Assert.assertEquals(12000, listenAddr.getPort()); - } - - @Test - public void canOptionallySetSystemPublishAddress() { - Properties sysProps = createSystemProperties(); - sysProps.put("CONFIG_PUBLISH_ADDRESS", "foo.example.com:9999"); - setConfigs(sysProps, new Properties()); - AgentStartupConfiguration config = AgentConfigsUtils.createAgentConfigs(); - - HostPortPair listenAddr = config.getConfigListenAddress(); - Assert.assertEquals("42.42.42.42", listenAddr.getHost()); - Assert.assertEquals(42, listenAddr.getPort()); - - HostPortPair publishAddr = config.getConfigPublishAddress(); - Assert.assertEquals("foo.example.com", publishAddr.getHost()); - Assert.assertEquals(9999, publishAddr.getPort()); - } - - @Test - public void canOptionallySetUserPublishAddress() { - Properties sysProps = createSystemProperties(); - sysProps.put("CONFIG_PUBLISH_ADDRESS", "foo.example.com:9999"); - Properties userProps = createUserProperties(); - userProps.put("CONFIG_PUBLISH_ADDRESS", "33.33.33.33:9333"); - setConfigs(sysProps, userProps); - AgentStartupConfiguration config = AgentConfigsUtils.createAgentConfigs(); - - HostPortPair listenAddr = config.getConfigListenAddress(); - Assert.assertEquals("24.24.24.24", listenAddr.getHost()); - Assert.assertEquals(24, listenAddr.getPort()); - - HostPortPair publishAddr = config.getConfigPublishAddress(); - Assert.assertEquals("33.33.33.33", publishAddr.getHost()); - Assert.assertEquals(9333, publishAddr.getPort()); - } - private Properties createSystemProperties(String configListenAddress) { return doCreateSystemProperties(configListenAddress); }
--- a/agent/core/src/test/java/com/redhat/thermostat/agent/config/AgentStartupConfigurationTest.java Tue Jun 13 12:02:12 2017 +0200 +++ /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.agent.config; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; - -import org.junit.Before; -import org.junit.Test; - -import com.redhat.thermostat.common.utils.HostPortPair; - -public class AgentStartupConfigurationTest { - - private static final String IP_V4_LISTEN_ADDRESS = "127.0.0.1:12000"; - private static final String IP_V6_LISTEN_ADDRESS = "[::1]:12000"; - - private AgentStartupConfiguration config; - - @Before - public void setup() { - config = new AgentStartupConfiguration(); - } - - @Test - public void testIPv4ConfigListenAddress() { - config.setConfigListenAddress(IP_V4_LISTEN_ADDRESS); - HostPortPair hostPort = config.getConfigListenAddress(); - assertEquals("127.0.0.1", hostPort.getHost()); - assertEquals(12000, hostPort.getPort()); - } - - @Test - public void testIPv6ConfigListenAddress() { - config.setConfigListenAddress(IP_V6_LISTEN_ADDRESS); - HostPortPair hostPort = config.getConfigListenAddress(); - assertEquals("::1", hostPort.getHost()); - assertEquals(12000, hostPort.getPort()); - } - - @Test - public void noPublishAddressDefaultsToListenAddress() { - config.setConfigListenAddress(IP_V6_LISTEN_ADDRESS); - HostPortPair publishAddr = config.getConfigPublishAddress(); - assertNotNull(publishAddr); - assertEquals("::1", publishAddr.getHost()); - assertEquals(12000, publishAddr.getPort()); - } - - @Test - public void canSetPublishAddressIndependentOfListenAddress() { - config.setConfigListenAddress(IP_V6_LISTEN_ADDRESS); - config.setConfigPublishAddress("foo.example.com:9212"); - HostPortPair publishAddr = config.getConfigPublishAddress(); - assertNotNull(publishAddr); - assertEquals("foo.example.com", publishAddr.getHost()); - assertEquals(9212, publishAddr.getPort()); - HostPortPair listenAddr = config.getConfigListenAddress(); - assertFalse(listenAddr.toExternalForm().equals(publishAddr.toExternalForm())); - } -}
--- a/agent/pom.xml Tue Jun 13 12:02:12 2017 +0200 +++ b/agent/pom.xml Mon Jun 12 20:50:03 2017 +0200 @@ -61,8 +61,6 @@ <modules> <module>cli</module> <module>core</module> - <module>command</module> - <module>command-server</module> <module>ipc</module> <module>proxy</module> </modules>
--- a/common/command/pom.xml Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,100 +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-common</artifactId> - <version>1.99.12-SNAPSHOT</version> - </parent> - - <artifactId>thermostat-common-command</artifactId> - <packaging>bundle</packaging> - - <name>Thermostat Command Channel Common Library</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>io.netty</groupId> - <artifactId>netty-handler</artifactId> - </dependency> - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-common-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-Vendor>Red Hat, Inc.</Bundle-Vendor> - <Bundle-Activator /> - <Bundle-SymbolicName>com.redhat.thermostat.common.command</Bundle-SymbolicName> - <Export-Package> - com.redhat.thermostat.common.command, - com.redhat.thermostat.common.command.noapi - </Export-Package> - <Private-Package /> - <!-- Do not autogenerate uses clauses in Manifests --> - <_nouses>true</_nouses> - </instructions> - </configuration> - </plugin> - </plugins> - </build> - -</project> -
--- a/common/command/src/main/java/com/redhat/thermostat/common/command/InvalidMessageException.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +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.common.command; - -/** - * Exception thrown when an improperly encoded {@link Message} has been received. - * - */ -@SuppressWarnings("serial") -public class InvalidMessageException extends Exception { - - public InvalidMessageException(String message) { - super(message); - } -} -
--- a/common/command/src/main/java/com/redhat/thermostat/common/command/Message.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +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.common.command; - -/** - * Base interface for the various message types. - * - * @see Request - * @see Response - */ -public interface Message { - - interface MessageType { - } - - MessageType getType(); - -} -
--- a/common/command/src/main/java/com/redhat/thermostat/common/command/Messages.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,94 +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.common.command; - -import java.util.Collection; - -/** - * Helper class for comparing messages, such as {@link Request} and - * {@link Response}. - * - */ -public class Messages { - - /** - * Two requests, a and b, are considered equal if and only if they are, - * not-null, of the same type and all parameters (all keys and values) - * match. Listeners and targets are ignored. - * - * @return true if a and b are both not-null and equal. false otherwise. - */ - public static boolean equal(Request a, Request b) { - if (a == null || b == null) { - return false; - } - // type needs to be the same - if (a.getType() != b.getType()) { - return false; - } - // all parameters and values need to match - Collection<String> ourParamValues = a.getParameterNames(); - Collection<String> otherParamValues = b.getParameterNames(); - if (ourParamValues.size() != otherParamValues.size()) { - return false; - } - for (String name: ourParamValues) { - String otherParamValue = b.getParameter(name); - if (otherParamValue == null) { - // other doesn't have param which we have - return false; - } else { - // both requests contain same param name - String ourParamValue = a.getParameter(name); - if (!ourParamValue.equals(otherParamValue)) { - return false; - } - } - } - return true; - } - - /** - * Two responses are equal if and only if they are of the same type. - * - * @return true if a and b are both not-null and are equal. false otherwise. - */ - public static boolean equal(Response a, Response b) { - return a.getType() == b.getType(); - } -} -
--- a/common/command/src/main/java/com/redhat/thermostat/common/command/Request.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,161 +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.common.command; - -import java.net.InetSocketAddress; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * <p> - * A Request object represents a request passed from a client - * to an agent. Each request is separate, complete and unordered. The - * agent may or may not take an action when it receives a request. - * </p> - * <p> - * Requests are meant for controlling the agent, not for asking an - * agent nor sending an agent any sort of data. - * </p> - */ -public class Request implements Message { - - private static final String RECEIVER = "receiver"; - - public static final String CLIENT_TOKEN = "client-token"; - public static final String AUTH_TOKEN = "auth-token"; - public static final String ACTION = "action-name"; - public static final String UNKNOWN_HOSTNAME = ""; - - private static final String FILTERED_PARAM_VALUE = "<filtered>"; - private static final Set<String> FILTERED_PARAMS; - - static { - FILTERED_PARAMS = new HashSet<>(); - FILTERED_PARAMS.add(AUTH_TOKEN); - FILTERED_PARAMS.add(CLIENT_TOKEN); - } - - - public enum RequestType implements MessageType { - NO_RESPONSE_EXPECTED, - RESPONSE_EXPECTED, - MULTIPART_RESPONSE_EXPECTED; - } - - private final RequestType type; - private final Map<String, String> parameters; - private final InetSocketAddress target; - private final Collection<RequestResponseListener> listeners; - - - public Request(RequestType type, InetSocketAddress target) { - this.type = type; - parameters = new TreeMap<>(); - this.target = target; - listeners = new CopyOnWriteArrayList<>(); - } - - @Override - public MessageType getType() { - return type; - } - - public void setParameter(String name, String value) { - parameters.put(name, value); - } - - public String getParameter(String name) { - return parameters.get(name); - } - - public Collection<String> getParameterNames() { - return parameters.keySet(); - } - - public void setReceiver(String clazz) { - setParameter(RECEIVER, clazz); - } - - public String getReceiver() { - return getParameter(RECEIVER); - } - - public InetSocketAddress getTarget() { - return target; - } - - public void addListener(RequestResponseListener listener) { - listeners.add(listener); - } - - public void removeListener(RequestResponseListener listener) { - listeners.remove(listener); - } - - public Collection<RequestResponseListener> getListeners() { - return Collections.unmodifiableCollection(listeners); - } - - @Override - public String toString() { - Map<String, String> filteredParams = getFilteredParams(parameters); - return "{ Request: {target = " + target.toString() + "}, {type = " + - type.name() + "}, {parameters = " + filteredParams + - "} }"; - } - - // package-private for testing - Map<String, String> getFilteredParams(Map<String, String> unfiltered) { - Map<String, String> filtered = new TreeMap<>(); - for (String key: unfiltered.keySet()) { - if (FILTERED_PARAMS.contains(key)) { - // actual value may be security sensitive - filtered.put(key, FILTERED_PARAM_VALUE); - } else { - filtered.put(key, unfiltered.get(key)); - } - } - return filtered; - } - -} -
--- a/common/command/src/main/java/com/redhat/thermostat/common/command/RequestResponseListener.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +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.common.command; - -/** - * A listener that is notified of the response to given request. - */ -public interface RequestResponseListener { - - public void fireComplete(Request request, Response response); - -} -
--- a/common/command/src/main/java/com/redhat/thermostat/common/command/Response.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,97 +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.common.command; - - -/** - * A Response object represents a response message passed from an agent - * to a client. Responses must not be used to send data; they reach only a - * specific client and are not recorded. - * <p> - * The implementation details of this class are subject to change at any time. - * <p> - * Response objects are serialized over the command channel in the following - * format: - * <pre> - * ------------ - * | A | TYPE | - * ------------ - * </pre> - * A is an 32 bit integer representing the length - in bytes - of TYPE. TYPE - * is a byte array representing the string of the response type (e.g. - * "OK"). - */ -public class Response implements Message { - - // TODO add parameter support to provide more information in some of these types. - public enum ResponseType implements MessageType { - /** Request has been acknowledged and completed agent-side */ - OK, - - /** Request has been acknowledged and refused agent-side. */ - NOK, - - /** - * Request has been acknowledged, but no action deemed necessary - * agent-side. - */ - NOOP, - - /** - * An error occurred. The status of the request is not known. - */ - ERROR, - - /** - * When authentication fails in SecureStorage. - */ - AUTH_FAILED; - } - - private ResponseType type; - - public Response (ResponseType type) { - this.type = type; - } - - @Override - public ResponseType getType() { - return type; - } - -} -
--- a/common/command/src/main/java/com/redhat/thermostat/common/command/noapi/ConfigurationCommandContext.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +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.common.command.noapi; - -import com.redhat.thermostat.shared.config.SSLConfiguration; - -import io.netty.bootstrap.AbstractBootstrap; - -public interface ConfigurationCommandContext { - - public AbstractBootstrap<?, ?> getBootstrap(); - - public SSLConfiguration getSSLConfiguration(); - -} -
--- a/common/command/src/main/java/com/redhat/thermostat/common/command/noapi/DecodingHelper.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,158 +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.common.command.noapi; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; - -public class DecodingHelper { - - /** - * Attempts to decode a String from the given buffer, carefully not changing - * the reader index of the buffer. The returned decoding context will tell - * you if the decoding has fully completed and if so how many bytes have - * been consumed. It's the callers responsibility to free the buffer's - * resources. Set the {@link ByteBuf#readerIndex(int)} to the value as - * returned by the decoding context and then discard bytes using - * {@link ByteBuf#discardReadBytes()}. - * - * @param buffer - * The buffer from which to decode the String from. - * - * @return A decoding context giving you details about the decoding status - * and a way to retrieve the decoded value. - */ - public static StringDecodingContext decodeString(ByteBuf buffer) { - StringDecodingContext ctx = new StringDecodingContext(); - return decodeString(buffer, ctx); - } - - private static StringDecodingContext decodeString(ByteBuf buffer, StringDecodingContext ctx) { - if (buffer.readableBytes() < 4) { - ctx.setState(StringDecodingState.INCOMPLETE_LENGTH_VAL); - return ctx; - } - int length = buffer.getInt(buffer.readerIndex()); - ctx.addToBytesRead(4); - ctx.setState(StringDecodingState.LENGTH_READ); - return decodeString(length, buffer, ctx); - } - - /** - * Attempts to decode String parameters from the given buffer, carefully not - * changing the reader index of the buffer. The returned decoding context - * will tell you if the decoding has fully completed and if so how many - * bytes have been consumed. It's the callers responsibility to free the - * buffer's resources. Set the {@link ByteBuf#readerIndex(int)} to the value - * as returned by the decoding context and then discard bytes using - * {@link ByteBuf#discardReadBytes()}. - * - * @param buffer The buffer from which to decode the parameters from. - * @return A decoding context giving you details about the decoding status - * and a way to retrieve the decoded parameters. - */ - public static ParameterDecodingContext decodeParameters(ByteBuf buffer) { - ParameterDecodingContext ctx = new ParameterDecodingContext(); - return decodeParameters(buffer, ctx); - } - - private static ParameterDecodingContext decodeParameters(ByteBuf buffer, ParameterDecodingContext ctx) { - if (buffer.readableBytes() < 4) { - ctx.setState(ParameterDecodingState.INCOMPLETE_PARAMS_LENGTH); - return ctx; - } - int numParms = buffer.getInt(buffer.readerIndex()); - ctx.addToBytesRead(4); - ctx.setState(ParameterDecodingState.PARAMS_LENGTH_READ); - for (int i = 0; i < numParms; i++) { - decodeParameter(buffer, ctx); - } - if ( (ctx.getState() == ParameterDecodingState.PARAMS_LENGTH_READ && numParms == 0) - || ctx.getState() == ParameterDecodingState.PARAM_KV_DATA_PLUS_ONE_READ) { - // Either zero parameters, or all params successfully read - ctx.setState(ParameterDecodingState.ALL_PARAMETERS_READ); - } - return ctx; - } - - private static void decodeParameter(ByteBuf buffer, ParameterDecodingContext ctx) { - if (buffer.readableBytes() < ctx.getBytesRead() + 8) { - ctx.setState(ParameterDecodingState.INCOMPLETE_PARAM_KV_LENGTH); - return; - } - int currIdx = buffer.readerIndex() + ctx.getBytesRead(); - int nameLength = buffer.getInt(currIdx); - int valueLength = buffer.getInt(currIdx + 4); - ctx.setState(ParameterDecodingState.PARAM_KV_LENGTH_READ); - ctx.addToBytesRead(8); - int nameStartIdx = buffer.readerIndex() + ctx.getBytesRead(); - ByteBuf nameBuf = buffer.slice(nameStartIdx, buffer.readableBytes() - nameStartIdx); - StringDecodingContext nameCtx = decodeString(nameLength, nameBuf, new StringDecodingContext()); - if (nameCtx.getState() != StringDecodingState.VALUE_READ) { - ctx.setState(ParameterDecodingState.INCOMPLETE_PARAM_KV_DATA); - return; - } - String name = nameCtx.getValue(); - ctx.addToBytesRead(nameCtx.getBytesRead()); - int valueStartIdx = buffer.readerIndex() + ctx.getBytesRead(); - ByteBuf valueBuf = buffer.slice(valueStartIdx, buffer.readableBytes() - valueStartIdx); - StringDecodingContext valueCtx = decodeString(valueLength, valueBuf, new StringDecodingContext()); - if (valueCtx.getState() != StringDecodingState.VALUE_READ) { - ctx.setState(ParameterDecodingState.INCOMPLETE_PARAM_KV_DATA); - return; - } - String value = valueCtx.getValue(); - ctx.addToBytesRead(valueCtx.getBytesRead()); - ctx.setState(ParameterDecodingState.PARAM_KV_DATA_PLUS_ONE_READ); - ctx.addParameter(name, value); - } - - private static StringDecodingContext decodeString(int length, ByteBuf buffer, StringDecodingContext ctx) { - if (buffer.readableBytes() < ctx.getBytesRead() + length) { - ctx.setState(StringDecodingState.INCOMPLETE_STR_VAL); - return ctx; - } - int startIdx = buffer.readerIndex() + ctx.getBytesRead(); - ByteBuf valueBuf = buffer.slice(startIdx, length); - byte[] stringBytes = Unpooled.copiedBuffer(valueBuf).array(); - ctx.setState(StringDecodingState.VALUE_READ); - ctx.addToBytesRead(length); - ctx.setValue(new String(stringBytes)); - return ctx; - } -} -
--- a/common/command/src/main/java/com/redhat/thermostat/common/command/noapi/EncodingHelper.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +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.common.command.noapi; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; - -public class EncodingHelper { - - public static void encode(String name, String value, ByteBuf dynamicBuffer) { - byte[] nameBytes = name.getBytes(); - byte[] valueBytes = value.getBytes(); - dynamicBuffer.writeInt(nameBytes.length); - dynamicBuffer.writeInt(valueBytes.length); - dynamicBuffer.writeBytes(nameBytes); - dynamicBuffer.writeBytes(valueBytes); - } - - public static ByteBuf encode(String value) { - byte[] valBytes = value.getBytes(); - int length = 4 + valBytes.length; - ByteBuf buf = Unpooled.buffer(length, length); - buf.writeInt(valBytes.length); - buf.writeBytes(valBytes); - return buf; - } - - public static String trimType(String full) { - int typePointer = full.lastIndexOf('.'); - return full.substring(typePointer + 1); - } - -} -
--- a/common/command/src/main/java/com/redhat/thermostat/common/command/noapi/MessageEncoder.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +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.common.command.noapi; - -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.redhat.thermostat.common.command.Message; -import com.redhat.thermostat.common.utils.LoggingUtils; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.MessageToByteEncoder; - -public abstract class MessageEncoder extends MessageToByteEncoder<Message> { - - private static final Logger logger = LoggingUtils.getLogger(MessageEncoder.class); - - protected MessageEncoder() { - super(); - } - - @Override - public void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) { - ByteBuf encodedMessage = encode(msg); - out.writeBytes(encodedMessage); - } - - /** - * Transforms the specified message into another message and return the - * transformed message. Note that you can not return {@code null}, unlike - * you can in - * {@link MessageDecoder#decode(org.jboss.netty.buffer.ChannelBuffer)}; you - * must return something, at least {@link ChannelBuffers#EMPTY_BUFFER}. - */ - protected abstract ByteBuf encode(Message originalMessage); - - @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { - logger.log(Level.WARNING, "Exception caught", cause); - ctx.close(); - } -} -
--- a/common/command/src/main/java/com/redhat/thermostat/common/command/noapi/ParameterDecodingContext.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,99 +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.common.command.noapi; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -/** - * Parameter decoding context. - * - * @see DecodingHelper - * @see ParameterDecodingState - */ -public class ParameterDecodingContext { - - ParameterDecodingContext() { - // package-private constructor. Only this package creates instances. - } - - private final Map<String, String> values = new HashMap<>(); - private ParameterDecodingState state; - private int bytesRead; - - /** - * - * @return A map of parameter {@code key=value} pairs. - * - * @throws IllegalStateException if not all parameters have yet been decoded. - */ - public Map<String, String> getValues() { - if (state != ParameterDecodingState.ALL_PARAMETERS_READ) { - throw new IllegalStateException("Not all parameters have yet been decoded"); - } - return Collections.unmodifiableMap(values); - } - - /** - * - * @return The current decoding state. - */ - public ParameterDecodingState getState() { - return state; - } - - /** - * - * @return The number of bytes consumed so far. - */ - public int getBytesRead() { - return bytesRead; - } - - void setState(ParameterDecodingState newState) { - state = newState; - } - - void addParameter(String key, String value) { - values.put(key, value); - } - - void addToBytesRead(int numBytes) { - bytesRead += numBytes; - } -}
--- a/common/command/src/main/java/com/redhat/thermostat/common/command/noapi/ParameterDecodingState.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +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.common.command.noapi; - -public enum ParameterDecodingState { - /** Insufficient data for decoding parameters */ - INCOMPLETE_PARAMS_LENGTH, - /** Number of parameters has been read */ - PARAMS_LENGTH_READ, - /** Insufficient data for decoding a parameter pair */ - INCOMPLETE_PARAM_KV_LENGTH, - /** Length of param's key/value has been read */ - PARAM_KV_LENGTH_READ, - /** Insufficient data for decoding values of a parameter pair */ - INCOMPLETE_PARAM_KV_DATA, - /** One (of potentially many) KV data pair decoded */ - PARAM_KV_DATA_PLUS_ONE_READ, - /** All parameters have been read from fragmented data */ - ALL_PARAMETERS_READ -}
--- a/common/command/src/main/java/com/redhat/thermostat/common/command/noapi/RequestEncoder.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,116 +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.common.command.noapi; - -import java.util.Collection; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.redhat.thermostat.common.command.Message; -import com.redhat.thermostat.common.command.Request; -import com.redhat.thermostat.common.utils.LoggingUtils; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.buffer.Unpooled; - -/** - * <p> - * {@link Request} objects are serialized over the command channel in the - * following format: - * <pre> - * ------------------------- - * | A | TYPE | B | PARAMS | - * ------------------------- - * - * A is an 32 bit integer representing the length - in bytes - of TYPE. TYPE - * is a byte array representing the string of the request type (e.g. - * "RESPONSE_EXPECTED") B is a 32 bit integer representing the number of - * request parameters which follow. - * - * PARAMS (if B > 0) is a variable length stream of the following format: - * - * It is a simple encoding of name => value pairs. - * - * ----------------------------------------------------------------------------------------------- - * | I_1 | K_1 | P_1 | V_1 | ... | I_(n-1) | K_(n-1) | P_(n-1) | V_(n-1) | I_n | K_n | P_n | V_n | - * ----------------------------------------------------------------------------------------------- - * - * I_n A 32 bit integer representing the length - in bytes - of the n'th - * parameter name. - * K_n A 32 bit integer representing the length - in bytes - of the n'th - * parameter value. - * P_n A byte array representing the string of the n'th parameter name. - * V_n A byte array representing the string of the n'th parameter value. - * </pre> - * </p> - */ -public class RequestEncoder extends MessageEncoder { - - private static final Logger logger = LoggingUtils.getLogger(RequestEncoder.class); - - /* - * See the javadoc of RequestEncoder for a description of the encoding. - */ - @Override - public ByteBuf encode(Message msg) { - // At this point we are only getting Messages. Since our only - // registered MessageEncoder is the one for Requests a cast - // to Request should be safe. - Request request = (Request) msg; - logger.log(Level.FINEST, "encoding Request object " + request.toString()); - - // Request Type - String requestType = EncodingHelper.trimType(request.getType() - .toString()); - ByteBuf typeBuffer = EncodingHelper.encode(requestType); - - // Parameters - ByteBuf parmsBuffer = Unpooled.buffer(); - Collection<String> parmNames = request.getParameterNames(); - parmsBuffer.writeInt(parmNames.size()); - for (String parmName : parmNames) { - EncodingHelper.encode(parmName, request.getParameter(parmName), - parmsBuffer); - } - // Compose the full message. - ByteBuf buf = Unpooled.wrappedBuffer(typeBuffer, parmsBuffer); - logger.log(Level.FINEST, "encoded reqest as: " + ByteBufUtil.hexDump(buf)); - return buf; - } -} -
--- a/common/command/src/main/java/com/redhat/thermostat/common/command/noapi/StringDecodingContext.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,93 +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.common.command.noapi; - -/** - * Context for decoding Strings. - * - * @see DecodingHelper - * @see StringDecodingState - */ -public class StringDecodingContext { - - StringDecodingContext() { - // package-private constructor. Only this package creates instances. - } - - private StringDecodingState state; - private String val; - private int bytesRead; - - /** - * - * @return The decoded String value. - */ - public String getValue() { - if (state != StringDecodingState.VALUE_READ) { - throw new IllegalStateException("Data not yet defragmented"); - } - return val; - } - - /** - * - * @return The current decoding state. - */ - public StringDecodingState getState() { - return state; - } - - /** - * - * @return The bytes read from a buffer. - */ - public int getBytesRead() { - return bytesRead; - } - - void setState(StringDecodingState newState) { - state = newState; - } - - void setValue(String value) { - val = value; - } - - void addToBytesRead(int value) { - bytesRead += value; - } -} \ No newline at end of file
--- a/common/command/src/main/java/com/redhat/thermostat/common/command/noapi/StringDecodingState.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +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.common.command.noapi; - -public enum StringDecodingState { - /** Not enough data to decode any String */ - INCOMPLETE_LENGTH_VAL, - /** - * Enough data to decode the length of the String, but not the String - * value just yet. - */ - LENGTH_READ, - /** Incomplete data for string value decoding. */ - INCOMPLETE_STR_VAL, - /** String length and value read **/ - VALUE_READ -} \ No newline at end of file
--- a/common/command/src/test/java/com/redhat/thermostat/common/command/MessagesTest.java Tue Jun 13 12:02:12 2017 +0200 +++ /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.common.command; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import org.junit.Test; - -import com.redhat.thermostat.common.command.Request.RequestType; -import com.redhat.thermostat.common.command.Response.ResponseType; - -public class MessagesTest { - - @Test - public void testRequestsEqual() { - // self - Request req1 = new Request(RequestType.RESPONSE_EXPECTED, null); - assertTrue(Messages.equal(req1, req1)); - req1.setParameter("test", "blah"); - assertTrue(Messages.equal(req1, req1)); - - req1 = new Request(RequestType.RESPONSE_EXPECTED, null); - // basics - assertFalse(Messages.equal((Request)null, (Request)null)); - assertFalse(Messages.equal(req1, null)); - assertFalse(Messages.equal(req1, new Request(RequestType.MULTIPART_RESPONSE_EXPECTED, null))); - - Request req2 = new Request(RequestType.RESPONSE_EXPECTED, null); - String receiverClassName = "com.example.receivers.MyReceiver"; - req1.setReceiver(receiverClassName); - req2.setReceiver(receiverClassName); - // receivers are parameters - assertTrue(Messages.equal(req1, req2)); - - // add parameters - req1.setParameter("fluff", "foo"); - req2.setParameter("fluff", "foo"); - assertTrue(Messages.equal(req1, req1)); - - // one key is different - req2.setParameter("test", "false"); - assertFalse(Messages.equal(req1, req2)); - - req1.setParameter("test", "false"); - assertTrue(Messages.equal(req1, req2)); - req2.setParameter("test", "true"); - assertFalse(Messages.equal(req1, req2)); - } - - @Test - public void testResponsesEqual() { - Response r = new Response(ResponseType.NOK); - assertTrue(Messages.equal(r, r)); - Response r2 = new Response(ResponseType.NOK); - assertTrue(Messages.equal(r, r2)); - Response r3 = new Response(ResponseType.OK); - assertFalse(Messages.equal(r2, r3)); - assertFalse(Messages.equal(r, r3)); - } -} -
--- a/common/command/src/test/java/com/redhat/thermostat/common/command/RequestTest.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,186 +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.common.command; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.net.InetSocketAddress; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import org.junit.Test; - -import com.redhat.thermostat.common.command.Request.RequestType; - -public class RequestTest { - - private class RequestResponseListenerImpl implements RequestResponseListener { - @Override - public void fireComplete(Request request, Response response) { - // Won't actually be used. - } - } - - private static final int PORT = 123; - private static final String HOST = "test.example.com"; - - @Test - public void testGetTypeAndTarget() { - Request request = new Request(RequestType.RESPONSE_EXPECTED, new InetSocketAddress(HOST, PORT)); - RequestType type = (RequestType) request.getType(); - assertEquals(RequestType.RESPONSE_EXPECTED, type); - - InetSocketAddress target = (InetSocketAddress) request.getTarget(); - assertEquals(PORT, target.getPort()); - assertEquals(HOST, target.getHostString()); - } - - @Test - public void testAddListener() { - Request request = new Request(RequestType.RESPONSE_EXPECTED, new InetSocketAddress(HOST, PORT)); - RequestResponseListener listener1 = new RequestResponseListenerImpl(); - RequestResponseListener listener2 = new RequestResponseListenerImpl(); - request.addListener(listener1); - request.addListener(listener2); - Collection<RequestResponseListener> listeners = request.getListeners(); - assertEquals(2, listeners.size()); - assertTrue(listeners.contains(listener1)); - assertTrue(listeners.contains(listener2)); - } - - @Test - public void testRemoveListener() { - Request request = new Request(RequestType.RESPONSE_EXPECTED, new InetSocketAddress(HOST, PORT)); - RequestResponseListener listener1 = new RequestResponseListenerImpl(); - RequestResponseListener listener2 = new RequestResponseListenerImpl(); - request.addListener(listener1); - request.addListener(listener2); - Collection<RequestResponseListener> listeners = request.getListeners(); - assertEquals(2, listeners.size()); - assertTrue(listeners.contains(listener1)); - assertTrue(listeners.contains(listener2)); - request.removeListener(listener1); - listeners = request.getListeners(); - assertEquals(1, listeners.size()); - assertTrue(listeners.contains(listener2)); - assertFalse(listeners.contains(listener1)); - } - - @Test - public void canGetHostname() { - // unresolved hostname - InetSocketAddress addr = new InetSocketAddress(HOST, PORT); - assertTrue(addr.isUnresolved()); - Request request = new Request(RequestType.RESPONSE_EXPECTED, addr); - assertEquals(HOST, request.getTarget().getHostString()); - - } - - @Test - public void testToString() { - InetSocketAddress addr = new InetSocketAddress(1234); - Request request = new Request(RequestType.RESPONSE_EXPECTED, addr); - assertEquals("{ Request: {target = "+ addr.toString() + "}, {type = RESPONSE_EXPECTED}, {parameters = {}} }", request.toString()); - } - - /* - * It is important that request parameters won't get logged (at any log - * level). Since toString() is used in some log statements it should be - * sufficient to verify toString() filters parameters appropriately. - */ - @Test - public void testToStringFiltersParams() { - InetSocketAddress addr = new InetSocketAddress(1234); - Request request = new Request(RequestType.RESPONSE_EXPECTED, addr); - request.setParameter(Request.AUTH_TOKEN, "foo-auth-token"); - request.setParameter(Request.CLIENT_TOKEN, "bar-client-token"); - String preamble = "{ Request: {target = "+ addr.toString() + - "}, {type = RESPONSE_EXPECTED}, "; - String postfix = " }"; - // maps aren't ordered. work around it by using a set assert. - String expectedParamOrdering1 = "{parameters = {" + - Request.AUTH_TOKEN +"=<filtered>, " + - Request.CLIENT_TOKEN +"=<filtered>}}"; - String expectedParamOrdering2 = "{parameters = {" + - Request.CLIENT_TOKEN +"=<filtered>, " + - Request.AUTH_TOKEN +"=<filtered>}}"; - Set<String> expectedStrings = new HashSet<>(); - expectedStrings.add(preamble + expectedParamOrdering1 + postfix); - expectedStrings.add(preamble + expectedParamOrdering2 + postfix); - String actual = request.toString(); - assertTrue("Security sensitive parameters should be filtered! String was: " - + actual, expectedStrings.contains(actual)); - } - - @Test - public void testFilterParams() { - Map<String, String> origParams = new HashMap<>(); - origParams.put(Request.AUTH_TOKEN, "foo-auth-token"); - origParams.put(Request.CLIENT_TOKEN, "bar-client-token"); - origParams.put("foo-param", "something"); - - InetSocketAddress addr = new InetSocketAddress(1234); - Request request = new Request(RequestType.RESPONSE_EXPECTED, addr); - Map<String, String> filteredParams = request.getFilteredParams(origParams); - assertEquals(Request.AUTH_TOKEN + " should be filtered", "<filtered>", filteredParams.get(Request.AUTH_TOKEN)); - assertEquals(Request.CLIENT_TOKEN + " should be filtered", "<filtered>", filteredParams.get(Request.CLIENT_TOKEN)); - assertEquals("something", filteredParams.get("foo-param")); - assertEquals(3, filteredParams.size()); - - origParams.clear(); - origParams.put(Request.AUTH_TOKEN, "foo-auth-token"); - origParams.put("foo-param", "something-new"); - filteredParams = request.getFilteredParams(origParams); - assertEquals(Request.AUTH_TOKEN + " should be filtered", "<filtered>", filteredParams.get(Request.AUTH_TOKEN)); - assertEquals("something-new", filteredParams.get("foo-param")); - assertEquals(2, filteredParams.size()); - - origParams.clear(); - origParams.put("bar-param", "should-be-unchanged"); - origParams.put(Request.CLIENT_TOKEN, "client-token"); - filteredParams = request.getFilteredParams(origParams); - assertEquals(Request.CLIENT_TOKEN + " should be filtered", "<filtered>", filteredParams.get(Request.CLIENT_TOKEN)); - assertEquals("should-be-unchanged", filteredParams.get("bar-param")); - assertEquals(2, filteredParams.size()); - } -} -
--- a/common/command/src/test/java/com/redhat/thermostat/common/command/ResponseTest.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +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.common.command; - -import static org.junit.Assert.assertEquals; - -import org.junit.Test; - -import com.redhat.thermostat.common.command.Response.ResponseType; - -public class ResponseTest { - - @Test - public void testGetType() { - Response r = new Response(ResponseType.OK); - assertEquals(ResponseType.OK, r.getType()); - r = new Response(ResponseType.ERROR); - assertEquals(ResponseType.ERROR, r.getType()); - } -} -
--- a/common/command/src/test/java/com/redhat/thermostat/common/command/noapi/DecodingHelperTest.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,217 +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.common.command.noapi; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import org.junit.Test; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; - -public class DecodingHelperTest { - - /** - * Fragmented string case. Not enough data for string decoding. Specifically - * missing length of string. - */ - @Test - public void decodeStringMissingLengthBytes() { - ByteBuf buf = Unpooled.buffer(0, 0); - assertEquals(0, buf.readerIndex()); - StringDecodingContext ctx = DecodingHelper.decodeString(buf); - assertEquals("reader index should be untouched", 0, buf.readerIndex()); - assertEquals(StringDecodingState.INCOMPLETE_LENGTH_VAL, ctx.getState()); - assertEquals(0, ctx.getBytesRead()); - } - - /** - * Fragmented string case. Not enough data for string decoding. Specifically - * missing string bytes. - */ - @Test - public void decodeStringMissingStringBytes() { - ByteBuf buf = Unpooled.buffer(0, 4); - buf.writeInt(5); - assertEquals(0, buf.readerIndex()); - StringDecodingContext ctx = DecodingHelper.decodeString(buf); - assertEquals("reader index should be untouched", 0, buf.readerIndex()); - assertEquals(StringDecodingState.INCOMPLETE_STR_VAL, ctx.getState()); - assertEquals(4, ctx.getBytesRead()); - } - - @Test - public void canDecodeStringFull() { - String original = "this is a test"; - ByteBuf buf = Unpooled.buffer(0, 4 + original.length()); - buf.writeInt(original.length()); - buf.writeBytes(original.getBytes()); - assertEquals(0, buf.readerIndex()); - StringDecodingContext ctx = DecodingHelper.decodeString(buf); - assertEquals("reader index should be untouched", 0, buf.readerIndex()); - assertEquals(original.getBytes().length + 4, ctx.getBytesRead()); - assertEquals(StringDecodingState.VALUE_READ, ctx.getState()); - assertEquals(original, ctx.getValue()); - } - - @Test - public void canDecodeParametersFull() { - String key1 = "key1"; - String value1 = "value1"; - String key2 = "this is a key"; - String value2 = "value 2"; - int totalBytes = 4 /* # params */ + - 8 /* len key + len value */ + - key1.getBytes().length + - value1.getBytes().length + - 8 /* len key + len value */ + - key2.getBytes().length + - value2.getBytes().length; - ByteBuf buf = Unpooled.buffer(0, totalBytes); - buf.writeInt(2); - buf.writeInt(key1.getBytes().length); - buf.writeInt(value1.getBytes().length); - buf.writeBytes(key1.getBytes()); - buf.writeBytes(value1.getBytes()); - buf.writeInt(key2.getBytes().length); - buf.writeInt(value2.getBytes().length); - buf.writeBytes(key2.getBytes()); - buf.writeBytes(value2.getBytes()); - assertEquals(0, buf.readerIndex()); - ParameterDecodingContext ctx = DecodingHelper.decodeParameters(buf); - assertEquals(ParameterDecodingState.ALL_PARAMETERS_READ, ctx.getState()); - assertEquals(totalBytes, ctx.getBytesRead()); - assertEquals("reader index should be untouched", 0, buf.readerIndex()); - assertEquals(value1, ctx.getValues().get(key1)); - assertEquals(value2, ctx.getValues().get(key2)); - } - - @Test - public void canDecodeParametersFullZeroParams() { - int totalBytes = 4 /* # params */; - ByteBuf buf = Unpooled.buffer(0, totalBytes); - buf.writeInt(0); - assertEquals(0, buf.readerIndex()); - ParameterDecodingContext ctx = DecodingHelper.decodeParameters(buf); - assertEquals(ParameterDecodingState.ALL_PARAMETERS_READ, ctx.getState()); - assertEquals(totalBytes, ctx.getBytesRead()); - assertEquals("reader index should be untouched", 0, buf.readerIndex()); - assertTrue(ctx.getValues().isEmpty()); - } - - @Test - public void canDecodeFragementedParamNoNumParams() { - ByteBuf buf = Unpooled.buffer(0, 0); - assertEquals(0, buf.readerIndex()); - ParameterDecodingContext ctx = DecodingHelper.decodeParameters(buf); - assertEquals(ParameterDecodingState.INCOMPLETE_PARAMS_LENGTH, ctx.getState()); - assertEquals(0, ctx.getBytesRead()); - assertEquals("reader index should be untouched", 0, buf.readerIndex()); - } - - /** - * Fragmented test case where the length of the value is missing in the - * buffer. - */ - @Test - public void canDecodeFragementedParamNoLengthValue() { - ByteBuf buf = Unpooled.buffer(0, 8); - buf.writeInt(1); // one parameter - buf.writeInt(3); // length of key - assertEquals(0, buf.readerIndex()); - ParameterDecodingContext ctx = DecodingHelper.decodeParameters(buf); - assertEquals(ParameterDecodingState.INCOMPLETE_PARAM_KV_LENGTH, ctx.getState()); - assertEquals(4, ctx.getBytesRead()); // num params have been read - assertEquals("reader index should be untouched", 0, buf.readerIndex()); - } - - /** - * Fragmented test case where the length of both the key and value is - * missing in the buffer. - */ - @Test - public void canDecodeFragementedParamNoLengthKey() { - ByteBuf buf = Unpooled.buffer(0, 4); - buf.writeInt(1); // one parameter - assertEquals(0, buf.readerIndex()); - ParameterDecodingContext ctx = DecodingHelper.decodeParameters(buf); - assertEquals(ParameterDecodingState.INCOMPLETE_PARAM_KV_LENGTH, ctx.getState()); - assertEquals(4, ctx.getBytesRead()); // num params have been read - assertEquals("reader index should be untouched", 0, buf.readerIndex()); - } - - /** - * Fragmented test case where the key/value data is missing from - * the buffer. - */ - @Test - public void canDecodeFragementedParamNoDataForKeyValue() { - ByteBuf buf = Unpooled.buffer(0, 12); - buf.writeInt(1); // one parameter - buf.writeInt(2); // length of key - buf.writeInt(7); // length of value - assertEquals(0, buf.readerIndex()); - ParameterDecodingContext ctx = DecodingHelper.decodeParameters(buf); - assertEquals(ParameterDecodingState.INCOMPLETE_PARAM_KV_DATA, ctx.getState()); - assertEquals(12, ctx.getBytesRead()); // num params + key/value length have been read - assertEquals("reader index should be untouched", 0, buf.readerIndex()); - } - - /** - * Fragmented test case where the key/value data is missing from - * the buffer. - */ - @Test - public void canDecodeFragementedParamNoLengthForSecondParam() { - String firstKey = "first"; - String firstValue = "value"; - int bytesInBuf = 12 + firstKey.getBytes().length + firstValue.getBytes().length; - ByteBuf buf = Unpooled.buffer(0, bytesInBuf); - buf.writeInt(2); // two params - buf.writeInt(firstKey.getBytes().length); - buf.writeInt(firstValue.getBytes().length); - buf.writeBytes(firstKey.getBytes()); - buf.writeBytes(firstValue.getBytes()); - assertEquals(0, buf.readerIndex()); - ParameterDecodingContext ctx = DecodingHelper.decodeParameters(buf); - assertEquals(ParameterDecodingState.INCOMPLETE_PARAM_KV_LENGTH, ctx.getState()); - assertEquals(bytesInBuf, ctx.getBytesRead()); // read up to the first param - assertEquals("reader index should be untouched", 0, buf.readerIndex()); - } -} -
--- a/common/command/src/test/java/com/redhat/thermostat/common/command/noapi/EncodingHelperTest.java Tue Jun 13 12:02:12 2017 +0200 +++ /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.common.command.noapi; - -import static org.junit.Assert.assertEquals; - -import java.nio.ByteBuffer; - -import org.junit.Test; - -import io.netty.buffer.ByteBuf; - -public class EncodingHelperTest { - - @Test - public void testEncode() { - String input = "a test string"; - byte[] inputBytes = input.getBytes(); - ByteBuf buf = EncodingHelper.encode(input); - int encodedMessageLength = buf.readInt(); - assertEquals(inputBytes.length, encodedMessageLength); - ByteBuffer bbuf = ByteBuffer.allocate(buf.readableBytes()); - buf.readBytes(bbuf); - byte[] output = bbuf.array(); - assertEquals(inputBytes.length, output.length); - for (int i = 0; i < inputBytes.length; i++) { - assertEquals(inputBytes[i], output[i]); - } - } - - @Test - public void testTrimType() { - String expected = "remaining"; - String original = "this.is.going.to.be.trimmed.with.only.the.last." + expected; - String stripped = EncodingHelper.trimType(original); - assertEquals(expected, stripped); - } - -} -
--- a/common/command/src/test/java/com/redhat/thermostat/common/command/noapi/RequestEncoderTest.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,160 +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.common.command.noapi; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.net.InetSocketAddress; -import java.nio.charset.Charset; -import java.util.Arrays; - -import org.junit.Test; - -import com.redhat.thermostat.common.command.Request; -import com.redhat.thermostat.common.command.Request.RequestType; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.buffer.Unpooled; - -public class RequestEncoderTest { - - private static final boolean DEBUG = false; - /** - * Represents low-level bytes for: - * <pre> - * Request request = new Request(RequestType.RESPONSE_EXPECTED, new InetSocketAddress(20)) - * request.setParameter("receiver", "com.redhat.foo.bar.Receiver"); - * </pre> - */ - private static final byte[] REQUEST_BYTES = new byte[] { 0, 0, 0, 17, 82, - 69, 83, 80, 79, 78, 83, 69, 95, 69, 88, 80, 69, 67, 84, 69, 68, 0, - 0, 0, 1, 0, 0, 0, 8, 0, 0, 0, 27, 114, 101, 99, 101, 105, 118, 101, - 114, 99, 111, 109, 46, 114, 101, 100, 104, 97, 116, 46, 102, 111, - 111, 46, 98, 97, 114, 46, 82, 101, 99, 101, 105, 118, 101, 114 }; - - @Test - public void testEncodingRequestToArray() { - Request request = new Request(RequestType.RESPONSE_EXPECTED, new InetSocketAddress(20)); - request.setParameter("receiver", "com.redhat.foo.bar.Receiver"); - RequestEncoder encoder = new RequestEncoder(); - ByteBuf buf = encoder.encode(request); - byte[] array = Unpooled.copiedBuffer(buf).array(); - assertTrue(Arrays.equals(REQUEST_BYTES, array)); - } - - @Test - public void canEncodeSimpleRequestWithNoParams() throws Exception { - RequestEncoder encoder = new RequestEncoder(); - String responseExp = "RESPONSE_EXPECTED"; - ByteBuf stringBuf = Unpooled.copiedBuffer(responseExp, Charset.defaultCharset()); - ByteBuf buf = Unpooled.buffer(4); - buf.writeInt(responseExp.getBytes().length); - ByteBuf buf2 = Unpooled.wrappedBuffer(buf, stringBuf); - buf = Unpooled.buffer(4); - buf.writeInt(0); - ByteBuf expected = Unpooled.wrappedBuffer(buf2, buf); - InetSocketAddress addr = new InetSocketAddress("testhost", 12); - Request item = new Request(RequestType.RESPONSE_EXPECTED, addr); - ByteBuf actual = encoder.encode(item); - if (DEBUG) { - printBuffers(actual, expected); - } - assertEquals(0, ByteBufUtil.compare(expected, actual)); - } - - @Test - public void canEncodeRequestWithParams() throws Exception { - InetSocketAddress addr = new InetSocketAddress(1234); - - // Prepare request we'd like to encode - Request item = new Request(RequestType.RESPONSE_EXPECTED, addr); - String param1Name = "param1"; - String param1Value = "value1"; - String param2Name = "param2"; - String param2Value = "value2"; - item.setParameter(param1Name, param1Value); - item.setParameter(param2Name, param2Value); - RequestEncoder encoder = new RequestEncoder(); - - // build expected - String responseExp = "RESPONSE_EXPECTED"; - ByteBuf stringBuf = Unpooled.copiedBuffer(responseExp, Charset.defaultCharset()); - ByteBuf buf = Unpooled.buffer(4); - buf.writeInt(responseExp.getBytes().length); - ByteBuf buf2 = Unpooled.wrappedBuffer(buf, stringBuf); - buf = Unpooled.buffer(4); - buf.writeInt(2); - ByteBuf request = Unpooled.wrappedBuffer(buf2, buf); - ByteBuf nameLen = Unpooled.buffer(4); - nameLen.writeInt(param1Name.getBytes().length); - ByteBuf valueLen = Unpooled.buffer(4); - valueLen.writeInt(param1Value.getBytes().length); - ByteBuf lens = Unpooled.wrappedBuffer(nameLen, valueLen); - ByteBuf nameBuf = Unpooled.copiedBuffer(param1Name, Charset.defaultCharset()); - ByteBuf valueBuf = Unpooled.copiedBuffer(param1Value, Charset.defaultCharset()); - ByteBuf payload = Unpooled.wrappedBuffer(nameBuf, valueBuf); - ByteBuf param1Buf = Unpooled.wrappedBuffer(lens, payload); - nameLen = Unpooled.buffer(4); - nameLen.writeInt(param2Name.getBytes().length); - valueLen = Unpooled.buffer(4); - valueLen.writeInt(param2Value.getBytes().length); - lens = Unpooled.wrappedBuffer(nameLen, valueLen); - nameBuf = Unpooled.copiedBuffer(param2Name, Charset.defaultCharset()); - valueBuf = Unpooled.copiedBuffer(param2Value, Charset.defaultCharset()); - payload = Unpooled.wrappedBuffer(nameBuf, valueBuf); - ByteBuf param2Buf = Unpooled.wrappedBuffer(lens, payload); - ByteBuf params = Unpooled.wrappedBuffer(param1Buf, param2Buf); - ByteBuf expected = Unpooled.wrappedBuffer(request, params); - - // Encode item for actual - ByteBuf actual = encoder.encode(item); - if (DEBUG) { - printBuffers(actual, expected); - } - assertEquals(0, ByteBufUtil.compare(expected, actual)); - } - - private void printBuffers(ByteBuf actual, ByteBuf expected) { - System.out.println("hexdump expected\n-------------------------------------"); - System.out.println(ByteBufUtil.hexDump(expected)); - System.out.println("\nhexdump actual\n-------------------------------------"); - System.out.println(ByteBufUtil.hexDump(actual) + "\n\n"); - } -} -
--- a/common/pom.xml Tue Jun 13 12:02:12 2017 +0200 +++ b/common/pom.xml Mon Jun 12 20:50:03 2017 +0200 @@ -66,7 +66,6 @@ <modules> <module>core</module> - <module>command</module> <module>portability</module> <module>test</module> </modules>
--- a/distribution/assembly/core-assembly.xml Tue Jun 13 12:02:12 2017 +0200 +++ b/distribution/assembly/core-assembly.xml Mon Jun 12 20:50:03 2017 +0200 @@ -53,22 +53,18 @@ <include>com.redhat.thermostat:thermostat-launcher</include> <include>com.redhat.thermostat:thermostat-agent-core</include> <include>com.redhat.thermostat:thermostat-agent-cli</include> - <include>com.redhat.thermostat:thermostat-agent-command</include> - <include>com.redhat.thermostat:thermostat-agent-command-server</include> <include>com.redhat.thermostat:thermostat-agent-proxy-server</include> <include>com.redhat.thermostat:thermostat-agent-ipc-tcpsocket-server</include> <include>com.redhat.thermostat:thermostat-agent-ipc-tcpsocket-client</include> <include>com.redhat.thermostat:thermostat-agent-ipc-unixsocket-server</include> <include>com.redhat.thermostat:thermostat-agent-ipc-unixsocket-client</include> <include>com.redhat.thermostat:thermostat-common-core</include> - <include>com.redhat.thermostat:thermostat-common-command</include> <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-system-backend</include> <include>org.osgi:org.osgi.compendium</include> <include>org.apache:org.apache.felix.scr</include> - <include>io.netty:netty-handler</include> <include>commons-codec:commons-codec</include> <include>org.apache.httpcomponents:httpclient-osgi</include> <include>org.eclipse.jetty:jetty-client</include>
--- a/distribution/config/agent.properties Tue Jun 13 12:02:12 2017 +0200 +++ b/distribution/config/agent.properties Mon Jun 12 20:50:03 2017 +0200 @@ -2,22 +2,6 @@ # or rather will purge the db SAVE_ON_EXIT=true -# A netty-based side channel for accepting configuration/tuning -# requests from the client will listen for connections on the address -# configured here. -# If this is removed or commented out, the default port is 127.0.0.1:12000 -# If this includes an IPv6 address, enclose it in [ and ] like: -# [1fff:0:a88:85a3::ac1f]:12000 -CONFIG_LISTEN_ADDRESS=127.0.0.1:12000 - -# Related to CONFIG_LISTEN_ADDRESS. CONFIG_PUBLISH_ADDRESS will be used -# as an address advertised to clients to reach the agent. If not specified -# defaults to CONFIG_LISTEN_ADDRESS. This config value is useful if the -# listen address of the agent is some local-only resolvable address. -# In that case, specify the globally reachable address of the agent via -# CONFIG_PUBLISH_ADDRESS. See CONFIG_LISTEN_ADDRESS for supported formats. -#CONFIG_PUBLISH_ADDRESS=agent.example.com:12000 - # Connection URL to storage. This can be overridden with the -d option # on the command line. DB_URL=http://127.0.0.1:8999/thermostat/storage
--- a/distribution/pom.xml Tue Jun 13 12:02:12 2017 +0200 +++ b/distribution/pom.xml Mon Jun 12 20:50:03 2017 +0200 @@ -423,16 +423,6 @@ </dependency> <dependency> <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-agent-command</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-agent-command-server</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>com.redhat.thermostat</groupId> <artifactId>thermostat-agent-proxy-server</artifactId> <version>${project.version}</version> </dependency> @@ -463,11 +453,6 @@ </dependency> <dependency> <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-common-command</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>com.redhat.thermostat</groupId> <artifactId>thermostat-common-portability</artifactId> <version>${project.version}</version> </dependency>
--- a/plugins/killvm/agent/pom.xml Tue Jun 13 12:02:12 2017 +0200 +++ b/plugins/killvm/agent/pom.xml Mon Jun 12 20:50:03 2017 +0200 @@ -84,11 +84,6 @@ </dependency> <dependency> <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-agent-command</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>com.redhat.thermostat</groupId> <artifactId>thermostat-common-core</artifactId> <version>${project.version}</version> </dependency> @@ -103,9 +98,19 @@ <version>${project.version}</version> </dependency> <dependency> + <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-commands-agent</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> <groupId>org.osgi</groupId> <artifactId>org.osgi.core</artifactId> </dependency> + <!-- declarative services --> + <dependency> + <groupId>org.apache.felix</groupId> + <artifactId>org.apache.felix.scr.annotations</artifactId> + </dependency> </dependencies> <build> @@ -117,7 +122,6 @@ <configuration> <instructions> <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor> - <Bundle-Activator>com.redhat.thermostat.killvm.agent.internal.Activator</Bundle-Activator> <Bundle-SymbolicName>com.redhat.thermostat.killvm.agent</Bundle-SymbolicName> <Private-Package>com.redhat.thermostat.killvm.agent.internal</Private-Package> <!-- Do not autogenerate uses clauses in Manifests --> @@ -125,6 +129,18 @@ </instructions> </configuration> </plugin> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-scr-plugin</artifactId> + <executions> + <execution> + <id>generate-scr-scrdescriptor</id> + <goals> + <goal>scr</goal> + </goals> + </execution> + </executions> + </plugin> </plugins> </build>
--- a/plugins/killvm/agent/src/main/java/com/redhat/thermostat/killvm/agent/internal/Activator.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +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.killvm.agent.internal; - -import com.redhat.thermostat.service.process.ProcessHandler; -import org.osgi.framework.BundleActivator; -import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceReference; -import org.osgi.util.tracker.ServiceTracker; - -import com.redhat.thermostat.agent.command.ReceiverRegistry; - -public class Activator implements BundleActivator { - - private ReceiverRegistry registry; - private ServiceTracker killActionTracker; - - @Override - public void start(final BundleContext context) { - registry = new ReceiverRegistry(context); - - killActionTracker = new ServiceTracker(context, ProcessHandler.class, null) { - @Override - public Object addingService(ServiceReference reference) { - ProcessHandler processHandler = (ProcessHandler) super.addingService(reference); - registry.registerReceiver(new KillVmReceiver(processHandler)); - return processHandler; - } - - @Override - public void removedService(ServiceReference reference, Object service) { - registry.unregisterReceivers(); - super.removedService(reference, service); - } - }; - - killActionTracker.open(); - } - - @Override - public void stop(BundleContext context) { - killActionTracker.close(); - } -} -
--- a/plugins/killvm/agent/src/main/java/com/redhat/thermostat/killvm/agent/internal/KillVmReceiver.java Tue Jun 13 12:02:12 2017 +0200 +++ b/plugins/killvm/agent/src/main/java/com/redhat/thermostat/killvm/agent/internal/KillVmReceiver.java Mon Jun 12 20:50:03 2017 +0200 @@ -39,41 +39,51 @@ import java.util.logging.Level; import java.util.logging.Logger; -import com.redhat.thermostat.agent.command.RequestReceiver; -import com.redhat.thermostat.common.command.Request; -import com.redhat.thermostat.common.command.Response; -import com.redhat.thermostat.common.command.Response.ResponseType; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Property; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.Service; + +import com.redhat.thermostat.commands.agent.receiver.RequestReceiver; +import com.redhat.thermostat.commands.model.AgentRequest; +import com.redhat.thermostat.commands.model.WebSocketResponse; +import com.redhat.thermostat.commands.model.WebSocketResponse.ResponseType; import com.redhat.thermostat.common.utils.LoggingUtils; import com.redhat.thermostat.service.process.ProcessHandler; import com.redhat.thermostat.service.process.UNIXSignal; +@Component +@Service(value = RequestReceiver.class) +@Property(name = "servicename", value = "com.redhat.thermostat.killvm.agent.internal.KillVmReceiver") public class KillVmReceiver implements RequestReceiver { - private final ProcessHandler processService; private static final Logger log = LoggingUtils.getLogger(KillVmReceiver.class); - public KillVmReceiver(ProcessHandler theService) { - this.processService = theService; - } + @Reference + private ProcessHandler processService; @Override - public Response receive(Request request) { + public WebSocketResponse receive(AgentRequest request) { if (processService == null) { // no dice, should have service by now log.severe("Process service is null!"); - return new Response(ResponseType.ERROR); + return new WebSocketResponse(request.getSequenceId(), ResponseType.ERROR); } - String strPid = request.getParameter("vm-pid"); + String strPid = request.getParam("vm-pid"); try { Integer pid = Integer.parseInt(strPid); processService.sendSignal(pid, UNIXSignal.TERM); log.fine("Killed VM with PID " + pid); - return new Response(ResponseType.OK); + return new WebSocketResponse(request.getSequenceId(), ResponseType.OK); } catch (NumberFormatException e) { log.log(Level.WARNING, "Invalid PID argument", e); - return new Response(ResponseType.ERROR); + return new WebSocketResponse(request.getSequenceId(), ResponseType.ERROR); } } + + protected void bindProcessService(ProcessHandler handler) { + this.processService = handler; + } }
--- a/plugins/killvm/agent/src/test/java/com/redhat/thermostat/killvm/agent/internal/ActivatorTest.java Tue Jun 13 12:02:12 2017 +0200 +++ /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.killvm.agent.internal; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; - -import org.junit.Test; - -import com.redhat.thermostat.agent.command.RequestReceiver; -import com.redhat.thermostat.service.process.ProcessHandler; -import com.redhat.thermostat.testutils.StubBundleContext; - -public class ActivatorTest { - - /** - * Makes sure receiver is registered and unix service gets set. - */ - @Test - public void verifyKillReciverIsNotRegisteredWithoutDependencies() { - StubBundleContext ctx = new StubBundleContext(); - Activator activator = new Activator(); - activator.start(ctx); - - assertEquals(0, ctx.getAllServices().size()); - - activator.stop(ctx); - } - - @Test - public void verifyKillReciverIsRegistered() { - StubBundleContext ctx = new StubBundleContext(); - - ctx.registerService(ProcessHandler.class, mock(ProcessHandler.class), null); - - Activator activator = new Activator(); - activator.start(ctx); - - assertEquals(2, ctx.getAllServices().size()); - assertTrue(ctx.isServiceRegistered(RequestReceiver.class.getName(), KillVmReceiver.class)); - - activator.stop(ctx); - - assertEquals(1, ctx.getAllServices().size()); - } -} -
--- a/plugins/killvm/agent/src/test/java/com/redhat/thermostat/killvm/agent/internal/KillVmReceiverTest.java Tue Jun 13 12:02:12 2017 +0200 +++ b/plugins/killvm/agent/src/test/java/com/redhat/thermostat/killvm/agent/internal/KillVmReceiverTest.java Mon Jun 12 20:50:03 2017 +0200 @@ -39,60 +39,71 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import java.lang.reflect.Constructor; import java.lang.reflect.Method; +import java.util.SortedMap; +import java.util.TreeMap; -import com.redhat.thermostat.service.process.ProcessHandler; import org.junit.Test; -import com.redhat.thermostat.common.command.Request; -import com.redhat.thermostat.common.command.Response; -import com.redhat.thermostat.common.command.Response.ResponseType; +import com.redhat.thermostat.commands.model.AgentRequest; +import com.redhat.thermostat.commands.model.WebSocketResponse; +import com.redhat.thermostat.commands.model.WebSocketResponse.ResponseType; +import com.redhat.thermostat.service.process.ProcessHandler; public class KillVmReceiverTest { @Test public void receiverReturnsOk() { ProcessHandler proc = mock(ProcessHandler.class); - KillVmReceiver receiver = new KillVmReceiver(proc); - Request req = mock(Request.class); - when(req.getParameter("vm-pid")).thenReturn("12345"); - Response response = receiver.receive(req); - assertEquals(ResponseType.OK, response.getType()); + KillVmReceiver receiver = new KillVmReceiver(); + receiver.bindProcessService(proc); + SortedMap<String, String> params = new TreeMap<>(); + params.put("vm-pid", "12345"); + AgentRequest req = new AgentRequest(322, params); + WebSocketResponse response = receiver.receive(req); + assertEquals(ResponseType.OK, response.getResponseType()); + assertEquals(322, response.getSequenceId()); } @Test public void receiverReturnsErrorNoPid() { ProcessHandler proc = mock(ProcessHandler.class); - KillVmReceiver receiver = new KillVmReceiver(proc); - Request req = mock(Request.class); - Response response = receiver.receive(req); - assertEquals(ResponseType.ERROR, response.getType()); + KillVmReceiver receiver = new KillVmReceiver(); + receiver.bindProcessService(proc); + SortedMap<String, String> params = new TreeMap<>(); + AgentRequest req = new AgentRequest(-1, params); + WebSocketResponse response = receiver.receive(req); + assertEquals(ResponseType.ERROR, response.getResponseType()); + assertEquals(-1, response.getSequenceId()); } @Test public void receiverReturnsErrorBadPid() { ProcessHandler proc = mock(ProcessHandler.class); - KillVmReceiver receiver = new KillVmReceiver(proc); - Request req = mock(Request.class); - when(req.getParameter("vm-pid")).thenReturn("hi"); - Response response = receiver.receive(req); - assertEquals(ResponseType.ERROR, response.getType()); + KillVmReceiver receiver = new KillVmReceiver(); + receiver.bindProcessService(proc); + SortedMap<String, String> params = new TreeMap<>(); + params.put("vm-pid", "hi"); + AgentRequest req = new AgentRequest(211, params); + WebSocketResponse response = receiver.receive(req); + assertEquals(ResponseType.ERROR, response.getResponseType()); + assertEquals(211, response.getSequenceId()); } @Test public void receiverReturnsErrorNoProcessHandler() { - KillVmReceiver receiver = new KillVmReceiver(null); - Request req = mock(Request.class); - Response response = receiver.receive(req); - assertEquals(ResponseType.ERROR, response.getType()); + KillVmReceiver receiver = new KillVmReceiver(); + SortedMap<String, String> params = new TreeMap<>(); + AgentRequest req = new AgentRequest(11, params); + WebSocketResponse response = receiver.receive(req); + assertEquals(ResponseType.ERROR, response.getResponseType()); + assertEquals(11, response.getSequenceId()); } /** * When a request is issued the fully qualified receiver class name is set - * via {@link Request#setReceiver(String)}. This test makes sure that this + * via the 'receiver' param name. This test makes sure that this * class is actually where it's supposed to be. * * @throws Exception @@ -109,11 +120,14 @@ fail("com.redhat.thermostat.agent.killvm.internal.KillVmReceiver class not found, but used by some request!"); } try { - Constructor<?> constructor = receiver.getConstructor(ProcessHandler.class); ProcessHandler service = mock(ProcessHandler.class); - Object instance = constructor.newInstance(service); - Method m = receiver.getMethod("receive", Request.class); - Request req = mock(Request.class); + Object instance = receiver.newInstance(); + Method bind = receiver.getDeclaredMethod("bindProcessService", ProcessHandler.class); + bind.invoke(instance, service); + Method m = receiver.getMethod("receive", AgentRequest.class); + SortedMap<String, String> params = new TreeMap<>(); + params.put("vm-pid", "12345"); + AgentRequest req = new AgentRequest(322, params); m.invoke(instance, req); } catch (Exception e) { e.printStackTrace();
--- a/plugins/vm-gc/remote-collector-command/pom.xml Tue Jun 13 12:02:12 2017 +0200 +++ b/plugins/vm-gc/remote-collector-command/pom.xml Mon Jun 12 20:50:03 2017 +0200 @@ -90,8 +90,13 @@ </dependency> <dependency> <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-agent-command</artifactId> - <version>${project.version}</version> + <artifactId>thermostat-commands-agent</artifactId> + <version>${project.version}</version> + </dependency> + <!-- declarative services --> + <dependency> + <groupId>org.apache.felix</groupId> + <artifactId>org.apache.felix.scr.annotations</artifactId> </dependency> <dependency> <groupId>com.redhat.thermostat</groupId> @@ -112,7 +117,6 @@ <instructions> <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor> <Bundle-SymbolicName>com.redhat.thermostat.gc.remote.command</Bundle-SymbolicName> - <Bundle-Activator>com.redhat.thermostat.gc.remote.command.internal.Activator</Bundle-Activator> <Export-Package> com.redhat.thermostat.gc.remote.command, </Export-Package> @@ -124,6 +128,18 @@ </instructions> </configuration> </plugin> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-scr-plugin</artifactId> + <executions> + <execution> + <id>generate-scr-scrdescriptor</id> + <goals> + <goal>scr</goal> + </goals> + </execution> + </executions> + </plugin> </plugins> </build>
--- a/plugins/vm-gc/remote-collector-command/src/main/java/com/redhat/thermostat/gc/remote/command/GCRequestReceiver.java Tue Jun 13 12:02:12 2017 +0200 +++ b/plugins/vm-gc/remote-collector-command/src/main/java/com/redhat/thermostat/gc/remote/command/GCRequestReceiver.java Mon Jun 12 20:50:03 2017 +0200 @@ -39,41 +39,47 @@ import java.util.logging.Level; import java.util.logging.Logger; -import com.redhat.thermostat.agent.command.RequestReceiver; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Property; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.Service; + import com.redhat.thermostat.agent.utils.management.MXBeanConnectionPool; -import com.redhat.thermostat.common.command.Request; -import com.redhat.thermostat.common.command.Response; -import com.redhat.thermostat.common.command.Response.ResponseType; +import com.redhat.thermostat.commands.agent.receiver.RequestReceiver; +import com.redhat.thermostat.commands.model.AgentRequest; +import com.redhat.thermostat.commands.model.WebSocketResponse; +import com.redhat.thermostat.commands.model.WebSocketResponse.ResponseType; import com.redhat.thermostat.common.utils.LoggingUtils; import com.redhat.thermostat.gc.remote.command.internal.GC; import com.redhat.thermostat.gc.remote.command.internal.GCException; import com.redhat.thermostat.gc.remote.common.command.GCAction; +@Component +@Service(value = RequestReceiver.class) +@Property(name = "servicename", value = "com.redhat.thermostat.gc.remote.command.GCRequestReceiver") public class GCRequestReceiver implements RequestReceiver { private static final Logger logger = LoggingUtils.getLogger(GCRequestReceiver.class); + + @Reference private MXBeanConnectionPool pool; - public GCRequestReceiver(MXBeanConnectionPool pool) { - this.pool = pool; - } - @Override - public Response receive(Request request) { - Response response = new Response(ResponseType.OK); + public WebSocketResponse receive(AgentRequest request) { + WebSocketResponse response = new WebSocketResponse(request.getSequenceId(), ResponseType.OK); - String command = request.getParameter(GCAction.class.getName()); + String command = request.getParam(GCAction.class.getName()); switch (GCAction.valueOf(command)) { case REQUEST_GC: - String strPid = request.getParameter(GCAction.VM_PID); + String strPid = request.getParam(GCAction.VM_PID); try { int vmId = Integer.parseInt(strPid); new GC(pool, vmId).gc(); } catch (GCException gce) { - response = new Response(ResponseType.ERROR); + response = new WebSocketResponse(request.getSequenceId(), ResponseType.ERROR); logger.log(Level.WARNING, "GC request failed", gce); } catch (NumberFormatException e) { - response = new Response(ResponseType.ERROR); + response = new WebSocketResponse(request.getSequenceId(), ResponseType.ERROR); logger.log(Level.WARNING, "Invalid PID: " + strPid, e); } break;
--- a/plugins/vm-gc/remote-collector-command/src/main/java/com/redhat/thermostat/gc/remote/command/internal/Activator.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +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.gc.remote.command.internal; - -import org.osgi.framework.BundleActivator; -import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceReference; -import org.osgi.util.tracker.ServiceTracker; - -import com.redhat.thermostat.agent.command.ReceiverRegistry; -import com.redhat.thermostat.agent.utils.management.MXBeanConnectionPool; -import com.redhat.thermostat.gc.remote.command.GCRequestReceiver; - -public class Activator implements BundleActivator { - - private ServiceTracker tracker; - - @Override - public void start(BundleContext context) throws Exception { - final ReceiverRegistry registry = new ReceiverRegistry(context); - - tracker = new ServiceTracker(context, MXBeanConnectionPool.class, null) { - @Override - public MXBeanConnectionPool addingService(ServiceReference reference) { - MXBeanConnectionPool pool = (MXBeanConnectionPool) super.addingService(reference); - registry.registerReceiver(new GCRequestReceiver(pool)); - return pool; - }; - - @Override - public void removedService(ServiceReference reference, Object service) { - registry.unregisterReceivers(); - super.removedService(reference, service); - }; - }; - tracker.open(); - } - - @Override - public void stop(BundleContext context) throws Exception { - tracker.close(); - } -} -
--- a/plugins/vm-gc/remote-collector-command/src/test/java/com/redhat/thermostat/gc/remote/command/internal/ActivatorTest.java Tue Jun 13 12:02:12 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,83 +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.gc.remote.command.internal; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; - -import org.junit.Before; -import org.junit.Test; - -import com.redhat.thermostat.agent.command.RequestReceiver; -import com.redhat.thermostat.agent.utils.management.MXBeanConnectionPool; -import com.redhat.thermostat.gc.remote.command.GCRequestReceiver; -import com.redhat.thermostat.testutils.StubBundleContext; - -public class ActivatorTest { - - private StubBundleContext context; - private Activator activator; - - @Before - public void setup() { - context = new StubBundleContext(); - activator = new Activator(); - } - - @Test - public void verifyReceiverRegistered() throws Exception { - MXBeanConnectionPool mxBeanConnectionPool = mock(MXBeanConnectionPool.class); - context.registerService(MXBeanConnectionPool.class, mxBeanConnectionPool, null); - - activator.start(context); - - assertEquals(2, context.getAllServices().size()); - assertTrue(context.isServiceRegistered(RequestReceiver.class.getName(), GCRequestReceiver.class)); - - activator.stop(context); - } - - @Test - public void verifyActivatorDoesNotRegisterServiceOnMissingDeps() throws Exception { - activator.start(context); - - assertEquals(0, context.getAllServices().size()); - - activator.stop(context); - } -}
--- a/pom.xml Tue Jun 13 12:02:12 2017 +0200 +++ b/pom.xml Mon Jun 12 20:50:03 2017 +0200 @@ -303,7 +303,6 @@ <felix.scr.annotations.version>1.9.12</felix.scr.annotations.version> <kxml2.version>2.3.0</kxml2.version> - <netty.version>4.0.42.Final</netty.version> <httpcomponents.core.version>4.3.2</httpcomponents.core.version> <httpcomponents.client.version>4.3.4</httpcomponents.client.version> <gson.version>2.2.2</gson.version> @@ -621,16 +620,6 @@ <artifactId>expectj</artifactId> <version>${expectj.version}</version> </dependency> - <dependency> - <groupId>io.netty</groupId> - <artifactId>netty-handler</artifactId> - <version>${netty.version}</version> - </dependency> - <dependency> - <groupId>io.netty</groupId> - <artifactId>netty-buffer</artifactId> - <version>${netty.version}</version> - </dependency> <!-- Note that jfreechart pulls in jcommon as a dep. The jcommon jar is used explicitly in the main