org.ros.internal.transport.ConnectionHeader.java Source code

Java tutorial

Introduction

Here is the source code for org.ros.internal.transport.ConnectionHeader.java

Source

/*
 * Copyright (C) 2011 Google Inc.
 *
 * 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 org.ros.internal.transport;

import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;

import org.apache.commons.logging.Log;
import org.jboss.netty.buffer.ChannelBuffer;
import org.ros.exception.RosRuntimeException;
import org.ros.internal.message.MessageBuffers;
import org.ros.log.RosLogFactory;

import java.nio.charset.Charset;
import java.util.Collections;
import java.util.Map;
import java.util.Map.Entry;

/**
 * @author damonkohler@google.com (Damon Kohler)
 */
public class ConnectionHeader {

    private static final Log log = RosLogFactory.getLog(ConnectionHeader.class);

    private final Map<String, String> fields;

    /**
     * Decodes a header that came over the wire into a {@link Map} of fields and
     * values.
     *
     * @param buffer
     *          the incoming {@link ChannelBuffer} containing the header
     * @return a {@link Map} of header fields and values
     */
    public static ConnectionHeader decode(ChannelBuffer buffer) {
        Map<String, String> fields = Maps.newHashMap();
        int position = 0;
        int readableBytes = buffer.readableBytes();
        while (position < readableBytes) {
            int fieldSize = buffer.readInt();
            position += 4;
            if (fieldSize == 0) {
                throw new IllegalStateException("Invalid 0 length handshake header field.");
            }
            if (position + fieldSize > readableBytes) {
                throw new IllegalStateException("Invalid line length handshake header field.");
            }
            String field = decodeAsciiString(buffer, fieldSize);
            position += field.length();
            Preconditions.checkState(field.indexOf("=") > 0,
                    String.format("Invalid field in handshake header: \"%s\"", field));
            String[] keyAndValue = field.split("=");
            if (keyAndValue.length == 1) {
                fields.put(keyAndValue[0], "");
            } else {
                fields.put(keyAndValue[0], keyAndValue[1]);
            }
        }
        if (log.isDebugEnabled()) {
            log.debug("Decoded header: " + fields);
        }
        ConnectionHeader connectionHeader = new ConnectionHeader();
        connectionHeader.mergeFields(fields);
        return connectionHeader;
    }

    private static String decodeAsciiString(ChannelBuffer buffer, int length) {
        return buffer.readBytes(length).toString(Charset.forName("US-ASCII"));
    }

    public ConnectionHeader() {
        this.fields = Maps.newConcurrentMap();
    }

    /**
     * Encodes this {@link ConnectionHeader} for transmission over the wire.
     *
     * @return a {@link ChannelBuffer} containing the encoded header for wire
     *         transmission
     */
    public ChannelBuffer encode() {
        ChannelBuffer buffer = MessageBuffers.dynamicBuffer();
        for (Entry<String, String> entry : fields.entrySet()) {
            String field = entry.getKey() + "=" + entry.getValue();
            buffer.writeInt(field.length());
            buffer.writeBytes(field.getBytes(Charset.forName("US-ASCII")));
        }
        return buffer;
    }

    public void merge(ConnectionHeader other) {
        Map<String, String> otherFields = other.getFields();
        mergeFields(otherFields);
    }

    public void mergeFields(Map<String, String> other) {
        for (Entry<String, String> field : other.entrySet()) {
            String name = field.getKey();
            String value = field.getValue();
            addField(name, value);
        }
    }

    public void addField(String name, String value) {
        if (!fields.containsKey(name) || fields.get(name).equals(value)) {
            fields.put(name, value);
        } else {
            throw new RosRuntimeException(
                    String.format("Unable to merge field %s: %s != %s", name, value, fields.get(name)));
        }
    }

    public Map<String, String> getFields() {
        return Collections.unmodifiableMap(fields);
    }

    public boolean hasField(String name) {
        return fields.containsKey(name);
    }

    public String getField(String name) {
        return fields.get(name);
    }

    @Override
    public String toString() {
        return String.format("ConnectionHeader <%s>", fields.toString());
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((fields == null) ? 0 : fields.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        ConnectionHeader other = (ConnectionHeader) obj;
        if (fields == null) {
            if (other.fields != null)
                return false;
        } else if (!fields.equals(other.fields))
            return false;
        return true;
    }
}