jdk.dio.DeviceMgmtPermission Maven / Gradle / Ivy
Show all versions of org.openjdk.dio Show documentation
/*
* 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.Objects;
import java.util.Vector;
import com.oracle.dio.utils.Utils;
import com.oracle.dio.utils.Utils;
import com.oracle.dio.utils.ExceptionMessage;
/**
* The {@code DeviceMgmtPermission} class defines permissions for registering and unregistering devices as
* well as opening devices using their registered configurations.
*
* Device management permissions have a target name and actions.
*
* The target name is a combination of a device name and of a device ID or range of device IDs.
* It takes the following form:
*
* {device-name-spec} [ ":"{device-id-spec} ]
*
* where {device-name-spec} and {device-id-spec} are defined as follows:
*
*
* {device-name-spec}
* -
* The
{device-name-spec} string takes the following form:
*
* {device-name} | "*" | ""
*
* The {device-name}string is a device name as may be returned by a call to {@link DeviceDescriptor#getName() DeviceDescriptor.getName}.
* Occurrences of the semicolon character ({@code ":"}) must be escaped with a backslash ({@code "\"}).
*
* A {device-name-spec} specification consisting of the asterisk ("*") matches all device names.
* A {device-name-spec} specification consisting of the empty string ("") designates an undefined device name
* that may only be matched by an empty string or an asterisk.
*
* {device-id-spec}
* -
* The
{device-id-spec} string takes the following form:
*
* {device-id} | "-"{device-id} | {device-id}"-"[{device-id}] | "*"
*
* The {device-id} string is a device ID as may be returned by a call to {@link DeviceDescriptor#getID() DeviceDescriptor.getID}.
* The characters in the string must all be decimal digits.
*
* A {device-id-spec} specification of the form "N-M" (where N and M are device IDs) designates
* a range of device IDs from N (inclusive) to M (inclusive), where M is greater or equal to N.
* A {device-id-spec} specification of the form "N-" (where N is a device ID) signifies all device IDs
* numbered N and above, while a specification of the form "-N" indicates all device IDs numbered N and below.
* A single asterisk in the place of the {device-id-spec} field matches all device IDs.
*
* The target name {@code "*:*"} matches all device names and all device IDs as is the target name {@code "*"}.
*
*
*
*
* 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 actions are {@code open}, {@code register} and {@code unregister}. Their
* meaning is defined as follows:
*
*
* - {@code open}
* - open a device using its device ID or name (see {@link DeviceManager#open(int) DeviceManager.open(id, ...)}
* and {@link DeviceManager#open(java.lang.String, java.lang.Class, java.lang.String[]) DeviceManager.open(name, ...)} methods)
* - {@code register}
* - register a new device (see {@link DeviceManager#register DeviceManager.register})
* - {@code unregister}
* - unregister a device (see {@link DeviceManager#unregister DeviceManager.unregister})
*
*
*
* @see DeviceManager#open DeviceManager.open
* @see DeviceManager#register DeviceManager.register
* @see DeviceManager#unregister DeviceManager.unregister
* @since 1.0
*/
@apimarker.API("device-io_1.1")
public class DeviceMgmtPermission extends Permission {
/**
* The {@code register} action.
*/
public static final String REGISTER = "register";
/**
* The {@code unregister} action.
*/
public static final String UNREGISTER = "unregister";
/**
* The {@code open} action.
*/
public static final String OPEN = "open";
/** Comma-separated ordered action list */
private String myActions;
private String thisName;
private int lowID = -1;
private int highID = -1;
/**
* Constructs a new {@code DeviceMgmtPermission} 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 {device-id} is represented in its canonical
* decimal representation form (no leading zeros).
*
*
* @param name
* the target name (as defined above).
* @param actions
* comma-separated list of device management operations: {@code register}
* {@code unregister} or {@code open}.
* @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.
*
*/
public DeviceMgmtPermission(String name, String actions) {
// null check
super(name.toString());
if (null == actions) {
throw new IllegalArgumentException(
ExceptionMessage.format(ExceptionMessage.DEVICE_NULL_ACTIONS)
);
}
checkTargetNameFormat(name);
myActions = Utils.verifyAndOrderActions(actions, REGISTER+","+UNREGISTER+","+OPEN);
}
private void checkTargetNameFormat(String name) {
Objects.requireNonNull(name, ExceptionMessage.format(ExceptionMessage.DEVICE_NULL_NAME));
String id;
int idx = -1;
while (-1 != (idx = name.indexOf(':', idx + 1))) {
if (idx == 0 || '\\' != name.charAt(idx - 1) ) {
break;
}
}
if (-1 == idx) {
thisName = name;
id = "";
} else {
thisName = name.substring(0, idx);
id = name.substring(idx + 1);
if ("".equals(id)) {
throw new IllegalArgumentException(ExceptionMessage.format(ExceptionMessage.DEVICE_INVALID_PERMISSION));
}
}
if ("*".equals(id) || "".equals(id)) {
lowID = 0;
highID = Integer.MAX_VALUE;
} else {
idx = -1;
boolean foundDash = false;
for (int i = 0; i < id.length(); i++) {
char c = id.charAt(i);
if (!Character.isDigit(c)) {
if ('-' == c && !foundDash) {
foundDash = true;
break;
}
}
}
lowID = 0;
highID = Integer.MAX_VALUE;
try {
if (foundDash) {
idx = id.indexOf('-');
if (idx > 0) {
lowID = Integer.parseInt(id.substring(0, idx));
}
if (idx < id.length() - 1) {
highID = Integer.parseInt(id.substring(idx + 1));
}
if (lowID > highID) {
throw new IllegalArgumentException(ExceptionMessage.format(ExceptionMessage.DEVICE_INVALID_PERMISSION));
}
} else {
lowID = Integer.parseInt(id);
highID = Integer.parseInt(id);
}
} catch (NumberFormatException e) {
throw new IllegalArgumentException(ExceptionMessage.format(ExceptionMessage.DEVICE_INVALID_PERMISSION));
}
}
return;
}
/**
* Checks two {@code DeviceMgmtPermission} 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 DevicePermission.equals(this, obj);
}
/**
* Returns the list of possible actions in the following order: {@code register},
* {@code unregister} or {@code open}.
*
* @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() + myActions).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 device name, ID or range thereof
* is included in this device name or ID range, whichever is defined.
*
*
* @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;
if (!Utils.implies(myActions, permission.getActions())) return false;
String thatName = ((DeviceMgmtPermission)permission).thisName;
if (!"*".equals(thisName)) {
// the empty string ("") designates an undefined peripheral name
// that may only be matched by an empty string or an asterisk.
// the same condition is for full name.
if (!thisName.equals(thatName)) {
return false;
}
}
int thatLowID = ((DeviceMgmtPermission)permission).lowID;
int thatHightID = ((DeviceMgmtPermission)permission).highID;
return (thatLowID >= lowID && thatLowID <= highID &&
thatHightID >= lowID && thatHightID <= highID);
}
/**
* Returns a new {@code PermissionCollection} for storing {@code DeviceMgmtPermission} objects.
*
* {@code DeviceMgmtPermission} 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.
*
* @return a new {@code PermissionCollection} suitable for storing {@code DeviceMgmtPermission} objects.
*/
@Override
public PermissionCollection newPermissionCollection() {
return null;
}
}