diff options
author | jfogell | 2005-12-15 19:59:24 +0000 |
---|---|---|
committer | jfogell | 2005-12-15 19:59:24 +0000 |
commit | dc520ec816e6ef38fd464ae9de307c2e2f9e534d (patch) | |
tree | 413caa4c34d2d45f143a978a7fde14ba1cc71c9d | |
parent | 2dd01c470ad3807cada22a62d9b3362345946398 (diff) | |
download | rt.equinox.bundles-dc520ec816e6ef38fd464ae9de307c2e2f9e534d.tar.gz rt.equinox.bundles-dc520ec816e6ef38fd464ae9de307c2e2f9e534d.tar.xz rt.equinox.bundles-dc520ec816e6ef38fd464ae9de307c2e2f9e534d.zip |
initial checkin for OSGi Device Access service
18 files changed, 2188 insertions, 0 deletions
diff --git a/bundles/org.eclipse.equinox.device/.classpath b/bundles/org.eclipse.equinox.device/.classpath new file mode 100644 index 000000000..065ac06e1 --- /dev/null +++ b/bundles/org.eclipse.equinox.device/.classpath @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" path="src"/> + <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/bundles/org.eclipse.equinox.device/.cvsignore b/bundles/org.eclipse.equinox.device/.cvsignore new file mode 100644 index 000000000..ba077a403 --- /dev/null +++ b/bundles/org.eclipse.equinox.device/.cvsignore @@ -0,0 +1 @@ +bin diff --git a/bundles/org.eclipse.equinox.device/.project b/bundles/org.eclipse.equinox.device/.project new file mode 100644 index 000000000..5d5c43191 --- /dev/null +++ b/bundles/org.eclipse.equinox.device/.project @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>org.eclipse.equinox.device</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.ManifestBuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.SchemaBuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.pde.PluginNature</nature> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> diff --git a/bundles/org.eclipse.equinox.device/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.device/META-INF/MANIFEST.MF new file mode 100644 index 000000000..4069367db --- /dev/null +++ b/bundles/org.eclipse.equinox.device/META-INF/MANIFEST.MF @@ -0,0 +1,15 @@ +Bundle-ManifestVersion: 2 +Bundle-Name: %bundleName +Bundle-Version: 1.0.0.qualifier +Bundle-Activator: org.eclipse.equinox.device.Activator +Bundle-SymbolicName: org.eclipse.equinox.device +Bundle-Vendor: %bundleVendor +Bundle-Copyright: %bundleCopyright +Bundle-Localization: plugin +Import-Service: org.osgi.service.log.LogService +Import-Package: org.osgi.framework;version="1.2", + org.osgi.service.device, + org.osgi.service.log;version="1.2", + org.osgi.util.tracker +Export-Package: org.eclipse.equinox.device; x-internal:=true +Eclipse-LazyStart: true diff --git a/bundles/org.eclipse.equinox.device/about.html b/bundles/org.eclipse.equinox.device/about.html new file mode 100644 index 000000000..b2f1e6bad --- /dev/null +++ b/bundles/org.eclipse.equinox.device/about.html @@ -0,0 +1,22 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3c.org/TR/1999/REC-html401-19991224/loose.dtd"> +<!-- saved from url=(0043)http://www.eclipse.org/legal/epl/about.html --> +<HTML><HEAD><TITLE>About</TITLE> +<META http-equiv=Content-Type content="text/html; charset=ISO-8859-1"> +<META content="MSHTML 6.00.2800.1498" name=GENERATOR></HEAD> +<BODY lang=EN-US> +<H2>About This Content</H2> +<P>February 24, 2005</P> +<H3>License</H3> +<P>The Eclipse Foundation makes available all content in this plug-in +("Content"). Unless otherwise indicated below, the Content is provided to you +under the terms and conditions of the Eclipse Public License Version 1.0 +("EPL"). A copy of the EPL is available at <A +href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</A>. +For purposes of the EPL, "Program" will mean the Content.</P> +<P>If you did not receive this Content directly from the Eclipse Foundation, the +Content is being redistributed by another party ("Redistributor") and different +terms and conditions may apply to your use of any object code in the Content. +Check the Redistributor's license that was provided with the Content. If no such +license exists, contact the Redistributor. Unless otherwise indicated below, the +terms and conditions of the EPL still apply to any source code in the +Content.</P></BODY></HTML> diff --git a/bundles/org.eclipse.equinox.device/build.properties b/bundles/org.eclipse.equinox.device/build.properties new file mode 100644 index 000000000..662d65185 --- /dev/null +++ b/bundles/org.eclipse.equinox.device/build.properties @@ -0,0 +1,16 @@ +############################################################################### +# Copyright (c) 2005 IBM Corporation. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# IBM Corporation - initial API and implementation +############################################################################### +bin.includes = META-INF/,\ + plugin*.properties,\ + about.html,\ + . +jars.compile.order = . +source.. = diff --git a/bundles/org.eclipse.equinox.device/plugin.properties b/bundles/org.eclipse.equinox.device/plugin.properties new file mode 100644 index 000000000..86742fd77 --- /dev/null +++ b/bundles/org.eclipse.equinox.device/plugin.properties @@ -0,0 +1,13 @@ +############################################################################### +# Copyright (c) 2005 IBM Corporation. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# IBM Corporation - initial API and implementation +############################################################################### +bundleVendor = Eclipse.org +bundleName = Device Access Service +bundleCopyright = Copyright (c) IBM Corp. 1999, 2005 diff --git a/bundles/org.eclipse.equinox.device/src/org/eclipse/equinox/device/Activator.java b/bundles/org.eclipse.equinox.device/src/org/eclipse/equinox/device/Activator.java new file mode 100644 index 000000000..847408936 --- /dev/null +++ b/bundles/org.eclipse.equinox.device/src/org/eclipse/equinox/device/Activator.java @@ -0,0 +1,420 @@ +/******************************************************************************* + * Copyright (c) 2000, 2005 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.device; + +import org.eclipse.osgi.util.NLS; +import org.osgi.framework.*; +import org.osgi.util.tracker.ServiceTracker; +import org.osgi.util.tracker.ServiceTrackerCustomizer; + +/** + * DeviceManager bundle. This bundle implements the OSGi Device Access 1.1 + * specification. + * + * This implementation does not include the optimizations in section + * 8.7.4 of the OSGi SP R2 spec. + * + */ +public class Activator implements BundleActivator, ServiceTrackerCustomizer, FrameworkListener, Runnable { + protected final static boolean DEBUG = false; + + /** DeviceManager BundleContext */ + protected BundleContext context; + + /** LogTracker object */ + protected LogTracker log; + + /** if false the thread must terminate */ + protected volatile boolean running; + + /** DeviceManager thread */ + protected Thread thread; + + /** DriverTracker for Driver services. */ + protected DriverTracker drivers; + + /** Tracker for DriverLocator services */ + protected DriverLocatorTracker locators; + + /** Tracker for DriverSelector services */ + protected DriverSelectorTracker selectors; + + /** ServiceTracker object for device services */ + protected ServiceTracker devices; + + /** filter for Device services */ + protected Filter deviceFilter; + + /** filter for Driver services */ + protected Filter driverFilter; + + /** + * Linked List item + */ + static class DeviceService { + /** object for this item */ + final DeviceTracker device; + /** next item in event queue */ + DeviceService next; + + /** + * Constructor for work queue item + * + * @param o Object for this event + */ + DeviceService(DeviceTracker device) { + this.device = device; + next = null; + } + } + + /** item at the head of the event queue */ + private DeviceService head; + /** item at the tail of the event queue */ + private DeviceService tail; + + /** number of milliseconds to wait before refining idle Device services */ + protected long updatewait; + + /** set to true by DriverTracker when a Driver Service is registered */ + protected volatile boolean driverServiceRegistered; + + /** + * Create a DeviceManager object. + * + */ + + public Activator() { + super(); + } + + /** + * Start the Device Manager. + * + * @param context The device manager's bundle context + */ + + public void start(BundleContext context) throws Exception { + this.context = context; + running = false; + + log = new LogTracker(context, System.err); + + try { + deviceFilter = context.createFilter("(|(" + org.osgi.framework.Constants.OBJECTCLASS + "=" + DeviceTracker.clazz + ////-1$ ////-2$ //$NON-NLS-1$ //$NON-NLS-2$ + ")(" + org.osgi.service.device.Constants.DEVICE_CATEGORY + "=*))"); //$NON-NLS-1$ //$NON-NLS-2$ + + driverFilter = context.createFilter("(" + org.osgi.framework.Constants.OBJECTCLASS + "=" + DriverTracker.clazz + ")"); ////-1$ ////-2$ ////-3$ //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } catch (InvalidSyntaxException e) { + log.log(log.LOG_ERROR, NLS.bind(DeviceMsg.Unable_to_create_Filter_for_DeviceManager, e)); ////-1$ + throw e; + } + + updatewait = 5 * 1000L; + + String prop = context.getProperty("com.ibm.osg.service.device.updatewait"); //$NON-NLS-1$ + + if (prop != null) { + try { + updatewait = Long.parseLong(prop) * 1000L; + } catch (NumberFormatException e) { + } + } + + Bundle systemBundle = context.getBundle(0); + + if ((systemBundle != null) && ((systemBundle.getState() & systemBundle.STARTING) != 0)) { /* if the system bundle is starting */ + context.addFrameworkListener(this); + } else { + startDeviceManager(); + } + + log.log(log.LOG_INFO, DeviceMsg.DeviceManager_started); + } + + /** + * Receive notification of a general framework event. + * + * @param event The FrameworkEvent. + */ + public void frameworkEvent(FrameworkEvent event) { + switch (event.getType()) { + case FrameworkEvent.STARTED : { + context.removeFrameworkListener(this); + + try { + startDeviceManager(); + } catch (Throwable t) { + log.log(log.LOG_ERROR, NLS.bind(DeviceMsg.DeviceManager_has_thrown_an_error, t)); ////-1$ + } + + break; + } + } + } + + /** + * Start the DeviceManager thread. + * + */ + public void startDeviceManager() { + if (!running) { + head = null; + tail = null; + + locators = new DriverLocatorTracker(this); + + selectors = new DriverSelectorTracker(this); + + drivers = new DriverTracker(this); + + devices = new ServiceTracker(context, deviceFilter, this); + devices.open(); + + running = true; + driverServiceRegistered = false; + + thread = (new SecureAction()).createThread(this, "DeviceManager"); //$NON-NLS-1$ + thread.start(); /* Start DeviceManager thread */ + } + } + + /** + * Stop the Device Manager bundle. + * + * @param context The device manager's bundle context + */ + + public void stop(BundleContext context) throws Exception { + context.removeFrameworkListener(this); + + if (running) { + Thread t = thread; + + running = false; /* request thread to stop */ + + if (t != null) { + t.interrupt(); + + synchronized (t) { + while (t.isAlive()) /* wait for thread to complete */ + { + try { + t.wait(0); + } catch (InterruptedException e) { + } + } + } + } + } + + if (drivers != null) { + drivers.close(); + drivers = null; + } + + if (devices != null) { + devices.close(); + devices = null; + } + + if (locators != null) { + locators.close(); + locators = null; + } + + if (selectors != null) { + selectors.close(); + selectors = null; + } + + if (log != null) { + log.close(); + log = null; + } + + this.context = null; + } + + /** + * A service is being added to the ServiceTracker. + * + * <p>This method is called before a service which matched + * the search parameters of the ServiceTracker is + * added to the ServiceTracker. This method should return the + * service object to be tracked for this ServiceReference. + * The returned service object is stored in the ServiceTracker + * and is available from the getService and getServices + * methods. + * + * @param reference Reference to service being added to the ServiceTracker. + * @return The service object to be tracked for the + * ServiceReference or <tt>null</tt> if the ServiceReference should not + * be tracked. + */ + public Object addingService(ServiceReference reference) { + if (Activator.DEBUG) { + log.log(reference, log.LOG_DEBUG, "DeviceManager device service registered"); //$NON-NLS-1$ + } + + enqueue(new DeviceTracker(this, reference)); + + return (reference); + } + + /** + * A service tracked by the ServiceTracker has been modified. + * + * <p>This method is called when a service being tracked + * by the ServiceTracker has had it properties modified. + * + * @param reference Reference to service that has been modified. + * @param service The service object for the modified service. + */ + public void modifiedService(ServiceReference reference, Object service) { + } + + /** + * A service tracked by the ServiceTracker is being removed. + * + * <p>This method is called after a service is no longer being tracked + * by the ServiceTracker. + * + * @param reference Reference to service that has been removed. + * @param service The service object for the removed service. + */ + public void removedService(ServiceReference reference, Object object) { + if (Activator.DEBUG) { + log.log(reference, log.LOG_DEBUG, "DeviceManager device service unregistered"); //$NON-NLS-1$ + } + + /* We do not implement optional driver reclamation. + * Thus we take no specific action upon Device service unregistration . + */ + } + + public void refineIdleDevices() { + if (Activator.DEBUG) { + log.log(log.LOG_DEBUG, "DeviceManager refining idle device services"); //$NON-NLS-1$ + } + + ServiceReference[] references = devices.getServiceReferences(); + + if (references != null) { + int size = references.length; + + for (int i = 0; i < size; i++) { + ServiceReference device = references[i]; + + enqueue(new DeviceTracker(this, device)); + } + } + } + + /** + * Main thread for DeviceManager. + * + * Attempt to refine all Device services that are not in use + * by a driver bundle. + */ + public void run() { + while (running) { + DeviceTracker device; + + try { + device = dequeue(); + } catch (InterruptedException e) { + continue; + } + + try { + device.refine(); + } catch (Throwable t) { + log.log(log.LOG_ERROR, NLS.bind(DeviceMsg.DeviceManager_has_thrown_an_error, t)); ////-1$ + } + } + } + + /** + * Queue the object to be processed on the work thread. + * The thread is notified. + * + * @param device Work item. + */ + public synchronized void enqueue(DeviceTracker device) { + if (device != null) { + if (Activator.DEBUG) { + log.log(log.LOG_DEBUG, "DeviceManager queuing DeviceTracker"); //$NON-NLS-1$ + } + + DeviceService item = new DeviceService(device); + + if (head == null) /* if the queue was empty */ + { + head = item; + tail = item; + } else /* else add to end of queue */ + { + tail.next = item; + tail = item; + } + } + + notify(); + } + + /** + * Dequeue an object from the work thread. + * If the queue is empty, this method blocks. + * + * @return Dequeue object from the work thread. + * @throws InterruptedException If the queue has been stopped. + */ + private synchronized DeviceTracker dequeue() throws InterruptedException { + while (running && (head == null)) { + /* This should be included per Section 8.7.7 of the OSGi SP R2 + * spec, but it causes the OSGi SP R2 Test Suite to fail. + * We should turn this on for R3. + + if (driverServiceRegistered) + */ + if (false) { + driverServiceRegistered = false; + + refineIdleDevices(); + } else { + locators.uninstallDriverBundles(); + + try { + if (Activator.DEBUG) { + log.log(log.LOG_DEBUG, "DeviceManager waiting on queue"); //$NON-NLS-1$ + } + + wait(); + } catch (InterruptedException e) { + } + } + } + + if (!running) /* if we are stopping */ + { + throw new InterruptedException(); /* throw an exception */ + } + + DeviceService item = head; + head = item.next; + if (head == null) { + tail = null; + } + + return (item.device); + } +} diff --git a/bundles/org.eclipse.equinox.device/src/org/eclipse/equinox/device/DeviceMsg.java b/bundles/org.eclipse.equinox.device/src/org/eclipse/equinox/device/DeviceMsg.java new file mode 100644 index 000000000..bbb83f35e --- /dev/null +++ b/bundles/org.eclipse.equinox.device/src/org/eclipse/equinox/device/DeviceMsg.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2000, 2005 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.device; + +import org.eclipse.osgi.util.NLS; + +public class DeviceMsg extends NLS { + private static final String BUNDLE_NAME = "org.eclipse.equinox.device.ExternalMessages"; //$NON-NLS-1$ + + public static String DeviceManager_started; + public static String Device_service_unregistered; + public static String Device_noDriverFound_called; + public static String Multiple_Driver_services_with_the_same_DRIVER_ID; + public static String DeviceManager_Update_Wait; + public static String Driver_service_has_no_DRIVER_ID_property; + public static String Device_attached_by_DRIVER_ID; + public static String Device_referred_to; + public static String Unable_to_create_Filter_for_DeviceManager; + public static String DeviceManager_has_thrown_an_error; + public static String Device_noDriverFound_error; + public static String DriverLocator_unable_to_load_driver; + public static String DriverLocator_error_calling_findDrivers; + public static String Unable_to_install_or_start_driver_bundle; + public static String Unable_to_uninstall_driver_bundle; + public static String Unable_to_uninstall_driver_bundle_number; + public static String DriverSelector_error_during_match; + public static String Driver_service_has_no_DRIVER_ID; + public static String Driver_error_during_match; + public static String Driver_error_during_attach; + + static { + // initialize resource bundles + NLS.initializeMessages(BUNDLE_NAME, DeviceMsg.class); + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.device/src/org/eclipse/equinox/device/DeviceTracker.java b/bundles/org.eclipse.equinox.device/src/org/eclipse/equinox/device/DeviceTracker.java new file mode 100644 index 000000000..ee85a7f6d --- /dev/null +++ b/bundles/org.eclipse.equinox.device/src/org/eclipse/equinox/device/DeviceTracker.java @@ -0,0 +1,341 @@ +/******************************************************************************* + * Copyright (c) 2000, 2005 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.device; + +import java.util.*; +import org.eclipse.osgi.util.NLS; +import org.osgi.framework.*; +import org.osgi.service.device.Device; +import org.osgi.service.log.LogService; +import org.osgi.util.tracker.ServiceTracker; + +/** + * DeviceTracker class. This class has the logic for refining a + * Device service. + * + */ +public class DeviceTracker extends ServiceTracker { + /** OSGi Device class name */ + protected final static String clazz = "org.osgi.service.device.Device"; //$NON-NLS-1$ + + /** DeviceManager object. */ + protected Activator manager; + + /** reference to Device service we are attempting to refine */ + protected ServiceReference device; + + /** LogService object */ + protected LogService log; + + /** Device services properties */ + protected Dictionary properties; + + /** if false the algorithm must terminate */ + protected volatile boolean running; + + /** + * Create a DeviceTracker from a ServiceReference. + * + * @param manager DeviceManager object + * @param device ServiceReference to the Device service. + * @param id ID of DeviceTracker object + */ + public DeviceTracker(Activator manager, ServiceReference device) { + super(manager.context, device, null); + + this.manager = manager; + log = manager.log; + + if (Activator.DEBUG) { + log.log(device, log.LOG_DEBUG, this + " constructor"); //$NON-NLS-1$ + } + + open(); + } + + /** + * Close the Device. + */ + + public void close() { + if (device != null) { + if (Activator.DEBUG) { + log.log(device, log.LOG_DEBUG, this + " closing"); //$NON-NLS-1$ + } + + running = false; /* request thread to stop */ + + super.close(); + + device = null; + } + } + + /** + * A service is being added to the ServiceTracker. + * + * <p>This method is called before a service which matched + * the search parameters of the ServiceTracker is + * added to the ServiceTracker. This method should return the + * service object to be tracked for this ServiceReference. + * The returned service object is stored in the ServiceTracker + * and is available from the getService and getServices + * methods. + * + * @param reference Reference to service being added to the ServiceTracker. + * @return The service object to be tracked for the + * ServiceReference or <tt>null</tt> if the ServiceReference should not + * be tracked. + */ + public Object addingService(ServiceReference reference) { + if (Activator.DEBUG) { + log.log(reference, log.LOG_DEBUG, this + " adding Device service"); //$NON-NLS-1$ + } + + device = reference; + + running = true; + + properties = new Properties(reference); + + return (reference); + } + + /** + * A service tracked by the ServiceTracker has been modified. + * + * <p>This method is called when a service being tracked + * by the ServiceTracker has had it properties modified. + * + * @param reference Reference to service that has been modified. + * @param service The service object for the modified service. + */ + public void modifiedService(ServiceReference reference, Object service) { + properties = new Properties(reference); + } + + /** + * A service tracked by the ServiceTracker is being removed. + * + * <p>This method is called after a service is no longer being tracked + * by the ServiceTracker. + * + * @param reference Reference to service that has been removed. + * @param service The service object for the removed service. + */ + public void removedService(ServiceReference reference, Object service) { + if (running) { + log.log(reference, log.LOG_WARNING, DeviceMsg.Device_service_unregistered); + running = false; /* request algorithm to stop */ + } else { + if (Activator.DEBUG) { + log.log(reference, log.LOG_DEBUG, this + " removing Device service"); //$NON-NLS-1$ + } + } + } + + /** + * Attempt to refine this Device service. + * + */ + public void refine() { + if (Activator.DEBUG) { + log.log(device, log.LOG_DEBUG, this + " refining " + device); //$NON-NLS-1$ + } + + if (running && isIdle()) { + /* List of excluded drivers from this algorithm run */ + DriverTracker drivers = manager.drivers; + + manager.locators.loadDrivers(properties, drivers); + + Vector exclude = new Vector(drivers.size()); + + while (running) { + ServiceReference driver = drivers.match(device, exclude); + + if (driver == null) { + noDriverFound(); + break; + } + + if (drivers.attach(driver, device, exclude)) { + break; + } + } + } + + close(); + } + + /** + * Determine if the device service tracked by this object is idle. + * + * OSGi SP R2 Section 8.2.2 defines in idle device service as: + * "A Device service is not used by any other bundle according to the Framework; + * it is called an idle Device service." + * + * This method defines it as: + * A Device service is not used by any DRIVER bundle according to the Framework; + * it is called an idle Device service. + * + * Thus if a non-driver bundle uses a device service, it is still considered + * idle by this method. + * + * @return true if the device service is idle. + */ + public boolean isIdle() { + if (Activator.DEBUG) { + log.log(device, log.LOG_DEBUG, "Check device service idle: " + device); //$NON-NLS-1$ + } + + Filter filter = manager.driverFilter; + Bundle[] users = device.getUsingBundles(); + + int userCount = (users == null) ? 0 : users.length; + + for (int i = 0; i < userCount; i++) { + ServiceReference[] services = users[i].getRegisteredServices(); + + int servicesCount = (services == null) ? 0 : services.length; + + for (int j = 0; j < servicesCount; j++) { + if (filter.match(services[j])) { + if (Activator.DEBUG) { + log.log(log.LOG_DEBUG, "Device " + device + " already in use by bundle " + users[i]); //$NON-NLS-1$ //$NON-NLS-2$ + } + + return (false); + } + } + } + + return (true); + } + + /** + * Called by the device manager after it has failed to attach + * any driver to the device. + * <p> + * If the device can be configured in alternate ways, the driver + * may respond by unregistering the device service and registering + * a different device service instead.</p> + */ + + public void noDriverFound() { + BundleContext context = manager.context; + + Object service = context.getService(device); + + try { + //It is possible that this is a Free Format Device that does not + //implement Device + if (service instanceof Device) { + log.log(device, log.LOG_INFO, DeviceMsg.Device_noDriverFound_called); + + try { + ((Device) service).noDriverFound(); + } catch (Throwable t) { + log.log(device, log.LOG_ERROR, NLS.bind(DeviceMsg.Device_noDriverFound_error, t)); + } + } + } finally { + context.ungetService(device); + } + + } + + public String toString() { + return "DeviceTracker"; //$NON-NLS-1$ + } + + /** + * Readonly Dictionary for device properties. + * + */ + static class Properties extends Hashtable { + /** + * keys in original case. + */ + protected Vector keys; + + /** + * Create a properties object for the service. + * + * @param device The service to get the properties of. + */ + protected Properties(ServiceReference device) { + super(); + + String[] props = device.getPropertyKeys(); + + if (props != null) { + int size = props.length; + + keys = new Vector(size); + + for (int i = 0; i < size; i++) { + String key = props[i]; + Object value = device.getProperty(key); + + if (value != null) { + keys.addElement(key); + + super.put(key.toLowerCase(), value); + } + } + } else { + keys = new Vector(0); + } + } + + /** + * Override keys to support case-preserving of keys. + */ + public Enumeration keys() { + return (keys.elements()); + } + + /** + * Override get to support case-insensitivity. + * + * @param key header name. + */ + public Object get(Object key) { + if (key instanceof String) { + return (super.get(((String) key).toLowerCase())); + } + + return (null); + } + + /** + * Override put to disable it. This Dictionary is readonly once built. + * + * @param key header name. + * @param value header value. + * @throws UnsupportedOperationException. + */ + public Object put(Object key, Object value) { + throw new UnsupportedOperationException(); + } + + /** + * Override remove to disable it. This Dictionary is readonly once built. + * + * @param key header name. + * @throws UnsupportedOperationException. + */ + public Object remove(Object key) { + throw new UnsupportedOperationException(); + } + } +} diff --git a/bundles/org.eclipse.equinox.device/src/org/eclipse/equinox/device/DriverLocatorTracker.java b/bundles/org.eclipse.equinox.device/src/org/eclipse/equinox/device/DriverLocatorTracker.java new file mode 100644 index 000000000..329fd6738 --- /dev/null +++ b/bundles/org.eclipse.equinox.device/src/org/eclipse/equinox/device/DriverLocatorTracker.java @@ -0,0 +1,344 @@ +/******************************************************************************* + * Copyright (c) 2000, 2005 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.device; + +import java.io.InputStream; +import java.util.Dictionary; +import java.util.Vector; +import org.eclipse.osgi.util.NLS; +import org.osgi.framework.*; +import org.osgi.service.device.DriverLocator; +import org.osgi.service.log.LogService; +import org.osgi.util.tracker.ServiceTracker; + +/** + * DriverLocatorTracker class. This class tracks all DriverLocator services. + * + */ +public class DriverLocatorTracker extends ServiceTracker { + protected final static String clazz = "org.osgi.service.device.DriverLocator"; //$NON-NLS-1$ + + /** DeviceManager object. */ + protected Activator manager; + + /** LogService object */ + protected LogService log; + + /** List of bundles to be uninstalled. */ + protected Vector bundles; + + /** + * Create the DriverLocatorTracker. + * + * @param context Device manager bundle context. + * @param log LogService object + */ + public DriverLocatorTracker(Activator manager) { + super(manager.context, clazz, null); + + this.manager = manager; + log = manager.log; + bundles = new Vector(10, 10); + + if (Activator.DEBUG) { + log.log(LogService.LOG_DEBUG, "DriverLocatorTracker constructor"); //$NON-NLS-1$ + } + + open(); + } + + /** + * A service is being added to the ServiceTracker. + * + * <p>This method is called before a service which matched + * the search parameters of the ServiceTracker is + * added to the ServiceTracker. This method should return the + * service object to be tracked for this ServiceReference. + * The returned service object is stored in the ServiceTracker + * and is available from the getService and getServices + * methods. + * + * @param reference Reference to service being added to the ServiceTracker. + * @return The service object to be tracked for the + * ServiceReference or <tt>null</tt> if the ServiceReference should not + * be tracked. + */ + public Object addingService(ServiceReference reference) { + if (Activator.DEBUG) { + log.log(reference, LogService.LOG_DEBUG, "DriverLocatorTracker adding service"); //$NON-NLS-1$ + } + + return (context.getService(reference)); + } + + /** + * A service tracked by the ServiceTracker has been modified. + * + * <p>This method is called when a service being tracked + * by the ServiceTracker has had it properties modified. + * + * @param reference Reference to service that has been modified. + * @param service The service object for the modified service. + */ + public void modifiedService(ServiceReference reference, Object service) { + } + + /** + * A service tracked by the ServiceTracker is being removed. + * + * <p>This method is called after a service is no longer being tracked + * by the ServiceTracker. + * + * @param reference Reference to service that has been removed. + * @param service The service object for the removed service. + */ + public void removedService(ServiceReference reference, Object object) { + if (Activator.DEBUG) { + log.log(reference, LogService.LOG_DEBUG, "DriverLocatorTracker removing service"); //$NON-NLS-1$ + } + + context.ungetService(reference); + } + + /** + * Call the DriverLocator services in an attempt to locate and + * install driver bundles to refine the device service. + * + * @param locators Array of DriverLocator objects + * @param drivers Dictionary of drivers with key=DRIVER_ID, value=Driver object + */ + public void loadDrivers(Dictionary properties, DriverTracker drivers) { + if (Activator.DEBUG) { + log.log(LogService.LOG_DEBUG, Thread.currentThread().getName() + ": DriverLocatorTracker loadDrivers called"); //$NON-NLS-1$ + } + + ServiceReference[] references = getServiceReferences(); + + if (references != null) { + int size = references.length; + + for (int i = 0; i < size; i++) { + ServiceReference locator = references[i]; + DriverLocator service = (DriverLocator) getService(locator); + + if (service != null) { + if (Activator.DEBUG) { + log.log(locator, LogService.LOG_DEBUG, Thread.currentThread().getName() + ": DriverLocator findDrivers called"); //$NON-NLS-1$ + } + + try { + String[] driver_ids = service.findDrivers(properties); + + if (Activator.DEBUG) { + int count = (driver_ids == null) ? 0 : driver_ids.length; + + StringBuffer sb = new StringBuffer(); + + sb.append('<'); + + for (int k = 0; k < count; k++) { + if (k > 0) { + sb.append(','); + } + sb.append(driver_ids[k]); + } + + sb.append('>'); + + log.log(locator, LogService.LOG_DEBUG, Thread.currentThread().getName() + ": DriverLocator findDrivers returned: " + sb); //$NON-NLS-1$ + } + + if (driver_ids != null) { + int count = driver_ids.length; + + for (int j = 0; j < count; j++) { + String driver_id = driver_ids[j]; + + if (drivers.getDriver(driver_id) == null) { + if (Activator.DEBUG) { + log.log(locator, LogService.LOG_DEBUG, Thread.currentThread().getName() + ": DriverLocator loadDriver called for driver: " + driver_id); //$NON-NLS-1$ + } + + try { + InputStream in = service.loadDriver(driver_id); + + if (Activator.DEBUG) { + log.log(locator, LogService.LOG_DEBUG, Thread.currentThread().getName() + ": DriverLocator loadDriver returned: " + in); //$NON-NLS-1$ + } + + installDriverBundle(driver_id, in); + } catch (Throwable t) { + log.log(locator, LogService.LOG_ERROR, NLS.bind(DeviceMsg.DriverLocator_unable_to_load_driver, driver_id), t); + } + } + } + } + } catch (Throwable t) { + log.log(locator, LogService.LOG_ERROR, DeviceMsg.DriverLocator_error_calling_findDrivers, t); + } + } + } + } + } + + /** + * Get an <code>InputStream</code> from which the driver bundle providing a driver with the giving ID can be installed. + * + * @param id the ID of the driver that needs to be installed. + * @return the <code>InputStream</code> from which the driver + * bundle can be installed + */ + + public void loadDriver(String driver_id, DriverTracker drivers) { + if (Activator.DEBUG) { + log.log(LogService.LOG_DEBUG, Thread.currentThread().getName() + ": DriverLocatorTracker loadDriver called for driver: " + driver_id); //$NON-NLS-1$ + } + + if (drivers.getDriver(driver_id) == null) { + ServiceReference[] references = getServiceReferences(); + + if (references != null) { + int size = references.length; + + for (int i = 0; i < size; i++) { + ServiceReference locator = references[i]; + DriverLocator service = (DriverLocator) getService(locator); + + if (service != null) { + if (Activator.DEBUG) { + log.log(locator, LogService.LOG_DEBUG, Thread.currentThread().getName() + ": DriverLocator loadDriver called for driver: " + driver_id); //$NON-NLS-1$ + } + + try { + InputStream in = service.loadDriver(driver_id); + + if (Activator.DEBUG) { + log.log(locator, LogService.LOG_DEBUG, Thread.currentThread().getName() + ": DriverLocator loadDriver returned: " + in); //$NON-NLS-1$ + } + + if (in != null) { + installDriverBundle(driver_id, in); + + break; + } + } catch (Throwable t) { + log.log(locator, LogService.LOG_ERROR, NLS.bind(DeviceMsg.DriverLocator_unable_to_load_driver, driver_id), t); + } + } + } + } + } + } + + /** + * Install a Driver bundle. + * + * @param driver_id DRIVER_ID for new driver bundle. + * @param in InputStream to a new driver bundle. + */ + public void installDriverBundle(String driver_id, InputStream in) { + if (Activator.DEBUG) { + log.log(LogService.LOG_DEBUG, Thread.currentThread().getName() + ": installDriverBundle from InputStream: " + driver_id); //$NON-NLS-1$ + } + + if (in != null) { + Bundle bundle = null; + + try { + bundle = context.installBundle(driver_id, in); + /* installBundle will close the InputStream */ + + if (Activator.DEBUG) { + log.log(LogService.LOG_DEBUG, Thread.currentThread().getName() + ": Driver bundle installed: " + driver_id); //$NON-NLS-1$ + } + + synchronized (bundles) { + if (!bundles.contains(bundle)) { + bundles.addElement(bundle); + } + } + + bundle.start(); + + if (Activator.DEBUG) { + log.log(LogService.LOG_DEBUG, Thread.currentThread().getName() + ": Driver bundle started: " + driver_id); //$NON-NLS-1$ + } + } catch (BundleException e) { + log.log(LogService.LOG_ERROR, NLS.bind(DeviceMsg.Unable_to_install_or_start_driver_bundle, driver_id), e); + + if (bundle != null) { + bundles.removeElement(bundle); + + try { + bundle.uninstall(); + + if (Activator.DEBUG) { + log.log(LogService.LOG_DEBUG, Thread.currentThread().getName() + ": Driver bundle uninstalled: " + driver_id); //$NON-NLS-1$ + } + } catch (BundleException ee) { + log.log(LogService.LOG_ERROR, NLS.bind(DeviceMsg.Unable_to_uninstall_driver_bundle_number, driver_id), ee); + } + + bundle = null; + } + } + } + } + + /** + * Remove bundle from uninstall list. + * + * @param bundle bundle to remove from list. + */ + public void usingDriverBundle(Bundle bundle) { + bundles.removeElement(bundle); + } + + /** + * Uninstall the recently installed but unused driver bundles. + * + */ + public void uninstallDriverBundles() { + int size; + Bundle[] uninstall = null; + + synchronized (bundles) { + size = bundles.size(); + + if (size > 0) { + uninstall = new Bundle[size]; + bundles.copyInto(uninstall); + } + } + + for (int i = 0; i < size; i++) { + Bundle bundle = uninstall[i]; + + if ((bundle.getState() & Bundle.UNINSTALLED) == 0) { /* if bundle not already uninstalled */ + try { + bundle.uninstall(); + + if (Activator.DEBUG) { + log.log(LogService.LOG_DEBUG, Thread.currentThread().getName() + ": Driver bundle uninstalled"); //$NON-NLS-1$ + } + } catch (BundleException ee) { + log.log(LogService.LOG_ERROR, NLS.bind(DeviceMsg.Unable_to_uninstall_driver_bundle, ee)); + } + } + } + + bundles.removeAllElements(); + } + + public boolean isUninstallCandidate(Bundle bundle) { + return bundles.contains(bundle); + } +} diff --git a/bundles/org.eclipse.equinox.device/src/org/eclipse/equinox/device/DriverSelectorTracker.java b/bundles/org.eclipse.equinox.device/src/org/eclipse/equinox/device/DriverSelectorTracker.java new file mode 100644 index 000000000..cbd469a0f --- /dev/null +++ b/bundles/org.eclipse.equinox.device/src/org/eclipse/equinox/device/DriverSelectorTracker.java @@ -0,0 +1,150 @@ +/******************************************************************************* + * Copyright (c) 2000, 2005 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.device; + +import org.osgi.framework.ServiceReference; +import org.osgi.service.device.Device; +import org.osgi.service.device.DriverSelector; +import org.osgi.service.log.LogService; +import org.osgi.util.tracker.ServiceTracker; + +/** + * DriverSelectorTracker class. This class tracks all DriverSelector services. + * + */ +public class DriverSelectorTracker extends ServiceTracker { + /** Driver service name */ + protected final static String clazz = "org.osgi.service.device.DriverSelector"; //$NON-NLS-1$ + + /** LogService object */ + protected LogService log; + + /** DeviceManager object. */ + protected Activator manager; + + /** + * Create the DriverTracker. + * + * @param manager DeviceManager object. + * @param device DeviceTracker we are working for. + */ + public DriverSelectorTracker(Activator manager) { + super(manager.context, clazz, null); + + this.manager = manager; + log = manager.log; + + if (Activator.DEBUG) { + log.log(log.LOG_DEBUG, "DriverSelectorTracker constructor"); //$NON-NLS-1$ + } + + open(); + } + + /** + * Select the matching driver. + * + * @param device Device service being matched. + * @param matches Array of the successful matches from Driver services. + * @return ServiceReference to best matched Driver or null of their is no match. + */ + public ServiceReference select(ServiceReference device, Match[] matches) { + if (Activator.DEBUG) { + log.log(device, log.LOG_DEBUG, "DriverSelector select called"); //$NON-NLS-1$ + } + + //This should give us the highest ranking DriverSelector (if available) + ServiceReference selector = getServiceReference(); + + if (selector != null) { + DriverSelector service = (DriverSelector) getService(selector); + + try { + int index = service.select(device, matches); + + if (index == DriverSelector.SELECT_NONE) { + return null; + } + + return matches[index].getDriver(); + } catch (Throwable t) { + log.log(selector, log.LOG_ERROR, DeviceMsg.DriverSelector_error_during_match, t); + } + } + + return defaultSelection(matches); + } + + /** + * Default match selection algorithm from OSGi SPR2 spec. + * + * @param matchArray An array of the successful matches. + * @return ServiceReference to the selected Driver service + */ + public ServiceReference defaultSelection(Match[] matches) { + int size = matches.length; + + int max = Device.MATCH_NONE; + ServiceReference reference = null; + + for (int i = 0; i < size; i++) { + Match driver = matches[i]; + + int match = driver.getMatchValue(); + + if (match >= max) { + if (match == max) /* we must break the tie */ + { + reference = breakTie(reference, driver.getDriver()); + } else { + max = match; + reference = driver.getDriver(); + } + } + } + + return reference; + } + + /** + * Select the service with the highest service.ranking. Break ties + * buy selecting the lowest service.id. + * + */ + public ServiceReference breakTie(ServiceReference ref1, ServiceReference ref2) { + //first we check service rankings + Object property = ref1.getProperty(org.osgi.framework.Constants.SERVICE_RANKING); + + int ref1Ranking = (property instanceof Integer) ? ((Integer) property).intValue() : 0; + + property = ref2.getProperty(org.osgi.framework.Constants.SERVICE_RANKING); + + int ref2Ranking = (property instanceof Integer) ? ((Integer) property).intValue() : 0; + + if (ref1Ranking > ref2Ranking) { + return ref1; + } else if (ref2Ranking > ref1Ranking) { + return ref2; + } else // The rankings must match here + { + //we now check service ids + long ref1ID = ((Long) (ref1.getProperty(org.osgi.framework.Constants.SERVICE_ID))).longValue(); + + long ref2ID = ((Long) (ref2.getProperty(org.osgi.framework.Constants.SERVICE_ID))).longValue(); + + if (ref1ID < ref2ID) { + return ref1; + } + + return ref2; + } + } +} diff --git a/bundles/org.eclipse.equinox.device/src/org/eclipse/equinox/device/DriverTracker.java b/bundles/org.eclipse.equinox.device/src/org/eclipse/equinox/device/DriverTracker.java new file mode 100644 index 000000000..a7026c401 --- /dev/null +++ b/bundles/org.eclipse.equinox.device/src/org/eclipse/equinox/device/DriverTracker.java @@ -0,0 +1,485 @@ +/******************************************************************************* + * Copyright (c) 2000, 2005 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.device; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Hashtable; +import java.util.Vector; +import org.eclipse.osgi.util.NLS; +import org.osgi.framework.*; +import org.osgi.service.device.Device; +import org.osgi.service.device.Driver; +import org.osgi.service.log.LogService; +import org.osgi.util.tracker.ServiceTracker; + +/** + * DriverTracker class. This class tracks all Driver services. + * + */ +public class DriverTracker extends ServiceTracker { + /** Driver service name */ + protected final static String clazz = "org.osgi.service.device.Driver"; //$NON-NLS-1$ + + /** LogService object */ + protected LogService log; + + /** Dictionary mapping DRIVER_ID strings <==> Driver ServiceReferences */ + protected Hashtable drivers; + + /** DeviceManager object. */ + protected Activator manager; + + /** Dictionary mapping Driver ID String => + * Hashtable (Device ServiceReference => cached Match objects) */ + protected Hashtable matches; + + /** Dictionary mapping Driver ID String => + * Hashtable (Device ServiceReference => cached referral String) */ + protected Hashtable referrals; + + /** + * Create the DriverTracker. + * + * @param manager DeviceManager object. + * @param device DeviceTracker we are working for. + */ + public DriverTracker(Activator manager) { + super(manager.context, clazz, null); + + this.manager = manager; + log = manager.log; + + drivers = new Hashtable(37); + matches = new Hashtable(37); + referrals = new Hashtable(37); + + if (Activator.DEBUG) { + log.log(LogService.LOG_DEBUG, this + " constructor"); //$NON-NLS-1$ + } + + open(); + } + + /** + * A service is being added to the ServiceTracker. + * + * <p>This method is called before a service which matched + * the search parameters of the ServiceTracker is + * added to the ServiceTracker. This method should return the + * service object to be tracked for this ServiceReference. + * The returned service object is stored in the ServiceTracker + * and is available from the getService and getServices + * methods. + * + * @param reference Reference to service being added to the ServiceTracker. + * @return The service object to be tracked for the + * ServiceReference or <tt>null</tt> if the ServiceReference should not + * be tracked. + */ + public Object addingService(ServiceReference reference) { + if (Activator.DEBUG) { + log.log(reference, LogService.LOG_DEBUG, this + " adding service"); //$NON-NLS-1$ + } + + String driver_id = getDriverID(reference); + + if (drivers.get(driver_id) != null) { + log.log(reference, LogService.LOG_WARNING, NLS.bind(DeviceMsg.Multiple_Driver_services_with_the_same_DRIVER_ID, driver_id)); + + return (null); /* don't track this driver */ + } + + drivers.put(driver_id, reference); + drivers.put(reference, driver_id); + + manager.driverServiceRegistered = true; + + /* OSGi SPR2 Device Access 1.1 + * Section 8.4.3 - When a new Driver service is registered, + * the Device Attachment Algorithm must be applied to all + * idle Device services. + * + * We do not refine idle Devices when the manager has not fully + * started or the Driver service is from a bundle just installed + * by the devicemanager. + */ + Bundle bundle = reference.getBundle(); + + if (manager.running && !manager.locators.isUninstallCandidate(bundle)) { + manager.refineIdleDevices(); + } + + return (context.getService(reference)); + } + + /** + * A service tracked by the ServiceTracker has been modified. + * + * <p>This method is called when a service being tracked + * by the ServiceTracker has had it properties modified. + * + * @param reference Reference to service that has been modified. + * @param service The service object for the modified service. + */ + public void modifiedService(ServiceReference reference, Object service) { + if (Activator.DEBUG) { + log.log(reference, LogService.LOG_DEBUG, this + " modified service"); //$NON-NLS-1$ + } + + String driver_id = getDriverID(reference); + + String old_id = (String) drivers.get(reference); + + if (!driver_id.equals(old_id)) { + drivers.put(driver_id, reference); + drivers.put(reference, driver_id); + drivers.remove(old_id); + } + } + + /** + * A service tracked by the ServiceTracker is being removed. + * + * <p>This method is called after a service is no longer being tracked + * by the ServiceTracker. + * + * @param reference Reference to service that has been removed. + * @param service The service object for the removed service. + */ + public void removedService(ServiceReference reference, Object object) { + if (Activator.DEBUG) { + log.log(reference, LogService.LOG_DEBUG, this + " removing service"); //$NON-NLS-1$ + } + + String driver_id = getDriverID(reference); + drivers.remove(driver_id); + drivers.remove(reference); + + matches.remove(driver_id); + referrals.remove(driver_id); + + context.ungetService(reference); + + /* OSGi SPR2 Device Access 1.1 + * Section 8.4.4 - When a Driver service is unregistered, + * the Device Attachment Algorithm must be applied to all + * idle Device services. + * + * We do not refine idle Devices when the manager has not fully + * started or the Driver service is from a bundle just installed + * by the devicemanager. + */ + + Bundle bundle = reference.getBundle(); + + if (manager.running && !manager.locators.isUninstallCandidate(bundle)) { + DriverUpdate update = new DriverUpdate(bundle, manager); + + Thread thread = (new SecureAction()).createThread(update, DeviceMsg.DeviceManager_Update_Wait); + + thread.start(); + } + } + + /** + * Return the DRIVER_ID string for a ServiceReference. + * + * Per Section 8.4.3 of the OSGi SP R2 spec, + * "A Driver service registration must have a DRIVER_ID property" + * + * This method is somewhat more lenient. If no DRIVER_ID property + * is set, it will use the Bundle's location instead. + * + * @param reference Reference to driver service. + * @param log LogService object. + * @return DRIVER_ID string. + */ + public String getDriverID(final ServiceReference reference) { + String driver_id = (String) reference.getProperty(org.osgi.service.device.Constants.DRIVER_ID); + + if (driver_id == null) { + log.log(reference, LogService.LOG_WARNING, DeviceMsg.Driver_service_has_no_DRIVER_ID); + driver_id = (String) AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + return reference.getBundle().getLocation(); + } + }); + } + + return (driver_id); + } + + /** + * Get the ServiceReference for a given DRIVER_ID. + * + * @param driver_id + * @return ServiceReference to a Driver service. + */ + public ServiceReference getDriver(String driver_id) { + return ((ServiceReference) drivers.get(driver_id)); + } + + /** + * Search the driver list to find the best match for the device. + * + * @return ServiceReference to best matched Driver or null of their is no match. + */ + public ServiceReference match(ServiceReference device, Vector exclude) { + if (Activator.DEBUG) { + log.log(device, LogService.LOG_DEBUG, this + ": Driver match called"); //$NON-NLS-1$ + } + + ServiceReference[] references = getServiceReferences(); + + if (references != null) { + int size = references.length; + + Vector successfulMatches = new Vector(size); + + for (int i = 0; i < size; i++) { + ServiceReference driver = references[i]; + + if (exclude.contains(driver)) { + if (Activator.DEBUG) { + log.log(driver, LogService.LOG_DEBUG, this + ": Driver match excluded: " + drivers.get(driver)); //$NON-NLS-1$ + } + } else { + if (Activator.DEBUG) { + log.log(driver, LogService.LOG_DEBUG, this + ": Driver match called: " + drivers.get(driver)); //$NON-NLS-1$ + } + + Match match = getMatch(driver, device); + + if (match == null) { + Driver service = (Driver) getService(driver); + + if (service == null) { + continue; + } + + int matchValue = Device.MATCH_NONE; + + try { + matchValue = service.match(device); + } catch (Throwable t) { + log.log(driver, LogService.LOG_ERROR, DeviceMsg.Driver_error_during_match, t); + + continue; + } + + if (Activator.DEBUG) { + log.log(driver, LogService.LOG_DEBUG, this + ": Driver match value: " + matchValue); //$NON-NLS-1$ + } + + match = new Match(driver, matchValue); + + storeMatch(driver, device, match); + } + + if (match.getMatchValue() > Device.MATCH_NONE) { + successfulMatches.addElement(match); + } + } + } + + size = successfulMatches.size(); + + if (size > 0) { + Match[] matchArray = new Match[size]; + successfulMatches.copyInto(matchArray); + + return manager.selectors.select(device, matchArray); + } + } + + return null; + } + + public Match getMatch(ServiceReference driver, ServiceReference device) { + String driverid = getDriverID(driver); + + Hashtable driverMatches = (Hashtable) matches.get(driverid); + + if (driverMatches == null) { + return null; + } + + return (Match) driverMatches.get(device); + } + + public void storeMatch(ServiceReference driver, ServiceReference device, Match match) { + String driverid = getDriverID(driver); + + Hashtable driverMatches = (Hashtable) matches.get(driverid); + + if (driverMatches == null) { + driverMatches = new Hashtable(37); + + matches.put(driverid, driverMatches); + } + + driverMatches.put(device, match); + } + + /** + * Attempt to attach the driver to the device. If the driver + * refers, add the referred driver to the driver list. + * + * @param driver Driver to attach + * @param device Device to be attached + * @return true is the Driver successfully attached. + */ + public boolean attach(ServiceReference driver, ServiceReference device, Vector exclude) { + if (Activator.DEBUG) { + log.log(driver, LogService.LOG_DEBUG, this + ": Driver attach called: " + drivers.get(driver)); //$NON-NLS-1$ + } + + Driver service = (Driver) getService(driver); + + if (service != null) { + String referral = getReferral(driver, device); + + if (referral == null) { + try { + referral = service.attach(device); + } catch (Throwable t) { + log.log(driver, LogService.LOG_ERROR, DeviceMsg.Driver_error_during_attach, t); + + exclude.addElement(driver); + + return (false); + } + + storeReferral(driver, device, (referral == null) ? "" : referral); //$NON-NLS-1$ + } else { + if (referral.length() == 0) { + referral = null; + } + } + + if (referral == null) { + log.log(device, LogService.LOG_INFO, NLS.bind(DeviceMsg.Device_attached_by_DRIVER_ID, drivers.get(driver))); + + manager.locators.usingDriverBundle(driver.getBundle()); + + return (true); + } + + log.log(device, LogService.LOG_INFO, NLS.bind(DeviceMsg.Device_referred_to, referral)); + manager.locators.loadDriver(referral, this); + } + + exclude.addElement(driver); + + return (false); + } + + public String getReferral(ServiceReference driver, ServiceReference device) { + String driverid = getDriverID(driver); + + Hashtable driverReferrals = (Hashtable) referrals.get(driverid); + + if (driverReferrals == null) { + return null; + } + + return (String) driverReferrals.get(device); + } + + public void storeReferral(ServiceReference driver, ServiceReference device, String referral) { + String driverid = getDriverID(driver); + + Hashtable driverReferrals = (Hashtable) referrals.get(driverid); + + if (driverReferrals == null) { + driverReferrals = new Hashtable(37); + + referrals.put(driverid, driverReferrals); + } + + driverReferrals.put(device, referral); + } + + public String toString() { + return "DriverTracker"; //$NON-NLS-1$ + } + + public class DriverUpdate implements Runnable, ServiceListener, BundleListener { + private Activator manager; + private Bundle bundle; + private BundleContext context; + + /** if false the thread must terminate */ + private volatile boolean running; + + private long updatewait; + + DriverUpdate(Bundle bundle, Activator manager) { + this.manager = manager; + this.bundle = bundle; + + context = manager.context; + updatewait = manager.updatewait; + running = true; + + context.addBundleListener(this); + try { + context.addServiceListener(this, manager.driverFilter.toString()); + } catch (InvalidSyntaxException e) { + /* this should not happen */ + } + } + + public void run() { + // 1. Wait for some time + // 2. if bundle registers Driver; terminate + // 3. if bundle uninstalls; cancel wait + // 4. manager.refineIdleDevices() + + try { + if (updatewait > 0) { + synchronized (this) { + wait(updatewait); + } + } + } catch (InterruptedException e) { + } + + context.removeServiceListener(this); + context.removeBundleListener(this); + + if (running) { + manager.refineIdleDevices(); + } + } + + public void serviceChanged(ServiceEvent event) { + if ((event.getType() == ServiceEvent.REGISTERED) && bundle.equals(event.getServiceReference().getBundle())) { + context.removeServiceListener(this); + + running = false; /* cancel */ + + /* should probably interrupt waiting thread here */ + } + } + + public void bundleChanged(BundleEvent event) { + if ((event.getType() == Bundle.UNINSTALLED) && bundle.equals(event.getBundle())) { + context.removeBundleListener(this); + + updatewait = 0; /* avoid wait */ + + /* should probably interrupt waiting thread here */ + } + } + } +} diff --git a/bundles/org.eclipse.equinox.device/src/org/eclipse/equinox/device/ExternalMessages.properties b/bundles/org.eclipse.equinox.device/src/org/eclipse/equinox/device/ExternalMessages.properties new file mode 100644 index 000000000..380f8f015 --- /dev/null +++ b/bundles/org.eclipse.equinox.device/src/org/eclipse/equinox/device/ExternalMessages.properties @@ -0,0 +1,37 @@ +############################################################################### +# Copyright (c) 2000, 2005 IBM Corporation. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# IBM Corporation - initial API and implementation +############################################################################### +# NLS_MESSAGEFORMAT_ALL + +DeviceManager_started=DeviceManager started +Device_service_unregistered=Device service unregistered +Device_noDriverFound_called=No matching driver found for device +Multiple_Driver_services_with_the_same_DRIVER_ID=Multiple Driver services with the same DRIVER_ID: {0} +DeviceManager_Update_Wait=DeviceManager Update Wait +Driver_service_has_no_DRIVER_ID_property=Driver service has no DRIVER_ID property. Using bundle location as DRIVER_ID. +Device_attached_by_DRIVER_ID=Device attached by DRIVER_ID={0} +Device_referred_to=Device referred to {0} +Unable_to_create_Filter_for_DeviceManager=Unable to create Filter for DeviceManager +DeviceManager_has_thrown_an_error=DeviceManager has thrown an error +Device_noDriverFound_error=Device noDriverFound error +DriverLocator_unable_to_load_driver=DriverLocator unable to load driver: {0} +DriverLocator_error_calling_findDrivers=DriverLocator error calling findDrivers +Unable_to_install_or_start_driver_bundle=Unable to install or start driver bundle: {0} +Unable_to_uninstall_driver_bundle=Unable to uninstall driver bundle +Unable_to_uninstall_driver_bundle_number=Unable to uninstall driver bundle: {0} +DriverSelector_error_during_match=DriverSelector error during match +Driver_service_has_no_DRIVER_ID=Driver service has no DRIVER_ID property. Using bundle location as DRIVER_ID. +Driver_error_during_match=Driver error during match +Driver_error_during_attach=Driver error during attach + +Unknown_Log_level=Unknown Log Level +Info=Log Info +Warning=Log Warning +Error=Log Error
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.device/src/org/eclipse/equinox/device/LogTracker.java b/bundles/org.eclipse.equinox.device/src/org/eclipse/equinox/device/LogTracker.java new file mode 100644 index 000000000..25debd056 --- /dev/null +++ b/bundles/org.eclipse.equinox.device/src/org/eclipse/equinox/device/LogTracker.java @@ -0,0 +1,150 @@ +/******************************************************************************* + * Copyright (c) 1998, 2005 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.device; + +import java.io.PrintStream; +import java.text.DateFormat; +import java.util.Calendar; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.service.log.LogService; +import org.osgi.util.tracker.ServiceTracker; + +/** + * LogTracker class. This class encapsulates the LogService + * and handles all issues such as the service coming and going. + */ + +public class LogTracker extends ServiceTracker implements LogService { + /** LogService interface class name */ + protected final static String clazz = "org.osgi.service.log.LogService"; //$NON-NLS-1$ + + /** PrintStream to use if LogService is unavailable */ + protected PrintStream out; + + /** Calendar and DateFormat to user if LogService is unavailable */ + private static Calendar calendar; + private static DateFormat dateFormat; + private String timestamp; + + /** + * Create new LogTracker. + * + * @param context BundleContext of parent bundle. + * @param out Default PrintStream to use if LogService is unavailable. + */ + public LogTracker(BundleContext context, PrintStream out) { + super(context, clazz, null); + this.out = out; + calendar = Calendar.getInstance(); + dateFormat = DateFormat.getDateTimeInstance(); + open(); + } + + /* + * ---------------------------------------------------------------------- + * LogService Interface implementation + * ---------------------------------------------------------------------- + */ + + public void log(int level, String message) { + log(null, level, message, null); + } + + public void log(int level, String message, Throwable exception) { + log(null, level, message, exception); + } + + public void log(ServiceReference reference, int level, String message) { + log(reference, level, message, null); + } + + public synchronized void log(ServiceReference reference, int level, String message, Throwable exception) { + ServiceReference[] references = getServiceReferences(); + + if (references != null) { + int size = references.length; + + for (int i = 0; i < size; i++) { + LogService service = (LogService) getService(references[i]); + if (service != null) { + try { + service.log(reference, level, message, exception); + } catch (Exception e) { + } + } + } + + return; + } + + noLogService(level, message, exception, reference); + } + + /** + * The LogService is not available so we write the message to a PrintStream. + * + * @param level Logging level + * @param message Log message. + * @param throwable Log exception or null if none. + * @param reference ServiceReference associated with message or null if none. + */ + protected void noLogService(int level, String message, Throwable throwable, ServiceReference reference) { + if (out != null) { + synchronized (out) { + // Bug #113286. If no log service present and messages are being + // printed to stdout, prepend message with a timestamp. + timestamp = dateFormat.format(calendar.getTime()); + out.print(timestamp + " "); //$NON-NLS-1$ + + switch (level) { + case LOG_DEBUG : { + out.print("Debug: "); //$NON-NLS-1$ + + break; + } + case LOG_INFO : { + out.print(LogTrackerMsg.Info); + + break; + } + case LOG_WARNING : { + out.print(LogTrackerMsg.Warning); + + break; + } + case LOG_ERROR : { + out.print(LogTrackerMsg.Error); + + break; + } + default : { + out.print("["); //$NON-NLS-1$ + out.print(LogTrackerMsg.Unknown_Log_level); + out.print("]: "); //$NON-NLS-1$ + + break; + } + } + + out.println(message); + + if (reference != null) { + out.println(reference); + } + + if (throwable != null) { + throwable.printStackTrace(out); + } + } + } + } +} diff --git a/bundles/org.eclipse.equinox.device/src/org/eclipse/equinox/device/LogTrackerMsg.java b/bundles/org.eclipse.equinox.device/src/org/eclipse/equinox/device/LogTrackerMsg.java new file mode 100644 index 000000000..75c1b48d4 --- /dev/null +++ b/bundles/org.eclipse.equinox.device/src/org/eclipse/equinox/device/LogTrackerMsg.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2005 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.device; + +import org.eclipse.osgi.util.NLS; + +public class LogTrackerMsg extends NLS { + private static final String BUNDLE_NAME = "org.eclipse.equinox.device.ExternalMessages"; //$NON-NLS-1$ + + public static String Unknown_Log_level; + public static String Info; + public static String Warning; + public static String Error; + + static { + // initialize resource bundles + NLS.initializeMessages(BUNDLE_NAME, LogTrackerMsg.class); + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.device/src/org/eclipse/equinox/device/Match.java b/bundles/org.eclipse.equinox.device/src/org/eclipse/equinox/device/Match.java new file mode 100644 index 000000000..39482e87c --- /dev/null +++ b/bundles/org.eclipse.equinox.device/src/org/eclipse/equinox/device/Match.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2000, 2005 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.device; + +import org.osgi.framework.ServiceReference; + +/** + * Match implementation class. + * + */ +public class Match implements org.osgi.service.device.Match { + + private ServiceReference driver; + private int matchValue; + + Match(ServiceReference driver, int matchValue) { + this.driver = driver; + this.matchValue = matchValue; + } + + public ServiceReference getDriver() { + return driver; + } + + public int getMatchValue() { + return matchValue; + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.device/src/org/eclipse/equinox/device/SecureAction.java b/bundles/org.eclipse.equinox.device/src/org/eclipse/equinox/device/SecureAction.java new file mode 100644 index 000000000..132cfae1a --- /dev/null +++ b/bundles/org.eclipse.equinox.device/src/org/eclipse/equinox/device/SecureAction.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2003, 2005 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.equinox.device; + +import java.io.IOException; +import java.net.URL; +import java.net.URLConnection; +import java.security.*; + +/** + * Utility class to execute common privileged code. + */ +public class SecureAction { + // make sure we use the correct controlContext; + private AccessControlContext controlContext; + + /** + * Constructs a new SecureAction object. The constructed SecureAction object + * uses the caller's AccessControlContext to perform security checks + */ + public SecureAction() { + // save the control context to be used. + this.controlContext = AccessController.getContext(); + } + + /** + * Creates a new Thread from a Runnable. Same as calling + * new Thread(target,name). + * @param target the Runnable to create the Thread from. + * @param name The name of the Thread. + * @return The new Thread + */ + public Thread createThread(final Runnable target, final String name) { + if (System.getSecurityManager() == null) + return new Thread(target, name); + return (Thread) AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + return new Thread(target, name); + } + }, controlContext); + } + + +} |