All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jdk.dio.DeviceManager Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package jdk.dio;

import java.io.IOException;
import java.security.AccessController;
import java.util.Iterator;
import java.util.Random;
import java.util.ServiceConfigurationError;
import java.util.ServiceLoader;

import com.oracle.dio.impl.PeripheralDescriptorImpl;
import com.oracle.dio.impl.PeripheralFactory;
import com.oracle.dio.impl.Platform;
import com.oracle.dio.registry.RegistrationEventHandler;
import com.oracle.dio.registry.RegistrationEventSender;
import com.oracle.dio.registry.Registry;
import com.oracle.dio.utils.Constants;
import com.oracle.dio.utils.ExceptionMessage;
import com.oracle.dio.utils.Logging;
import com.oracle.dio.utils.PrivilegeController;
import com.oracle.dio.utils.PrivilegedAction;

import jdk.dio.spi.DeviceProvider;

import romizer.Local;

/**
 * The {@code DeviceManager} class provides methods for opening and registering
 * devices that can then be handled as {@link Device} instances. A device
 * of a particular type can be opened using its platform-specific numeric ID or name as well as
 * its properties or using an ad-hoc configuration (in which case, its hardware addressing
 * information must be explicitly provided).
 * 

* A device may be identified by a numeric ID. This ID is unrelated to the * hardware number (hardware addressing information) that may be used to identify a device such as a * GPIO pin number or an I2C slave device address. A device ID typically corresponds to a * registered configuration for a device. The numeric ID of a device must be * greater than or equal to {@code 0} and must be unique. Yet the same device may be * directly and indirectly mapped through several IDs; each ID may correspond to a different * configuration, representation or abstraction for the same underlying device hardware * resource.
* A device opened with an ad-hoc configuration - that is: not * through one of its registered configurations - is not assigned a numeric ID nor a name. Its * numeric ID and name are both undefined and set respectively to * {@link DeviceDescriptor#UNDEFINED_ID UNDEFINED_ID} and {@code null}. *

* Devices may be opened in either * exclusive or shared mode. By default, * devices are opened in exclusive mode. Whether a device can be opened in * shared mode depends on the underlying device hardware as well as on the underlying * device driver. It also depends on whether the provided {@code Device} implementation is a * dedicated, virtualized or shared abstraction of the underlying * device resource.
* When a device is open with an ad-hoc configuration in shared mode then the * {@code Device} implementation (or driver) may throw a * {@link InvalidDeviceConfigException} if the device is already open and the * requested adhoc configuration is incompatible with the current configuration of the * device.
* When a device is open in shared mode then some explicit means of access * synchronization may have to be used such as by invoking {@link Device#tryLock Device.tryLock} and * {@link Device#unlock Device.unlock}. Device locks are held on a per {@code Device} instance basis. * When the same device is open twice in shared access mode by the same application, * locking one of the {@code Device} instances will prevent the other from being accessed/used. *

* Opening a device of a specific type with a registered configuration is * subject to permission checks (see {@link DeviceMgmtPermission#OPEN}).
* Opening a device of a specific type with an ad-hoc configuration is subject * to permission checks specific for that type (for example see * {@link jdk.dio.gpio.GPIOPinPermission GPIOPinPermission.OPEN}). This permission check * should be implemented by the {@link jdk.dio.spi.DeviceProvider#open * DeviceProvider.open} method.
* Registration and unregistration of devices are subject to permission checks (see * {@link DeviceMgmtPermission#REGISTER} and {@link DeviceMgmtPermission#UNREGISTER}). *
* For more details see Security Model. *

*

Device Probing

* For some peripheral hardware such as I2C bus or SPI bus, opening (or registering) a device * such as a slave device on a bus does not necessarily entail immediately * accessing the device. Upon opening the device the underlying platform or * driver may probe for the device to check whether the device exists and is * addressable and whether the requested configuration is valid; if the probing * for device determines that the device does not exist or is not addressable * or, that it does not support the requested configuration a * {@code DeviceNotFoundException} or respectively an * {@code InvalidDeviceConfigException} is thrown. When the underlying platform or * driver does not implement any probing facility a {@code Device} instance * is returned, but I/O operations on the device will later fail - typically with an * {@code IOException} - if the device does not exist, is not addressable, or * does not support the requested configuration. * * @see UnavailableDeviceException * @see DeviceMgmtPermission * @see Device * @see jdk.dio.spi.DeviceProvider * @see DeviceConfig * @since 1.0 */ @apimarker.API("device-io_1.1") public class DeviceManager { /** * Exclusive access mode. *

* This bit flag can be bitwise-combined (OR) with other access mode bit flags. *

*/ public static final int EXCLUSIVE = 1; /** * Shared access mode. *

* This bit flag can be bitwise-combined (OR) with other access mode bit flags. *

*/ public static final int SHARED = 2; /** * Unspecified device numeric ID - requesting the allocation of a free ID. * * @see #register register */ public static final int UNSPECIFIED_ID = -1; /** * Platform specific initialization. */ static { Platform.initialize(); } /** * List all platform- and user-registered devices. * * @param

* the type of devices listed. * @return an enumeration of the descriptors of all registered devices. */ public static

> Iterator> list() { return Registry.getInstance().list(null); } /** * List all platform- and user-registered devices of the designated type. * * @param

* the type of devices to list. * @param intf * the interface (sub-interface of {@code Device}) of the device to be * registered. * @return an enumeration of the descriptors of all registered devices of the designated * type. * @throws NullPointerException * if {@code intf} is {@code null}. */ public static

> Iterator> list(Class

intf) { // checks for null intf.isArray(); return Registry.getInstance().list(intf); } /** * Opens a device, returning a {@code Device} instance of the specified type to access it. * The device to open is designated by the provided hardware addressing information and is * initially set-up according to the specified configuration. The specified device type and specified * configuration type must be compatible. *

* Opening a device from its hardware addressing information and with an ad-hoc configuration * may be subject to device probing limitations . *

* The device is opened in exclusive access mode. *

* The returned {@code Device} instance's ID and name are undefined. * A new instance is returned upon each call. *

* * @param

* the type of the device to open. * @param intf * the interface (sub-interface of {@code Device}) of the device to open. * @param config * the device configuration (which includes hardware addressing information as * well as configuration parameters). * @return a new {@code Device} instance to access the designated device. * @throws UnsupportedDeviceTypeException * if the designated device type is not supported. * @throws InvalidDeviceConfigException * if the provided device configuration (as defined by the configuration * parameters) is not valid/supported. * @throws DeviceNotFoundException * if the device designated by the hardware addressing information is not found. * @throws UnavailableDeviceException * if the designated device is not currently available - such as if it is * already open with exclusive access. * @throws IOException * if any other I/O error occurred. * @throws SecurityException * if the caller has no permission to access the designated device (see * {@link DevicePermission#OPEN}). * @throws NullPointerException * if {@code intf} or {@code config} is {@code null}. * @throws ClassCastException * if the device configuration type specified by {@code config} * is not applicable to the device type specified by {@code intf}. */ public static

> P open(Class

intf, DeviceConfig config) throws IOException, InvalidDeviceConfigException, UnsupportedDeviceTypeException, DeviceNotFoundException, UnavailableDeviceException { return open(intf, config, EXCLUSIVE); } /** * Opens a device, returning a {@code Device} instance of the specified type to access it. * The device to open is designated by the provided hardware addressing information and is * initially set-up according to the specified configuration. The specified device type and specified * configuration type must be compatible. *

* Opening a device from its hardware addressing information and with an ad-hoc configuration * may be subject to device probing limitations . *

* The device is opened in the designated access mode. A device may be * opened in shared mode if supported by the underlying driver and hardware and if it is not * already opened in exclusive mode. A device may be opened in exclusive mode if * supported by the underlying driver and hardware and if it is not already opened. *

* The returned {@code Device} instance's ID and name are undefined. * A new instance is returned upon each call. *

* * @param

* the type of the device to open. * @param intf * the interface (sub-interface of {@code Device}) of the device to open. * @param config * the device configuration (which includes hardware addressing information as * well as configuration parameters). * @param mode * the access mode, one of: {@link #EXCLUSIVE} or {@link #SHARED}. * @return a new {@code Device} instance to access the designated device. * @throws UnsupportedDeviceTypeException * if the designated device type is not supported. * @throws InvalidDeviceConfigException * if the provided device configuration (as defined by the configuration * parameters) is not valid/supported or when opened in shared mode, if the provided * device configuration is incompatible with the currently open configuration of * the device. * @throws DeviceNotFoundException * if the device designated by the hardware addressing information is not found. * @throws UnavailableDeviceException * if the designated device is not currently available - such as if it is * already open with exclusive access. * @throws UnsupportedAccessModeException * if the requested access mode is not supported. * @throws IOException * if any other I/O error occurred. * @throws SecurityException * if the caller has no permission to access the designated device (see * {@link DevicePermission#OPEN}). * @throws NullPointerException * if {@code intf} or {@code config} is {@code null}. * @throws ClassCastException * if the device configuration type specified by {@code config} * is not applicable to the device type specified by {@code intf}. */ public static

> P open(Class

intf, DeviceConfig config, int mode) throws IOException, InvalidDeviceConfigException, UnsupportedDeviceTypeException, DeviceNotFoundException, UnavailableDeviceException, UnsupportedAccessModeException { if (null == intf) { throw new NullPointerException( ExceptionMessage.format(ExceptionMessage.DEVICE_NULL_CONFIG_OR_INTF) ); } return openWithConfig(intf, config, mode); } private static

> P openWithConfig(Class

intf, DeviceConfig config, int mode) throws IOException, InvalidDeviceConfigException, UnsupportedDeviceTypeException, DeviceNotFoundException, UnavailableDeviceException, UnsupportedAccessModeException { if (null == config) { throw new NullPointerException( ExceptionMessage.format(ExceptionMessage.DEVICE_NULL_CONFIG_OR_INTF) ); } checkMode(mode); PeripheralDescriptorImpl

descr = new PeripheralDescriptorImpl(UNSPECIFIED_ID, null, config, intf, null); if (null != intf) { try { return ((PeripheralFactory

)getFactory(intf)).create(descr, mode); } catch (DeviceNotFoundException | UnsupportedDeviceTypeException e) { P res = (P)loadFromDriver(descr, mode); if (null == res) { throw e; } return res; } } else { // special case: getDefaultType returns null that means config is not for embedded drivers // try to load from installed drivers P res = (P)loadFromDriver(descr, mode); if (null == res) { throw new UnsupportedDeviceTypeException(config.toString()); } return res; } } /** * Looks up then opens the device designated by the provided numeric ID, * returning a {@code Device} instance to access it. * The device configuration registered for the provided ID is first looked up; * the device designated by the retrieved hardware addressing information is open and is * initially set-up according to the registered configuration. *

* The device is opened in exclusive access mode. * A new instance is returned upon each call. *

* * @param

* the type of the device to open. * @param id * the numeric device id. * @return a new {@code Device} instance to access the designated device. * @throws DeviceNotFoundException * if the designated device is not found. * @throws UnavailableDeviceException * if the designated device is not currently available - such as if it is * already open with exclusive access. * @throws IOException * if any other I/O error occurred. * @throws SecurityException * if the caller has no permission to access the designated device (see * {@link DeviceMgmtPermission#OPEN}). * @throws IllegalArgumentException * if {@code id} is less than {@code 0}. */ public static

> P open(int id) throws IOException, DeviceNotFoundException, UnavailableDeviceException { try { return (P)open(id, Device.class); } catch (UnsupportedDeviceTypeException e) { throw new DeviceNotFoundException( ExceptionMessage.format(ExceptionMessage.DEVICE_CONFIG_PROBLEM, e.getMessage()) ); } } /** * Looks up then opens the device designated by the provided numeric ID and type, * returning a {@code Device} instance of the specified type to access it. * The device configuration registered for the provided ID is first looked up; * the device designated by the retrieved hardware addressing information is open and is * initially set-up according to the registered configuration. The specified device type and retrieved * configuration type must be compatible. *

* The device is opened in exclusive access mode. * A new instance is returned upon each call. *

* * @param

* the type of the device to open. * @param id * the numeric device id. * @param intf * the interface (sub-interface of {@code Device}) of the device being looked * up. * @return a new {@code Device} instance to access the designated device. * @throws DeviceNotFoundException * if the designated device is not found. * @throws UnsupportedDeviceTypeException * if the designated device type is not supported. * @throws UnavailableDeviceException * if the designated device is not currently available - such as if it is * already open with exclusive access. * @throws IOException * if any other I/O error occurred. * @throws SecurityException * if the caller has no permission to access the designated device (see * {@link DeviceMgmtPermission#OPEN}). * @throws IllegalArgumentException * if {@code id} is less than {@code 0}. * @throws NullPointerException * if {@code intf} is {@code null}. */ public static

> P open(int id, Class

intf) throws IOException, UnsupportedDeviceTypeException, DeviceNotFoundException, UnavailableDeviceException { try { return open(id, intf, EXCLUSIVE); } catch (UnsupportedAccessModeException e) { throw new DeviceNotFoundException( ExceptionMessage.format(ExceptionMessage.DEVICE_EXCLUSIVE_MODE_UNSUPPORTED) ); } } /** * Looks up then opens the device designated by the provided numeric ID and type, * returning a {@code Device} instance of the specified type to access it. * The device configuration registered for the provided ID is first looked up; * the device designated by the retrieved hardware addressing information is open and is * initially set-up according to the registered configuration. The specified device type and retrieved * configuration type must be compatible. *

* The device is opened in the designated access mode. A device may be * opened in shared mode if supported by the underlying driver and hardware and if it is not * already opened in exclusive mode. A device may be opened in exclusive mode if * supported by the underlying driver and hardware and if it is not already opened. *

* A new instance is returned upon each call. *

* * @param

* the type of the device to open. * @param id * the numeric device id. * @param intf * the interface (sub-interface of {@code Device}) of the device being looked * up. * @param mode * the access mode, one of: {@link #EXCLUSIVE} or {@link #SHARED}. * @return a new {@code Device} instance to access the designated device. * @throws UnsupportedDeviceTypeException * if the designated device type is not supported. * @throws DeviceNotFoundException * if the designated device is not found. * @throws UnavailableDeviceException * if the designated device is not currently available - such as when it is * already open in an access mode incompatible with the requested access mode. * @throws UnsupportedAccessModeException * if the requested access mode is not supported. * @throws IOException * if any other I/O error occurred. * @throws SecurityException * if the caller has no permission to access the designated device (see * {@link DeviceMgmtPermission#OPEN}). * @throws IllegalArgumentException * if {@code id} is less than {@code 0}. * @throws NullPointerException * if {@code intf} is {@code null}. */ public static

> P open(int id, Class

intf, int mode) throws IOException, UnsupportedDeviceTypeException, DeviceNotFoundException, UnavailableDeviceException, UnsupportedAccessModeException { Registry.checkID(id); do { AccessController.checkPermission(new DeviceMgmtPermission("*:" + id, DeviceMgmtPermission.OPEN)); } while (false); checkMode(mode); if (null == intf) { throw new NullPointerException( ExceptionMessage.format(ExceptionMessage.DEVICE_NULL_INTF) ); } PeripheralDescriptorImpl

descr = (PeripheralDescriptorImpl

)Registry.getInstance().get(id); if (null == descr) { throw new DeviceNotFoundException( ExceptionMessage.format(ExceptionMessage.DEVICE_NOT_FOUND, String.valueOf(id)) ); } if (!intf.isAssignableFrom(descr.getInterface())) { getFactory(intf); throw new DeviceNotFoundException( ExceptionMessage.format(ExceptionMessage.DEVICE_HAS_DIFFERENT_TYPE, id, descr.getInterface()) ); } try { final PeripheralFactory

f = getFactory(descr.getInterface()); final DeviceDescriptor

fdescr = descr; final int fmode = mode; return PrivilegeController.doPrivileged(new PrivilegedAction

() { public P run() throws IOException { return f.create(fdescr, fmode); } }); } catch (InvalidDeviceConfigException e) { throw new DeviceNotFoundException(e.getMessage()); } catch (DeviceNotFoundException | UnsupportedDeviceTypeException e) { P res = (P)loadFromDriver(descr, mode); if (null == res) { throw e; } return res; } } /** * Looks up then opens the device designated by the provided numeric ID, * returning a {@code Device} instance to access it. * The device configuration registered for the provided ID is first looked up; * the device designated by the retrieved hardware addressing information is open and is * initially set-up according to the registered configuration. *

* The device is opened in the designated access mode. A device may be * opened in shared mode if supported by the underlying driver and hardware and if it is not * already opened in exclusive mode. A device may be opened in exclusive mode if * supported by the underlying driver and hardware and if it is not already opened. *

* The device is opened in exclusive access mode. * A new instance is returned upon each call. *

* * @param

* the type of the device to open. * @param id * the numeric device id. * @param mode * the access mode, one of: {@link #EXCLUSIVE} or {@link #SHARED}. * @return a new {@code Device} instance to access the designated device. * @throws DeviceNotFoundException * if the designated device is not found. * @throws UnavailableDeviceException * if the designated device is not currently available - such as when it is * already open in an access mode incompatible with the requested access mode. * @throws UnsupportedAccessModeException * if the requested access mode is not supported. * @throws IOException * if any other I/O error occurred. * @throws SecurityException * if the caller has no permission to access the designated device (see * {@link DeviceMgmtPermission#OPEN}). * @throws IllegalArgumentException * if {@code id} is less than {@code 0}. */ public static

> P open(int id, int mode) throws IOException, DeviceNotFoundException, UnavailableDeviceException, UnsupportedAccessModeException { try { return (P)open(id, Device.class, mode); } catch (UnsupportedDeviceTypeException e) { throw new DeviceNotFoundException( ExceptionMessage.format(ExceptionMessage.DEVICE_CONFIG_PROBLEM, e.getMessage()) ); } } /** * Opens a device, returning a {@code Device} instance of the specified type to access it. * The device to open is designated by the provided hardware addressing information and is * initially set-up according to the specified configuration. * The type of the device is inferred from the configuration type. *

* Opening a device from its hardware addressing information and with an ad-hoc configuration * may be subject to device probing limitations . *

* The device is opened in exclusive access mode. *

* The returned {@code Device} instance's ID and name are undefined. * A new instance is returned upon each call. *

* * @param

* the type of the device to open. * @param config * the device configuration (which includes hardware addressing information as * well as configuration parameters). * @return a new {@code Device} instance to access the designated device. * @throws UnsupportedDeviceTypeException * if the designated device type is not supported. * @throws InvalidDeviceConfigException * if the provided device configuration (as defined by the configuration * parameters) is not valid/supported. * @throws DeviceNotFoundException * if the device designated by the hardware addressing information is not found. * @throws UnavailableDeviceException * if the designated device is not currently available - such as if it is * already open with exclusive access. * @throws IOException * if any other I/O error occurred. * @throws SecurityException * if the caller has no permission to access the designated device (see * {@link DevicePermission#OPEN}). * @throws NullPointerException * if {@code config} is {@code null}. */ public static

> P open(DeviceConfig config) throws IOException, InvalidDeviceConfigException, UnsupportedDeviceTypeException, DeviceNotFoundException, UnavailableDeviceException { return open(config, EXCLUSIVE); } /** * Opens a device, returning a {@code Device} instance of the specified type to access it. * The device to open is designated by the provided hardware addressing information and is * initially set-up according to the specified configuration. * The type of the device is inferred from the configuration type. *

* Opening a device from its hardware addressing information and with an ad-hoc configuration * may be subject to device probing limitations. *

* The device is opened in the designated access mode. A device may be * opened in shared mode if supported by the underlying driver and hardware and if it is not * already opened in exclusive mode. A device may be opened in exclusive mode if * supported by the underlying driver and hardware and if it is not already opened. *

* The returned {@code Device} instance's ID and name are undefined. * A new instance is returned upon each call. *

* * @param

* the type of the device to open. * @param config * the device configuration (which includes hardware addressing information as * well as configuration parameters). * @param mode * the access mode, one of: {@link #EXCLUSIVE} or {@link #SHARED}. * @return a new {@code Device} instance to access the designated device. * @throws UnsupportedDeviceTypeException * if the designated device type is not supported. * @throws InvalidDeviceConfigException * if the provided device configuration (as defined by the configuration * parameters) is not valid/supported or when opened in shared mode, if the provided * device configuration is incompatible with the currently open configuration of * the device. * @throws DeviceNotFoundException * if the device designated by the hardware addressing information is not found. * @throws UnavailableDeviceException * if the designated device is not currently available - such as if it is * already open with exclusive access. * @throws UnsupportedAccessModeException * if the requested access mode is not supported. * @throws IOException * if any other I/O error occurred. * @throws SecurityException * if the caller has no permission to access the designated device (see * {@link DevicePermission#OPEN}). * @throws NullPointerException * if {@code config} is {@code null}. */ public static

> P open(DeviceConfig config, int mode) throws IOException, InvalidDeviceConfigException, UnsupportedDeviceTypeException, DeviceNotFoundException, UnavailableDeviceException, UnsupportedAccessModeException { return openWithConfig(getDefaultType(config),config,mode); } /** * Looks up then opens a device designated by the provided name, type and properties, * returning a {@code Device} instance of the specified type to access it. * A registered device configuration matching the provided name, type and properties is first looked up; * if the device designated by the retrieved hardware addressing information is available * it is open and initially set-up according to the matching configuration; * if the device is already open in a mode that is not compatible * with the requested mode the next matching registered device configuration is considered. *
* A provided {@code null} name matches all registered device names; an empty * string name can only be matched by an empty string name or a by a {@code null} name. *

* The device is opened in the designated access mode. A device may be * opened in shared mode if supported by the underlying driver and hardware and if it is not * already opened in exclusive mode. A device may be opened in exclusive mode if * supported by the underlying driver and hardware and if it is not already opened. *

* A new instance is returned upon each call. *

* Property-based lookup only uses exact (case-insensitive) matching and does not perform any * semantic interpretation. *

* * @param

* the type of the device to open. * @param name * the device name; may be {@code null}. * @param intf * the interface (sub-interface of {@code Device}) of the device being looked * up. * @param mode * the access mode, one of: {@link #EXCLUSIVE} or {@link #SHARED}. * @param properties * the list of required properties; may be {@code null}. * @return a new {@code Device} instance to access the designated device. * @throws UnsupportedDeviceTypeException * if the designated device type is not supported. * @throws DeviceNotFoundException * if the designated device is not found. * @throws UnavailableDeviceException * if the designated device is not currently available - such as when it is * already open in an access mode incompatible with the requested access mode. * @throws UnsupportedAccessModeException * if the requested access mode is not supported. * @throws IOException * if any other I/O error occurred. * @throws SecurityException * if the caller has no permission to access the designated device (see * {@link DeviceMgmtPermission#OPEN}). * @throws IllegalArgumentException * if both {@code name} is {@code null} and {@code properties} is empty. * @throws NullPointerException * if {@code intf} is {@code null}. */ public static

> P open(String name, Class

intf, int mode, String... properties) throws IOException, UnsupportedDeviceTypeException, DeviceNotFoundException, UnavailableDeviceException, UnsupportedAccessModeException { if (null == name && (null == properties || 0 == properties.length)) { throw new IllegalArgumentException( ExceptionMessage.format(ExceptionMessage.DEVICE_NULL_NAME_AND_PROPERTIES) ); } do { AccessController.checkPermission(new DeviceMgmtPermission(((null == name)? "" : name) + ":*", DeviceMgmtPermission.OPEN)); } while (false); if (null == intf) { throw new NullPointerException( ExceptionMessage.format(ExceptionMessage.DEVICE_NULL_INTF) ); } checkMode(mode); // try to guess if this device type is valid try { getFactory(intf); } catch (UnsupportedDeviceTypeException e) { // nothing found yet checkWithProviders(intf); } Iterator> iter = Registry.getInstance().get(name, intf, properties); while (iter.hasNext()) { PeripheralDescriptorImpl

descr = iter.next(); try { final PeripheralFactory

f = getFactory(descr.getInterface()); final DeviceDescriptor

fdescr = descr; final int fmode = mode; return PrivilegeController.doPrivileged(new PrivilegedAction

() { public P run() throws IOException { return f.create(fdescr, fmode); } }); } catch (InvalidDeviceConfigException e) { throw new DeviceNotFoundException(e.getMessage()); } catch (UnavailableDeviceException e2) { if (iter.hasNext()) { // find next configuration continue; } throw e2; } catch (DeviceNotFoundException | UnsupportedDeviceTypeException e) { P res = (P)loadFromDriver(descr, mode); if (null == res) { throw e; } return res; } } // type is valid, but no valid config is found throw new DeviceNotFoundException(name); } /** * Looks up then opens a device designated by the provided name, type and properties, * returning a {@code Device} instance of the specified type to access it. * A registered device configuration matching the provided name, type and properties is first looked up; * if the device designated by the retrieved hardware addressing information is available * it is open and initially set-up according to the matching configuration; * if the device is already open (therefore not available) * the next matching registered device configuration is considered. *
* A provided {@code null} name matches all registered device names; an empty * string name can only be matched by an empty string name or a by a {@code null} name. *

* The device is opened in exclusive access mode. *

* A new instance is returned upon each call. *

* Property-based lookup only uses exact (case-insensitive) matching and does not perform any * semantic interpretation. *

* * @param

* the type of the device to open. * @param name * the device name; may be {@code null}. * @param intf * the interface (sub-interface of {@code Device}) of the device being looked * up. * @param properties * the list of required properties; may be {@code null}. * @return a new {@code Device} instance to access the designated device. * @throws UnsupportedDeviceTypeException * if the designated device type is not supported. * @throws DeviceNotFoundException * if the designated device is not found. * @throws UnavailableDeviceException * if the designated device is not currently available - such as if it is * already open with exclusive access. * @throws IOException * if any other I/O error occurred. * @throws SecurityException * if the caller has no permission to access the designated device (see * {@link DeviceMgmtPermission#OPEN}). * @throws IllegalArgumentException * if both {@code name} is {@code null} and {@code properties} is empty. * @throws NullPointerException * if {@code intf} is {@code null}. */ public static

> P open(String name, Class

intf, String... properties) throws IOException, UnsupportedDeviceTypeException, DeviceNotFoundException, UnavailableDeviceException { try { return open(name, intf, EXCLUSIVE, properties); } catch (UnsupportedAccessModeException e) { throw new DeviceNotFoundException( ExceptionMessage.format(ExceptionMessage.DEVICE_EXCLUSIVE_MODE_UNSUPPORTED) ); } } /** * Registers under the specified ID and name (as well as optional properties) a new device * supporting the provided configuration. Upon successful registration all * {@link RegistrationListener} instances registered for the type of the registered device * are notified. *

* An implementation of the {@code DeviceManager} MUST guarantee that an application * registering a device is the first one to get notified (in the event it has registered a * {@code RegistrationListener} for that type of devices). *

* The designated device may be probed to check if the provided configuration is valid * (see device probing limitations ). *

* Prior to registering a new device of a certain type the * {@link DeviceMgmtPermission} is checked with the action * {@link DeviceMgmtPermission#REGISTER DeviceMgmtPermission.REGISTER}.
* For example, if a device of type {@link jdk.dio.gpio.GPIOPin * GPIOPin} is to be registered the {@code DeviceMgmtPermission} is checked with a target * name composed of the requested device name and ID and with the action * {@link DeviceMgmtPermission#REGISTER DeviceMgmtPermission.REGISTER}. *

* The following is an example of how this method may be used to register a new UART with Modem * control lines:

*
     * DeviceManager.register(10, // the device ID
     *         ModemUART.class, // the device type/interface
     *         new UARTConfig.Builder()
     *             .setControllerNumber(0)
     *             .setChannelNumber(0)
     *             .setBaudRate(2400)
     *             .setDataBits(UARTConfig.DATABITS_8)
     *             .setParity(UARTConfig.PARITY_EVEN)
     *             .setStopBits(UARTConfig.STOPBITS_1)
     *             .setFlowControlMode(UARTConfig.FLOWCONTROL_NONE)
     *             .build(), // the device configuration
     *         "MODEM", // the device name
     *         "com.foobar.modem.xxx=true", "com.foobar.modem.yyy=true" // the device capabilities
     * );
     * 
*
* * @param

* the type of the device to be registered. * @param id * the device ID; if {@code id} is equal to {@link #UNSPECIFIED_ID} a free ID * will be allocated. * @param intf * the interface (sub-interface of {@code Device}) of the device to be * registered. * @param config * the device configuration. * @param name * the name of the device to be registered. * @param properties * the list of properties/capabilities of the device to be registered; may be * {@code null}. * @return the assigned device ID. * @throws InvalidDeviceConfigException * if the provided device configuration (as defined by the configuration * parameters) is not valid/supported. * @throws UnsupportedDeviceTypeException * if the designated device type is not supported. * @throws DeviceNotFoundException * if the device designated by the hardware addressing information is not found. * @throws DeviceAlreadyExistsException * if {@code id} is already assigned to a device. * @throws IOException * if any other I/O error occurred. * @throws NullPointerException * if {@code name}, {@code intf} or {@code config} is {@code null}. * @throws IllegalArgumentException * if {@code id} is less than {@code 0} and is not equal to {@link #UNSPECIFIED_ID}. * @throws UnsupportedOperationException * if registering a new device is not supported - such as may be the case * on a platform supporting only a closed device topology. * @throws SecurityException * if the caller does not have the required permission (see * {@link DeviceMgmtPermission#REGISTER}). * @throws ClassCastException * if the device configuration type specified by {@code config} * is not applicable to the device type specified by {@code intf}. */ public static

> int register(int id, Class

intf, DeviceConfig config, String name, String... properties) throws IOException, UnsupportedDeviceTypeException, InvalidDeviceConfigException, DeviceNotFoundException, DeviceAlreadyExistsException { // quick fix: need info about custom DeviceConfig factory (if any) PeripheralDescriptorImpl

dscr = new PeripheralDescriptorImpl(id, name, config, intf, properties); // this fills dscr with correct provider try (Device d = loadFromDriver(dscr, EXCLUSIVE)) { } catch (Exception e) { // intentionally ignored } int new_id = Registry.getInstance().register(dscr); RegistrationEventSender.notifyRegistered(null, dscr); return new_id; } /** * Unregisters the device associated with the specified ID. Upon successful * unregistration all {@link RegistrationListener} instances registered for the type of the * device that has been unregistered are notified. *

* Some devices are registered by the underlying platform and cannot be unregistered. *

* Unregistration of a device has no side effect on its currently open * {@code Device} instances. These {@code Device} instances especially retain the * device ID that was assigned to them at the time they were open. *

* This method returns silently if the provided ID does not correspond to a registered * device. *

* * @param id * the ID of the device to unregister. * @throws IllegalArgumentException * if {@code id} is less than {@code 0} or if {@code id} corresponds to a device * device registered by the platform. * @throws SecurityException * if the caller does not have the required permission (see * {@link DeviceMgmtPermission#UNREGISTER}). */ public static void unregister(int id) { final Registry r = Registry.getInstance(); DeviceDescriptor unreg_d = r.unregister(id); // send notify if (null != unreg_d) RegistrationEventSender.notifyUnregistered(null, unreg_d); } /** * Adds the specified registration listener to receive notification of registration and * unregistration of devices of the specified type. * * @param

* the type of the device to be listened for. * @param listener * the registration listener. * @param intf * the interface (sub-interface of {@code Device}) of the devices to be * listened for. * @throws NullPointerException * if {@code listener} or {@code intf} is {@code null}. */ public static

> void addRegistrationListener(RegistrationListener

listener, Class

intf) { // checks for null listener.getClass(); intf.isArray(); RegistrationEventHandler.addListener(listener, intf); } /** * Removes the specified registration listener so that it no longer receives notification of * registration and unregistration of devices of the specified type. * * @param

* the type of the device listened for. * @param listener * the registration listener. * @param intf * the interface (sub-interface of {@code Device}) of the devices listened * for. * @throws NullPointerException * if {@code listener} or {@code intf} is {@code null}. */ public static

> void removeRegistrationListener(RegistrationListener

listener, Class

intf) { // checks for null listener.getClass(); intf.isArray(); RegistrationEventHandler.removeListener(listener, intf); } /** * Prevents instantiation. */ private DeviceManager() {} /* ------------------- Private API ---------------- */ private static void checkMode(int mode) throws UnsupportedAccessModeException { if (SHARED != mode && EXCLUSIVE != mode) { throw new UnsupportedAccessModeException(); } } @Local(WeakDontRenameSubtypes = {"jdk.dio.DeviceConfig"}) private static

> Class

getDefaultType(DeviceConfig config) throws UnsupportedDeviceTypeException { String fullName = config.getClass().getName(); if (-1 != fullName.indexOf(Constants.PREFIX)) { try { // extract peripheral name from config name // i.e. ADCChannel from com.oracle.dio.ADCChannelConfig int configPos = fullName.indexOf(Constants.CONFIG); return (Class

)Class.forName(fullName.substring(0, configPos)); } catch (RuntimeException | ClassNotFoundException e) { } } // this will cause NPE at open(Class, DeviceConfig, int) // fix later return null; } @Local(DontRenameNonAbstractSubtypes = {"com.oracle.dio.impl.PeripheralFactory"}) private static PeripheralFactory getFactory(Class clazz) throws UnsupportedDeviceTypeException { // get package name of com.oracle.dio.PACAKAGE_NAME.PERIPHERAL_IFACE // following code is correct for precompiled peripheral driver that follows DAAPI name convention. String fullName = clazz.getName(); // check for name correctness from current spec point of view. // it is enough to check only name of class itself because of all DAAPI config class are final. // it is assumed that neither driver nor application can create a code for com.oracle.* domain. // it is not correct for JavaSE but running code has no super user rights. if (-1 != fullName.indexOf(Constants.PREFIX)) { int pIndex = fullName.indexOf('.', Constants.PREFIX.length()); try { String pack = fullName.substring(Constants.PREFIX.length(), pIndex); String device = fullName.substring(pIndex + 1); return (PeripheralFactory)Class.forName(Constants.FACTORY_PREFIX + pack + Constants.IMPL + device + Constants.FACTORY).newInstance(); } catch (RuntimeException | ClassNotFoundException | InstantiationException | IllegalAccessException e) { } } throw new UnsupportedDeviceTypeException( ExceptionMessage.format(ExceptionMessage.DEVICE_INVALID_CLASSNAME, fullName) ); } // is called in response to UDTE and DNFE private static

> P loadFromDriver(PeripheralDescriptorImpl

descr, int mode) throws DeviceNotFoundException, UnavailableDeviceException, InvalidDeviceConfigException, UnsupportedAccessModeException, IOException { ServiceLoader loader = ServiceLoader.load(DeviceProvider.class); Iterator iter = loader.iterator(); final DeviceConfig

config = descr.getConfiguration(); final Class

type = descr.getInterface(); boolean found = false; try { if (!iter.hasNext()) { return null; } while (iter.hasNext()) { DeviceProvider provider = iter.next(); try { if (provider.getConfigType().isAssignableFrom(config.getClass()) && (null == type || provider.getType().equals(type))) { found = true; if (provider.matches(descr.getProperties())) { // properties was checked by Registry when descriptor was loaded up P dev = (P)provider.open(config,descr.getProperties(),mode); // hack for config registration: save info about factory that may restore config from serialized data descr.setDeviceProvider(provider); return dev; } } } catch (UnavailableDeviceException | InvalidDeviceConfigException | UnsupportedAccessModeException | SecurityException e) { // driver was found but it rejects provided data or device is busy or application has no rights to use the driver. // the driver is suitable for config class deserialization as well descr.setDeviceProvider(provider); throw e; } catch (Throwable e3) { Logging.reportError("Provider " + provider + " throws " + e3); // try other driver. // spec quotation: // A compliant implementation of the DeviceManager specification MUST catch undeclared unchecked exceptions, // unexpected values (such as null) or mismatching value types that may be thrown // or respectively returned at any of these steps // and MUST report these conditions to the caller as a DeviceNotFoundException. found = true; continue; } } } catch (ServiceConfigurationError ex) { // service framework exception equals to empty iterator return null; } if (found) { throw new DeviceNotFoundException( ExceptionMessage.format(ExceptionMessage.DEVICE_DRIVERS_NOT_MATCH) ); } // no driver matches descritor, caller will throw UDTE or DNFE return null; } private static void checkWithProviders(Class intf) throws UnsupportedDeviceTypeException { Iterator iter = ServiceLoader.load(DeviceProvider.class).iterator(); try { while (iter.hasNext()) { DeviceProvider provider = iter.next(); try { if (provider.getType().equals(intf)) { return; } } catch (Throwable e) { // any exception threats as type is not suuported by provider } } } catch (ServiceConfigurationError ex) { // intentionally ignored } throw new UnsupportedDeviceTypeException ( ExceptionMessage.format(ExceptionMessage.DEVICE_DRIVER_MISSING) ); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy