blob: d05848d11b3c7bd42ec140ceff67e618ca605be5 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.mina.coap;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import org.apache.mina.filter.query.Request;
import org.apache.mina.filter.query.Response;
/**
* A representation of CoAP message following the CoAP RFC.
*
* @author <a href="http://mina.apache.org">Apache MINA Project</a>
*/
public class CoapMessage implements Request, Response {
public static final CoapMessage get(String url, boolean confimable) {
return new CoapMessage(1, confimable ? MessageType.CONFIRMABLE : MessageType.NON_CONFIRMABLE,
CoapCode.GET.getCode(), (int) (System.nanoTime() % 65536), null, optionsForUrl(url), null);
}
public static final CoapMessage post(String url, boolean confimable, byte[] payload) {
return new CoapMessage(1, confimable ? MessageType.CONFIRMABLE : MessageType.NON_CONFIRMABLE,
CoapCode.GET.getCode(), (int) (System.nanoTime() % 65536), null, optionsForUrl(url), payload);
}
private static final CoapOption[] optionsForUrl(String url) {
String[] parts = url.split("\\?");
String[] paths = parts[0].split("\\/");
String[] params = new String[] {};
if (parts.length > 1) {
params = parts[1].split("\\&");
}
CoapOption[] opt = new CoapOption[paths.length + params.length];
for (int i = 0; i < paths.length; i++) {
try {
opt[i] = new CoapOption(CoapOptionType.URI_PATH, paths[i].getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException(e);
}
}
for (int i = 0; i < params.length; i++) {
try {
opt[paths.length + i] = new CoapOption(CoapOptionType.URI_QUERY, params[i].getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException(e);
}
}
return opt;
}
private static final byte[] EMPTY_BYTE_ARRAY = new byte[] {};
private int version;
private MessageType type;
private int code;
private int id;
private byte[] token;
private byte[] payload;
private CoapOption[] options;
/**
* Create a CoAP message
*
* @param version the version (you probably want 1 here)
* @param type the type of CoAP message
* @param code the message code : {@link CoapCode}
* @param id the identifier for this message
* @param token the message token (can be <code>null</code>)
* @param options list of options for this message (can be <code>null</code>)
* @param payload the payload of the message (can be <code>null</code>
*/
public CoapMessage(int version, MessageType type, int code, int id, byte[] token, CoapOption[] options,
byte[] payload) {
super();
this.version = version;
this.type = type;
this.code = code;
this.id = id;
this.token = token == null ? EMPTY_BYTE_ARRAY : token;
this.payload = payload == null ? EMPTY_BYTE_ARRAY : payload;
this.options = options == null ? new CoapOption[] {} : options;
// sort options by code (easier for delta encoding)
Arrays.<CoapOption> sort(this.options, new Comparator<CoapOption>() {
@Override
public int compare(CoapOption o1, CoapOption o2) {
return o1.getType().getCode() < o2.getType().getCode() ? -1 : (o1.getType().getCode() == o2.getType()
.getCode() ? 0 : 1);
};
});
}
/**
* {@inheritDoc}
*/
@Override
public Object requestId() {
return id;
}
public int getVersion() {
return version;
}
public int getCode() {
return code;
}
public int getId() {
return id;
}
public byte[] getToken() {
return token;
}
public byte[] getPayload() {
return payload;
}
public CoapOption[] getOptions() {
return options;
}
public MessageType getType() {
return type;
}
/* Utility methods to rebuild some CoAP options */
/**
* @return all segments of the absolute path to the resource
*/
public String[] getUriPath() {
return strArrayOptions(CoapOptionType.URI_PATH);
}
/**
* @return all arguments parameterizing the resource
*/
public String[] getUriQuery() {
return strArrayOptions(CoapOptionType.URI_QUERY);
}
/**
* @return the Internet host of the resource being requested
*/
public String getUriHost() {
return strOption(CoapOptionType.URI_HOST);
}
/**
* @return the transport layer port number of the resource
*/
public Integer getUriPort() {
return intOption(CoapOptionType.URI_PORT);
}
/**
* return the absolute URI used to make a request to a forward-proxy
*/
public String getProxyUri() {
return strOption(CoapOptionType.PROXY_URI);
}
/**
* @return the scheme to be used in the proxy URI
*/
public String getProxyScheme() {
return strOption(CoapOptionType.PROXY_SCHEME);
}
/**
* @return the representation format of the message payload
*/
public Integer getContentFormat() {
return intOption(CoapOptionType.CONTENT_FORMAT);
}
/**
* @return which Content-Format is acceptable to the client
*/
public Integer getAccept() {
return intOption(CoapOptionType.ACCEPT);
}
/**
* @return the maximum time a response may be cached before it is considered not fresh
*/
public Integer getMaxAge() {
return intOption(CoapOptionType.MAX_AGE);
}
/**
* @return all segments of the path to the created resource (as the result of a POST request)
*/
public String[] getLocationPath() {
return strArrayOptions(CoapOptionType.LOCATION_PATH);
}
/**
* @return all arguments parameterizing the created resource (as the result of a POST request)
*/
public String[] getLocationQuery() {
return strArrayOptions(CoapOptionType.LOCATION_QUERY);
}
private String strOption(CoapOptionType type) {
if (options != null) {
for (CoapOption option : options) {
if (type.equals(option.getType())) {
try {
return new String(option.getData(), "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException(e);
}
}
}
}
return null;
}
private String[] strArrayOptions(CoapOptionType type) {
Collection<String> opts = new ArrayList<>();
if (options != null) {
for (CoapOption option : options) {
if (type.equals(option.getType())) {
try {
opts.add(new String(option.getData(), "UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException(e);
}
}
}
}
return opts.toArray(new String[0]);
}
private Integer intOption(CoapOptionType type) {
if (options != null) {
for (CoapOption option : options) {
if (type.equals(option.getType())) {
ByteBuffer bb = ByteBuffer.wrap(option.getData());
bb.order(ByteOrder.BIG_ENDIAN);
return bb.getInt();
}
}
}
return null;
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
CoapCode c = CoapCode.fromCode(code);
String cstr;
if (c == null) {
cstr = String.valueOf(code);
} else {
cstr = c.getText();
}
builder.append("CoapMessage [version=").append(version).append(", type=").append(type).append(", code=")
.append(cstr).append(", id=").append(id).append(", token=").append(Arrays.toString(token))
.append(", payload=").append(Arrays.toString(payload)).append(", options=")
.append(Arrays.toString(options)).append("]");
return builder.toString();
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + code;
result = prime * result + id;
result = prime * result + Arrays.hashCode(options);
result = prime * result + Arrays.hashCode(payload);
result = prime * result + Arrays.hashCode(token);
result = prime * result + ((type == null) ? 0 : type.hashCode());
result = prime * result + version;
return result;
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
CoapMessage other = (CoapMessage) obj;
if (code != other.code) {
return false;
}
if (id != other.id) {
return false;
}
if (!Arrays.equals(options, other.options)) {
return false;
}
if (!Arrays.equals(payload, other.payload)) {
return false;
}
if (!Arrays.equals(token, other.token)) {
return false;
}
if (type != other.type) {
return false;
}
if (version != other.version) {
return false;
}
return true;
}
public void setVersion(int version) {
this.version = version;
}
public void setType(MessageType type) {
this.type = type;
}
public void setCode(int code) {
this.code = code;
}
public void setId(int id) {
this.id = id;
}
public void setToken(byte[] token) {
this.token = token;
}
public void setPayload(byte[] payload) {
this.payload = payload;
}
public void setOptions(CoapOption[] options) {
this.options = options;
}
}