All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.cybergarage.upnp.Service Maven / Gradle / Ivy

There is a newer version: 2.6.0
Show newest version
/******************************************************************
*
*	CyberLink for Java
*
*	Copyright (C) Satoshi Konno 2002-2003
*
*	File: Service.java
*
*	Revision;
*
*	11/28/02
*		- first revision.
*	04/12/02
*		- Holmes, Arran C 
*		- Fixed SERVICE_ID constant instead of "serviceId".
*	06/17/03
*		- Added notifyAllStateVariables().
*	09/03/03
*		- Giordano Sassaroli 
*		- Problem : The device does not accepts request for services when control or subscription urls are absolute
*		- Error : device methods, when requests are received, search for services that have a controlUrl (or eventSubUrl) equal to the request URI
*		          but request URI must be relative, so they cannot equal absolute urls
*	09/03/03
*		- Steven Yen
*		- description: to retrieve service information based on information in URLBase and SCPDURL
*		- problem: not able to retrieve service information when URLBase is missing and SCPDURL is relative
*		- fix: modify to retrieve host information from Header's Location (required) field and update the
*		       BaseURL tag in the xml so subsequent information retrieval can be done (Steven Yen, 8.27.2003)
*		- note: 1. in the case that Header's Location field combine with SCPDURL is not able to retrieve proper 
*		          information, updating BaseURL would not hurt, since exception will be thrown with or without update.
*		        2. this problem was discovered when using PC running MS win XP with ICS enabled (gateway). 
*		          It seems that  root device xml file does not have BaseURL and SCPDURL are all relative.
*		        3. UPnP device architecture states that BaseURL is optional and SCPDURL may be relative as 
*		          specified by UPnP vendor, so MS does not seem to violate the rule.
*	10/22/03
*		- Added setActionListener().
*	01/04/04
*		- Changed about new QueryListener interface.
*	01/06/04
*		- Moved the following methods to StateVariable class.
*		  getQueryListener() 
*		  setQueryListener() 
*		  performQueryListener()
*		- Added new setQueryListener() to set a listner to all state variables.
*	07/02/04
*		- Added serviceSearchResponse().
*		- Deleted getLocationURL().
*		- Fixed announce() to set the root device URL to the LOCATION field.
*	07/31/04
*		- Changed notify() to remove the expired subscribers and not to remove the invalid response subscribers for NMPR.
*	10/29/04
*		- Fixed a bug when notify() removes the expired devices().
*	03/23/05
*		- Added loadSCPD() to load the description from memory.
*	03/30/05
*		- Added isSCPDURL().
*		- Removed setDescriptionURL() and getDescriptionURL()
*	03/31/05
*		- Added getSCPDData().
* 	04/25/05
*		- Thanks for Mikael Hakman 
* 		- Changed getSCPDData() to add a XML declaration at first line.
*	06/21/05
*		- Changed notify() to continue when the subscriber is null.
*	04/12/06
*		- Added setUserData() and getUserData() to set a user original data object.
*	09/18/2010 Robin V. 
*		- Fixed getSCPDNode() not to occur recursive http get requests.
*
******************************************************************/

package org.cybergarage.upnp;

import java.io.File;
import java.io.InputStream;
import java.io.IOException;
import java.net.URL;
import java.util.Iterator;

import org.cybergarage.http.HTTP;
import org.cybergarage.http.HTTPResponse;
import org.cybergarage.upnp.control.ActionListener;
import org.cybergarage.upnp.control.QueryListener;
import org.cybergarage.upnp.device.InvalidDescriptionException;
import org.cybergarage.upnp.device.NTS;
import org.cybergarage.upnp.device.ST;
import org.cybergarage.upnp.event.NotifyRequest;
import org.cybergarage.upnp.event.Subscriber;
import org.cybergarage.upnp.event.SubscriberList;
import org.cybergarage.upnp.ssdp.SSDPNotifyRequest;
import org.cybergarage.upnp.ssdp.SSDPNotifySocket;
import org.cybergarage.upnp.ssdp.SSDPPacket;
import org.cybergarage.upnp.xml.ServiceData;
import org.cybergarage.util.Debug;
import org.cybergarage.util.Mutex;
import org.cybergarage.util.StringUtil;
import org.cybergarage.xml.Node;
import org.cybergarage.xml.Parser;
import org.cybergarage.xml.ParserException;

public class Service
{
	////////////////////////////////////////////////
	//	Constants
	////////////////////////////////////////////////
	
	public final static String ELEM_NAME = "service";

	////////////////////////////////////////////////
	//	Member
	////////////////////////////////////////////////

	private Node serviceNode;

	public Node getServiceNode()
	{
		return serviceNode;
	}

	////////////////////////////////////////////////
	//	Constructor
	////////////////////////////////////////////////
	public static final String SCPD_ROOTNODE="scpd";
	public static final String SCPD_ROOTNODE_NS="urn:schemas-upnp-org:service-1-0"; 

	public static final String SPEC_VERSION="specVersion";
	public static final String MAJOR="major";
	public static final String MAJOR_VALUE="1";
	public static final String MINOR="minor";
	public static final String MINOR_VALUE="0";
	
	public Service(){
		this(new Node(ELEM_NAME));
		
		Node sp = new Node(SPEC_VERSION);
		
		Node M =new Node(MAJOR);
		M.setValue(MAJOR_VALUE);
		sp.addNode(M);
				
		Node m =new Node(MINOR);
		m.setValue(MINOR_VALUE);
		sp.addNode(m);
		
		//Node scpd = new Node(SCPD_ROOTNODE,SCPD_ROOTNODE_NS); wrong!
		Node scpd = new Node(SCPD_ROOTNODE);
		scpd.addAttribute("xmlns",SCPD_ROOTNODE_NS);
		scpd.addNode(sp);
		getServiceData().setSCPDNode(scpd);
	}

	public Service(Node node)
	{
		serviceNode = node;
	}

	////////////////////////////////////////////////
	// Mutex
	////////////////////////////////////////////////
	
	private Mutex mutex = new Mutex();
	
	public void lock()
	{
		mutex.lock();
	}
	
	public void unlock()
	{
		mutex.unlock();
	}
	
	////////////////////////////////////////////////
	//	isServiceNode
	////////////////////////////////////////////////

	public static boolean isServiceNode(Node node)
	{
		return Service.ELEM_NAME.equals(node.getName());
	}
	
	////////////////////////////////////////////////
	//	Device/Root Node
	////////////////////////////////////////////////

	private Node getDeviceNode()
	{
		Node node = getServiceNode().getParentNode();
		if (node == null)
			return null;
		return node.getParentNode();
	}

	private Node getRootNode()
	{
		return getServiceNode().getRootNode();
	}

	////////////////////////////////////////////////
	//	Device
	////////////////////////////////////////////////

	public Device getDevice()
	{
		return new Device(getRootNode(), getDeviceNode());
	}

	public Device getRootDevice()
	{
		return getDevice().getRootDevice();
	}

	////////////////////////////////////////////////
	//	serviceType
	////////////////////////////////////////////////

	private final static String SERVICE_TYPE = "serviceType";
	
	public void setServiceType(String value)
	{
		getServiceNode().setNode(SERVICE_TYPE, value);
	}

	public String getServiceType()
	{
		return getServiceNode().getNodeValue(SERVICE_TYPE);
	}

	////////////////////////////////////////////////
	//	serviceID
	////////////////////////////////////////////////

	private final static String SERVICE_ID = "serviceId";
	
	public void setServiceID(String value)
	{
		getServiceNode().setNode(SERVICE_ID, value);
	}

	public String getServiceID()
	{
		return getServiceNode().getNodeValue(SERVICE_ID);
	}

	////////////////////////////////////////////////
	//	configID
	////////////////////////////////////////////////

	private final static String CONFIG_ID = "configId";
	
	public void updateConfigId()
	{
		Node scpdNode = getSCPDNode();
		if (scpdNode == null)
			return;
		
		String scpdXml = scpdNode.toString();
		int configId = UPnP.caluculateConfigId(scpdXml);
		scpdNode.setAttribute(CONFIG_ID, configId);
	}

	public int getConfigId()
	{
		Node scpdNode = getSCPDNode();
		if (scpdNode == null)
			return 0;
		return scpdNode.getAttributeIntegerValue(CONFIG_ID);
	}
	
	////////////////////////////////////////////////
	//	isURL
	////////////////////////////////////////////////
	
	// Thanks for Giordano Sassaroli  (09/03/03)
	private boolean isURL(String referenceUrl, String url)
	{
		if (referenceUrl ==null || url == null)
			return false;
		boolean ret = url.equals(referenceUrl);
		if (ret == true)
			return true;
		String relativeRefUrl = HTTP.toRelativeURL(referenceUrl, false);
		ret = url.equals(relativeRefUrl);
		if (ret == true)
			return true;
		return false;
	}
	
	////////////////////////////////////////////////
	//	SCPDURL
	////////////////////////////////////////////////

	private final static String SCPDURL = "SCPDURL";
	
	public void setSCPDURL(String value)
	{
		getServiceNode().setNode(SCPDURL, value);
	}

	public String getSCPDURL()
	{
		return getServiceNode().getNodeValue(SCPDURL);
	}

	public boolean isSCPDURL(String url)
	{
		return isURL(getSCPDURL(), url);
	}
	
	////////////////////////////////////////////////
	//	controlURL
	////////////////////////////////////////////////

	private final static String CONTROL_URL = "controlURL";
	
	public void setControlURL(String value)
	{
		getServiceNode().setNode(CONTROL_URL, value);
	}

	public String getControlURL()
	{
		return getServiceNode().getNodeValue(CONTROL_URL);
	}

	public boolean isControlURL(String url)
	{
		return isURL(getControlURL(), url);
	}

	////////////////////////////////////////////////
	//	eventSubURL
	////////////////////////////////////////////////

	private final static String EVENT_SUB_URL = "eventSubURL";
	
	public void setEventSubURL(String value)
	{
		getServiceNode().setNode(EVENT_SUB_URL, value);
	}

	public String getEventSubURL()
	{
		return getServiceNode().getNodeValue(EVENT_SUB_URL);
	}

	public boolean isEventSubURL(String url)
	{
		return isURL(getEventSubURL(), url);
	}
	
	////////////////////////////////////////////////
	//	SCPD node
	////////////////////////////////////////////////

	public boolean loadSCPD(String scpdStr) throws InvalidDescriptionException
	{
		try {
			Parser parser = UPnP.getXMLParser();
			Node scpdNode = parser.parse(scpdStr);
			if (scpdNode == null)
				return false;
			ServiceData data = getServiceData();
			data.setSCPDNode(scpdNode);
		}
		catch (ParserException e) {
			throw new InvalidDescriptionException(e);
		}
		
		return true;
	}

	public boolean loadSCPD(File file) throws ParserException
	{
		Parser parser = UPnP.getXMLParser();
		Node scpdNode = parser.parse(file);
		if (scpdNode == null)
			return false;
		
		ServiceData data = getServiceData();
		data.setSCPDNode(scpdNode);

		return true;
	}

	/**
	 * @since 1.8.0 
	 */
	public boolean loadSCPD(InputStream input) throws ParserException
	{
		Parser parser = UPnP.getXMLParser();
		Node scpdNode = parser.parse(input);
		if (scpdNode == null)
			return false;
		
		ServiceData data = getServiceData();
		data.setSCPDNode(scpdNode);
		
		return true;
	}
	
	
    public void setDescriptionURL(String value)
    {
    	getServiceData().setDescriptionURL(value);
    }

    public String getDescriptionURL()
    {
    	return getServiceData().getDescriptionURL();
    }
	
	
	private Node getSCPDNode(URL scpdUrl) throws ParserException
	{
		Parser parser = UPnP.getXMLParser();
		return parser.parse(scpdUrl);
	}
	
	private Node getSCPDNode(File scpdFile) throws ParserException
	{
		Parser parser = UPnP.getXMLParser();
		return parser.parse(scpdFile);
	}

	private Node getSCPDNode()
	{
		ServiceData data = getServiceData();
		Node scpdNode = data.getSCPDNode();
		if (scpdNode != null)
			return scpdNode;
		
		// Thanks for Jaap (Sep 18, 2010)
		Device rootDev = getRootDevice();
		if (rootDev == null)
			return null;
		
		String scpdURLStr = getSCPDURL();

/****
 * I2P - no, dont attempt to load local file
 *
		// Thanks for Robin V. (Sep 18, 2010)
		String rootDevPath = rootDev.getDescriptionFilePath();
		if(rootDevPath!=null) {
			File f;
			f = new File(rootDevPath.concat(scpdURLStr));
		
			if(f.exists()) {
				try {
					scpdNode = getSCPDNode(f);
				} catch (ParserException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				if(scpdNode!=null) {
					data.setSCPDNode(scpdNode);
					return scpdNode;
				}
			}
		}
****/

		try {
			URL scpdUrl = new URL(rootDev.getAbsoluteURL(scpdURLStr));
			scpdNode = getSCPDNode(scpdUrl);		
			if (scpdNode != null) {
				data.setSCPDNode(scpdNode);
				return scpdNode;
			}
		}
		catch (Exception e) {
			// I2P
			Debug.warning(e);
		}
		
/****
 * I2P - no, dont attempt to load local file
 *
		String newScpdURLStr = rootDev.getDescriptionFilePath() + HTTP.toRelativeURL(scpdURLStr);
		try {
			scpdNode = getSCPDNode(new File(newScpdURLStr));
			return scpdNode;
		}
		catch (Exception e) {
			Debug.warning(e);
		}
****/
		
		return null;
	}

	public byte[] getSCPDData()
	{
		Node scpdNode = getSCPDNode();
		if (scpdNode == null)
			return new byte[0];
		// Thanks for Mikael Hakman (04/25/05)
		String desc = new String();
		desc += UPnP.XML_DECLARATION;
		desc += "\n";
		desc += scpdNode.toString();
		return desc.getBytes();
	}
	
	////////////////////////////////////////////////
	//	actionList
	////////////////////////////////////////////////

	public ActionList getActionList()
	{
		ActionList actionList = new ActionList();
		Node scdpNode = getSCPDNode();
		if (scdpNode == null)
			return actionList;
		Node actionListNode = scdpNode.getNode(ActionList.ELEM_NAME);
		if (actionListNode == null)
			return actionList;
		int nNode = actionListNode.getNNodes();
		for (int n=0; n i = a.getArgumentList().iterator();
		while (i.hasNext()) {
			Argument arg = i.next();
			arg.setService(this);
		}

		Node scdpNode = getSCPDNode();
		Node actionListNode = scdpNode.getNode(ActionList.ELEM_NAME);
		if (actionListNode == null){			
			actionListNode = new Node(ActionList.ELEM_NAME);
			scdpNode.addNode(actionListNode);
		}
		actionListNode.addNode(a.getActionNode());
	}
	
	////////////////////////////////////////////////
	//	serviceStateTable
	////////////////////////////////////////////////

	public ServiceStateTable getServiceStateTable()
	{
		ServiceStateTable stateTable = new ServiceStateTable();
		Node stateTableNode = getSCPDNode().getNode(ServiceStateTable.ELEM_NAME);
		if (stateTableNode == null)
			return stateTable;
		Node serviceNode = getServiceNode();
		int nNode = stateTableNode.getNNodes();
		for (int n=0; n
	 * 
* Note: This method should be used to create a dynamic
* Device withtout writing any XML that describe the device
. *
* Note: that no control for duplicate StateVariable is done. * * @param var StateVariable that will be added */ public void addStateVariable(StateVariable var) { //TODO Some test are done not stable Node stateTableNode = getSCPDNode().getNode(ServiceStateTable.ELEM_NAME); if (stateTableNode == null){ stateTableNode = new Node(ServiceStateTable.ELEM_NAME); /* * Force the node to be the first node inside */ //getSCPDNode().insertNode(stateTableNode,0); getSCPDNode().addNode(stateTableNode); } var.setServiceNode(getServiceNode()); stateTableNode.addNode(var.getStateVariableNode()); } //////////////////////////////////////////////// // userData //////////////////////////////////////////////// private Object userData = null; public void setUserData(Object data) { userData = data; } public Object getUserData() { return userData; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy