org.openiot.gsn.http.rest.RestStreamHanlder.java Source code

Java tutorial

Introduction

Here is the source code for org.openiot.gsn.http.rest.RestStreamHanlder.java

Source

/**
*    Copyright (c) 2011-2014, OpenIoT
*   
*    This file is part of OpenIoT.
*
*    OpenIoT is free software: you can redistribute it and/or modify
*    it under the terms of the GNU Lesser General Public License as published by
*    the Free Software Foundation, version 3 of the License.
*
*    OpenIoT is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU Lesser General Public License for more details.
*
*    You should have received a copy of the GNU Lesser General Public License
*    along with OpenIoT.  If not, see <http://www.gnu.org/licenses/>.
*
*     Contact: OpenIoT mailto: info@openiot.eu
 * @author Ali Salehi
 * @author Mehdi Riahi
 * @author Timotee Maret
 * @author Julien Eberle
*/

package org.openiot.gsn.http.rest;

import org.openiot.gsn.DataDistributer;
import org.openiot.gsn.Main;
import org.openiot.gsn.Mappings;
import org.openiot.gsn.beans.VSensorConfig;
import org.openiot.gsn.http.ac.DataSource;
import org.openiot.gsn.http.ac.GeneralServicesAPI;
import org.openiot.gsn.http.ac.User;
import org.openiot.gsn.storage.SQLUtils;
import org.openiot.gsn.storage.SQLValidator;
import org.openiot.gsn.utils.Helpers;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.StringTokenizer;
import java.util.concurrent.LinkedBlockingQueue;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.DatatypeConverter;

import org.apache.http.HttpStatus;
import org.apache.log4j.Logger;
import org.eclipse.jetty.continuation.Continuation;
import org.eclipse.jetty.continuation.ContinuationSupport;

public class RestStreamHanlder extends HttpServlet {

    public static final int SUCCESS_200 = 200;

    private static final int _300 = 300;

    private static final String STREAMING = "/streaming/";

    private static transient Logger logger = Logger.getLogger(RestStreamHanlder.class);

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException {

        Object is2ndPass = request.getAttribute("2ndPass");
        Continuation continuation = ContinuationSupport.getContinuation(request);

        if (continuation.isExpired()) {
            logger.debug("Continuation has expired.");
            return;
        }

        String[] cred = null;
        if (Main.getContainerConfig().isAcEnabled()) {
            cred = parseAuthorizationHeader(request);
            if (cred == null) {
                try {
                    response.setHeader("WWW-Authenticate", "Basic realm=\"GSN Access Control\"");// set the supported challenge
                    response.sendError(HttpStatus.SC_UNAUTHORIZED, "Unauthorized access.");
                } catch (IOException e) {
                    logger.debug(e.getMessage(), e);
                }
                return;
            }
        }

        if (is2ndPass == null) {
            continuation.setAttribute("2ndPass", Boolean.TRUE);
            continuation.setAttribute("status", new LinkedBlockingQueue<Boolean>(1));
            continuation.setTimeout(-1); // Disable the timeout on the continuation.
            continuation.suspend();
            final DefaultDistributionRequest streamingReq;
            try {
                URLParser parser = new URLParser(request);
                //
                if (Main.getContainerConfig().isAcEnabled()) {
                    String vsName = parser.getVSensorConfig().getName();
                    if (DataSource.isVSManaged(vsName)) {
                        User user = GeneralServicesAPI.getInstance().doLogin(cred[0], cred[1]);
                        if ((user == null || (!user.isAdmin() && !user.hasReadAccessRight(vsName)))) {
                            response.setHeader("WWW-Authenticate", "Basic realm=\"GSN Access Control\"");// set the supported challenge
                            response.sendError(HttpStatus.SC_UNAUTHORIZED, "Unauthorized access.");
                            return;
                        }
                    }
                }
                //
                RestDelivery deliverySystem = new RestDelivery(continuation);
                streamingReq = DefaultDistributionRequest.create(deliverySystem, parser.getVSensorConfig(),
                        parser.getQuery(), parser.getStartTime());
                DataDistributer.getInstance(deliverySystem.getClass()).addListener(streamingReq);
            } catch (Exception e) {
                logger.warn(e.getMessage());
                continuation.complete();
            }
        } else {
            boolean status = false;
            try {
                status = !continuation.getServletResponse().getWriter().checkError();
            } catch (Exception e) {
                logger.debug(e.getMessage(), e);
            }
            continuation.suspend();
            try {
                ((LinkedBlockingQueue<Boolean>) continuation.getAttribute("status")).put(status);
            } catch (InterruptedException e) {
                logger.debug(e.getMessage(), e);
            }
        }
    }

    /**
     * This happens at the server
     */
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException {
        try {
            URLParser parser = new URLParser(request);
            String vsName = parser.getVSensorConfig().getName();

            //
            if (Main.getContainerConfig().isAcEnabled()) {
                String[] cred = parseAuthorizationHeader(request);
                if (cred == null) {
                    try {
                        response.setHeader("WWW-Authenticate", "Basic realm=\"GSN Access Control\"");// set the supported challenge
                        response.sendError(HttpStatus.SC_UNAUTHORIZED, "Unauthorized access.");
                    } catch (IOException e) {
                        logger.debug(e.getMessage(), e);
                    }
                    return;
                }
                if (DataSource.isVSManaged(vsName)) {
                    User user = GeneralServicesAPI.getInstance().doLogin(cred[0], cred[1]);
                    if ((user == null || (!user.isAdmin() && !user.hasReadAccessRight(vsName)))) {
                        response.setHeader("WWW-Authenticate", "Basic realm=\"GSN Access Control\"");// set the supported challenge
                        response.sendError(HttpStatus.SC_UNAUTHORIZED, "Unauthorized access.");
                        return;
                    }
                }
            }
            //
            Double notificationId = Double.parseDouble(request.getParameter(PushDelivery.NOTIFICATION_ID_KEY));
            String localContactPoint = request.getParameter(PushDelivery.LOCAL_CONTACT_POINT);
            if (localContactPoint == null) {
                logger.warn("Push streaming request received without " + PushDelivery.LOCAL_CONTACT_POINT
                        + " parameter !");
                return;
            }
            //checking to see if there is an already registered notification id, in that case, we ignore (re)registeration.
            DeliverySystem delivery;
            if (parser.pushType.equals("wp"))
                delivery = new WPPushDelivery(localContactPoint, notificationId, response.getWriter(),
                        parser.nClass, parser.nMessage);
            else
                delivery = new PushDelivery(localContactPoint, notificationId, response.getWriter());

            boolean isExist = DataDistributer.getInstance(delivery.getClass()).contains(delivery);
            if (isExist) {
                logger.debug("Keep alive request received for the notification-id:" + notificationId);
                response.setStatus(SUCCESS_200);
                delivery.close();
                return;
            }

            DefaultDistributionRequest distributionReq = DefaultDistributionRequest.create(delivery,
                    parser.getVSensorConfig(), parser.getQuery(), parser.getStartTime());
            logger.debug("Rest request received: " + distributionReq.toString());
            DataDistributer.getInstance(delivery.getClass()).addListener(distributionReq);
            logger.debug("Streaming request received and registered:" + distributionReq.toString());
        } catch (Exception e) {
            logger.warn(e.getMessage(), e);
            return;
        }
    }

    /**
     * This happens at the client
     */
    public void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException {
        double notificationId = Double.parseDouble(request.getParameter(PushDelivery.NOTIFICATION_ID_KEY));
        PushRemoteWrapper notification = NotificationRegistry.getInstance().getNotification(notificationId);
        try {
            if (notification != null) {
                boolean status = notification.manualDataInsertion(request.getParameter(PushDelivery.DATA));
                if (status)
                    response.setStatus(SUCCESS_200);
                else
                    response.setStatus(_300);
            } else {
                logger.warn("Received a Http put request for an INVALID notificationId: " + notificationId);
                response.sendError(_300);
            }
        } catch (IOException e) {
            logger.warn("Failed in writing the status code into the connection.\n" + e.getMessage(), e);
        }
    }

    /**
     *
     * @param request
     * @return [username,password] or null if unable to retrieve these pieces of information.
     */
    private String[] parseAuthorizationHeader(HttpServletRequest request) {
        // Get username/password from the Authorization header
        String authHeader = request.getHeader("Authorization"); // form: BASIC d2VibWFzdGVyOnRyeTJndWVTUw
        if (authHeader != null) {
            String[] ahs = authHeader.split(" ");
            if (ahs.length == 2) {
                String b64UsernamPassword = ahs[1]; // we get: d2VibWFzdGVyOnRyeTJndWVTUw
                String userPass = new String(DatatypeConverter.parseBase64Binary(b64UsernamPassword)); // form: username:passsword
                String[] ups;
                if ((ups = userPass.split(":")).length == 2) {
                    return new String[] { ups[0], // username
                            ups[1] // password
                    };
                }
            }
        }
        return null;
    }

    class URLParser {
        private String query, tableName, pushType, nMessage;
        private int nClass;
        private long startTime;
        private VSensorConfig config;

        public URLParser(HttpServletRequest request) throws UnsupportedEncodingException, Exception {
            String requestURI = request.getRequestURI()
                    .substring(request.getRequestURI().toLowerCase().indexOf(STREAMING) + STREAMING.length());
            StringTokenizer tokens = new StringTokenizer(requestURI, "/");
            startTime = System.currentTimeMillis();
            String first = tokens.nextToken();
            if (first.startsWith("wp")) { //registering from a Windows Phone
                pushType = "wp";
                nClass = Integer.parseInt(first.substring(2, 3));
                nMessage = URLDecoder.decode(first.substring(3), "UTF-8");
                query = tokens.nextToken();
            } else {
                query = first;
            }
            query = URLDecoder.decode(query, "UTF-8");
            if (tokens.hasMoreTokens())
                startTime = Helpers.convertTimeFromIsoToLong(URLDecoder.decode(tokens.nextToken(), "UTF-8"));
            tableName = SQLValidator.getInstance().validateQuery(query);
            if (tableName == null)
                throw new RuntimeException("Bad Table name in the query:" + query);
            /** IMPORTANT: We change the table names to lower-case as some databases (e.g., MySQL on linux) are case sensitive and in 
             * general we use lower case for table names in GSN. **/
            tableName = tableName.trim();
            query = SQLUtils.newRewrite(query, tableName, tableName.toLowerCase()).toString();
            tableName = tableName.toLowerCase();
            config = Mappings.getConfig(tableName);
        }

        public VSensorConfig getVSensorConfig() {
            return config;
        }

        public String getQuery() {
            return query;
        }

        public long getStartTime() {
            return startTime;
        }

    }

}