added Clock and BinaryLight UPnP examples

git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@399191 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/org.apache.felix.upnp.sample.binaryLight/pom.xml b/org.apache.felix.upnp.sample.binaryLight/pom.xml
new file mode 100644
index 0000000..d72af42
--- /dev/null
+++ b/org.apache.felix.upnp.sample.binaryLight/pom.xml
@@ -0,0 +1,60 @@
+<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 Sample Binary-Light</name>

+  <artifactId>org.apache.felix.upnp.sample.binaryLight</artifactId>

+  <version>0.1.0-SNAPSHOT</version>

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

+  <dependencies>

+    <dependency>

+      <groupId>${pom.groupId}</groupId>

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

+      <version>0.8.0-SNAPSHOT</version>

+      <scope>provided</scope>

+    </dependency>

+    <dependency>

+      <groupId>${pom.groupId}</groupId>

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

+      <version>0.8.0-SNAPSHOT</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>UPnPBinaryLight</bundleName>

+            <bundleVendor>Apache Software Foundation</bundleVendor>

+            <bundleVersion>0.1.0</bundleVersion>

+            <bundleDescription>

+               	Standardized BinaryLight DCPs to test UPnP Base Driver

+            </bundleDescription>

+            <bundleSymbolicName>org.apache.felix.upnp.sample.binaryLight</bundleSymbolicName>

+		<bundleActivator>org.apache.felix.upnp.sample.binaryLight.Activator</bundleActivator>

+            <importPackage>

+			javax.swing,javax.imageio,org.osgi.framework;specification-version=1.3,org.osgi.service.upnp;specification-version=1.1

+            </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.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/Activator.java b/org.apache.felix.upnp.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/Activator.java
new file mode 100644
index 0000000..52fb38b
--- /dev/null
+++ b/org.apache.felix.upnp.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/Activator.java
@@ -0,0 +1,64 @@
+/*
+ *   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.sample.binaryLight;
+
+import java.util.Dictionary;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.upnp.UPnPDevice;
+
+
+/* 
+* @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+*/
+
+public class Activator implements BundleActivator {
+
+	static BundleContext context;
+	private ServiceRegistration serviceRegistration;
+	private LightDevice light;
+	
+	/**
+	 * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
+	 */
+	public void start(BundleContext context) throws Exception {
+		Activator.context = context;
+		doServiceRegistration();
+	}
+
+	private void doServiceRegistration() {
+		light = new LightDevice(context);
+		Dictionary dict = light.getDescriptions(null);
+				
+		serviceRegistration = context.registerService(
+				UPnPDevice.class.getName(),
+				light,
+				dict
+			);
+	}
+
+	/**
+	 * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
+	 */
+	public void stop(BundleContext context) throws Exception {
+		serviceRegistration.unregister();
+		light.close();
+	}
+}
diff --git a/org.apache.felix.upnp.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/EventSource.java b/org.apache.felix.upnp.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/EventSource.java
new file mode 100644
index 0000000..c0c56de
--- /dev/null
+++ b/org.apache.felix.upnp.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/EventSource.java
@@ -0,0 +1,32 @@
+/*

+ *   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.sample.binaryLight;

+

+import java.beans.PropertyChangeListener;

+

+/* 

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

+*/

+

+public interface EventSource {

+	void addPropertyChangeListener(PropertyChangeListener listener);

+	void addPropertyChangeListener(String propertyName, PropertyChangeListener listener);

+	void removePropertyChangeListener(PropertyChangeListener listener);

+	void removePropertyChangeListener(String propertyName, PropertyChangeListener listener);

+}

+

diff --git a/org.apache.felix.upnp.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/GetStatusAction.java b/org.apache.felix.upnp.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/GetStatusAction.java
new file mode 100644
index 0000000..746662b
--- /dev/null
+++ b/org.apache.felix.upnp.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/GetStatusAction.java
@@ -0,0 +1,89 @@
+/*

+ *   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.sample.binaryLight;

+

+import java.util.Dictionary;

+import java.util.Hashtable;

+

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

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

+

+/* 

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

+*/

+

+public class GetStatusAction implements UPnPAction {

+

+	final private String NAME = "GetStatus";

+	final private String RESULT_STATUS = "ResultStatus";

+	final private String[] OUT_ARG_NAMES = new String[]{RESULT_STATUS};

+	private UPnPStateVariable state;

+	private LightModel model;

+	

+	

+	public GetStatusAction(LightModel model,UPnPStateVariable state){

+		this.state = state;

+		this.model=model;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public String getName() {

+		return NAME;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public String getReturnArgumentName() {

+		return null;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public String[] getInputArgumentNames() {

+		

+		return null;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public String[] getOutputArgumentNames() {

+		return OUT_ARG_NAMES;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public UPnPStateVariable getStateVariable(String argumentName) {

+		return state;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public Dictionary invoke(Dictionary args) throws Exception {

+		boolean status = model.getStatus();

+		Hashtable result = new Hashtable();

+		result.put(RESULT_STATUS,new Boolean(status));

+		return result;

+	}

+}

diff --git a/org.apache.felix.upnp.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/GetTargetAction.java b/org.apache.felix.upnp.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/GetTargetAction.java
new file mode 100644
index 0000000..eb55c06
--- /dev/null
+++ b/org.apache.felix.upnp.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/GetTargetAction.java
@@ -0,0 +1,89 @@
+/*

+ *   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.sample.binaryLight;

+

+import java.util.Dictionary;

+import java.util.Hashtable;

+

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

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

+

+/* 

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

+*/

+

+public class GetTargetAction implements UPnPAction {

+

+	final private String NAME = "GetTarget";

+	final private String RET_TARGET_VALUE = "RetTargetValue";

+	final private String[] OUT_ARG_NAMES = new String[]{RET_TARGET_VALUE};

+	private UPnPStateVariable state;

+	private LightModel model;

+	

+	

+	public GetTargetAction(LightModel model,UPnPStateVariable state){

+		this.state = state;

+		this.model=model;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public String getName() {

+		return NAME;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public String getReturnArgumentName() {

+		return null;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public String[] getInputArgumentNames() {

+		

+		return null;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public String[] getOutputArgumentNames() {

+		return OUT_ARG_NAMES;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public UPnPStateVariable getStateVariable(String argumentName) {

+		return state;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public Dictionary invoke(Dictionary args) throws Exception {

+		boolean target = model.getTarget();

+		Hashtable result = new Hashtable();

+		result.put(RET_TARGET_VALUE,new Boolean(target));

+		return result;

+	}

+}

diff --git a/org.apache.felix.upnp.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/LightDevice.java b/org.apache.felix.upnp.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/LightDevice.java
new file mode 100644
index 0000000..1157a05
--- /dev/null
+++ b/org.apache.felix.upnp.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/LightDevice.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.sample.binaryLight;

+

+import java.util.Dictionary;

+import java.util.Properties;

+

+import org.osgi.framework.BundleContext;

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

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

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

+

+/* 

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

+*/

+

+public class LightDevice implements UPnPDevice {

+

+	final private String DEVICE_ID = "uuid:Felix-BinaryLight";

+	private BundleContext context;

+	private LightModel model;

+	private LightUI ui;

+	private PowerSwitchService powerSwitch;

+	private UPnPService[] services;

+	private Dictionary dictionary;

+	private UPnPEventNotifier notifier;

+	

+	public LightDevice(BundleContext context) {

+		this.context=context;

+		model = new LightModel();

+		ui = new LightUI(model);

+		powerSwitch = new PowerSwitchService(model);

+		services = new UPnPService[]{powerSwitch};

+		setupDeviceProperties();

+		buildEventNotifyer();

+	}

+

+	/**

+	 * 

+	 */

+	private void buildEventNotifyer() {

+		notifier = new UPnPEventNotifier(context,DEVICE_ID,powerSwitch,model);

+	}

+

+	private void setupDeviceProperties(){

+		dictionary = new Properties();

+		dictionary.put(UPnPDevice.UPNP_EXPORT,"");

+		dictionary.put(

+		        org.osgi.service

+		        	.device.Constants.DEVICE_CATEGORY,

+	        	new String[]{UPnPDevice.DEVICE_CATEGORY}

+	        );

+		//dictionary.put(UPnPDevice.DEVICE_CATEGORY,new String[]{UPnPDevice.DEVICE_CATEGORY});

+		dictionary.put(UPnPDevice.FRIENDLY_NAME,"Felix OSGi-UPnP BinaryLight");

+		dictionary.put(UPnPDevice.MANUFACTURER,"Apache Software Foundation");

+		dictionary.put(UPnPDevice.MANUFACTURER_URL,"http://incubator.apache.org/felix/");

+		dictionary.put(UPnPDevice.MODEL_DESCRIPTION,"A BinaryLight device to test OSGi to UPnP service export");

+		dictionary.put(UPnPDevice.MODEL_NAME,"Lucciola");

+		dictionary.put(UPnPDevice.MODEL_NUMBER,"1.0");

+		dictionary.put(UPnPDevice.MODEL_URL,"http://incubator.apache.org/felix/lucciola");

+		dictionary.put(UPnPDevice.PRESENTATION_URL,"http://incubator.apache.org/felix/lucciola/presentation");

+		dictionary.put(UPnPDevice.SERIAL_NUMBER,"123456789");

+		dictionary.put(UPnPDevice.TYPE,"urn:schemas-upnp-org:device:BinaryLight:1");

+		dictionary.put(UPnPDevice.UDN,DEVICE_ID);

+		//dictionary.put(UPnPDevice.ID,dictionary.get(UPnPDevice.UDN));

+		dictionary.put(UPnPDevice.UPC,"1213456789");

+	}

+	

+	

+	/* (non-Javadoc)

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

+	 */

+	public UPnPService getService(String serviceId) {

+		if  (serviceId.equals(powerSwitch.getId())) return powerSwitch;

+		return null;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public UPnPService[] getServices() {

+		return services;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public UPnPIcon[] getIcons(String locale) {

+		UPnPIcon icon = new LightIcon();

+		return new UPnPIcon[]{icon} ;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public Dictionary getDescriptions(String locale) {

+		return dictionary;

+	}

+

+	/**

+	 * 

+	 */

+	public void close() {

+		ui.dispose();

+		notifier.destroy();

+	}

+	

+}

diff --git a/org.apache.felix.upnp.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/LightIcon.java b/org.apache.felix.upnp.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/LightIcon.java
new file mode 100644
index 0000000..cef3a36
--- /dev/null
+++ b/org.apache.felix.upnp.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/LightIcon.java
@@ -0,0 +1,71 @@
+/*

+ *   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.sample.binaryLight;

+import java.io.IOException;

+import java.io.InputStream;

+

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

+

+/* 

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

+*/

+

+public class LightIcon implements UPnPIcon {

+

+	/* (non-Javadoc)

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

+	 */

+	public String getMimeType() {

+		return "image/gif";

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public int getWidth() {

+		return 32;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public int getHeight() {

+		return 32;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public int getSize() {

+		return 0;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public int getDepth() {

+		return 16;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public InputStream getInputStream() throws IOException {

+		return LightIcon.class.getResourceAsStream("images/LightOn.gif");

+	}

+}

diff --git a/org.apache.felix.upnp.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/LightModel.java b/org.apache.felix.upnp.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/LightModel.java
new file mode 100644
index 0000000..4e512ca
--- /dev/null
+++ b/org.apache.felix.upnp.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/LightModel.java
@@ -0,0 +1,106 @@
+/*

+ *   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.sample.binaryLight;

+

+import java.beans.PropertyChangeListener;

+import java.beans.PropertyChangeSupport;

+

+/* 

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

+*/

+

+public class LightModel implements EventSource{

+	

+	private boolean status = false;

+	private boolean target = false;

+	private boolean failure = false;

+	private PropertyChangeSupport propertySupport = new PropertyChangeSupport(this);

+	

+	public LightModel(){	

+	}

+	

+	public void addPropertyChangeListener(PropertyChangeListener listener){

+		propertySupport.addPropertyChangeListener(listener);

+	}

+	

+	public void removePropertyChangeListener(PropertyChangeListener listener){

+		propertySupport.removePropertyChangeListener(listener);

+	}

+	public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {

+		propertySupport.addPropertyChangeListener(propertyName,listener);

+	}

+

+	public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {

+		propertySupport.removePropertyChangeListener(propertyName,listener);

+	}

+	

+	public void doSwitch(boolean value){

+		if (value) switchOn();

+		else switchOff();

+	}

+	

+	public void switchOn(){

+		target = true;

+		if(! failure) {

+			boolean oldStatus = status;

+			status = true;

+			propertySupport.firePropertyChange("Status",oldStatus,status);

+		}

+	}

+	

+	public void switchOff(){

+		target = false;

+		if(! failure) {

+			boolean oldStatus = status;

+			status = false;

+			propertySupport.firePropertyChange("Status",oldStatus,status);

+		}

+	}

+	

+	public void setFailure(boolean value){

+		boolean oldFailure = failure;

+		boolean oldStatus = status;

+		failure = value;

+		if (failure){

+			status = false;

+		}

+		else if (target){

+			status = true;

+		}

+		propertySupport.firePropertyChange("Status",oldStatus,status);

+		propertySupport.firePropertyChange("Failure",oldFailure,failure);

+	}

+	

+

+	/**

+	 * @return

+	 */

+	public boolean getTarget() {

+		return target;

+	}

+

+	/**

+	 * @return

+	 */

+	public boolean getStatus() {

+		return status;

+	}

+

+

+

+}

diff --git a/org.apache.felix.upnp.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/LightUI.java b/org.apache.felix.upnp.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/LightUI.java
new file mode 100644
index 0000000..5f67ba7
--- /dev/null
+++ b/org.apache.felix.upnp.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/LightUI.java
@@ -0,0 +1,150 @@
+/*

+ *   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.sample.binaryLight;

+

+import java.awt.BorderLayout;

+import java.awt.event.MouseAdapter;

+import java.awt.event.MouseEvent;

+import java.awt.event.WindowAdapter;

+import java.awt.event.WindowEvent;

+import java.beans.PropertyChangeEvent;

+import java.beans.PropertyChangeListener;

+import java.net.URL;

+

+import javax.swing.Icon;

+import javax.swing.ImageIcon;

+import javax.swing.JButton;

+import javax.swing.JFrame;

+import javax.swing.JLabel;

+import javax.swing.JPanel;

+import javax.swing.SwingUtilities;

+

+import org.osgi.framework.BundleException;

+

+/* 

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

+*/

+

+public class LightUI extends JFrame implements PropertyChangeListener {

+    private final static ImageIcon LIGHT_ON = LightUI.loadIcon("LightOn.gif","ON");

+    private final static ImageIcon LIGHT_OFF = LightUI.loadIcon("LightOff.gif","OFF");

+    private final static ImageIcon LIGHT_FAIL = LightUI.loadIcon("LightFail.gif","FAILURE");

+	private final JLabel label = new JLabel();

+    private LightModel model;

+   

+	public LightUI(LightModel model)   {

+		super("Felix UPnP BinaryLight");

+		this.model = model;

+		setSize(150,150);

+		JPanel panel = new JPanel(new BorderLayout());

+		panel.add(doMainPanel(),BorderLayout.CENTER);

+		panel.add(doControlPanel(),BorderLayout.SOUTH);

+		getContentPane().add(panel);

+		model.addPropertyChangeListener(this);

+

+		addWindowListener(new WindowAdapter(){

+			public void windowClosing(WindowEvent e) 

+			{

+				try {

+					Activator.context.getBundle().stop();

+				} catch (BundleException ex) {

+					ex.printStackTrace();

+				}

+			}

+		});			

+	       try {

+	            URL eventIconUrl = LightUI.class.getResource("images/logo.gif");           

+	            ImageIcon icon=  new ImageIcon(eventIconUrl,"logo");

+	            setIconImage(icon.getImage());

+	       }

+	        catch (Exception ex){

+	                System.out.println("Resource: IMAGES/logo.gif not found : " + ex.toString());

+	        }

+	

+		pack();

+		show();

+    }

+	

+	private JPanel doMainPanel(){

+		JPanel panel = new JPanel();

+		label.setIcon(LIGHT_OFF);

+		//label.setSize(new Dimension(32,32));

+	    label.addMouseListener(new MouseAdapter(){          

+	          public void mouseClicked(MouseEvent e){

+	            if (SwingUtilities.isLeftMouseButton(e)){

+	              if (e.getClickCount()==1){

+	              Icon icon = label.getIcon();

+	              if (icon == LIGHT_ON)

+	                  model.switchOff();

+	              else 

+	                  model.switchOn();

+	              }

+	            }

+	          }

+	    });

+	    panel.add(label);

+	    return panel;

+	}

+	          

+	private JPanel doControlPanel(){

+		JPanel panel = new JPanel();

+		JButton btnSwitch = new JButton("On");

+		JButton btnFailure = new JButton("Failure");

+		panel.add(btnSwitch);

+		panel.add(btnFailure);

+		return panel;

+	}

+	

+    public  static ImageIcon loadIcon(String path,String title)

+    {

+        try {

+            URL eventIconUrl = LightUI.class.getResource("images/" + path);

+            return new ImageIcon(eventIconUrl,title);

+        }

+        catch (Exception ex){

+			System.out.println("Resource:" + path + " not found : " + ex.toString());

+            return null;

+        }

+    }

+

+	/* (non-Javadoc)

+	 * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)

+	 */

+    public void propertyChange(PropertyChangeEvent evt) {

+    	String property = evt.getPropertyName();

+    	System.out.println("Light changed property::"+property);

+    	boolean value = ((Boolean) evt.getNewValue()).booleanValue();

+    	if (property.equals("Status")){

+    		if (value)

+    			label.setIcon(LIGHT_ON);

+    		else

+    			label.setIcon(LIGHT_OFF);

+    	}

+    	else if (property.equals("Failure")){            

+    		if (value)

+    			label.setIcon(LIGHT_FAIL);

+    		else

+    			label.setIcon(LIGHT_OFF);

+    	}

+    	getContentPane().validate();

+    	repaint();

+		

+	}

+

+	

+}

diff --git a/org.apache.felix.upnp.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/PowerSwitchService.java b/org.apache.felix.upnp.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/PowerSwitchService.java
new file mode 100644
index 0000000..1d0989f
--- /dev/null
+++ b/org.apache.felix.upnp.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/PowerSwitchService.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.sample.binaryLight;

+

+import java.util.HashMap;

+

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

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

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

+

+/* 

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

+*/

+

+public class PowerSwitchService implements UPnPService{

+	

+	final private String SERVICE_ID = "urn:upnp-org:serviceId:SwitchPower:1";

+	final private String SERVICE_TYPE = "urn:schemas-upnp-org:service:SwitchPower:1";

+	final private String VERSION ="1";

+

+	private LightModel model;

+	private UPnPStateVariable status,target;

+	private UPnPStateVariable[] states;

+	private HashMap actions = new HashMap();

+	

+	

+	public PowerSwitchService(LightModel model){

+		this.model = model;

+		status = new StatusStateVariable();

+		target = new TargetStateVariable();

+		this.states = new UPnPStateVariable[]{status,target};

+		

+		UPnPAction setTarget = new SetTargetAction(model,target);

+		UPnPAction getTarget = new GetTargetAction(model,target);

+		UPnPAction getStatus = new GetStatusAction(model,status);

+		actions.put(setTarget.getName(),setTarget);

+		actions.put(getTarget.getName(),getTarget);

+		actions.put(getStatus.getName(),getStatus);

+		

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPService#getId()

+	 */

+	public String getId() {

+		return SERVICE_ID;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPService#getType()

+	 */

+	public String getType() {

+		return SERVICE_TYPE;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPService#getVersion()

+	 */

+	public String getVersion() {

+		return VERSION;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPService#getAction(java.lang.String)

+	 */

+	public UPnPAction getAction(String name) {

+		return (UPnPAction)actions.get(name);

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPService#getActions()

+	 */

+	public UPnPAction[] getActions() {

+		return (UPnPAction[])(actions.values()).toArray(new UPnPAction[]{});

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPService#getStateVariables()

+	 */

+	public UPnPStateVariable[] getStateVariables() {

+		return states;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public UPnPStateVariable getStateVariable(String name) {

+		if (name.equals("Status"))

+			return status;

+		else if (name.equals("Target"))

+			return target;

+		else return null;

+	}

+}

diff --git a/org.apache.felix.upnp.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/SetTargetAction.java b/org.apache.felix.upnp.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/SetTargetAction.java
new file mode 100644
index 0000000..42fb290
--- /dev/null
+++ b/org.apache.felix.upnp.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/SetTargetAction.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.sample.binaryLight;

+

+import java.util.Dictionary;

+

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

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

+

+/* 

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

+*/

+

+public class SetTargetAction implements UPnPAction {

+

+	final private String NAME = "SetTarget";

+	final private String NEW_TARGET_VALUE = "NewTargetValue";

+	final private String[] IN_ARG_NAMES = new String[]{NEW_TARGET_VALUE};

+	private UPnPStateVariable state;

+	private LightModel model;

+	

+	

+	public SetTargetAction(LightModel model,UPnPStateVariable state){

+		this.state = state;

+		this.model=model;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public String getName() {

+		return NAME;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public String getReturnArgumentName() {

+		return null;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public String[] getInputArgumentNames() {

+		return IN_ARG_NAMES;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public String[] getOutputArgumentNames() {

+		return null;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public UPnPStateVariable getStateVariable(String argumentName) {

+		return state;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public Dictionary invoke(Dictionary args) throws Exception {

+		Boolean value = (Boolean) args.get(NEW_TARGET_VALUE);

+		model.doSwitch(value.booleanValue());

+		return null;

+	}

+}

diff --git a/org.apache.felix.upnp.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/StatusStateVariable.java b/org.apache.felix.upnp.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/StatusStateVariable.java
new file mode 100644
index 0000000..bf64539
--- /dev/null
+++ b/org.apache.felix.upnp.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/StatusStateVariable.java
@@ -0,0 +1,95 @@
+/*

+ *   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.sample.binaryLight;

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

+/* 

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

+*/

+

+public class StatusStateVariable implements UPnPStateVariable{

+	

+	final private String NAME = "Status";

+	final private Boolean DEFAULT_VALUE = Boolean.FALSE;

+	

+	

+	public StatusStateVariable(){

+	}

+	

+	/* (non-Javadoc)

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

+	 */

+	public String getName() {

+		return NAME;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPStateVariable#getJavaDataType()

+	 */

+	public Class getJavaDataType() {

+		return Boolean.class;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPStateVariable#getUPnPDataType()

+	 */

+	public String getUPnPDataType() {

+		return TYPE_BOOLEAN;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPStateVariable#getDefaultValue()

+	 */

+	public Object getDefaultValue() {

+		return DEFAULT_VALUE;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPStateVariable#getAllowedValues()

+	 */

+	public String[] getAllowedValues() {

+		return null;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPStateVariable#getMinimum()

+	 */

+	public Number getMinimum() {

+		return null;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPStateVariable#getMaximum()

+	 */

+	public Number getMaximum() {

+		return null;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPStateVariable#getStep()

+	 */

+	public Number getStep() {

+		return null;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPStateVariable#sendsEvents()

+	 */

+	public boolean sendsEvents() {

+		return true;

+	}

+}

diff --git a/org.apache.felix.upnp.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/TargetStateVariable.java b/org.apache.felix.upnp.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/TargetStateVariable.java
new file mode 100644
index 0000000..7b792fd
--- /dev/null
+++ b/org.apache.felix.upnp.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/TargetStateVariable.java
@@ -0,0 +1,95 @@
+/*

+ *   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.sample.binaryLight;

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

+/* 

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

+*/

+

+public class TargetStateVariable implements UPnPStateVariable{

+	

+	final private String NAME = "Target";

+	final private Boolean DEFAULT_VALUE = Boolean.FALSE;

+	

+	

+	public TargetStateVariable(){

+	}

+	

+	/* (non-Javadoc)

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

+	 */

+	public String getName() {

+		return NAME;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPStateVariable#getJavaDataType()

+	 */

+	public Class getJavaDataType() {

+		return Boolean.class;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPStateVariable#getUPnPDataType()

+	 */

+	public String getUPnPDataType() {

+		return TYPE_BOOLEAN;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPStateVariable#getDefaultValue()

+	 */

+	public Object getDefaultValue() {

+		return DEFAULT_VALUE;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPStateVariable#getAllowedValues()

+	 */

+	public String[] getAllowedValues() {

+		return null;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPStateVariable#getMinimum()

+	 */

+	public Number getMinimum() {

+		return null;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPStateVariable#getMaximum()

+	 */

+	public Number getMaximum() {

+		return null;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPStateVariable#getStep()

+	 */

+	public Number getStep() {

+		return null;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPStateVariable#sendsEvents()

+	 */

+	public boolean sendsEvents() {

+		return false;

+	}

+}

diff --git a/org.apache.felix.upnp.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/UPnPEventNotifier.java b/org.apache.felix.upnp.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/UPnPEventNotifier.java
new file mode 100644
index 0000000..65c771e
--- /dev/null
+++ b/org.apache.felix.upnp.sample.binaryLight/src/main/java/org/apache/felix/upnp/sample/binaryLight/UPnPEventNotifier.java
@@ -0,0 +1,181 @@
+/*

+ *   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.sample.binaryLight;

+

+import java.beans.PropertyChangeEvent;

+import java.beans.PropertyChangeListener;

+import java.util.Iterator;

+import java.util.Properties;

+import java.util.Vector;

+

+import org.osgi.framework.BundleContext;

+import org.osgi.framework.Constants;

+import org.osgi.framework.Filter;

+import org.osgi.framework.ServiceEvent;

+import org.osgi.framework.ServiceListener;

+import org.osgi.framework.ServiceReference;

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

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

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

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

+

+/* 

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

+*/

+

+public class UPnPEventNotifier implements PropertyChangeListener,ServiceListener {

+	BundleContext context;

+	String deviceId;

+	UPnPService service;

+	EventSource source;

+	

+	Properties UPnPTargetListener;

+	String serviceId;

+	Vector upnpListeners = new Vector();

+	

+	public UPnPEventNotifier(BundleContext context,String deviceId,UPnPService service,EventSource source){

+		this.context=context;

+		this.deviceId=deviceId;

+		this.service=service;

+		this.source=source;

+		this.serviceId=service.getId();

+		setupUPnPListenerHouseKeeping(deviceId);

+	}

+	

+	/**

+	 * @param deviceId

+	 */

+	private void setupUPnPListenerHouseKeeping(String deviceId) {

+		UPnPTargetListener = new Properties();

+		UPnPTargetListener.put(UPnPDevice.ID,deviceId);

+		UPnPTargetListener.put(UPnPService.ID,serviceId);

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

+		

+		ServiceReference[] listeners = null; 

+		try {

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

+			if (listeners != null){

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

+					ServiceReference sr = listeners[i];

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

+					if (filter == null) upnpListeners.add(sr);

+					else {				

+						if (filter.match(UPnPTargetListener))

+							addNewListener(sr);

+					}

+				}

+			}

+		} catch (Exception ex) {

+			System.out.println(ex);

+		}

+		

+	    try {

+	    	//String filter = "(&" + ANY_UPnPEventListener + deviceId_Filter + ")";

+	    	String filter = ANY_UPnPEventListener;

+			context.addServiceListener(this,filter);

+		} catch (Exception ex) {

+			System.out.println(ex);

+		}

+		

+		if (source!=null){

+			UPnPStateVariable[] vars = service.getStateVariables();

+			if (vars != null){

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

+					if(vars[i].sendsEvents())

+						source.addPropertyChangeListener(vars[i].getName(),this);

+			}

+		}

+		

+		

+	}

+

+	/* (non-Javadoc)

+	 * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)

+	 */

+	public void propertyChange(PropertyChangeEvent evt) {

+		Iterator list = upnpListeners.iterator();

+		String property = evt.getPropertyName();

+		Object value = evt.getNewValue();

+		String valueString = value.toString();

+		final Properties events = new Properties();

+		events.put(property,valueString);

+		while (list.hasNext()){

+			final ServiceReference sr = (ServiceReference)list.next();

+			String[] props =sr.getPropertyKeys();

+			new Thread(null,null,"Notifier"){

+				public void run(){

+					try {

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

+						listener.notifyUPnPEvent(deviceId,serviceId,events);

+						context.ungetService(sr);

+					} catch (Exception ex){

+						System.out.println("UPnPEventNotifier Err: " +ex);

+					}

+				}

+			}.start();						

+		}

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public void serviceChanged(ServiceEvent e) {

+		switch(e.getType()){

+			case ServiceEvent.REGISTERED:{

+			    System.out.println();

+				ServiceReference sr = e.getServiceReference();

+			    System.out.println(sr);

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

+			    System.out.println(filter);

+				if (filter == null) addNewListener(sr);

+				else {				

+					if (filter.match(UPnPTargetListener))

+						addNewListener(sr);

+				}

+			};break;

+			

+			case ServiceEvent.MODIFIED:{				

+			};break;

+			

+			case ServiceEvent.UNREGISTERING:{	

+				removeListener(e.getServiceReference());

+			};break;

+				

+		}

+		

+	}

+

+	/**

+	 * @param reference

+	 */

+	private void removeListener(ServiceReference reference) {

+		upnpListeners.remove(reference);		

+	}

+

+	/**

+	 * @param reference

+	 */

+	private void addNewListener(ServiceReference reference) {

+		upnpListeners.add(reference);	

+	}

+	

+	public void destroy(){

+		context.removeServiceListener(this);

+		upnpListeners.removeAllElements();

+	}

+}

diff --git a/org.apache.felix.upnp.sample.binaryLight/src/main/resources/META-INF/MANIFEST.MF b/org.apache.felix.upnp.sample.binaryLight/src/main/resources/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..da39e56
--- /dev/null
+++ b/org.apache.felix.upnp.sample.binaryLight/src/main/resources/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Bundle-Author: Matteo Demuru <demuru@apache.org>,Francesco Furfari <furfari@apache.org>,Stefano "Kismet" Lenzi <lenzi@apache.org>

+Bundle-ClassPath: .

+

diff --git a/org.apache.felix.upnp.sample.binaryLight/src/main/resources/org/apache/felix/upnp/sample/binaryLight/images/LightFail.gif b/org.apache.felix.upnp.sample.binaryLight/src/main/resources/org/apache/felix/upnp/sample/binaryLight/images/LightFail.gif
new file mode 100644
index 0000000..974194b
--- /dev/null
+++ b/org.apache.felix.upnp.sample.binaryLight/src/main/resources/org/apache/felix/upnp/sample/binaryLight/images/LightFail.gif
Binary files differ
diff --git a/org.apache.felix.upnp.sample.binaryLight/src/main/resources/org/apache/felix/upnp/sample/binaryLight/images/LightOff.gif b/org.apache.felix.upnp.sample.binaryLight/src/main/resources/org/apache/felix/upnp/sample/binaryLight/images/LightOff.gif
new file mode 100644
index 0000000..b93b2ec
--- /dev/null
+++ b/org.apache.felix.upnp.sample.binaryLight/src/main/resources/org/apache/felix/upnp/sample/binaryLight/images/LightOff.gif
Binary files differ
diff --git a/org.apache.felix.upnp.sample.binaryLight/src/main/resources/org/apache/felix/upnp/sample/binaryLight/images/LightOn.gif b/org.apache.felix.upnp.sample.binaryLight/src/main/resources/org/apache/felix/upnp/sample/binaryLight/images/LightOn.gif
new file mode 100644
index 0000000..7024922
--- /dev/null
+++ b/org.apache.felix.upnp.sample.binaryLight/src/main/resources/org/apache/felix/upnp/sample/binaryLight/images/LightOn.gif
Binary files differ
diff --git a/org.apache.felix.upnp.sample.binaryLight/src/main/resources/org/apache/felix/upnp/sample/binaryLight/images/logo.gif b/org.apache.felix.upnp.sample.binaryLight/src/main/resources/org/apache/felix/upnp/sample/binaryLight/images/logo.gif
new file mode 100644
index 0000000..ef39d61
--- /dev/null
+++ b/org.apache.felix.upnp.sample.binaryLight/src/main/resources/org/apache/felix/upnp/sample/binaryLight/images/logo.gif
Binary files differ
diff --git a/org.apache.felix.upnp.sample.clock/pom.xml b/org.apache.felix.upnp.sample.clock/pom.xml
new file mode 100644
index 0000000..952b71f
--- /dev/null
+++ b/org.apache.felix.upnp.sample.clock/pom.xml
@@ -0,0 +1,60 @@
+<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 Sample Clock</name>

+  <artifactId>org.apache.felix.upnp.sample.clock</artifactId>

+  <version>0.1.0-SNAPSHOT</version>

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

+  <dependencies>

+    <dependency>

+      <groupId>${pom.groupId}</groupId>

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

+      <version>0.8.0-SNAPSHOT</version>

+      <scope>provided</scope>

+    </dependency>

+    <dependency>

+      <groupId>${pom.groupId}</groupId>

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

+      <version>0.8.0-SNAPSHOT</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>UPnPClock</bundleName>

+            <bundleVendor>Apache Software Foundation</bundleVendor>

+            <bundleVersion>0.1.0</bundleVersion>

+            <bundleDescription>

+               	CyberLink Clock clone to test UPnPBase driver

+            </bundleDescription>

+            <bundleSymbolicName>org.apache.felix.upnp.sample.clock</bundleSymbolicName>

+		<bundleActivator>org.apache.felix.upnp.sample.clock.Activator</bundleActivator>

+            <importPackage>

+			javax.swing,javax.imageio,org.osgi.framework;specification-version=1.3,org.osgi.service.upnp;specification-version=1.1

+            </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.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/Activator.java b/org.apache.felix.upnp.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/Activator.java
new file mode 100644
index 0000000..5b92db7
--- /dev/null
+++ b/org.apache.felix.upnp.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/Activator.java
@@ -0,0 +1,65 @@
+/*
+ *   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.sample.clock;
+
+import java.util.Dictionary;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.upnp.UPnPDevice;
+
+/* 
+* @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+*/
+public class Activator implements BundleActivator {
+
+	private ServiceRegistration serviceRegistration;
+	private BundleContext context;
+	private ClockFrame clockFrame;
+	
+	/**
+	 * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
+	 */
+	public void start(BundleContext context) throws Exception {
+		this.context = context;
+		doServiceRegistration();
+	}
+
+	private void doServiceRegistration() {
+		clockFrame = new ClockFrame(context);
+		Dictionary dict = clockFrame.getClockDevice().getDescriptions(null);
+		
+		serviceRegistration = context.registerService(
+				UPnPDevice.class.getName(),
+				clockFrame.getClockDevice(),
+				dict
+			);
+		
+		clockFrame.start();
+
+	}
+
+	/**
+	 * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
+	 */
+	public void stop(BundleContext context) throws Exception {
+		serviceRegistration.unregister();
+		clockFrame.stop();
+	}
+}
diff --git a/org.apache.felix.upnp.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/Clock.java b/org.apache.felix.upnp.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/Clock.java
new file mode 100644
index 0000000..294e637
--- /dev/null
+++ b/org.apache.felix.upnp.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/Clock.java
@@ -0,0 +1,156 @@
+/*

+ *   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.sample.clock;

+

+import java.util.Calendar;

+/* 

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

+*/

+

+public class Clock

+{

+	private Calendar cal;

+

+	public Clock(Calendar cal)

+	{

+		this.cal = cal;

+	}

+

+	public Calendar getCalendar()

+	{

+		return cal;

+	}

+

+	////////////////////////////////////////////////

+	//	Time

+	////////////////////////////////////////////////

+

+	public int getHour()

+	{

+		return getCalendar().get(Calendar.HOUR);

+	}

+

+	public int getMinute()

+	{

+		return getCalendar().get(Calendar.MINUTE);

+	}

+

+	public int getSecond()

+	{

+		return getCalendar().get(Calendar.SECOND);

+	}

+	

+	////////////////////////////////////////////////

+	//	paint

+	////////////////////////////////////////////////

+

+	public final static Clock getInstance()

+	{

+		return new Clock(Calendar.getInstance());

+	}

+

+	////////////////////////////////////////////////

+	//	getDateString

+	////////////////////////////////////////////////

+

+	public final static String toClockString(int value)

+	{

+		if (value < 10)

+			return "0" + Integer.toString(value);

+		return Integer.toString(value);

+	}

+

+	private final static String MONTH_STRING[] = {

+		"Jan",

+		"Feb",

+		"Mar",

+		"Apr",

+		"May",

+		"Jun",

+		"Jul",

+		"Aug",

+		"Sep",

+		"Oct",

+		"Nov",

+		"Dec",

+	};

+

+	public final static String toMonthString(int value)

+	{

+		value -= Calendar.JANUARY;

+		if (0 <= value && value < 12)

+			return MONTH_STRING[value];

+		return "";

+	}

+	

+	private final static String WEEK_STRING[] = {

+		"Sun",

+		"Mon",

+		"Tue",

+		"Wed",

+		"Thu",

+		"Fri",

+		"Sat",

+	};

+

+	public final static String toWeekString(int value)

+	{

+		value -= Calendar.SUNDAY;

+		if (0 <= value && value < 7)

+			return WEEK_STRING[value];

+		return "";

+	}

+	

+	public String getDateString()

+	{

+		Calendar cal = getCalendar();

+		return

+			toWeekString(cal.get(Calendar.DAY_OF_WEEK)) +", " + 

+			toMonthString(cal.get(Calendar.MONTH)) + " " +

+			Integer.toString(cal.get(Calendar.DATE)) + ", " +

+			toClockString(cal.get(Calendar.YEAR) % 100);

+	}

+

+	////////////////////////////////////////////////

+	//	getTimeString

+	////////////////////////////////////////////////

+	

+	public String getTimeString()

+	{

+		Calendar cal = getCalendar();

+		return

+			toClockString(cal.get(Calendar.HOUR)) +

+			(((cal.get(Calendar.SECOND) % 2) == 0) ? ":" : " ") +

+			toClockString(cal.get(Calendar.MINUTE));

+	}

+

+	////////////////////////////////////////////////

+	//	toString

+	////////////////////////////////////////////////

+

+	public String toString()

+	{

+		Calendar cal = getCalendar();

+		return

+			getDateString() + ", " +

+			toClockString(cal.get(Calendar.HOUR)) + ":" +

+			toClockString(cal.get(Calendar.MINUTE)) + ":" +

+			toClockString(cal.get(Calendar.SECOND));

+	}

+		

+}

+

diff --git a/org.apache.felix.upnp.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/ClockDevice.java b/org.apache.felix.upnp.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/ClockDevice.java
new file mode 100644
index 0000000..677975b
--- /dev/null
+++ b/org.apache.felix.upnp.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/ClockDevice.java
@@ -0,0 +1,135 @@
+/*

+ *   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.sample.clock;

+

+

+import java.beans.PropertyChangeEvent;

+import java.util.Dictionary;

+import java.util.Properties;

+

+import org.osgi.framework.BundleContext;

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

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

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

+/* 

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

+*/

+

+public class ClockDevice implements UPnPDevice {

+

+	final private String DEVICE_ID = "uuid:Felix-Clock";

+	private BundleContext context;

+	private TimerService timerService;

+	private UPnPService[] services;

+	private Dictionary dictionary;

+	UPnPEventNotifier notifier;

+	

+	public ClockDevice(BundleContext context) {

+		this.context=context;

+		timerService = new TimerService();

+		services = new UPnPService[]{timerService};

+		setupDeviceProperties();

+		buildEventNotifyer();

+	}

+

+	/**

+	 * 

+	 */

+	private void buildEventNotifyer() {

+		 notifier = new UPnPEventNotifier(context,this,timerService,null);

+	}

+

+	private void setupDeviceProperties(){

+		dictionary = new Properties();

+		dictionary.put(UPnPDevice.UPNP_EXPORT,"");

+		dictionary.put(

+		        org.osgi.service

+		        	.device.Constants.DEVICE_CATEGORY,

+	        	new String[]{UPnPDevice.DEVICE_CATEGORY}

+	        );

+		//dictionary.put(UPnPDevice.DEVICE_CATEGORY,new String[]{UPnPDevice.DEVICE_CATEGORY});

+		dictionary.put(UPnPDevice.FRIENDLY_NAME,"Felix OSGi-UPnP Clock");

+		dictionary.put(UPnPDevice.MANUFACTURER,"Apache Software Foundation");

+		dictionary.put(UPnPDevice.MANUFACTURER_URL,"http://incubator.apache.org/felix/");

+		dictionary.put(UPnPDevice.MODEL_DESCRIPTION,"A CyberLink Clock device clone to test OSGi to UPnP service export");

+		dictionary.put(UPnPDevice.MODEL_NAME,"DolceDormire");

+		dictionary.put(UPnPDevice.MODEL_NUMBER,"1.0");

+		dictionary.put(UPnPDevice.MODEL_URL,"http://incubator.apache.org/felix/DolceDormire");

+		dictionary.put(UPnPDevice.PRESENTATION_URL,"http://incubator.apache.org/felix/dolceDormire/presentation");

+		dictionary.put(UPnPDevice.SERIAL_NUMBER,"123456789");

+		dictionary.put(UPnPDevice.TYPE,"urn:schemas-upnp-org:device:clock:1");

+		dictionary.put(UPnPDevice.UDN,DEVICE_ID);

+		//dictionary.put(UPnPDevice.ID,dictionary.get(UPnPDevice.UDN));

+		dictionary.put(UPnPDevice.UPC,"1213456789");

+	}

+	

+	

+	/* (non-Javadoc)

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

+	 */

+	public UPnPService getService(String serviceId) {

+		if  (serviceId.equals(timerService.getId())) return timerService;

+		return null;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public UPnPService[] getServices() {

+		return services;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public UPnPIcon[] getIcons(String locale) {

+		UPnPIcon icon = new ClockIcon();

+		return new UPnPIcon[]{icon} ;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public Dictionary getDescriptions(String locale) {

+		return dictionary;

+	}

+

+	/**

+	 * 

+	 */

+	public void start() {

+		// TODO Auto-generated method stub

+		

+	}

+

+	/**

+	 * 

+	 */

+	public void stop() {

+		notifier.destroy();	

+	}

+

+	/**

+	 * 

+	 */

+	public void update() {

+		Clock clock = Clock.getInstance();

+		String timeStr = clock.toString();

+		notifier.propertyChange(new PropertyChangeEvent(this,"Time","",timeStr));

+	}

+	

+}

diff --git a/org.apache.felix.upnp.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/ClockFrame.java b/org.apache.felix.upnp.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/ClockFrame.java
new file mode 100644
index 0000000..a35dc38
--- /dev/null
+++ b/org.apache.felix.upnp.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/ClockFrame.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.sample.clock;

+

+import java.awt.BorderLayout;

+import java.awt.event.WindowAdapter;

+import java.awt.event.WindowEvent;

+import java.net.URL;

+

+import javax.swing.ImageIcon;

+import javax.swing.JFrame;

+

+import org.osgi.framework.BundleContext;

+import org.osgi.framework.BundleException;

+/* 

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

+*/

+

+public class ClockFrame extends JFrame implements Runnable 

+{

+	private final static String TITLE = "Felix UPnP Clock";

+	private ClockDevice clockDev;

+	private ClockPane clockPane;

+	

+	public ClockFrame(final BundleContext context)

+	{

+		super(TITLE);

+		try {

+			clockDev = new ClockDevice( context);

+		}

+		catch (Exception e) {

+			System.out.println(e);

+		}

+				

+		getContentPane().setLayout(new BorderLayout());

+

+		clockPane = new ClockPane();		

+		getContentPane().add(clockPane, BorderLayout.CENTER);

+

+		addWindowListener(new WindowAdapter(){

+			public void windowClosing(WindowEvent e) 

+			{

+				try {

+					context.getBundle().stop();

+				} catch (BundleException ex) {

+					ex.printStackTrace();

+				}

+			}

+		});			

+	       try {

+	            URL eventIconUrl = ClockFrame.class.getResource("images/logo.gif");           

+	            ImageIcon icon=  new ImageIcon(eventIconUrl,"logo");

+	            setIconImage(icon.getImage());

+	       }

+	        catch (Exception ex){

+	                System.out.println("Resource: IMAGES/logo.gif not found : " + ex.toString());

+	        }

+		

+		pack();

+		setVisible(true);

+	}

+

+	public ClockPane getClockPanel()

+	{

+		return clockPane;

+	}

+

+	public ClockDevice getClockDevice()

+	{

+		return clockDev;

+	}

+		

+	////////////////////////////////////////////////

+	//	run	

+	////////////////////////////////////////////////

+

+	private Thread timerThread = null;

+		

+	public void run()

+	{

+		Thread thisThread = Thread.currentThread();

+

+		while (timerThread == thisThread) {

+			getClockDevice().update();

+			getClockPanel().repaint();

+			try {

+				Thread.sleep(1000);

+			}

+			catch(InterruptedException e) {}

+		}

+	}

+	

+	public void start()

+	{

+		clockDev.start();

+		

+		timerThread = new Thread(this);

+		timerThread.start();

+	}

+	

+	public void stop()

+	{

+		clockDev.stop();

+		timerThread = null;

+		dispose();

+	}

+

+}

+

diff --git a/org.apache.felix.upnp.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/ClockIcon.java b/org.apache.felix.upnp.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/ClockIcon.java
new file mode 100644
index 0000000..53586be
--- /dev/null
+++ b/org.apache.felix.upnp.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/ClockIcon.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.sample.clock;

+import java.io.IOException;

+import java.io.InputStream;

+

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

+/* 

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

+*/

+

+public class ClockIcon implements UPnPIcon {

+

+	/* (non-Javadoc)

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

+	 */

+	public String getMimeType() {

+		return "image/gif";

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public int getWidth() {

+		return 32;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public int getHeight() {

+		return 32;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public int getSize() {

+		return 0;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public int getDepth() {

+		return 16;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public InputStream getInputStream() throws IOException {

+		return ClockIcon.class.getResourceAsStream("images/clock.gif");

+	}

+}

diff --git a/org.apache.felix.upnp.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/ClockPane.java b/org.apache.felix.upnp.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/ClockPane.java
new file mode 100644
index 0000000..3a9e232
--- /dev/null
+++ b/org.apache.felix.upnp.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/ClockPane.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.sample.clock;

+

+import java.awt.Color;

+import java.awt.Dimension;

+import java.awt.Font;

+import java.awt.FontMetrics;

+import java.awt.Graphics;

+import java.awt.geom.Rectangle2D;

+import java.awt.image.BufferedImage;

+

+import javax.imageio.ImageIO;

+import javax.swing.JPanel;

+

+/* 

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

+*/

+

+public class ClockPane extends JPanel  // MouseListener

+{

+	public ClockPane()

+	{

+		loadImage();

+		initPanel();

+	}

+

+	////////////////////////////////////////////////

+	//	Background

+	////////////////////////////////////////////////

+	

+

+	private BufferedImage panelmage;

+	

+	private void loadImage()

+	{

+		

+		try {

+			panelmage = ImageIO.read(ClockPane.class.getResourceAsStream("images/clock.jpg"));

+		}

+		catch (Exception e) {

+			System.out.println(e);

+		}

+	}

+

+	private BufferedImage getPaneImage()

+	{

+		return panelmage;

+	}

+

+	////////////////////////////////////////////////

+	//	Background

+	////////////////////////////////////////////////

+

+	private void initPanel()

+	{

+		BufferedImage panelmage = getPaneImage();

+		setPreferredSize(new Dimension(panelmage.getWidth(), panelmage.getHeight()));

+	}

+

+	////////////////////////////////////////////////

+	//	Font

+	////////////////////////////////////////////////

+

+	private final static String DEFAULT_FONT_NAME = "Lucida Console";

+	private final static int DEFAULT_TIME_FONT_SIZE = 60;

+	private final static int DEFAULT_DATE_FONT_SIZE = 18;

+	private final static int DEFAULT_SECOND_BLOCK_HEIGHT = 8;

+	private final static int DEFAULT_SECOND_BLOCK_FONT_SIZE = 10;

+

+	private Font timeFont = null;

+	private Font dateFont = null;

+	private Font secondFont = null;

+

+	private Font getFont(Graphics g, int size)

+	{

+		Font font = new Font(DEFAULT_FONT_NAME, Font.PLAIN, size);

+		if (font != null)

+			return font;

+		return g.getFont();

+	}

+		

+	private Font getTimeFont(Graphics g)

+	{

+		if (timeFont == null)

+			timeFont = getFont(g, DEFAULT_TIME_FONT_SIZE);

+		return timeFont;

+	}

+

+	private Font getDateFont(Graphics g)

+	{

+		if (dateFont == null)

+			dateFont = getFont(g, DEFAULT_DATE_FONT_SIZE);

+		return dateFont;

+	}

+

+	private Font getSecondFont(Graphics g)

+	{

+		if (secondFont == null)

+			secondFont = getFont(g, DEFAULT_SECOND_BLOCK_FONT_SIZE);

+		return secondFont;

+	}

+

+	////////////////////////////////////////////////

+	//	paint

+	////////////////////////////////////////////////

+

+	private void drawClockInfo(Graphics g)

+	{

+		Clock clock = Clock.getInstance();

+		

+		int winWidth = getWidth();

+		int winHeight = getHeight();

+		

+		g.setColor(Color.BLACK);

+		

+		//// Time String ////

+		

+		String timeStr = clock.getTimeString();

+

+		Font timeFont = getTimeFont(g);

+		g.setFont(timeFont);

+

+		FontMetrics timeFontMetric = g.getFontMetrics();

+		Rectangle2D timeStrBounds = timeFontMetric.getStringBounds(timeStr, g);

+

+		int timeStrWidth = (int)timeStrBounds.getWidth();		

+		int timeStrHeight = (int)timeStrBounds.getHeight();

+		int timeStrX = (winWidth-timeStrWidth)/2;

+		int timeStrY = (winHeight+timeStrHeight)/2;

+		int timeStrOffset = timeStrHeight/8/2;

+		g.drawString(

+			timeStr,

+			timeStrX,

+			timeStrY);

+

+		//// Date String ////

+

+		String dateStr = clock.getDateString();

+

+		Font dateFont = getDateFont(g);

+		g.setFont(dateFont);

+

+		FontMetrics dateFontMetric = g.getFontMetrics();

+		Rectangle2D dateStrBounds = dateFontMetric.getStringBounds(dateStr, g);

+

+		g.drawString(

+			dateStr,

+			(winWidth-(int)dateStrBounds.getWidth())/2,

+			timeStrY-timeStrHeight-timeStrOffset);

+

+		//// Second Bar ////

+		

+		Font secFont = getSecondFont(g);

+		g.setFont(secFont);

+		int sec = clock.getSecond();

+		int secBarBlockSize = timeStrWidth / 60;

+		int secBarBlockY = timeStrY + timeStrOffset;

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

+			int x = timeStrX + (secBarBlockSize*n);

+			g.fillRect(

+				x,

+				secBarBlockY,

+				secBarBlockSize-1,

+				DEFAULT_SECOND_BLOCK_HEIGHT);

+		}

+		if (sec != 0 && (sec % 10) == 0) {

+			int x = timeStrX + (secBarBlockSize*sec);

+			g.drawString(

+				Integer.toString(sec),

+				x + secBarBlockSize,

+				secBarBlockY + DEFAULT_SECOND_BLOCK_HEIGHT);

+		}

+	}

+

+	private void clear(Graphics g)

+	{

+		g.setColor(Color.GRAY);

+		g.clearRect(0, 0, getWidth(), getHeight());

+	}

+	

+

+	private void drawPanelImage(Graphics g)

+	{

+		g.drawImage(getPaneImage(), 0, 0, null);

+	}

+		

+	public void paint(Graphics g)

+	{

+		clear(g);

+		drawPanelImage(g);

+		drawClockInfo(g);

+	}

+}

+

diff --git a/org.apache.felix.upnp.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/EventSource.java b/org.apache.felix.upnp.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/EventSource.java
new file mode 100644
index 0000000..62fd7b1
--- /dev/null
+++ b/org.apache.felix.upnp.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/EventSource.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.sample.clock;

+

+import java.beans.PropertyChangeListener;

+/* 

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

+*/

+

+public interface EventSource {

+	void addPropertyChangeListener(PropertyChangeListener listener);

+	void addPropertyChangeListener(String propertyName, PropertyChangeListener listener);

+	void removePropertyChangeListener(PropertyChangeListener listener);

+	void removePropertyChangeListener(String propertyName, PropertyChangeListener listener);

+}

+

diff --git a/org.apache.felix.upnp.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/GetTimeAction.java b/org.apache.felix.upnp.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/GetTimeAction.java
new file mode 100644
index 0000000..d3d8728
--- /dev/null
+++ b/org.apache.felix.upnp.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/GetTimeAction.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.sample.clock;

+

+import java.util.Dictionary;

+import java.util.Hashtable;

+

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

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

+

+/* 

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

+*/

+

+public class GetTimeAction implements UPnPAction {

+

+	final private String NAME = "GetTime";

+	final private String RESULT_STATUS = "CurrentTime";

+	final private String[] OUT_ARG_NAMES = new String[]{RESULT_STATUS};

+	private TimeStateVariable time;

+	

+	

+	public GetTimeAction(TimeStateVariable time){

+		this.time = time;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public String getName() {

+		return NAME;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public String getReturnArgumentName() {

+		return null;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public String[] getInputArgumentNames() {

+		

+		return null;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public String[] getOutputArgumentNames() {

+		return OUT_ARG_NAMES;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public UPnPStateVariable getStateVariable(String argumentName) {

+		return time;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public Dictionary invoke(Dictionary args) throws Exception {

+		String value = time.getCurrentTime();

+		Hashtable result = new Hashtable();

+		result.put(RESULT_STATUS,value);

+		return result;

+	}

+}

diff --git a/org.apache.felix.upnp.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/ResultStateVariable.java b/org.apache.felix.upnp.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/ResultStateVariable.java
new file mode 100644
index 0000000..45983b8
--- /dev/null
+++ b/org.apache.felix.upnp.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/ResultStateVariable.java
@@ -0,0 +1,96 @@
+/*

+ *   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.sample.clock;

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

+/* 

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

+*/

+

+public class ResultStateVariable implements UPnPStateVariable{

+	

+	final private String NAME = "Result";

+	final private String DEFAULT_VALUE = "";

+	private Clock clock;

+	

+	

+	public ResultStateVariable(){

+	}

+	

+	/* (non-Javadoc)

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

+	 */

+	public String getName() {

+		return NAME;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPStateVariable#getJavaDataType()

+	 */

+	public Class getJavaDataType() {

+		return String.class;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPStateVariable#getUPnPDataType()

+	 */

+	public String getUPnPDataType() {

+		return TYPE_STRING;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPStateVariable#getDefaultValue()

+	 */

+	public Object getDefaultValue() {

+		return DEFAULT_VALUE;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPStateVariable#getAllowedValues()

+	 */

+	public String[] getAllowedValues() {

+		return null;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPStateVariable#getMinimum()

+	 */

+	public Number getMinimum() {

+		return null;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPStateVariable#getMaximum()

+	 */

+	public Number getMaximum() {

+		return null;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPStateVariable#getStep()

+	 */

+	public Number getStep() {

+		return null;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPStateVariable#sendsEvents()

+	 */

+	public boolean sendsEvents() {

+		return false;

+	}

+	

+}

diff --git a/org.apache.felix.upnp.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/SetTimeAction.java b/org.apache.felix.upnp.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/SetTimeAction.java
new file mode 100644
index 0000000..6312e02
--- /dev/null
+++ b/org.apache.felix.upnp.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/SetTimeAction.java
@@ -0,0 +1,92 @@
+/*

+ *   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.sample.clock;

+

+import java.util.Dictionary;

+

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

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

+

+/* 

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

+*/

+

+public class SetTimeAction implements UPnPAction {

+

+	final private String NAME = "SetTime";

+	final private String NEW_TIME_VALUE = "NewTime";

+	final private String NEW_RESULT_VALUE = "Result";

+	final private String[] IN_ARG_NAMES = new String[]{NEW_TIME_VALUE};

+	final private String[] OUT_ARG_NAMES = new String[]{NEW_RESULT_VALUE};

+	private UPnPStateVariable time,result;

+	

+	

+	public SetTimeAction(UPnPStateVariable time,UPnPStateVariable result){

+		this.time = time;

+		this.result=result;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public String getName() {

+		return NAME;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public String getReturnArgumentName() {

+		return "Result";

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public String[] getInputArgumentNames() {

+		return IN_ARG_NAMES;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public String[] getOutputArgumentNames() {

+		return OUT_ARG_NAMES;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public UPnPStateVariable getStateVariable(String argumentName) {

+		if (argumentName.equals("NewTime")) return time;

+		else if (argumentName.equals("Result")) return result;

+		else return null;

+	}

+

+	/* (non-Javadoc)

+	 * 

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

+	 */

+	public Dictionary invoke(Dictionary args) throws Exception {

+		//Date value = (Date) args.get(NEW_TIME_VALUE);

+		long l = ((Long) args.get(NEW_TIME_VALUE)).longValue();

+		((TimeStateVariable) time).setCurrentTime(l);

+		args.remove(NEW_TIME_VALUE);

+		args.put(NEW_RESULT_VALUE,((TimeStateVariable) time).getCurrentTime());

+		return args;

+	}

+}

diff --git a/org.apache.felix.upnp.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/TimeStateVariable.java b/org.apache.felix.upnp.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/TimeStateVariable.java
new file mode 100644
index 0000000..8ee30b5
--- /dev/null
+++ b/org.apache.felix.upnp.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/TimeStateVariable.java
@@ -0,0 +1,104 @@
+/*

+ *   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.sample.clock;

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

+/* 

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

+*/

+

+public class TimeStateVariable implements UPnPStateVariable{

+	

+	final private String NAME = "Time";

+	final private String DEFAULT_VALUE = "";

+	private Clock clock;

+	

+	

+	public TimeStateVariable(){

+		clock = Clock.getInstance();

+	}

+	

+	/* (non-Javadoc)

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

+	 */

+	public String getName() {

+		return NAME;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPStateVariable#getJavaDataType()

+	 */

+	public Class getJavaDataType() {

+		return Long.class;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPStateVariable#getUPnPDataType()

+	 */

+	public String getUPnPDataType() {

+		return TYPE_TIME;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPStateVariable#getDefaultValue()

+	 */

+	public Object getDefaultValue() {

+		return DEFAULT_VALUE;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPStateVariable#getAllowedValues()

+	 */

+	public String[] getAllowedValues() {

+		return null;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPStateVariable#getMinimum()

+	 */

+	public Number getMinimum() {

+		return null;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPStateVariable#getMaximum()

+	 */

+	public Number getMaximum() {

+		return null;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPStateVariable#getStep()

+	 */

+	public Number getStep() {

+		return null;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPStateVariable#sendsEvents()

+	 */

+	public boolean sendsEvents() {

+		return true;

+	}

+	

+	public String getCurrentTime(){

+		return clock.getTimeString();

+	}

+	

+	public void setCurrentTime(long milliseconds){

+		clock.getCalendar().setTimeInMillis(milliseconds);

+	}

+}

diff --git a/org.apache.felix.upnp.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/TimerService.java b/org.apache.felix.upnp.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/TimerService.java
new file mode 100644
index 0000000..57927cf
--- /dev/null
+++ b/org.apache.felix.upnp.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/TimerService.java
@@ -0,0 +1,103 @@
+/*

+ *   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.sample.clock;

+

+import java.util.HashMap;

+

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

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

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

+

+/* 

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

+*/

+

+public class TimerService implements UPnPService {

+	final private String SERVICE_ID = "urn:schemas-upnp-org:serviceId:timer:1";

+	final private String SERVICE_TYPE = "urn:schemas-upnp-org:service:timer:1";

+	final private String VERSION ="1";

+

+	private UPnPStateVariable time,result;

+	private UPnPStateVariable[] states;

+	private HashMap actions = new HashMap();

+	

+	

+	public TimerService(){

+		time = new TimeStateVariable();

+		result = new ResultStateVariable();

+		this.states = new UPnPStateVariable[]{time,result};

+		

+		UPnPAction setTime= new SetTimeAction(time,result);

+		UPnPAction getTime = new GetTimeAction((TimeStateVariable)time);

+		actions.put(setTime.getName(),setTime);

+		actions.put(getTime.getName(),getTime);

+		

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPService#getId()

+	 */

+	public String getId() {

+		return SERVICE_ID;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPService#getType()

+	 */

+	public String getType() {

+		return SERVICE_TYPE;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPService#getVersion()

+	 */

+	public String getVersion() {

+		return VERSION;

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPService#getAction(java.lang.String)

+	 */

+	public UPnPAction getAction(String name) {

+		return (UPnPAction)actions.get(name);

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPService#getActions()

+	 */

+	public UPnPAction[] getActions() {

+		return (UPnPAction[])(actions.values()).toArray(new UPnPAction[]{});

+	}

+

+	/* (non-Javadoc)

+	 * @see org.osgi.service.upnp.UPnPService#getStateVariables()

+	 */

+	public UPnPStateVariable[] getStateVariables() {

+		return states;

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public UPnPStateVariable getStateVariable(String name) {

+		if (name.equals("Time"))

+			return time;

+		else if (name.equals("Result"))

+			return result;

+		else return null;

+	}

+}

diff --git a/org.apache.felix.upnp.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/UPnPEventNotifier.java b/org.apache.felix.upnp.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/UPnPEventNotifier.java
new file mode 100644
index 0000000..b7c41df
--- /dev/null
+++ b/org.apache.felix.upnp.sample.clock/src/main/java/org/apache/felix/upnp/sample/clock/UPnPEventNotifier.java
@@ -0,0 +1,187 @@
+/*

+ *   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.sample.clock;

+

+import java.beans.PropertyChangeEvent;

+import java.beans.PropertyChangeListener;

+import java.util.Dictionary;

+import java.util.Iterator;

+import java.util.Properties;

+import java.util.Vector;

+

+import org.osgi.framework.BundleContext;

+import org.osgi.framework.Constants;

+import org.osgi.framework.Filter;

+import org.osgi.framework.ServiceEvent;

+import org.osgi.framework.ServiceListener;

+import org.osgi.framework.ServiceReference;

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

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

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

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

+

+/* 

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

+*/

+

+public class UPnPEventNotifier implements PropertyChangeListener,ServiceListener {

+	BundleContext context;

+	UPnPDevice device;

+	UPnPService service;

+	EventSource source;

+	

+	Properties UPnPTargetListener;

+	String deviceId;

+	String serviceId;

+	Vector upnpListeners = new Vector();

+	

+	public UPnPEventNotifier(BundleContext context,UPnPDevice device,UPnPService service,EventSource source){

+		this.context=context;

+		this.device=device;

+		this.service=service;

+		this.source=source;

+		this.serviceId=service.getId();

+		setupUPnPListenerHouseKeeping(device);

+	}

+	

+	/**

+	 * @param deviceId

+	 */

+	private void setupUPnPListenerHouseKeeping(UPnPDevice device) {

+		UPnPTargetListener = new Properties();

+		Dictionary dict = device.getDescriptions(null);

+		deviceId = (String) dict.get(UPnPDevice.ID);

+		UPnPTargetListener.put(UPnPDevice.ID,deviceId);

+		UPnPTargetListener.put(UPnPService.ID,serviceId);

+		UPnPTargetListener.put(UPnPDevice.TYPE,dict.get(UPnPDevice.TYPE));

+		UPnPTargetListener.put(UPnPService.TYPE,service.getType());

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

+		

+		ServiceReference[] listeners = null; 

+		try {

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

+			if (listeners != null){

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

+					ServiceReference sr = listeners[i];

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

+					if (filter == null) upnpListeners.add(sr);

+					else {				

+						if (filter.match(UPnPTargetListener))

+							addNewListener(sr);

+					}

+				}

+			}

+		} catch (Exception ex) {

+			System.out.println(ex);

+		}

+		

+	    try {

+	    	//String filter = "(&" + ANY_UPnPEventListener + deviceId_Filter + ")";

+	    	String filter = ANY_UPnPEventListener;

+			context.addServiceListener(this,filter);

+		} catch (Exception ex) {

+			System.out.println(ex);

+		}

+		

+		if (source!=null){

+			UPnPStateVariable[] vars = service.getStateVariables();

+			if (vars != null){

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

+					if(vars[i].sendsEvents())

+						source.addPropertyChangeListener(vars[i].getName(),this);

+			}

+		}

+		

+		

+	}

+

+	/* (non-Javadoc)

+	 * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)

+	 */

+	public void propertyChange(PropertyChangeEvent evt) {

+		Iterator list = upnpListeners.iterator();

+		String property = evt.getPropertyName();

+		Object value = evt.getNewValue();

+		String valueString = value.toString();

+		final Properties events = new Properties();

+		events.put(property,valueString);

+		while (list.hasNext()){

+			final ServiceReference sr = (ServiceReference)list.next();

+			String[] props =sr.getPropertyKeys();

+			new Thread(){

+				public void run(){

+					try {

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

+						listener.notifyUPnPEvent(deviceId,serviceId,events);

+						context.ungetService(sr);

+					} catch (Exception ex){

+						System.out.println("Clock UPnPEventNotifier Err: " +ex);

+						System.out.println("context: " +context);

+						System.out.println("listener: " +context.getService(sr));

+						System.out.println("sr: " +sr);

+						System.out.println();

+					}

+				}

+			}.start();						

+		}

+	}

+

+	/* (non-Javadoc)

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

+	 */

+	public void serviceChanged(ServiceEvent e) {

+		switch(e.getType()){

+			case ServiceEvent.REGISTERED:{

+				ServiceReference sr = e.getServiceReference();

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

+				if (filter == null) addNewListener(sr);

+				else {				

+					if (filter.match(UPnPTargetListener))

+						addNewListener(sr);

+				}

+			};break;

+			

+			case ServiceEvent.MODIFIED:{				

+			};break;

+			

+			case ServiceEvent.UNREGISTERING:{	

+				removeListener(e.getServiceReference());

+			};break;

+				

+		}

+		

+	}

+

+	/**

+	 * @param reference

+	 */

+	private void removeListener(ServiceReference reference) {

+		upnpListeners.remove(reference);		

+	}

+

+	/**

+	 * @param reference

+	 */

+	private void addNewListener(ServiceReference reference) {

+		upnpListeners.add(reference);	

+	}

+	

+	public void destroy(){

+		context.removeServiceListener(this);

+		upnpListeners.removeAllElements();

+	}

+}

diff --git a/org.apache.felix.upnp.sample.clock/src/main/resources/META-INF/Manifest.mf b/org.apache.felix.upnp.sample.clock/src/main/resources/META-INF/Manifest.mf
new file mode 100644
index 0000000..69ff757
--- /dev/null
+++ b/org.apache.felix.upnp.sample.clock/src/main/resources/META-INF/Manifest.mf
@@ -0,0 +1,4 @@
+Bundle-Author: Matteo Demuru <demuru@apache.org>,Francesco Furfari <furfari@apache.org>,Satoshi Konno <konno@users.sourceforge.

+ net>,Stefano "Kismet" Lenzi <lenzi@apache.org>

+Bundle-ClassPath: .

+

diff --git a/org.apache.felix.upnp.sample.clock/src/main/resources/org/apache/felix/upnp/sample/clock/images/clock.gif b/org.apache.felix.upnp.sample.clock/src/main/resources/org/apache/felix/upnp/sample/clock/images/clock.gif
new file mode 100644
index 0000000..21327fc
--- /dev/null
+++ b/org.apache.felix.upnp.sample.clock/src/main/resources/org/apache/felix/upnp/sample/clock/images/clock.gif
Binary files differ
diff --git a/org.apache.felix.upnp.sample.clock/src/main/resources/org/apache/felix/upnp/sample/clock/images/clock.jpg b/org.apache.felix.upnp.sample.clock/src/main/resources/org/apache/felix/upnp/sample/clock/images/clock.jpg
new file mode 100644
index 0000000..f7fcea0
--- /dev/null
+++ b/org.apache.felix.upnp.sample.clock/src/main/resources/org/apache/felix/upnp/sample/clock/images/clock.jpg
Binary files differ
diff --git a/org.apache.felix.upnp.sample.clock/src/main/resources/org/apache/felix/upnp/sample/clock/images/logo.gif b/org.apache.felix.upnp.sample.clock/src/main/resources/org/apache/felix/upnp/sample/clock/images/logo.gif
new file mode 100644
index 0000000..ef39d61
--- /dev/null
+++ b/org.apache.felix.upnp.sample.clock/src/main/resources/org/apache/felix/upnp/sample/clock/images/logo.gif
Binary files differ