| /* |
| * 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(); |
| } |
| } |