/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.upnp.basedriver.export; import java.io.File; import java.util.Enumeration; import java.util.Hashtable; import java.util.Properties; import java.util.Vector; import org.apache.felix.upnp.basedriver.Activator; import org.cybergarage.upnp.Device; import org.cybergarage.upnp.DeviceList; import org.cybergarage.upnp.ServiceList; import org.osgi.framework.BundleException; import org.osgi.framework.Constants; import org.osgi.framework.Filter; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceEvent; import org.osgi.framework.ServiceListener; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; import org.osgi.service.upnp.UPnPDevice; import org.osgi.service.upnp.UPnPEventListener; /* * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a> */ public class ThreadExporter implements Runnable,ServiceListener { private boolean end; private RootDeviceExportingQueue queueRootDevice; // private String basePath; twa: redundant // private File baseFile; twa: redundant private Hashtable exportedDevices; private boolean listening; private class ExportedDeviceInfo{ private Device device; private ServiceRegistration serviceRegistration; //private DeviceNode deviceNode; /** * @param device * @param serviceRegistration * @param deviceNode */ private ExportedDeviceInfo(Device device, ServiceRegistration serviceRegistration, DeviceNode deviceNode) { super(); this.device = device; this.serviceRegistration = serviceRegistration; //this.deviceNode = deviceNode; } private Device getDevice() { return this.device; } private ServiceRegistration getServiceRegistration() { return this.serviceRegistration; } /*private DeviceNode getDeviceNode(){ return this.deviceNode; }*/ } /** * */ public ThreadExporter(RootDeviceExportingQueue queue) throws InvalidSyntaxException { end=false; queueRootDevice=queue; this.exportedDevices=new Hashtable(); setListening(false); } public void run() { File osgiRoot = Activator.bc.getDataFile(""); if (osgiRoot == null) { Activator.logger.ERROR("Unable to use filesystem"); while (true) { try { Activator.bc.getBundle().stop(); break; } catch (BundleException e) { e.printStackTrace(); try { Thread.sleep(1000); } catch (InterruptedException ex) { ex.printStackTrace(); } } } return; } ServiceReference rootDevice = null; while (!shouldEnd()) { DeviceNode dn = queueRootDevice.getRootDevice(); if (dn == null) continue; rootDevice = dn.getReference(); if(!getListening()) setListen(); Activator.logger.INFO("[Exporter] Exporting device "+ rootDevice.getProperty(UPnPDevice.FRIENDLY_NAME)); /* * I don't know if the exporting should be make default language of the framework * or without any lanuguages Root r = new Root(rootDevice, context, context .getProperty(Constants.FRAMEWORK_LANGUAGE)); */ synchronized (this) { Device d = BuildDevice.createCyberLinkDevice(dn.getReference()); if (d != null) { if(!bindInvokes(d,rootDevice)){ Activator.logger.DEBUG("Unable to find all the sub device or to set action listener"); continue; } ServiceRegistration listenReg = bindSubscribe(d); if(listenReg==null){ Activator.logger.DEBUG("Unable to set action listener event listener"); continue; } //makeIcons(r.getRootDevice(),xml.getAbsolutePath()); d.start(); exportedDevices.put( rootDevice.getProperty(UPnPDevice.UDN), new ExportedDeviceInfo(d,listenReg,dn) ); } } } } /** * */ private void setListen() { { try { Activator.bc.addServiceListener( this, // fixed by Matteo and Francesco 21/9/04 "(&("+Constants.OBJECTCLASS+"="+UPnPDevice.class.getName()+")" + "(" + UPnPDevice.UPNP_EXPORT +"=*))" ); } catch (InvalidSyntaxException ingnore) {} } } /* /** * @param upnpDev * @param refDev * private void makeIcons( org.apache.felix.upnpbase.export.xml.Device upnpDev, String path) { Icon[] icons = upnpDev.getIcons(); if(icons!=null){ byte[] buf = new byte[512]; for (int i = 0; i < icons.length; i++) { try { String icoPath = path+icons[i].getUrl().replace('/',File.separatorChar); InputStream is = icons[i].getInputStream(); Converter.makeParentPath(icoPath); FileOutputStream fos = new FileOutputStream(icoPath); int n=is.read(buf,0,buf.length); while(n>0){ fos.write(buf,0,n); n=is.read(buf,0,buf.length); } } catch (IOException e) { e.printStackTrace(); } } } org.apache.felix.upnpbase.export.xml.Device[] devs = upnpDev.getDevices(); if(devs==null) return; for (int i = 0; i < devs.length; i++) { makeIcons(devs[i],path); } }*/ /** * This method is used to connect all the Action that are shown to UPnP world * by CyberLink UPnP Device to the real implementation that is conatined iniside * the OSGi service. * This method will connect even all the subdevice of te given OSGi device. * * @param d CyberLink Device that will be used associated to the OSGi Device * @param rootDevice ServiceReference to the OSGi Device that will be used as * implementation of the CyberLink Device * @return true if and only if the binding off all the action of all the children * device is done succesfully */ private boolean bindInvokes(Device d, ServiceReference rootDevice) { bindInvoke(d,rootDevice); ServiceReference[] childs = null; try { childs = Activator.bc.getServiceReferences( UPnPDevice.class.getName(), "("+UPnPDevice.PARENT_UDN+"="+rootDevice.getProperty(UPnPDevice.UDN)+")" ); } catch (InvalidSyntaxException e) { e.printStackTrace(); } String[] childsUDN = (String[]) rootDevice.getProperty(UPnPDevice.CHILDREN_UDN); if((childs==null)&&(childsUDN==null)){ return true; }else if((childs==null)||(childsUDN==null)){ return false; }else if(childs.length==childsUDN.length){ DeviceList dl = d.getDeviceList(); for (int i = 0; i < childs.length; i++) { Device dev = (Device)dl.elementAt(i); if(!bindInvokes(dev,childs[i])) return false; } return true; }else{ return false; } } /** * This method add an UPnPEventListener Service to the OSGi Framework so that * the Base Driver can notify all the event listener registered on the CyberLink * UPnP device from the UPnP World. * * @param d Device of CyberLink that will be notified by the changing of the StateVariable * that happen on the OSGi World * @return ServiceRegistration of the new registered service. */ private ServiceRegistration bindSubscribe(Device d) { ExporterUPnPEventListener eventer = new ExporterUPnPEventListener(d); Properties p = new Properties(); StringBuffer sb = new StringBuffer("(|"); Vector v = new Vector(); v.add(d); Device current; while (v.size() != 0) { current = (Device) v.elementAt(0); v.remove(0); DeviceList dl = current.getDeviceList(); for (int i = 0; i < dl.size(); i++) { v.add(dl.elementAt(i)); } sb.append("(").append(UPnPDevice.ID).append("=").append( current.getUDN()).append(")"); } sb.append(")"); Filter f = null; try { f = Activator.bc.createFilter(sb.toString()); } catch (InvalidSyntaxException e) { e.printStackTrace(); return null; } if (f != null) p.put(UPnPEventListener.UPNP_FILTER, f); return Activator.bc.registerService(UPnPEventListener.class.getName(), eventer, p); } /** * This method do the real connection between OSGi UPnP Service action and * CyberLink UPnP Device action * * @param upnpDev the CyberLink UPnP Device object that will be connected * @param osgiDev the ServiceReference to OSGi UPnP Service that will be connected to * CyberLink UPnP as implementation of the Action * @return true if and only if the binding off all the action is done succesfully */ private boolean bindInvoke(Device upnpDev,ServiceReference osgiDev) { ServiceList sl = upnpDev.getServiceList(); int l=sl.size(); for (int i = 0; i < l; i++) { sl.getService(i).setActionListener( new GeneralActionListener( osgiDev, sl.getService(i).getServiceID() ) ); } return true; } /** * */ public synchronized void cleanUp() { Activator.logger.INFO("Cleaning..."); Enumeration keys; Activator.logger.INFO("Removing temporary listener...."); keys=exportedDevices.keys(); while (keys.hasMoreElements()) { ServiceRegistration sr = ((ExportedDeviceInfo) exportedDevices.get(keys.nextElement())).getServiceRegistration(); sr.unregister(); } Activator.logger.INFO("Done"); Activator.logger.INFO("Removing device...."); keys=exportedDevices.keys(); while (keys.hasMoreElements()) { Device dev = ((ExportedDeviceInfo) exportedDevices.get(keys.nextElement())).getDevice(); dev.stop(); } Activator.logger.INFO("Done"); } private synchronized boolean shouldEnd() { return end; } public synchronized void end() { end = true; queueRootDevice.addRootDevice(null); } /** * @see org.osgi.framework.ServiceListener#serviceChanged(org.osgi.framework.ServiceEvent) */ public void serviceChanged(ServiceEvent event) { switch(event.getType()){ case ServiceEvent.REGISTERED:break; case ServiceEvent.MODIFIED: case ServiceEvent.UNREGISTERING:{ this.unexportDevice(event.getServiceReference()); if(exportedDevices.size()==0){ Activator.bc.removeServiceListener(this); setListening(false); } }break; } } /** * @param b */ private synchronized void setListening(boolean b) { listening=b; } private synchronized boolean getListening(){ return listening; } /** * @param property */ private synchronized void unexportDevice(ServiceReference dev) { String udn=(String) dev.getProperty(UPnPDevice.PARENT_UDN); if(udn==null){ ExportedDeviceInfo edi = (ExportedDeviceInfo) exportedDevices.get( dev.getProperty(UPnPDevice.UDN) ); Device d = edi.getDevice(); if(d!=null) { Activator.logger.INFO("[Exporter] removing device:" +d.getFriendlyName()); d.stop(); exportedDevices.remove(d.getUDN()); } ServiceRegistration srListener=edi.getServiceRegistration(); if(srListener!=null) srListener.unregister(); }else{ ServiceReference[] servs=null; try { servs = Activator.bc.getServiceReferences( UPnPDevice.class.getName(), "("+UPnPDevice.UDN+"="+udn+")" ); } catch (InvalidSyntaxException ignored) {} if(servs==null) return; this.unexportDevice(servs[0]); } } }