/* * ==================================================================== * ======== 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.tomp2p.upnp; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.TreeMap; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import org.w3c.dom.Document; import org.w3c.dom.Node; /** * Representation of an UPNP service * * @author <a href="mailto:superbonbon@sbbi.net">SuperBonBon</a> * @version 1.0 */ public class Service { /***/ public final String serviceType; /***/ public final String serviceId; /***/ public final URL SCPDURL; /***/ public final URL controlURL; /***/ public final URL eventSubURL; /***/ public final String USN; /***/ public final Device serviceOwnerDevice; private int specVersionMajor; private int specVersionMinor; private String SCPDURLData; private Map<String, Action> UPNPServiceActions = new TreeMap<String, Action>(); private Map<String, StateVariable> UPNPServiceStateVariables = new TreeMap<String, StateVariable>(); private boolean parsedSCPD = false; /** * @param serviceCtx * @param baseDeviceURL * @param serviceOwnerDevice * @throws MalformedURLException * @throws XPathExpressionException */ public Service(Node serviceCtx, URL baseDeviceURL, Device serviceOwnerDevice) throws MalformedURLException, XPathExpressionException { this.serviceOwnerDevice = serviceOwnerDevice; serviceType = XMLUtil.xpath.evaluate("serviceType", serviceCtx); serviceId = XMLUtil.xpath.evaluate("serviceId", serviceCtx); SCPDURL = Device.getURL(XMLUtil.xpath.evaluate("SCPDURL", serviceCtx), baseDeviceURL); controlURL = Device.getURL(XMLUtil.xpath.evaluate("controlURL", serviceCtx), baseDeviceURL); eventSubURL = Device.getURL(XMLUtil.xpath.evaluate("eventSubURL", serviceCtx), baseDeviceURL); USN = serviceOwnerDevice.UDN.concat("::").concat(serviceType); } /** * @return major version */ public int getSpecVersionMajor() { lazyInitiate(); return specVersionMajor; } /** * @return minor version */ public int getSpecVersionMinor() { lazyInitiate(); return specVersionMinor; } /** * Retrieves 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 Action getUPNPServiceAction(String actionName) { lazyInitiate(); return UPNPServiceActions.get(actionName); } /** * Retrieves 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 StateVariable getUPNPServiceStateVariable(String stateVariableName) { lazyInitiate(); return UPNPServiceStateVariables.get(stateVariableName); } /** * @return action names */ public Iterator<String> getAvailableActionsName() { lazyInitiate(); return UPNPServiceActions.keySet().iterator(); } /** * @return action count */ public int getAvailableActionsSize() { lazyInitiate(); return UPNPServiceActions.keySet().size(); } /** * @return state variable names */ public Iterator<String> getAvailableStateVariableName() { lazyInitiate(); return UPNPServiceStateVariables.keySet().iterator(); } /** * @return state variable count */ public int getAvailableStateVariableSize() { lazyInitiate(); return UPNPServiceStateVariables.keySet().size(); } private void parseSCPD() { try { Document doc = XMLUtil.getXML(SCPDURL); XPath xpath = XMLUtil.xpath; specVersionMajor = Integer.parseInt(xpath.evaluate("scpd/specVersion/major", doc)); specVersionMinor = Integer.parseInt(xpath.evaluate("scpd/specVersion/major", doc)); Node varList = (Node) xpath.evaluate("scpd/serviceStateTable", doc, XPathConstants.NODE); int varCount = Integer.parseInt(xpath.evaluate("count( stateVariable )", varList)); UPNPServiceStateVariables = new HashMap<String, StateVariable>(); for (int i = 1; i <= varCount; i++) { Node stateVarXML = (Node) xpath.evaluate("stateVariable[ " + i + " ]", varList, XPathConstants.NODE); StateVariable var = new StateVariable(this, stateVarXML); UPNPServiceStateVariables.put(var.name, var); } Node actionList = (Node) xpath.evaluate("scpd/actionList", doc, XPathConstants.NODE); int actionCount = Integer.parseInt(xpath.evaluate("count( action )", actionList)); UPNPServiceActions = new HashMap<String, Action>(); for (int i = 1; i <= actionCount; i++) { Node actionXML = (Node) xpath.evaluate("action[ " + i + " ]", actionList, XPathConstants.NODE); Action action = new Action(this, actionXML); // hook up the state variables for (Argument arg : action.arguments) { arg.relatedStateVariable = UPNPServiceStateVariables.get(arg.relatedStateVariableName); } UPNPServiceActions.put(action.getName(), action); } parsedSCPD = true; } catch (Throwable t) { System.out.println(XMLUtil.getXMLString(SCPDURL)); throw new RuntimeException("Error during lazy SCDP file parsing at " + SCPDURL, t); } } private void lazyInitiate() { if (!parsedSCPD) { synchronized (this) { if (!parsedSCPD) { parseSCPD(); } } } } /** * @return definition xml */ public String getSCDPData() { if (SCPDURLData == null) { try { java.io.InputStream in = SCPDURL.openConnection().getInputStream(); int readen = 0; byte[] buff = new byte[512]; StringBuilder strBuff = new StringBuilder(); 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; } @Override public String toString() { lazyInitiate(); StringBuilder b = new StringBuilder(); b.append("type = ").append(serviceType); b.append("\nid = ").append(serviceId); b.append("\nurl = ").append(SCPDURL); b.append("\ncontrol = ").append(controlURL); b.append("\nevent = ").append(eventSubURL); b.append("\nActions:"); for (Action action : UPNPServiceActions.values()) { String s = "\n\t" + action.toString(); s = s.replaceAll("\n", "\n\t"); b.append(s); } b.append("\nVariables:"); for (StateVariable v : UPNPServiceStateVariables.values()) { String s = "\n\t" + v.toString(); s = s.replaceAll("\n", "\n\t"); b.append(s); } return b.toString(); } }