Commit 5ce8f292 authored by Björn Butzin's avatar Björn Butzin
Browse files

Cleanup & added feature "/.well-known/core filter" & BUGFIX CoAP Header Option ignored

---
Deleted:
 - CoapWellKnownResource - unfinished & unused
 - Resource - merged content into CoapResource.java -> avoids problematic casting in the ResourceServer
 - ResourceHandler - undocumented/unknown purpose & unused
Modified:
 - AbstractCoapMessage -> BUGFIX CoAP Header Option ignored
 - CoapMediaType -> added mime types
 - BasicCoapResource -> added interface description, size estimate & configuration for read and write permissions
 - CoapResource -> changed to more generic datatypes & merged with Resource
 - CoapResourceServer -> changed according to modiied interfaces
 - CoreResource -> now inherits from BasicCoapResource & removed duplicate code & added feature "/.well-known/core filter"
 - Resource Server -> changed according to modified interfaces & enhanced documentation
 - InterfaceTest -> removed encoding error & warning suppress
parent 856bc757
/.settings
/.gradle
/bin
/build
/target
/.idea
*.iml
\ No newline at end of file
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.ws4d</groupId>
<groupId>org.ws4d.coap</groupId>
<artifactId>jcoap</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>jCoAP</name>
......@@ -23,6 +23,7 @@
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
......
......@@ -554,6 +554,7 @@ public abstract class AbstractCoapMessage implements CoapMessage {
throw new IllegalArgumentException("Header option value MUST NOT be null");
}
this.optionType = optionType;
this.optionTypeValue = optionType.getValue();
this.optionData = value;
if (value.length < 13) {
......
......@@ -22,18 +22,20 @@ package org.ws4d.coap.messages;
* @author Christian Lerche <christian.lerche@uni-rostock.de>
*/
public enum CoapMediaType {
text_plain(0), // text/plain; charset=utf-8
link_format(40), // application/link-format
xml(41), // application/xml
octet_stream(42), // application/octet-stream
exi(47), // application/exi
json(50), // application/json
UNKNOWN(-1);
text_plain(0 ,"text/plain; charset=utf-8"),
link_format(40, "application/link-format"),
xml(41, "application/xml"),
octet_stream(42, "application/octet-stream"),
exi(47, "application/exi"),
json(50, "application/json"),
UNKNOWN(-1, "");
int mediaType;
private int mediaType;
private String mimeType;
private CoapMediaType(int mediaType) {
private CoapMediaType(int mediaType, String mimeType) {
this.mediaType = mediaType;
this.mimeType = mimeType;
}
/**
......@@ -65,6 +67,13 @@ public enum CoapMediaType {
* @return The media type code of the ENUM element.
*/
public int getValue() {
return mediaType;
return this.mediaType;
}
/**
* @return The mime type code of respective coapMediaType.
*/
public String getMimeType() {
return this.mimeType;
}
}
\ No newline at end of file
/* Copyright 2015 University of Rostock
/* Copyright 2016 University of Rostock
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -16,7 +16,8 @@
package org.ws4d.coap.rest;
import java.util.HashMap;
import java.util.Vector;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import org.ws4d.coap.interfaces.CoapChannel;
......@@ -28,39 +29,41 @@ import org.ws4d.coap.messages.CoapResponseCode;
/**
* @author Christian Lerche <christian.lerche@uni-rostock.de>
* @author Bjrn Butzin <bjoern.butzin@uni-rostock.de>
*/
public class BasicCoapResource implements CoapResource {
/* use the logger of the resource server */
private final static Logger logger = Logger
.getLogger(CoapResourceServer.class);
private final static Logger logger = Logger.getLogger(CoapResourceServer.class);
private ResourceServer serverListener = null; // could be a list of listener
// parameter
private String resourceType = null;
private String interfaceDescription = null;
private CoapMediaType mediaType;
private String path;
protected byte[] value;
ResourceHandler resourceHandler = null;
ResourceServer serverListener = null; // could be a list of listener
String resourceType = null;
HashMap<CoapChannel, CoapRequest> observer = new HashMap<CoapChannel, CoapRequest>();
boolean observable = false;
boolean deletable = false;
/** MUST NOT be greater than 0xFFFF (2 byte integer) */
int observeSequenceNumber = 0;
/** DEFAULT NULL: let the client decide */
Boolean reliableNotification = null;
/**
* The Unix time (in milliseconds), when resource expires<br>
* -1, when resource never expires */
long expires = -1;
private byte[] value;
private long expires = -1; // never expires
// permissions
private boolean readable = true;
private boolean writable = true;
private boolean observable = true;
private boolean deletable = true;
// observe
private Map<CoapChannel, CoapRequest> observer = new HashMap<CoapChannel, CoapRequest>();
/** MUST NOT be greater than 0xFFFF (2 byte integer) **/
private int observeSequenceNumber = 0;
/** DEFAULT NULL: let the client decide **/
private Boolean reliableNotification = null;
public BasicCoapResource(String path, byte[] value, CoapMediaType mediaType) {
path = path.trim();
String[] segments = path.split("/");
for(String segment : segments){
if(segment.getBytes().length > 255 ){
throw new IllegalArgumentException("Uri-Path too long");
String[] segments = path.trim().split("/");
for (String segment : segments) {
if (segment.getBytes().length > 255) {
IllegalArgumentException e = new IllegalArgumentException("Uri-Path too long");
logger.warn("BasicCoapResource(" + path + "," + value + "," + mediaType + "): Uri-Path too long", e);
throw e;
}
}
this.path = path;
......@@ -68,110 +71,92 @@ public class BasicCoapResource implements CoapResource {
this.mediaType = mediaType;
}
public void setCoapMediaType(CoapMediaType mediaType) {
public BasicCoapResource setCoapMediaType(CoapMediaType mediaType) {
this.mediaType = mediaType;
return this;
}
@Override
public CoapMediaType getCoapMediaType() {
return mediaType;
return this.mediaType;
}
public String getMimeType() {
// TODO: implement
return null;
return this.mediaType.getMimeType();
}
@Override
public String getPath() {
return path;
return this.path;
}
@Override
public String getShortName() {
return null;
}
@Override
public byte[] getValue() {
return value;
}
@Override
public byte[] getValue(Vector<String> query) {
return value;
return getPath();
}
public void setValue(byte[] value) {
public boolean setValue(byte[] value) {
this.value = value;
this.changed();
return true;
}
@Override
public String getResourceType() {
return resourceType;
}
public void setResourceType(String resourceType) {
this.resourceType = resourceType;
public byte[] getValue() {
return this.value;
}
public Boolean getReliableNotification() {
return reliableNotification;
public byte[] getValue(List<String> query) {
return this.value;
}
/**
*
* @param reliableNotification NULL = let the client decide
* @param reliableNotification
* NULL = let the client decide
*/
public void setReliableNotification(Boolean reliableNotification) {
public BasicCoapResource setReliableNotification(Boolean reliableNotification) {
this.reliableNotification = reliableNotification;
return this;
}
public Boolean getReliableNotification() {
return this.reliableNotification;
}
@Override
public String toString() {
return getPath(); // TODO implement
return getPath()+"\n"+getValue().toString();
}
@Override
public void post(byte[] data) {
if (resourceHandler != null) {
resourceHandler.onPost(data);
}
return;
public boolean post(byte[] data) {
byte[] c = new byte[this.value.length + data.length];
System.arraycopy(this.value, 0, c, 0, this.value.length);
System.arraycopy(data, 0, c, this.value.length, data.length);
this.value = c;
return true;
}
@Override
public void changed() {
if (serverListener != null) {
serverListener.resourceChanged(this);
if (this.serverListener != null) {
this.serverListener.resourceChanged(this);
}
observeSequenceNumber++;
if (observeSequenceNumber > 0xFFFF) {
observeSequenceNumber = 0;
this.observeSequenceNumber++;
if (this.observeSequenceNumber > 0xFFFF) {
this.observeSequenceNumber = 0;
}
/* notify all observers */
for (CoapRequest obsRequest : observer.values()) {
CoapServerChannel channel = (CoapServerChannel) obsRequest
.getChannel();
// notify all observers
for (CoapRequest obsRequest : this.observer.values()) {
CoapServerChannel channel = (CoapServerChannel) obsRequest.getChannel();
CoapResponse response;
if (reliableNotification == null) {
response = channel.createNotification(obsRequest,
CoapResponseCode.Content_205, observeSequenceNumber);
if (this.reliableNotification == null) {
response = channel.createNotification(obsRequest, CoapResponseCode.Content_205,
this.observeSequenceNumber);
} else {
response = channel.createNotification(obsRequest,
CoapResponseCode.Content_205, observeSequenceNumber,
reliableNotification);
response = channel.createNotification(obsRequest, CoapResponseCode.Content_205,
this.observeSequenceNumber, this.reliableNotification);
}
response.setPayload(getValue());
channel.sendNotification(response);
}
}
public void registerResourceHandler(ResourceHandler handler) {
this.resourceHandler = handler;
}
public void registerServerListener(ResourceServer server) {
this.serverListener = server;
}
......@@ -180,55 +165,90 @@ public class BasicCoapResource implements CoapResource {
this.serverListener = null;
}
@Override
public boolean addObserver(CoapRequest request) {
observer.put(request.getChannel(), request);
this.observer.put(request.getChannel(), request);
return true;
}
public void removeObserver(CoapChannel channel) {
observer.remove(channel);
this.observer.remove(channel);
}
public boolean isObservable() {
return observable;
public int getObserveSequenceNumber() {
return this.observeSequenceNumber;
}
public BasicCoapResource setExpires(long expires) {
this.expires = expires;
return this;
}
public void setObservable(boolean observable) {
public long expires() {
return this.expires;
}
public boolean isExpired() {
if (this.expires == -1 || this.expires > System.currentTimeMillis()) {
return false;
}
return true;
}
public BasicCoapResource setReadable(boolean readable) {
this.readable = readable;
return this;
}
public boolean isReadable() {
return this.readable;
}
public BasicCoapResource setWritable(boolean writeable) {
this.writable = writeable;
return this;
}
public boolean isWriteable() {
return this.writable;
}
public BasicCoapResource setObservable(boolean observable) {
this.observable = observable;
return this;
}
public int getObserveSequenceNumber() {
return observeSequenceNumber;
public boolean isObservable() {
return this.observable;
}
public BasicCoapResource setDeletable(boolean deletable) {
this.deletable = deletable;
return this;
}
public boolean isDeletable() {
return deletable;
return this.deletable;
}
public void setDeletable(boolean deletable) {
this.deletable = deletable;
public BasicCoapResource setResourceType(String resourceType) {
this.resourceType = resourceType;
return this;
}
@Override
public long expires() {
return expires;
public String getResourceType() {
return this.resourceType;
}
@Override
public boolean isExpired() {
if (expires == -1) {
return false; // -1 == never expires
}
public BasicCoapResource setInterfaceDescription(String interfaceDescription) {
this.interfaceDescription = interfaceDescription;
return this;
}
if (expires < System.currentTimeMillis()) {
return true;
} else {
return false;
}
public String getInterfaceDescription() {
return this.interfaceDescription;
}
public void setExpires(long expires) {
this.expires = expires;
public int getSizeEstimate() {
return getValue().length;
}
}
}
\ No newline at end of file
......@@ -15,6 +15,8 @@
package org.ws4d.coap.rest;
import java.util.List;
import org.ws4d.coap.interfaces.CoapChannel;
import org.ws4d.coap.interfaces.CoapRequest;
import org.ws4d.coap.messages.CoapMediaType;
......@@ -23,55 +25,104 @@ import org.ws4d.coap.messages.CoapMediaType;
* @author Nico Laum <nico.laum@uni-rostock.de>
* @author Christian Lerche <christian.lerche@uni-rostock.de>
*/
public interface CoapResource extends Resource {
/**
* @return the CoAP Media Type
*/
public CoapMediaType getCoapMediaType();
public interface CoapResource{
/**
* called by the application, when the resource state changed -> used for
* observation
* Can be called to inform the resource about changed content.
*/
public void changed();
/**
* called by the server to register a new observer
* Adds an observer to this resource
*
* @param request
* @return false if resource is not observable
* - the client request to observe this resource
* @return False if and only if the observer can not be added. <br>
* This might have several reasons e.g. that the resource is not
* observable.
*/
public boolean addObserver(CoapRequest request);
/**
* removes an observer from the list
* Removes an observer from this resource
*
* @param channel
*/
public void removeObserver(CoapChannel channel);
/**
* @return true, if the resource is observable.
* @return The last sequence number used for notification. Will not be
* greater than 0xFFFF (2 byte integer)
*/
public boolean isObservable();
public int getObserveSequenceNumber();
/**
* @return The Unix time (in milliseconds), when the resource expires. -1,
* when the resource never expires.
*/
public long expires();
/**
* @return true if and only if the resource is expired
*/
public boolean isExpired();
/* ------------------------------------------------------------------*/
/**
* Get the MIME Type of the resource (e.g., "application/xml")
* @return The MIME Type of this resource as String.
*/
public String getMimeType();
/**
* Get the unique name of this resource
* @return The unique name of the resource.
*/
public String getPath();
public String getShortName();
public boolean setValue(byte[] value);
public byte[] getValue();
public byte[] getValue(List<String> query);
//TODO: bad api: no return value
public boolean post(byte[] data);
public void registerServerListener(ResourceServer server);
public void unregisterServerListener(ResourceServer server);
/**
* @return true, if the resource is deletable.
* @return True, if and only if the resource is readable.
*/
public boolean isDeletable();
public boolean isReadable();
/**
* if the resource is observable
* @return
* @return True, if and only if the resource is writable.
*/
public int getObserveSequenceNumber();
public boolean isWriteable();
/**
* @return The Unix time (in milliseconds), when resource expires. <br>
* -1, when the resource never expires.
* @return True, if and only if the resource is observable.
*/
public long expires();
public boolean isObservable();
/**
* @return true, when the resource is expired
* @return True, if and only if the resource is delete-able.
*/
public boolean isExpired();
public boolean isDeletable();
/**
* @return the CoAP Media Type of this resource
*/
public CoapMediaType getCoapMediaType();
public String getResourceType();
public String getInterfaceDescription();
public int getSizeEstimate();
}
......@@ -22,6 +22,8 @@ import java.net.URI;
import java.net.URISyntaxException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import org.apache.log4j.ConsoleAppender;
......@@ -41,161 +43,154 @@ import org.ws4d.coap.messages.CoapResponseCode;
/**
* @author Christian Lerche <christian.lerche@uni-rostock.de>
* @author Björn Konieczek <bjoern.konieczek@uni-rostock.de>
* @author Bjrn Konieczek <bjoern.konieczek@uni-rostock.de>
*/
public class CoapResourceServer implements CoapServer, ResourceServer {
private int port = 0;
private final static Logger logger = Logger.getLogger(CoapResourceServer.class);
protected HashMap<String, Resource> resources = new HashMap<String, Resource>();
protected HashMap<String, byte[]> etags = new HashMap<String, byte[]>();
private CoreResource coreResource = new CoreResource(this);
private final static Logger logger = Logger.getLogger(CoapResourceServer.class);