Resolved some race condition cases
Backporting for JDK 1.3 completed (Thanks to Nico Goeminne)
Added some comment and debug lines



git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@606021 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/upnp/basedriver/pom.xml b/upnp/basedriver/pom.xml
index 4174998..a85f6e2 100644
--- a/upnp/basedriver/pom.xml
+++ b/upnp/basedriver/pom.xml
@@ -145,7 +145,7 @@
     <dependency>
       <groupId>org.apache.felix</groupId>
       <artifactId>org.apache.felix.upnp.extra</artifactId>
-      <version>0.2.0-SNAPSHOT</version>      
+      <version>0.3.0-SNAPSHOT</version>      
     </dependency>
   </dependencies>
 </project>
diff --git a/upnp/basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/MyCtrlPoint.java b/upnp/basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/MyCtrlPoint.java
index fa6b4a9..59bc43d 100644
--- a/upnp/basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/MyCtrlPoint.java
+++ b/upnp/basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/MyCtrlPoint.java
@@ -211,96 +211,108 @@
 		} 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);

+            synchronized (devices) {		

 

-				} 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]);

+				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]);

+	

+	                    //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);

 					}

-					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);

 				}

-			}

+				

+			}//synchronized(devices)

 		} else {

 			/*

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

+			 * if it is a service means that it has deleted when the 

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

+			 * 

+			 * //TODO Understand the comment

+			 *

 			 */

 		}

 	}

     

-	public synchronized void removeOSGiandUPnPDeviceHierarchy(UPnPDeviceImpl dev) 

+	public synchronized void removeOSGiandUPnPDeviceHierarchy(final UPnPDeviceImpl dev) 

     {

 		/*

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

 		 */

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

+		

+		if(devices.containsKey(udn) == false){

+			Activator.logger.INFO("Device "+dev.getDescriptions(null).get(UPnPDevice.FRIENDLY_NAME)+"("+udn+") already removed");

+			return;

+		}		

+		

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

 				UPnPDevice.CHILDREN_UDN);

+

 		if (childrenUDN == null) {

-			//no children

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

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

-					.getRegistration());

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

+			//no children			

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

+			Activator.logger.INFO("Device "+dev.getDescriptions(null).get(UPnPDevice.FRIENDLY_NAME)+"("+udn+") deleted");

+			devices.remove(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());

+		} else {

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

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

+					removeOSGiandUPnPDeviceHierarchy(((OSGiDeviceInfo) devices.get(childrenUDN[i])).getOSGiDevice());

+				}

 			}

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

+			Activator.logger.INFO("Device "+dev.getDescriptions(null).get(UPnPDevice.FRIENDLY_NAME)+"("+udn+") deleted");

+			devices.remove(udn);

 		}

-		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) {

@@ -788,6 +800,7 @@
             device.setProperty(UPnPServiceImpl.TYPE,currentServicesType);

             

             //registering the service with the updated properties

+            //TODO Check if null to the first paramaters is correct or it requires the reference to the cyberdomo upnp device

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

             searchForListener(cyberDevice);

         }   

@@ -809,17 +822,21 @@
     	doDeviceRegistration(udn);

     }

     

-    public void doDeviceRegistration(String udn){

+    public synchronized void doDeviceRegistration(String udn){

         /*

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

+         * registering the new device either 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());

+        	/*

+        	 * In this case the UPnP SDK notifies us that a ssdp:alive has arrived,

+        	 * but,  because the no root device ssdp:alive packet has recieved by the UPnP SDK

+        	 * no Device is present in the UPnP SDK device list. 

+        	 */

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

+        }else if(devices.containsKey(udn) == false) {

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

             registerUPnPDevice(dev, null, null);

             searchForListener(dev);

             /*

@@ -831,7 +848,9 @@
 				Device d = (Device) i.next();

 				doDeviceRegistration(d.getUDN(),true);

 			}

-        }    

+        }else if(devices.containsKey(udn) == true) {

+        	Activator.logger.INFO("[Importer] UPnPDevice UDN::"+dev.getFriendlyName()+"("+dev.getUDN()+") already registered Skipping");

+        }

     }

     

 	public void searchForListener(Device device) {

diff --git a/upnp/basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/upnp/UPnPIconImpl.java b/upnp/basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/upnp/UPnPIconImpl.java
index 57602c9..dba0d8a 100644
--- a/upnp/basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/upnp/UPnPIconImpl.java
+++ b/upnp/basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/upnp/UPnPIconImpl.java
@@ -54,7 +54,6 @@
 	 * @see org.osgi.service.upnp.UPnPIcon#getWidth()

 	 */

 	public int getWidth() {

-		//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;

@@ -66,7 +65,6 @@
 	 * @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;

@@ -86,7 +84,6 @@
 	 * @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;

@@ -98,8 +95,6 @@
 	 * @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);

diff --git a/upnp/basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/upnp/UPnPServiceImpl.java b/upnp/basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/upnp/UPnPServiceImpl.java
index 7182640..40c7c26 100644
--- a/upnp/basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/upnp/UPnPServiceImpl.java
+++ b/upnp/basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/core/upnp/UPnPServiceImpl.java
@@ -33,7 +33,7 @@
 import org.osgi.service.upnp.UPnPService;

 import org.osgi.service.upnp.UPnPStateVariable;

 

-/* 

+/** 

 * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>

 */

 public class UPnPServiceImpl implements UPnPService {

@@ -87,9 +87,10 @@
 	 * @see org.osgi.service.upnp.UPnPService#getVersion()

 	 */

 	public String getVersion() {

-		//TODO to check can I speed up this? May be using lastIndexOf

-		String [] splited=service.getServiceType().split(":"); 

-		return splited[splited.length-1];

+		String serviceType = service.getServiceType();

+		int start = serviceType.lastIndexOf(':');

+		String version = serviceType.substring(start+1);

+		return version;

 	} 

 	/*

 	   * (non-Javadoc)

diff --git a/upnp/basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/util/HTTPRequestForIcon.java b/upnp/basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/util/HTTPRequestForIcon.java
index e662561..3c38cfc 100644
--- a/upnp/basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/util/HTTPRequestForIcon.java
+++ b/upnp/basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/util/HTTPRequestForIcon.java
@@ -22,7 +22,7 @@
 import java.io.*;

 import java.net.*;

 

-/* 

+/** 

 * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>

 */

 public class HTTPRequestForIcon {

diff --git a/upnp/basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/util/ParseLocation.java b/upnp/basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/util/ParseLocation.java
index 6262667..21c0c4f 100644
--- a/upnp/basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/util/ParseLocation.java
+++ b/upnp/basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/util/ParseLocation.java
@@ -19,12 +19,13 @@
 

 package org.apache.felix.upnp.basedriver.importer.util;

 

-/* 

+/** 

 * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>

 */

 public class ParseLocation {

 	public static String getUrlBase(String location){

-		String [] splited=location.split("/");

-		return splited[0]+"/"+"/"+splited[2];

+		String [] splited=StringSplitter.split(location, '/');

+		String value=splited[0]+"/"+"/"+splited[2];

+		return value;		

 	}

 }

diff --git a/upnp/basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/util/ParseUSN.java b/upnp/basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/util/ParseUSN.java
index 5fc5858..c0194ac 100644
--- a/upnp/basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/util/ParseUSN.java
+++ b/upnp/basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/util/ParseUSN.java
@@ -29,7 +29,7 @@
 	String serviceType;

 	

 	public ParseUSN(String usn) {

-		String [] splited=usn.split(":"); 	

+		String [] splited=StringSplitter.split(usn, ':');

 		if(splited.length==5||splited.length==2){

 			udn="uuid:"+splited[1];

 			device=true;

diff --git a/upnp/basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/util/StringSplitter.java b/upnp/basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/util/StringSplitter.java
new file mode 100644
index 0000000..9de4e95
--- /dev/null
+++ b/upnp/basedriver/src/main/java/org/apache/felix/upnp/basedriver/importer/util/StringSplitter.java
@@ -0,0 +1,42 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.ArrayList;
+
+/** 
+* The class is used only for JDK1.3 backporting purpose
+* 
+* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+* @since 0.3
+*/
+public class StringSplitter {
+	
+	public static String [] split (String tosplit, char ch){
+		ArrayList result = new ArrayList();
+		int  pos = -1;
+		while ( (pos = tosplit.indexOf(ch)) != -1) {
+			result.add(new String (tosplit.substring(0, pos)));
+			tosplit = tosplit.substring(pos + 1);
+		}
+		if (!tosplit.equals("")) result.add(new String(tosplit));
+		return (String [])result.toArray(new String [0]);
+	}
+
+}
diff --git a/upnp/basedriver/src/main/java/org/apache/felix/upnp/basedriver/tool/Util.java b/upnp/basedriver/src/main/java/org/apache/felix/upnp/basedriver/tool/Util.java
index 3e4088d..29a42f3 100644
--- a/upnp/basedriver/src/main/java/org/apache/felix/upnp/basedriver/tool/Util.java
+++ b/upnp/basedriver/src/main/java/org/apache/felix/upnp/basedriver/tool/Util.java
@@ -60,10 +60,6 @@
 		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);
diff --git a/upnp/extra/pom.xml b/upnp/extra/pom.xml
index da6de3a..fb209fb 100644
--- a/upnp/extra/pom.xml
+++ b/upnp/extra/pom.xml
@@ -11,7 +11,7 @@
   <groupId>org.apache.felix</groupId>
   <name>Apache Felix UPnP Extra </name>
   <artifactId>org.apache.felix.upnp.extra</artifactId>
-  <version>0.2.0-SNAPSHOT</version>
+  <version>0.3.0-SNAPSHOT</version>
   <!-- <url>http://maven.apache.org</url> -->
   <dependencies>
     <dependency>
diff --git a/upnp/extra/src/main/java/org/apache/felix/upnp/extra/util/Constants.java b/upnp/extra/src/main/java/org/apache/felix/upnp/extra/util/Constants.java
index 4826434..8b8b993 100644
--- a/upnp/extra/src/main/java/org/apache/felix/upnp/extra/util/Constants.java
+++ b/upnp/extra/src/main/java/org/apache/felix/upnp/extra/util/Constants.java
@@ -25,7 +25,7 @@
 	/**
 	 * If this property is set on a UPnP Device means that the 
 	 * device service is been created by UPnP base Driver. <br>
-	 * The value of the do not mean nothing. <br>
+	 * The value of the does not carry any mean. <br>
 	 * The name of the property is "UPnP.device.import".
 	 */
 	public static final String UPNP_IMPORT = "UPnP.device.imported"; 
diff --git a/upnp/extra/src/main/java/org/apache/felix/upnp/extra/util/Converter.java b/upnp/extra/src/main/java/org/apache/felix/upnp/extra/util/Converter.java
index 7fb0fca..4b68514 100644
--- a/upnp/extra/src/main/java/org/apache/felix/upnp/extra/util/Converter.java
+++ b/upnp/extra/src/main/java/org/apache/felix/upnp/extra/util/Converter.java
@@ -27,7 +27,7 @@
 import org.apache.xerces.impl.dv.util.HexBin;

 import org.osgi.service.upnp.*;

 

-/* 

+/** 

 * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>

 */

 public class Converter {

@@ -153,12 +153,11 @@
 			String[] timeFormats=new String[]{"HH:mm:ssZ","HH:mm:ss"};

 			Date d=getDateValue(value,timeFormats,timeFormats);

 			TimeZone tz = TimeZone.getDefault();			

-			int dst = tz.getDSTSavings();	

 			Calendar c = Calendar.getInstance(tz);

 			c.setTime(d);

 			

-			if(timeFormats[0].equals("HH:mm:ssZ")&&(dst!=0))

-				c.add(Calendar.MILLISECOND,dst);

+			if(timeFormats[0].equals("HH:mm:ssZ")&&(tz.inDaylightTime(d)))

+				c.add(Calendar.MILLISECOND,3600000);

 			return new Long(

 					c.get(Calendar.HOUR_OF_DAY)*3600000

 					+c.get(Calendar.MINUTE)*60000