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

jdk.dio.DevicePermission 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.security.Permission;
import java.security.PermissionCollection;
import java.util.Enumeration;
import java.util.Vector;

import com.oracle.dio.utils.ExceptionMessage;
import com.oracle.dio.utils.Utils;
import romizer.Local;

/**
 * The {@code DevicePermission} abstract class is the superclass of all device permissions.
 * 

* A {@code DevicePermission} permission has a target name and, optionally, a list of actions. *

* The target name contains hardware addressing information. It takes the following form:

*
( {controller-spec} ) [ ":" {channel-spec}]
* where {controller-spec} and {channel-spec} are defined as follows: *
*
*
{controller-spec}
*
The {controller-spec} takes the following form:
* {controller-name-spec} | {controller-number} | "*" | ""
* where {controller-name-spec} and {controller-number} are defined as follows: *
*
*
{controller-name-spec}
*
The {controller-name-spec} string is the string representation of a controller name as * may be returned by a call to {@link DeviceConfig.HardwareAddressing#getControllerName * DeviceConfig.HardwareAddressing.getControllerName}. A controller name is Operating System specific * such as a device file name on UNIX systems. Occurrences of the semicolon character ( * {@code ":"}) must be escaped with a backslash ({@code "\"}). A {controller-name-spec} * string that ends with an asterisk ({@code "*"}) is a prefix pattern that matches all the controller * names starting with the same prefix.
*
{controller-number}
*
The {controller-number} string is the decimal string representation of a controller * number as may be returned by a call to * {@link DeviceConfig.HardwareAddressing#getControllerNumber * DeviceConfig.HardwareAddressing.getControllerNumber}. The characters in the string must all be * decimal digits.
*
*
* A {controller-spec} specification consisting of the asterisk ({@code "*"}) matches all * controller names or numbers. A {controller-spec} specification consisting of the empty * string ({@code ""}) designates an undefined controller name or number that may only be matched by an * empty string or an asterisk.
*
{channel-spec}
*
The {channel-spec} takes the following form:
* {channel-desc} | "*" | ""
* where {channel-desc} is defined as follows: *
*
*
{channel-desc}
*
The {channel-desc} string is device type-specific and must be defined by * subclasses.
*
*
* A {channel-spec} specification consisting of the asterisk ({@code "*"}) matches all * channels. A {channel-spec} specification consisting of the empty string ({@code ""}) * designates an undefined channel that may only be matched by an empty string or an asterisk. *
* The {@code DevicePermission} abstract class treats the {channel-desc} string * as an opaque string: a {channel-spec} string may therefore only be matched * by the exact same {channel-spec} string or by the asterisk ({@code "*"}). *
*
*
* Subclasses of {@code DevicePermission} may defined additional specific target name formats to * designate devices using their specific hardware addressing information. *

* The actions to be granted are passed to the constructor in a string containing a list of one or * more comma-separated keywords. The supported common actions are {@code open} and * {@code powermanage}. Their meaning is defined as follows:

*
*
*
{@code open}
*
open a device (see {@link DeviceManager#open DeviceManager.open})
*
{@code powermanage}
*
manage the power saving mode of a device (see * {@link jdk.dio.power.PowerManaged})
*
*
* Additional actions to be granted may be defined by subclasses of * {@code DevicePermission}. * * @see DeviceManager#open DeviceManager.open * @see jdk.dio.power.PowerManaged * @since 1.0 */ @apimarker.API("device-io_1.1") public abstract class DevicePermission extends Permission { /** * The {@code open} action. */ public static final String OPEN = "open"; /** * The {@code powermanage} action. */ public static final String POWER_MANAGE = "powermanage"; /** * Coma-separated action list * */ private String myActions; private String thisDevice; private String thisChannel; /** * Constructs a new {@code DevicePermission} with the specified target name and the implicit * {@code open} action. * The target name is normalized so that leading and trailing spaces are removed * and each occurrence of {controller-number} is represented in its canonical * decimal representation form (without leading zeros). * * @param name the target name (as defined above). * @throws NullPointerException if {@code name} is {@code null}. * @throws IllegalArgumentException if {@code name} is not properly formatted. * @see #getName getName */ public DevicePermission(String name) { // null check super(name.toString()); String[] ret = Utils.parseDevicePermissionName(name); thisDevice = ret[0]; thisChannel = ret[1]; myActions = OPEN; } /** * Constructs a new {@code DevicePermission} instance with the specified target name and * action list. * The target name is normalized so that leading and trailing spaces are removed * and each occurrence of {controller-number} is represented in its canonical * decimal representation form (without leading zeros). * * @param name the target name (as defined above). * @param actions comma-separated list of device operations: {@code open} or {@code powermanage} * (additional actions may be defined by subclasses). * @throws NullPointerException if {@code name} is {@code null}. * @throws IllegalArgumentException
    *
  • if {@code actions} is {@code null}, empty or contains an action other than the * specified possible actions,
  • *
  • if {@code name} is not properly formatted.
  • *
* @see #getName getName */ public DevicePermission(String name, String actions) { // null check super(name.toString()); if (null == actions) { throw new IllegalArgumentException( ExceptionMessage.format(ExceptionMessage.DEVICE_NULL_ACTIONS) ); } String[] ret = Utils.parseDevicePermissionName(name); thisDevice = ret[0]; thisChannel = ret[1]; myActions = Utils.verifyAndOrderDeviceActions(actions); } /** * Checks two {@code DevicePermission} objects for equality. * Checks that {@code obj}'s class is the same as this object's class and has the * same name (as returned by {@link Permission#getName Permission.getName}) and same actions (sorted as per {@link #getActions getActions}) as this object. * * @param obj the object to test for equality with this object. * @return {@code true} if {@code obj}'s class is the same as this object's class and has the same target * name and actions as this object; {@code false} otherwise. */ @Override public boolean equals(Object obj) { return equals(this, obj); } /** * Static fucntion for utilization by this class and {@link * DeviceMgmtPermission} * * @param obj1 First object to compare * @param obj2 Second object to compare * @return {@code true} if objects are equals, {@code false} otherwise */ static boolean equals(Object obj1, Object obj2) { if (obj1 == obj2) { return true; } if ((obj1 == null) || (obj2 == null) || (obj1.getClass() != obj2.getClass())) { return false; } Permission p1 = (Permission) obj1; Permission p2 = (Permission) obj2; return (p1.getName().equals(p2.getName()) && p1.getActions().equals(p2.getActions())); } /** * Returns the list of possible actions in the following order: {@code open} * or {@code powermanage} (additional actions may be defined by subclasses). * * @return comma-separated list of possible actions. */ @Override public String getActions() { return myActions; } /** * Returns the hash code value for this object. The hash code is calculated * from this permission's name (as returned by {@link Permission#getName Permission.getName}) and actions (sorted as per {@link #getActions getActions}) * in a way that ensures that {@code permission1.equals(permission2)} implies * that {@code permission1.hashCode()==permission2.hashCode()} for any two permissions, * {@code permission1} and {@code permission2}, as required by the general contract of {@link Object#hashCode() Object.hashCode} * and the contract of {@link Permission#hashCode Permission.hashCode}. * * @return a hash code value for this object. */ @Override public int hashCode() { return (getName() + getActions()).hashCode(); } /** * Checks if this object "implies" the specified permission. *

* More specifically, this method returns {@code true} if:

*
    *
  • {@code permission}'s class is the same as this object's class, and
  • *
  • {@code permission}'s actions (as returned by {@link #getActions getActions}) are a proper subset of this object's action list, and
  • *
  • {@code permission}'s hardware addressing information or range thereof is included in this * object's hardware addressing information range; the implementation of this method by * the {@code DevicePermission} abstract class treats the channel description ({channel-desc}) string * as an opaque string: a channel specification ({channel-spec}) string may therefore only be matched * by the exact same a channel specification string or by the asterisk ({@code "*"}).
  • *
* * @param permission the permission to check against. * @return {@code true} if the specified permission is not {@code null} and is implied by this * object, {@code false} otherwise. */ @Override public boolean implies(Permission permission) { if ((permission == null) || (permission.getClass() != getClass())) { return false; } return privateImplies(permission); } @Local(WeakDontRenameSubtypes = {"jdk.dio.DevicePermission"}) public String toString() { return getClass().getName() + " \'" + getName() + "\' " + getActions(); } boolean privateImplies(Permission permission) { if (!Utils.implies(getActions(), permission.getActions())) { return false; } String thatDevice = ((DevicePermission) permission).thisDevice; String thatChannel = ((DevicePermission) permission).thisChannel; // compare names if (!"*".equals(thisDevice)) { // if not pure wildcard if (thisDevice.endsWith("*")) { // compare "\dev\tty*" and "\dev\*" or "\dev\tty1" and "\dev\*" if (thisDevice.length() > thatDevice.length() || // wildcard has to be shorter or equals to other name or whildcard !thatDevice.startsWith(thisDevice.substring(0, thisDevice.length() - 1)) // other name should starts with our wildcard ) { return false; } } else { if (!thisDevice.equals(thatDevice)) { // other name may not be either wildcard or different name return false; } } } if (!"*".equals(thisChannel)) { // compare channels if (0 == thisChannel.length() && (0 == thatChannel.length() || "*".equals(thatChannel))) { //A {channel-spec} specification consisting of the empty string ("") designates an undefined channel //that may only be matched by an empty string or an asterisk. return true; } // no need to parse as every {channel-spec} limits characters map to either decimal or heximal digits but does not allow to mix them return thisChannel.equals(thatChannel); } //A {channel-spec} specification consisting of the asterisk ("*") matches all channels. return true; } /** * Returns a new {@code PermissionCollection} for storing {@code DevicePermission} objects. *

* {@code DevicePermission} objects must be stored in a manner that allows them to be * inserted into the collection in any order, but that also enables the * {@link PermissionCollection#implies PermissionCollection.implies} method to be implemented in an efficient (and * consistent) manner. *

* For example, assuming a {@code PermissionCollection} object containing * the two following {@code DevicePermission}s:

*
    *
  1. "adc:1", "powermanage"
  2. *
  3. "adc:*", "open"
  4. *
*

* when calling the {@code implies} method on that * {@code PermissionCollection} object with the {@code DevicePermission}: *

     *   "adc:1", "open,powermanage",
     * 
*

the {@code implies} method must take into account both the "adc:*" * and "adc:1" permissions, so the effective permission is * "open,powermanage", and {@code implies} returns {@code true}. The * "implies" semantics for {@code DevicePermission}s are handled properly by * the {@code PermissionCollection} object returned by this method. If a device-specific subclass * of {@code DevicePermission} defines a different "implies" semantics then * that subclass must re-implement this method accordingly. *

* * @return a new {@code PermissionCollection} suitable for storing {@code DevicePermission}. */ @Override public PermissionCollection newPermissionCollection() { return new PeripheralPermissionCollection(this.getClass()); } } final class LocalPermission extends DevicePermission { /** * Comma-separated actions list */ private String myActions; LocalPermission(String name) { super(name); myActions = OPEN; } LocalPermission(String name, String actionsList) { //super(name, actionsList); super(name); myActions = Utils.verifyAndOrderActions(actionsList, DevicePermission.OPEN + ",data," + DevicePermission.POWER_MANAGE + ",setdirection"); } @Override public String getActions() { return myActions; } } final class PeripheralPermissionCollection extends PermissionCollection { private final Vector permissions = new Vector<>(6); /** * The class to which all PeripheralPermissios in this * PeripheralPermissionCollection belongs. */ private final Class permClazz; PeripheralPermissionCollection(Class clazz) { permClazz = clazz; } public boolean implies(Permission permission) { if (!permClazz.isInstance(permission)) { return false; } DevicePermission perm = (DevicePermission) permission; String[] actionsList = Utils.getActionsList(perm.getActions()); Enumeration search = permissions.elements(); int len = actionsList.length; if (len <= 1) { while (search.hasMoreElements()) { if (search.nextElement().implies(perm)) { return true; } } } else { DevicePermission splittedPerm; boolean implyRes = true; for (int i = 0; i < len && implyRes; i++) { boolean res = false; splittedPerm = new LocalPermission(permission.getName(), actionsList[i]); search = permissions.elements(); while (search.hasMoreElements()) { DevicePermission p = search.nextElement(); if (p.privateImplies(splittedPerm)) { res = true; break; } } implyRes = implyRes && res; } return implyRes; } return false; } public void add(Permission permission) { if (!permClazz.isInstance(permission)) { throw new IllegalArgumentException( ExceptionMessage.format(ExceptionMessage.DEVICE_INVALID_PERMISSION, permission) ); } if (isReadOnly()) { throw new SecurityException( ExceptionMessage.format(ExceptionMessage.DEVICE_READONLY_PERMISSION_COLLECTION) ); } permissions.addElement((DevicePermission) permission); } public Enumeration elements() { return permissions.elements(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy