org.coltram.nsd.upnp.UPnPProcessor.java Source code

Java tutorial

Introduction

Here is the source code for org.coltram.nsd.upnp.UPnPProcessor.java

Source

/*
 * Copyright (c) 2012-2013. Telecom ParisTech/TSI/MM/GPAC Jean-Claude Dufourd
 * This code was developed with the Coltram project, funded by the French ANR.
 *
 * This program 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, either version 3 of
 * the License, or (at your option) any later version.
 *
 * This program 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.
 *
 * This notice must stay in all subsequent versions of this code.
 */

package org.coltram.nsd.upnp;

import java.nio.channels.NotYetConnectedException;
import java.util.ArrayList;

import org.coltram.nsd.communication.AtomConnection;
import org.coltram.nsd.communication.TopManager;
import org.json.JSONException;
import org.json.JSONObject;
import org.teleal.cling.controlpoint.ActionCallback;
import org.teleal.cling.model.ValidationException;
import org.teleal.cling.model.action.ActionArgumentValue;
import org.teleal.cling.model.action.ActionInvocation;
import org.teleal.cling.model.message.UpnpResponse;
import org.teleal.cling.model.meta.DeviceDetails;
import org.teleal.cling.model.meta.DeviceIdentity;
import org.teleal.cling.model.meta.LocalDevice;
import org.teleal.cling.model.meta.Service;
import org.teleal.cling.model.types.DeviceType;
import org.teleal.cling.model.types.ServiceId;
import org.teleal.cling.model.types.ServiceType;
import org.teleal.cling.model.types.UDN;
import org.teleal.cling.registry.Registry;

public class UPnPProcessor {
    private static java.util.logging.Logger log = java.util.logging.Logger.getLogger(UPnPProcessor.class.getName());
    private ArrayList<SubscriptionCallback> subscriptions = new ArrayList<SubscriptionCallback>();

    private TopManager coltramManager;

    public UPnPProcessor(TopManager deviceManager) {
        this.coltramManager = deviceManager;
    }

    public void updateEvent(String eventName, String eventValue, String serviceId) {
        log.fine("up ev update " + eventName + "=" + eventValue);
        GenericService service = (GenericService) coltramManager.getServiceManager().findService(serviceId);
        if (service == null) {
            log.severe("updating event without an exposed service");
            throw new RuntimeException("updating event without an exposed service");
        }
        service.setEventValue(eventName, eventValue);
    }

    public void unsubscribe(String serviceId, String eventName) {
        log.info("unsubscribe UPnP " + eventName);
        for (SubscriptionCallback cb : subscriptions) {
            if (serviceId.endsWith(cb.getService().getServiceId().getId()) && eventName.equals(cb.getEventName())) {
                cb.end();
                return;
            }
        }
    }

    public void subscribe(String serviceId, String eventName, String callback, AtomConnection connection) {
        log.info("subscribe UPnP " + eventName);
        Service service = coltramManager.getServiceManager().findService(serviceId);
        SubscriptionCallback subscriptionCallback = new SubscriptionCallback(service, 600, eventName, connection,
                callback);
        subscriptions.add(subscriptionCallback);
        coltramManager.getConnectionManager().getUpnpService().getControlPoint().execute(subscriptionCallback);
    }

    public void callAction(String serviceId, String actionName, JSONObject arguments, AtomConnection connection,
            String callBack) {
        Service s = coltramManager.getServiceManager().findService(serviceId);
        if (s == null) {
            // service does not exist (any more ?)
            log.info("no service with id " + serviceId + " (" + actionName + ")");
        } else {
            executeAction(s, actionName, arguments, connection, callBack);
        }
    }

    /**
     * Function executing an action on a service, including the reply processing
     * only used in UPnP
     *
     * @param service       the target service
     * @param actionName    the name of the action to call
     * @param args          the arguments of the action
     * @param connection    the incoming connection in case reply is needed
     * @param replyCallBack the reply callback function name
     */
    private void executeAction(final Service service, final String actionName, JSONObject args,
            final AtomConnection connection, final String replyCallBack) {
        log.info("ENTERING executeAction" + " - actionName=" + actionName + ", replyCallBack=" + replyCallBack);
        //
        // to avoid a loop in the logging, any reply from COLTRAMAgentLogger is not logged
        //
        final String serviceType = service.getServiceType().toString();
        org.teleal.cling.model.meta.Action action = service.getAction(actionName);
        if (action == null) {
            log.warning("unknown action for this service: " + actionName + " " + service.getReference().toString());
            return;
        }
        NSDActionInvocation setTargetInvocation = new NSDActionInvocation(action, args);
        coltramManager.getConnectionManager().getUpnpService().getControlPoint()
                .execute(new ActionCallback(setTargetInvocation) {
                    @Override
                    public void success(org.teleal.cling.model.action.ActionInvocation invocation) {
                        log.finer("ENTERING ActionCallback.success" + " - actionName=" + actionName
                                + ", replyCallBack=" + replyCallBack);
                        ActionArgumentValue[] values = invocation.getOutput();
                        if (values != null && values.length > 0 && !"".equals(replyCallBack)) {
                            //
                            // if there is an output, call reply callback
                            //
                            JSONObject result = new JSONObject();
                            try {
                                result.put("purpose", "reply");
                                result.put("callBack", replyCallBack);
                                String sid = service.getDevice().getIdentity().getUdn().getIdentifierString();
                                sid += service.getReference().getServiceId().toString();
                                result.put("serviceId", sid);
                                result.put("actionName", actionName);
                            } catch (JSONException e) {
                                log.throwing(this.getClass().getName(),
                                        "JSON error while building reply (constant header)", e);
                            }
                            for (ActionArgumentValue v : values) {
                                try {
                                    result.put(v.getArgument().getName(), v.getValue());
                                } catch (JSONException e) {
                                    log.finer("JSON error while building reply: " + v.getArgument().getName());
                                }
                            }
                            try {
                                String s = result.toString();
                                connection.getConnection().send(s);
                                log.finer("sent " + s);
                            } catch (NotYetConnectedException e) {
                            }
                        }
                        log.finer("Successfully called action!");
                    }

                    @Override
                    public void failure(ActionInvocation invocation, UpnpResponse operation, String defaultMsg) {
                        System.err.println(defaultMsg);
                    }
                });
    }

    public void exposeService(String serviceType, String friendlyName, String deviceType, String serviceId,
            JSONObject service, AtomConnection connection, String serviceImplementationName) throws JSONException {
        ActionList actionList;
        try {
            actionList = new ActionList(service.getJSONArray("actionList"), connection, serviceImplementationName,
                    service.optJSONArray("eventList"));
        } catch (RuntimeException e) {
            // error in service description, translated to runtimeexception, so stop processing
            return;
        }
        try {
            GenericService exposedService = new GenericService<GenericService>(
                    ServiceType.valueOf(serviceType.substring(5)), ServiceId.valueOf(serviceId), actionList, false);
            exposedService.setManager(new ServiceManager<GenericService>(exposedService, GenericService.class));
            LocalDevice newDevice = new LocalDevice(new DeviceIdentity(new UDN(friendlyName)),
                    DeviceType.valueOf(deviceType), new DeviceDetails(friendlyName), exposedService);
            //Logger.logln("exposeService " + serviceType);
            coltramManager.getConnectionManager().getUpnpService().getRegistry().addDevice(newDevice);
            connection.add(newDevice);
            serviceId = newDevice.getIdentity().getUdn().getIdentifierString()
                    + exposedService.getReference().getServiceId().toString();
            connection.setExposedService(serviceId);
            log.finer("exposed Service: friendlyName=" + friendlyName + ", type=" + deviceType + ", serviceId="
                    + serviceId + ", serviceImplementationName=" + serviceImplementationName);
        } catch (ValidationException e) {
            e.printStackTrace();
        }
    }

    public void unexposeService(String friendlyName, AtomConnection connection) throws JSONException {
        log.finer("unexposeService: friendlyName=" + friendlyName);
        Registry reg = coltramManager.getConnectionManager().getUpnpService().getRegistry();
        UDN udn = new UDN(friendlyName);

        reg.removeDevice(udn);

        for (LocalDevice device : connection.devices()) {
            //log.finer(device.getIdentity().toString());
            //log.finer(new DeviceIdentity(new UDN(friendlyName)).toString());
            if (device.getIdentity().equals(new DeviceIdentity(new UDN(friendlyName)))) {
                log.finer("device removed from connection");
                connection.remove(device);
                break;
            }
        }

    }
}