net.sbbi.upnp.services.UPNPService.java Source code

Java tutorial

Introduction

Here is the source code for net.sbbi.upnp.services.UPNPService.java

Source

/*
 * ============================================================================
 *                 The Apache Software License, Version 1.1
 * ============================================================================
 *
 * Copyright (C) 2002 The Apache Software Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modifica-
 * tion, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of  source code must  retain the above copyright  notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * 3. The end-user documentation included with the redistribution, if any, must
 *    include the following  acknowledgment: "This product includes software
 *    developed by SuperBonBon Industries (http://www.sbbi.net/)."
 *    Alternately, this acknowledgment may appear in the software itself, if
 *    and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "UPNPLib" and "SuperBonBon Industries" must not be
 *    used to endorse or promote products derived from this software without
 *    prior written permission. For written permission, please contact
 *    info@sbbi.net.
 *
 * 5. Products  derived from this software may not be called 
 *    "SuperBonBon Industries", nor may "SBBI" appear in their name, 
 *    without prior written permission of SuperBonBon Industries.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED. IN NO EVENT SHALL THE
 * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT,INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
 * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * This software  consists of voluntary contributions made by many individuals
 * on behalf of SuperBonBon Industries. For more information on 
 * SuperBonBon Industries, please see <http://www.sbbi.net/>.
 */
package net.sbbi.upnp.services;

import org.apache.commons.jxpath.*;
import org.apache.commons.jxpath.xml.*;

import java.util.*;
import java.io.IOException;
import java.net.*;

import net.sbbi.upnp.JXPathParser;
import net.sbbi.upnp.devices.*;

/**
 * Representation of an UPNP service
 * @author <a href="mailto:superbonbon@sbbi.net">SuperBonBon</a>
 * @version 1.0
 */
public class UPNPService {

    protected String serviceType;
    protected String serviceId;
    private int specVersionMajor;
    private int specVersionMinor;
    protected URL SCPDURL;
    protected String SCPDURLData;
    protected URL controlURL;
    protected URL eventSubURL;
    protected UPNPDevice serviceOwnerDevice;

    protected Map UPNPServiceActions;
    protected Map UPNPServiceStateVariables;
    private String USN;

    private boolean parsedSCPD = false;
    private DocumentContainer UPNPService;

    public UPNPService(JXPathContext serviceCtx, URL baseDeviceURL, UPNPDevice serviceOwnerDevice)
            throws MalformedURLException {
        this.serviceOwnerDevice = serviceOwnerDevice;
        serviceType = (String) serviceCtx.getValue("serviceType");
        serviceId = (String) serviceCtx.getValue("serviceId");
        SCPDURL = UPNPRootDevice.getURL((String) serviceCtx.getValue("SCPDURL"), baseDeviceURL);
        controlURL = UPNPRootDevice.getURL((String) serviceCtx.getValue("controlURL"), baseDeviceURL);
        eventSubURL = UPNPRootDevice.getURL((String) serviceCtx.getValue("eventSubURL"), baseDeviceURL);
        USN = serviceOwnerDevice.getUDN().concat("::").concat(serviceType);
    }

    public String getServiceType() {
        return serviceType;
    }

    public String getServiceId() {
        return serviceId;
    }

    public String getUSN() {
        return USN;
    }

    public URL getSCPDURL() {
        return SCPDURL;
    }

    public URL getControlURL() {
        return controlURL;
    }

    public URL getEventSubURL() {
        return eventSubURL;
    }

    public int getSpecVersionMajor() {
        lazyInitiate();
        return specVersionMajor;
    }

    public int getSpecVersionMinor() {
        lazyInitiate();
        return specVersionMinor;
    }

    public UPNPDevice getServiceOwnerDevice() {
        return serviceOwnerDevice;
    }

    /**
     * Retreives a service action for its given name
     * @param actionName the service action name
     * @return a ServiceAction object or null if no matching action for this service has been found
     */
    public ServiceAction getUPNPServiceAction(String actionName) {
        lazyInitiate();
        return (ServiceAction) UPNPServiceActions.get(actionName);
    }

    /**
     * Retreives a service state variable for its given name
     * @param stateVariableName the state variable name
     * @return a ServiceStateVariable object or null if no matching state variable has been found
     */
    public ServiceStateVariable getUPNPServiceStateVariable(String stateVariableName) {
        lazyInitiate();
        return (ServiceStateVariable) UPNPServiceStateVariables.get(stateVariableName);
    }

    public Iterator getAvailableActionsName() {
        lazyInitiate();
        return UPNPServiceActions.keySet().iterator();
    }

    public int getAvailableActionsSize() {
        lazyInitiate();
        return UPNPServiceActions.keySet().size();
    }

    public Iterator getAvailableStateVariableName() {
        lazyInitiate();
        return UPNPServiceStateVariables.keySet().iterator();
    }

    public int getAvailableStateVariableSize() {
        lazyInitiate();
        return UPNPServiceStateVariables.keySet().size();
    }

    private void parseSCPD() {
        try {
            DocumentContainer.registerXMLParser(DocumentContainer.MODEL_DOM, new JXPathParser());
            UPNPService = new DocumentContainer(SCPDURL, DocumentContainer.MODEL_DOM);
            JXPathContext context = JXPathContext.newContext(this);
            Pointer rootPtr = context.getPointer("UPNPService/scpd");
            JXPathContext rootCtx = context.getRelativeContext(rootPtr);

            specVersionMajor = Integer.parseInt((String) rootCtx.getValue("specVersion/major"));
            specVersionMinor = Integer.parseInt((String) rootCtx.getValue("specVersion/minor"));

            parseServiceStateVariables(rootCtx);

            Pointer actionsListPtr = rootCtx.getPointer("actionList");
            JXPathContext actionsListCtx = context.getRelativeContext(actionsListPtr);
            Double arraySize = (Double) actionsListCtx.getValue("count( action )");
            UPNPServiceActions = new HashMap();
            for (int i = 1; i <= arraySize.intValue(); i++) {
                ServiceAction action = new ServiceAction();
                action.name = (String) actionsListCtx.getValue("action[" + i + "]/name");
                action.parent = this;
                Pointer argumentListPtr = null;
                try {
                    argumentListPtr = actionsListCtx.getPointer("action[" + i + "]/argumentList");
                } catch (JXPathException ex) {
                    // there is no arguments list.
                }
                if (argumentListPtr != null) {
                    JXPathContext argumentListCtx = actionsListCtx.getRelativeContext(argumentListPtr);
                    Double arraySizeArgs = (Double) argumentListCtx.getValue("count( argument )");

                    List orderedActionArguments = new ArrayList();
                    for (int z = 1; z <= arraySizeArgs.intValue(); z++) {
                        ServiceActionArgument arg = new ServiceActionArgument();
                        arg.name = (String) argumentListCtx.getValue("argument[" + z + "]/name");
                        String direction = (String) argumentListCtx.getValue("argument[" + z + "]/direction");
                        arg.direction = direction.equals(ServiceActionArgument.DIRECTION_IN)
                                ? ServiceActionArgument.DIRECTION_IN
                                : ServiceActionArgument.DIRECTION_OUT;
                        String stateVarName = (String) argumentListCtx
                                .getValue("argument[" + z + "]/relatedStateVariable");
                        ServiceStateVariable stateVar = (ServiceStateVariable) UPNPServiceStateVariables
                                .get(stateVarName);
                        if (stateVar == null) {
                            throw new IllegalArgumentException(
                                    "Unable to find any state variable named " + stateVarName + " for service "
                                            + getServiceId() + " action " + action.name + " argument " + arg.name);
                        }
                        arg.relatedStateVariable = stateVar;
                        orderedActionArguments.add(arg);
                    }

                    if (arraySizeArgs.intValue() > 0) {
                        action.setActionArguments(orderedActionArguments);
                    }
                }

                UPNPServiceActions.put(action.getName(), action);
            }
            parsedSCPD = true;
        } catch (Throwable t) {
            throw new RuntimeException("Error during lazy SCDP file parsing at " + SCPDURL, t);
        }
    }

    private void parseServiceStateVariables(JXPathContext rootContext) {
        Pointer serviceStateTablePtr = rootContext.getPointer("serviceStateTable");
        JXPathContext serviceStateTableCtx = rootContext.getRelativeContext(serviceStateTablePtr);
        Double arraySize = (Double) serviceStateTableCtx.getValue("count( stateVariable )");
        UPNPServiceStateVariables = new HashMap();
        for (int i = 1; i <= arraySize.intValue(); i++) {
            ServiceStateVariable srvStateVar = new ServiceStateVariable();
            String sendEventsLcl = null;
            try {
                sendEventsLcl = (String) serviceStateTableCtx.getValue("stateVariable[" + i + "]/@sendEvents");
            } catch (JXPathException defEx) {
                // sendEvents not provided defaulting according to specs to "yes"
                sendEventsLcl = "yes";
            }
            srvStateVar.parent = this;
            srvStateVar.sendEvents = sendEventsLcl.equalsIgnoreCase("no") ? false : true;
            srvStateVar.name = (String) serviceStateTableCtx.getValue("stateVariable[" + i + "]/name");
            srvStateVar.dataType = (String) serviceStateTableCtx.getValue("stateVariable[" + i + "]/dataType");
            try {
                srvStateVar.defaultValue = (String) serviceStateTableCtx
                        .getValue("stateVariable[" + i + "]/defaultValue");
            } catch (JXPathException defEx) {
                // can happend since default value is not
            }
            Pointer allowedValuesPtr = null;
            try {
                allowedValuesPtr = serviceStateTableCtx.getPointer("stateVariable[" + i + "]/allowedValueList");
            } catch (JXPathException ex) {
                // there is no allowed values list.
            }
            if (allowedValuesPtr != null) {
                JXPathContext allowedValuesCtx = serviceStateTableCtx.getRelativeContext(allowedValuesPtr);
                Double arraySizeAllowed = (Double) allowedValuesCtx.getValue("count( allowedValue )");
                srvStateVar.allowedvalues = new HashSet();
                for (int z = 1; z <= arraySizeAllowed.intValue(); z++) {
                    String allowedValue = (String) allowedValuesCtx.getValue("allowedValue[" + z + "]");
                    srvStateVar.allowedvalues.add(allowedValue);
                }
            }

            Pointer allowedValueRangePtr = null;
            try {
                allowedValueRangePtr = serviceStateTableCtx
                        .getPointer("stateVariable[" + i + "]/allowedValueRange");
            } catch (JXPathException ex) {
                // there is no allowed values list, can happen
            }
            if (allowedValueRangePtr != null) {

                srvStateVar.minimumRangeValue = (String) serviceStateTableCtx
                        .getValue("stateVariable[" + i + "]/allowedValueRange/minimum");
                srvStateVar.maximumRangeValue = (String) serviceStateTableCtx
                        .getValue("stateVariable[" + i + "]/allowedValueRange/maximum");
                try {
                    srvStateVar.stepRangeValue = (String) serviceStateTableCtx
                            .getValue("stateVariable[" + i + "]/allowedValueRange/step");
                } catch (JXPathException stepEx) {
                    // can happend since step is not mandatory
                }
            }
            UPNPServiceStateVariables.put(srvStateVar.getName(), srvStateVar);
        }

    }

    private void lazyInitiate() {
        if (!parsedSCPD)
            synchronized (this) {
                if (!parsedSCPD)
                    parseSCPD();
            }
    }

    /**
     * Used for JXPath parsing, do not use this method
     * @return a Container object for Xpath parsing capabilities
     */
    public Container getUPNPService() {
        return UPNPService;
    }

    public String getSCDPData() {
        if (SCPDURLData == null) {
            try {

                java.io.InputStream in = SCPDURL.openConnection().getInputStream();
                int readen = 0;
                byte[] buff = new byte[512];
                StringBuffer strBuff = new StringBuffer();
                while ((readen = in.read(buff)) != -1) {
                    strBuff.append(new String(buff, 0, readen));
                }
                in.close();
                SCPDURLData = strBuff.toString();
            } catch (IOException ioEx) {
                return null;
            }
        }
        return SCPDURLData;
    }
}