Package ch.ethz.inf.vs.californium.rd.resources

Source Code of ch.ethz.inf.vs.californium.rd.resources.RDNodeResource$ValidationTask

package ch.ethz.inf.vs.californium.rd.resources;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Logger;

import ch.ethz.inf.vs.californium.coap.CoAP.ResponseCode;
import ch.ethz.inf.vs.californium.coap.LinkFormat;
import ch.ethz.inf.vs.californium.coap.MediaTypeRegistry;
import ch.ethz.inf.vs.californium.coap.Request;
import ch.ethz.inf.vs.californium.coap.Response;
import ch.ethz.inf.vs.californium.network.config.NetworkConfig;
import ch.ethz.inf.vs.californium.server.resources.CoapExchange;
import ch.ethz.inf.vs.californium.server.resources.Resource;
import ch.ethz.inf.vs.californium.server.resources.ResourceBase;

public class RDNodeResource extends ResourceBase {

  private static final Logger LOGGER = Logger.getLogger(RDNodeResource.class.getCanonicalName());
 
  /*
   * After the lifetime expires, the endpoint has RD_VALIDATION_TIMEOUT seconds
   * to update its entry before the RD enforces validation and removes the endpoint
   * if it does not respond.
   */
  private Timer lifetimeTimer;
  private Timer validationTimer;
 
  private int lifeTime;
  private long expiryTime;
 
  private String endpointIdentifier;
  private String domain;
  private String endpointType;
  private String context;
 
  private byte[] etag = null;
 
 
  public RDNodeResource(String name, String endpointID, String domain) {
    super(name);   
    this.endpointIdentifier = endpointID;
    this.domain = domain;
  }

  /**
   * Updates the endpoint parameters from POST and PUT requests.
   *
   * @param request A POST or PUT request with a {?et,lt,con} URI Template query
   *       and a Link Format payload.
   *
   */
  public boolean setParameters(Request request) {

    LinkAttribute attr;
   
    String newEndpointType = "";
    int newLifeTime = NetworkConfig.getStandard().getInt("RD_DEFAULT_LIFETIME");
    String newContext = "";
   
    /*
     * get lifetime from option query - only for PUT request.
     */
    List<String> query = request.getOptions().getURIQueries();
    for (String q : query) {
      // FIXME Do not use Link attributes for URI template variables
      attr = LinkAttribute.parse(q);

      if (attr.getName().equals(LinkFormat.END_POINT_TYPE)) {
        newEndpointType = attr.getValue();
      }
     
      if (attr.getName().equals(LinkFormat.LIFE_TIME)) {
        newLifeTime = attr.getIntValue();
       
        if (newLifeTime < 60) {
          LOGGER.warning("Enforcing minimal RD lifetime of 60 seconds (was "+newLifeTime+")");
          newLifeTime = 60;
        }
      }
     
      if (attr.getName().equals(LinkFormat.CONTEXT)){
        newContext = attr.getValue();
      }
    }
   
    setEndpointType(newEndpointType);
    setLifeTime(newLifeTime);

    // TODO check with draft authors if update should be atomic
    if (newContext.equals("")) {
      context = "coap://" + request.getSource()+":"+request.getSourcePort();
    } else {
      Request checkRequest = Request.newGet();

      try {
        checkRequest.setURI(context);
      } catch (Exception e) {
        LOGGER.warning(e.toString());
        return false;
      }
    }
   
    return updateEndpointResources(request.getPayloadString());
  }

  /*
   * add a new resource to the node. E.g. the resource temperature or
   * humidity. If the path is /readings/temp, temp will be a subResource
   * of readings, which is a subResource of the node.
   */
  public ResourceBase addNodeResource(String path) {
    Scanner scanner = new Scanner(path);
    scanner.useDelimiter("/");
    String next = "";
    boolean resourceExist = false;
    Resource resource = this; // It's the resource that represents the endpoint
   
    ResourceBase subResource = null;
    while (scanner.hasNext()) {
      resourceExist = false;
      next = scanner.next();
      for (Resource res : resource.getChildren()) {
        if (res.getName().equals(next)) {
          subResource = (ResourceBase) res;
          resourceExist = true;
        }
      }
      if (!resourceExist) {
        subResource = new RDTagResource(next,true, this);
        resource.add(subResource);
      }
      resource = subResource;
    }
    subResource.setPath(resource.getPath());
    subResource.setName(next);
    scanner.close();
    return subResource;
  }

  @Override
  public void delete() {

    LOGGER.info("Removing endpoint: "+getContext());
   
    if (lifetimeTimer!=null) {
      lifetimeTimer.cancel();
    }
    if (validationTimer!=null) {
      validationTimer.cancel();
    }
   
    super.delete();
  }

  /*
   * GET only debug return endpoint identifier
   */
  @Override
  public void handleGET(CoapExchange exchange) {
    exchange.setMaxAge((int) Math.max((expiryTime - System.currentTimeMillis())/1000, 0));
    exchange.respond(ResponseCode.CONTENT, endpointIdentifier+"."+domain, MediaTypeRegistry.TEXT_PLAIN);
  }
 
  /*
   * PUTs content to this resource. PUT is a periodic request from the
   * node to update the lifetime.
   */
  @Override
  public void handlePUT(CoapExchange exchange) {
   
    if (lifetimeTimer != null) {
      lifetimeTimer.cancel();
    }
    if (validationTimer!=null) {
      validationTimer.cancel();
    }
   
    setParameters(exchange.advanced().getRequest());
   
    // complete the request
    exchange.respond(ResponseCode.CHANGED);
   
  }
 
  /*
   * DELETEs this node resource
   */
  @Override
  public void handleDELETE(CoapExchange exchange) {
    delete();
    exchange.respond(ResponseCode.DELETED);
  }

  /*
   * set either a new lifetime (for new resources, POST request) or update
   * the lifetime (for PUT request)
   */
  public void setLifeTime(int newLifeTime) {
   
    lifeTime = newLifeTime;
   
    expiryTime = System.currentTimeMillis() + lifeTime * 1000;
   
    if (lifetimeTimer != null) {
      lifetimeTimer.cancel();
    }
    if (validationTimer!=null) {
      validationTimer.cancel();
    }
   
    lifetimeTimer = new Timer();
    lifetimeTimer.schedule(new ExpiryTask(this), lifeTime * 1000);// from sec to ms
 
  }

 
   
  /**
   * Creates a new subResource for each resource the node wants
   * register. Each resource is separated by ",". E.g. A node can
   * register a resource for reading the temperature and another one
   * for reading the humidity.
   */
  private boolean updateEndpointResources(String linkFormat) {

    Scanner scanner = new Scanner(linkFormat);
   
    scanner.useDelimiter(",");
    List<String> pathResources = new ArrayList<String>();
    while (scanner.hasNext()) {
      pathResources.add(scanner.next());
    }
    for (String p : pathResources) {
      scanner = new Scanner(p);

      /*
       * get the path of the endpoint's resource. E.g. from
       * </readings/temp> it will select /readings/temp.
       */
      String path = "", pathTemp = "";
      if ((pathTemp = scanner.findInLine("</.*?>")) != null) {
        path = pathTemp.substring(1, pathTemp.length() - 1);
      } else {
        scanner.close();
        return false;
      }
     
      ResourceBase resource = addNodeResource(path);
      /*
       * Since created the subResource, get all the attributes from
       * the payload. Each parameter is separated by a ";".
       */
      scanner.useDelimiter(";");
      while (scanner.hasNext()) {
        LinkAttribute attr = LinkAttribute.parse(scanner.next());
        if (attr.getValue() == null)
          resource.getAttributes().addAttribute(attr.getName());
        else resource.getAttributes().addAttribute(attr.getName(), attr.getValue());
      }
      resource.getAttributes().addAttribute(LinkFormat.END_POINT, getEndpointIdentifier());
    }
    scanner.close();
   
    return true;
  }

  // TODO: Merge into LinkFormat class
  /*
   * the following three methods are used to print the right string to put in
   * the payload to respond to the GET request.
   */
  public String toLinkFormat(List<String> query) {

    // Create new StringBuilder
    StringBuilder builder = new StringBuilder();
   
    // Build the link format
    buildLinkFormat(this, builder, query);

    // Remove last delimiter
    if (builder.length() > 0) {
      builder.deleteCharAt(builder.length() - 1);
    }

    return builder.toString();
  }

  public String toLinkFormatItem(Resource resource) {
    StringBuilder linkFormat = new StringBuilder();

//TODO return absolute link
    linkFormat.append("<"+getContext());
    linkFormat.append(resource.getPath().substring(this.getPath().length()));
    linkFormat.append(">");
   
    return linkFormat.append( LinkFormat.serializeResource(resource).toString().replaceFirst("<.+>", "") ).toString();
  }
 

  private void buildLinkFormat(Resource resource, StringBuilder builder, List<String> query) {
    if (resource.getChildren().size() > 0) {

      // Loop over all sub-resources
      for (Resource res : resource.getChildren()) {
        // System.out.println(resource.getSubResources().size());
        // System.out.println(res.getName());
        if (LinkFormat.matches(res, query) && res.getAttributes().getCount() > 0) {

          // Convert Resource to string representation and add
          // delimiter
          builder.append(toLinkFormatItem(res));
          builder.append(',');
        }
        // Recurse
        buildLinkFormat(res, builder, query);
      }
    }
  }
 
 
 
  /*
   * Setter And Getter
   */

  public String getEndpointIdentifier() {
    return endpointIdentifier;
  }

  public String getDomain() {
    return domain;
  }

  public String getEndpointType() {
    return endpointType;
  }

  public void setEndpointType(String endpointType) {
    this.endpointType = endpointType;
  }

  public String getContext() {
    return context;
  }

  public void setContext(String context) {
    this.context = context;
  }
 
  class ExpiryTask extends TimerTask {
    RDNodeResource resource;

    public ExpiryTask(RDNodeResource resource) {
      super();
      this.resource = resource;
    }

    @Override
    public void run() {
      LOGGER.info("Scheduling validation of expired endpoint: "+getContext());
      validationTimer = new Timer();
      validationTimer.schedule(new ValidationTask(resource), NetworkConfig.getStandard().getInt("RD_VALIDATION_TIMEOUT") * 1000);
    }
  }
 
  class ValidationTask extends TimerTask {
    RDNodeResource resource;

    public ValidationTask(RDNodeResource resource) {
      super();
      this.resource = resource;
    }

    @Override
    public void run() {

      LOGGER.info("Validating endpoint: "+getContext());
     
      Request validationRequest = Request.newGet();
      validationRequest.setURI(getContext()+"/.well-known/core");
      if (etag!=null) {
        validationRequest.getOptions().addETag(etag);
      }
      Response response = null;
     
      try {
        validationRequest.send();
        response = validationRequest.waitForResponse();
       
      } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
     
      if (response == null) {
       
        delete();
       
      } else if(response.getCode() == ResponseCode.VALID) {
       
        LOGGER.fine("Resources up-to-date: "+getContext());
       
      } else if (response.getCode() == ResponseCode.CONTENT) {
 
        List<byte[]> etags = response.getOptions().getETags();
       
        if (!etags.isEmpty()) {
          etag = etags.get(0);
        }
 
        updateEndpointResources(response.getPayloadString());
        setLifeTime(lifeTime);
       
        LOGGER.fine("Updated Resources: " + getContext());
      }
    }
  }
 
}
TOP

Related Classes of ch.ethz.inf.vs.californium.rd.resources.RDNodeResource$ValidationTask

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.