changeset 2286:e5c64ae6f6f3

Move non-api classes in common.command to noapi package. Reviewed-by: ebaron Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2016-April/018461.html
author Severin Gehwolf <sgehwolf@redhat.com>
date Wed, 06 Apr 2016 15:07:01 +0200
parents 9886546c9092
children 981f2ef6d5a9
files README.api 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/CommandChannelServerContext.java agent/command-server/src/main/java/com/redhat/thermostat/agent/command/server/internal/ResponseEncoder.java client/command/src/main/java/com/redhat/thermostat/client/command/internal/ConfigurationRequestContext.java client/command/src/main/java/com/redhat/thermostat/client/command/internal/ResponseDecoder.java client/command/src/test/java/com/redhat/thermostat/client/command/internal/ConfigurationRequestContextTest.java common/command/pom.xml common/command/src/main/java/com/redhat/thermostat/common/command/ConfigurationCommandContext.java common/command/src/main/java/com/redhat/thermostat/common/command/DecodingHelper.java common/command/src/main/java/com/redhat/thermostat/common/command/EncodingHelper.java common/command/src/main/java/com/redhat/thermostat/common/command/MessageEncoder.java common/command/src/main/java/com/redhat/thermostat/common/command/ParameterDecodingContext.java common/command/src/main/java/com/redhat/thermostat/common/command/ParameterDecodingState.java common/command/src/main/java/com/redhat/thermostat/common/command/RequestEncoder.java common/command/src/main/java/com/redhat/thermostat/common/command/StringDecodingContext.java common/command/src/main/java/com/redhat/thermostat/common/command/StringDecodingState.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/DecodingHelperTest.java common/command/src/test/java/com/redhat/thermostat/common/command/EncodingHelperTest.java common/command/src/test/java/com/redhat/thermostat/common/command/RequestEncoderTest.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 pom.xml
diffstat 33 files changed, 1235 insertions(+), 1235 deletions(-) [+]
line wrap: on
line diff
--- a/README.api	Tue May 03 15:49:54 2016 +0200
+++ b/README.api	Wed Apr 06 15:07:01 2016 +0200
@@ -59,3 +59,4 @@
  - c.r.t.*.internal (and subpackages)
  - c.r.t.storage.mongodb (and subpackages)
  - c.r.t.web (and subpackages)
+ - c.r.t.*.noapi
--- a/agent/command-server/src/main/java/com/redhat/thermostat/agent/command/server/internal/CommandChannelRequestDecoder.java	Tue May 03 15:49:54 2016 +0200
+++ b/agent/command-server/src/main/java/com/redhat/thermostat/agent/command/server/internal/CommandChannelRequestDecoder.java	Wed Apr 06 15:07:01 2016 +0200
@@ -42,14 +42,14 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import com.redhat.thermostat.common.command.DecodingHelper;
 import com.redhat.thermostat.common.command.InvalidMessageException;
-import com.redhat.thermostat.common.command.ParameterDecodingContext;
-import com.redhat.thermostat.common.command.ParameterDecodingState;
 import com.redhat.thermostat.common.command.Request;
 import com.redhat.thermostat.common.command.Request.RequestType;
-import com.redhat.thermostat.common.command.StringDecodingContext;
-import com.redhat.thermostat.common.command.StringDecodingState;
+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;
--- a/agent/command-server/src/main/java/com/redhat/thermostat/agent/command/server/internal/CommandChannelServerContext.java	Tue May 03 15:49:54 2016 +0200
+++ b/agent/command-server/src/main/java/com/redhat/thermostat/agent/command/server/internal/CommandChannelServerContext.java	Wed Apr 06 15:07:01 2016 +0200
@@ -43,7 +43,7 @@
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLEngine;
 
-import com.redhat.thermostat.common.command.ConfigurationCommandContext;
+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;
--- a/agent/command-server/src/main/java/com/redhat/thermostat/agent/command/server/internal/ResponseEncoder.java	Tue May 03 15:49:54 2016 +0200
+++ b/agent/command-server/src/main/java/com/redhat/thermostat/agent/command/server/internal/ResponseEncoder.java	Wed Apr 06 15:07:01 2016 +0200
@@ -39,10 +39,10 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import com.redhat.thermostat.common.command.EncodingHelper;
 import com.redhat.thermostat.common.command.Message;
-import com.redhat.thermostat.common.command.MessageEncoder;
 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;
--- a/client/command/src/main/java/com/redhat/thermostat/client/command/internal/ConfigurationRequestContext.java	Tue May 03 15:49:54 2016 +0200
+++ b/client/command/src/main/java/com/redhat/thermostat/client/command/internal/ConfigurationRequestContext.java	Wed Apr 06 15:07:01 2016 +0200
@@ -42,8 +42,8 @@
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLEngine;
 
-import com.redhat.thermostat.common.command.ConfigurationCommandContext;
-import com.redhat.thermostat.common.command.RequestEncoder;
+import com.redhat.thermostat.common.command.noapi.ConfigurationCommandContext;
+import com.redhat.thermostat.common.command.noapi.RequestEncoder;
 import com.redhat.thermostat.common.ssl.SSLContextFactory;
 import com.redhat.thermostat.common.utils.LoggingUtils;
 import com.redhat.thermostat.shared.config.SSLConfiguration;
--- a/client/command/src/main/java/com/redhat/thermostat/client/command/internal/ResponseDecoder.java	Tue May 03 15:49:54 2016 +0200
+++ b/client/command/src/main/java/com/redhat/thermostat/client/command/internal/ResponseDecoder.java	Wed Apr 06 15:07:01 2016 +0200
@@ -40,12 +40,12 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import com.redhat.thermostat.common.command.DecodingHelper;
 import com.redhat.thermostat.common.command.InvalidMessageException;
 import com.redhat.thermostat.common.command.Response;
 import com.redhat.thermostat.common.command.Response.ResponseType;
-import com.redhat.thermostat.common.command.StringDecodingContext;
-import com.redhat.thermostat.common.command.StringDecodingState;
+import com.redhat.thermostat.common.command.noapi.DecodingHelper;
+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;
--- a/client/command/src/test/java/com/redhat/thermostat/client/command/internal/ConfigurationRequestContextTest.java	Tue May 03 15:49:54 2016 +0200
+++ b/client/command/src/test/java/com/redhat/thermostat/client/command/internal/ConfigurationRequestContextTest.java	Wed Apr 06 15:07:01 2016 +0200
@@ -60,7 +60,7 @@
 
 import com.redhat.thermostat.client.command.internal.ConfigurationRequestContext.ClientPipelineInitializer;
 import com.redhat.thermostat.client.command.internal.ConfigurationRequestContext.ClientPipelineInitializerCreator;
-import com.redhat.thermostat.common.command.RequestEncoder;
+import com.redhat.thermostat.common.command.noapi.RequestEncoder;
 import com.redhat.thermostat.common.ssl.SSLContextFactory;
 import com.redhat.thermostat.shared.config.SSLConfiguration;
 
--- a/common/command/pom.xml	Tue May 03 15:49:54 2016 +0200
+++ b/common/command/pom.xml	Wed Apr 06 15:07:01 2016 +0200
@@ -85,6 +85,7 @@
             <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 -->
--- a/common/command/src/main/java/com/redhat/thermostat/common/command/ConfigurationCommandContext.java	Tue May 03 15:49:54 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * Copyright 2012-2016 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.common.command;
-
-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/DecodingHelper.java	Tue May 03 15:49:54 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,158 +0,0 @@
-/*
- * Copyright 2012-2016 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.common.command;
-
-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/EncodingHelper.java	Tue May 03 15:49:54 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,68 +0,0 @@
-/*
- * Copyright 2012-2016 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.common.command;
-
-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/MessageEncoder.java	Tue May 03 15:49:54 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,77 +0,0 @@
-/*
- * Copyright 2012-2016 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.common.command;
-
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-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/ParameterDecodingContext.java	Tue May 03 15:49:54 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,99 +0,0 @@
-/*
- * Copyright 2012-2016 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.common.command;
-
-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/ParameterDecodingState.java	Tue May 03 15:49:54 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-/*
- * Copyright 2012-2016 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.common.command;
-
-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/RequestEncoder.java	Tue May 03 15:49:54 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,114 +0,0 @@
-/*
- * Copyright 2012-2016 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.common.command;
-
-import java.util.Collection;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-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/StringDecodingContext.java	Tue May 03 15:49:54 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-/*
- * Copyright 2012-2016 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.common.command;
-
-/**
- * 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/StringDecodingState.java	Tue May 03 15:49:54 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/*
- * Copyright 2012-2016 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.common.command;
-
-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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/command/src/main/java/com/redhat/thermostat/common/command/noapi/ConfigurationCommandContext.java	Wed Apr 06 15:07:01 2016 +0200
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.common.command.noapi;
+
+import com.redhat.thermostat.shared.config.SSLConfiguration;
+
+import io.netty.bootstrap.AbstractBootstrap;
+
+public interface ConfigurationCommandContext {
+
+    public AbstractBootstrap<?, ?> getBootstrap();
+
+    public SSLConfiguration getSSLConfiguration();
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/command/src/main/java/com/redhat/thermostat/common/command/noapi/DecodingHelper.java	Wed Apr 06 15:07:01 2016 +0200
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.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;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/command/src/main/java/com/redhat/thermostat/common/command/noapi/EncodingHelper.java	Wed Apr 06 15:07:01 2016 +0200
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.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);
+    }
+    
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/command/src/main/java/com/redhat/thermostat/common/command/noapi/MessageEncoder.java	Wed Apr 06 15:07:01 2016 +0200
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.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();
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/command/src/main/java/com/redhat/thermostat/common/command/noapi/ParameterDecodingContext.java	Wed Apr 06 15:07:01 2016 +0200
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.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;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/command/src/main/java/com/redhat/thermostat/common/command/noapi/ParameterDecodingState.java	Wed Apr 06 15:07:01 2016 +0200
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.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
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/command/src/main/java/com/redhat/thermostat/common/command/noapi/RequestEncoder.java	Wed Apr 06 15:07:01 2016 +0200
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.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;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/command/src/main/java/com/redhat/thermostat/common/command/noapi/StringDecodingContext.java	Wed Apr 06 15:07:01 2016 +0200
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/command/src/main/java/com/redhat/thermostat/common/command/noapi/StringDecodingState.java	Wed Apr 06 15:07:01 2016 +0200
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.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/DecodingHelperTest.java	Tue May 03 15:49:54 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,219 +0,0 @@
-/*
- * Copyright 2012-2016 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.common.command;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.common.command.DecodingHelper;
-
-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/EncodingHelperTest.java	Tue May 03 15:49:54 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-/*
- * Copyright 2012-2016 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.common.command;
-
-import static org.junit.Assert.assertEquals;
-
-import java.nio.ByteBuffer;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.common.command.EncodingHelper;
-
-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/RequestEncoderTest.java	Tue May 03 15:49:54 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,161 +0,0 @@
-/*
- * Copyright 2012-2016 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.common.command;
-
-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.RequestEncoder;
-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");
-    }
-}
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/command/src/test/java/com/redhat/thermostat/common/command/noapi/DecodingHelperTest.java	Wed Apr 06 15:07:01 2016 +0200
@@ -0,0 +1,217 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.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());
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/command/src/test/java/com/redhat/thermostat/common/command/noapi/EncodingHelperTest.java	Wed Apr 06 15:07:01 2016 +0200
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.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);
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/command/src/test/java/com/redhat/thermostat/common/command/noapi/RequestEncoderTest.java	Wed Apr 06 15:07:01 2016 +0200
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.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/pom.xml	Tue May 03 15:49:54 2016 +0200
+++ b/pom.xml	Wed Apr 06 15:07:01 2016 +0200
@@ -343,7 +343,7 @@
           <artifactId>maven-javadoc-plugin</artifactId>
           <version>2.9.1</version>
           <configuration>
-            <excludePackageNames>*.internal*;*.dev.*;*.experimental;com.redhat.thermostat.agent.proxy;com.redhat.thermostat.main;com.redhat.thermostat.numa;com.redhat.thermostat.storage.mongodb;com.redhat.thermostat.testutils;com.redhat.thermostat.vm;com.redhat.thermostat.host;com.redhat.thermostat.gc;com.redhat.thermostat.thread;com.redhat.thermostat.validate;com.redhat.thermostat.service.activator;com.redhat.thermostat.web;com.redhat.thermostat.killvm;com.redhat.thermostat.notes;com.redhat.thermostat.shared.perflog</excludePackageNames>
+            <excludePackageNames>*.noapi*;*.internal*;*.dev.*;*.experimental;com.redhat.thermostat.agent.proxy;com.redhat.thermostat.main;com.redhat.thermostat.numa;com.redhat.thermostat.storage.mongodb;com.redhat.thermostat.testutils;com.redhat.thermostat.vm;com.redhat.thermostat.host;com.redhat.thermostat.gc;com.redhat.thermostat.thread;com.redhat.thermostat.validate;com.redhat.thermostat.service.activator;com.redhat.thermostat.web;com.redhat.thermostat.killvm;com.redhat.thermostat.notes;com.redhat.thermostat.shared.perflog</excludePackageNames>
           </configuration>
         </plugin>
         <plugin>