Importing Google TV Pairing Protocol library

This has been modified to compile using nanobuf

Change-Id: If8f092b422d4be7b78ff0f6ef92c94beaea4300c
diff --git a/java/src/com/google/polo/wire/protobuf/ProtobufWireAdapter.java b/java/src/com/google/polo/wire/protobuf/ProtobufWireAdapter.java
new file mode 100644
index 0000000..ea3a7cb
--- /dev/null
+++ b/java/src/com/google/polo/wire/protobuf/ProtobufWireAdapter.java
@@ -0,0 +1,579 @@
+/*
+ * Copyright (C) 2009 Google Inc.  All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.polo.wire.protobuf;
+
+import com.google.polo.exception.BadSecretException;
+import com.google.polo.exception.NoConfigurationException;
+import com.google.polo.exception.PoloException;
+import com.google.polo.exception.ProtocolErrorException;
+import com.google.polo.pairing.PairingContext;
+import com.google.polo.pairing.PoloUtil;
+import com.google.polo.pairing.message.ConfigurationAckMessage;
+import com.google.polo.pairing.message.ConfigurationMessage;
+import com.google.polo.pairing.message.EncodingOption;
+import com.google.polo.pairing.message.OptionsMessage;
+import com.google.polo.pairing.message.PairingRequestAckMessage;
+import com.google.polo.pairing.message.PairingRequestMessage;
+import com.google.polo.pairing.message.PoloMessage;
+import com.google.polo.pairing.message.SecretAckMessage;
+import com.google.polo.pairing.message.SecretMessage;
+import com.google.polo.wire.PoloWireInterface;
+import com.google.polo.wire.protobuf.PoloProto.OuterMessage;
+import com.google.protobuf.nano.MessageNano;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Implementation of {@link PoloWireInterface} that uses Protocol Buffers for
+ * the data representation.
+ * <p/>
+ * The primary work of this class is to translate Protocol Buffer messages
+ * instances (derived from {@link MessageNano} to an internal message
+ * instance (derived from {@link PoloMessage}, and vice versa.
+ * <p/>
+ * The reason we are going through all this trouble, and not using protocol
+ * buffer objects directly, is that we'd like to limit the scope of protocol
+ * buffers to the wire protocol only.  Some applications may prefer to use
+ * a different wire format, where the requirement of adding the protobuf library
+ * could be an impediment.
+ */
+public class ProtobufWireAdapter implements PoloWireInterface {
+
+    /**
+     * The output coming from the peer.
+     */
+    private final InputStream mInputStream;
+    /**
+     * The input going to the peer.
+     */
+    private final OutputStream mOutputStream;
+
+    /**
+     * Constructor.
+     *
+     * @param input  the {@link InputStream} from the peer
+     * @param output the {@link OutputStream} to the peer
+     */
+    public ProtobufWireAdapter(InputStream input, OutputStream output) {
+        mInputStream = input;
+        mOutputStream = output;
+    }
+
+    /**
+     * Generates a new instance from a {@link PairingContext}.
+     *
+     * @param context the {@link PairingContext}
+     * @return the new instance
+     */
+    public static ProtobufWireAdapter fromContext(PairingContext context) {
+        return new ProtobufWireAdapter(context.getPeerInputStream(),
+                context.getPeerOutputStream());
+    }
+
+    /**
+     * Returns the next message sent over the wire, blocking as necessary.
+     */
+    public PoloMessage getNextMessage() throws IOException, PoloException {
+        return protoToPoloMessage(readNextInnerMessage());
+    }
+
+    /**
+     * Returns the next message read over the wire, requiring it to be a certain
+     * type.
+     *
+     * @param type the required message type
+     * @throws IOException   on error during read
+     * @throws PoloException if the wrong message type was read, or on protocol
+     *                       error
+     */
+    public PoloMessage getNextMessage(PoloMessage.PoloMessageType type)
+            throws IOException, PoloException {
+        PoloMessage message = getNextMessage();
+        if (message.getType() != type) {
+            throw new PoloException("Wrong message type (wanted " + type +
+                    ", got " + message.getType() + ")");
+        }
+        return message;
+    }
+
+    /**
+     * Returns the next message seen on the input stream.
+     *
+     * @return the next OuterMessage read from the wire
+     * @throws IOException on error during read
+     */
+    private OuterMessage readNextOuterMessage() throws IOException, PoloException {
+        // Read the preamble (length of payload)
+        byte[] preambleBuffer = readBytesBlocking(4);
+        int messageLen = (int) PoloUtil.intBigEndianBytesToLong(preambleBuffer);
+
+        // Read the payload (serialized PoloMessage)
+        byte[] messageBuffer = readBytesBlocking(messageLen);
+
+        // Decode and return the payload
+        OuterMessage message = OuterMessage.parseFrom(messageBuffer);
+
+        if (message.status != OuterMessage.STATUS_OK) {
+            throw new ProtocolErrorException();
+        }
+
+        return message;
+    }
+
+    /**
+     * Reads the next inner message from the wire, decoding and handling the outer
+     * message in the process.
+     *
+     * @return a protocol buffer message
+     * @throws IOException   on error during read
+     * @throws PoloException on protocol error
+     */
+    private MessageNano readNextInnerMessage()
+            throws IOException, PoloException {
+        OuterMessage message = readNextOuterMessage();
+
+        byte[] payload = message.payload;
+
+        if (message.type == OuterMessage.MESSAGE_TYPE_OPTIONS) {
+            return PoloProto.Options.parseFrom(payload);
+        } else if (message.type == OuterMessage.MESSAGE_TYPE_PAIRING_REQUEST) {
+            return PoloProto.PairingRequest.parseFrom(payload);
+        } else if (message.type == OuterMessage.MESSAGE_TYPE_PAIRING_REQUEST_ACK) {
+            return PoloProto.PairingRequestAck.parseFrom(payload);
+        } else if (message.type == OuterMessage.MESSAGE_TYPE_CONFIGURATION) {
+            return PoloProto.Configuration.parseFrom(payload);
+        } else if (message.type == OuterMessage.MESSAGE_TYPE_CONFIGURATION_ACK) {
+            return PoloProto.ConfigurationAck.parseFrom(payload);
+        } else if (message.type == OuterMessage.MESSAGE_TYPE_SECRET) {
+            return PoloProto.Secret.parseFrom(payload);
+        } else if (message.type == OuterMessage.MESSAGE_TYPE_SECRET_ACK) {
+            return PoloProto.SecretAck.parseFrom(payload);
+        }
+
+        throw new IOException("Could not unparse message");
+    }
+
+    /**
+     * Convenience method to read a fixed number of bytes from the client
+     * InputStream, blocking if necessary.
+     *
+     * @param numBytes the number of bytes to read
+     * @return the bytes read
+     * @throws IOException on error during read
+     */
+    private byte[] readBytesBlocking(int numBytes) throws IOException {
+        byte[] buf = new byte[numBytes];
+        int bytesRead = 0;
+
+        // For an SSLSocket, read() can frequently return zero bytes,
+        // or fewer bytes than desired, due to SSL unwrapping and other
+        // non-application-data events.
+        while (bytesRead < numBytes) {
+            int inc = mInputStream.read(buf, bytesRead, numBytes - bytesRead);
+            if (inc < 0) {
+                throw new IOException("Stream closed while reading.");
+            }
+            bytesRead += inc;
+        }
+        return buf;
+    }
+
+    /**
+     * Wraps an outer message in an inner message.
+     *
+     * @param message the {@link MessageNano} to wrap
+     * @throws PoloException if the message was not well formed
+     */
+    private OuterMessage wrapInnerMessage(MessageNano message)
+            throws PoloException {
+        int type;
+        if (message instanceof PoloProto.Options) {
+            type = OuterMessage.MESSAGE_TYPE_OPTIONS;
+        } else if (message instanceof PoloProto.PairingRequest) {
+            type = OuterMessage.MESSAGE_TYPE_PAIRING_REQUEST;
+        } else if (message instanceof PoloProto.PairingRequestAck) {
+            type = OuterMessage.MESSAGE_TYPE_PAIRING_REQUEST_ACK;
+        } else if (message instanceof PoloProto.Configuration) {
+            type = OuterMessage.MESSAGE_TYPE_CONFIGURATION;
+        } else if (message instanceof PoloProto.ConfigurationAck) {
+            type = OuterMessage.MESSAGE_TYPE_CONFIGURATION_ACK;
+        } else if (message instanceof PoloProto.Secret) {
+            type = OuterMessage.MESSAGE_TYPE_SECRET;
+        } else if (message instanceof PoloProto.SecretAck) {
+            type = OuterMessage.MESSAGE_TYPE_SECRET_ACK;
+        } else {
+            throw new PoloException("Bad inner message type.");
+        }
+
+        // compose outer message
+        OuterMessage outerMessage = new OuterMessage();
+        outerMessage.status = OuterMessage.STATUS_OK;
+        outerMessage.protocolVersion = 1;
+        outerMessage.type = type;
+        outerMessage.payload = MessageNano.toByteArray(message);
+        return outerMessage;
+    }
+
+    /**
+     * Writes an {@link OuterMessage} to the wire.
+     *
+     * @param message the message
+     * @throws IOException on error during write
+     */
+    private void writeMessage(OuterMessage message) throws IOException {
+        byte[] messageBytes = message.payload;
+        int messageLength = messageBytes.length;
+
+        mOutputStream.write(PoloUtil.intToBigEndianIntBytes(messageLength));
+        mOutputStream.write(messageBytes);
+    }
+
+    /**
+     * Writes a new message to the wire.
+     */
+    public void sendMessage(PoloMessage message)
+            throws IOException, PoloException {
+        MessageNano pb = poloMessageToProto(message);
+        OuterMessage outerMessage = wrapInnerMessage(pb);
+        writeMessage(outerMessage);
+    }
+
+    /**
+     * Sends a new error message to the wire.
+     */
+    public void sendErrorMessage(Exception e) throws IOException {
+        OuterMessage outerMessage = new OuterMessage();
+        outerMessage.protocolVersion = 1;
+
+        if (e instanceof NoConfigurationException) {
+            outerMessage.status = OuterMessage.STATUS_BAD_CONFIGURATION;
+        } else if (e instanceof BadSecretException) {
+            outerMessage.status = OuterMessage.STATUS_BAD_SECRET;
+        } else {
+            outerMessage.status = OuterMessage.STATUS_ERROR;
+        }
+
+        writeMessage(outerMessage);
+    }
+
+    /**
+     * Converts an internal message to the corresponding protocol buffer message.
+     *
+     * @param poloMessage the internal message
+     * @return a new {@link MessageNano} instance
+     */
+    private MessageNano poloMessageToProto(PoloMessage poloMessage) {
+        if (poloMessage instanceof PairingRequestMessage) {
+            return toProto((PairingRequestMessage) poloMessage);
+        } else if (poloMessage instanceof PairingRequestAckMessage) {
+            return toProto((PairingRequestAckMessage) poloMessage);
+        } else if (poloMessage instanceof OptionsMessage) {
+            return toProto((OptionsMessage) poloMessage);
+        } else if (poloMessage instanceof ConfigurationMessage) {
+            return toProto((ConfigurationMessage) poloMessage);
+        } else if (poloMessage instanceof ConfigurationAckMessage) {
+            return toProto((ConfigurationAckMessage) poloMessage);
+        } else if (poloMessage instanceof SecretMessage) {
+            return toProto((SecretMessage) poloMessage);
+        } else if (poloMessage instanceof SecretAckMessage) {
+            return toProto((SecretAckMessage) poloMessage);
+        }
+        return null;
+    }
+
+    /**
+     * Converts a {@link PairingRequestMessage} to a
+     * {@link PoloProto.PairingRequest}.
+     */
+    private PoloProto.PairingRequest toProto(PairingRequestMessage poloMessage) {
+        PoloProto.PairingRequest pairingRequest = new PoloProto.PairingRequest();
+        pairingRequest.serviceName = poloMessage.getServiceName();
+
+        if (poloMessage.hasClientName()) {
+            pairingRequest.clientName = poloMessage.getClientName();
+        }
+        return pairingRequest;
+    }
+
+    /**
+     * Converts a {@link PairingRequestAckMessage} to a
+     * {@link PoloProto.PairingRequestAck}.
+     */
+    private PoloProto.PairingRequestAck toProto(PairingRequestAckMessage poloMessage) {
+        PoloProto.PairingRequestAck pairingRequestAck = new PoloProto.PairingRequestAck();
+        if (poloMessage.hasServerName()) {
+            pairingRequestAck.serverName = poloMessage.getServerName();
+        }
+        return pairingRequestAck;
+    }
+
+    /**
+     * Converts a {@link OptionsMessage} to a {@link PoloProto.Options}.
+     */
+    private PoloProto.Options toProto(OptionsMessage poloMessage) {
+        PoloProto.Options options = new PoloProto.Options();
+
+        switch (poloMessage.getProtocolRolePreference()) {
+            case DISPLAY_DEVICE:
+                options.preferredRole = PoloProto.Options.ROLE_TYPE_INPUT;
+                break;
+            case INPUT_DEVICE:
+                options.preferredRole = PoloProto.Options.ROLE_TYPE_OUTPUT;
+                break;
+        }
+
+        int i = 0, n = poloMessage.getOutputEncodingSet().size();
+        options.outputEncodings = new PoloProto.Options.Encoding[n];
+        for (EncodingOption enc : poloMessage.getOutputEncodingSet()) {
+            options.outputEncodings[i++] = toProto(enc);
+        }
+
+        i = 0;
+        n = poloMessage.getInputEncodingSet().size();
+        options.inputEncodings = new PoloProto.Options.Encoding[n];
+        for (EncodingOption enc : poloMessage.getInputEncodingSet()) {
+            options.inputEncodings[i++] = toProto(enc);
+        }
+
+        return options;
+    }
+
+    /**
+     * Converts a {@link ConfigurationMessage} to a
+     * {@link PoloProto.Configuration}.
+     */
+    private PoloProto.Configuration toProto(ConfigurationMessage poloMessage) {
+        PoloProto.Configuration configuration = new PoloProto.Configuration();
+        configuration.encoding = toProto(poloMessage.getEncoding());
+        configuration.clientRole = toProto(poloMessage.getClientRole());
+        return configuration;
+    }
+
+    /**
+     * Converts a {@link EncodingOption} to a {@link PoloProto.Options.Encoding}.
+     */
+    private PoloProto.Options.Encoding toProto(EncodingOption enc) {
+        PoloProto.Options.Encoding encoding = new PoloProto.Options.Encoding();
+
+        switch (enc.getType()) {
+            case ENCODING_ALPHANUMERIC:
+                encoding.type = PoloProto.Options.Encoding.ENCODING_TYPE_ALPHANUMERIC;
+                break;
+            case ENCODING_HEXADECIMAL:
+                encoding.type = PoloProto.Options.Encoding.ENCODING_TYPE_HEXADECIMAL;
+                break;
+            case ENCODING_NUMERIC:
+                encoding.type = PoloProto.Options.Encoding.ENCODING_TYPE_NUMERIC;
+                break;
+            case ENCODING_QRCODE:
+                encoding.type = PoloProto.Options.Encoding.ENCODING_TYPE_QRCODE;
+                break;
+            default:
+                encoding.type = PoloProto.Options.Encoding.ENCODING_TYPE_UNKNOWN;
+                break;
+        }
+
+        encoding.symbolLength = enc.getSymbolLength();
+        return encoding;
+    }
+
+    /**
+     * Converts a {@link OptionsMessage.ProtocolRole} to a
+     * {@link PoloProto.Options}.
+     */
+    private int toProto(OptionsMessage.ProtocolRole role) {
+        switch (role) {
+            case DISPLAY_DEVICE:
+                return PoloProto.Options.ROLE_TYPE_OUTPUT;
+            case INPUT_DEVICE:
+                return PoloProto.Options.ROLE_TYPE_INPUT;
+            default:
+                return PoloProto.Options.ROLE_TYPE_UNKNOWN;
+        }
+    }
+
+    /**
+     * Converts a {@link ConfigurationAckMessage} to a
+     * {@link PoloProto.ConfigurationAck}.
+     */
+    private PoloProto.ConfigurationAck toProto(ConfigurationAckMessage poloMessage) {
+        PoloProto.ConfigurationAck configurationAck = new PoloProto.ConfigurationAck();
+        return configurationAck;
+    }
+
+    /**
+     * Converts a {@link SecretMessage} to a {@link PoloProto.Secret}.
+     */
+    private PoloProto.Secret toProto(SecretMessage poloMessage) {
+        PoloProto.Secret secret = new PoloProto.Secret();
+        secret.secret = poloMessage.getSecret();
+        return secret;
+    }
+
+    /**
+     * Converts a {@link SecretAckMessage} to a {@link PoloProto.SecretAck}.
+     */
+    private PoloProto.SecretAck toProto(SecretAckMessage poloMessage) {
+        PoloProto.SecretAck secretAck = new PoloProto.SecretAck();
+        secretAck.secret = poloMessage.getSecret();
+        return secretAck;
+    }
+
+    //
+    // polo -> protocol buffer routines
+    //
+
+    /**
+     * Converts a protocol buffer message to the corresponding internal
+     * message.
+     *
+     * @param protoMessage the protobuf message to convert
+     * @return the new {@link PoloMessage}
+     */
+    private PoloMessage protoToPoloMessage(MessageNano protoMessage) {
+        if (protoMessage instanceof PoloProto.PairingRequest) {
+            return fromProto((PoloProto.PairingRequest) protoMessage);
+        } else if (protoMessage instanceof PoloProto.PairingRequestAck) {
+            return fromProto((PoloProto.PairingRequestAck) protoMessage);
+        } else if (protoMessage instanceof PoloProto.Options) {
+            return fromProto((PoloProto.Options) protoMessage);
+        } else if (protoMessage instanceof PoloProto.Configuration) {
+            return fromProto((PoloProto.Configuration) protoMessage);
+        } else if (protoMessage instanceof PoloProto.ConfigurationAck) {
+            return fromProto((PoloProto.ConfigurationAck) protoMessage);
+        } else if (protoMessage instanceof PoloProto.Secret) {
+            return fromProto((PoloProto.Secret) protoMessage);
+        } else if (protoMessage instanceof PoloProto.SecretAck) {
+            return fromProto((PoloProto.SecretAck) protoMessage);
+        }
+        return null;
+    }
+
+    /**
+     * Converts a {@link PoloProto.PairingRequest} to a
+     * {@link PairingRequestMessage}.
+     */
+    private PairingRequestMessage fromProto(PoloProto.PairingRequest protoMessage) {
+        return new PairingRequestMessage(protoMessage.serviceName, protoMessage.clientName);
+    }
+
+    /**
+     * Converts a {@link PoloProto.PairingRequestAck} to a
+     * {@link PairingRequestAckMessage}.
+     */
+    private PairingRequestAckMessage fromProto(PoloProto.PairingRequestAck protoMessage) {
+        return new PairingRequestAckMessage(protoMessage.serverName);
+    }
+
+    /**
+     * Converts a {@link PoloProto.Options} to a {@link OptionsMessage}.
+     */
+    private OptionsMessage fromProto(PoloProto.Options protoMessage) {
+        OptionsMessage optionsMessage = new OptionsMessage();
+
+        switch (protoMessage.preferredRole) {
+            case PoloProto.Options.ROLE_TYPE_INPUT:
+                optionsMessage.setProtocolRolePreference(OptionsMessage.ProtocolRole.INPUT_DEVICE);
+                break;
+            case PoloProto.Options.ROLE_TYPE_OUTPUT:
+                optionsMessage.setProtocolRolePreference(OptionsMessage.ProtocolRole.DISPLAY_DEVICE);
+                break;
+        }
+
+        for (PoloProto.Options.Encoding e : protoMessage.inputEncodings) {
+            optionsMessage.addInputEncoding(fromProto(e));
+        }
+
+        for (PoloProto.Options.Encoding e : protoMessage.outputEncodings) {
+            optionsMessage.addOutputEncoding(fromProto(e));
+        }
+
+        return optionsMessage;
+    }
+
+    /**
+     * Converts a {@link PoloProto.Configuration} to a
+     * {@link ConfigurationMessage}.
+     */
+    private ConfigurationMessage fromProto(PoloProto.Configuration protoMessage) {
+        EncodingOption enc = fromProto(protoMessage.encoding);
+        OptionsMessage.ProtocolRole role = OptionsMessage.ProtocolRole.UNKNOWN;
+
+        switch (protoMessage.clientRole) {
+            case PoloProto.Options.ROLE_TYPE_INPUT:
+                role = OptionsMessage.ProtocolRole.INPUT_DEVICE;
+                break;
+            case PoloProto.Options.ROLE_TYPE_OUTPUT:
+                role = OptionsMessage.ProtocolRole.DISPLAY_DEVICE;
+                break;
+        }
+
+        return new ConfigurationMessage(enc, role);
+    }
+
+    /**
+     * Converts a {@link PoloProto.ConfigurationAck} to a
+     * {@link ConfigurationAckMessage}.
+     */
+    private ConfigurationAckMessage fromProto(PoloProto.ConfigurationAck protoMessage) {
+        return new ConfigurationAckMessage();
+    }
+
+    /**
+     * Converts a {@link PoloProto.Secret} to a {@link SecretMessage}.
+     */
+    private SecretMessage fromProto(PoloProto.Secret protoMessage) {
+        return new SecretMessage(protoMessage.secret);
+    }
+
+    /**
+     * Converts a {@link PoloProto.SecretAck} to a {@link SecretAckMessage}.
+     */
+    private SecretAckMessage fromProto(PoloProto.SecretAck protoMessage) {
+        return new SecretAckMessage(protoMessage.secret);
+    }
+
+    /**
+     * Converts a {@link PoloProto.Options.Encoding} to a {@link EncodingOption}.
+     */
+    private EncodingOption fromProto(PoloProto.Options.Encoding enc) {
+        EncodingOption.EncodingType type;
+
+        switch (enc.type) {
+            case PoloProto.Options.Encoding.ENCODING_TYPE_ALPHANUMERIC:
+                type = EncodingOption.EncodingType.ENCODING_ALPHANUMERIC;
+                break;
+            case PoloProto.Options.Encoding.ENCODING_TYPE_HEXADECIMAL:
+                type = EncodingOption.EncodingType.ENCODING_HEXADECIMAL;
+                break;
+            case PoloProto.Options.Encoding.ENCODING_TYPE_NUMERIC:
+                type = EncodingOption.EncodingType.ENCODING_NUMERIC;
+                break;
+            case PoloProto.Options.Encoding.ENCODING_TYPE_QRCODE:
+                type = EncodingOption.EncodingType.ENCODING_QRCODE;
+                break;
+            default:
+                type = EncodingOption.EncodingType.ENCODING_UNKNOWN;
+        }
+
+        return new EncodingOption(type, enc.symbolLength);
+
+    }
+
+}