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

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

The newest version!
/******************************************************************
*
*	CyberLink for Java
*
*	Copyright (C) Satoshi Konno 2002-2004
*
*	File: Device.java
*
*	Revision:
*
*	11/28/02
*		- first revision.
*	02/26/03
*		- URLBase is updated automatically.
* 		- Description of a root device is returned from the XML node tree.
*	05/13/03
*		- URLBase is updated when the request is received.
*		- Changed to create socket threads each local interfaces.
*		  (HTTP, SSDPSearch)
*	06/17/03
*		- Added notify all state variables when a new subscription is received.
*	06/18/03
*		- Fixed a announce bug when the bind address is null on J2SE v 1.4.1_02 and Redhat 9.
*	09/02/03
*		- Giordano Sassaroli 
*		- Problem : bad request response sent even with successful subscriptions
*		- Error : a return statement is missing in the httpRequestRecieved method
*	10/21/03
*		- Updated a udn field by a original uuid.
*	10/22/03
*		- Added setActionListener().
*		- Added setQueryListener().
*	12/12/03
*		- Added a static() to initialize UPnP class.
*	12/25/03
*		- Added advertiser functions.
*	01/05/04
*		- Added isExpired().
*	03/23/04
*		- Oliver Newell 
*		- Changed to update the UDN only when the field is null.
*	04/21/04
*		- Added isDeviceType().
*	06/18/04
*		- Added setNMPRMode() and isNMPRMode().
*		- Changed getDescriptionData() to update only when the NMPR mode is false.
*	06/21/04
*		- Changed start() to send a bye-bye before the announce.
*		- Changed annouce(), byebye() and deviceSearchReceived() to send the SSDP
*		  messsage four times when the NMPR and the Wireless mode are true.
*	07/02/04
*		- Fixed announce() and byebye() to send the upnp::rootdevice message despite embedded devices.
*		- Fixed getRootNode() to return the root node when the device is embedded.
*	07/24/04
*		- Thanks for Stefano Lenzi 
*		- Added getParentDevice().
*	10/20/04 
*		- Brent Hills 
*		- Changed postSearchResponse() to add MYNAME header.
*	11/19/04
*		- Theo Beisch 
*		- Added getStateVariable(String serviceType, String name).
*	03/22/05
*		- Changed httpPostRequestRecieved() to return the bad request when the post request isn't the soap action.
*	03/23/05
*		- Added loadDescription(String) to load the description from memory.
*	03/30/05
*		- Added getDeviceByDescriptionURI().
*		- Added getServiceBySCPDURL().
*	03/31/05
*		- Changed httpGetRequestRecieved() to return the description stream using
*		  Device::getDescriptionData() and Service::getSCPDData() at first.
*	04/25/05
*		- Thanks for Mikael Hakman 
*		  Changed announce() and byebye() to close the socket after the posting.
*	04/25/05
*		- Thanks for Mikael Hakman 
*		  Changed deviceSearchResponse() answer with USN:UDN:: when request ST is device type.
* 	04/25/05
*		- Thanks for Mikael Hakman 
* 		- Changed getDescriptionData() to add a XML declaration at first line.
* 	04/25/05
*		- Thanks for Mikael Hakman 
*		- Added a new setActionListener() and serQueryListner() to include the sub devices. 
*	07/24/05
*		- Thanks for Stefano Lenzi 
*		- Fixed a bug of getParentDevice() to return the parent device normally.
*	02/21/06
*		- Changed httpRequestRecieved() not to ignore HEAD requests.
*	04/12/06
*		- Added setUserData() and getUserData() to set a user original data object.
*
*	02/01/08
*		- added thread name for device advertiser in setLeaseTime (francesco)
*		- TODO check if restart is compatibile with Advertiser thread suspended on sleep
* 
******************************************************************/

package org.cybergarage.upnp;

import java.io.File;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.URL;
import java.util.Calendar;

import org.cybergarage.http.HTTPRequest;
import org.cybergarage.http.HTTPResponse;
import org.cybergarage.http.HTTPServerList;
import org.cybergarage.http.HTTPStatus;
import org.cybergarage.net.HostInterface;
import org.cybergarage.soap.SOAPResponse;
import org.cybergarage.upnp.control.ActionListener;
import org.cybergarage.upnp.control.ActionRequest;
import org.cybergarage.upnp.control.ActionResponse;
import org.cybergarage.upnp.control.ControlRequest;
import org.cybergarage.upnp.control.ControlResponse;
import org.cybergarage.upnp.control.QueryListener;
import org.cybergarage.upnp.control.QueryRequest;
import org.cybergarage.upnp.device.Advertiser;
import org.cybergarage.upnp.device.Description;
import org.cybergarage.upnp.device.InvalidDescriptionException;
import org.cybergarage.upnp.device.NTS;
import org.cybergarage.upnp.device.ST;
import org.cybergarage.upnp.device.SearchListener;
import org.cybergarage.upnp.device.USN;
import org.cybergarage.upnp.event.Subscriber;
import org.cybergarage.upnp.event.Subscription;
import org.cybergarage.upnp.event.SubscriptionRequest;
import org.cybergarage.upnp.event.SubscriptionResponse;
import org.cybergarage.upnp.ssdp.SSDPNotifyRequest;
import org.cybergarage.upnp.ssdp.SSDPNotifySocket;
import org.cybergarage.upnp.ssdp.SSDPPacket;
import org.cybergarage.upnp.ssdp.SSDPSearchResponse;
import org.cybergarage.upnp.ssdp.SSDPSearchResponseSocket;
import org.cybergarage.upnp.ssdp.SSDPSearchSocketList;
import org.cybergarage.upnp.xml.DeviceData;
import org.cybergarage.util.Debug;
import org.cybergarage.util.FileUtil;
import org.cybergarage.util.Mutex;
import org.cybergarage.util.TimerUtil;
import org.cybergarage.xml.Node;
import org.cybergarage.xml.Parser;
import org.cybergarage.xml.ParserException;
import org.cybergarage.xml.XML;

public class Device implements org.cybergarage.http.HTTPRequestListener, SearchListener
{
	////////////////////////////////////////////////
	//	Constants
	////////////////////////////////////////////////
	
	public final static String ELEM_NAME = "device";
	public final static String UPNP_ROOTDEVICE = "upnp:rootdevice";

	public final static int DEFAULT_STARTUP_WAIT_TIME = 1000;
	public final static int DEFAULT_DISCOVERY_WAIT_TIME = 300;
	public final static int DEFAULT_LEASE_TIME = 30 * 60;

	public final static int HTTP_DEFAULT_PORT = 4004;

	public final static String DEFAULT_DESCRIPTION_URI = "/description.xml";
	
	////////////////////////////////////////////////
	//	Member
	////////////////////////////////////////////////

	private Node rootNode;
	private Node deviceNode;

	public Node getRootNode()
	{
		if (rootNode != null)
			return rootNode;
		if (deviceNode == null)
			return null;
		return deviceNode.getRootNode();
	}

	public Node getDeviceNode()
	{
		return deviceNode;
	}

	public void setRootNode(Node node)
	{
		rootNode = node;
	}

	public void setDeviceNode(Node node)
	{
		deviceNode = node;
	}
				
	////////////////////////////////////////////////
	//	Initialize
	////////////////////////////////////////////////
	
	static 
	{
		UPnP.initialize();
	}
	
	////////////////////////////////////////////////
	//	Constructor
	////////////////////////////////////////////////

	public Device(Node root, Node device)
	{
		rootNode = root;
		deviceNode = device;
		setUUID(UPnP.createUUID());
		setWirelessMode(false);
	}

	public Device()
	{
		this(null, null);
	}
	
	public Device(Node device)
	{
		this(null, device);
	}

	public Device(File descriptionFile) throws InvalidDescriptionException
	{
		this(null, null);
		loadDescription(descriptionFile);
	}

	/**
	 * @since 1.8.0
	 */
	public Device(InputStream input) throws InvalidDescriptionException
	{
		this(null, null);
		loadDescription(input);
	}

	
	public Device(String descriptionFileName) throws InvalidDescriptionException
	{
		this(new File(descriptionFileName));
	}

	////////////////////////////////////////////////
	// Mutex
	////////////////////////////////////////////////
	
	private Mutex mutex = new Mutex();
	
	public void lock()
	{
		mutex.lock();
	}
	
	public void unlock()
	{
		mutex.unlock();
	}
	
	////////////////////////////////////////////////
	//	NMPR
	////////////////////////////////////////////////
	
	public void setNMPRMode(boolean flag)
	{
		Node devNode = getDeviceNode();
		if (devNode == null)
			return;
		if (flag == true) {
			devNode.setNode(UPnP.INMPR03, UPnP.INMPR03_VERSION);
			devNode.removeNode(Device.URLBASE_NAME);
		}
		else {
			devNode.removeNode(UPnP.INMPR03);
		}
	}

	public boolean isNMPRMode()
	{
		Node devNode = getDeviceNode();
		if (devNode == null)
			return false;
		return (devNode.getNode(UPnP.INMPR03) != null) ? true : false;
	}
	
	////////////////////////////////////////////////
	//	Wireless
	////////////////////////////////////////////////
	
	private boolean wirelessMode;
	
	public void setWirelessMode(boolean flag)
	{
		wirelessMode = flag;
	}

	public boolean isWirelessMode()
	{
		return wirelessMode;
	}

	public int getSSDPAnnounceCount()
	{
		if (isNMPRMode() == true && isWirelessMode() == true)
			return UPnP.INMPR03_DISCOVERY_OVER_WIRELESS_COUNT;
		return 1;
	}

	////////////////////////////////////////////////
	//	Device UUID
	////////////////////////////////////////////////

	private String devUUID;
	
	private void setUUID(String uuid)
	{
		devUUID = uuid;
	}
	
	private String getUUID() 
	{
		return devUUID;
	}
	
	private void updateUDN()
	{
		setUDN("uuid:" + getUUID());	
	}
	
	////////////////////////////////////////////////
	//	Root Device
	////////////////////////////////////////////////
	
	public Device getRootDevice()
	{
		Node rootNode = getRootNode();
		if (rootNode == null)
			return null;
		Node devNode = rootNode.getNode(Device.ELEM_NAME);
		if (devNode == null)
			return null;
		return new Device(rootNode, devNode);
	}

	////////////////////////////////////////////////
	//	Parent Device
	////////////////////////////////////////////////
	
	// Thanks for Stefano Lenzi (07/24/04)

	/**
	 * 
	 * @return A Device that contain this object.
* Return null if this is a root device. * @author Stefano "Kismet" Lenzi */ public Device getParentDevice() { if(isRootDevice()) return null; Node devNode = getDeviceNode(); Node aux = null; // aux = devNode.getParentNode().getParentNode(); return new Device(aux); } /** * Add a Service to device without checking for duplicate or syntax error * * @param s Add Service s to the Device */ public void addService(Service s) { Node serviceListNode = getDeviceNode().getNode(ServiceList.ELEM_NAME); if (serviceListNode == null) { serviceListNode = new Node(ServiceList.ELEM_NAME); getDeviceNode().addNode(serviceListNode); } serviceListNode.addNode(s.getServiceNode()); } /** * Add a Device to device without checking for duplicate or syntax error. * This method set or reset the root node of the Device and itself
*
* Note: This method should be used to create a dynamic
* Device withtout writing any XML that describe the device
. * * @param d Add Device d to the Device * * @author Stefano "Kismet" Lenzi - [email protected] - 2005 * */ public void addDevice(Device d) { Node deviceListNode = getDeviceNode().getNode(DeviceList.ELEM_NAME); if (deviceListNode == null) { //deviceListNode = new Node(ServiceList.ELEM_NAME); twa wrong ELEM_NAME; deviceListNode = new Node(DeviceList.ELEM_NAME); getDeviceNode().addNode(deviceListNode); } deviceListNode.addNode(d.getDeviceNode()); d.setRootNode(null); if(getRootNode()==null){ Node root = new Node(RootDescription.ROOT_ELEMENT); root.setNameSpace("",RootDescription.ROOT_ELEMENT_NAMESPACE); Node spec = new Node(RootDescription.SPECVERSION_ELEMENT); Node maj =new Node(RootDescription.MAJOR_ELEMENT); maj.setValue("1"); Node min =new Node(RootDescription.MINOR_ELEMENT); min.setValue("0"); spec.addNode(maj); spec.addNode(min); root.addNode(spec); setRootNode(root); } } //////////////////////////////////////////////// // UserData //////////////////////////////////////////////// private DeviceData getDeviceData() { Node node = getDeviceNode(); DeviceData userData = (DeviceData)node.getUserData(); if (userData == null) { userData = new DeviceData(); node.setUserData(userData); userData.setNode(node); } return userData; } //////////////////////////////////////////////// // Description //////////////////////////////////////////////// private void setDescriptionFile(File file) { getDeviceData().setDescriptionFile(file); } public File getDescriptionFile() { return getDeviceData().getDescriptionFile(); } private void setDescriptionURI(String uri) { getDeviceData().setDescriptionURI(uri); } private String getDescriptionURI() { return getDeviceData().getDescriptionURI(); } private boolean isDescriptionURI(String uri) { String descriptionURI = getDescriptionURI(); if (uri == null || descriptionURI == null) return false; return descriptionURI.equals(uri); } public String getDescriptionFilePath() { File descriptionFile = getDescriptionFile(); if (descriptionFile == null) return ""; return descriptionFile.getAbsoluteFile().getParent(); } /** * @since 1.8.0 */ public boolean loadDescription(InputStream input) throws InvalidDescriptionException { try { Parser parser = UPnP.getXMLParser(); rootNode = parser.parse(input); if (rootNode == null) throw new InvalidDescriptionException(Description.NOROOT_EXCEPTION); deviceNode = rootNode.getNode(Device.ELEM_NAME); if (deviceNode == null) throw new InvalidDescriptionException(Description.NOROOTDEVICE_EXCEPTION); } catch (ParserException e) { throw new InvalidDescriptionException(e); } if (initializeLoadedDescription() == false) return false; setDescriptionFile(null); return true; } public boolean loadDescription(String descString) throws InvalidDescriptionException { try { Parser parser = UPnP.getXMLParser(); rootNode = parser.parse(descString); if (rootNode == null) throw new InvalidDescriptionException(Description.NOROOT_EXCEPTION); deviceNode = rootNode.getNode(Device.ELEM_NAME); if (deviceNode == null) throw new InvalidDescriptionException(Description.NOROOTDEVICE_EXCEPTION); } catch (ParserException e) { throw new InvalidDescriptionException(e); } if (initializeLoadedDescription() == false) return false; setDescriptionFile(null); return true; } public boolean loadDescription(File file) throws InvalidDescriptionException { try { Parser parser = UPnP.getXMLParser(); rootNode = parser.parse(file); if (rootNode == null) throw new InvalidDescriptionException(Description.NOROOT_EXCEPTION, file); deviceNode = rootNode.getNode(Device.ELEM_NAME); if (deviceNode == null) throw new InvalidDescriptionException(Description.NOROOTDEVICE_EXCEPTION, file); } catch (ParserException e) { throw new InvalidDescriptionException(e); } if (initializeLoadedDescription() == false) return false; setDescriptionFile(file); return true; } private boolean initializeLoadedDescription() { setDescriptionURI(DEFAULT_DESCRIPTION_URI); setLeaseTime(DEFAULT_LEASE_TIME); setHTTPPort(HTTP_DEFAULT_PORT); // Thanks for Oliver Newell (03/23/04) if (hasUDN() == false) updateUDN(); return true; } //////////////////////////////////////////////// // isDeviceNode //////////////////////////////////////////////// public static boolean isDeviceNode(Node node) { return Device.ELEM_NAME.equals(node.getName()); } //////////////////////////////////////////////// // Root Device //////////////////////////////////////////////// public boolean isRootDevice(){ return getRootNode().getNode("device").getNodeValue(UDN).equals(getUDN()); } //////////////////////////////////////////////// // Root Device //////////////////////////////////////////////// public void setSSDPPacket(SSDPPacket packet) { getDeviceData().setSSDPPacket(packet); } public SSDPPacket getSSDPPacket() { if (isRootDevice() == false) return null; return getDeviceData().getSSDPPacket(); } //////////////////////////////////////////////// // Location //////////////////////////////////////////////// public void setLocation(String value) { getDeviceData().setLocation(value); } public String getLocation() { SSDPPacket packet = getSSDPPacket(); if (packet != null) return packet.getLocation(); return getDeviceData().getLocation(); } //////////////////////////////////////////////// // LeaseTime //////////////////////////////////////////////// public void setLeaseTime(int value) { getDeviceData().setLeaseTime(value); Advertiser adv = getAdvertiser(); if (adv != null) { announce(); adv.restart("Cyber.device.advertiser["+getFriendlyName()+"]"); } } public int getLeaseTime() { SSDPPacket packet = getSSDPPacket(); if (packet != null) return packet.getLeaseTime(); return getDeviceData().getLeaseTime(); } //////////////////////////////////////////////// // TimeStamp //////////////////////////////////////////////// public long getTimeStamp() { SSDPPacket packet = getSSDPPacket(); if (packet != null) return packet.getTimeStamp(); return 0; } public long getElapsedTime() { return (System.currentTimeMillis() - getTimeStamp()) / 1000; } public boolean isExpired() { long elipsedTime = getElapsedTime(); long leaseTime = getLeaseTime() + UPnP.DEFAULT_EXPIRED_DEVICE_EXTRA_TIME; if (leaseTime < elipsedTime) return true; return false; } //////////////////////////////////////////////// // URL Base //////////////////////////////////////////////// private final static String URLBASE_NAME = "URLBase"; private void setURLBase(String value) { if (isRootDevice() == true) { Node node = getRootNode().getNode(URLBASE_NAME); if (node != null) { node.setValue(value); return; } node = new Node(URLBASE_NAME); node.setValue(value); int index = 1; if (getRootNode().hasNodes() == false) index = 1; getRootNode().insertNode(node, index); } } private void updateURLBase(String host) { String urlBase = HostInterface.getHostURL(host, getHTTPPort(), ""); setURLBase(urlBase); } public String getURLBase() { if (isRootDevice() == true) return getRootNode().getNodeValue(URLBASE_NAME); return ""; } //////////////////////////////////////////////// // deviceType //////////////////////////////////////////////// private final static String DEVICE_TYPE = "deviceType"; public void setDeviceType(String value) { getDeviceNode().setNode(DEVICE_TYPE, value); } public String getDeviceType() { return getDeviceNode().getNodeValue(DEVICE_TYPE); } public boolean isDeviceType(String value) { if (value == null) return false; return value.equals(getDeviceType()); } //////////////////////////////////////////////// // friendlyName //////////////////////////////////////////////// private final static String FRIENDLY_NAME = "friendlyName"; public void setFriendlyName(String value) { getDeviceNode().setNode(FRIENDLY_NAME, value); } public String getFriendlyName() { return getDeviceNode().getNodeValue(FRIENDLY_NAME); } //////////////////////////////////////////////// // manufacture //////////////////////////////////////////////// private final static String MANUFACTURE = "manufacturer"; public void setManufacture(String value) { getDeviceNode().setNode(MANUFACTURE, value); } public String getManufacture() { return getDeviceNode().getNodeValue(MANUFACTURE); } //////////////////////////////////////////////// // manufactureURL //////////////////////////////////////////////// private final static String MANUFACTURE_URL = "manufacturerURL"; public void setManufactureURL(String value) { getDeviceNode().setNode(MANUFACTURE_URL, value); } public String getManufactureURL() { return getDeviceNode().getNodeValue(MANUFACTURE_URL); } //////////////////////////////////////////////// // modelDescription //////////////////////////////////////////////// private final static String MODEL_DESCRIPTION = "modelDescription"; public void setModelDescription(String value) { getDeviceNode().setNode(MODEL_DESCRIPTION, value); } public String getModelDescription() { return getDeviceNode().getNodeValue(MODEL_DESCRIPTION); } //////////////////////////////////////////////// // modelName //////////////////////////////////////////////// private final static String MODEL_NAME = "modelName"; public void setModelName(String value) { getDeviceNode().setNode(MODEL_NAME, value); } public String getModelName() { return getDeviceNode().getNodeValue(MODEL_NAME); } //////////////////////////////////////////////// // modelNumber //////////////////////////////////////////////// private final static String MODEL_NUMBER = "modelNumber"; public void setModelNumber(String value) { getDeviceNode().setNode(MODEL_NUMBER, value); } public String getModelNumber() { return getDeviceNode().getNodeValue(MODEL_NUMBER); } //////////////////////////////////////////////// // modelURL //////////////////////////////////////////////// private final static String MODEL_URL = "modelURL"; public void setModelURL(String value) { getDeviceNode().setNode(MODEL_URL, value); } public String getModelURL() { return getDeviceNode().getNodeValue(MODEL_URL); } //////////////////////////////////////////////// // serialNumber //////////////////////////////////////////////// private final static String SERIAL_NUMBER = "serialNumber"; public void setSerialNumber(String value) { getDeviceNode().setNode(SERIAL_NUMBER, value); } public String getSerialNumber() { return getDeviceNode().getNodeValue(SERIAL_NUMBER); } //////////////////////////////////////////////// // UDN //////////////////////////////////////////////// private final static String UDN = "UDN"; public void setUDN(String value) { getDeviceNode().setNode(UDN, value); } public String getUDN() { return getDeviceNode().getNodeValue(UDN); } public boolean hasUDN() { String udn = getUDN(); if (udn == null || udn.length() <= 0) return false; return true; } //////////////////////////////////////////////// // UPC //////////////////////////////////////////////// private final static String UPC = "UPC"; public void setUPC(String value) { getDeviceNode().setNode(UPC, value); } public String getUPC() { return getDeviceNode().getNodeValue(UPC); } //////////////////////////////////////////////// // presentationURL //////////////////////////////////////////////// private final static String presentationURL = "presentationURL"; public void setPresentationURL(String value) { getDeviceNode().setNode(presentationURL, value); } public String getPresentationURL() { return getDeviceNode().getNodeValue(presentationURL); } //////////////////////////////////////////////// // deviceList //////////////////////////////////////////////// public DeviceList getDeviceList() { DeviceList devList = new DeviceList(); Node devListNode = getDeviceNode().getNode(DeviceList.ELEM_NAME); if (devListNode == null) return devList; int nNode = devListNode.getNNodes(); for (int n=0; n© 2015 - 2024 Weber Informatics LLC | Privacy Policy