vitro.vgw.wsiadapter.TCSWSIAdapter.java Source code

Java tutorial

Introduction

Here is the source code for vitro.vgw.wsiadapter.TCSWSIAdapter.java

Source

/*
 * #--------------------------------------------------------------------------
 * # Copyright (c) 2013 VITRO FP7 Consortium.
 * # All rights reserved. This program and the accompanying materials
 * # are made available under the terms of the GNU Lesser Public License v3.0 which accompanies this distribution, and is available at
 * # http://www.gnu.org/licenses/lgpl-3.0.html
 * #
 * # Contributors:
 * #     Antoniou Thanasis (Research Academic Computer Technology Institute)
 * #     Paolo Medagliani (Thales Communications & Security)
 * #     D. Davide Lamanna (WLAB SRL)
 * #     Alessandro Leoni (WLAB SRL)
 * #     Francesco Ficarola (WLAB SRL)
 * #     Stefano Puglia (WLAB SRL)
 * #     Panos Trakadas (Technological Educational Institute of Chalkida)
 * #     Panagiotis Karkazis (Technological Educational Institute of Chalkida)
 * #     Andrea Kropp (Selex ES)
 * #     Kiriakos Georgouleas (Hellenic Aerospace Industry)
 * #     David Ferrer Figueroa (Telefonica Investigacin y Desarrollo S.A.)
 * #
 * #--------------------------------------------------------------------------
 */
package vitro.vgw.wsiadapter;

import alter.vitro.vgw.wsiadapter.InfoOnTrustRouting;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.ws4d.coap.connection.BasicCoapChannelManager;
import org.ws4d.coap.interfaces.CoapChannelManager;
import org.ws4d.coap.interfaces.CoapClient;
import org.ws4d.coap.interfaces.CoapClientChannel;
import org.ws4d.coap.interfaces.CoapRequest;
import org.ws4d.coap.interfaces.CoapResponse;
import org.ws4d.coap.messages.CoapEmptyMessage;
import org.ws4d.coap.messages.CoapRequestCode;
import vitro.vgw.exception.VitroGatewayException;
import vitro.vgw.exception.WSIAdapterException;
import vitro.vgw.model.Node;
import vitro.vgw.model.NodeDescriptor;
import vitro.vgw.model.Observation;
import vitro.vgw.model.Resource;
import vitro.vgw.wsiadapter.coap.model.MoteResource;
import vitro.vgw.wsiadapter.coap.model.Network;
import vitro.vgw.wsiadapter.coap.util.Constants;
import vitro.vgw.wsiadapter.coap.util.Functions;
import ch.ethz.inf.vs.californium.coap.*;
import ch.ethz.inf.vs.californium.endpoint.RemoteResource;
import ch.ethz.inf.vs.californium.util.Log;
//import ch.ethz.inf.vs.californium.endpoint.Resource;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.thalesgroup.tai.sensors.*;

public class TCSWSIAdapter implements WSIAdapter, CoapClient {
    private static final int UNDEFINED_COAP_MESSAGE_ID = -1;
    static ArrayList<Integer> timedOutCoapMessageIDsList = new ArrayList<Integer>();
    static ArrayList<Integer> timedOut_DTN_CoapMessageIDsList = new ArrayList<Integer>(); //stores packet Ids
    //15/04
    static HashMap<String, CoapClientChannel> proxyAddrToClientChannelResourcesHM = new HashMap<String, CoapClientChannel>();
    static HashMap<String, CoapClientChannel> proxyAddrToClientChannelObservationsHM = new HashMap<String, CoapClientChannel>();

    private JSONParser parser;
    private List<NodeDescriptor> nodeList;
    private List<Node> listofnode;
    private List<Resource> resourceList;
    private Logger logger = LoggerFactory.getLogger(getClass());
    private CountDownLatch signal;
    private CoapChannelManager channelManager;
    //private CoapClientChannel clientChannelObservations;
    //private CoapClientChannel clientChannelResources;
    private String resourceValue;
    private String exceptionError;
    // uri of coap proxy
    private URI proxyUri;
    private boolean isDtnEnabled;
    private boolean trustCoapMessagingActivated;
    private final int PORT = Constants.COAP_DEFAULT_PORT;
    private List<Request> pendingRequests;

    private static final String DISCOVERY_RESOURCE = "/.well-known/core";

    private static final int IDX_ZMQ_RPLSOCKET = 0;
    private static final int IDX_ZMQ_PUBSOCKET = 1;
    private static final int IDX_COAP_PROXY = 2;
    private static final int IDX_SOS_ENDPOINT = 3;

    private static final int ERR_BAD_URI = 2;
    private static final int ERR_REQUEST_FAILED = 5;
    private static final int ERR_RESPONSE_FAILED = 6;
    private static final int ERR_BAD_LINK_FORMAT = 7;
    private static final int ERR_MISSING_ZMQ_PULLSOCKET = 8;
    private static final int ERR_MISSING_ZMQ_PUBSOCKET = 9;
    private static final int ERR_MISSING_COAP_PROXY = 10;
    private static final int ERR_MISSING_SOS_ENDPOINT = 11;

    // if we use a coap proxy. Note: 03/05/2012, could not use jcoap as CoAP-CoAP
    // proxy. interoperability problem.
    private boolean useCoapProxy = false;

    public TCSWSIAdapter() {
        signal = null;
        channelManager = null;
        //clientChannelObservations = null;
        //clientChannelResources = null;
        nodeList = new ArrayList<NodeDescriptor>();
        listofnode = new ArrayList<Node>();
        resourceList = new ArrayList<Resource>();
        resourceValue = null;
        exceptionError = "";
        parser = new JSONParser();
        channelManager = BasicCoapChannelManager.getInstance();
        isDtnEnabled = false;
        trustCoapMessagingActivated = false;
        pendingRequests = new ArrayList<Request>();
    }

    /*
     * This method returns the list of all Nodes managed by VGW.
     *
     * If a discovery process is not available on the underlying WSNs, a configuration file could be used
     *
     * Thales :
     * Step 1 : Get the addresses of the json.
     * Step 2 : Sort this information inside the right objects.
     */

    public List<Node> getAvailableNodeList() throws WSIAdapterException {

        String raw_data = doHttpGet("http://[aaaa::212:7401:1:101]");

        if (!raw_data.equals("")) {
            Object raw_obj = null;

            try {

                raw_obj = parser.parse(raw_data);
            } catch (ParseException pe) {

                System.out.println("position: " + pe.getPosition());
                System.out.println(pe);

            }

            System.out.println(raw_obj);

            JSONObject obj2 = (JSONObject) raw_obj;
            JSONArray raw_arr = (JSONArray) obj2.get("route");

            System.out.println("Routes are: " + raw_arr);

            //

            assert obj2 != null;
            //   JSONArray raw_arr = (JSONArray) obj2.get("address");

            //   System.out.println("Nodes are: " + raw_arr);
            Object[] objs = raw_arr.toArray();
            for (Object o : objs) {
                JSONObject id = (JSONObject) o;
                String ipaddr = ((String) id.get("address")).split("/")[0];
                Node n = new NodeDescriptor();

                Node m = new Node();

                n.setId(ipaddr);
                if (nodeList == null) {
                    System.err.println("m vale " + m);
                    return null;
                }
                nodeList.add((NodeDescriptor) n);

                m.setId(ipaddr);
                listofnode.add(m);

            }
        }
        return listofnode;
    }

    public static String doHttpGet(String endpoint) {
        String output;
        String temp = "";
        try {

            DefaultHttpClient httpClient = new DefaultHttpClient();
            HttpGet getRequest = new HttpGet(endpoint);
            getRequest.addHeader("accept", "application/json");

            HttpResponse response = httpClient.execute(getRequest);

            if (response.getStatusLine().getStatusCode() != 200) {
                throw new RuntimeException(
                        "Failed : HTTP error code : " + response.getStatusLine().getStatusCode());
            }

            BufferedReader br = new BufferedReader(new InputStreamReader((response.getEntity().getContent())));

            System.out.println("Output from Server .... \n");
            while ((output = br.readLine()) != null) {
                System.out.println(output);
                temp = output;

            }
            br.close();
            httpClient.getConnectionManager().shutdown();

        } catch (ClientProtocolException e) {
            System.err.println("ClientProtocolException\n");
            return "";

        } catch (IOException e) {
            System.err.println("IOException\n");
            return "";
        }

        return temp;
    }

    private int coapResourcesRequest(Node node) throws UnknownHostException, WSIAdapterException {
        int messageIDToReturn = UNDEFINED_COAP_MESSAGE_ID;
        String proxyAddress = getProxyAddress(node);

        if (proxyAddress != null) {
            // 15/04
            CoapClientChannel clientChannelResources = null;
            try {
                // *** Alternative approach
                if (!proxyAddrToClientChannelResourcesHM.isEmpty()
                        && proxyAddrToClientChannelResourcesHM.containsKey(proxyAddress)
                        && proxyAddrToClientChannelResourcesHM.get(proxyAddress) != null) {
                    //re use it.
                    clientChannelResources = proxyAddrToClientChannelResourcesHM.get(proxyAddress);

                } else {
                    clientChannelResources = channelManager.connect((CoapClient) this,
                            InetAddress.getByName(proxyAddress), PORT);
                    if (clientChannelResources != null) {
                        proxyAddrToClientChannelResourcesHM.put(proxyAddress, clientChannelResources);
                    } else {
                        logger.error("Impossible to setup a coap channel for resources!");
                        return UNDEFINED_COAP_MESSAGE_ID;
                    }
                }
                // *** end of alternative approach

                // == Fix that was still causing too many open files:
                //if(clientChannelResources!= null) {
                //    clientChannelResources.close();
                //}
                //clientChannelResources = channelManager.connect((CoapClient)this, InetAddress.getByName(proxyAddress), PORT);
                // == end of fix
                //         clientChannelResources = channelManager.connect(this, InetAddress.getByName("localhost"), PORT);
                CoapRequest coapRequest = clientChannelResources.createRequest(true, CoapRequestCode.GET);
                //coapRequest.setContentType(CoapMediaType.octet_stream);
                //coapRequest.setProxyUri("coap://[" + node.getId() + "]:5683/" + MoteResource.RESOURCE_DISCOVERY);
                System.out.println("Il nodo da contattare  " + node.getId());
                coapRequest.setUriHost(node.getId());
                coapRequest.setUriPort(5683);
                coapRequest.setUriPath(MoteResource.RESOURCE_DISCOVERY);
                clientChannelResources.sendMessage(coapRequest);
                messageIDToReturn = coapRequest.getMessageID();
                logger.info("Sent Request: {} for node {}", coapRequest.toString(), node.getId());
                //clientChannelResources.close();
            } catch (Exception ex) {
                if (clientChannelResources != null) {
                    //    clientChannelResources.close();
                }
                throw new WSIAdapterException("Unable to send coap resource req to " + node.getId());
            } finally {
                if (clientChannelResources != null) {
                    //    clientChannelResources.close();
                }
            }
        } else {
            logger.warn("No available proxy for Node " + node.getId() + " is found");
            throw new WSIAdapterException("No available proxy for Node " + node.getId() + " is found");
        }
        return messageIDToReturn;
    }

    public List<Resource> getResources(Node node) throws WSIAdapterException {
        /*      List<Resource> resourceList = new ArrayList<Resource>();
            
              String ipaddr = node.getId();
                  
              //discoverCoapEndpoint("coap://[" + ipaddr + "]:5683");
              Resource resource = null;
              try {
                 resource = MoteResource.getResource("st");
                 resourceList.add(resource);
                 resource = MoteResource.getResource("co2");
                 resourceList.add(resource);
              } catch (VitroGatewayException e) {
                 // TODO Auto-generated catch block
                 e.printStackTrace();
              }
                  
              return resourceList;
              }
              */
        signal = new CountDownLatch(1);
        List<Resource> resourceList = new ArrayList<Resource>();
        int requestMessageID = UNDEFINED_COAP_MESSAGE_ID;
        try {
            boolean requestWasRespondedWithinTimelimit = false;
            if (isDtnEnabled) {
                //requestMessageID = dtnResourcesRequest(node);
                requestWasRespondedWithinTimelimit = signal.await(Constants.DTN_REQUEST_TIMEOUT, TimeUnit.MINUTES);
            } else {
                requestMessageID = coapResourcesRequest(node);
                // TODO: the signal await function will return FALSE if the timeout has expired.
                // This allows to manage the timeout case, and possibly the re-sending of messages that the coap gateway will do (until receiving a response)
                // The plan is that if this request times out, the ID of the request is logged in a static/global table and we further ignore messages for this ID (we don't handle them anymore).
                requestWasRespondedWithinTimelimit = signal.await(Constants.SIMPLE_COAP_REQUEST_TIMEOUT_SECONDS,
                        TimeUnit.SECONDS);
            }

            if (!requestWasRespondedWithinTimelimit) { //if we had timeout
                if (isDtnEnabled) //for DTN mode, iwe add it to a separate list (different callback function and messages )
                {
                    // TODO: we need to make something similar for DTN too!
                    if (requestMessageID != UNDEFINED_COAP_MESSAGE_ID
                            && !timedOut_DTN_CoapMessageIDsList.contains(Integer.valueOf(requestMessageID))) {
                        timedOut_DTN_CoapMessageIDsList.add(Integer.valueOf(requestMessageID));
                    }

                } else {
                    //add the messageId to the list of IDs to ignore in the future (the check will be done in the callback function
                    if (requestMessageID != UNDEFINED_COAP_MESSAGE_ID
                            && !timedOutCoapMessageIDsList.contains(Integer.valueOf(requestMessageID))) {
                        timedOutCoapMessageIDsList.add(Integer.valueOf(requestMessageID));
                    }
                }
            } else {//if no time-out occurred
                if (this.resourceList.size() > 0) {

                    resourceList.addAll(this.resourceList);
                    this.resourceList.clear();

                } else {

                    String error = "";
                    if (!exceptionError.equals("")) {
                        error = exceptionError;
                        exceptionError = "";
                    } else {
                        error = "No available resources for Node " + node.getId();
                    }

                    throw new WSIAdapterException(error);
                }
            }

        } catch (InterruptedException e) {
            throw new WSIAdapterException(e.getMessage(), e);
        } catch (UnknownHostException e) {
            throw new WSIAdapterException(e.getMessage(), e);
        }
        return resourceList;

    }

    void doRequest(String method, String strUri) {
        URI uri;
        try {
            uri = new URI(strUri);
        } catch (URISyntaxException e) {
            e.printStackTrace();
            return;
        }
        doRequest(method, uri);
    }

    private static Request newRequest(String method) {
        if (method.equals("GET")) {
            return new GETRequest();
        } else if (method.equals("POST")) {
            return new POSTRequest();
        } else if (method.equals("PUT")) {
            return new PUTRequest();
        } else if (method.equals("DELETE")) {
            return new DELETERequest();
        } else if (method.equals("DISCOVER")) {
            return new GETRequest();
        } else if (method.equals("OBSERVE")) {
            return new GETRequest();
        } else {
            return null;
        }
    }

    void doRequest(String method, URI uri) {

        Request request = newRequest(method);
        URI reqUri = uri;

        //      if(useCoapProxy) {
        //         System.out.println("Setting proxy for request");
        //         request.setOption(new Option(uri.toString(), OptionNumberRegistry.PROXY_URI));
        //      }

        if (method.equals("OBSERVE")) {
            request.setOption(new Option(0, OptionNumberRegistry.OBSERVE));
        }

        // set request URI
        if (method.equals("DISCOVER")
                && (uri.getPath() == null || uri.getPath().isEmpty() || uri.getPath().equals("/"))) {
            // add discovery resource path to URI
            try {
                reqUri = new URI(uri.getScheme(), uri.getAuthority(), DISCOVERY_RESOURCE, uri.getQuery());

            } catch (URISyntaxException e) {
                System.err.println("Failed to parse URI: " + e.getMessage());
                System.exit(ERR_BAD_URI);
            }

        }

        if (useCoapProxy) {
            System.out.println("Setting proxy for request");
            request.setOption(new Option(reqUri.toString(), OptionNumberRegistry.PROXY_URI));
            //         request.setURI(reqUri);
            // override peer address with proxy address
            EndpointAddress a = new EndpointAddress(proxyUri);
            request.setPeerAddress(a);
        } else {
            System.out.println("No proxy for request");
            request.setURI(reqUri);
        }
        request.setPayload("");
        request.setToken(TokenManager.getInstance().acquireToken());
        System.out.println("Ici???s");

        ResponseHandler respHandler = new ResponseHandler() {

            public void handleResponse(Response response) {
                System.out.println("On arrive ici");
                doHandleResponse(response);
            }
        };
        request.registerResponseHandler(respHandler);
        System.out.println("response handler registered");
        // enable response queue in order to use blocking I/O
        //   request.enableResponseQueue(true);

        //
        request.prettyPrint();

        pendingRequests.add(request);
        System.out.println("request stored");
        // execute request
        try {
            request.execute();
            System.out.println("request executed");
        } catch (UnknownHostException e) {
            System.err.println("Unknown host: " + e.getMessage());
            System.exit(ERR_REQUEST_FAILED);
        } catch (IOException e) {
            System.err.println("Failed to execute request: " + e.getMessage());
            System.exit(ERR_REQUEST_FAILED);
        }
    }

    public void discoverCoapEndpoint(String addr) {
        // create request according to specified method
        String method = "DISCOVER";
        URI uri = null;
        try {
            uri = new URI(addr);
        } catch (URISyntaxException e) {
            System.err.println("Failed to parse URI: " + e.getMessage());
            return;
        }

        doRequest(method, uri);
    }

    private String getProxyAddress(Node node) {
        String nodeIP = node.getId();
        logger.debug("node getid returns " + nodeIP);

        return nodeIP;
    }

    private String formatResourceValue(String resourceValue, Resource resource) {

        String resultRet = "";
        StringBuilder resultBld = new StringBuilder();
        resultBld.append(resourceValue);
        resultRet = resultBld.toString();

        int resourceValueLength = resultRet.length();
        System.out.println("La stringa ricevuta  " + resultRet);

        String integerPart = resultRet.substring(0, resourceValueLength - 2);
        String decimalPart = resultRet.substring(resourceValueLength - 2, resourceValueLength);

        if (resource.getName().equals("temperature")
        //||
        //             resource.getName().equals(Resource.PHENOMENOM_LIGHT)
        ) {
            //result = resultRet;//integerPart + "." + decimalPart;
            logger.debug("Result is " + resultRet);
        } else if (resource.getName().equals("co2")
        //||
        //             resource.getName().equals(Resource.PHENOMENOM_LIGHT)
        ) {

            //result = resultRet;//integerPart + "." + decimalPart;
            logger.debug("Result co2 is " + resultRet);
        }

        return resultRet;

    }

    private int coapObservationRequest(Node node, Resource resource)
            throws UnknownHostException, VitroGatewayException {
        int messageIDToReturn = UNDEFINED_COAP_MESSAGE_ID;
        String proxyAddress = getProxyAddress(node);
        //proxyAddress = node.getId();
        if (proxyAddress != null) {
            String moteUriResource = "";
            if (MoteResource.containsValue(resource)) {
                //moteUriResource += "temperature";//MoteResource.getMoteUriResource(resource);
                String theResourceName = MoteResource.getMoteUriResource(resource);
                if (theResourceName == null) {
                    logger.error("unsupported resource");
                    return UNDEFINED_COAP_MESSAGE_ID;
                }
                // FOR TCS adapter, we prefer the TEMPERATURE_TCS
                // FOR WLAB and HAI we prefer the TEMPERATURE_ALT
                // we do this check because the getMoteUriResource is making a reverse lookup in the hashmap (where two keys point to the same resource)
                if (theResourceName.compareToIgnoreCase(MoteResource.TEMPERATURE_ALT) == 0) {
                    theResourceName = MoteResource.TEMPERATURE_TCS;
                }
                moteUriResource += theResourceName;
                int PORT = Constants.COAP_DEFAULT_PORT;
                // 15/04
                CoapClientChannel clientChannelObservations = null;
                try {
                    // *** Alternative approach
                    if (!proxyAddrToClientChannelObservationsHM.isEmpty()
                            && proxyAddrToClientChannelObservationsHM.containsKey(proxyAddress)
                            && proxyAddrToClientChannelObservationsHM.get(proxyAddress) != null) {
                        //re use it.
                        clientChannelObservations = proxyAddrToClientChannelObservationsHM.get(proxyAddress);

                    } else {
                        clientChannelObservations = channelManager.connect((CoapClient) this,
                                InetAddress.getByName(proxyAddress), PORT);
                        if (clientChannelObservations != null) {
                            proxyAddrToClientChannelObservationsHM.put(proxyAddress, clientChannelObservations);
                        } else {
                            logger.error("Impossible to setup a coap channel for observations!");
                            return UNDEFINED_COAP_MESSAGE_ID;
                        }
                    }
                    // *** end of alternative approach

                    // == Fix that was still causing too many open files:
                    //if(clientChannelObservations!= null) {
                    //    clientChannelObservations.close();
                    //}
                    //clientChannelObservations = channelManager.connect((CoapClient) this, InetAddress.getByName(proxyAddress), PORT);
                    // == end of fix

                    //            clientChannelObservations = channelManager.connect(this, InetAddress.getByName("localhost"), PORT);
                    CoapRequest coapRequest = clientChannelObservations.createRequest(true, CoapRequestCode.GET);
                    //coapRequest.setProxyUri("coap://[" + node.getId() + "]:5683/" + moteUriResource);
                    coapRequest.setUriHost(node.getId());
                    System.out.println("l'host  " + node.getId());
                    coapRequest.setUriPort(PORT);
                    System.out.println("la porta  " + PORT);
                    coapRequest.setUriPath(moteUriResource);
                    System.out.println("l'URI  " + coapRequest.getUriPath());
                    clientChannelObservations.sendMessage(coapRequest);
                    messageIDToReturn = coapRequest.getMessageID();
                    logger.info("Sent Request: " + coapRequest.toString());
                    //clientChannelObservations.close();
                } catch (Exception ex) {
                    logger.error("Could not setup a coap channel or send the coapObservationRequest message!", ex);
                    if (clientChannelObservations != null) {
                        //clientChannelObservations.close();
                    }
                    throw new WSIAdapterException("Unable to send coap observe req to " + node.getId()
                            + " and Resource " + resource.getName());
                } finally {
                    if (clientChannelObservations != null) {
                        //clientChannelObservations.close();
                    }
                }
            } else {
                logger.warn("No resource mapping for Node " + node.getId() + " and Resource " + resource.getName());
                throw new WSIAdapterException(
                        "No resource mapping for Node " + node.getId() + " and Resource " + resource.getName());
            }
            //
        } else {
            logger.warn("No available proxy for Node " + node.getId() + " is found");
            throw new WSIAdapterException("No available proxy for Node " + node.getId() + " is found");
        }
        return messageIDToReturn;
    }

    public Observation getNodeObservation(Node node, Resource resource) throws WSIAdapterException {
        signal = new CountDownLatch(1);
        Observation observation = new Observation();

        try {
            logger.debug("arrivo qui");

            int requestMessageID = UNDEFINED_COAP_MESSAGE_ID;
            boolean requestWasRespondedWithinTimelimit = false;
            if (isDtnEnabled) {
                // requestMessageID = dtnObservationRequest(node, resource);
                requestWasRespondedWithinTimelimit = signal.await(Constants.DTN_REQUEST_TIMEOUT, TimeUnit.MINUTES);
            } else {
                requestMessageID = coapObservationRequest(node, resource);
                // TODO: the signal await function will return FALSE if the timeout has expired.
                // This allows to manage the timeout case, and possibly the re-sending of messages that the coap gateway will do (until receiving a response)
                // The plan is that if this request times out, the ID of the request is logged in a static/global table and we further ignore messages for this ID (we don't handle them anymore).
                requestWasRespondedWithinTimelimit = signal.await(Constants.SIMPLE_COAP_REQUEST_TIMEOUT_SECONDS,
                        TimeUnit.SECONDS);
            }
            if (!requestWasRespondedWithinTimelimit) { //if we had timeout
                if (isDtnEnabled) //for DTN mode, we add it to a separate list (different callback function and messages )
                {
                    if (requestMessageID != UNDEFINED_COAP_MESSAGE_ID
                            && !timedOut_DTN_CoapMessageIDsList.contains(Integer.valueOf(requestMessageID))) {
                        timedOut_DTN_CoapMessageIDsList.add(Integer.valueOf(requestMessageID));
                    }
                } else {
                    //add the messageId to the list of IDs to ignore in the future (the check will be done in the callback function
                    if (requestMessageID != UNDEFINED_COAP_MESSAGE_ID
                            && !timedOutCoapMessageIDsList.contains(Integer.valueOf(requestMessageID))) {
                        timedOutCoapMessageIDsList.add(Integer.valueOf(requestMessageID));
                    }
                }
            } else {
                if (resourceValue != null) {

                    observation.setNode(node);
                    observation.setResource(resource);
                    observation.setValue(formatResourceValue(resourceValue, resource));
                    observation.setTimestamp(System.currentTimeMillis());
                    resourceValue = null;

                } else {

                    String error;
                    if (!exceptionError.equals("")) {
                        error = exceptionError;
                        exceptionError = "";
                    } else {
                        error = "No available resources for Node " + node.getId() + " and Resource "
                                + resource.getName();
                    }

                    throw new WSIAdapterException(error);
                }
            }

        } catch (UnknownHostException e) {
            throw new WSIAdapterException(e.getMessage(), e);
        } catch (InterruptedException e) {
            throw new WSIAdapterException(e.getMessage(), e);
        } catch (VitroGatewayException e) {
            throw new WSIAdapterException(e.getMessage(), e);
        }

        return observation;
    }

    public void onConnectionFailed(CoapClientChannel channel, boolean notReachable, boolean resetByServer) {
        if (notReachable) {
            logger.warn("Connection failed: server is not reachable");
            exceptionError = "Connection failed: server is not reachable";
        } else {
            logger.warn("Connection failed");
            exceptionError = "Connection failed";
        }
        // signal.countDown(); //commented out because the message will timeout.
    }

    public void onResponse(CoapClientChannel channel, CoapResponse response) {
        boolean countDownTheSignal = false;
        try {
            if (!timedOutCoapMessageIDsList.contains(Integer.valueOf(response.getMessageID()))
                    && response.getMessageID() != UNDEFINED_COAP_MESSAGE_ID) {
                manageResponse(response);
                countDownTheSignal = true;
            }
            // TODO: if it is contained, do we remove it to clean up the list? (also the messageID for the coapMessages could be rotating, so we would need clean-up !!)
            //                          or do we expect further responses for a timeout message (due to the re-transmissions?)
        } catch (VitroGatewayException e) {
            logger.error(e.getMessage());
        }
        if (countDownTheSignal) {
            signal.countDown();
        }
    }

    public void onSeparateResponse(CoapClientChannel channel, CoapResponse message) {
        logger.info("Received Separate Response");
        //TODO: no implementation in TinyOS
        // signal.countDown(); //commented out because the message will timeout.
    }

    private void manageTextPlain(byte[] payloadBytes) throws VitroGatewayException {
        String payloadString = new String(payloadBytes);
        System.out.println("The resource is " + payloadString);
        resourceValue = payloadString;
    }

    synchronized void doHandleResponse(Response response) {
        System.out.println("Receiving COAP response...");
        boolean success = true;

        if (response != null) {
            response.prettyPrint();
            System.out.println(response.getMID());
            System.out.println("Time elapsed (ms): " + response.getRTT());

            // check of response contains resources
            String data = "";
            if (response.getContentType() == MediaTypeRegistry.APPLICATION_LINK_FORMAT) {

                data = response.getPayloadString();
                System.out.println("\npayload string: " + data);

                // create resource tree from link format
                ch.ethz.inf.vs.californium.endpoint.Resource root = ch.ethz.inf.vs.californium.endpoint.RemoteResource
                        .newRoot(data);
                if (root != null) {

                    // output discovered resources
                    System.out.println("\nDiscovered resources:");
                    root.prettyPrint();
                    for (ch.ethz.inf.vs.californium.endpoint.Resource resource : root.getSubResources()) {

                        vitro.vgw.model.Resource r = null;
                        try {
                            String proposition = resource.getPath().replace("/", "");
                            System.out.println("=> Proposition : " + proposition);
                            if (proposition.equals(Resource.PHENOMENOM_TEMPERATURE)) {
                                r = vitro.vgw.model.Resource.getResource(proposition);
                                resourceList.add(r);
                            }

                        } catch (VitroGatewayException e) {
                            System.out.println("Tu fais un amalgame entre la coqueterie et la classe");
                            e.printStackTrace();
                        }

                    }
                    System.out.println("Liste finale =>" + resourceList.toString());

                    //               for (ch.ethz.inf.vs.californium.endpoint.Resource resource:root.getSubResources()) {
                    //                  // automatically subscribe to observable resources
                    //                  if(resource.isObservable()) {
                    //                     System.out.println("\nSubscribing to observable resource:"+response.getPeerAddress()+ resource.getPath());
                    //                     doRequest("OBSERVE", "coap://" + response.getPeerAddress()+ resource.getPath());
                    //                  }
                    //
                    //                  String id="randomstuff"+response.getPeerAddress()+resource.getPath();
                    //
                    //
                    //               }

                } else {
                    System.err.println("Failed to parse link format");
                    System.exit(ERR_BAD_LINK_FORMAT);
                }
            } else {
                System.out.println("\nReceived response from " + response.getPeerAddress());
                System.out.println("\n   content type " + MediaTypeRegistry.toString(response.getContentType()));
            }

            if (!response.hasOption(OptionNumberRegistry.OBSERVE)) {
                Request _req = response.getRequest();
                boolean removed = pendingRequests.remove(_req);
                if (removed) {
                    System.out.println("\nPending request removed");
                }
            }

            // TODO FIXME we need to keep a registry of the id in the link-format and the IP address of 
            // the node in here somewhere. Because, when we receive a response and we don't keep the id 
            // discovered for the node, we have no way to get it.
            String id = "randomstuff" + response.getPeerAddress() + response.getUriPath();
            //sosClient.doAddObservation(id, MediaTypeRegistry.toString(response.getContentType()), response.getPayload());

        } else {
            // TODO FIXME: need to find a way to receive timeout and clean the pending requests
            System.out.println("Handling request timeout");
            //         boolean removed = pendingRequests.remove(response.getRequest());
            //         if(removed) {
            //            System.out.println("\nPending request removed");
            //         } else {
            //            System.out.println("\nNo pending request found");
            //         }
        }
    }

    private void manageOctetStream(byte[] payloadBytes) {
        if (payloadBytes.length == 2) {
            short payloadShort = Functions.byteArraytoShort(payloadBytes);
            resourceValue = String.valueOf(payloadShort);
        } else {
            // CHANGED THIS TO REFLECT THE EXACT BYTES ARRAY AND BE ABLE TO RECONSTRUCT IT
            //resourceValue = new String(payloadBytes);
            resourceValue = Base64.encodeBase64String(payloadBytes);
        }
    }

    private void manageResponse(CoapResponse response) throws VitroGatewayException {
        logger.info("Received response code: " + response.getResponseCode());
        logger.info("CoAP Message ID: " + response.getMessageID());
        logger.info("Content Type: " + response.getContentType());
        logger.info("CoAP Server address: " + response.getChannel().getRemoteAddress());

        if (response.getPayload() == null) {
            return;
        }

        byte[] payloadBytes = response.getPayload();
        if (payloadBytes.length > 0) {
            switch (response.getContentType().getValue()) {
            case 0: {
                manageTextPlain(payloadBytes); //textplain
                break;
            }
            case 40: {
                manageLinkFormat(payloadBytes); //linkformat --> /.well-known/core
                break;
            }
            case 41: //TODO: xml (required???)
                break;
            case 42: {
                manageOctetStream(payloadBytes); //octetstream --> resource outcomes
                break;
            }
            case 47: //TODO: exi (required???)
                break;
            case 50: //TODO: json (required???)
            default:
                logger.warn("Unknown Content Type");
            }
        } else {
            logger.warn("The payload is empty.");
        }
    }

    private void manageLinkFormat(byte[] payloadBytes) throws VitroGatewayException {

        String payloadString = new String(payloadBytes);

        /** 
         * Manage /.well-known/core resource 
         */

        // Pattern example: </st>;ct=42,</sh>;ct=42
        Pattern p = Pattern.compile("(</\\w+>);?(ct=\\d+)?", Pattern.CASE_INSENSITIVE);
        Matcher m = p.matcher(payloadString);

        while (m.find()) {
            logger.debug("Regex Result: " + m.group());

            /** Resource Name */
            if (m.group(1) != null) {
                String resourceName = m.group(1).replaceAll("<|/|>", "");
                if (MoteResource.containsKey(resourceName)) {
                    logger.debug("Resource name: " + resourceName);
                    Resource resource = MoteResource.getResource(resourceName);
                    resourceList.add(resource);
                }
            }

            /** Resource Content Type 
            if(m.group(0) != null) {
               String resourceName = m.group(0).replaceAll("<|/|>", "");
               if(MoteResource.containsKey(resourceName)) {
                  logger.debug("Resource name: " + resourceName);
                  Resource resource = MoteResource.getResource(resourceName);
                  resourceList.add(resource);
               }
            }*/
        }
    }

    public void onSeparateResponseAck(CoapClientChannel channel, CoapEmptyMessage message) {
        logger.info("Received Ack of Separate Response");
        //TODO: no implementation in TinyOS
        // signal.countDown(); //commented out because the message will timeout.
    }

    synchronized List<Resource> doHandleResponse1(Response response) {
        System.out.println("Receiving COAP response...");
        boolean success = true;

        if (response != null) {
            response.prettyPrint();
            System.out.println(response.getMID());
            System.out.println("Time elapsed (ms): " + response.getRTT());

            // check of response contains resources
            String data = "";
            if (response.getContentType() == MediaTypeRegistry.APPLICATION_LINK_FORMAT) {

                data = response.getPayloadString();
                System.out.println("\npayload string: " + data);

                // create resource tree from link format
                ch.ethz.inf.vs.californium.endpoint.Resource root = ch.ethz.inf.vs.californium.endpoint.RemoteResource
                        .newRoot(data);
                if (root != null) {

                    // output discovered resources
                    System.out.println("\nDiscovered resources:");
                    root.prettyPrint();
                    for (ch.ethz.inf.vs.californium.endpoint.Resource resource : root.getSubResources()) {

                        vitro.vgw.model.Resource r = null;
                        try {
                            String proposition = resource.getPath().replace("/", "");
                            System.out.println("=> Proposition : " + proposition);
                            if (proposition.equals(Resource.PHENOMENOM_TEMPERATURE)) {
                                r = vitro.vgw.model.Resource.getResource(proposition);
                                resourceList.add(r);
                            }

                        } catch (VitroGatewayException e) {
                            System.out.println("Tu fais un amalgame entre la coqueterie et la classe");
                            e.printStackTrace();
                        }

                    }
                    System.out.println("Liste finale =>" + resourceList.toString());

                    //               for (ch.ethz.inf.vs.californium.endpoint.Resource resource:root.getSubResources()) {
                    //                  // automatically subscribe to observable resources
                    //                  if(resource.isObservable()) {
                    //                     System.out.println("\nSubscribing to observable resource:"+response.getPeerAddress()+ resource.getPath());
                    //                     doRequest("OBSERVE", "coap://" + response.getPeerAddress()+ resource.getPath());
                    //                  }
                    //
                    //                  String id="randomstuff"+response.getPeerAddress()+resource.getPath();
                    //
                    //
                    //               }

                } else {
                    System.err.println("Failed to parse link format");
                    System.exit(ERR_BAD_LINK_FORMAT);
                }
            } else {
                System.out.println("\nReceived response from " + response.getPeerAddress());
                System.out.println("\n   content type " + MediaTypeRegistry.toString(response.getContentType()));
            }

            if (!response.hasOption(OptionNumberRegistry.OBSERVE)) {
                Request _req = response.getRequest();
                boolean removed = pendingRequests.remove(_req);
                if (removed) {
                    System.out.println("\nPending request removed");
                }
            }

            // TODO FIXME we need to keep a registry of the id in the link-format and the IP address of 
            // the node in here somewhere. Because, when we receive a response and we don't keep the id 
            // discovered for the node, we have no way to get it.
            String id = "randomstuff" + response.getPeerAddress() + response.getUriPath();
            //sosClient.doAddObservation(id, MediaTypeRegistry.toString(response.getContentType()), response.getPayload());

        } else {
            // TODO FIXME: need to find a way to receive timeout and clean the pending requests
            System.out.println("Handling request timeout");
            //         boolean removed = pendingRequests.remove(response.getRequest());
            //         if(removed) {
            //            System.out.println("\nPending request removed");
            //         } else {
            //            System.out.println("\nNo pending request found");
            //         }
        }
        return resourceList;
    }

    public boolean getDtnPolicy() {
        return isDtnEnabled;
    }

    /**
     * is supposed to start the DTN (switch on the DTN mode)
     */
    public void setDtnPolicy(boolean value) {
        isDtnEnabled = value;
    }

    // ------------------ trust coap messaging
    public boolean isTrustCoapMessagingActive() {
        return trustCoapMessagingActivated;
    }

    /**
     * is supposed to start the Trust Coap Messaging (switch on the Trust Coap Messaging mode)
     */
    public void setTrustCoapMessagingActive(boolean value) {
        trustCoapMessagingActivated = value;
    }

    /**
     * Used to get the coap response message for the trust routing resource from a node.  (the Resource parameter will always be Resource.RES_TRUST_ROUTING
     * @param node the  node queried
     * @param resource the resource queried (always Resource.RES_TRUST_ROUTING)
     * @return InfoOnTrustRouting object with the response
     */
    public InfoOnTrustRouting getNodeTrustRoutingInfo(Node node, Resource resource) throws WSIAdapterException {
        // TODO: an implementation is needed if this action is supported
        return null;
    }

}