Committed the initial version (R3) of the UPnP Base Driver bundle (FELIX-52).
It requires org.osgi.core, org.osgi.compendium, org.apache.felix.upnp.extra and cyberlink-patched-release.
I've installed the cyberlink-1.7-patched-release.jar on my local repository.
In order to install the library you can use the command :
mvn install:install-file -DgroupId=org.cybergarage -DartifactId=cyberlink-patched-release /
-Dversion=1.7 -Dpackaging=jar -Dfile=<basedir>\trunk\org.apache.felix.upnp.basedriver\src\main\resources\lib\cyberlink-1.7-patched-release.jar
I've added the source code in the resources dir (cyberlink-1.7-patched-debug.jar)

The basedriver doesn't compile without it, so I've commented the module related to it in the trunk/pom.xml
I need help to understand how to use an external repository.

git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@391447 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/org.apache.felix.upnp.basedriver/pom.xml b/org.apache.felix.upnp.basedriver/pom.xml
new file mode 100644
index 0000000..9fcad51
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/pom.xml
@@ -0,0 +1,73 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

+  <parent>

+    <groupId>org.apache.felix</groupId>

+    <artifactId>felix</artifactId>

+    <version>0.8.0-SNAPSHOT</version>

+  </parent>

+  <modelVersion>4.0.0</modelVersion>

+  <packaging>osgi-bundle</packaging>

+  <groupId>org.apache.felix</groupId>

+  <name>Apache Felix UPnP Base Driver</name>

+  <artifactId>org.apache.felix.upnp.basedriver</artifactId>

+  <version>0.1.0-SNAPSHOT</version>

+  <!-- <url>http://maven.apache.org</url> -->

+  <dependencies>

+    <dependency>

+      <groupId>org.osgi</groupId>

+      <artifactId>org.osgi.core</artifactId>

+      <version>4.0</version>

+      <scope>provided</scope>

+    </dependency>

+    <dependency>

+      <groupId>org.osgi</groupId>

+      <artifactId>org.osgi.compendium</artifactId>

+      <version>4.0</version>

+      <scope>provided</scope>

+    </dependency>

+    <dependency>

+      <groupId>org.apache.felix</groupId>

+      <artifactId>org.apache.felix.upnp.extra</artifactId>

+      <version>1.0-SNAPSHOT</version>

+      <scope>provided</scope>

+    </dependency>

+    <dependency>

+      <groupId>org.cybergarage</groupId>

+      <artifactId>cyberlink-patched-release</artifactId>

+      <version>1.7</version>

+      <scope>provided</scope>

+    </dependency>

+  </dependencies>

+  <build>

+    <plugins>

+      <plugin>

+        <groupId>org.apache.felix.plugins</groupId>

+        <artifactId>maven-osgi-plugin</artifactId>

+        <!-- <version>${pom.version}</version> -->

+        <extensions>true</extensions>

+        <configuration>

+          <osgiManifest>

+            <bundleName>UPnPBaseDriver</bundleName>

+            <bundleVendor>Apache Software Foundation</bundleVendor>

+            <bundleVersion>1.0.0</bundleVersion>

+            <bundleDescription>

+               	A Bundle implementation of the UPnP Service Specification R4 (not yet)

+            </bundleDescription>

+            <bundleSymbolicName>org.apache.felix.upnp.basedriver</bundleSymbolicName>

+		<!-- <bundleClassPath>.,lib/cyberlink-1.7-patched-release.jar</bundleClassPath> -->

+		<bundleActivator>org.apache.felix.upnp.basedriver.Activator</bundleActivator>

+            <importPackage>

+			org.osgi.framework;specification-version=1.3,org.osgi.service.device;specification-version=1.1,org.osgi.service.upnp;specification-version=1.1,org.osgi.service.log;specification-version=1.3,org.apache.felix.upnp.extra.util;specification-version=1.0,org.apache.felix.upnp.extra.controller;specification-version=1.0

+            </importPackage>

+          </osgiManifest>

+          <manifestFile>src/main/resources/META-INF/Manifest.mf</manifestFile>

+        </configuration>

+      </plugin>

+    </plugins>

+    <resources>

+      <resource>

+	  <directory>src/main/resources</directory>

+      </resource>

+    </resources>

+  </build>

+</project>

diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/Activator.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/Activator.java
new file mode 100644
index 0000000..3129b97
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/Activator.java
@@ -0,0 +1,136 @@
+/*
+ *   Copyright 2006 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+
+package org.apache.felix.upnp.basedriver;
+
+import org.apache.felix.upnp.extra.controller.DevicesInfo;
+import org.apache.felix.upnp.extra.controller.DriverController;
+
+import org.cybergarage.upnp.UPnP;
+import org.cybergarage.xml.parser.JaxpParser;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+import org.apache.felix.upnp.basedriver.controller.impl.DriverControllerImpl;
+import org.apache.felix.upnp.basedriver.export.RootDeviceExportingQueue;
+import org.apache.felix.upnp.basedriver.export.RootDeviceListener;
+import org.apache.felix.upnp.basedriver.export.ThreadExporter;
+import org.apache.felix.upnp.basedriver.importer.core.MyCtrlPoint;
+import org.apache.felix.upnp.basedriver.importer.core.event.structs.Monitor;
+import org.apache.felix.upnp.basedriver.importer.core.event.structs.NotifierQueue;
+import org.apache.felix.upnp.basedriver.importer.core.event.structs.SubscriptionQueue;
+import org.apache.felix.upnp.basedriver.importer.core.event.thread.Notifier;
+import org.apache.felix.upnp.basedriver.importer.core.event.thread.SubScriber;
+import org.apache.felix.upnp.basedriver.tool.Logger;
+import org.apache.felix.upnp.basedriver.tool.Util;
+
+/**
+ * @author Stefano "Kismet" Lenzi, 
+ * @author Francesco Furfari
+ * 
+ */
+public class Activator implements BundleActivator {
+
+    public static BundleContext bc;
+    public static Logger logger;        
+	private RootDeviceExportingQueue queue;
+	private RootDeviceListener producerDeviceToExport;
+	private ThreadExporter consumerDeviceToExport;
+
+	private MyCtrlPoint ctrl;
+	private SubScriber subScriber;
+	private Notifier notifier;
+	private NotifierQueue notifierQueue;
+	private SubscriptionQueue subQueue;
+	private Monitor monitor;
+    private DriverControllerImpl drvController;
+    private ServiceRegistration drvControllerRegistrar;	
+	
+	/**
+	 * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
+	 */
+	public void start(BundleContext context) throws Exception {
+		//Setting basic variabile used by everyone
+        
+ 		Activator.bc = context;				
+		
+	    String levelStr = (String) Util.getPropertyDefault(context,"domoware.upnpbase.log","2");	    
+		Activator.logger = new Logger(levelStr);
+	    String cyberLog = (String) Util.getPropertyDefault(context,"domoware.upnpbase.cyberlink.log","false");
+	    Activator.logger.setCyberDebug(cyberLog);
+
+        UPnP.setXMLParser(new JaxpParser());
+		
+		//Setting up Base Driver Exporter
+		this.queue = new RootDeviceExportingQueue();
+		this.producerDeviceToExport = new RootDeviceListener(queue);
+		producerDeviceToExport.activate();
+		consumerDeviceToExport = new ThreadExporter(queue);
+		new Thread(consumerDeviceToExport, "Exporter").start();
+
+		//Setting up Base Driver Importer
+		this.notifierQueue = new NotifierQueue();
+		this.subQueue = new SubscriptionQueue();
+		ctrl = new MyCtrlPoint(context, subQueue, notifierQueue);
+		
+		//Enable CyberLink re-new for Event
+		ctrl.setNMPRMode(true);
+			
+		this.monitor=new Monitor();
+		this.notifier = new Notifier(notifierQueue,monitor);
+		this.subScriber = new SubScriber(ctrl, subQueue,monitor);
+		
+		ctrl.start();
+		subScriber.start();
+		notifier.start();
+        
+        doControllerRegistration();
+        
+	}
+
+	private void doControllerRegistration() {
+        drvController = new DriverControllerImpl(ctrl);
+        drvControllerRegistrar = bc.registerService(
+            new String[]{
+            		DriverController.class.getName(),
+            		DevicesInfo.class.getName()},
+            drvController,
+            null
+        );       
+    }
+
+    /**
+	 * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
+	 */
+	public void stop(BundleContext context) throws Exception {
+        
+        drvControllerRegistrar.unregister();
+        
+		//Setting up Base Driver Exporter
+		consumerDeviceToExport.end();
+		consumerDeviceToExport.cleanUp();
+		producerDeviceToExport.deactive();
+
+		//Setting up Base Driver Importer
+		ctrl.stop();
+		Activator.logger.close();
+		Activator.logger=null;
+		Activator.bc = null;
+	}
+}
\ No newline at end of file
diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/controller/impl/DriverControllerImpl.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/controller/impl/DriverControllerImpl.java
new file mode 100644
index 0000000..49719c6
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/controller/impl/DriverControllerImpl.java
@@ -0,0 +1,126 @@
+/*

+ *   Copyright 2006 The Apache Software Foundation

+ *

+ *   Licensed under the Apache License, Version 2.0 (the "License");

+ *   you may not use this file except in compliance with the License.

+ *   You may obtain a copy of the License at

+ *

+ *       http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *   Unless required by applicable law or agreed to in writing, software

+ *   distributed under the License is distributed on an "AS IS" BASIS,

+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *   See the License for the specific language governing permissions and

+ *   limitations under the License.

+ *

+ */

+

+

+package org.apache.felix.upnp.basedriver.controller.impl;

+

+import org.apache.felix.upnp.extra.controller.DevicesInfo;

+import org.apache.felix.upnp.extra.controller.DriverController;

+

+import org.cybergarage.upnp.Device;

+import org.cybergarage.upnp.Service;

+

+import org.apache.felix.upnp.basedriver.Activator;

+import org.apache.felix.upnp.basedriver.importer.core.MyCtrlPoint;

+import org.apache.felix.upnp.basedriver.tool.Logger;

+

+/**

+ * @author Stefano "Kismet" Lenzi 

+ * @author Francesco Furfari 

+ *

+ */

+public class DriverControllerImpl implements DriverController, DevicesInfo{

+    private MyCtrlPoint myCtrl;

+    private Logger logger = Activator.logger;

+    

+    public DriverControllerImpl(MyCtrlPoint myCtrl){

+        this.myCtrl = myCtrl;

+        

+    }

+    

+    public void setLogLevel(int n) {

+        logger.setLogLevel(n);

+    }

+

+    public int getLogLevel() {

+        return logger.getLogLevel();

+    }

+

+    public void setCyberDebug(boolean b) {

+        logger.setCyberDebug(b);

+    }

+

+    public boolean getCyberDebug() {

+        return logger.getCyberDebug();

+    }

+

+    public String getLocationURL(String udn) {

+        if (udn == null || udn.equals(""))  throw new IllegalArgumentException("Invalid udn paramenter");

+        Device device = myCtrl.getDevice(udn);

+        if (device == null) logger.WARNING("getLocationURL():: No device data available for UDN:"+udn);

+        return myCtrl.getDevice(udn).getLocation();

+    }

+    

+    public String getSCPDURL(String udn, String serviceId) {

+        if (udn == null || udn.equals("") )  throw new IllegalArgumentException("Invalid udn paramenter");

+        if (serviceId == null || serviceId.equals("") )  throw new IllegalArgumentException("Invalid serviceId paramenter");

+        Device device= myCtrl.getDevice(udn);

+        if (device == null) {

+            logger.WARNING("getSCPDURL():: No device data available for UDN: "+udn);

+            return null;

+        }

+        Service service = device.getService(serviceId);

+        if (service == null) {

+            logger.WARNING("getSCPDURL():: No service data available for serviceId:"+serviceId + " of UDN " + udn);

+            return null;

+        }

+        String scpd = service.getSCPDURL().trim();

+        return resolveRelativeLink(device,scpd);

+    }

+    

+    public String resolveRelativeUrl(String udn, String link) {

+        if (udn == null || udn.equals(""))  throw new IllegalArgumentException("Invalid udn paramenter");

+        Device device = myCtrl.getDevice(udn);

+        return resolveRelativeLink(device,link);        

+    }

+

+    private String resolveRelativeLink(Device device, String link) {

+        if ( device == null || link == null) return null;

+        if (link.startsWith("http:"))

+            return link;

+        else {

+            String hostname = "";

+            String location = "";

+            String urlBase = device.getURLBase().trim();

+            //TODO Check if is more important URLBase or location

+            if (urlBase.equals("")){

+                location = device.getLocation().trim();

+                int endHostnameIdx = location.indexOf("/",7);

+                if (endHostnameIdx!=-1)

+                    hostname=location.substring(0,endHostnameIdx);

+                else

+                    hostname = location;

+                if (link.startsWith("/")){

+                    return hostname+link;

+                }else{

+                	//TODO Check for link start with .. or /

+                    return location +link;

+                }

+            }

+            else {

+               return urlBase+link;

+            }             

+        }

+   }

+

+    public void search(String target) {

+        myCtrl.search(target);       

+    }

+

+

+

+}

diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/export/ActionDispatcher.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/export/ActionDispatcher.java
new file mode 100644
index 0000000..0417997
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/export/ActionDispatcher.java
@@ -0,0 +1,46 @@
+/*

+ *   Copyright 2006 The Apache Software Foundation

+ *

+ *   Licensed under the Apache License, Version 2.0 (the "License");

+ *   you may not use this file except in compliance with the License.

+ *   You may obtain a copy of the License at

+ *

+ *       http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *   Unless required by applicable law or agreed to in writing, software

+ *   distributed under the License is distributed on an "AS IS" BASIS,

+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *   See the License for the specific language governing permissions and

+ *   limitations under the License.

+ *

+ */

+

+package org.apache.felix.upnp.basedriver.export;

+

+import org.cybergarage.upnp.Action;

+import org.cybergarage.upnp.control.ActionListener;

+

+import org.osgi.framework.ServiceReference;

+

+

+/**

+ * @author Stefano "Kismet" Lenzi 

+ * 

+ */

+public class ActionDispatcher implements ActionListener{

+    /**

+     * 

+     */

+    public ActionDispatcher(ServiceReference sr) {

+        super();

+    }

+

+    /**

+     * @see org.cybergarage.upnp.control.ActionListener#actionControlReceived(org.cybergarage.upnp.Action)

+     */

+    public boolean actionControlReceived(Action action) {

+        // TODO Auto-generated method stub

+        return false;

+    }

+

+}

diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/export/BuildDevice.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/export/BuildDevice.java
new file mode 100644
index 0000000..64864eb
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/export/BuildDevice.java
@@ -0,0 +1,267 @@
+/*
+ *   Copyright 2006 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+
+package org.apache.felix.upnp.basedriver.export;
+
+
+import org.cybergarage.upnp.Action;
+import org.cybergarage.upnp.AllowedValueList;
+import org.cybergarage.upnp.AllowedValueRange;
+import org.cybergarage.upnp.Argument;
+import org.cybergarage.upnp.ArgumentList;
+import org.cybergarage.upnp.Device;
+import org.cybergarage.upnp.Service;
+import org.cybergarage.upnp.StateVariable;
+import org.cybergarage.upnp.xml.DeviceData;
+import org.cybergarage.xml.Node;
+
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.upnp.UPnPAction;
+import org.osgi.service.upnp.UPnPDevice;
+import org.osgi.service.upnp.UPnPService;
+import org.osgi.service.upnp.UPnPStateVariable;
+
+import org.ungoverned.device.RootDescription;
+
+import org.apache.felix.upnp.basedriver.Activator;
+import org.apache.felix.upnp.extra.util.Converter;
+/**
+ * 
+ * @author Stefano "Kismet" Lenzi 
+ * 
+ */
+public class BuildDevice {
+	
+	private static Node buildRootNode(){
+		Node root = new Node(RootDescription.ROOT_ELEMENT);
+		root.setAttribute("xmlns",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);
+		return root;
+	}
+	
+	private static Device buildRootDeviceNode(Node root,ServiceReference sr){		
+		Node dev = new Node(Device.ELEM_NAME);
+		root.addNode(dev);
+		DeviceData dd = new DeviceData();
+		dd.setDescriptionURI("/gen-desc.xml");
+		dev.setUserData(dd);
+		Device devUPnP = new Device(root,dev);
+
+
+		Object aux = sr.getProperty(UPnPDevice.TYPE);
+		if(aux==null){
+			devUPnP.setDeviceType(null);		
+		}else if(aux instanceof String){
+			devUPnP.setDeviceType((String) aux);
+		}else if(aux instanceof String[]){
+			//The property key UPnP.device.type should be a String
+			String[] v = (String[]) aux;
+			int maxindex=0;
+			int max=Integer.parseInt(v[0].substring(v[0].lastIndexOf(":")+1));
+			int tmp;
+			for (int i = 1; i < v.length; i++) {
+				tmp=Integer.parseInt(v[i].substring(v[i].lastIndexOf(":")+1));				
+				if(max<tmp){
+					max=tmp;
+					maxindex=i;
+				}				
+			}
+			devUPnP.setDeviceType(v[maxindex]);
+		}				
+		
+		devUPnP.setFriendlyName((String) sr.getProperty(UPnPDevice.FRIENDLY_NAME));
+		devUPnP.setManufacture((String) sr.getProperty(UPnPDevice.MANUFACTURER));
+		devUPnP.setManufactureURL((String) sr.getProperty(UPnPDevice.MANUFACTURER_URL));
+		devUPnP.setModelDescription((String) sr.getProperty(UPnPDevice.MODEL_DESCRIPTION));
+		devUPnP.setModelName((String) sr.getProperty(UPnPDevice.MODEL_NAME));
+		devUPnP.setUDN((String) sr.getProperty(UPnPDevice.UDN));
+		devUPnP.setPresentationURL((String) sr.getProperty(UPnPDevice.PRESENTATION_URL));
+		devUPnP.setUPC((String) sr.getProperty(UPnPDevice.UPC));
+		devUPnP.setModelNumber((String) sr.getProperty(UPnPDevice.MODEL_NUMBER));
+		devUPnP.setModelURL((String) sr.getProperty(UPnPDevice.MODEL_URL));
+		devUPnP.setSerialNumber((String) sr.getProperty(UPnPDevice.SERIAL_NUMBER));
+		devUPnP.setLocation("/gen-desc.xml");		
+
+		addServices("",devUPnP,sr);
+		addDevices("",devUPnP,sr);
+		
+		return devUPnP;
+	}
+	
+	private static void addDevices(String id,Device devUPnP, ServiceReference sr) {
+
+		String[] udns=(String[]) sr.getProperty(UPnPDevice.CHILDREN_UDN);
+		if(udns==null) {
+			return;
+		}
+		for (int i = 0; i < udns.length; i++) {
+			try {
+				ServiceReference[] aux = Activator.bc.getServiceReferences(
+						UPnPDevice.class.getName(),"("+UPnPDevice.UDN+"="+udns[i]+")"
+					);
+				if(aux==null || aux.length == 0)
+					continue;
+				//id=+"/device/"+i;						// twa: wrong in recursion
+				//buildDevice(id,devUPnP,aux[0]);		// twa: wrong in recursion
+				String localId = new StringBuffer(id).append("/device/").append(i).toString();		
+				buildDevice(localId,devUPnP,aux[0]); 	// twa: better
+			} catch (InvalidSyntaxException ignored) {}						
+		}		
+	}
+
+	private static void buildDevice(String id,Device parent, ServiceReference sr) {
+		Node dev = new Node(Device.ELEM_NAME);
+		DeviceData dd = new DeviceData();
+		dd.setDescriptionURI(id+"/gen-desc.xml");
+		dev.setUserData(dd);
+		
+		Device devUPnP = new Device(dev);
+		
+		devUPnP.setFriendlyName((String) sr.getProperty(UPnPDevice.FRIENDLY_NAME));
+		devUPnP.setManufacture((String) sr.getProperty(UPnPDevice.MANUFACTURER));
+		devUPnP.setManufactureURL((String) sr.getProperty(UPnPDevice.MANUFACTURER_URL));
+		devUPnP.setModelDescription((String) sr.getProperty(UPnPDevice.MODEL_DESCRIPTION));
+		devUPnP.setModelName((String) sr.getProperty(UPnPDevice.MODEL_NAME));
+		devUPnP.setUDN((String) sr.getProperty(UPnPDevice.UDN));
+		devUPnP.setPresentationURL((String) sr.getProperty(UPnPDevice.PRESENTATION_URL));
+		devUPnP.setUPC((String) sr.getProperty(UPnPDevice.UPC));
+		devUPnP.setModelNumber((String) sr.getProperty(UPnPDevice.MODEL_NUMBER));
+		devUPnP.setModelURL((String) sr.getProperty(UPnPDevice.MODEL_URL));
+		devUPnP.setSerialNumber((String) sr.getProperty(UPnPDevice.SERIAL_NUMBER));
+		devUPnP.setLocation(id+"/gen-desc.xml");		
+
+		addServices(id,devUPnP,sr);
+		addDevices(id,devUPnP,sr);
+
+		parent.addDevice(devUPnP); //		twa: essential!!!!!!!
+	}
+	
+	/**
+	* Method used to create a new Service in CyberLink world without creating the XML
+	*
+	* @param id ServiceId
+	* @param devUPnP the CyberLink device that where the new Service will be created
+	* @param sr ServiceReference to OSGi Device that used as source of the information
+	*              for the creation of the device
+	*/
+	private static void addServices(String id,Device devUPnP, ServiceReference sr) {
+		UPnPDevice devOSGi = (UPnPDevice) Activator.bc.getService(sr);
+
+		if( devOSGi == null) {	//added by twa to prevent a null pointer exception
+			Activator.logger.WARNING("UPnP Device taht cotains serviceId="
+					+id+" is deregistered from the framework while is exported");
+			return;
+		}
+
+		UPnPService[] services =  devOSGi.getServices();
+		if(services==null || services.length==0)
+			return;
+		
+		
+		
+		for (int i = 0; i < services.length; i++) {
+			Service ser = new Service();
+			devUPnP.addService(ser);
+			ser.setServiceType(services[i].getType() );
+			ser.setServiceID(services[i].getId());
+			ser.setSCPDURL(id+"/service/"+i+"/gen-desc.xml");
+			ser.setDescriptionURL(id+"/service/"+i+"/gen-desc.xml");
+			ser.setControlURL(id+"/service/"+i+"/ctrl");
+			ser.setEventSubURL(id+"/service/"+i+"/event");
+			
+			UPnPStateVariable[] vars = services[i].getStateVariables();
+			for (int j = 0; j < vars.length; j++) {
+				StateVariable var = new StateVariable();
+				var.setDataType(vars[j].getUPnPDataType());
+				var.setName(vars[j].getName());
+				var.setSendEvents(vars[j].sendsEvents());
+				String[] values = vars[j].getAllowedValues();
+				if(values!=null){
+					AllowedValueList avl = new AllowedValueList(values);
+					var.setAllowedValueList(avl);
+				}else if(vars[j].getMaximum()!= null){
+					AllowedValueRange avr = new AllowedValueRange(
+							vars[j].getMaximum(),
+							vars[j].getMinimum(),
+							vars[j].getStep()
+						);
+					var.setAllowedValueRange(avr);
+				}
+				if(vars[j].getDefaultValue()!=null)
+					try {
+						var.setDefaultValue(Converter.toString(
+								vars[j].getDefaultValue(),vars[j].getUPnPDataType()
+							));
+					} catch (Exception ignored) {
+					}
+				ser.addStateVariable(var);				
+			}
+			
+			UPnPAction[] actions = services[i].getActions();
+			for (int j = 0; j < actions.length; j++) {
+				Action act = new Action(ser.getServiceNode());
+				act.setName(actions[j].getName());
+				ArgumentList al = new ArgumentList();
+				
+				String[] names=actions[j].getInputArgumentNames();				
+				if(names!=null){
+					for (int k = 0; k < names.length; k++) {
+						Argument a = new Argument();
+						a.setDirection(Argument.IN);
+						a.setName(names[k]);
+						a.setRelatedStateVariableName(
+								actions[j].getStateVariable(names[k]).getName()
+						);						
+						al.add(a);						
+					}
+				}
+				names=actions[j].getOutputArgumentNames();
+				if(names!=null){
+					for (int k = 0; k < names.length; k++) {
+						Argument a = new Argument();
+						a.setDirection(Argument.OUT);
+						a.setName(names[k]);
+						a.setRelatedStateVariableName(
+								actions[j].getStateVariable(names[k]).getName()
+						);						
+						al.add(a);						
+					}
+				}
+				act.setArgumentList(al);
+				ser.addAction(act);
+			}
+			
+			Activator.bc.ungetService(sr);
+		}
+		
+		
+	}
+
+	public static Device createCyberLinkDevice(ServiceReference sr){
+		Node root = buildRootNode();
+		Device devUPnP = buildRootDeviceNode(root,sr);		
+		return devUPnP;
+	}
+}
diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/export/DeviceNode.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/export/DeviceNode.java
new file mode 100644
index 0000000..a2c1d0c
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/export/DeviceNode.java
@@ -0,0 +1,183 @@
+/*

+ *   Copyright 2006 The Apache Software Foundation

+ *

+ *   Licensed under the Apache License, Version 2.0 (the "License");

+ *   you may not use this file except in compliance with the License.

+ *   You may obtain a copy of the License at

+ *

+ *       http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *   Unless required by applicable law or agreed to in writing, software

+ *   distributed under the License is distributed on an "AS IS" BASIS,

+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *   See the License for the specific language governing permissions and

+ *   limitations under the License.

+ *

+ */

+

+package org.apache.felix.upnp.basedriver.export;

+import java.util.ArrayList;

+import java.util.Collection;

+import java.util.Iterator;

+import java.util.Vector;

+

+import org.osgi.framework.BundleContext;

+import org.osgi.framework.ServiceReference;

+import org.osgi.service.upnp.UPnPDevice;

+

+/**

+ * @author Stefano "Kismet" Lenzi 

+ * @author Francesco "Sygent" Furfari 

+ *  

+ */

+public class DeviceNode {

+	

+	private ServiceReference sr;

+	private boolean isRootNode;

+	private String udn ;

+	private boolean hasChild;

+	private int numberOfSons;

+	private ArrayList children;

+	private DeviceNode parent;

+	

+	public DeviceNode(ServiceReference sr){

+		//PRE: argument is always UPnPDevice service reference

+		if (sr == null) 

+			throw new IllegalArgumentException("null is not a valid arg in DeviceNode constructor");

+		this.sr = sr;

+		udn = (String) sr.getProperty(UPnPDevice.UDN);

+		parent=null;

+		isRootNode = (sr.getProperty(UPnPDevice.PARENT_UDN) == null);

+		String[] sons = ((String[]) sr.getProperty(UPnPDevice.CHILDREN_UDN));

+		hasChild = (sons != null);

+		if (hasChild) {

+			children = new ArrayList();

+			numberOfSons = sons.length;

+		}

+	}

+	

+	public ServiceReference getReference(){

+		return sr;

+	}

+	public UPnPDevice getDevice(BundleContext ctx){

+		return (UPnPDevice)ctx.getService(sr);

+	}

+	

+	public void attach(DeviceNode node){

+		if (node == null) 

+			throw new IllegalArgumentException("null is not a valid arg in DeviceNode.attach() method");

+		node.parent = this;

+		children.add(node);

+	}

+	

+	public DeviceNode dethatch(String name){

+		DeviceNode dn = this.search(name);

+		if(dn==null) 

+			return null;

+		

+		if(dn.parent!=null){

+			Iterator list = dn.parent.children.iterator();

+			while (list.hasNext()) {

+				DeviceNode x = (DeviceNode) list.next();

+				if(x.udn.equals(name)){

+					list.remove();

+					break;

+				}

+			}

+		}

+		dn.parent=null;

+		return dn;

+	}

+	

+	public Collection getAllChildren(){

+		if((this.children==null)||(this.children.size()==0)) 

+			return null;

+		

+		Vector v = new Vector(this.children);

+		Iterator list = this.children.iterator();

+		while (list.hasNext()) {

+			DeviceNode x = (DeviceNode) list.next();

+			Collection c = x.getAllChildren();

+			if(c==null) continue;

+			v.addAll(c);

+		}

+		return v;

+	}

+

+	public Collection getChildren(){

+		if((this.children==null)||(this.children.size()==0)) 

+			return null;

+		return this.children;

+	}	

+	

+	/**

+	 * @param name <code>String</code> that contain the UDN to look for

+	 * @return return a <code>DeviceNode</code> that have the UDN equals to name and <br>

+	 * 		if there is any <code>DeviceNode</code> with the proper UDN value return <code>null</code>

+	 */

+	public DeviceNode search(String name){

+		if (name == null) 

+			throw new IllegalArgumentException("null is not a valid arg in DeviceNode.search() method");

+		if (name.equals(udn))

+			return this;

+		else if (hasChild){

+			Iterator list = children.iterator();

+			while (list.hasNext()){

+				DeviceNode child = (DeviceNode)list.next();

+				DeviceNode node = child.search(name);

+				if (node != null) return node;				

+			}

+		}

+		return null;

+	}

+	

+	/**

+	 * 

+	 * @param udn

+	 * @return <code>true</code> if and only if this <code>DeviceNode</code>

+	 * 		contains a DeviceNode with UDN equals to passed argument or if

+	 * 		its USN is equal to passed argument

+	 */

+	public boolean contains(String udn){

+		return this.search(udn)!=null;

+	}

+	

+	public boolean isComplete(){

+		if (! hasChild) return true;

+		if (numberOfSons != children.size())return false;

+		Iterator list = children.iterator();

+		while (list.hasNext()){

+			DeviceNode child = (DeviceNode)list.next();

+			if (! child.isComplete()) return false;

+		}

+		return true;

+	}

+	

+	public DeviceNode isAttachable(DeviceNode node){

+		if (node == null) 

+			throw new IllegalArgumentException("null is not a valid arg in DeviceNode.isAttachable() method");

+		String parentUDN=(String) node.getReference().getProperty(UPnPDevice.PARENT_UDN);

+		if(parentUDN==null) return null;

+		return search(parentUDN);		

+	}

+		

+	public boolean isRoot(){

+		return isRootNode;		

+	}

+	

+	public boolean equals(String udn){

+		return this.udn.equals(udn);

+	}

+	

+	public String toString(){

+		return udn;

+	}

+

+	/**

+	 * @return true if and only 

+	 * 		if the Device doesn't have embedded Device

+	 */

+	public boolean isLeaf() {

+		return !hasChild;

+	}		

+}

diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/export/ExporterUPnPEventListener.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/export/ExporterUPnPEventListener.java
new file mode 100644
index 0000000..b99cb17
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/export/ExporterUPnPEventListener.java
@@ -0,0 +1,69 @@
+/*
+ *   Copyright 2006 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+
+package org.apache.felix.upnp.basedriver.export;
+
+
+
+import java.util.Dictionary;
+import java.util.Enumeration;
+
+import org.cybergarage.upnp.Device;
+import org.cybergarage.upnp.Service;
+import org.cybergarage.upnp.StateVariable;
+
+import org.osgi.service.upnp.UPnPEventListener;
+
+import org.apache.felix.upnp.extra.util.Converter;
+
+/**
+ * @author Stefano "Kismet" Lenzi 
+ * 
+ */
+public class ExporterUPnPEventListener implements UPnPEventListener {
+
+	private Device d;
+	
+	public ExporterUPnPEventListener(Device d){
+		this.d=d;
+	}
+		
+	/**
+	 * @see org.osgi.service.upnp.UPnPEventListener#notifyUPnPEvent(java.lang.String, java.lang.String, java.util.Dictionary)
+	 */
+	public void notifyUPnPEvent(String deviceId, String serviceId,Dictionary events) {
+		Device dAux = null;
+		if(d.getUDN().equals(deviceId)){
+			dAux=d;
+		}else{
+			dAux= d.getDevice(deviceId);
+		}
+		Service s = dAux.getService(serviceId);
+		// fix 2/9/2004 francesco 
+		Enumeration e = events.keys();
+		StateVariable sv;
+		while (e.hasMoreElements()) {
+			String name = (String) e.nextElement();
+			sv=s.getStateVariable(name);
+			//sv.setValue((String) events.get(name));
+			try {
+				sv.setValue(Converter.toString(events.get(name),sv.getDataType()));
+			} catch (Exception ignored) {
+			}
+		}
+	}
+}
diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/export/GeneralActionListener.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/export/GeneralActionListener.java
new file mode 100644
index 0000000..2c90817
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/export/GeneralActionListener.java
@@ -0,0 +1,158 @@
+/*
+ *   Copyright 2006 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+
+package org.apache.felix.upnp.basedriver.export;
+
+
+import java.util.Dictionary;
+import java.util.Properties;
+
+import org.cybergarage.upnp.Action;
+import org.cybergarage.upnp.Argument;
+import org.cybergarage.upnp.ArgumentList;
+import org.cybergarage.upnp.UPnPStatus;
+import org.cybergarage.upnp.control.ActionListener;
+
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.upnp.UPnPAction;
+import org.osgi.service.upnp.UPnPDevice;
+import org.osgi.service.upnp.UPnPService;
+
+import org.apache.felix.upnp.basedriver.Activator;
+import org.apache.felix.upnp.extra.util.Converter;
+import org.apache.felix.upnp.extra.util.UPnPException;
+
+/**
+ * @author Stefano "Kismet" Lenzi 
+ * 
+ *
+ */
+public class GeneralActionListener implements ServiceListener,ActionListener {
+
+	private ServiceReference dev;
+	private String id;
+	private boolean open;
+		
+	/**
+	 * @param osgiServ
+	 */
+	public GeneralActionListener(ServiceReference sr, String serviceId) {
+		try {
+			Activator.bc.addServiceListener(this,
+				"("+Constants.SERVICE_ID+"="+sr.getProperty(Constants.SERVICE_ID)+")");
+		} catch (InvalidSyntaxException ingnored) {}
+		this.dev=sr;
+		this.id=serviceId;
+		this.open=true;
+	}
+
+	/**
+	 * @see org.cybergarage.upnp.control.ActionListener#actionControlReceived(org.cybergarage.upnp.Action)
+	 */
+	public synchronized boolean actionControlReceived(Action upnpAct) {
+		if(!open) return false;			
+		UPnPService osgiServ=null;
+		try{
+			osgiServ=((UPnPDevice) Activator.bc.getService(dev)).getService(id);	
+		}catch(Exception ignored){}
+		
+		if(osgiServ==null)
+			return exiting(false);
+		
+		UPnPAction osgiAct = osgiServ.getAction(upnpAct.getName());
+		Properties inArgs = null;
+		ArgumentList al = upnpAct.getArgumentList();
+		String[] inArg = osgiAct.getInputArgumentNames();
+		boolean invalidAction=false;
+		if(inArg!=null){
+			inArgs = new Properties();
+			Argument arg;
+			for (int j = 0; j < inArg.length; j++) {
+				arg=al.getArgument(inArg[j]);
+				try {
+					inArgs.put(
+							inArg[j],
+							Converter.parseString(
+									arg.getValue(),
+									arg.getRelatedStateVariable().getDataType()
+									/*osgiServ.getStateVariable(arg.getRelatedStateVariableName()).getUPnPDataType()*/
+							)
+					);
+				} catch (Exception e) {
+					invalidAction=true;
+					break;
+				}
+			}
+		}
+		Dictionary outArgs=null;
+		try {
+			outArgs=osgiAct.invoke(inArgs);
+		} catch (UPnPException e) {
+			//TODO Activator.logger.log()
+			upnpAct.setStatus(e.getErrorCode(),e.getErrorDescription());
+			invalidAction=true;
+		} catch (Exception e){
+			//TODO Activator.logger.log()
+			upnpAct.setStatus(UPnPStatus.ACTION_FAILED);
+			invalidAction=true;
+		}		
+		if(invalidAction)
+			return exiting(false);
+		String[] outArg = osgiAct.getOutputArgumentNames();
+		if(outArg!=null){
+			Argument arg;
+			for (int j = 0; j < outArg.length; j++) {
+				arg = al.getArgument(outArg[j]);								
+				try {
+					arg.setValue(
+						Converter.toString(
+								outArgs.get(outArg[j]),
+								arg.getRelatedStateVariable().getDataType()
+								/*osgiServ.getStateVariable(arg.getRelatedStateVariableName()).getUPnPDataType()*/
+						)
+					);
+				} catch (Exception e) {
+					e.printStackTrace();
+					return exiting(false);
+				}
+			}
+		}
+		return exiting(true);
+	}
+
+	/**
+	 * @param b
+	 * @return
+	 */
+	private boolean exiting(boolean b) {
+		Activator.bc.ungetService(dev);
+		return b;
+	}
+
+	/**
+	 * @see org.osgi.framework.ServiceListener#serviceChanged(org.osgi.framework.ServiceEvent)
+	 */
+	public void serviceChanged(ServiceEvent e) {
+		if(e.getType()==ServiceEvent.UNREGISTERING){
+			Activator.bc.removeServiceListener(this);
+		}			
+	}				
+}
diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/export/RootDeviceExportingQueue.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/export/RootDeviceExportingQueue.java
new file mode 100644
index 0000000..5ddaf99
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/export/RootDeviceExportingQueue.java
@@ -0,0 +1,69 @@
+/*
+ *   Copyright 2006 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+
+package org.apache.felix.upnp.basedriver.export;
+
+import java.util.Vector;
+
+/**
+ * @author Stefano "Kismet" Lenzi 
+ *
+ */
+public class RootDeviceExportingQueue {
+	
+    private Vector v;
+    private boolean waiting;
+    
+    public RootDeviceExportingQueue(){
+        v = new Vector();
+        waiting=false;
+    }
+    
+    public synchronized void addRootDevice(DeviceNode dev){
+        v.addElement(dev);
+        if(waiting) notify();
+    }
+    
+    public synchronized DeviceNode getRootDevice(){
+        while(v.isEmpty()){
+            waiting=true;
+            try {
+                wait();
+            } catch (InterruptedException e) {
+            }
+        }
+        DeviceNode dev = (DeviceNode) v.firstElement();
+        v.remove(0);
+        return dev;
+    }
+    /**
+     * 
+     * @param udn <code>String</code> rappresentaing the UDN of the device to remove 
+     * @return a root <code>DeviceNode</code> that have UDN equals to the passed
+     * 		 udn <code>String</code> or contain a device with the spcified UDN
+     */
+    public synchronized DeviceNode removeRootDevice(String udn){
+        for (int i = 0; i < v.size(); i++) {
+        	DeviceNode aux=(DeviceNode) v.elementAt(i);
+            if(aux.contains(udn)){
+                v.remove(i);
+                return aux;
+            }
+        }
+        return null;
+    }
+}
diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/export/RootDeviceListener.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/export/RootDeviceListener.java
new file mode 100644
index 0000000..4e4f73f
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/export/RootDeviceListener.java
@@ -0,0 +1,209 @@
+/*
+ *   Copyright 2006 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+
+package org.apache.felix.upnp.basedriver.export;
+
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.upnp.UPnPDevice;
+
+import org.apache.felix.upnp.basedriver.Activator;
+
+/**
+ * @author Stefano "Kismet" Lenzi 
+ * @author Francesco "Sygent" Furfari 
+ */
+public class RootDeviceListener implements ServiceListener {
+
+	private RootDeviceExportingQueue queue;
+
+	private ArrayList devices;
+
+	public RootDeviceListener(RootDeviceExportingQueue queue) {
+		this.queue = queue;
+		devices = new ArrayList();
+	}
+
+	public synchronized void addDevice(ServiceReference sr) {
+		DeviceNode node = new DeviceNode(sr);
+		
+	if(node.isRoot() && node.isLeaf()){
+		//Obiovsly
+		queue.addRootDevice(node);
+		return;
+	}
+
+	if(!node.isLeaf()){
+		//I look if there is some partial tree that is child 
+		//of my new node. This operation may complete the tree 
+		Iterator list = devices.iterator();
+		DeviceNode handle = null;
+		while(list.hasNext()){
+			DeviceNode tree = (DeviceNode) list.next();
+			if((handle = node.isAttachable(tree)) != null){
+				handle.attach(tree);
+				list.remove();
+				if(node.isRoot() && node.isComplete()){
+					queue.addRootDevice(node);
+					return;
+				}
+			}
+		}
+	}
+	
+	if(!node.isRoot()){
+		//I look if there is some partial tree that should own
+		//my new node. This operation may complete the tree			
+		Iterator list = devices.iterator();
+		DeviceNode handle = null;
+		while(list.hasNext()){
+			DeviceNode tree = (DeviceNode) list.next();
+			if((handle = tree.isAttachable(node)) != null){
+				handle.attach(node);
+				if(tree.isRoot() && tree.isComplete()){
+					list.remove();
+					queue.addRootDevice(tree);
+				}
+				return;
+			}
+		}		
+	}
+	
+	devices.add(node);
+
+	}
+
+	/**
+	 * @see org.osgi.framework.ServiceListener#serviceChanged(org.osgi.framework.ServiceEvent)
+	 */
+	public void serviceChanged(ServiceEvent e) {
+		switch (e.getType()) {
+			case ServiceEvent.REGISTERED: {
+				addDevice(e.getServiceReference());
+			}break;
+
+			case ServiceEvent.MODIFIED: 
+			break;
+
+			case ServiceEvent.UNREGISTERING: {
+				removeDevice(e.getServiceReference());
+			}break;
+		}
+	}
+
+	/**
+	 * @param serviceReference
+	 */
+	public synchronized void removeDevice(ServiceReference sr) {
+		String udn = (String) sr.getProperty(UPnPDevice.UDN);
+		DeviceNode removeNode = null;
+		/*
+		 * I look in the queue of complete device that will be exported
+		 */
+		
+		DeviceNode root=this.queue.removeRootDevice(udn);
+		if(root!=null) removeNode=root.dethatch(udn);
+
+		/*
+		 * I look in the list that conatin unqueue,so no-complete Device 
+		 */
+		Iterator i = this.devices.iterator();
+		while (i.hasNext()) {
+			root = (DeviceNode) i.next();
+			removeNode = root.dethatch(udn);
+		}
+		
+		/*
+		 * if I found the device removeNode != null
+		 */
+		if(removeNode==null) return;
+		/*
+		 * I get all the already attached subdevice and add to 
+		 * unttached device list
+		 */
+		Collection c=removeNode.getChildren();
+		if(c==null) return;		
+		this.devices.addAll(c);
+	}
+
+	/**
+	 * Register this object to listen to all "well registered" UPnPDevice <br>
+	 * that should be Exported <br>
+	 * And look for all the already registered UPnPDevice to be exported
+	 *  
+	 */
+	public void activate() {
+		/*
+		 * I listen for the UPnPDevice service that are Root that should be
+		 * exported to UPnP Network.
+		 * 
+		 * Please Note: The following filter disable listining for bad registerd
+		 * UPnPDevice
+		 */
+		try {
+			Activator.bc.addServiceListener(this, 
+					"(&" + 
+					"(" + Constants.OBJECTCLASS	+ "=" + UPnPDevice.class.getName() + ")" + 
+					"("	+ UPnPDevice.UPNP_EXPORT + "=*)" + 
+					"(DEVICE_CATEGORY=UPnP)" + 
+					"(" + UPnPDevice.UDN + "=*)" + 
+					"("	+ UPnPDevice.FRIENDLY_NAME + "=*)" +
+					"("	+ UPnPDevice.MANUFACTURER + "=*)" + 
+					"("	+ UPnPDevice.MODEL_NAME + "=*)" + 
+					"(" + UPnPDevice.TYPE + "=*)" + 
+					")");
+		} catch (InvalidSyntaxException e) {
+			e.printStackTrace();
+		}
+		ServiceReference[] roots = null;
+		try {
+			roots = Activator.bc.getServiceReferences(UPnPDevice.class.getName(),
+					"(&" + "(" + UPnPDevice.UPNP_EXPORT + "=*)"	+ 
+							"(DEVICE_CATEGORY=UPnP)" + 
+							"(" + UPnPDevice.UDN + "=*)" + 
+							"(" + UPnPDevice.FRIENDLY_NAME + "=*)" +  
+							"(" + UPnPDevice.MANUFACTURER + "=*)" + 
+							"("	+ UPnPDevice.MODEL_NAME + "=*)" + 
+							"("	+ UPnPDevice.TYPE + "=*)" + 
+							"(!("+ UPnPDevice.PARENT_UDN + "=*))" + 
+							")");
+		} catch (InvalidSyntaxException e) {
+			e.printStackTrace();
+		}
+		if (roots != null) {
+			for (int i = 0; i < roots.length; i++) {
+				addDevice(roots[i]);
+			}
+		}
+	}	
+
+	/**
+	 *  
+	 */
+	public void deactive() {
+		Activator.bc.removeServiceListener(this);
+	}
+
+}
\ No newline at end of file
diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/export/ThreadExporter.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/export/ThreadExporter.java
new file mode 100644
index 0000000..a0a1141
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/export/ThreadExporter.java
@@ -0,0 +1,512 @@
+/*
+ *   Copyright 2006 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+
+package org.apache.felix.upnp.basedriver.export;
+
+
+import java.io.File;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Properties;
+import java.util.Vector;
+
+import org.cybergarage.upnp.Device;
+import org.cybergarage.upnp.DeviceList;
+import org.cybergarage.upnp.ServiceList;
+import org.cybergarage.upnp.UPnP;
+
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.upnp.UPnPDevice;
+import org.osgi.service.upnp.UPnPEventListener;
+
+import org.apache.felix.upnp.basedriver.Activator;
+
+/**
+ * @author Stefano "Kismet" Lenzi 
+ *  
+ */
+public class ThreadExporter implements Runnable,ServiceListener {
+
+	private boolean end;
+
+	private RootDeviceExportingQueue queueRootDevice;
+
+//	private String basePath; twa: redundant
+
+//	private File baseFile; twa: redundant
+
+	private Hashtable exportedDevices;
+	
+	private boolean listening;
+	
+	private class ExportedDeviceInfo{
+		private Device device;
+		private ServiceRegistration serviceRegistration;
+		//private DeviceNode deviceNode;
+		
+			
+		/**
+		 * @param device
+		 * @param serviceRegistration
+		 * @param deviceNode
+		 */
+		private ExportedDeviceInfo(Device device,
+				ServiceRegistration serviceRegistration,
+				DeviceNode deviceNode) {
+			super();
+			this.device = device;
+			this.serviceRegistration = serviceRegistration;
+			//this.deviceNode = deviceNode;
+		}
+		
+		
+		private Device getDevice() {
+			return this.device;
+		}
+		private ServiceRegistration getServiceRegistration() {
+			return this.serviceRegistration;
+		}
+		/*private DeviceNode getDeviceNode(){
+			return this.deviceNode;
+		}*/
+        
+		
+	}
+	
+	/**
+	 *  
+	 */
+	public ThreadExporter(RootDeviceExportingQueue queue) throws InvalidSyntaxException {
+	    end=false;
+	    queueRootDevice=queue;
+//		basePath="./tmp/device"; twa: redundant
+//		baseFile = Activator.bc.getDataFile("./tmp/device"); twa: redundant
+//		if(!baseFile.exists())	baseFile.mkdirs(); twa: redundant
+		this.exportedDevices=new Hashtable();
+		setListening(false);
+		UPnP.setEnable(UPnP.USE_ONLY_IPV4_ADDR);		
+	}
+	public void run() {
+		
+		File osgiRoot = Activator.bc.getDataFile("");
+		if (osgiRoot == null) {
+			Activator.logger.ERROR("Unable to use filesystem");
+			while (true) {
+				try {
+					Activator.bc.getBundle().stop();
+					break;
+				} catch (BundleException e) {
+					e.printStackTrace();
+					try {
+						Thread.sleep(1000);
+					} catch (InterruptedException ex) {
+						ex.printStackTrace();
+					}
+				}
+			}
+			return;
+		}
+		
+		ServiceReference rootDevice = null;
+		while (!shouldEnd()) {
+			DeviceNode dn = queueRootDevice.getRootDevice();
+			if (dn == null)
+				continue;
+			rootDevice = dn.getReference();
+			if(!getListening()) 
+				setListen();
+			Activator.logger.INFO("[Exporter] Exporting device "+ rootDevice.getProperty(UPnPDevice.FRIENDLY_NAME));
+			/*
+			File xml = new File(baseFile, 
+					Converter.sanitizeFilename(
+						(String) rootDevice.getProperty(UPnPDevice.UDN)
+					)
+				);
+			if (xml == null)
+				continue;			
+			if (!xml.exists())
+				xml.mkdir();
+
+			FileOutputStream fos = null;
+			try {
+				fos = new FileOutputStream(xml.getAbsolutePath()
+						+ File.separator + "desc.xml");
+			} catch (FileNotFoundException e) {				
+				Activator.logger.log(LogService.LOG_ERROR,"Unable to write:" + xml.getAbsolutePath(), e);
+				continue;
+			}
+			if (fos == null)
+				continue;*/
+			/*
+			 * I don't know if the exporting should be make default language of the framework
+			 * or without any lanuguages
+			Root r = new Root(rootDevice, context, context
+					.getProperty(Constants.FRAMEWORK_LANGUAGE));
+					*/
+            
+			synchronized (this) {
+				//Root r = new Root(rootDevice, Activator.bc, null);
+				/*
+				 * Now that I have XML I'm going to exporting device
+				 * so I have to avoid rece condition with deregistration 
+				 * of the same device
+				 */
+				/*
+				try {
+					r.writeXML(fos);
+				} catch (IOException e) {
+					e.printStackTrace();
+					continue;
+				}
+				if(writeXMLService(xml.getAbsolutePath(),r.getRootDevice())){
+					Device d = null;
+					try {
+						d = new Device(xml.getAbsolutePath()
+								+ File.separator + "desc.xml");
+					} catch (InvalidDescriptionException e) {
+						e.printStackTrace();
+					}*/
+					Device d = BuildDevice.createCyberLinkDevice(dn.getReference());
+					if (d != null) {
+						if(!bindInvokes(d,rootDevice)){
+							Activator.logger.DEBUG("Unable to find all the sub device or to set action listener");
+							continue;
+						}
+						ServiceRegistration listenReg = bindSubscribe(d);
+						if(listenReg==null){
+							Activator.logger.DEBUG("Unable to set action listener event listener");
+							continue;
+						}			
+						//makeIcons(r.getRootDevice(),xml.getAbsolutePath());
+						d.start();
+						exportedDevices.put(
+								rootDevice.getProperty(UPnPDevice.UDN),
+								new ExportedDeviceInfo(d,listenReg,dn)
+						);
+					}
+				//}
+			}
+		}
+	}
+
+	/**
+	 * 
+	 */
+	private void setListen() {
+		{
+			try {
+				Activator.bc.addServiceListener(
+						this,
+						// fixed by Matteo and Francesco 21/9/04
+						"(&("+Constants.OBJECTCLASS+"="+UPnPDevice.class.getName()+")" 
+						+ "(" + UPnPDevice.UPNP_EXPORT +"=*))"
+				);
+			} catch (InvalidSyntaxException ingnore) {}
+		}
+	}
+	/*
+	/**
+	 * @param upnpDev
+	 * @param refDev
+	 *
+	private void makeIcons(
+			org.apache.felix.upnpbase.export.xml.Device upnpDev, 
+			String path) {
+		Icon[] icons = upnpDev.getIcons();
+		if(icons!=null){
+			byte[] buf = new byte[512];
+			for (int i = 0; i < icons.length; i++) {
+				try {
+					String icoPath = path+icons[i].getUrl().replace('/',File.separatorChar);
+					InputStream is = icons[i].getInputStream();
+					Converter.makeParentPath(icoPath);
+					FileOutputStream fos = new FileOutputStream(icoPath);
+					int n=is.read(buf,0,buf.length);
+					while(n>0){
+						fos.write(buf,0,n);
+						n=is.read(buf,0,buf.length);
+					}
+				} catch (IOException e) {
+					e.printStackTrace();
+				}
+			}
+		}
+		org.apache.felix.upnpbase.export.xml.Device[] devs = upnpDev.getDevices();
+		if(devs==null)
+			return;
+		for (int i = 0; i < devs.length; i++) {
+			makeIcons(devs[i],path);
+		}
+	}*/
+	/**
+	 * This method is used to connect all the Action that are shown to UPnP world
+	 * by CyberLink UPnP Device to the real implementation that is conatined iniside
+	 * the OSGi service.
+	 * This method will connect even all the subdevice of te given OSGi device.
+	 * 
+	 * @param d CyberLink Device that will be used associated to the OSGi Device
+	 * @param rootDevice ServiceReference to the OSGi Device that will be used as 
+	 * 	implementation of the CyberLink Device
+	 * @return true if and only if the binding off all the action of all the children
+	 * 		device is done succesfully
+	 */
+	private boolean bindInvokes(Device d, ServiceReference rootDevice) {
+		bindInvoke(d,rootDevice);
+		//Activator.bc.ungetService(rootDevice);
+		ServiceReference[] childs = null;
+		try {
+			childs = Activator.bc.getServiceReferences(
+				UPnPDevice.class.getName(),
+				"("+UPnPDevice.PARENT_UDN+"="+rootDevice.getProperty(UPnPDevice.UDN)+")"
+			);
+		} catch (InvalidSyntaxException e) {
+			e.printStackTrace();				
+		}		
+		String[] childsUDN = (String[]) rootDevice.getProperty(UPnPDevice.CHILDREN_UDN);
+		if((childs==null)&&(childsUDN==null)){
+			return true;			
+		}else if((childs==null)||(childsUDN==null)){
+			return false;
+		}else if(childs.length==childsUDN.length){
+            /*--- your code ---            
+            for (int i = 0; i < childs.length; i++) {
+                if(!bindInvokes(d,childs[i]))
+                    return false;
+            }           
+            ----- your code end ---*/
+            /*--- twa code ---*/
+            DeviceList dl = d.getDeviceList();
+            for (int i = 0; i < childs.length; i++) {
+                Device dev = (Device)dl.elementAt(i);
+                if(!bindInvokes(dev,childs[i]))
+                    return false;
+            }
+            /*----- twa code end ---*/
+
+			return true;
+		}else{
+			return false;
+		}
+			
+	}
+	/*
+	/**
+	 * @param path
+	 *
+	private boolean writeXMLService(String path,org.apache.felix.upnpbase.export.xml.Device d) {
+		Vector v = new Vector();
+		v.add(d);
+		while(v.size()!=0){
+			d=(org.apache.felix.upnpbase.export.xml.Device) v.elementAt(0);
+			v.remove(0);
+			Service[] servs = d.getServices();
+			if(servs==null)
+				continue;
+			for (int i = 0; i < servs.length; i++) {
+				FileOutputStream fos;
+				String xmlPath=path+servs[i].getScpdURL().replace('/',File.separatorChar);
+				if(!Converter.makeParentPath(xmlPath)) return false;
+				try {
+					fos = new FileOutputStream(xmlPath);
+				} catch (FileNotFoundException e) {
+					e.printStackTrace();
+					return false;
+				}
+				try {
+					servs[i].writeXML(fos);
+					fos.close();
+				} catch (IOException e) {
+					e.printStackTrace();
+				}
+			}
+			
+			org.apache.felix.upnpbase.export.xml.Device[] subs = d.getDevices();
+			if(subs==null){
+				return true;
+			}else{
+				for(int i = 0; i < subs.length;i++){
+					v.add(subs[i]);
+				}
+			}
+		}
+		return true;
+	}*/
+	/**
+	 * This method add an UPnPEventListener Service to the OSGi Framework so that
+	 * the Base Driver can notify all the event listener registered on the CyberLink
+	 * UPnP device from the UPnP World. 
+	 * 
+	 * @param d Device of CyberLink that will be notified by the changing of the StateVariable
+	 * 		that happen on the OSGi World  
+	 * @return ServiceRegistration of the new registered service.
+	 */
+	private ServiceRegistration bindSubscribe(Device d) {
+		ExporterUPnPEventListener eventer = new ExporterUPnPEventListener(d);
+		Properties p = new Properties();
+
+		StringBuffer sb = new StringBuffer("(|");
+		Vector v = new Vector();
+		v.add(d);
+		Device current;
+		while (v.size() != 0) {
+			current = (Device) v.elementAt(0);
+			v.remove(0);
+			DeviceList dl = current.getDeviceList();
+			for (int i = 0; i < dl.size(); i++) {
+				v.add(dl.elementAt(i));
+			}
+			sb.append("(").append(UPnPDevice.ID).append("=").append(
+					current.getUDN()).append(")");
+		}
+		sb.append(")");
+		Filter f = null;
+		try {
+			f = Activator.bc.createFilter(sb.toString());
+		} catch (InvalidSyntaxException e) {
+			e.printStackTrace();
+			return null;
+		}
+		if (f != null) p.put(UPnPEventListener.UPNP_FILTER, f);
+		
+		return Activator.bc.registerService(UPnPEventListener.class.getName(), eventer, p);
+	}
+
+	/**
+	 * This method do the real connection between OSGi UPnP Service action and 
+	 * CyberLink UPnP Device action
+	 * 
+	 * @param upnpDev the CyberLink UPnP Device object that will be connected
+	 * @param osgiDev the ServiceReference to OSGi UPnP Service that will be connected to
+	 * 		CyberLink UPnP as implementation of the Action
+	 * @return true if and only if the binding off all the action is done succesfully 
+	 */
+	private boolean bindInvoke(Device upnpDev,ServiceReference osgiDev) {
+		ServiceList sl = upnpDev.getServiceList();
+		int l=sl.size();
+		for (int i = 0; i < l; i++) {
+			sl.getService(i).setActionListener(
+				new GeneralActionListener(
+					osgiDev,
+					sl.getService(i).getServiceID()
+				)
+			);			
+		}
+		return true;
+	}
+
+	/**
+	 *  
+	 */
+	public synchronized void cleanUp() {
+		Activator.logger.INFO("Cleaning...");
+		
+		Enumeration keys;
+		
+		Activator.logger.INFO("Removing temporary listener....");
+		keys=exportedDevices.keys();
+		while (keys.hasMoreElements()) {
+			ServiceRegistration sr = ((ExportedDeviceInfo) 
+					exportedDevices.get(keys.nextElement())).getServiceRegistration();
+			sr.unregister();
+		}		
+		Activator.logger.INFO("Done");
+		
+		Activator.logger.INFO("Removing device....");
+		keys=exportedDevices.keys();
+		while (keys.hasMoreElements()) {
+			Device dev = ((ExportedDeviceInfo) 
+					exportedDevices.get(keys.nextElement())).getDevice();
+			dev.stop();
+		}		
+		Activator.logger.INFO("Done");
+	}
+
+	private synchronized boolean shouldEnd() {
+		return end;
+	}
+
+	public synchronized void end() {
+		end = true;
+		queueRootDevice.addRootDevice(null);
+	}
+	/**
+	 * @see org.osgi.framework.ServiceListener#serviceChanged(org.osgi.framework.ServiceEvent)
+	 */
+	public void serviceChanged(ServiceEvent event) {
+		switch(event.getType()){
+			case ServiceEvent.REGISTERED:break;
+			
+			case ServiceEvent.MODIFIED:
+			case ServiceEvent.UNREGISTERING:{
+				this.unexportDevice(event.getServiceReference());
+				if(exportedDevices.size()==0){
+					Activator.bc.removeServiceListener(this);
+					setListening(false);
+				}
+			}break;
+		}
+	}
+	/**
+	 * @param b
+	 */
+	private synchronized void setListening(boolean b) {
+		listening=b;	
+	}
+	
+	private synchronized boolean getListening(){
+		return listening;
+	}
+	
+	/**
+	 * @param property
+	 */
+	private synchronized void unexportDevice(ServiceReference dev) {
+		String udn=(String) dev.getProperty(UPnPDevice.PARENT_UDN);
+		if(udn==null){
+			ExportedDeviceInfo edi =
+				(ExportedDeviceInfo) exportedDevices.get(
+					dev.getProperty(UPnPDevice.UDN)
+				);
+			Device d = edi.getDevice();
+			if(d!=null) {
+                Activator.logger.INFO("[Exporter] removing device:" +d.getFriendlyName());
+				d.stop();
+				exportedDevices.remove(d.getUDN());
+			}
+			ServiceRegistration srListener=edi.getServiceRegistration();
+			if(srListener!=null) srListener.unregister();
+			
+		}else{
+			ServiceReference[] servs=null;
+			try {
+				servs = Activator.bc.getServiceReferences(
+						UPnPDevice.class.getName(),
+						"("+UPnPDevice.UDN+"="+udn+")"
+				);
+			} catch (InvalidSyntaxException ignored) {}
+			if(servs==null) return;
+			this.unexportDevice(servs[0]);
+		}
+	}
+}
diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/MyCtrlPoint.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/MyCtrlPoint.java
new file mode 100644
index 0000000..1c86669
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/MyCtrlPoint.java
@@ -0,0 +1,933 @@
+/*

+ *   Copyright 2006 The Apache Software Foundation

+ *

+ *   Licensed under the Apache License, Version 2.0 (the "License");

+ *   you may not use this file except in compliance with the License.

+ *   You may obtain a copy of the License at

+ *

+ *       http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *   Unless required by applicable law or agreed to in writing, software

+ *   distributed under the License is distributed on an "AS IS" BASIS,

+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *   See the License for the specific language governing permissions and

+ *   limitations under the License.

+ *

+ */

+

+package org.apache.felix.upnp.basedriver.importer.core;

+

+

+import java.util.ArrayList;

+import java.util.Dictionary;

+import java.util.Enumeration;

+import java.util.Hashtable;

+import java.util.Iterator;

+import java.util.Vector;

+

+import org.cybergarage.http.HTTPRequest;

+import org.cybergarage.upnp.ControlPoint;

+import org.cybergarage.upnp.Device;

+import org.cybergarage.upnp.DeviceList;

+import org.cybergarage.upnp.Service;

+import org.cybergarage.upnp.ServiceList;

+import org.cybergarage.upnp.ServiceStateTable;

+import org.cybergarage.upnp.StateVariable;

+import org.cybergarage.upnp.device.NotifyListener;

+import org.cybergarage.upnp.device.SearchResponseListener;

+import org.cybergarage.upnp.event.NotifyRequest;

+import org.cybergarage.upnp.event.Property;

+import org.cybergarage.upnp.event.PropertyList;

+import org.cybergarage.upnp.ssdp.SSDPPacket;

+

+import org.osgi.framework.BundleContext;

+import org.osgi.framework.Constants;

+import org.osgi.framework.Filter;

+import org.osgi.framework.InvalidSyntaxException;

+import org.osgi.framework.ServiceEvent;

+import org.osgi.framework.ServiceListener;

+import org.osgi.framework.ServiceReference;

+import org.osgi.framework.ServiceRegistration;

+import org.osgi.service.upnp.UPnPDevice;

+import org.osgi.service.upnp.UPnPEventListener;

+import org.osgi.service.upnp.UPnPService;

+import org.osgi.service.upnp.UPnPStateVariable;

+

+import org.apache.felix.upnp.basedriver.Activator;

+import org.apache.felix.upnp.basedriver.importer.core.event.message.FirstMessage;

+import org.apache.felix.upnp.basedriver.importer.core.event.message.ListenerModified;

+import org.apache.felix.upnp.basedriver.importer.core.event.message.ListenerUnRegistration;

+import org.apache.felix.upnp.basedriver.importer.core.event.message.StateChanged;

+import org.apache.felix.upnp.basedriver.importer.core.event.structs.NotifierQueue;

+import org.apache.felix.upnp.basedriver.importer.core.event.structs.SubscriptionQueue;

+import org.apache.felix.upnp.basedriver.importer.core.upnp.UPnPDeviceImpl;

+import org.apache.felix.upnp.basedriver.importer.core.upnp.UPnPServiceImpl;

+import org.apache.felix.upnp.basedriver.importer.util.DictionaryProp;

+import org.apache.felix.upnp.basedriver.importer.util.ParseUSN;

+import org.apache.felix.upnp.extra.util.Converter;

+

+/**

+ * @author Matteo "matted" Demuru 

+ * @author Stefano "Kismet" Lenzi

+ * @author Francesco Furfari 

+ * 

+ *  

+ */

+public class MyCtrlPoint extends ControlPoint

+		implements

+			NotifyListener,

+			SearchResponseListener,

+			ServiceListener

+{

+	private BundleContext context;   

+    private Hashtable devices;//key UDN value OsgideviceInfo(Osgi)

+	private SubscriptionQueue subQueue;

+	private NotifierQueue notifierQueue;

+    

+    private final String UPNP_EVENT_LISTENER_FLTR =

+        "(" + Constants.OBJECTCLASS + "=" + UPnPEventListener.class.getName() + ")";

+    private final String UPNP_DEVICE_FLTR =

+        "(" + Constants.OBJECTCLASS + "=" + UPnPDevice.class.getName() + ")";

+    private final String EXPORT_FLTR =

+        "(" + UPnPDevice.UPNP_EXPORT + "=*" + ")";

+    private final String IMPORT_FLTR =

+        "(" + org.apache.felix.upnp.extra.util.Constants.UPNP_IMPORT + "=*" + ")";

+

+    

+    public MyCtrlPoint(BundleContext context, SubscriptionQueue subQueue,

+			NotifierQueue notifierQueue) {

+		super();

+		this.context = context;

+        devices = new Hashtable();

+		addNotifyListener(this);

+		addSearchResponseListener(this);

+		try {

+			context.addServiceListener(this, UPNP_EVENT_LISTENER_FLTR);

+		} catch (InvalidSyntaxException e) {

+			e.printStackTrace();

+		}

+		this.subQueue = subQueue;

+		this.notifierQueue = notifierQueue;

+	}

+

+	public void httpRequestRecieved(HTTPRequest httpReq) {

+        Activator.logger.DEBUG("[Importer] httpRequestRecieved event");

+        Activator.logger.PACKET(httpReq.toString());

+

+        if (httpReq.isNotifyRequest() == true) {

+            Activator.logger.DEBUG("[Importer] Notify Request");

+			NotifyRequest notifyReq = new NotifyRequest(httpReq);

+			String uuid = notifyReq.getSID();

+			long seq = notifyReq.getSEQ();

+			PropertyList props = notifyReq.getPropertyList();

+//			int propCnt = props.size();

+//			Hashtable hash = new Hashtable();

+//			for (int n = 0; n < propCnt; n++) {

+//				Property prop = props.getProperty(n);

+//				String varName = prop.getName();

+//				String varValue = prop.getValue();

+//				hash.put(varName, varValue);

+//			}

+            newEventArrived(uuid, seq, props);

+			httpReq.returnOK();

+			return;

+		}

+

+        Activator.logger.DEBUG("BAD Request");

+		httpReq.returnBadRequest();

+

+	}

+

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.cybergarage.upnp.ControlPoint#removeExpiredDevices()

+	 *  

+	 */

+	public void removeExpiredDevices() {

+		DeviceList devList = getDeviceList();

+		int devCnt = devList.size();

+		for (int n = 0; n < devCnt; n++) {

+			Device dev = devList.getDevice(n);

+			if (dev.isExpired() == true) {

+                Activator.logger.DEBUG("[Importer] Expired device:"+ dev.getFriendlyName());

+				removeDevice(dev);

+				removeOSGiExpireDevice(dev);

+			}

+		}

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.cybergarage.upnp.device.NotifyListener#deviceNotifyReceived(org.cybergarage.upnp.ssdp.SSDPPacket)

+	 */

+	public void deviceNotifyReceived(SSDPPacket ssdpPacket) {

+        Activator.logger.DEBUG("[Importer] deviceNotifyReceived");

+        Activator.logger.PACKET(ssdpPacket.toString());

+		/*

+		 * case is notify case isalive case new root crea e aggiungi il servizio

+		 * in Osgi con tutta la stirpe case device or service controllo se

+		 * esiste in OSGi se si nada, se no lo creo partendo dal root case

+		 * byebye case root deregistro tutta la stirpe case device o service

+		 * reinstanzio il root con le modifiche

+		 *  

+		 */

+		/*

+		 * if the packet is 

+		 * 		NOTIFY or ISALIVE or *new* ROOT	then create and register the UPnPDevice and 

+		 * 										all the embeeded device too

+		 * 		DEVICE or SERVICE	then if they already exist in OSGi do nothing otherwise I'll create and 

+		 * 							register all the UPnPDevice need starting from the root device

+		 * 		*root* BYEBYE		then I'll unregister it and all its children from OSGi Framework 

+		 * 		*service* BYEBYE	then I'll re-register the UPnPDevice that contain the service with the updated

+		 * 							properties 

+		 * 		*device* BYEBYE		then I'll re-register the UPnPDevice that contain the device with the updated

+		 * 							properties and also unregister the UPnPDevice that has left

+		 */

+		String usn = ssdpPacket.getUSN();

+		ParseUSN parseUSN = new ParseUSN(usn);

+		String udn = parseUSN.getUDN();

+        

+		ServiceReference[] refs = null;

+		String filter = "(&" + UPNP_DEVICE_FLTR + EXPORT_FLTR+ ")";

+		try {

+			refs = context.getServiceReferences(UPnPDevice.class.getName(),	filter);

+		} catch (InvalidSyntaxException e) {

+			e.printStackTrace();

+		}

+		if (refs != null) {

+			for (int i = 0; i < refs.length; i++) {

+				UPnPDevice dev = (UPnPDevice) context.getService(refs[i]);

+				Dictionary dic = dev.getDescriptions(null);

+				if (((String) dic.get(UPnPDevice.UDN)).equals(udn)) {

+					return;

+				}

+			}

+		}

+

+		if (ssdpPacket.isAlive()) {

+			

+            Activator.logger.DEBUG("[Importer] ssdpPacket.isAlive");

+			if (devices.containsKey(udn)) {

+                Activator.logger.DEBUG("[Importer] Device already discovered");

+				if (parseUSN.isService()) {

+                    doServiceUpdating(udn,parseUSN.getServiceType());

+				}

+			} else {

+                doDeviceRegistration(udn);

+			}

+

+		} else if (ssdpPacket.isByeBye()) {

+            Activator.logger.DEBUG("[Importer] ssdpPacket.isByeBye");

+

+			if (devices.containsKey(udn)) {

+				if (parseUSN.isDevice()) {

+                    Activator.logger.DEBUG("[Importer] parseUSN.isDevice ...unregistering all the children devices ");

+                    

+					//unregistering all the children devices 

+					UPnPDeviceImpl dev = ((OSGiDeviceInfo) devices.get(udn)).getOSGiDevice();

+					removeOSGiandUPnPDeviceHierarchy(dev);

+

+				} else if (parseUSN.isService()) {

+                    Activator.logger.DEBUG("[Importer] parseUSN.isService ...registering modified device again ");

+					/* 

+					 * I have to unregister the UPnPDevice and register it again 

+					 * with the updated properties  

+					 */

+					UPnPDeviceImpl device = 

+                        ((OSGiDeviceInfo) devices.get(udn)).getOSGiDevice();

+					ServiceRegistration registar = 

+                        ((OSGiDeviceInfo) devices.get(udn)).getRegistration();

+					String[] oldServicesID = 

+                        (String[]) (device.getDescriptions(null).get(UPnPService.ID));

+					String[] oldServiceType = 

+                        (String[]) (device.getDescriptions(null).get(UPnPService.TYPE));

+                    

+					Device cyberDevice = findDeviceCtrl(this, udn);

+					Vector vec = new Vector();

+					for (int i = 0; i < oldServiceType.length; i++) {

+						Service ser = cyberDevice.getService(oldServicesID[i]);

+						if (!(ser.getServiceType().equals(parseUSN.getServiceType()))) 

+                        {

+							vec.add(oldServicesID[i]);

+						}

+					}

+

+                    //new serviceID

+					String[] actualServicesID = new String[vec.size()];

+					actualServicesID = (String[]) vec.toArray(new String[]{});

+

+                    //new serviceType

+					String[] actualServiceType = new String[oldServiceType.length - 1];

+					vec.clear();

+					for (int i = 0; i < oldServiceType.length; i++) {

+						if (!(oldServiceType[i].equals(parseUSN.getServiceType()))) 

+                        {

+							vec.add(oldServiceType[i]);

+						}

+					}

+					actualServiceType = (String[]) vec.toArray(new String[]{});

+

+                    //unrigistering and registering again with the new properties

+					unregisterUPnPDevice(registar);

+					device.setProperty(UPnPService.ID, actualServicesID);

+					device.setProperty(UPnPService.TYPE, actualServiceType);

+					registerUPnPDevice(null, device, device.getDescriptions(null));

+					searchForListener(cyberDevice);

+				}

+			}

+		} else {

+			/*

+			 * if it is a service means that it is beend delete when the 

+			 * owner was unregister so I can skip this bye-bye

+			 */

+		}

+	}

+    

+	public synchronized void removeOSGiandUPnPDeviceHierarchy(UPnPDeviceImpl dev) 

+    {

+		/*

+		 * remove all the UPnPDevice from the struct of local device recursively

+		 */

+		String[] childrenUDN = (String[]) dev.getDescriptions(null).get(

+				UPnPDevice.CHILDREN_UDN);

+		if (childrenUDN == null) {

+			//non ha figli

+			//no children

+			unregisterUPnPDevice(((OSGiDeviceInfo) devices.get(dev

+					.getDescriptions(null).get(UPnPDevice.UDN)))

+					.getRegistration());

+			devices.remove(dev.getDescriptions(null).get(UPnPDevice.UDN));

+			return;

+		}

+		for (int i = 0; i < childrenUDN.length; i++) {

+			if (devices.get(childrenUDN[i]) == null) {

+				continue;

+			} else {

+				removeOSGiandUPnPDeviceHierarchy(((OSGiDeviceInfo) devices

+						.get(childrenUDN[i])).getOSGiDevice());

+			}

+		}

+		unregisterUPnPDevice(((OSGiDeviceInfo) devices.get(dev.getDescriptions(

+				null).get(UPnPDevice.UDN))).getRegistration());

+		devices.remove(dev.getDescriptions(null).get(UPnPDevice.UDN));

+	}

+

+	public synchronized void removeOSGiExpireDevice(Device dev) {

+		/*

+		 * unregistering root device with all its children device from OSGi 

+		 * deleting root device and all its children from struct that conatin 

+		 * a list of local device

+		 */

+		removeOSGiandUPnPDeviceHierarchy(((OSGiDeviceInfo) devices.get(dev

+				.getUDN())).getOSGiDevice());

+	}

+

+	public void registerUPnPDevice(Device dev, UPnPDeviceImpl upnpDev,

+			Dictionary prop) {

+		/*

+		 * registering the new Device as OSGi UPnPDevice and then add 

+		 * ServiceRegistration and UPnPDevice reference to the hashtable

+		 * that contains local devices

+		 */

+		if (prop == null && upnpDev == null) {

+			UPnPDeviceImpl newDevice = new UPnPDeviceImpl(dev, context);

+			ServiceRegistration registration = 

+                context.registerService(UPnPDevice.class.getName(), 

+                                        newDevice, 

+                                        newDevice.getDescriptions(null));

+			OSGiDeviceInfo deviceInfo = 

+                new OSGiDeviceInfo(newDevice,registration);

+            

+            String udn = (String) ((newDevice.getDescriptions(null)).get(UPnPDevice.UDN));

+			devices.put(udn, deviceInfo);

+		} else {

+			ServiceRegistration registration = 

+                context.registerService(UPnPDevice.class.getName(), upnpDev, prop);

+			OSGiDeviceInfo deviceInfo = 

+                new OSGiDeviceInfo(upnpDev,	registration);

+			devices.put(upnpDev.getDescriptions(null).get(UPnPDevice.UDN),deviceInfo);

+		}

+	}

+    

+    

+	/*

+	 * public void registerHierarchyUPnPDevice(Device dev) { registro il root

+	 * con tutta la sua stirpe in osgi registerUPnPDevice(dev); DeviceList

+	 * devList = dev.getDeviceList(); for (int i = 0; i < devList.size(); i++) {

+	 * registerHierarchyUPnPDevice(devList.getDevice(i)); } }

+	 */

+	public void unregisterUPnPDevice(ServiceRegistration registration) {

+		registration.unregister();

+

+	}

+

+	public Device findDeviceCtrl(ControlPoint ctrl, String udn) {

+		/* 

+		 * this return the device looking in all the struct

+		 */

+		

+		DeviceList devList = getDeviceList();

+		Device dev = null;

+		int i = 0;

+		while (i < devList.size() && (dev == null)) {

+			if (devList.getDevice(i).getUDN().equals(udn)) {

+				dev = devList.getDevice(i);

+				return dev;

+			}

+			dev = findDevice(udn, devList.getDevice(i));

+			i++;	

+		}

+		return dev;

+	}

+    

+	public Device findDevice(String udn, Device dev) {

+		/*

+		 * look for the device if it exist, starting from the root on

+		 * cyberlink struct

+		 */

+		DeviceList devList = dev.getDeviceList();

+		Device aux = null;

+		for (int i = 0; i < devList.size(); i++) {

+			if (devList.getDevice(i).getUDN().equals(udn)) {

+				return devList.getDevice(i);

+			} else {

+				if((aux = findDevice(udn, devList.getDevice(i))) != null)

+					return aux;

+			}

+		}

+		return null;

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.cybergarage.upnp.device.SearchResponseListener#deviceSearchResponseReceived(org.cybergarage.upnp.ssdp.SSDPPacket)

+	 */

+	public void deviceSearchResponseReceived(SSDPPacket ssdpPacket) {

+        Activator.logger.DEBUG("[Importer] deviceSearchResponseReceived");

+        Activator.logger.PACKET(ssdpPacket.toString());

+

+		String usn = ssdpPacket.getUSN();

+		ParseUSN parseUSN = new ParseUSN(usn);

+		String udn = parseUSN.getUDN();

+

+		ServiceReference[] refs = null;

+        

+        String filter = "(&" + UPNP_DEVICE_FLTR + EXPORT_FLTR + ")";

+       

+		try {

+			refs = context.getServiceReferences(UPnPDevice.class.getName(),

+					filter);

+		} catch (InvalidSyntaxException e) {

+			e.printStackTrace();

+		}

+        

+		if (refs != null) {

+			for (int i = 0; i < refs.length; i++) {

+				UPnPDevice dev = (UPnPDevice) context.getService(refs[i]);

+				Dictionary dic = dev.getDescriptions(null);

+				if (((String) dic.get(UPnPDevice.UDN)).equals(udn)) {

+					return;

+				}

+			}

+		}

+

+		if (devices.containsKey(udn)) {			

+            Activator.logger.DEBUG("[Importer] Device already discovered");

+			/*

+			 * Exist the registered device either in OSGi and 

+			 * hashtable of local device

+			 */

+			if (parseUSN.isService()) {

+                doServiceUpdating(udn,parseUSN.getServiceType());

+			}

+		} else {

+            doDeviceRegistration(udn);

+		}

+

+	}

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.osgi.framework.ServiceListener#serviceChanged(org.osgi.framework.ServiceEvent)

+	 */

+	public void serviceChanged(ServiceEvent event) {

+        Activator.logger.DEBUG("[Importer] serviceChanged");

+        Activator.logger.DEBUG("Event::"+event.toString());

+

+		if (event.getType() == ServiceEvent.REGISTERED) {

+			/* check new listener registration */

+			ServiceReference serRef = event.getServiceReference();

+			Object obj = serRef.getProperty(UPnPEventListener.UPNP_FILTER);

+			/* obtain interested devices for the listener */

+			ServiceReference[] devicesRefs = null;

+			if (obj != null) {

+				Filter filter = (Filter) obj;

+				String filtra = filter.toString();

+				/*

+				 * Avoid to implement the notification for device 

+				 * that are not been created by BaseDriver

+				 */ 

+				String newfilter = "(&" + filtra +  IMPORT_FLTR + ")";

+                //String newfilter = "(&" + filtra + "(!" + EXPORT_FLTR + ")" + ")";

+				//System.out.println(newfilter);

+				try {

+					devicesRefs = context.getServiceReferences(UPnPDevice.class

+							.getName(), newfilter);

+				} catch (InvalidSyntaxException e) {

+					e.printStackTrace();

+				}

+

+				if (devicesRefs != null) {/*

+										   * solo se ci sono dei device

+										   * compatibili

+										   * 

+										   * only if there is a compatibile device

+										   */

+					Dictionary dic = new DictionaryProp();

+					/* cerco i servizi che matchano */

+					for (int i = 0; i < devicesRefs.length; i++) {

+						UPnPDevice device = (UPnPDevice) context.getService(devicesRefs[i]);

+						dic.put(UPnPDevice.ID, device.getDescriptions(null).get(UPnPDevice.UDN));

+						dic.put(UPnPDevice.TYPE, device.getDescriptions(null).get(UPnPDevice.TYPE));

+						UPnPService[] services = device.getServices();

+						//TODO fare l'unget del servizio UPnPDevice??

+						//TODO do I have to do the unget of UPnPDevice??

+						if (services != null) {

+							for (int j = 0; j < services.length; j++) {

+								dic.put(UPnPService.ID, services[j].getId());

+								dic.put(UPnPService.TYPE, services[j].getType());

+								//TODO add method boolean serviceEvented() so we can remove the below cycle

+								UPnPStateVariable[] stateVars = services[j].getStateVariables();

+								boolean hasEventedVars = false;

+								for (int k = 0; k < stateVars.length && ! hasEventedVars; k++) {

+									hasEventedVars = stateVars[k].sendsEvents();

+									if (hasEventedVars) {

+										if(filter.match(dic)){

+											UPnPEventListener listener = 

+		                                        (UPnPEventListener) context.getService(serRef);

+											FirstMessage msg = new FirstMessage(

+													((UPnPServiceImpl) services[j]).getCyberService(),

+													listener);

+											subQueue.enqueue(msg);											

+										}

+									}

+								}

+							}

+						}

+					}

+				}

+			} else {/* obj==null (interested in all devices) */

+				try {

+					String newfilter = "(!(" + EXPORT_FLTR+ ")";

+					devicesRefs = context.getServiceReferences(UPnPDevice.class.getName(), newfilter);

+				} catch (InvalidSyntaxException e) {

+					e.printStackTrace();

+				}

+				if (devicesRefs != null) {/*

+										   * solo se ci sono dei device

+										   * 

+										   * only if there is a device

+										   */

+

+					for (int i = 0; i < devicesRefs.length; i++) {

+						UPnPDevice device = (UPnPDevice) context

+								.getService(devicesRefs[i]);

+						UPnPService[] services = device.getServices();

+						//fare l'unget del servizio UPnPDevice??

+						//do I have to do the unget of UPnPDevice??

+						if (services != null) {

+							for (int j = 0; j < services.length; j++) {

+								UPnPStateVariable[] stateVars = services[j]

+										.getStateVariables();

+								boolean bool = false;								

+								for (int k = 0; k < stateVars.length; k++) {

+									bool = stateVars[k].sendsEvents();

+									if (bool) {

+										break;

+									}

+								}

+								if (bool) {

+									UPnPEventListener listener = 

+                                        (UPnPEventListener) context.getService(serRef);

+									FirstMessage msg = new FirstMessage(

+											((UPnPServiceImpl) services[j]).getCyberService(),

+											listener);

+									subQueue.enqueue(msg);

+								}

+							}

+						}

+					}

+				}

+			}

+

+		} else if (event.getType() == ServiceEvent.MODIFIED) {

+			Vector newServices = new Vector();

+			ServiceReference serRef = event.getServiceReference();

+			Filter filter = (Filter) serRef.getProperty(UPnPEventListener.UPNP_FILTER);

+			UPnPEventListener listener = (UPnPEventListener) context.getService(serRef);

+			ServiceReference[] devicesRefs = null;

+

+			if (filter != null) {

+				try {

+					String filtra = filter.toString();

+                    String newfilter = "(&" + filtra + "(!" + EXPORT_FLTR + ")" + ")";

+					devicesRefs = context.getServiceReferences(UPnPDevice.class.getName(), newfilter);

+				} catch (InvalidSyntaxException e) {

+					e.printStackTrace();

+				}

+				if (devicesRefs != null) {/*

+										   * solo se ci sono dei device

+										   * compatibili

+										   * 

+										   * only if there is a compatibile device

+										   */

+					Dictionary dic = new DictionaryProp();

+					/* 

+					 * cerco i servizi che matchano

+					 * 

+					 * look for the service that match

+					 */

+					for (int i = 0; i < devicesRefs.length; i++) {

+						UPnPDevice device = (UPnPDevice) context

+								.getService(devicesRefs[i]);

+						dic.put(UPnPDevice.ID, device.getDescriptions(null)

+								.get(UPnPDevice.UDN));

+						dic.put(UPnPDevice.TYPE, device.getDescriptions(null)

+								.get(UPnPDevice.TYPE));

+						UPnPService[] services = device.getServices();

+

+						//fare l'unget del servizio UPnPDevice??

+						//do I have to do the unget of UPnPDevice??

+						if (services != null) {

+							for (int j = 0; j < services.length; j++) {

+								dic.put(UPnPService.ID, services[j].getId());

+								dic

+										.put(UPnPService.TYPE, services[j]

+												.getType());

+

+								UPnPStateVariable[] stateVars = services[j]

+										.getStateVariables();

+								boolean hasEventedVars = false;

+								for (int k = 0; k < stateVars.length; k++) {

+									hasEventedVars = stateVars[k].sendsEvents();

+									if (hasEventedVars) {

+										break;

+									}

+								}

+								if (!hasEventedVars) {

+									continue;

+								}

+

+								boolean bool = filter.match(dic);

+								if (bool) {

+									newServices

+											.add(((UPnPServiceImpl) services[j])

+													.getCyberService());

+								}

+							}//for services

+						}//services ==null

+					}//for devicesRefs

+					ListenerModified msg = new ListenerModified(newServices,

+							listener);

+					subQueue.enqueue(msg);

+				}//devicesrefs !=null

+			} else {//interrested in all devices

+				try {

+

+					String newfilter = "(!(" + UPnPDevice.UPNP_EXPORT + "=*"

+							+ ")" + ")";

+					devicesRefs = context.getServiceReferences(UPnPDevice.class

+							.getName(), newfilter);

+				} catch (InvalidSyntaxException e) {

+					e.printStackTrace();

+				}

+				if (devicesRefs != null) {/*

+										   * solo se ci sono dei device

+										   * 

+										   * only if there is a device

+										   */

+

+					for (int i = 0; i < devicesRefs.length; i++) {

+						UPnPDevice device = (UPnPDevice) context

+								.getService(devicesRefs[i]);

+						UPnPService[] services = device.getServices();

+						//fare l'unget del servizio UPnPDevice??

+						//do I have to do the unget of UPnPDevice??

+						if (services != null) {

+							for (int j = 0; j < services.length; j++) {

+								UPnPStateVariable[] stateVars = services[j]

+										.getStateVariables();

+								boolean hasEventedVars = false;

+								for (int k = 0; k < stateVars.length; k++) {

+									hasEventedVars = stateVars[k].sendsEvents();

+									if (hasEventedVars) {

+										break;

+									}

+								}

+								if (hasEventedVars) {

+									newServices

+											.add(((UPnPServiceImpl) services[j])

+													.getCyberService());

+								}//hasEventedvars

+							}//for services

+						}//services !=null

+					}//for devicesRefs

+					subQueue

+							.enqueue(new ListenerModified(newServices, listener));

+				}//devicesRefs !=null

+

+			}

+

+		} else if (event.getType() == ServiceEvent.UNREGISTERING) {

+			UPnPEventListener listener = (UPnPEventListener) context

+					.getService(event.getServiceReference());

+			if (listener != null) {

+				ListenerUnRegistration msg = new ListenerUnRegistration(

+						listener);

+				subQueue.enqueue(msg);

+			}

+			context.ungetService(event.getServiceReference());

+		}

+	} /*

+	   * (non-Javadoc)

+	   * 

+	   * @see org.cybergarage.upnp.event.EventListener#eventNotifyReceived(java.lang.String,

+	   *      long, java.lang.String, java.lang.String)

+	   */

+	/*

+	 * public void eventNotifyReceived(String uuid, long seq, String varName,

+	 * String value) { // TODO Auto-generated method stub StateChanged msg = new

+	 * StateChanged(uuid, varName, value,seq);,serviceFromSid(uuid)

+	 * notifierQueue.enqueue(msg); }

+	 */

+

+	public Service serviceFromSid(String sid) {

+		Enumeration e = devices.elements();

+		Service cyberService = null;

+		while (e.hasMoreElements()) {

+			OSGiDeviceInfo deviceinfo = (OSGiDeviceInfo) e.nextElement();

+			UPnPDevice device = deviceinfo.getOSGiDevice();

+			UPnPService[] services = (UPnPService[]) device.getServices();

+			UPnPServiceImpl[] servicesImpl = new UPnPServiceImpl[services.length];

+			for (int i = 0; i < servicesImpl.length; i++) {

+				servicesImpl[i] = (UPnPServiceImpl) services[i];

+			}

+			for (int i = 0; i < servicesImpl.length; i++) {

+				cyberService = servicesImpl[i].getCyberService();

+				boolean bool = cyberService.isSubscribed();

+				if (bool) {

+					if (cyberService.getSID().equals(sid)) {

+						return cyberService;

+					}

+				}

+			}

+		}

+		return null;

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.apache.felix.upnpbase.importer.MyEventListener#newEventArrived(java.lang.String,

+	 *      long, java.util.Dictionary)

+	 */

+	public void newEventArrived(String uuid, long seq, PropertyList props) {

+        Activator.logger.DEBUG("[Importer] newEventArrived");

+		Service service = serviceFromSid(uuid);

+		if (service != null) {

+            int size = props.size();

+            Hashtable hash = new Hashtable();

+            for (int i = 0; i < size; i++) {

+                Property prop = props.getProperty(i);

+                String varName = prop.getName();

+                String varValue = prop.getValue();

+                String upnpType = service.getStateVariable(varName).getDataType();

+                Object valueObj;

+                try {

+                    valueObj = Converter.parseString(varValue,upnpType);

+                } catch (Exception e) {

+                    Activator.logger.ERROR("[Importer] Bad data value in Notify event: "

+                            +"var name="+varName +" value="+varValue +" type="+upnpType + "\n"+e);

+                    return;

+                }

+                hash.put(varName, valueObj);

+            }

+           

+			Device device = service.getDevice();

+			StateChanged msg = new StateChanged(uuid, seq, hash, device, service);

+			notifierQueue.enqueue(msg);

+		}

+	}

+    

+    public void doServiceUpdating(String udn,String serviceType){

+        Activator.logger.DEBUG("[Importer] check for service updating");

+        OSGiDeviceInfo deviceinfo = (OSGiDeviceInfo) devices.get(udn);

+        UPnPDeviceImpl device = deviceinfo.getOSGiDevice();

+        boolean isSerPresent = device.existServiceType(serviceType);

+        if (!isSerPresent) {

+            /*

+             * The serivice doesn't exist so it's new.

+             * Find the udn of owner device and re-register the owner

+             */

+            ServiceRegistration registar = 

+                ((OSGiDeviceInfo) devices.remove(udn)).getRegistration();

+            String[] oldServicesID = 

+                (String[]) device.getDescriptions(null).get(UPnPServiceImpl.ID);

+            String[] oldServicesType = 

+                (String[]) device.getDescriptions(null).get(UPnPServiceImpl.TYPE);

+            

+            //per via delle istanze multiple di un tipo di servizio

+            //to handle multiple instance of a serivice of the same type

+            Device cyberDevice = findDeviceCtrl(this, udn);

+            ServiceList serviceList = cyberDevice.getServiceList();

+            ArrayList newServicesID = new ArrayList();

+

+            for (int i = 0; i < serviceList.size(); i++) {

+                if (serviceList.getService(i).getServiceType()

+                        .equals(serviceType)) 

+                {

+                    newServicesID.add(serviceList.getService(i).getServiceID());

+                }

+            }

+            

+            //adding the new servicesID 

+            String[] currentServicesID = 

+                new String[(oldServicesID.length + newServicesID.size())];

+            int endOld = 1;

+            for (int i = 0; i < oldServicesID.length; i++) {

+                currentServicesID[i] = oldServicesID[i];

+                endOld++;

+            }

+            int j = 0;

+            for (; endOld < currentServicesID.length; endOld++) {

+                currentServicesID[endOld] = (String) newServicesID.get(j);

+                j++;

+            }

+            

+            //adding the new ServiceType

+            String[] currentServicesType = new String[oldServicesType.length + 1];

+            for (int i = 0; i < oldServicesType.length; i++) {

+                currentServicesType[i] = oldServicesType[i];

+            }

+            currentServicesType[currentServicesType.length - 1] = serviceType;

+            

+            

+            // unregistring the OSGi Device

+            // and setting new properties

+            unregisterUPnPDevice(registar);

+            device.setProperty(UPnPService.ID, currentServicesID);

+            device.setProperty(UPnPServiceImpl.TYPE,currentServicesType);

+            

+            //registering the service with the updated properties

+            registerUPnPDevice(null, device, device.getDescriptions(null));

+            searchForListener(cyberDevice);

+        }   

+    }

+    

+    public void doDeviceRegistration(String udn,boolean checkDouble){

+    	if(checkDouble){    		

+    		try {

+    			ServiceReference[] refs =

+    				Activator.bc.getServiceReferences(

+						UPnPDevice.class.getName(),

+						"(" + UPnPDevice.UDN + "=" + udn + ")"

+    				);

+    			if(refs!=null)

+    				return;

+			} catch (InvalidSyntaxException ignored) {

+			}

+    	}

+    	doDeviceRegistration(udn);

+    }

+    

+    public void doDeviceRegistration(String udn){

+        /*

+         * registering the new device even if it is new root device or

+         * a new embedded device 

+         */

+        Device dev = findDeviceCtrl(this, udn);

+        if (dev == null) {

+            Activator.logger.WARNING("Cyberlink notified packet from UDN:" +udn+ ", but Device instance doesn't exist in Cyberlink structs !");

+        }        

+        if (dev != null) {

+            Activator.logger.INFO("[Importer] registering UPnPDevice UDN:"+dev.getFriendlyName());

+            registerUPnPDevice(dev, null, null);

+            searchForListener(dev);

+            /*

+             * now we can register all the device embedded device and service without

+             * recieving the NOTIFY 

+             */

+            //XXX Think about this choice

+            for (Iterator i = dev.getDeviceList().iterator(); i.hasNext();) {

+				Device d = (Device) i.next();

+				doDeviceRegistration(d.getUDN(),true);

+			}

+        }    

+    }

+    

+	public void searchForListener(Device device) {

+        Activator.logger.DEBUG("[Importer] searching for UPnPEventListener");

+		ServiceReference[] listeners = null;

+		try {

+			listeners = context.getServiceReferences(UPnPEventListener.class.getName(), null);

+		} catch (InvalidSyntaxException e) {

+			// TODO Auto-generated catch block

+			e.printStackTrace();

+		}

+		if (listeners != null) {

+			String deviceID = device.getUDN();

+			String serviceID;

+			String deviceType = device.getDeviceType();

+			String serviceType;

+			Hashtable hash = new Hashtable();

+			hash.put(UPnPDevice.ID, deviceID);

+			hash.put(UPnPDevice.TYPE, deviceType);

+			ServiceList services = device.getServiceList();

+			Vector eventedSers = new Vector();

+

+			for (int i = 0; i < services.size(); i++) {

+				Service service = (Service) services.elementAt(i);

+				ServiceStateTable vars = service.getServiceStateTable();

+				for (int j = 0; j < vars.size(); j++) {

+					StateVariable var = (StateVariable) vars.elementAt(j);

+					if (var.isSendEvents()) {

+						eventedSers.add(service);

+						break;

+					}

+				}

+			}

+

+			for (int i = 0; i < listeners.length; i++) {

+				UPnPEventListener listener = (UPnPEventListener) context

+						.getService(listeners[i]);

+				Filter filter = (Filter) listeners[i]

+						.getProperty(UPnPEventListener.UPNP_FILTER);

+				if (filter == null) {

+					for (int j = 0; j < eventedSers.size(); j++) {

+						Service ser = (Service) eventedSers.elementAt(j);

+						subQueue.enqueue(new FirstMessage(ser, listener));

+					}

+				} else {

+					for (int j = 0; j < eventedSers.size(); j++) {

+						Service ser = (Service) eventedSers.elementAt(j);

+						serviceID = ser.getServiceID();

+						serviceType = ser.getServiceType();

+						hash.put(UPnPService.ID, serviceID);

+						hash.put(UPnPService.TYPE, serviceType);

+						boolean bool = filter.match(hash);

+						if (bool) {

+							subQueue.enqueue(new FirstMessage(ser, listener));

+						}

+

+					}

+				}

+

+			}

+

+		}

+	}

+}
\ No newline at end of file
diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/OSGiDeviceInfo.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/OSGiDeviceInfo.java
new file mode 100644
index 0000000..1fa69c6
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/OSGiDeviceInfo.java
@@ -0,0 +1,48 @@
+/*

+ *   Copyright 2006 The Apache Software Foundation

+ *

+ *   Licensed under the Apache License, Version 2.0 (the "License");

+ *   you may not use this file except in compliance with the License.

+ *   You may obtain a copy of the License at

+ *

+ *       http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *   Unless required by applicable law or agreed to in writing, software

+ *   distributed under the License is distributed on an "AS IS" BASIS,

+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *   See the License for the specific language governing permissions and

+ *   limitations under the License.

+ *

+ */

+

+package org.apache.felix.upnp.basedriver.importer.core;

+

+

+import org.osgi.framework.ServiceRegistration;

+

+import org.apache.felix.upnp.basedriver.importer.core.upnp.UPnPDeviceImpl;

+

+/**

+ * @author Matteo "matted" Demuru

+ *

+ */

+public class OSGiDeviceInfo {

+	private UPnPDeviceImpl osgidevice;

+	private ServiceRegistration registration;

+	

+	/**

+	 * @param osgidevice UPnPDeviceImpl a Service

+	 * @param registration Serviceregistration of the UPnPDevice service

+	 */

+	public OSGiDeviceInfo(UPnPDeviceImpl osgidevice,

+			ServiceRegistration registration) {

+		this.osgidevice = osgidevice;

+		this.registration = registration;

+	}

+	public UPnPDeviceImpl getOSGiDevice(){

+		return osgidevice;

+	}

+	public ServiceRegistration getRegistration(){

+		return registration;

+	}

+}

diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/message/FirstMessage.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/message/FirstMessage.java
new file mode 100644
index 0000000..c599165
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/message/FirstMessage.java
@@ -0,0 +1,67 @@
+/*

+ *   Copyright 2006 The Apache Software Foundation

+ *

+ *   Licensed under the Apache License, Version 2.0 (the "License");

+ *   you may not use this file except in compliance with the License.

+ *   You may obtain a copy of the License at

+ *

+ *       http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *   Unless required by applicable law or agreed to in writing, software

+ *   distributed under the License is distributed on an "AS IS" BASIS,

+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *   See the License for the specific language governing permissions and

+ *   limitations under the License.

+ *

+ */

+

+package org.apache.felix.upnp.basedriver.importer.core.event.message;

+

+import org.cybergarage.upnp.Device;

+import org.cybergarage.upnp.Service;

+

+import org.osgi.service.upnp.UPnPEventListener;

+

+/**

+ * This class rappresent a message that is equeued for the Suscriber.<br>

+ * This is message is related to a registration of listener for a 

+ * CyberLink Service during the registering of the UPnP Event Listener

+ * 

+ * @author Matteo "matted" Demuru

+ *

+ */

+

+public class FirstMessage {

+	private Service service;

+	private UPnPEventListener listener;

+	private String sid;

+	private Device device;

+

+	public FirstMessage(Service service, UPnPEventListener listener) {

+		this.service = service;

+		this.listener = listener;

+		this.sid = "";

+		this.device = service.getDevice();

+	}

+	public Service getService() {

+		return service;

+	}

+	public UPnPEventListener getListener() {

+		return listener;

+	}

+	public void setSid(String sid) {

+		this.sid = sid;

+	}

+	public String getSid() {

+		return sid;

+	}

+	public Device getDevice() {

+		return device;

+	}

+	public String getDeviceID(){

+		return device.getUDN();

+	}

+	public String getServiceID(){

+		return service.getServiceID();	

+	}

+}
\ No newline at end of file
diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/message/ListenerModified.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/message/ListenerModified.java
new file mode 100644
index 0000000..7b15d59
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/message/ListenerModified.java
@@ -0,0 +1,44 @@
+/*

+ *   Copyright 2006 The Apache Software Foundation

+ *

+ *   Licensed under the Apache License, Version 2.0 (the "License");

+ *   you may not use this file except in compliance with the License.

+ *   You may obtain a copy of the License at

+ *

+ *       http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *   Unless required by applicable law or agreed to in writing, software

+ *   distributed under the License is distributed on an "AS IS" BASIS,

+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *   See the License for the specific language governing permissions and

+ *   limitations under the License.

+ *

+ */

+

+package org.apache.felix.upnp.basedriver.importer.core.event.message;

+

+import java.util.Vector;

+

+import org.osgi.service.upnp.UPnPEventListener;

+

+/**

+ * Message that is euqueued for Suscriber, only when a UPnPEventListener changes 

+ * his properties

+ * 

+ * @author Matteo "matted" Demuru

+ *

+ */

+public class ListenerModified {

+	private Vector newServices;

+	private UPnPEventListener listener;

+	public ListenerModified(Vector newServices,UPnPEventListener listener){

+		this.newServices=newServices;

+		this.listener=listener;

+	}

+	public UPnPEventListener getListener(){

+		return listener;

+	}

+	public Vector getNewServices(){

+		return newServices;

+	}

+}

diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/message/ListenerUnRegistration.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/message/ListenerUnRegistration.java
new file mode 100644
index 0000000..434c9ce
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/message/ListenerUnRegistration.java
@@ -0,0 +1,38 @@
+/*

+ *   Copyright 2006 The Apache Software Foundation

+ *

+ *   Licensed under the Apache License, Version 2.0 (the "License");

+ *   you may not use this file except in compliance with the License.

+ *   You may obtain a copy of the License at

+ *

+ *       http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *   Unless required by applicable law or agreed to in writing, software

+ *   distributed under the License is distributed on an "AS IS" BASIS,

+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *   See the License for the specific language governing permissions and

+ *   limitations under the License.

+ *

+ */

+

+package org.apache.felix.upnp.basedriver.importer.core.event.message;

+

+import org.osgi.service.upnp.UPnPEventListener;

+

+/**

+ * @author Matteo "matted" Demuru

+ *

+ */

+public class ListenerUnRegistration {

+	private UPnPEventListener listener;

+	/**

+	 * @param listener

+	 */

+	public ListenerUnRegistration(UPnPEventListener listener) {

+		super();

+		this.listener = listener;

+	}

+	public UPnPEventListener getListener() {

+		return listener;

+	}

+}

diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/message/SidExipired.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/message/SidExipired.java
new file mode 100644
index 0000000..0324c7f
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/message/SidExipired.java
@@ -0,0 +1,44 @@
+/*

+ *   Copyright 2006 The Apache Software Foundation

+ *

+ *   Licensed under the Apache License, Version 2.0 (the "License");

+ *   you may not use this file except in compliance with the License.

+ *   You may obtain a copy of the License at

+ *

+ *       http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *   Unless required by applicable law or agreed to in writing, software

+ *   distributed under the License is distributed on an "AS IS" BASIS,

+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *   See the License for the specific language governing permissions and

+ *   limitations under the License.

+ *

+ */

+

+

+package org.apache.felix.upnp.basedriver.importer.core.event.message;

+

+import org.cybergarage.upnp.Service;

+

+/**

+ * @author Matteo "matted" Demuru

+ *

+ */

+public class SidExipired {

+private String sid;

+private Service service;

+/**

+	 * @param sid

+	 */

+	public SidExipired(String sid,Service service) {

+		super();

+		this.sid = sid;

+		this.service=service;

+	}

+	public String getSid(){

+		return sid;

+	}

+	public Service getService(){

+		return service;

+	}

+}

diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/message/StateChanged.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/message/StateChanged.java
new file mode 100644
index 0000000..7f26339
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/message/StateChanged.java
@@ -0,0 +1,79 @@
+/*

+ *   Copyright 2006 The Apache Software Foundation

+ *

+ *   Licensed under the Apache License, Version 2.0 (the "License");

+ *   you may not use this file except in compliance with the License.

+ *   You may obtain a copy of the License at

+ *

+ *       http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *   Unless required by applicable law or agreed to in writing, software

+ *   distributed under the License is distributed on an "AS IS" BASIS,

+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *   See the License for the specific language governing permissions and

+ *   limitations under the License.

+ *

+ */

+

+package org.apache.felix.upnp.basedriver.importer.core.event.message;

+

+import java.util.Dictionary;

+

+import org.cybergarage.upnp.Device;

+import org.cybergarage.upnp.Service;

+

+/**

+ * @author Matteo "matted" Demuru

+ *

+ */

+public class StateChanged {

+	private String sid;

+	private Dictionary dic;

+	private long seq;

+	private Service service;

+	private Device device;

+	/**

+	 * @param sid

+	 * @param dic

+	 * @param varName

+	 * @param varValue

+	 */

+	public StateChanged(String sid, long seq, Dictionary dic, Device device,

+			Service service) {

+		super();

+		this.sid = sid;

+		/*

+		 * this.varName = varName; this.varValue = varValue;

+		 */

+		this.dic = dic;

+		/* dic.put(this.varName, this.varValue); */

+		//this.service=service;

+		this.seq = seq;

+		this.device = device;

+		this.service = service;

+	}

+

+	public Dictionary getDictionary() {

+		return dic;

+	}

+	public String getSid() {

+		return sid;

+	}

+	/*

+	 * public String getVarName() { return varName; } public String

+	 * getVarValue() { return varValue; }

+	 */

+	public long getSeq() {

+		return seq;

+	}

+	/*

+	 * public Service getService(){ return service; }

+	 *  

+	 */

+	public String getDeviceID() {

+		return device.getUDN();

+	}

+	public String getServiceID() {

+		return service.getServiceID();

+	}

+}
\ No newline at end of file
diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/structs/Listener2Sids.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/structs/Listener2Sids.java
new file mode 100644
index 0000000..9d2e492
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/structs/Listener2Sids.java
@@ -0,0 +1,58 @@
+/*

+ *   Copyright 2006 The Apache Software Foundation

+ *

+ *   Licensed under the Apache License, Version 2.0 (the "License");

+ *   you may not use this file except in compliance with the License.

+ *   You may obtain a copy of the License at

+ *

+ *       http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *   Unless required by applicable law or agreed to in writing, software

+ *   distributed under the License is distributed on an "AS IS" BASIS,

+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *   See the License for the specific language governing permissions and

+ *   limitations under the License.

+ *

+ */

+

+package org.apache.felix.upnp.basedriver.importer.core.event.structs;

+

+import java.util.Hashtable;

+import java.util.Vector;

+

+import org.osgi.service.upnp.UPnPEventListener;

+

+/**

+ * @author Matteo "matted" Demuru

+ * @author Francesco Furfari 

+ * 

+ */

+public class Listener2Sids {

+	private Hashtable listenerSid;

+    

+	public Listener2Sids() {

+		this.listenerSid = new Hashtable();

+	}

+    

+	public void put(UPnPEventListener listener, String sid) {

+		if (!listenerSid.containsKey(listener)) {

+			Vector vec = new Vector();

+			vec.add(sid);

+			listenerSid.put(listener, vec);

+		} else {

+			Vector vec = (Vector) listenerSid.get(listener);

+			if (!vec.contains(sid)) {

+				vec.add(sid);

+			}

+		}

+	}

+    

+	public final void remove(UPnPEventListener listener) {

+		listenerSid.remove(listener);

+	}

+

+	public final Vector get(UPnPEventListener listener) {

+		return ((Vector) listenerSid.get(listener));

+	}

+}

+

diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/structs/Monitor.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/structs/Monitor.java
new file mode 100644
index 0000000..d178122
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/structs/Monitor.java
@@ -0,0 +1,244 @@
+/*

+ *   Copyright 2006 The Apache Software Foundation

+ *

+ *   Licensed under the Apache License, Version 2.0 (the "License");

+ *   you may not use this file except in compliance with the License.

+ *   You may obtain a copy of the License at

+ *

+ *       http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *   Unless required by applicable law or agreed to in writing, software

+ *   distributed under the License is distributed on an "AS IS" BASIS,

+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *   See the License for the specific language governing permissions and

+ *   limitations under the License.

+ *

+ */

+

+

+package org.apache.felix.upnp.basedriver.importer.core.event.structs;

+

+

+import java.util.Dictionary;

+import java.util.Hashtable;

+import java.util.Iterator;

+import java.util.Vector;

+

+import org.cybergarage.upnp.Service;

+

+import org.osgi.service.upnp.UPnPEventListener;

+

+import org.apache.felix.upnp.basedriver.importer.core.MyCtrlPoint;

+import org.apache.felix.upnp.basedriver.importer.core.event.message.FirstMessage;

+import org.apache.felix.upnp.basedriver.importer.core.event.message.ListenerModified;

+

+/**

+ * @author Matteo "matted" Demuru

+ * @author Francesco Furfari 

+ * 

+ *

+ */

+public class Monitor {

+	private Hashtable sidStateVars;

+	private SidsListenersMaps sidListSid;

+

+	public Monitor() {

+		this.sidListSid = new SidsListenersMaps();

+		this.sidStateVars = new Hashtable();

+	}

+

+	public synchronized void putStateVars(String sid, StateVarsToNotify vars) {

+		sidStateVars.put(sid, vars);

+		Vector listeners = (Vector) sidListSid.getListenersFromSid(sid);

+		if (listeners != null) {

+			sidListSid.updateListeners(sid, vars.getDeviceID(), vars.getServiceID(), vars.getDictionary());

+			sidListSid.setAlreadyFirst(sid,true);

+		} else {

+			sidListSid.setAlreadyFirst(sid, false);

+		}

+	}

+	public synchronized void updateStateVars(String sid, Dictionary dic) {

+		StateVarsToNotify vars = (StateVarsToNotify) sidStateVars.get(sid);

+		if (vars != null) {

+			vars.updateDic(dic);

+			if (sidListSid.getAlreadyFirst(sid)) {

+			    /*

+			     * Sends only the changed StateVariable

+			     */

+				sidListSid.updateListeners(sid, 

+				        vars.getDeviceID(), vars.getServiceID(), 

+				        dic);

+			} else {

+			    /*

+			     * Sends the sholw StateVariable for the service 

+			     */

+				boolean bool = sidListSid.updateListeners(sid, 

+				        vars.getDeviceID(), vars.getServiceID(), 

+				        vars.getDictionary());

+				if (bool) {

+					sidListSid.setAlreadyFirst(sid,true);

+				}

+			}

+		}

+	}

+    

+/*    

+ * controllare se bisogna fare un po' di cleaning

+ * 

+    public synchronized StateVarsToNotify getStateVars(String sid) {

+        return (StateVarsToNotify) sidStateVars.get(sid);

+    }

+    public synchronized void removeStateVars(String sid) {

+        sidStateVars.remove(sid);

+    }

+*/

+	public synchronized void addListener(String sid, UPnPEventListener listener) {

+		StateVarsToNotify vars = (StateVarsToNotify) sidStateVars.get(sid);

+		if (vars != null) {

+		    /*

+		     * Notify the listener whit the whole StateVariables and then

+		     * the next time you send only the changed StateVariables

+		     */

+            listener.notifyUPnPEvent(vars.getDeviceID(), 

+                    vars.getServiceID(),vars.getDictionary());

+        }

+		sidListSid.putSid2Listeners(sid, listener);

+		sidListSid.putListener2Sids(listener, sid);

+	}

+

+	/**

+	 * Delete the reference to the listener from the stuctures sid2Listeners and listener2Sids.

+	 * Also if no more listner are listening for a UPnP Service that UPnP Service is unscribed.

+	 * 

+	 * @param listener The listener to delete

+	 * @param ctrl Needed for reference

+	 */

+	public synchronized void delListener(UPnPEventListener listener,

+			MyCtrlPoint ctrl/*##renew, SidRenewer sidRenewer*/) {

+        

+        //francesco-renew

+        // le strutture delle variabili di stato quando si ripulisono?

+        

+		Vector sids = sidListSid.getSidsFromListener(listener);

+		if (sids != null) {

+		    Iterator i = sids.iterator();

+			while(i.hasNext()){

+			    String sid = (String) i.next();

+				Vector listeners = 

+                    sidListSid.getListenersFromSid(sid);

+				listeners.remove(listener);

+				if (listeners.size() == 0) {

+					Service service = 

+                        ctrl.serviceFromSid(sid);

+					//##renew  Renewer renewer = sidRenewer.get((String) sids.elementAt(i));

+					//##renew  renewer.stop();

+					if (service != null) {

+						boolean ok = ctrl.unsubscribe(service);

+						if (!ok) {

+						    //TODO Log?s

+							service.clearSID();

+						}

+					}

+					sidListSid.setAlreadyFirst(sid,false);

+					sidStateVars.remove(sid);

+					i.remove();

+				}

+			}

+			sidListSid.removeListenerKey(listener);			

+		}

+	}

+

+	public synchronized void updateListener(ListenerModified msg,

+			SubscriptionQueue subqueue, MyCtrlPoint ctrl/*##renew, SidRenewer sidRenewer*/) {

+		UPnPEventListener listener = msg.getListener();

+		Vector newServices = msg.getNewServices();

+		Vector subscribed = new Vector();

+		Vector notSubscribed = new Vector();

+		

+		for (int i = 0; i < newServices.size(); i++) {

+			Service ser = (Service) newServices.elementAt(i);

+			if (ser.isSubscribed()) {

+				subscribed.add(ser);

+			} else {

+				notSubscribed.add(ser);

+			}

+		}

+		

+

+		Vector oldSids = sidListSid.getSidsFromListener(listener);

+        // francesco-renew

+        // qua mi sembra che si esca troppo presto

+        // i servizi notSubribed si registrano soltanto dopo ""

+		if(oldSids==null) return;

+		

+		for (int i = 0; i < notSubscribed.size(); i++) {

+			Service ser = (Service) notSubscribed.elementAt(i);

+			subqueue.enqueue(new FirstMessage(ser, listener));

+		}

+		

+		for (int i = 0; i < oldSids.size(); i++) {

+			String oldSid = (String) oldSids.elementAt(i);

+			if (!subscribed.contains(oldSid)) {

+                // francesco-renew

+                // qua si rimuove il sid dalla lista Listner2Sids

+                // ma il Listner dalla lista sid2Listener?

+                // la delListner che si esegue dopo � pensata per rimuovere principalmente i

+                // listener e ci sono condizioni es. Lista Listener2Sid vuota

+                // che nn fanno rimuovere eventuali listener dalla sid2Listener

+                // controllare bene !!

+                

+				

+				unsubscribeListenerForSid(oldSid,listener,ctrl);

+			}

+		}

+

+	}

+    

+	/**

+	 * Unregister the listener as UPnPListener for the UPnPService with

+	 * the spicfied SID

+	 * 

+     * @param sid

+     * @param listener

+     * @param ctrl

+     */

+    private void unsubscribeListenerForSid(String sid, UPnPEventListener listener, MyCtrlPoint ctrl) {

+        Vector listeners = sidListSid.getListenersFromSid(sid);

+        listeners.remove(listener);

+        if(listeners.size()==0){

+			Service service = ctrl.serviceFromSid(sid);

+			if (service != null) {

+				boolean ok = ctrl.unsubscribe(service);

+				if (!ok) {

+				    //TODO Log?

+					service.clearSID();

+				}

+			}

+			sidListSid.setAlreadyFirst(sid,false);

+			sidStateVars.remove(sid);

+		}

+        Vector sids = sidListSid.getSidsFromListener(listener);

+        sids.remove(sid);

+        if(sids.size()==0){

+            sidListSid.removeListenerKey(listener);

+        }

+    }

+

+    public synchronized void delSid(String sid) {

+		Vector listeners = sidListSid.getListenersFromSid(sid);

+		if(listeners==null)return;

+		for (int i = 0; i < listeners.size(); i++) {

+			Vector sids = sidListSid.getSidsFromListener((UPnPEventListener) listeners

+					.elementAt(i));

+			sids.remove(sid);

+		}

+		sidListSid.removeSidKey(sid);

+	}

+

+	public synchronized void clearAll(String sid, Service service) {

+		service.clearSID();

+		delSid(sid);

+		sidStateVars.remove(sid);

+	}

+

+}
\ No newline at end of file
diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/structs/NotifierQueue.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/structs/NotifierQueue.java
new file mode 100644
index 0000000..409e04c
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/structs/NotifierQueue.java
@@ -0,0 +1,54 @@
+/*

+ *   Copyright 2006 The Apache Software Foundation

+ *

+ *   Licensed under the Apache License, Version 2.0 (the "License");

+ *   you may not use this file except in compliance with the License.

+ *   You may obtain a copy of the License at

+ *

+ *       http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *   Unless required by applicable law or agreed to in writing, software

+ *   distributed under the License is distributed on an "AS IS" BASIS,

+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *   See the License for the specific language governing permissions and

+ *   limitations under the License.

+ *

+ */

+

+package org.apache.felix.upnp.basedriver.importer.core.event.structs;

+

+import java.util.Vector;

+

+/**

+ * @author Matteo "matted" Demuru

+ *         

+ */

+public class NotifierQueue {

+	private Vector queue;

+	

+	public NotifierQueue(){

+		queue=new Vector();

+	}

+	

+	public synchronized void enqueue(Object obj){

+		queue.add(obj);

+		if(queue.size() == 1){

+			notify();

+		}

+		

+	}

+	

+	public synchronized Object dequeue(){

+		while(queue.size()==0){

+			try {

+				wait();

+			} catch (InterruptedException e) {

+				// TODO Auto-generated catch block

+				e.printStackTrace();

+			}

+		}

+		

+		return queue.remove(0);

+	}

+

+}

diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/structs/Sid2Listeners.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/structs/Sid2Listeners.java
new file mode 100644
index 0000000..85ddfd3
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/structs/Sid2Listeners.java
@@ -0,0 +1,84 @@
+/*

+ *   Copyright 2006 The Apache Software Foundation

+ *

+ *   Licensed under the Apache License, Version 2.0 (the "License");

+ *   you may not use this file except in compliance with the License.

+ *   You may obtain a copy of the License at

+ *

+ *       http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *   Unless required by applicable law or agreed to in writing, software

+ *   distributed under the License is distributed on an "AS IS" BASIS,

+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *   See the License for the specific language governing permissions and

+ *   limitations under the License.

+ *

+ */

+

+package org.apache.felix.upnp.basedriver.importer.core.event.structs;

+

+import java.util.Dictionary;

+import java.util.Hashtable;

+import java.util.Vector;

+

+import org.osgi.service.upnp.UPnPEventListener;

+

+/**

+ * @author Matteo "matted" Demuru

+ *

+ */

+public class Sid2Listeners {

+	private Hashtable sidListener;

+	private Hashtable alreadyfirst;

+    

+	public Sid2Listeners() {

+		this.sidListener = new Hashtable();

+		this.alreadyfirst = new Hashtable();

+	}

+    

+	public void put(String sid, UPnPEventListener listener) {

+		if (!sidListener.containsKey(sid)) {

+			Vector vec = new Vector();

+			vec.add(listener);

+			sidListener.put(sid, vec);

+		} else {

+			Vector vec = (Vector) sidListener.get(sid);

+			if (!vec.contains(listener)) {

+				vec.add(listener);

+			}

+		}

+	}

+

+	public final void remove(String sid) {

+		sidListener.remove(sid);

+	}

+

+	public final Vector get(String sid) {

+		return ((Vector) sidListener.get(sid));

+	}

+

+    /**

+	 * @param sid

+	 * @param dictionary

+	 */

+	public boolean updateListeners(String sid, String deviceID,String serviceID, Dictionary dictionary) {

+        

+		Vector listeners = (Vector) sidListener.get(sid);

+		if (listeners != null) {

+			for (int i = 0; i < listeners.size(); i++) {

+				UPnPEventListener listener = (UPnPEventListener) listeners.elementAt(i);

+				listener.notifyUPnPEvent(deviceID, serviceID, dictionary);

+			}

+			return true;

+		}

+		return false;

+	}

+    

+	public boolean getAlreadyFirst(String sid) {

+		return ((Boolean) alreadyfirst.get(sid)).booleanValue();

+	}

+

+    public void setAlreadyFirst(String sid, boolean bool) {

+		alreadyfirst.put(sid, new Boolean(bool));

+	}

+}
\ No newline at end of file
diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/structs/SidRenewer.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/structs/SidRenewer.java
new file mode 100644
index 0000000..4525048
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/structs/SidRenewer.java
@@ -0,0 +1,49 @@
+/*

+ *   Copyright 2006 The Apache Software Foundation

+ *

+ *   Licensed under the Apache License, Version 2.0 (the "License");

+ *   you may not use this file except in compliance with the License.

+ *   You may obtain a copy of the License at

+ *

+ *       http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *   Unless required by applicable law or agreed to in writing, software

+ *   distributed under the License is distributed on an "AS IS" BASIS,

+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *   See the License for the specific language governing permissions and

+ *   limitations under the License.

+ *

+ */

+

+package org.apache.felix.upnp.basedriver.importer.core.event.structs;

+

+

+import java.util.Hashtable;

+

+import org.apache.felix.upnp.basedriver.importer.core.event.thread.Renewer;

+

+/**

+ * @author Matteo "matted" Demuru

+ *

+ */

+public class SidRenewer {

+private Hashtable hash;

+

+	/**

+	 * @param hash

+	 */

+	public SidRenewer() {

+		super();

+		this.hash = new Hashtable();

+	}

+

+	public synchronized void put(String sid, Renewer renewer){

+		hash.put(sid,renewer);

+	}

+	public synchronized Renewer get(String sid){

+		return (Renewer)hash.get(sid);

+	}

+	public synchronized void remove(String sid){

+		hash.remove(sid);

+	}

+}

diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/structs/SidsListenersMaps.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/structs/SidsListenersMaps.java
new file mode 100644
index 0000000..3e47be2
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/structs/SidsListenersMaps.java
@@ -0,0 +1,78 @@
+/*

+ *   Copyright 2006 The Apache Software Foundation

+ *

+ *   Licensed under the Apache License, Version 2.0 (the "License");

+ *   you may not use this file except in compliance with the License.

+ *   You may obtain a copy of the License at

+ *

+ *       http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *   Unless required by applicable law or agreed to in writing, software

+ *   distributed under the License is distributed on an "AS IS" BASIS,

+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *   See the License for the specific language governing permissions and

+ *   limitations under the License.

+ *

+ */

+

+package org.apache.felix.upnp.basedriver.importer.core.event.structs;

+

+import java.util.Dictionary;

+import java.util.Vector;

+

+import org.osgi.service.upnp.UPnPEventListener;

+

+/**

+ * This class contain two table:

+ *  - sid2listener: have SID of Suscribed Service as key and a Vector of UPnPEventListener as value

+ *  - listener2sids: have an UPnPEventListener as kay and a Vector of SID of Scriscrobed Service 

+ * 

+ * @author Matteo "matted" Demuru

+ * @author Francesco Furfari 

+ * @author Stefano "Kismet" Lenzi

+ * 

+ *

+ */

+public class SidsListenersMaps {

+	private Sid2Listeners sid2Listeners;

+	private Listener2Sids listeners2Sids;

+	

+	public SidsListenersMaps(){

+		sid2Listeners=new Sid2Listeners();

+		listeners2Sids=new Listener2Sids();

+	}

+    

+    

+	/////////////////// Sid to Listeners //////////////////////////////////

+	public final void putSid2Listeners(String sid, UPnPEventListener listener) {

+		sid2Listeners.put(sid,listener);

+	}

+    public final Vector getListenersFromSid(String sid) {

+        return sid2Listeners.get(sid);

+    }

+    public final void removeSidKey(String sid) {

+        sid2Listeners.remove(sid);

+    }

+	public final boolean updateListeners(String sid, String deviceID, String serviceID,Dictionary dictionary){

+		return sid2Listeners.updateListeners(sid,deviceID,serviceID,dictionary);

+	}

+	public final boolean getAlreadyFirst(String sid) {

+		return sid2Listeners.getAlreadyFirst(sid);

+	}

+	public final void setAlreadyFirst(String sid, boolean bool) {

+		sid2Listeners.setAlreadyFirst(sid,bool);

+	}

+    

+    

+    

+    /////////////////// Listener to Sids //////////////////////////////////

+	public final void putListener2Sids(UPnPEventListener listener,String sid) {

+		listeners2Sids.put(listener,sid);

+	}

+	public final Vector getSidsFromListener(UPnPEventListener listener){

+		return listeners2Sids.get(listener);

+	}

+	public final void removeListenerKey(UPnPEventListener listener){

+		listeners2Sids.remove(listener);

+	}

+}
\ No newline at end of file
diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/structs/StateVarsToNotify.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/structs/StateVarsToNotify.java
new file mode 100644
index 0000000..e9ec10f
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/structs/StateVarsToNotify.java
@@ -0,0 +1,67 @@
+/*

+ *   Copyright 2006 The Apache Software Foundation

+ *

+ *   Licensed under the Apache License, Version 2.0 (the "License");

+ *   you may not use this file except in compliance with the License.

+ *   You may obtain a copy of the License at

+ *

+ *       http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *   Unless required by applicable law or agreed to in writing, software

+ *   distributed under the License is distributed on an "AS IS" BASIS,

+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *   See the License for the specific language governing permissions and

+ *   limitations under the License.

+ *

+ */

+

+package org.apache.felix.upnp.basedriver.importer.core.event.structs;

+

+

+import java.util.Dictionary;

+import java.util.Enumeration;

+

+import org.apache.felix.upnp.basedriver.importer.core.event.message.StateChanged;

+

+/**

+ * @author Matteo "matted" Demuru

+ * 

+ */

+public class StateVarsToNotify {

+	private Dictionary stateVars;

+	private String sid;

+	private String deviceID;

+	private String serviceID;

+    

+    //public StateVarsToNotify(String sid, String deviceID, String serviceID,Dictionary dic) {

+    public StateVarsToNotify(StateChanged msg) {

+		this.stateVars= msg.getDictionary();

+		this.sid = msg.getSid();

+		this.deviceID = msg.getDeviceID();

+		this.serviceID = msg.getServiceID();

+	}

+

+

+	public synchronized Dictionary getDictionary() {

+			return stateVars;

+	}

+    public synchronized String getSid() {

+		return sid;

+	}

+	public synchronized String getDeviceID() {

+		return deviceID;

+	}

+	public synchronized String getServiceID() {

+		return serviceID;

+	}

+    

+    

+	public void updateDic(Dictionary dic){

+		Enumeration e=dic.keys();

+		while(e.hasMoreElements()){

+			String varName=(String)e.nextElement();

+			Object varValue=dic.get(varName);

+			stateVars.put(varName,varValue);

+		}

+	}

+}
\ No newline at end of file
diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/structs/SubscriptionQueue.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/structs/SubscriptionQueue.java
new file mode 100644
index 0000000..4275f9e
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/structs/SubscriptionQueue.java
@@ -0,0 +1,53 @@
+/*

+ *   Copyright 2006 The Apache Software Foundation

+ *

+ *   Licensed under the Apache License, Version 2.0 (the "License");

+ *   you may not use this file except in compliance with the License.

+ *   You may obtain a copy of the License at

+ *

+ *       http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *   Unless required by applicable law or agreed to in writing, software

+ *   distributed under the License is distributed on an "AS IS" BASIS,

+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *   See the License for the specific language governing permissions and

+ *   limitations under the License.

+ *

+ */

+

+package org.apache.felix.upnp.basedriver.importer.core.event.structs;

+

+import java.util.Vector;

+

+

+

+/**

+ * @author Matteo "matted" Demuru

+ *

+ */

+public class SubscriptionQueue {

+	private Vector queue;

+	

+	public SubscriptionQueue(){

+		queue=new Vector();

+	}

+	public synchronized void enqueue(Object obj){

+		queue.add(obj);

+		if(queue.size()==1){

+			notify();

+		}

+	}

+	public synchronized Object dequeue(){

+		while(queue.size()==0){

+			try {

+				wait();

+			} catch (InterruptedException e) {

+				// TODO Auto-generated catch block

+				e.printStackTrace();

+			}

+		}

+		return queue.remove(0); 

+	}	

+	

+

+}

diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/thread/Notifier.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/thread/Notifier.java
new file mode 100644
index 0000000..30ca333
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/thread/Notifier.java
@@ -0,0 +1,55 @@
+/*

+ *   Copyright 2006 The Apache Software Foundation

+ *

+ *   Licensed under the Apache License, Version 2.0 (the "License");

+ *   you may not use this file except in compliance with the License.

+ *   You may obtain a copy of the License at

+ *

+ *       http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *   Unless required by applicable law or agreed to in writing, software

+ *   distributed under the License is distributed on an "AS IS" BASIS,

+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *   See the License for the specific language governing permissions and

+ *   limitations under the License.

+ *

+ */

+

+package org.apache.felix.upnp.basedriver.importer.core.event.thread;

+

+import org.apache.felix.upnp.basedriver.importer.core.event.message.StateChanged;

+import org.apache.felix.upnp.basedriver.importer.core.event.structs.Monitor;

+import org.apache.felix.upnp.basedriver.importer.core.event.structs.NotifierQueue;

+import org.apache.felix.upnp.basedriver.importer.core.event.structs.StateVarsToNotify;

+

+

+/**

+ * @author Matteo "matted" Demuru
+ * @author Stefano "kismet-sl" Lenzi
+ * 

+ */

+public class Notifier extends Thread {

+

+	private NotifierQueue notifierQueue;

+	private Monitor monitor;

+

+    public Notifier(NotifierQueue notifierQueue,Monitor monitor) {

+		super("Notifier");

+		this.notifierQueue = notifierQueue;

+		this.monitor = monitor;

+		

+	}

+

+	public void run() {

+		while (true) {

+            StateChanged msg = (StateChanged) notifierQueue.dequeue();

+				StateVarsToNotify vars = null;

+				if (msg.getSeq() == 0) {

+					vars = new StateVarsToNotify(msg);

+					monitor.putStateVars(msg.getSid(),vars);

+				} else {

+					monitor.updateStateVars(msg.getSid(),msg.getDictionary());

+				}

+		}

+	}

+}
\ No newline at end of file
diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/thread/Renewer.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/thread/Renewer.java
new file mode 100644
index 0000000..cf87bcf
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/thread/Renewer.java
@@ -0,0 +1,86 @@
+/*

+ *   Copyright 2006 The Apache Software Foundation

+ *

+ *   Licensed under the Apache License, Version 2.0 (the "License");

+ *   you may not use this file except in compliance with the License.

+ *   You may obtain a copy of the License at

+ *

+ *       http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *   Unless required by applicable law or agreed to in writing, software

+ *   distributed under the License is distributed on an "AS IS" BASIS,

+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *   See the License for the specific language governing permissions and

+ *   limitations under the License.

+ *

+ */

+

+package org.apache.felix.upnp.basedriver.importer.core.event.thread;

+

+

+import org.cybergarage.upnp.Service;

+

+import org.apache.felix.upnp.basedriver.importer.core.MyCtrlPoint;

+import org.apache.felix.upnp.basedriver.importer.core.event.message.SidExipired;

+import org.apache.felix.upnp.basedriver.importer.core.event.structs.SubscriptionQueue;

+

+/**

+ * @author Matteo "matted" Demuru

+ * @author Stefano "kismet-sl" Lenzi

+ * @author Francesco Furfari

+ *         

+ *

+ */

+public class Renewer extends Thread {

+	private long timeout;

+	private String sid;

+	private Service service;

+	private MyCtrlPoint ctrl;

+	private boolean bool;

+	private SubscriptionQueue subqueue;

+	private final long time_before_renew=60000;

+	/**

+	 * *

+	 * 

+	 * @param timeout

+	 * @param sid

+	 * @param service

+	 */

+    public Renewer(long timeout, String sid, Service service,

+            MyCtrlPoint ctrl,SubscriptionQueue subqueue) {

+		super("ReNewal" + sid);

+		if (timeout - time_before_renew > 0) {

+			this.timeout = timeout - time_before_renew;

+		} else {

+			this.timeout = timeout;

+		}

+		this.sid = sid;

+		this.service = service;

+		this.ctrl = ctrl;

+		bool = true;

+		this.subqueue=subqueue;

+	}

+	public void run() {

+		while (bool) {

+			try {

+				sleep(timeout);

+			} catch (InterruptedException e) {

+				// TODO Auto-generated catch block

+				e.printStackTrace();

+			}

+			boolean ok = ctrl.subscribe(service, sid, 180000);

+			if (ok) {//renew ok

+				if (service.getTimeout() - time_before_renew > 0) {

+					timeout = service.getTimeout() - time_before_renew;

+				} else {

+					timeout = service.getTimeout();

+				}

+			} else {//renew not ok

+				bool=false;

+				//System.out.println("morto renewer");

+				subqueue.enqueue(new SidExipired(sid,service));

+			}

+		}

+	}

+

+}
\ No newline at end of file
diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/thread/SubScriber.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/thread/SubScriber.java
new file mode 100644
index 0000000..ab36182
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/event/thread/SubScriber.java
@@ -0,0 +1,107 @@
+/*

+ *   Copyright 2006 The Apache Software Foundation

+ *

+ *   Licensed under the Apache License, Version 2.0 (the "License");

+ *   you may not use this file except in compliance with the License.

+ *   You may obtain a copy of the License at

+ *

+ *       http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *   Unless required by applicable law or agreed to in writing, software

+ *   distributed under the License is distributed on an "AS IS" BASIS,

+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *   See the License for the specific language governing permissions and

+ *   limitations under the License.

+ *

+ */

+

+package org.apache.felix.upnp.basedriver.importer.core.event.thread;

+

+

+import org.cybergarage.upnp.Service;

+

+import org.osgi.service.log.LogService;

+

+import org.apache.felix.upnp.basedriver.Activator;

+import org.apache.felix.upnp.basedriver.importer.core.MyCtrlPoint;

+import org.apache.felix.upnp.basedriver.importer.core.event.message.FirstMessage;

+import org.apache.felix.upnp.basedriver.importer.core.event.message.ListenerModified;

+import org.apache.felix.upnp.basedriver.importer.core.event.message.ListenerUnRegistration;

+import org.apache.felix.upnp.basedriver.importer.core.event.message.SidExipired;

+import org.apache.felix.upnp.basedriver.importer.core.event.structs.Monitor;

+import org.apache.felix.upnp.basedriver.importer.core.event.structs.SubscriptionQueue;

+

+/**

+ * @author Matteo "matted" Demuru

+ * @author Stefano "kismet-sl" Lenzi

+ * @author Francesco Furfari

+ *         
+ *

+ */

+public class SubScriber extends Thread {

+

+	private MyCtrlPoint ctrl;

+	private SubscriptionQueue subQueue;

+    private boolean stopCond = true;

+	//##renew private SidRenewer sidRenew;

+	private Monitor monitor;

+

+    

+    public SubScriber(MyCtrlPoint ctrl, SubscriptionQueue subQueue, Monitor monitor) {

+		super("Subscriber");

+		this.ctrl = ctrl;

+		this.subQueue = subQueue;

+		this.monitor=monitor;

+		//##renew this.sidRenew = new SidRenewer();

+		

+	}

+

+	public void run() {

+		while (stopCond) {

+			Object msg = subQueue.dequeue();

+			if (msg instanceof FirstMessage) {

+				FirstMessage firstmsg = (FirstMessage) msg;

+				Service service = firstmsg.getService();

+				if (!service.isSubscribed()) {//is not subscribe

+					boolean ok = ctrl.subscribe(service,120000);

+					String sid = "";

+					if (ok) {//subcribe ok

+                        

+						sid = service.getSID();

+						firstmsg.setSid(sid);

+                        // ########### Renew ########################

+//                      ##renew Renewer renewer = new Renewer((service.getTimeout()),

+//                      ##renew 		sid, service, ctrl,	subQueue);

+//                      ##renew sidRenew.put(sid, renewer);

+//                      ##renew renewer.start();

+                        // ########### Renew ########################

+						//StateVarsToNotify vars=monitor.getStateVars(sid);

+                        

+						monitor.addListener(sid,firstmsg.getListener());						

+					} else {//subscribe not ok

+						Activator.logger.log(LogService.LOG_ERROR,"Sucribe failed");

+					}

+				} else {// already subscribe

+					monitor.addListener(service.getSID(),firstmsg.getListener());

+				}

+			} else if (msg instanceof ListenerModified) {

+                // ########### Renew ########################

+				monitor.updateListener((ListenerModified)msg,subQueue,ctrl/*##renew ,sidRenew*/);

+                // ########### Renew ########################

+			} else if (msg instanceof ListenerUnRegistration) {

+				ListenerUnRegistration unreg=(ListenerUnRegistration)msg;

+                // ########### Renew ########################

+				monitor.delListener(unreg.getListener(),ctrl/*##renew,sidRenew*/);

+                // ########### Renew ########################

+			} else if(msg instanceof SidExipired){

+			    Activator.logger.WARNING("[Importer] Please report the bug.Used code - should be checked and removed");

+			    /*

+				Activator.logger.INFO("Removing Expired Subscribe Service");

+				SidExipired sidExpired=(SidExipired)msg;

+				monitor.clearAll(sidExpired.getSid(),sidExpired.getService());

+				*/

+			}

+		}

+	}

+

+}
\ No newline at end of file
diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/upnp/UPnPActionImpl.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/upnp/UPnPActionImpl.java
new file mode 100644
index 0000000..7f82fa4
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/upnp/UPnPActionImpl.java
@@ -0,0 +1,188 @@
+/*

+ *   Copyright 2006 The Apache Software Foundation

+ *

+ *   Licensed under the Apache License, Version 2.0 (the "License");

+ *   you may not use this file except in compliance with the License.

+ *   You may obtain a copy of the License at

+ *

+ *       http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *   Unless required by applicable law or agreed to in writing, software

+ *   distributed under the License is distributed on an "AS IS" BASIS,

+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *   See the License for the specific language governing permissions and

+ *   limitations under the License.

+ *

+ */

+

+package org.apache.felix.upnp.basedriver.importer.core.upnp;

+

+

+import java.util.Dictionary;

+import java.util.Properties;

+

+import org.cybergarage.upnp.Action;

+import org.cybergarage.upnp.Argument;

+import org.cybergarage.upnp.ArgumentList;

+import org.cybergarage.upnp.UPnPStatus;

+

+import org.osgi.service.upnp.UPnPAction;

+import org.osgi.service.upnp.UPnPStateVariable;

+

+import org.apache.felix.upnp.extra.util.Converter;

+import org.apache.felix.upnp.extra.util.UPnPException;

+

+/**

+ * @author Matteo "matted" Demuru
+ * @author Stefanoi "kismet-sl" Lenzi
+ * 

+ */

+public class UPnPActionImpl implements UPnPAction {

+

+	private Action act;	

+	private UPnPServiceImpl actsFather;

+	/**

+	 * @param act

+	 */

+	public UPnPActionImpl(Action act,UPnPServiceImpl ser) {

+		// TODO to check

+		this.act=act;

+		actsFather=ser;	

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPAction#getName()

+	 */

+	public String getName() {

+		// TODO to check

+		return act.getName();

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPAction#getReturnArgumentName()

+	 */

+	public String getReturnArgumentName() {

+	/*	 TODO da discutere .. perche' mi dovrei riparsare l'xml 

+		 */

+		

+		return null;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPAction#getInputArgumentNames()

+	 */

+	public String[] getInputArgumentNames() {

+		// TODO to check

+		ArgumentList argsList=act.getInputArgumentList();

+		if(argsList.size()==0){

+			return null;

+		}

+		String [] inputArgs=new String[argsList.size()]; 

+		for(int i=0;i<argsList.size();i++){

+			inputArgs[i]=argsList.getArgument(i).getName();

+		}

+		return inputArgs;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPAction#getOutputArgumentNames()

+	 */

+	public String[] getOutputArgumentNames() {

+		// TODO to check

+		ArgumentList argsList=act.getOutputArgumentList();

+		if(argsList.size()==0){

+			return null;

+		}

+		String [] outArgs=new String[argsList.size()]; 

+		for(int i=0;i<argsList.size();i++){

+			outArgs[i]=argsList.getArgument(i).getName();

+		}

+		return outArgs;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPAction#getStateVariable(java.lang.String)

+	 */

+	public UPnPStateVariable getStateVariable(String argumentName) {

+		/*TODO  controllare se non e' 

+		troppo brutto il modo di ottenere 

+		la UPnPStateVariable

+		

+		check if the way to obtain the UPnPStateVariabile is not too bad

+		

+		*/

+		Argument arg=act.getArgument(argumentName);

+		if(arg==null){

+			return null;

+		}

+		String varName=arg.getRelatedStateVariableName();

+		return actsFather.getStateVariable(varName);

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPAction#invoke(java.util.Dictionary)

+	 */

+	public Dictionary invoke(Dictionary args) throws Exception {

+		/*TODO da controllare se ho capito bene quello che 

+		richiedeva il metodo

+		

+		check if I have understood wath this method should do

+		*/

+		/*

+		 * mi ricavo gli argomenti e i valori

+		 * e gli inserisco in un ArgumentList

+		 * 

+		 * I look for argument and value and then I add them to ArgumentList

+		 */

+		ArgumentList argsList=new ArgumentList();

+		argsList= act.getInputArgumentList();

+	

+		for(int i=0;i<argsList.size();i++){

+			/*

+			TODO assumo che .getArgument(i) mi dia un Argument con solo il nome e non il valore 

+			che sara' cio che ci mettero' io 

+			e assumo anche che siano ordinati

+			

+			 * I assert that .getArgument(i) will return to me an Argument with only the name of the

+			 * Argument and not it's value. I'll set the associated value by myself and

+			 * Also I assert that the Argument are ordered

+			 */

+			Argument argument=argsList.getArgument(i);

+			String argumentName=argument.getName();

+			//String relateVar=argument.getRelatedStateVariableName();

+			UPnPStateVariable stateVar=this.getStateVariable(argumentName);

+			String upnpType=stateVar.getUPnPDataType();

+			/*Class javaClass=stateVar.getJavaDataType();*/

+			//setto il valore dell'argomento di input

+			//setting the value related to the input argument

+			argument.setValue(Converter.toString(args.get(argumentName),upnpType));

+		}

+		act.setArgumentValues(argsList);

+		if(act.postControlAction()==true){

+			//TODO controllare cosa succede se non ho argomenti di out 

+			//TODO check what happen if I don't have any output argument

+			Properties outDic=new Properties();

+			ArgumentList outArgs=act.getOutputArgumentList();

+			if(outArgs.size()==0){

+				return null;

+			}

+			for(int i=0;i<outArgs.size();i++){

+				Argument argument=outArgs.getArgument(i);

+				String argumentName=outArgs.getArgument(i).getName();

+				//String relateVar=argument.getRelatedStateVariableName();

+				UPnPStateVariable stateVar=getStateVariable(argumentName);

+				//String javaType=stateVar.getJavaDataType().getName(); 

+				//TODO ricordarsi di catchare nunber exception

+				//TODO rember to catch number exception

+				String upnpType=stateVar.getUPnPDataType();

+				outDic.put(argumentName,Converter.parseString(argument.getValue(),upnpType));

+			}

+			return outDic;

+		}else{

+            UPnPStatus controlStatus = act.getControlStatus();

+            throw new UPnPException(controlStatus.getCode(),controlStatus.getDescription());

+		}

+

+	}

+

+}

diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/upnp/UPnPDeviceImpl.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/upnp/UPnPDeviceImpl.java
new file mode 100644
index 0000000..f877dc3
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/upnp/UPnPDeviceImpl.java
@@ -0,0 +1,146 @@
+/*

+ *   Copyright 2006 The Apache Software Foundation

+ *

+ *   Licensed under the Apache License, Version 2.0 (the "License");

+ *   you may not use this file except in compliance with the License.

+ *   You may obtain a copy of the License at

+ *

+ *       http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *   Unless required by applicable law or agreed to in writing, software

+ *   distributed under the License is distributed on an "AS IS" BASIS,

+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *   See the License for the specific language governing permissions and

+ *   limitations under the License.

+ *

+ */

+

+package org.apache.felix.upnp.basedriver.importer.core.upnp;

+

+

+import java.util.Dictionary;

+import java.util.Enumeration;

+import java.util.Hashtable;

+import java.util.Vector;

+

+import org.cybergarage.upnp.Device;

+

+import org.osgi.framework.BundleContext;

+import org.osgi.service.upnp.UPnPDevice;

+import org.osgi.service.upnp.UPnPIcon;

+import org.osgi.service.upnp.UPnPService;

+

+import org.apache.felix.upnp.basedriver.importer.util.DeviceSetup;

+import org.apache.felix.upnp.basedriver.importer.util.DictionaryProp;

+

+/**

+ * @author Matteo "matted" Demuru
+ * @author Stefanoi "kismet-sl" Lenzi
+ * 

+ */

+public class UPnPDeviceImpl implements UPnPDevice {

+

+	/**

+	 * <code>properties</code> Dictionary that contains Device properties

+	 */

+	private DictionaryProp properties;

+	private Vector icons;

+	private Hashtable services;

+	/**

+	 * @param dev

+	 *            Device the cyberLink Device used to rappresent the real UPnP

+	 *            Device

+	 */

+	public UPnPDeviceImpl(Device dev, BundleContext context) {

+		properties = new DictionaryProp();

+		this.services=new Hashtable();

+		this.icons=new Vector();

+		DeviceSetup.deviceSetup(properties,dev,icons,services);

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.osgi.service.upnp.UPnPDevice#getService(java.lang.String)

+	 */

+	public UPnPService getService(String serviceId) {

+		return (UPnPServiceImpl) services.get(serviceId);

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.osgi.service.upnp.UPnPDevice#getServices()

+	 */

+	public UPnPService[] getServices() {

+		Enumeration e = services.elements();

+		if (e == null) {

+			//TODO restituisco null o un array vuoto null l'ho letto nella specifica

+			//TODO should I return null or an empty array? The specification seems to said to return null

+			return null;

+		}

+		UPnPService[] uPnPser = new UPnPService[services.size()];

+		int i = 0;

+		while (e.hasMoreElements()) {

+			uPnPser[i] = (UPnPServiceImpl) e.nextElement();

+			i++;

+		}

+		return uPnPser;

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.osgi.service.upnp.UPnPDevice#getIcons(java.lang.String)

+	 */

+	public UPnPIcon[] getIcons(String locale) {

+		if (locale != null) {

+			return null;

+		}

+		if(icons.size()==0){

+			return null;

+		}

+		return (UPnPIcon[]) icons.toArray(new UPnPIcon[]{});

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.osgi.service.upnp.UPnPDevice#getDescriptions(java.lang.String)

+	 */

+

+	public Dictionary getDescriptions(String locale) {

+		//TODO Sent the right localized version of Description if are available

+		if (locale != null) {

+			return null;

+		}

+		return properties;

+	}

+

+	/**

+	 * @param serviceType

+	 * @return true if device contains the serviceType

+	 */

+	public boolean existServiceType(String serviceType) {

+		String[] services = (String[]) properties.get(UPnPService.TYPE);

+		if (services != null) {

+			for (int i = 0; i < services.length; i++) {

+				if (services[i].equals(serviceType)) {

+					return true;

+				}

+			}

+		}

+		return false;

+	}

+

+	/**

+	 * @param property

+	 * @param obj

+	 */

+	public void setProperty(String property, Object obj) {

+		properties.remove(property);

+		properties.put(property, obj);

+

+	}

+

+}
\ No newline at end of file
diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/upnp/UPnPIconImpl.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/upnp/UPnPIconImpl.java
new file mode 100644
index 0000000..24248ff
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/upnp/UPnPIconImpl.java
@@ -0,0 +1,111 @@
+/*

+ *   Copyright 2006 The Apache Software Foundation

+ *

+ *   Licensed under the Apache License, Version 2.0 (the "License");

+ *   you may not use this file except in compliance with the License.

+ *   You may obtain a copy of the License at

+ *

+ *       http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *   Unless required by applicable law or agreed to in writing, software

+ *   distributed under the License is distributed on an "AS IS" BASIS,

+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *   See the License for the specific language governing permissions and

+ *   limitations under the License.

+ *

+ */

+

+package org.apache.felix.upnp.basedriver.importer.core.upnp;

+

+

+import java.io.IOException;

+import java.io.InputStream;

+import java.net.URL;

+

+import org.cybergarage.upnp.Icon;

+

+import org.osgi.service.upnp.UPnPIcon;

+

+import org.apache.felix.upnp.basedriver.importer.util.HTTPRequestForIcon;

+import org.apache.felix.upnp.basedriver.importer.util.ParseLocation;

+

+/**

+ * @author Matteo "matted" Demuru
+ * @author Stefanoi "kismet-sl" Lenzi
+ * 

+ */

+public class UPnPIconImpl implements UPnPIcon {

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPIcon#getMimeType()

+	 */

+	private Icon icon;

+	private org.cybergarage.upnp.Device cyberdev;

+	public UPnPIconImpl(Icon cybericon,org.cybergarage.upnp.Device cyberdev){

+		this.icon=cybericon;

+		this.cyberdev=cyberdev;

+	}

+	public String getMimeType() {

+		// TODO to check

+		return icon.getMimeType();

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPIcon#getWidth()

+	 */

+	public int getWidth() {

+		// TODO se parso una stringa vuota che succede ? da eccezione?penso di si 

+		//TODO what happen if the String is empty? do I get an Exception? I think so

+		String width=icon.getWidth();

+		if(width.length()==0){

+			return -1;

+		}

+		return Integer.parseInt(width);

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPIcon#getHeight()

+	 */

+	public int getHeight() {

+		// TODO Auto-generated method stub

+		String higth=icon.getHeight();

+		if(higth.length()==0){

+			return -1;

+		}

+		return Integer.parseInt(higth);

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPIcon#getSize()

+	 */

+	public int getSize() {

+		// TODO Auto-generated method stub

+		return -1;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPIcon#getDepth()

+	 */

+	public int getDepth() {

+		// TODO Auto-generated method stub

+		String depth=icon.getDepth();

+		if(depth.length()==0){

+			return -1;

+		}

+		return Integer.parseInt(depth);

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPIcon#getInputStream()

+	 */

+	public InputStream getInputStream() throws IOException {

+		// TODO Auto-generated method stub

+		

+		String urlString=ParseLocation.getUrlBase(cyberdev.getLocation())+icon.getURL();

+		URL url=new URL(urlString);

+		HTTPRequestForIcon requestor=new HTTPRequestForIcon(url);

+		

+		return requestor.getInputStream();

+	}

+

+}

diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/upnp/UPnPServiceImpl.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/upnp/UPnPServiceImpl.java
new file mode 100644
index 0000000..d7c46f7
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/upnp/UPnPServiceImpl.java
@@ -0,0 +1,164 @@
+/*

+ *   Copyright 2006 The Apache Software Foundation

+ *

+ *   Licensed under the Apache License, Version 2.0 (the "License");

+ *   you may not use this file except in compliance with the License.

+ *   You may obtain a copy of the License at

+ *

+ *       http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *   Unless required by applicable law or agreed to in writing, software

+ *   distributed under the License is distributed on an "AS IS" BASIS,

+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *   See the License for the specific language governing permissions and

+ *   limitations under the License.

+ *

+ */

+

+package org.apache.felix.upnp.basedriver.importer.core.upnp;

+

+

+import java.util.Enumeration;

+import java.util.Hashtable;

+

+import org.cybergarage.upnp.Action;

+import org.cybergarage.upnp.ActionList;

+import org.cybergarage.upnp.Service;

+import org.cybergarage.upnp.ServiceStateTable;

+import org.cybergarage.upnp.StateVariable;

+

+import org.osgi.service.upnp.UPnPAction;

+import org.osgi.service.upnp.UPnPService;

+import org.osgi.service.upnp.UPnPStateVariable;

+

+/**

+ * @author Matteo "matted" Demuru
+ * @author Stefanoi "kismet-sl" Lenzi
+ * 

+ */

+public class UPnPServiceImpl implements UPnPService {

+	private Service service;

+	private Hashtable actions;

+	private Hashtable stateVariables;

+	

+	public UPnPServiceImpl(Service service) {

+		this.service = service;

+		actions = new Hashtable();

+		stateVariables=new Hashtable();

+		/*

+		 * azioni

+		 * action

+		 */

+		ActionList actionlist = service.getActionList();

+		for (int i = 0; i < actionlist.size(); i++) {

+			Action act = actionlist.getAction(i);

+			actions.put(act.getName(), new UPnPActionImpl(act,this));

+		}

+		/*StateVariable*/

+		ServiceStateTable stateTable=service.getServiceStateTable();

+		for(int i=0;i<stateTable.size();i++){

+			StateVariable var= stateTable.getStateVariable(i);

+			stateVariables.put(var.getName(),new UPnPStateVariableImpl(var));

+		}

+	

+	

+	} /*

+	   * (non-Javadoc)

+	   * 

+	   * @see org.osgi.service.upnp.UPnPService#getId()

+	   */

+	public String getId() {

+		// TODO Auto-generated method stub

+		return service.getServiceID();

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.osgi.service.upnp.UPnPService#getType()

+	 */

+	public String getType() {

+		// TODO Auto-generated method stub

+		return service.getServiceType();

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.osgi.service.upnp.UPnPService#getVersion()

+	 */

+	public String getVersion() {

+		// TODO da  controllare si puo' migliorare lastindexof

+		//TODO to check can I speed up this? May be using lastIndexOf

+		String [] splited=service.getServiceType().split(":"); 

+		return splited[splited.length-1];

+	} 

+	/*

+	   * (non-Javadoc)

+	   * 

+	   * @see org.osgi.service.upnp.UPnPService#getAction(java.lang.String)

+	   */

+	public UPnPAction getAction(String name) {

+		// TODO da controllare

+		//TODO to check

+		return (UPnPAction) actions.get(name);

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.osgi.service.upnp.UPnPService#getActions()

+	 */

+	public UPnPAction[] getActions() {

+		// TODO ricontrollare

+		//TODO check again

+		Enumeration e=actions.elements();

+		if(e==null){

+			return null;

+		}

+		UPnPAction [] uPnPacts=new UPnPAction[actions.size()];

+		int i=0;

+		while(e.hasMoreElements()){

+			uPnPacts[i]=(UPnPActionImpl)e.nextElement();

+			i++;

+		}

+		return uPnPacts;

+	}

+	

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.osgi.service.upnp.UPnPService#getStateVariables()

+	 */

+	public UPnPStateVariable[] getStateVariables() {

+		// TODO ricontrollare

+		//TODO check again

+		UPnPStateVariableImpl [] vars =new UPnPStateVariableImpl[stateVariables.size()];

+		Enumeration e=stateVariables.elements();

+		if(e==null){

+			return null;

+		}

+		int i=0;

+		while(e.hasMoreElements()){

+			vars[i]=(UPnPStateVariableImpl)e.nextElement();

+			i++;

+		}

+		return vars;

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.osgi.service.upnp.UPnPService#getStateVariable(java.lang.String)

+	 */

+	public UPnPStateVariable getStateVariable(String name) {

+		// TODO ricontrollare	

+		//TODO chack again

+		return (UPnPStateVariableImpl) stateVariables.get(name);

+	}

+

+	public Service getCyberService(){

+		return service;

+	}

+

+}
\ No newline at end of file
diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/upnp/UPnPStateVariableImpl.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/upnp/UPnPStateVariableImpl.java
new file mode 100644
index 0000000..55577b0
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/upnp/UPnPStateVariableImpl.java
@@ -0,0 +1,242 @@
+/*

+ *   Copyright 2006 The Apache Software Foundation

+ *

+ *   Licensed under the Apache License, Version 2.0 (the "License");

+ *   you may not use this file except in compliance with the License.

+ *   You may obtain a copy of the License at

+ *

+ *       http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *   Unless required by applicable law or agreed to in writing, software

+ *   distributed under the License is distributed on an "AS IS" BASIS,

+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *   See the License for the specific language governing permissions and

+ *   limitations under the License.

+ *

+ */

+

+package org.apache.felix.upnp.basedriver.importer.core.upnp;

+

+

+import java.util.Date;

+import java.util.Hashtable;

+

+import org.cybergarage.upnp.AllowedValueList;

+import org.cybergarage.upnp.AllowedValueRange;

+import org.cybergarage.upnp.StateVariable;

+

+import org.osgi.service.upnp.UPnPStateVariable;

+

+import org.apache.felix.upnp.extra.util.Converter;

+

+/**

+ * @author Matteo "matted" Demuru
+ * @author Stefanoi "kismet-sl" Lenzi
+ * 

+ */

+public class UPnPStateVariableImpl implements UPnPStateVariable {

+

+	private StateVariable variable;

+	private static Hashtable upnp2javaTable = null;

+	

+	static{

+		upnp2javaTable = new Hashtable(30);

+		String[] upnpType = null;

+		upnpType = new String[]{"ui1","ui2","i1","i2","i4","int"};

+		for (int i = 0; i < upnpType.length; i++) {

+			upnp2javaTable.put(upnpType[i],Integer.class);

+		}

+

+		upnpType = new String[]{"ui4","time","time.tz"};

+		for (int i = 0; i < upnpType.length; i++) {

+			upnp2javaTable.put(upnpType[i],Long.class);

+		}		

+

+		upnpType = new String[]{"r4","float"};

+		for (int i = 0; i < upnpType.length; i++) {

+			upnp2javaTable.put(upnpType[i],Float.class);

+		}		

+

+		upnpType = new String[]{"r8","number","fixed.14.4"};

+		for (int i = 0; i < upnpType.length; i++) {

+			upnp2javaTable.put(upnpType[i],Double.class);

+		}		

+

+		upnpType = new String[]{"char"};

+		for (int i = 0; i < upnpType.length; i++) {

+			upnp2javaTable.put(upnpType[i],Character.class);

+		}		

+

+		upnpType = new String[]{"string","uri","uuid"};

+		for (int i = 0; i < upnpType.length; i++) {

+			upnp2javaTable.put(upnpType[i],String.class);

+		}		

+

+		upnpType = new String[]{"date","dateTime","dateTime.tz"};

+		for (int i = 0; i < upnpType.length; i++) {

+			upnp2javaTable.put(upnpType[i],Date.class);

+		}		

+

+		upnpType = new String[]{"boolean"};

+		for (int i = 0; i < upnpType.length; i++) {

+			upnp2javaTable.put(upnpType[i],Boolean.class);

+		}		

+

+		upnpType = new String[]{"bin.base64","bin.hex"};

+		for (int i = 0; i < upnpType.length; i++) {

+			upnp2javaTable.put(upnpType[i],byte[].class);

+		}		

+		

+		

+	}

+	

+	/**

+	 * @param variable

+	 */

+	public UPnPStateVariableImpl(StateVariable variable) {

+

+		this.variable = variable;

+	} /*

+	   * (non-Javadoc)

+	   * 

+	   * @see org.osgi.service.upnp.UPnPStateVariable#getName()

+	   */

+

+	public String getName() {

+		return variable.getName();

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.osgi.service.upnp.UPnPStateVariable#getJavaDataType()

+	 */

+	public Class getJavaDataType() {

+		return (Class) upnp2javaTable.get(variable.getDataType());

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.osgi.service.upnp.UPnPStateVariable#getUPnPDataType()

+	 */

+	public String getUPnPDataType() {

+		return variable.getDataType();

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.osgi.service.upnp.UPnPStateVariable#getDefaultValue()

+	 */

+	public Object getDefaultValue() {

+		//TODO da implementare da zero.. e' raccommended ..

+		//TODO must be implemented from scretch, it's just raccommend

+		return null;

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.osgi.service.upnp.UPnPStateVariable#getAllowedValues()

+	 */

+	public String[] getAllowedValues() {

+		if (variable.getDataType().equals("string")) {

+			AllowedValueList allowedvalue = variable.getAllowedValueList();

+            if (allowedvalue == null) return null;

+			if(allowedvalue.size()==0){

+				return null;

+			} 

+			String[] values = new String[allowedvalue.size()];

+			for (int i = 0; i < allowedvalue.size(); i++) {

+				values[i] = allowedvalue.getAllowedValue(i).getValue();

+			}

+			return values;

+		}

+

+		return null;

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.osgi.service.upnp.UPnPStateVariable#getMinimum()

+	 */

+	public Number getMinimum() {

+		// TODO stessa cosa get maximum

+		//TODO the same thing for getMaximum

+		AllowedValueRange allowedValueRange = variable.getAllowedValueRange();

+		if(allowedValueRange==null){

+			return null;

+		}

+		String min=allowedValueRange.getMinimum();

+        //francesco 22/10/2005

+        if (min.equals("")) return null;

+		try {

+			return (Number)Converter.parseString(min,getUPnPDataType());

+		} catch (Exception e) {

+			// TODO Auto-generated catch block

+			e.printStackTrace();

+			return null;

+		}

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.osgi.service.upnp.UPnPStateVariable#getMaximum()

+	 */

+	public Number getMaximum() {

+		// TODO suppongo che le invochino con cognizione di causa ??

+		//TODO I think that this method will be invoked from people that know what is doing

+		AllowedValueRange allowedValueRange = variable.getAllowedValueRange();

+		if(allowedValueRange==null){

+			return null;

+		}

+		String max = allowedValueRange.getMaximum();

+        //francesco 22/10/2005

+        if (max.equals("")) return null;

+		try {

+			return (Number)Converter.parseString(max,getUPnPDataType());

+		} catch (Exception e) {

+			// TODO Auto-generated catch block

+			e.printStackTrace();

+			return null;

+		}

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.osgi.service.upnp.UPnPStateVariable#getStep()

+	 */

+	public Number getStep() {

+		// TODO stssa cosa di getmaximum

+		//TODO same things of getMaxium

+		AllowedValueRange allowedValueRange = variable.getAllowedValueRange();

+		if(allowedValueRange==null){

+			return null;

+		}

+		String step = allowedValueRange.getStep();

+        //francesco 22/10/2005

+        if (step.equals("")) return null;

+		try {

+			return (Number)Converter.parseString(step,getUPnPDataType());

+		} catch (Exception e) {

+			// TODO Auto-generated catch block

+			e.printStackTrace();

+			return null;

+		}

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.osgi.service.upnp.UPnPStateVariable#sendsEvents()

+	 */

+	public boolean sendsEvents() {

+		return variable.isSendEvents();

+	}

+

+

+}

diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/util/DeviceSetup.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/util/DeviceSetup.java
new file mode 100644
index 0000000..0f6ad24
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/util/DeviceSetup.java
@@ -0,0 +1,146 @@
+/*

+ *   Copyright 2006 The Apache Software Foundation

+ *

+ *   Licensed under the Apache License, Version 2.0 (the "License");

+ *   you may not use this file except in compliance with the License.

+ *   You may obtain a copy of the License at

+ *

+ *       http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *   Unless required by applicable law or agreed to in writing, software

+ *   distributed under the License is distributed on an "AS IS" BASIS,

+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *   See the License for the specific language governing permissions and

+ *   limitations under the License.

+ *

+ */

+

+package org.apache.felix.upnp.basedriver.importer.util;

+

+

+import java.util.HashSet;

+import java.util.Hashtable;

+import java.util.Iterator;

+import java.util.Vector;

+

+import org.cybergarage.upnp.Device;

+import org.cybergarage.upnp.DeviceList;

+import org.cybergarage.upnp.IconList;

+import org.cybergarage.upnp.Service;

+import org.cybergarage.upnp.ServiceList;

+

+import org.osgi.service.upnp.UPnPDevice;

+import org.osgi.service.upnp.UPnPIcon;

+import org.osgi.service.upnp.UPnPService;

+

+import org.apache.felix.upnp.basedriver.importer.core.upnp.UPnPIconImpl;

+import org.apache.felix.upnp.basedriver.importer.core.upnp.UPnPServiceImpl;

+import org.apache.felix.upnp.extra.util.Constants;

+

+/**

+ * @author Matteo "matted" Demuru 

+ * @author Stefano "Kismet" Lenzi

+ *  

+ */

+public class DeviceSetup {

+

+	public static void deviceSetup(DictionaryProp properties, Device dev,Vector icons,Hashtable services) {

+		//TODO se non ho device ho una devlist con zero elementi

+		//TODO if I don't have any device, the size of devlist is 0 

+		DeviceList devList = dev.getDeviceList();

+		/* childrenUDN property */

+		if (devList.size() > 0) {

+			String[] childrenUDN = new String[devList.size()];

+			for (int i = 0; i < devList.size(); i++) {

+				childrenUDN[i] = devList.getDevice(i).getUDN();

+			}

+			properties.put(UPnPDevice.CHILDREN_UDN, childrenUDN);

+		}

+		/* DEVICE CATEGORY */

+		properties.put(

+		        org.osgi.service

+		        	.device.Constants.DEVICE_CATEGORY,

+	        	new String[]{UPnPDevice.DEVICE_CATEGORY}

+	        );

+

+		/*UPNP_IMPORT*/

+		properties.put(Constants.UPNP_IMPORT, "http://domoware.isti.cnr.it");

+		

+		/* FRIENDLY_NAME */

+		//TODO controllato in metodo getFriendlyName se non esiste il frinedly mi restituisce una stringa vuota

+		//check the implementation fo getFriendlyName made by CyberLink

+		properties.put(UPnPDevice.FRIENDLY_NAME, dev.getFriendlyName());

+		/* MANUFACTURER */

+		properties.put(UPnPDevice.MANUFACTURER, dev.getManufacture());

+		/* MANUFACTURER_URL */

+		properties.put(UPnPDevice.MANUFACTURER_URL, dev.getManufactureURL());

+		/* MODEL_DESCRIPTION */

+		properties.put(UPnPDevice.MODEL_DESCRIPTION, dev.getModelDescription());

+		/* MODEL_NAME */

+		properties.put(UPnPDevice.MODEL_NAME, dev.getModelName());

+		/* MODEL_NUMBER */

+		properties.put(UPnPDevice.MODEL_NUMBER, dev.getModelNumber());

+		/* MODEL_URL */

+		properties.put(UPnPDevice.MODEL_URL, dev.getModelURL());

+		/* PARENT_UDN */

+		if (!dev.isRootDevice()) {

+			Device parent = dev.getParentDevice();

+			/*Device root = dev.getRootDevice();

+			if (root == null) {

+				System.out.println("il device " + dev.getFriendlyName()

+						+ "non ha root !!!");

+			}*/

+			properties.put(UPnPDevice.PARENT_UDN, parent.getUDN());

+		}

+		/* PRESENTATION_URL */

+		properties.put(UPnPDevice.PRESENTATION_URL, dev.getPresentationURL());

+		/* SERIAL_NUMBER */

+		properties.put(UPnPDevice.SERIAL_NUMBER, dev.getSerialNumber());

+		/* TYPE */

+		properties.put(UPnPDevice.TYPE, dev.getDeviceType());

+		/* UDN */

+		properties.put(UPnPDevice.UDN, dev.getUDN());

+		/* UPC */

+		properties.put(UPnPDevice.UPC, dev.getUPC());

+

+		IconList iconsList = dev.getIconList();

+		if (iconsList.size() != 0) {

+			for (int i = 0; i < iconsList.size(); i++) {

+				UPnPIcon icon = new UPnPIconImpl(iconsList.getIcon(i),dev);

+				icons.add(icon);

+			}

+		}

+		/* 

+		 * servizi del device

+		 * service of this device

+		 */ 

+		ServiceList serviceList = dev.getServiceList();//ok mi restituisce una

+													   // service list con zero

+													   // elementi

+		/*

+		 * if dev contain no service I'll get an empty SserviceList object

+		 */

+		String[] servicesIDProperty = new String[serviceList.size()];

+		String[] servicesTypeProperty;

+		HashSet serTypeSet = new HashSet();

+		for (int i = 0; i < serviceList.size(); i++) {

+			Service service = serviceList.getService(i);

+			UPnPServiceImpl serviceImpl = new UPnPServiceImpl(service);

+			services.put(service.getServiceID(), serviceImpl);

+			servicesIDProperty[i] = serviceImpl.getId();

+			serTypeSet.add(serviceImpl.getType());

+		}

+		servicesTypeProperty = new String[serTypeSet.size()];

+		Iterator iter = serTypeSet.iterator();

+		int i = 0;

+		while (iter.hasNext()) {

+			servicesTypeProperty[i] = (String) iter.next();

+			i++;

+		}

+		properties.put(UPnPService.ID, servicesIDProperty);

+		properties.put(UPnPService.TYPE, servicesTypeProperty);

+

+	

+	}

+

+}
\ No newline at end of file
diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/util/DictionaryProp.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/util/DictionaryProp.java
new file mode 100644
index 0000000..f3e8af0
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/util/DictionaryProp.java
@@ -0,0 +1,123 @@
+/*

+ *   Copyright 2006 The Apache Software Foundation

+ *

+ *   Licensed under the Apache License, Version 2.0 (the "License");

+ *   you may not use this file except in compliance with the License.

+ *   You may obtain a copy of the License at

+ *

+ *       http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *   Unless required by applicable law or agreed to in writing, software

+ *   distributed under the License is distributed on an "AS IS" BASIS,

+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *   See the License for the specific language governing permissions and

+ *   limitations under the License.

+ *

+ */

+

+package org.apache.felix.upnp.basedriver.importer.util;

+

+import java.util.*;

+

+/**

+ * @author Matteo "matted" Demuru

+ *

+ */

+public class DictionaryProp extends Dictionary {

+	private Hashtable hash=null;

+	/* (non-Javadoc)

+	 * @see java.util.Dictionary#size()

+	 */

+

+	public DictionaryProp(){

+		hash=new Hashtable();

+	}

+	

+	public int size() {

+		// TODO Auto-generated method stub

+		return hash.size();

+	}

+

+	/* (non-Javadoc)

+	 * @see java.util.Dictionary#isEmpty()

+	 */

+	public boolean isEmpty() {

+		// TODO Auto-generated method stub

+		return hash.isEmpty();

+	}

+

+	/* (non-Javadoc)

+	 * @see java.util.Dictionary#elements()

+	 */

+	public Enumeration elements() {

+		// TODO Auto-generated method stub

+		return hash.elements();

+	}

+

+	/* (non-Javadoc)

+	 * @see java.util.Dictionary#keys()

+	 */

+	public Enumeration keys() {

+		// TODO Auto-generated method stub

+		return hash.keys();

+	}

+

+	/* (non-Javadoc)

+	 * @see java.util.Dictionary#get(java.lang.Object)

+	 */

+	public Object get(Object key) {

+		// TODO Auto-generated method stub

+		String s=((String)key).toLowerCase();

+		return hash.get(s);

+	}

+

+	/* (non-Javadoc)

+	 * @see java.util.Dictionary#remove(java.lang.Object)

+	 */

+	public Object remove(Object arg0) {

+		// TODO Auto-generated method stub

+		String s=((String)arg0).toLowerCase();

+		return hash.remove(s);

+	}

+

+	/* (non-Javadoc)

+	 * @see java.util.Dictionary#put(java.lang.Object, java.lang.Object)

+	 */

+	public Object put(Object arg0, Object arg1) {

+		// TODO Auto-generated method stub

+		String s=((String)arg0).toLowerCase();

+		return hash.put(s,arg1);

+	}

+

+	/**

+	 * @param key

+	 * @return

+	 */

+	public boolean containsKey(Object key) {

+		//String s=((String)key).toLowerCase();

+		return hash.containsKey(key);

+	}

+

+	public String toString() {

+		StringBuffer sb = new StringBuffer("");

+		Enumeration e = keys();

+		while (e.hasMoreElements()) {

+			String key = (String) e.nextElement();

+			sb.append(key).append(" = ");

+			if(get(key) instanceof String[]){

+				String[] aux = (String[]) get(key);

+				sb.append("[");

+				for (int i = 0; i < aux.length-1; i++) {

+					sb.append(aux[i]).append(",");

+				}

+				if(aux.length>0)

+					sb.append(aux[aux.length-1]);

+				sb.append("]");

+			}else{

+				sb.append(get(key).toString());

+			}

+			sb.append("\n");

+		}

+		return sb.toString();

+	}

+}

diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/util/HTTPRequestForIcon.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/util/HTTPRequestForIcon.java
new file mode 100644
index 0000000..dd19673
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/util/HTTPRequestForIcon.java
@@ -0,0 +1,98 @@
+/*

+ *   Copyright 2006 The Apache Software Foundation

+ *

+ *   Licensed under the Apache License, Version 2.0 (the "License");

+ *   you may not use this file except in compliance with the License.

+ *   You may obtain a copy of the License at

+ *

+ *       http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *   Unless required by applicable law or agreed to in writing, software

+ *   distributed under the License is distributed on an "AS IS" BASIS,

+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *   See the License for the specific language governing permissions and

+ *   limitations under the License.

+ *

+ */

+

+package org.apache.felix.upnp.basedriver.importer.util;

+

+import java.io.*;

+import java.net.*;

+

+/**

+ * @author Matteo "matted" Demuru
+ * @author Stefanoi "kismet-sl" Lenzi
+ *

+ * 

+ * TODO To change the template for this generated type comment go to Window -

+ * Preferences - Java - Code Style - Code Templates

+ */

+public class HTTPRequestForIcon {

+	private URL url;

+

+	public HTTPRequestForIcon(URL url) {

+		this.url = url;

+	}

+	public InputStream getInputStream() throws IOException {

+		//TODO da discutere

+		//TODO we should speak about that

+		InetAddress inet = InetAddress.getByName(url.getHost());

+		int port = url.getPort();

+		Socket socket = null;

+		socket = new Socket(inet, port);

+		OutputStream out = null;

+		out = socket.getOutputStream();

+		String CRLF = "\r\n";

+		url.getFile();

+		String request = "GET " + url.getPath() + " " + "HTTP/1.1" + CRLF

+				+ "Host: " + url.getHost() + CRLF + "Connection: " + "close"

+				+ CRLF + CRLF;

+		//System.out.println(request);

+		byte[] get = request.getBytes();

+		out.write(get, 0, get.length);

+		InputStream in = socket.getInputStream();

+		boolean exit = true;

+		while (exit) {

+			byte[] b = new byte[1];

+			in.read(b, 0, b.length);

+

+			if (b[0] == '\r') {

+				in.read(b, 0, b.length);

+				while (b[0] == '\r') {

+					in.read(b, 0, b.length);

+				}

+				if (b[0] != '\n') {

+					continue;

+				}

+				in.read(b, 0, b.length);

+				if (b[0] != '\r') {

+					continue;

+				}

+				in.read(b, 0, b.length);

+				if (b[0] != '\n') {

+					continue;

+				}

+				exit = false;

+			}

+		}

+

+		return in;

+

+		/*

+		 * utilizzando la classe di satoshi HTTPResponse response=new

+		 * HTTPResponse(in); InputStream

+		 * iconInStream=response.getContentInputStream(); return iconInStream;

+		 * 

+		 */

+		/*

+		 * 

+		 * byte[] buff = new byte[maxLength]; int initial = 0; while (initial <

+		 * maxLength - 1) { int read = 0; read = in.read(buff, initial, 1024);

+		 * if (read == -1) break; initial += read; } System.out.println(new

+		 * String(buff));

+		 */

+

+	}

+

+}
\ No newline at end of file
diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/util/ParseLocation.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/util/ParseLocation.java
new file mode 100644
index 0000000..a401090
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/util/ParseLocation.java
@@ -0,0 +1,30 @@
+/*

+ *   Copyright 2006 The Apache Software Foundation

+ *

+ *   Licensed under the Apache License, Version 2.0 (the "License");

+ *   you may not use this file except in compliance with the License.

+ *   You may obtain a copy of the License at

+ *

+ *       http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *   Unless required by applicable law or agreed to in writing, software

+ *   distributed under the License is distributed on an "AS IS" BASIS,

+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *   See the License for the specific language governing permissions and

+ *   limitations under the License.

+ *

+ */

+

+package org.apache.felix.upnp.basedriver.importer.util;

+

+/**

+ * @author Matteo "matted" Demuru

+ *

+ */

+public class ParseLocation {

+	public static String getUrlBase(String location){

+		//http://148.12.14.144:65888/

+		String [] splited=location.split("/");

+		return splited[0]+"/"+"/"+splited[2];

+	}

+}

diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/util/ParseUSN.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/util/ParseUSN.java
new file mode 100644
index 0000000..511abff
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/util/ParseUSN.java
@@ -0,0 +1,62 @@
+/*

+ *   Copyright 2006 The Apache Software Foundation

+ *

+ *   Licensed under the Apache License, Version 2.0 (the "License");

+ *   you may not use this file except in compliance with the License.

+ *   You may obtain a copy of the License at

+ *

+ *       http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *   Unless required by applicable law or agreed to in writing, software

+ *   distributed under the License is distributed on an "AS IS" BASIS,

+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *   See the License for the specific language governing permissions and

+ *   limitations under the License.

+ *

+ */

+

+package org.apache.felix.upnp.basedriver.importer.util;

+

+/**

+ * @author Matteo "matted" Demuru

+ *

+ */

+public class ParseUSN {

+	boolean service;

+	boolean device;

+	String udn;

+	String serviceType;

+	

+	public ParseUSN(String usn) {

+		String [] splited=usn.split(":"); 	

+		if(splited.length==5||splited.length==2){

+			udn="uuid:"+splited[1];

+			device=true;

+			service=false;

+		}else if(splited.length==8){

+			udn="uuid:"+splited[1];

+			if(splited[5].equals("device")){

+				device=true;

+				service=false;

+			}else{

+				serviceType=splited[3]+":"+splited[4]+":"+splited[5]+":"+splited[6]+":"+splited[7];

+				device=false;

+				service=true;

+			}

+		}

+	}	

+

+	public boolean isService() {

+		return service;

+	}

+	public boolean isDevice() {

+		return device;

+	}

+	public String getUDN() {

+		return udn;

+	}

+	public String getServiceType() {

+		return serviceType;

+	}

+	

+}
\ No newline at end of file
diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/tool/Logger.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/tool/Logger.java
new file mode 100644
index 0000000..f253dfc
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/tool/Logger.java
@@ -0,0 +1,255 @@
+/*

+ *   Copyright 2006 The Apache Software Foundation

+ *

+ *   Licensed under the Apache License, Version 2.0 (the "License");

+ *   you may not use this file except in compliance with the License.

+ *   You may obtain a copy of the License at

+ *

+ *       http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *   Unless required by applicable law or agreed to in writing, software

+ *   distributed under the License is distributed on an "AS IS" BASIS,

+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *   See the License for the specific language governing permissions and

+ *   limitations under the License.

+ *

+ */

+

+package org.apache.felix.upnp.basedriver.tool;

+

+import java.io.PrintStream;

+

+import org.cybergarage.util.Debug;

+

+import org.osgi.framework.Constants;

+import org.osgi.framework.InvalidSyntaxException;

+import org.osgi.framework.ServiceEvent;

+import org.osgi.framework.ServiceListener;

+import org.osgi.framework.ServiceReference;

+import org.osgi.service.log.LogService;

+

+import org.apache.felix.upnp.basedriver.Activator;

+

+/**

+ * @author Stefano "Kismet" Lenzi

+ * @author Francesco Furfari

+ *         

+ */

+public class Logger implements ServiceListener {

+	

+	private ServiceReference rls;

+	private LogService osgiLogService;

+    private int level;

+	private PrintStream out;

+	public  final static String NEWLINE = System.getProperty("line.separator");

+    public static final String ROW ="\n================REQUEST=====================\n";

+    public static final String END_ROW ="--------------------------------------------";

+    

+	private final static String LEVEL_TO_STRING[] = new String[]{

+		"",

+		"ERROR [ " + Activator.bc.getBundle().getBundleId() + " ] ",

+		"WARNING [ " + Activator.bc.getBundle().getBundleId() + " ] ",

+		"INFO [ " + Activator.bc.getBundle().getBundleId() + " ] ",

+		"DEBUG [ " + Activator.bc.getBundle().getBundleId() + " ] ",

+	};

+	

+	

+	/**

+	 * Create a Logger with <code>System.out</code> as <tt>PrintStream</tt> and without 

+	 * 		reporting message on both <tt>PrintStream</tt> and <tt>LogService</tt>

+	 * 

+	 * @param log <tt>ServiceReference</tt> to the <tt>LogService</tt> to use, 

+	 * 		or null to avoid the use of this service

+	 * 

+	 * @see #Logger(LogService, PrintStream, boolean)

+	 */

+	public Logger(String levelStr){

+	    this.out = System.out;

+		try {

+	        this.level = Integer.parseInt(levelStr);

+	    } catch (Exception ex){

+	    	out.println("WARNING [UPnPBaseDriver Log]: " + levelStr+" is not a valid value!");

+	    	this.level=2;

+	    }

+ 	    findService();

+	}

+

+    public void setCyberDebug(String value){

+        try {

+            if (Boolean.valueOf(value).booleanValue()){

+                Debug.on();

+                out.println("INFO [UPnPBaseDriver] Started CyberLink Debug");

+            }

+       } catch (Exception ex){

+            out.println("WARNING [UPnPBaseDriver CyberLog]: " + value +" is not a valid value!");

+        }

+    }

+    

+    ////////////////////////////////////////////////////////////////////////////////////

+    //////////////////////////// programmatic interface ////////////////////////////////

+    ////////////////////////////////////////////////////////////////////////////////////

+    

+    public void setLogLevel(int level){

+        if (level < 0 || level >4 ) throw new IllegalArgumentException("Log Level must be [0-4]");

+        this.level = level;

+    }

+    

+    public int getLogLevel(){

+        return this.level;

+    }

+    

+    

+    public void setCyberDebug(boolean value){

+        if (value) Debug.on();

+        else Debug.off();

+    }

+    

+    public boolean getCyberDebug(){

+        return Debug.isOn();

+    }

+    //////////////////////////// end programmatic interface ////////////////////////////

+   

+    

+	public final void ERROR(String message) {

+	    log(1,message);

+	}

+	

+	public final void WARNING(String message) {

+	    log(2,message);

+	}

+	

+	public final void INFO(String message) {

+	    log(3,message);

+	}

+	

+    public final void DEBUG(String message) {

+        log(4,message);

+    }

+    

+    public final void PACKET(String message) {

+        log(4, new StringBuffer(ROW).append(message).append(END_ROW).toString());

+    }

+

+    /**

+     * Logs a message.

+     *

+     * <p>The <tt>ServiceReference</tt> field and the <tt>Throwable</tt>

+     * field of the <tt>LogEntry</tt> object will be set to <tt>null</tt>.

+     * @param msglevel The severity of the message.

+     * This should be one of the defined log levels

+     * but may be any integer that is interpreted in a user defined way.

+     * @param message Human readable string describing the condition or <tt>null</tt>.

+     * @see #LOG_ERROR

+     * @see #LOG_WARNING

+     * @see #LOG_INFO

+     * @see #LOG_DEBUG

+     */

+	public void log(int msglevel, String message) {

+		synchronized (this) {

+            if (msglevel <= this.level){

+    			if (this.osgiLogService != null ){

+    				    osgiLogService.log(msglevel, message);

+    			}

+    			else {

+    				StringBuffer sb = new StringBuffer(Logger.LEVEL_TO_STRING[msglevel]);

+    			    this.out.println(sb.append(message));

+    			}

+            }

+		}

+		

+	}

+

+	 /**

+     * Logs a message with an exception.

+     *

+     * <p>The <tt>ServiceReference</tt> field of the <tt>LogEntry</tt> object will be set to <tt>null</tt>.

+     * @param msglevel The severity of the message.

+     * This should be one of the defined log levels

+     * but may be any integer that is interpreted in a user defined way.

+     * @param message The human readable string describing the condition or <tt>null</tt>.

+     * @param exception The exception that reflects the condition or <tt>null</tt>.

+     * @see #LOG_ERROR

+     * @see #LOG_WARNING

+     * @see #LOG_INFO

+     * @see #LOG_DEBUG

+     */

+	public void log(int msglevel, String message, Throwable exception) {

+		synchronized (this) {

+            if (msglevel <= this.level){ 

+    			if(this.osgiLogService != null){

+    				    osgiLogService.log(msglevel, message, exception);

+    			}

+    			else {

+    				StringBuffer sb = new StringBuffer(Logger.LEVEL_TO_STRING[msglevel]);

+    			    this.out.println(sb.append(message).append(NEWLINE).append(exception));

+    				exception.printStackTrace(this.out);

+    			}

+            }

+		}

+	}

+

+	private synchronized void setLogService(ServiceReference reference){

+		this.rls = reference;

+		this.osgiLogService = (LogService) Activator.bc.getService(rls);

+	}	

+	/**

+	 * This look for a <tt>LogService</tt> if it founds no <tt>LogService</tt> will register a new

+	 * Listener of LogService 

+	 *

+	 */

+	private synchronized void findService() {

+		//PRE:Actually no LogService are setted and we are registered as ServiceListener 

+		//		for LogService (unregisterin event)

+		this.rls = Activator.bc.getServiceReference(LogService.class.getName());

+		if (this.rls != null){

+			this.osgiLogService = (LogService) Activator.bc.getService(rls);

+		}

+		try {

+			Activator.bc.addServiceListener(this, 

+					"(" + Constants.OBJECTCLASS	+ "=" + LogService.class.getName() + ")"

+			);

+		} catch (InvalidSyntaxException ignore) {}				

+		//POST: We are connected to a LogService or we are registered as ServiceListener 

+		//		for LogService(registering event)

+	}

+	

+	private synchronized void releaseLogService() {

+        if( osgiLogService != null)

+            Activator.bc.ungetService(this.rls);

+		this.rls = null;

+		this.osgiLogService = null;

+	}

+	

+	/**

+	 * Used to keep track the existence of a <tt>LogService</tt>

+	 * 

+	 * @see ServiceListener#serviceChanged(org.osgi.framework.ServiceEvent)

+	 */

+	public void serviceChanged(ServiceEvent e) {

+		switch (e.getType()) {

+			case ServiceEvent.REGISTERED: {

+			    // put here code check for serviceid

+				setLogService(e.getServiceReference());

+			}break;

+	

+			case ServiceEvent.MODIFIED: 

+			break;

+	

+			case ServiceEvent.UNREGISTERING: {				

+			    // put here code check for serviceid

+				releaseLogService();

+			}break;

+		}		

+	}

+

+	/**

+	 * Stop using the <tt>LogService</tt> and listening for those service event

+	 * 

+	 * NOTE: All the message will be reported to <tt>PrintStream</tt>

+	 *

+	 */

+	public void close(){	

+		Activator.bc.removeServiceListener(this);

+		releaseLogService();

+	}

+}

diff --git a/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/tool/Util.java b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/tool/Util.java
new file mode 100644
index 0000000..bc8f046
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/java/org/apache/felix/upnp/basedriver/tool/Util.java
@@ -0,0 +1,94 @@
+/*
+ *   Copyright 2006 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+
+package org.apache.felix.upnp.basedriver.tool;
+
+import java.io.File;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.upnp.UPnPDevice;
+
+/**
+ * @author Stefano "Kismet" Lenzi 
+ * 
+ */
+public class Util {
+	
+	public static boolean isUPnPDevice(ServiceReference sr){
+		String[] aux = (String[]) sr.getProperty(Constants.OBJECTCLASS);
+		String val=UPnPDevice.class.getName();
+		int i;
+		for (i = 0; i < aux.length; i++) {
+			if(aux[i].equals(val)) break;
+		}
+		if(i==aux.length) return false;
+		aux = (String[]) sr.getProperty(org.osgi.service.device.Constants.DEVICE_CATEGORY);
+		val=UPnPDevice.DEVICE_CATEGORY;
+		for (i = 0; i < aux.length; i++) {
+			if(aux[i].equals(val)) 
+					return true;
+		}		
+		return false;
+	}
+	
+	public static final boolean isRootDevice(ServiceReference sr){
+		return (sr.getProperty(UPnPDevice.PARENT_UDN)==null)
+				&& isUPnPDevice(sr);
+	}
+	
+	public static final String getPropertyDefault(BundleContext bc, String propertyName, String defaultValue ){
+		String value = bc.getProperty(propertyName);
+		if(value == null)
+			return defaultValue;
+		return value;
+	}
+
+	public static String sanitizeFilename(String name){
+		return name.replaceAll("[:;\\,/*?<>\"|]","_");
+	}
+
+	public static boolean makeParentPath(String filePath){
+		int l=filePath.lastIndexOf(File.separator);
+		filePath=filePath.substring(0,l);
+		File p=new File(filePath);
+		if(p.exists())
+			return true;
+		return p.mkdirs();
+	}
+
+	/**
+	 * @param d
+	 */
+	public static boolean deleteRecursive(File d) {
+		if(!d.delete()){
+			if(d.isDirectory()){
+				File[] subs = d.listFiles();
+				for (int i = 0; i < subs.length; i++) {
+					if(!deleteRecursive(subs[i]))
+						return false;
+				}
+				return d.delete();
+			}else{
+				return false;
+			}			
+		}
+		return true;
+	}	
+	
+}
diff --git a/org.apache.felix.upnp.basedriver/src/main/resources/META-INF/Manifest.mf b/org.apache.felix.upnp.basedriver/src/main/resources/META-INF/Manifest.mf
new file mode 100644
index 0000000..b037441
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/resources/META-INF/Manifest.mf
@@ -0,0 +1,6 @@
+Manifest-Version: 1.0

+Bundle-ClassPath: .,lib/cyberlink-1.7-patched-release.jar

+Bundle-Author: Matteo Demuru <matte-d@users.sourceforge.net>,Stefano "

+ Kismet" Lenzi <kismet-sl@users.sourceforge.net>,Francesco Furfari <fr

+ ancesco.furfari@isti.cnr.it>,Satoshi Konno

+

diff --git a/org.apache.felix.upnp.basedriver/src/main/resources/lib/cyberlink-1.7-patched-debug.jar b/org.apache.felix.upnp.basedriver/src/main/resources/lib/cyberlink-1.7-patched-debug.jar
new file mode 100644
index 0000000..e8e7232
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/resources/lib/cyberlink-1.7-patched-debug.jar
Binary files differ
diff --git a/org.apache.felix.upnp.basedriver/src/main/resources/lib/cyberlink-1.7-patched-release.jar b/org.apache.felix.upnp.basedriver/src/main/resources/lib/cyberlink-1.7-patched-release.jar
new file mode 100644
index 0000000..851f577
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/resources/lib/cyberlink-1.7-patched-release.jar
Binary files differ
diff --git a/org.apache.felix.upnp.basedriver/src/main/resources/lib/install CyberLink.txt b/org.apache.felix.upnp.basedriver/src/main/resources/lib/install CyberLink.txt
new file mode 100644
index 0000000..c3b8448
--- /dev/null
+++ b/org.apache.felix.upnp.basedriver/src/main/resources/lib/install CyberLink.txt
@@ -0,0 +1,2 @@
+mvn install:install-file -DgroupId=org.cybergarage -DartifactId=cyberlink-patched-release 

+-Dversion=1.7 -Dpackaging=jar -Dfile=<basedir>trunk\org.apache.felix.upnp.basedriver\src\main\resources\lib\cyberlink-1.7-patched-release.jar
\ No newline at end of file