Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 package org.ros.internal.transport;
00018
00019 import com.google.common.base.Preconditions;
00020 import com.google.common.collect.Maps;
00021
00022 import org.apache.commons.logging.Log;
00023 import org.apache.commons.logging.LogFactory;
00024 import org.jboss.netty.buffer.ChannelBuffer;
00025 import org.ros.exception.RosRuntimeException;
00026 import org.ros.internal.message.MessageBuffers;
00027
00028 import java.nio.charset.Charset;
00029 import java.util.Collections;
00030 import java.util.Map;
00031 import java.util.Map.Entry;
00032
00036 public class ConnectionHeader {
00037
00038 private static final boolean DEBUG = false;
00039 private static final Log log = LogFactory.getLog(ConnectionHeader.class);
00040
00041 private final Map<String, String> fields;
00042
00051 public static ConnectionHeader decode(ChannelBuffer buffer) {
00052 Map<String, String> fields = Maps.newHashMap();
00053 int position = 0;
00054 int readableBytes = buffer.readableBytes();
00055 while (position < readableBytes) {
00056 int fieldSize = buffer.readInt();
00057 position += 4;
00058 if (fieldSize == 0) {
00059 throw new IllegalStateException("Invalid 0 length handshake header field.");
00060 }
00061 if (position + fieldSize > readableBytes) {
00062 throw new IllegalStateException("Invalid line length handshake header field.");
00063 }
00064 String field = decodeAsciiString(buffer, fieldSize);
00065 position += field.length();
00066 Preconditions.checkState(field.indexOf("=") > 0,
00067 String.format("Invalid field in handshake header: \"%s\"", field));
00068 String[] keyAndValue = field.split("=");
00069 if (keyAndValue.length == 1) {
00070 fields.put(keyAndValue[0], "");
00071 } else {
00072 fields.put(keyAndValue[0], keyAndValue[1]);
00073 }
00074 }
00075 if (DEBUG) {
00076 log.info("Decoded header: " + fields);
00077 }
00078 ConnectionHeader connectionHeader = new ConnectionHeader();
00079 connectionHeader.mergeFields(fields);
00080 return connectionHeader;
00081 }
00082
00083 private static String decodeAsciiString(ChannelBuffer buffer, int length) {
00084 return buffer.readBytes(length).toString(Charset.forName("US-ASCII"));
00085 }
00086
00087 public ConnectionHeader() {
00088 this.fields = Maps.newConcurrentMap();
00089 }
00090
00097 public ChannelBuffer encode() {
00098 ChannelBuffer buffer = MessageBuffers.dynamicBuffer();
00099 for (Entry<String, String> entry : fields.entrySet()) {
00100 String field = entry.getKey() + "=" + entry.getValue();
00101 buffer.writeInt(field.length());
00102 buffer.writeBytes(field.getBytes(Charset.forName("US-ASCII")));
00103 }
00104 return buffer;
00105 }
00106
00107 public void merge(ConnectionHeader other) {
00108 Map<String, String> otherFields = other.getFields();
00109 mergeFields(otherFields);
00110 }
00111
00112 public void mergeFields(Map<String, String> other) {
00113 for (Entry<String, String> field : other.entrySet()) {
00114 String name = field.getKey();
00115 String value = field.getValue();
00116 addField(name, value);
00117 }
00118 }
00119
00120 public void addField(String name, String value) {
00121 if (!fields.containsKey(name) || fields.get(name).equals(value)) {
00122 fields.put(name, value);
00123 } else {
00124 throw new RosRuntimeException(String.format("Unable to merge field %s: %s != %s", name,
00125 value, fields.get(name)));
00126 }
00127 }
00128
00129 public Map<String, String> getFields() {
00130 return Collections.unmodifiableMap(fields);
00131 }
00132
00133 public boolean hasField(String name) {
00134 return fields.containsKey(name);
00135 }
00136
00137 public String getField(String name) {
00138 return fields.get(name);
00139 }
00140
00141 @Override
00142 public String toString() {
00143 return String.format("ConnectionHeader <%s>", fields.toString());
00144 }
00145
00146 @Override
00147 public int hashCode() {
00148 final int prime = 31;
00149 int result = 1;
00150 result = prime * result + ((fields == null) ? 0 : fields.hashCode());
00151 return result;
00152 }
00153
00154 @Override
00155 public boolean equals(Object obj) {
00156 if (this == obj)
00157 return true;
00158 if (obj == null)
00159 return false;
00160 if (getClass() != obj.getClass())
00161 return false;
00162 ConnectionHeader other = (ConnectionHeader) obj;
00163 if (fields == null) {
00164 if (other.fields != null)
00165 return false;
00166 } else if (!fields.equals(other.fields))
00167 return false;
00168 return true;
00169 }
00170 }