blob: 0dd7f8bb12e64fe39ada0fdac2791ce55e1783f1 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.felix.upnp.extra.util;
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.UPnPLocalStateVariable;
import org.osgi.service.upnp.UPnPService;
import org.osgi.service.upnp.UPnPStateVariable;
/*
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*/
public class UPnPEventNotifier implements PropertyChangeListener, ServiceListener {
private BundleContext context;
private UPnPDevice device;
private UPnPService service;
private String deviceId;
private String serviceId;
private Properties UPnPTargetListener;
private Vector upnpListeners = new Vector();
final private Object LOCK = new Object();
private class NotifierThread extends Thread {
private ServiceReference sr;
private Properties events;
public NotifierThread(ServiceReference sr, Properties events){
super("UPnPEventNotifier");
this.sr = sr;
this.events = events;
}
public void run(){
try {
UPnPEventListener listener = (UPnPEventListener) context.getService(sr);
listener.notifyUPnPEvent(deviceId,serviceId,events);
context.ungetService(sr);
} catch (Exception ignored){
}
}
}
public UPnPEventNotifier(BundleContext context, UPnPDevice device, UPnPService service, EventSource source){
this(context,device,service);
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);
}
}
}
}
}
public UPnPEventNotifier(BundleContext context, UPnPDevice device, UPnPService service){
this.context=context;
this.device=device;
this.service=service;
setupUPnPListenerWatcher();
}
/**
* @param deviceId
*/
private void setupUPnPListenerWatcher() {
Dictionary dict = device.getDescriptions(null);
this.deviceId = (String) dict.get(UPnPDevice.ID);
this.serviceId=service.getId();
UPnPTargetListener = new Properties();
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()+")";
synchronized (LOCK) {
try {
String filter = ANY_UPnPEventListener;
context.addServiceListener(this,filter);
} catch (Exception ex) {
System.out.println(ex);
}
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);
}
Properties status = getCurrentStatus();
if (! status.isEmpty())
doNotify(status);
} // end LOCK
}
private Properties getCurrentStatus() {
Properties status = new Properties();
UPnPStateVariable[] vars = service.getStateVariables();
if (vars != null){
for (int i=0;i<vars.length;i++){
if(vars[i].sendsEvents()){
if (vars[i] instanceof UPnPLocalStateVariable){
UPnPLocalStateVariable localVar = (UPnPLocalStateVariable) vars[i];
String property = localVar.getName();
Object value = localVar.getCurrentValue();
status.put(property,value);
}
else {
System.out.println("[Warning] The StateVariable (" +vars[i].getName() +")"
+ " of device (ID:" + deviceId + ") "
+ "should implement the interface UPnPLocalStateVariable");
}
}
} // end for
}
return status;
}
/* (non-Javadoc)
* @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
*/
public void propertyChange(PropertyChangeEvent evt) {
String property = evt.getPropertyName();
Object value = evt.getNewValue();
Properties events = new Properties();
events.put(property,value);
doNotify(events);
}
private void doNotify(Properties events){
synchronized (LOCK) {
Iterator list = upnpListeners.iterator();
while (list.hasNext()){
final ServiceReference sr = (ServiceReference)list.next();
new NotifierThread(sr,events).start();
}
}
}
private void doNotify(ServiceReference sr) {
Properties status = getCurrentStatus();
if (! status.isEmpty())
new NotifierThread(sr,status).start();
}
/* (non-Javadoc)
* @see org.osgi.framework.ServiceListener#serviceChanged(org.osgi.framework.ServiceEvent)
*/
public void serviceChanged(ServiceEvent e) {
ServiceReference sr = e.getServiceReference();
synchronized (LOCK) {
switch(e.getType()){
case ServiceEvent.REGISTERED:{
Filter filter = (Filter) sr.getProperty(UPnPEventListener.UPNP_FILTER);
if (filter == null) {
addNewListener(sr);
doNotify(sr);
}
else {
if (filter.match(UPnPTargetListener)){
addNewListener(sr);
doNotify(sr);
}
}
};break;
case ServiceEvent.MODIFIED:{
Filter filter = (Filter) sr.getProperty(UPnPEventListener.UPNP_FILTER);
removeListener(sr);
if (filter == null)
addNewListener(sr);
else {
if (filter.match(UPnPTargetListener))
addNewListener(sr);
}
};break;
case ServiceEvent.UNREGISTERING:{
removeListener(sr);
};break;
}
}//end LOCK
}
/**
* @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();
}
}