com.ericsson.deviceaccess.tutorial.rest.GenericDeviceServlet.java Source code

Java tutorial

Introduction

Here is the source code for com.ericsson.deviceaccess.tutorial.rest.GenericDeviceServlet.java

Source

/*
 * Copyright Ericsson AB 2011-2014. All Rights Reserved.
 *
 * The contents of this file are subject to the Lesser GNU Public License,
 *  (the "License"), either version 2.1 of the License, or
 * (at your option) any later version.; you may not use this file except in
 * compliance with the License. You should have received a copy of the
 * License along with this software. If not, it can be
 * retrieved online at https://www.gnu.org/licenses/lgpl.html. Moreover
 * it could also be requested from Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 * BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
 * WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
 * EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
 * OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND,
    
 * EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
 * LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE,
 * YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
 *
 * IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
 * WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
 * REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR
 * DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL
 * DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY
 * (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED
 * INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE
 * OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH
 * HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 *
 */
package com.ericsson.deviceaccess.tutorial.rest;

import com.ericsson.common.util.LegacyUtil;
import com.ericsson.common.util.serialization.Format;
import com.ericsson.common.util.serialization.SerializationException;
import com.ericsson.common.util.serialization.SerializationUtil;
import com.ericsson.common.util.serialization.View;
import com.ericsson.deviceaccess.api.Constants;
import com.ericsson.deviceaccess.api.GenericDevice;
import com.ericsson.deviceaccess.api.genericdevice.GDAction;
import com.ericsson.deviceaccess.api.genericdevice.GDActionResult;
import com.ericsson.deviceaccess.api.genericdevice.GDEventListener;
import com.ericsson.deviceaccess.api.genericdevice.GDException;
import com.ericsson.deviceaccess.api.genericdevice.GDProperties;
import com.ericsson.deviceaccess.api.genericdevice.GDService;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceEvent;
import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;

public class GenericDeviceServlet extends NanoHTTPD implements BundleActivator, GDEventListener, ServiceListener {

    private static Log logger = LogFactory.getLog(GenericDeviceServlet.class);

    private BundleContext context;
    private boolean shutdown;

    //   private LogTracker logger = null;
    private ServiceRegistration sr;
    protected HashMap sockets;

    public GenericDeviceServlet(int port) {
        super(port);
    }

    public GenericDeviceServlet() {
        super(8090);
    }

    @Override
    public Response serve(String uri, String method, Properties header, Properties parms, Properties files) {
        logger.debug("REST: Get request for " + uri);
        String resource;
        try {
            if (uri.startsWith("/devices")) {
                if (uri.length() <= 9) {
                    resource = getAllDevices();
                    return new NanoHTTPD.Response(HTTP_OK, "application/json", resource);
                } else {
                    uri = uri.substring(8);
                    String deviceId;
                    String requestedNode = "";
                    int pathIndex = uri.indexOf('/', 1);
                    if (pathIndex < 0) {
                        deviceId = uri.substring(1);
                        GenericDevice dev = getDevice(deviceId);
                        if (dev == null) {
                            return new NanoHTTPD.Response(HTTP_NOTFOUND, "text/plain",
                                    "Device " + deviceId + " not found");
                        }
                        resource = dev.getSerializedNode(requestedNode, Format.JSON);
                        return new NanoHTTPD.Response(HTTP_OK, "application/json", resource);
                    } else {
                        deviceId = uri.substring(1, pathIndex);
                        requestedNode = uri.substring(pathIndex + 1);
                        return handleAction(deviceId, requestedNode, parms);
                    }
                }
            } else {
                return new NanoHTTPD.Response(HTTP_NOTFOUND, "text/plain", "No servlet registered for " + uri);
            }
        } catch (GDException | IOException e) {
            StringWriter sw = new StringWriter();
            e.printStackTrace(new PrintWriter(sw));
            return new NanoHTTPD.Response(HTTP_INTERNALERROR, "text/plain",
                    "Failed to get resource " + uri + " due to " + sw.toString());
        } finally {
            logger.debug("REST: Returned");
        }
    }

    /**
     * @param req
     * @param dev
     * @throws IOException
     */
    private NanoHTTPD.Response handleAction(String deviceId, String request, Properties parms) throws IOException {
        StringTokenizer st = new StringTokenizer(request, "/?&");

        try {
            String service = st.nextToken();
            String action = st.nextToken();
            GenericDevice dev = getDevice(deviceId);
            if (dev != null) {
                GDService svc = dev.getService(service);
                if (svc != null) {
                    GDAction act = svc.getAction(action);
                    if (act != null) {
                        GDProperties properties = act.createArguments();
                        properties.setStringValue("device", deviceId);
                        properties.setStringValue("service", service);
                        properties.setStringValue("action", action);
                        properties.setStringValue("authorized", "true");
                        setArguments(properties, parms);
                        GDActionResult result = act.execute(properties);
                        return new NanoHTTPD.Response(HTTP_OK, "application/json",
                                result.getValue().serialize(Format.JSON));
                    } else {
                        return new NanoHTTPD.Response(HTTP_NOTFOUND, "text/plain",
                                "Could not find action: " + action);
                    }
                } else {
                    return new NanoHTTPD.Response(HTTP_NOTFOUND, "text/plain",
                            "Could not find service: " + service);
                }
            } else {
                return new NanoHTTPD.Response(HTTP_NOTFOUND, "text/plain", "Could not find device: " + deviceId);
            }
        } catch (GDException e) {
            return new NanoHTTPD.Response(HTTP_INTERNALERROR, "text/plain",
                    "Failed to perform action " + request + " due to " + e);
        }
    }

    /**
     * @param ac
     */
    private void setArguments(GDProperties ac, Properties parms) {
        Enumeration parameterNames = parms.keys();
        while (parameterNames.hasMoreElements()) {
            String paramName = (String) parameterNames.nextElement();
            String paramValue = parms.getProperty(paramName);
            ac.setStringValue(paramName, paramValue);
        }
    }

    private GenericDevice getDevice(String deviceId) {
        try {
            String idFilter = "(" + Constants.PARAM_DEVICE_ID + "=" + deviceId + ")";
            ServiceReference[] refs = context.getAllServiceReferences(GenericDevice.class.getName(), idFilter);
            if (refs != null) {
                logger.debug(refs.length + " device found");
                for (ServiceReference ref : refs) {
                    GenericDevice dev = (GenericDevice) context.getService(ref);
                    if (deviceId.equals(dev.getId())) {
                        return dev;
                    }
                }
            }
        } catch (InvalidSyntaxException e) {
            logger.error(e);
        }
        logger.error("No such device found");
        return null;
    }

    private String getAllDevices() {
        try {
            Map<String, GenericDevice> devices = context.getServiceReferences(GenericDevice.class, null).stream()
                    .map(ref -> context.getService(ref))
                    .collect(Collectors.toMap(dev -> dev.getId(), Function.identity()));
            return SerializationUtil.execute(Format.JSON,
                    mapper -> mapper.writerWithView(View.ID.Ignore.class).writeValueAsString(devices));
        } catch (InvalidSyntaxException | SerializationException e) {
            logger.error(e);
        }
        return "{}";
    }

    @Override
    public void start(BundleContext bc) throws Exception {
        context = bc;
        Map<String, Object> props = new HashMap<>();
        props.put(GDEventListener.GENERICDEVICE_FILTER, "(device.id=*)");
        sr = bc.registerService(GDEventListener.class, this, LegacyUtil.toDictionary(props));

        try {
            bc.addServiceListener(this,
                    "(" + org.osgi.framework.Constants.OBJECTCLASS + "=" + GenericDevice.class.getName() + ")");
        } catch (InvalidSyntaxException e) {
            logger.error(e);
        }
    }

    @Override
    public void stop(BundleContext bc) throws Exception {
        shutdown = true;
        sr.unregister();
        shutdown();
    }

    @Override
    public void notifyGDEvent(String deviceId, String serviceName, Map<String, Object> properties) {
        logger.debug("REST Servlet received event: " + deviceId + ", " + serviceName + ", " + properties);
    }

    @Override
    public void notifyGDPropertyEvent(Type type, String deviceId, String serviceName, String propertyId) {
        logger.debug(type + " property " + propertyId + " from " + deviceId + "." + propertyId);
    }

    @Override
    public void serviceChanged(ServiceEvent event) {
        ServiceReference sr = event.getServiceReference();
        switch (event.getType()) {
        case ServiceEvent.REGISTERED: {
            GenericDevice device = (GenericDevice) context.getService(sr);
            //         logger.log(LogService.LOG_DEBUG, "added:" + device.getId());
            logger.debug("added:" + device.getId());
        }
            break;
        case ServiceEvent.UNREGISTERING: {
            GenericDevice device = (GenericDevice) context.getService(sr);
            //         logger.log(LogService.LOG_DEBUG, "removed:" + device.getId());
            logger.debug("removed:" + device.getId());
        }
            break;
        default:
            break;
        }
    }
}