You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by ch...@apache.org on 2008/08/02 11:56:04 UTC
svn commit: r681945 [5/9] - in /felix/trunk/org.osgi.compendium: ./ doc/
src/main/java/info/ src/main/java/info/dmtree/
src/main/java/info/dmtree/notification/
src/main/java/info/dmtree/notification/spi/
src/main/java/info/dmtree/registry/ src/main/jav...
Added: felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/security/DmtPermission.java
URL: http://svn.apache.org/viewvc/felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/security/DmtPermission.java?rev=681945&view=auto
==============================================================================
--- felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/security/DmtPermission.java (added)
+++ felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/security/DmtPermission.java Sat Aug 2 02:56:01 2008
@@ -0,0 +1,442 @@
+/*
+ * $Header: /cvshome/build/info.dmtree/src/info/dmtree/security/DmtPermission.java,v 1.10 2006/10/19 13:32:53 tszeredi Exp $
+ *
+ * Copyright (c) OSGi Alliance (2004, 2006). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package info.dmtree.security;
+
+import info.dmtree.Acl;
+import info.dmtree.Uri;
+
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.util.*;
+
+/**
+ * Controls access to management objects in the Device Management Tree (DMT). It
+ * is intended to control local access to the DMT. DmtPermission target string
+ * identifies the management object URI and the action field lists the OMA DM
+ * commands that are permitted on the management object. Example:
+ *
+ * <pre>
+ * DmtPermission("./OSGi/bundles", "Add,Replace,Get");
+ * </pre>
+ *
+ * This means that owner of this permission can execute Add, Replace and Get
+ * commands on the ./OSGi/bundles management object. It is possible to use
+ * wildcards in both the target and the actions field. Wildcard in the target
+ * field means that the owner of the permission can access children nodes of the
+ * target node. Example:
+ *
+ * <pre>
+ * DmtPermission("./OSGi/bundles/*", "Get");
+ * </pre>
+ *
+ * This means that owner of this permission has Get access on every child node
+ * of ./OSGi/bundles. The asterix does not necessarily have to follow a '/'
+ * character. For example the
+ * <code>"./OSGi/a*"</code> target matches the
+ * <code>./OSGi/applications</code> subtree.
+ * <p>
+ * If wildcard is present in the actions field, all legal OMA DM commands are
+ * allowed on the designated nodes(s) by the owner of the permission. Action
+ * names are interpreted case-insensitively, but the canonical action string
+ * returned by {@link #getActions} uses the forms defined by the action
+ * constants.
+ */
+public class DmtPermission extends Permission {
+ private static final long serialVersionUID = -1910969921419407809L;
+
+ /**
+ * Holders of DmtPermission with the Add action present can create new nodes
+ * in the DMT, that is they are authorized to execute the
+ * createInteriorNode() and createLeafNode() methods of the DmtSession. This
+ * action is also required for the copy() command, which needs to perform
+ * node creation operations (among others).
+ */
+ public static final String ADD = "Add";
+
+ /**
+ * Holders of DmtPermission with the Delete action present can delete nodes
+ * from the DMT, that is they are authorized to execute the deleteNode()
+ * method of the DmtSession.
+ */
+ public static final String DELETE = "Delete";
+
+ /**
+ * Holders of DmtPermission with the Exec action present can execute nodes
+ * in the DMT, that is they are authorized to call the execute() method of
+ * the DmtSession.
+ */
+ public static final String EXEC = "Exec";
+
+ /**
+ * Holders of DmtPermission with the Get action present can query DMT node
+ * value or properties, that is they are authorized to execute the
+ * isLeafNode(), getNodeAcl(), getEffectiveNodeAcl(), getMetaNode(),
+ * getNodeValue(), getChildNodeNames(), getNodeTitle(), getNodeVersion(),
+ * getNodeTimeStamp(), getNodeSize() and getNodeType() methods of the
+ * DmtSession. This action is also required for the copy() command, which
+ * needs to perform node query operations (among others).
+ */
+ public static final String GET = "Get";
+
+ /**
+ * Holders of DmtPermission with the Replace action present can update DMT
+ * node value or properties, that is they are authorized to execute the
+ * setNodeAcl(), setNodeTitle(), setNodeValue(), setNodeType() and
+ * renameNode() methods of the DmtSession. This action is also be required
+ * for the copy() command if the original node had a title property (which
+ * must be set in the new node).
+ */
+ public static final String REPLACE = "Replace";
+
+ // does this permission have a wildcard at the end?
+ private final boolean prefixPath;
+
+ // the name without the wildcard on the end
+ private final String path;
+
+ // the actions mask
+ private final int mask;
+
+ // the canonical action string (redundant)
+ private final String actions;
+
+ /**
+ * Creates a new DmtPermission object for the specified DMT URI with the
+ * specified actions. The given URI can be:
+ * <ul>
+ * <li> <code>"*"</code>, which matches all valid
+ * (see {@link Uri#isValidUri}) absolute URIs;
+ * <li> the prefix of an absolute URI followed by the <code>*</code>
+ * character (for example <code>"./OSGi/L*"</code>), which matches all valid
+ * absolute URIs beginning with the given prefix;
+ * <li> a valid absolute URI, which matches itself.
+ * </ul>
+ * <p>
+ * Since the <code>*</code> character is itself a valid URI character, it
+ * can appear as the last character of a valid absolute URI. To distinguish
+ * this case from using <code>*</code> as a wildcard, the <code>*</code>
+ * character at the end of the URI must be escaped with the <code>\</code>
+ * charater. For example the URI <code>"./a*"</code> matches
+ * <code>"./a"</code>, <code>"./aa"</code>, <code>"./a/b"</code> etc. while
+ * <code>"./a\*"</code> matches <code>"./a*"</code> only.
+ * <p>
+ * The actions string must either be "*" to allow all actions, or it must
+ * contain a non-empty subset of the valid actions, defined as constants in
+ * this class.
+ *
+ * @param dmtUri URI of the management object (or subtree)
+ * @param actions OMA DM actions allowed
+ * @throws NullPointerException if any of the parameters are
+ * <code>null</code>
+ * @throws IllegalArgumentException if any of the parameters are invalid
+ */
+ public DmtPermission(String dmtUri, String actions) {
+ super(dmtUri);
+ mask = getMask(actions);
+ this.actions = canonicalActions(mask);
+
+ if (dmtUri == null)
+ throw new NullPointerException("'dmtUri' parameter must not be " +
+ "null.");
+
+ prefixPath = dmtUri.endsWith("*") && !dmtUri.endsWith("\\*");
+
+ if(prefixPath) {
+ dmtUri = dmtUri.substring(0, dmtUri.length() - 1);
+
+ // the single "*" as dmtUri is the only valid non-absolute URI param
+ if(dmtUri.length() == 0) {
+ path = "";
+ return;
+ }
+ }
+
+ // if URI ends with "/*", remove it before the validity check
+ if(prefixPath && dmtUri.endsWith("/") && !dmtUri.endsWith("\\/"))
+ checkUri(dmtUri.substring(0, dmtUri.length() - 1));
+ else
+ checkUri(dmtUri);
+
+ // canonicalize URI: remove escapes from non-special characters
+ StringBuffer sb = new StringBuffer(dmtUri);
+ int i = 0;
+ while(i < sb.length()) { // length can decrease during the loop!
+ if(sb.charAt(i) == '\\') {
+ // there must be a next character after a '\' in a valid URI
+ char nextCh = sb.charAt(i+1);
+ if(nextCh != '/' && nextCh != '\\')
+ sb.deleteCharAt(i); // remove the extra '\'
+ else
+ i++;
+ }
+ i++;
+ }
+ path = sb.toString();
+ }
+
+ private void checkUri(String dmtUri) throws IllegalArgumentException {
+ if(!Uri.isValidUri(dmtUri))
+ throw new IllegalArgumentException("'dmtUri' parameter does not " +
+ "contain a valid URI.");
+
+ if(!Uri.isAbsoluteUri(dmtUri))
+ throw new IllegalArgumentException("'dmtUri' parameter does not " +
+ "contain an absolute URI.");
+ }
+
+ /**
+ * Checks whether the given object is equal to this DmtPermission instance.
+ * Two DmtPermission instances are equal if they have the same target string
+ * and the same action mask. The "*" action mask is considered equal to a
+ * mask containing all actions.
+ *
+ * @param obj the object to compare to this DmtPermission instance
+ * @return <code>true</code> if the parameter represents the same
+ * permissions as this instance
+ */
+ public boolean equals(Object obj) {
+ if (obj == this)
+ return true;
+
+ if (!(obj instanceof DmtPermission))
+ return false;
+
+ DmtPermission other = (DmtPermission) obj;
+
+ return mask == other.mask && prefixPath == other.prefixPath
+ && path.equals(other.path);
+ }
+
+ /**
+ * Returns the String representation of the action list. The allowed actions
+ * are listed in the following order: Add, Delete, Exec, Get, Replace. The
+ * wildcard character is not used in the returned string, even if the class
+ * was created using the "*" wildcard.
+ *
+ * @return canonical action list for this permission object
+ */
+ public String getActions() {
+ return actions;
+ }
+
+ /**
+ * Returns the hash code for this permission object. If two DmtPermission
+ * objects are equal according to the {@link #equals} method, then calling
+ * this method on each of the two DmtPermission objects must produce the
+ * same integer result.
+ *
+ * @return hash code for this permission object
+ */
+ public int hashCode() {
+ return new Integer(mask).hashCode()
+ ^ new Boolean(prefixPath).hashCode() ^ path.hashCode();
+ }
+
+ /**
+ * Checks if this DmtPermission object "implies" the specified
+ * permission. This method returns <code>false</code> if and only if at
+ * least one of the following conditions are fulfilled for the specified
+ * permission:
+ * <ul>
+ * <li>it is not a DmtPermission
+ * <li>its set of actions contains an action not allowed by this permission
+ * <li>the set of nodes defined by its path contains a node not defined by
+ * the path of this permission
+ * </ul>
+ *
+ * @param p the permission to check for implication
+ * @return true if this DmtPermission instance implies the specified
+ * permission
+ */
+ public boolean implies(Permission p) {
+ if (!(p instanceof DmtPermission))
+ return false;
+
+ DmtPermission other = (DmtPermission) p;
+
+ if ((mask & other.mask) != other.mask)
+ return false;
+
+ return impliesPath(other);
+ }
+
+ /**
+ * Returns a new PermissionCollection object for storing DmtPermission
+ * objects.
+ *
+ * @return the new PermissionCollection
+ */
+ public PermissionCollection newPermissionCollection() {
+ return new DmtPermissionCollection();
+ }
+
+ // parses the given action string, and returns the corresponding action mask
+ private static int getMask(String actions) {
+ int mask = 0;
+
+ if (actions == null)
+ throw new NullPointerException(
+ "'actions' parameter cannot be null.");
+
+ if (actions.equals("*"))
+ return Acl.ALL_PERMISSION;
+
+ // empty tokens (swallowed by StringTokenizer) are not considered errors
+ StringTokenizer st = new StringTokenizer(actions, ",");
+ while (st.hasMoreTokens()) {
+ String action = st.nextToken();
+ if (action.equalsIgnoreCase(GET)) {
+ mask |= Acl.GET;
+ } else if (action.equalsIgnoreCase(ADD)) {
+ mask |= Acl.ADD;
+ } else if (action.equalsIgnoreCase(REPLACE)) {
+ mask |= Acl.REPLACE;
+ } else if (action.equalsIgnoreCase(DELETE)) {
+ mask |= Acl.DELETE;
+ } else if (action.equalsIgnoreCase(EXEC)) {
+ mask |= Acl.EXEC;
+ } else
+ throw new IllegalArgumentException("Invalid action '" + action
+ + "'");
+ }
+
+ if (mask == 0)
+ throw new IllegalArgumentException("Action mask cannot be empty.");
+
+ return mask;
+ }
+
+ // generates the canonical string representation of the action list
+ private static String canonicalActions(int mask) {
+ StringBuffer sb = new StringBuffer();
+ addAction(sb, mask, Acl.ADD, ADD);
+ addAction(sb, mask, Acl.DELETE, DELETE);
+ addAction(sb, mask, Acl.EXEC, EXEC);
+ addAction(sb, mask, Acl.GET, GET);
+ addAction(sb, mask, Acl.REPLACE, REPLACE);
+ return sb.toString();
+ }
+
+ // if 'flag' appears in 'mask', appends the 'action' string to the contents
+ // of 'sb', separated by a comma if needed
+ private static void addAction(StringBuffer sb, int mask, int flag,
+ String action) {
+ if ((mask & flag) != 0) {
+ if (sb.length() > 0)
+ sb.append(',');
+ sb.append(action);
+ }
+ }
+
+ // used by DmtPermissionCollection to retrieve the action mask
+ int getMask() {
+ return mask;
+ }
+
+ // returns true if the path parameter of the given DmtPermission is
+ // implied by the path of this permission, i.e. this path is a prefix of the
+ // other path, but ends with a *, or the two path strings are equal
+ boolean impliesPath(DmtPermission p) {
+ return prefixPath ? p.path.startsWith(path) : !p.prefixPath
+ && p.path.equals(path);
+ }
+}
+
+/**
+ * Represents a homogeneous collection of DmtPermission objects.
+ */
+final class DmtPermissionCollection extends PermissionCollection {
+ private static final long serialVersionUID = -4172481774562012941L;
+
+ // OPTIMIZE keep a special flag for permissions of "*" path
+
+ private ArrayList perms;
+
+ /**
+ * Create an empty DmtPermissionCollection object.
+ */
+ public DmtPermissionCollection() {
+ perms = new ArrayList();
+ }
+
+ /**
+ * Adds a permission to the DmtPermissionCollection.
+ *
+ * @param permission the Permission object to add
+ * @exception IllegalArgumentException if the permission is not a
+ * DmtPermission
+ * @exception SecurityException if this DmtPermissionCollection object has
+ * been marked readonly
+ */
+ public void add(Permission permission) {
+ if (!(permission instanceof DmtPermission))
+ throw new IllegalArgumentException(
+ "Cannot add permission, invalid permission type: "
+ + permission);
+ if (isReadOnly())
+ throw new SecurityException(
+ "Cannot add permission, collection is marked read-only.");
+
+ // No need to synchronize because all adds are done sequentially
+ // before any implies() calls
+ perms.add(permission);
+ }
+
+ /**
+ * Check whether this set of permissions implies the permission specified in
+ * the parameter.
+ *
+ * @param permission the Permission object to compare
+ * @return true if the parameter permission is a proper subset of the
+ * permissions in the collection, false otherwise
+ */
+ public boolean implies(Permission permission) {
+ if (!(permission instanceof DmtPermission))
+ return false;
+
+ DmtPermission other = (DmtPermission) permission;
+
+ int required = other.getMask();
+ int available = 0;
+ int needed = required;
+
+ Iterator i = perms.iterator();
+ while (i.hasNext()) {
+ DmtPermission p = (DmtPermission) i.next();
+ if (((needed & p.getMask()) != 0) && p.impliesPath(other)) {
+ available |= p.getMask();
+ if ((available & required) == required)
+ return true;
+ needed = (required ^ available);
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns an enumeration of all the DmtPermission objects in the container.
+ * The returned value cannot be <code>null</code>.
+ *
+ * @return an enumeration of all the DmtPermission objects
+ */
+ public Enumeration elements() {
+ // Convert Iterator into Enumeration
+ return Collections.enumeration(perms);
+ }
+}
Added: felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/security/DmtPrincipalPermission.java
URL: http://svn.apache.org/viewvc/felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/security/DmtPrincipalPermission.java?rev=681945&view=auto
==============================================================================
--- felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/security/DmtPrincipalPermission.java (added)
+++ felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/security/DmtPrincipalPermission.java Sat Aug 2 02:56:01 2008
@@ -0,0 +1,263 @@
+/*
+ * $Header: /cvshome/build/info.dmtree/src/info/dmtree/security/DmtPrincipalPermission.java,v 1.4 2006/07/12 21:21:52 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2004, 2006). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package info.dmtree.security;
+
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.util.*;
+
+/**
+ * Indicates the callers authority to create DMT sessions on behalf of a remote
+ * management server. Only protocol adapters communicating with management
+ * servers should be granted this permission.
+ * <p>
+ * <code>DmtPrincipalPermission</code> has a target string which controls the
+ * name of the principal on whose behalf the protocol adapter can act. A
+ * wildcard is allowed at the end of the target string, to allow using any
+ * principal name with the given prefix. The "*" target means the
+ * adapter can create a session in the name of any principal.
+ */
+public class DmtPrincipalPermission extends Permission {
+ private static final long serialVersionUID = 6388752177325038332L;
+
+ // specifies whether the target string had a wildcard at the end
+ private final boolean isPrefix;
+
+ // the target string without the wildcard (if there was one)
+ private final String principal;
+
+ /**
+ * Creates a new <code>DmtPrincipalPermission</code> object with its name
+ * set to the target string. Name must be non-null and non-empty.
+ *
+ * @param target the name of the principal, can end with <code>*</code> to
+ * match any principal with the given prefix
+ * @throws NullPointerException if <code>name</code> is <code>null</code>
+ * @throws IllegalArgumentException if <code>name</code> is empty
+ */
+ public DmtPrincipalPermission(String target) {
+ super(target);
+
+ if (target == null)
+ throw new NullPointerException(
+ "'target' parameter must not be null.");
+
+ if (target.equals(""))
+ throw new IllegalArgumentException(
+ "'target' parameter must not be empty.");
+
+ isPrefix = target.endsWith("*");
+ if (isPrefix)
+ principal = target.substring(0, target.length() - 1);
+ else
+ principal = target;
+ }
+
+ /**
+ * Creates a new <code>DmtPrincipalPermission</code> object using the
+ * 'canonical' two argument constructor. In this version this class does not
+ * define any actions, the second argument of this constructor must be "*"
+ * so that this class can later be extended in a backward compatible way.
+ *
+ * @param target the name of the principal, can end with <code>*</code> to
+ * match any principal with the given prefix
+ * @param actions no actions defined, must be "*" for forward compatibility
+ * @throws NullPointerException if <code>name</code> or
+ * <code>actions</code> is <code>null</code>
+ * @throws IllegalArgumentException if <code>name</code> is empty or
+ * <code>actions</code> is not "*"
+ */
+ public DmtPrincipalPermission(String target, String actions) {
+ this(target);
+
+ if (actions == null)
+ throw new NullPointerException(
+ "'actions' parameter must not be null.");
+
+ if (!actions.equals("*"))
+ throw new IllegalArgumentException(
+ "'actions' parameter must be \"*\".");
+ }
+
+ /**
+ * Checks whether the given object is equal to this DmtPrincipalPermission
+ * instance. Two DmtPrincipalPermission instances are equal if they have the
+ * same target string.
+ *
+ * @param obj the object to compare to this DmtPrincipalPermission instance
+ * @return <code>true</code> if the parameter represents the same
+ * permissions as this instance
+ */
+ public boolean equals(Object obj) {
+ if (obj == this)
+ return true;
+
+ if (!(obj instanceof DmtPrincipalPermission))
+ return false;
+
+ DmtPrincipalPermission other = (DmtPrincipalPermission) obj;
+
+ return isPrefix == other.isPrefix && principal.equals(other.principal);
+ }
+
+ /**
+ * Returns the action list (always <code>*</code> in the current version).
+ *
+ * @return the action string "*"
+ */
+ public String getActions() {
+ return "*";
+ }
+
+ /**
+ * Returns the hash code for this permission object. If two
+ * DmtPrincipalPermission objects are equal according to the {@link #equals}
+ * method, then calling this method on each of the two
+ * DmtPrincipalPermission objects must produce the same integer result.
+ *
+ * @return hash code for this permission object
+ */
+ public int hashCode() {
+ return new Boolean(isPrefix).hashCode() ^ principal.hashCode();
+ }
+
+ /**
+ * Checks if this DmtPrincipalPermission object implies the specified
+ * permission. Another DmtPrincipalPermission instance is implied by this
+ * permission either if the target strings are identical, or if this target
+ * can be made identical to the other target by replacing a trailing
+ * "*" with any string.
+ *
+ * @param p the permission to check for implication
+ * @return true if this DmtPrincipalPermission instance implies the
+ * specified permission
+ */
+ public boolean implies(Permission p) {
+ if (!(p instanceof DmtPrincipalPermission))
+ return false;
+
+ DmtPrincipalPermission other = (DmtPrincipalPermission) p;
+
+ return impliesPrincipal(other);
+ }
+
+ /**
+ * Returns a new PermissionCollection object for storing
+ * DmtPrincipalPermission objects.
+ *
+ * @return the new PermissionCollection
+ */
+ public PermissionCollection newPermissionCollection() {
+ return new DmtPrincipalPermissionCollection();
+ }
+
+ /*
+ * Returns true if the principal parameter of the given
+ * DmtPrincipalPermission is implied by the principal of this permission,
+ * i.e. this principal is a prefix of the other principal but ends with a *,
+ * or the two principal strings are equal.
+ */
+ boolean impliesPrincipal(DmtPrincipalPermission p) {
+ return isPrefix ? p.principal.startsWith(principal) : !p.isPrefix
+ && p.principal.equals(principal);
+ }
+}
+
+/**
+ * Represents a homogeneous collection of DmtPrincipalPermission objects.
+ */
+final class DmtPrincipalPermissionCollection extends PermissionCollection {
+ private static final long serialVersionUID = -6692103535775802684L;
+
+ private ArrayList perms;
+
+ /**
+ * Create an empty DmtPrincipalPermissionCollection object.
+ */
+ public DmtPrincipalPermissionCollection() {
+ perms = new ArrayList();
+ }
+
+ /**
+ * Adds a permission to the DmtPrincipalPermissionCollection.
+ *
+ * @param permission the Permission object to add
+ * @exception IllegalArgumentException if the permission is not a
+ * DmtPrincipalPermission
+ * @exception SecurityException if this DmtPrincipalPermissionCollection
+ * object has been marked readonly
+ */
+ public void add(Permission permission) {
+ if (!(permission instanceof DmtPrincipalPermission))
+ throw new IllegalArgumentException(
+ "Cannot add permission, invalid permission type: "
+ + permission);
+ if (isReadOnly())
+ throw new SecurityException(
+ "Cannot add permission, collection is marked read-only.");
+
+ // only add new permission if it is not already implied by the
+ // permissions in the collection
+ if (!implies(permission)) {
+ // remove all permissions that are implied by the new one
+ Iterator i = perms.iterator();
+ while (i.hasNext())
+ if (permission.implies((DmtPrincipalPermission) i.next()))
+ i.remove();
+
+ // no need to synchronize because all adds are done sequentially
+ // before any implies() calls
+ perms.add(permission);
+
+ }
+ }
+
+ /**
+ * Check whether this set of permissions implies the permission specified in
+ * the parameter.
+ *
+ * @param permission the Permission object to compare
+ * @return true if the parameter permission is a proper subset of the
+ * permissions in the collection, false otherwise
+ */
+ public boolean implies(Permission permission) {
+ if (!(permission instanceof DmtPrincipalPermission))
+ return false;
+
+ DmtPrincipalPermission other = (DmtPrincipalPermission) permission;
+
+ Iterator i = perms.iterator();
+ while (i.hasNext())
+ if (((DmtPrincipalPermission) i.next()).impliesPrincipal(other))
+ return true;
+
+ return false;
+ }
+
+ /**
+ * Returns an enumeration of all the DmtPrincipalPermission objects in the
+ * container. The returned value cannot be <code>null</code>.
+ *
+ * @return an enumeration of all the DmtPrincipalPermission objects
+ */
+ public Enumeration elements() {
+ // Convert Iterator into Enumeration
+ return Collections.enumeration(perms);
+ }
+}
Added: felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/spi/DataPlugin.java
URL: http://svn.apache.org/viewvc/felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/spi/DataPlugin.java?rev=681945&view=auto
==============================================================================
--- felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/spi/DataPlugin.java (added)
+++ felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/spi/DataPlugin.java Sat Aug 2 02:56:01 2008
@@ -0,0 +1,137 @@
+/*
+ * $Header: /cvshome/build/info.dmtree/src/info/dmtree/spi/DataPlugin.java,v 1.4 2006/06/16 16:31:59 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2004, 2006). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package info.dmtree.spi;
+
+import info.dmtree.DmtException;
+import info.dmtree.DmtSession;
+
+/**
+ * An implementation of this interface takes the responsibility of handling data
+ * requests in a subtree of the DMT.
+ * <p>
+ * In an OSGi environment such implementations should be registered at the OSGi
+ * service registry specifying the list of root node URIs in a
+ * <code>String</code> array in the <code>dataRootURIs</code> registration
+ * parameter.
+ * <p>
+ * When the first reference in a session is made to a node handled by this
+ * plugin, the DmtAdmin calls one of the <code>open...</code> methods to
+ * retrieve a plugin session object for processing the request. The called
+ * method depends on the lock type of the current session. In case of
+ * {@link #openReadWriteSession(String[], DmtSession)} and
+ * {@link #openAtomicSession(String[], DmtSession)}, the plugin may return
+ * <code>null</code> to indicate that the specified lock type is not
+ * supported. In this case the DmtAdmin may call
+ * {@link #openReadOnlySession(String[], DmtSession)} to start a read-only
+ * plugin session, which can be used as long as there are no write operations on
+ * the nodes handled by this plugin.
+ * <p>
+ * The <code>sessionRoot</code> parameter of each method is a String array
+ * containing the segments of the URI pointing to the root of the session. This
+ * is an absolute path, so the first segment is always ".". Special
+ * characters appear escaped in the segments.
+ * <p>
+ */
+public interface DataPlugin {
+
+ /**
+ * This method is called to signal the start of a read-only session when the
+ * first reference is made within a <code>DmtSession</code> to a node
+ * which is handled by this plugin. Session information is given as it is
+ * needed for sending alerts back from the plugin.
+ * <p>
+ * The plugin can assume that there are no writing sessions open on any
+ * subtree that has any overlap with the subtree of this session.
+ *
+ * @param sessionRoot the path to the subtree which is accessed in the
+ * current session, must not be <code>null</code>
+ * @param session the session from which this plugin instance is accessed,
+ * must not be <code>null</code>
+ * @return a plugin session capable of executing read operations
+ * @throws DmtException with the following possible error codes:
+ * <ul>
+ * <li><code>NODE_NOT_FOUND</code> if <code>sessionRoot</code>
+ * points to a non-existing node
+ * <li><code>COMMAND_FAILED</code> if some unspecified error is
+ * encountered while attempting to complete the command
+ * </ul>
+ * @throws SecurityException if some underlying operation failed because of
+ * lack of permissions
+ */
+ ReadableDataSession openReadOnlySession(String[] sessionRoot,
+ DmtSession session) throws DmtException;
+
+ /**
+ * This method is called to signal the start of a non-atomic read-write
+ * session when the first reference is made within a <code>DmtSession</code>
+ * to a node which is handled by this plugin. Session information is given
+ * as it is needed for sending alerts back from the plugin.
+ * <p>
+ * The plugin can assume that there are no other sessions open on any
+ * subtree that has any overlap with the subtree of this session.
+ *
+ * @param sessionRoot the path to the subtree which is locked in the current
+ * session, must not be <code>null</code>
+ * @param session the session from which this plugin instance is accessed,
+ * must not be <code>null</code>
+ * @return a plugin session capable of executing read-write operations, or
+ * <code>null</code> if the plugin does not support non-atomic
+ * read-write sessions
+ * @throws DmtException with the following possible error codes:
+ * <ul>
+ * <li><code>NODE_NOT_FOUND</code> if <code>sessionRoot</code>
+ * points to a non-existing node
+ * <li><code>COMMAND_FAILED</code> if some unspecified error is
+ * encountered while attempting to complete the command
+ * </ul>
+ * @throws SecurityException if some underlying operation failed because of
+ * lack of permissions
+ */
+ ReadWriteDataSession openReadWriteSession(String[] sessionRoot,
+ DmtSession session) throws DmtException;
+
+ /**
+ * This method is called to signal the start of an atomic read-write session
+ * when the first reference is made within a <code>DmtSession</code> to a
+ * node which is handled by this plugin. Session information is given as it
+ * is needed for sending alerts back from the plugin.
+ * <p>
+ * The plugin can assume that there are no other sessions open on any
+ * subtree that has any overlap with the subtree of this session.
+ *
+ * @param sessionRoot the path to the subtree which is locked in the current
+ * session, must not be <code>null</code>
+ * @param session the session from which this plugin instance is accessed,
+ * must not be <code>null</code>
+ * @return a plugin session capable of executing read-write operations in an
+ * atomic block, or <code>null</code> if the plugin does not
+ * support atomic read-write sessions
+ * @throws DmtException with the following possible error codes:
+ * <ul>
+ * <li><code>NODE_NOT_FOUND</code> if <code>sessionRoot</code>
+ * points to a non-existing node
+ * <li><code>COMMAND_FAILED</code> if some unspecified error is
+ * encountered while attempting to complete the command
+ * </ul>
+ * @throws SecurityException if some underlying operation failed because of
+ * lack of permissions
+ */
+ TransactionalDataSession openAtomicSession(String[] sessionRoot,
+ DmtSession session) throws DmtException;
+}
Added: felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/spi/ExecPlugin.java
URL: http://svn.apache.org/viewvc/felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/spi/ExecPlugin.java?rev=681945&view=auto
==============================================================================
--- felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/spi/ExecPlugin.java (added)
+++ felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/spi/ExecPlugin.java Sat Aug 2 02:56:01 2008
@@ -0,0 +1,74 @@
+/*
+ * $Header: /cvshome/build/info.dmtree/src/info/dmtree/spi/ExecPlugin.java,v 1.3 2006/06/16 16:31:59 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2004, 2006). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package info.dmtree.spi;
+
+import info.dmtree.DmtException;
+import info.dmtree.DmtSession;
+
+/**
+ * An implementation of this interface takes the responsibility of handling node
+ * execute requests requests in a subtree of the DMT.
+ * <p>
+ * In an OSGi environment such implementations should be registered at the OSGi
+ * service registry specifying the list of root node URIs in a
+ * <code>String</code> array in the <code>execRootURIs</code> registration
+ * parameter.
+ */
+public interface ExecPlugin {
+
+ /**
+ * Execute the given node with the given data. This operation corresponds to
+ * the EXEC command in OMA DM.
+ * <p>
+ * The semantics of an execute operation and the data parameter it takes
+ * depends on the definition of the managed object on which the command is
+ * issued. Session information is given as it is needed for sending alerts
+ * back from the plugin. If a correlation ID is specified, it should be used
+ * as the <code>correlator</code> parameter for alerts sent in response to
+ * this execute operation.
+ * <p>
+ * The <code>nodePath</code> parameter contains an array of path segments
+ * identifying the node to be executed in the subtree of this plugin. This
+ * is an absolute path, so the first segment is always ".".
+ * Special characters appear escaped in the segments.
+ *
+ * @param session a reference to the session in which the operation was
+ * issued, must not be <code>null</code>
+ * @param nodePath the absolute path of the node to be executed, must not be
+ * <code>null</code>
+ * @param correlator an identifier to associate this operation with any
+ * alerts sent in response to it, can be <code>null</code>
+ * @param data the parameter of the execute operation, can be
+ * <code>null</code>
+ * @throws DmtException with the following possible error codes:
+ * <ul>
+ * <li><code>NODE_NOT_FOUND</code> if the node does not exist and
+ * the plugin does not allow executing unexisting nodes
+ * <li><code>METADATA_MISMATCH</code> if the command failed
+ * because of meta-data restrictions
+ * <li><code>DATA_STORE_FAILURE</code> if an error occurred while
+ * accessing the data store
+ * <li><code>COMMAND_FAILED</code> if some unspecified error is
+ * encountered while attempting to complete the command
+ * </ul>
+ * @see DmtSession#execute(String, String)
+ * @see DmtSession#execute(String, String, String)
+ */
+ void execute(DmtSession session, String[] nodePath, String correlator,
+ String data) throws DmtException;
+}
Added: felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/spi/ReadWriteDataSession.java
URL: http://svn.apache.org/viewvc/felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/spi/ReadWriteDataSession.java?rev=681945&view=auto
==============================================================================
--- felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/spi/ReadWriteDataSession.java (added)
+++ felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/spi/ReadWriteDataSession.java Sat Aug 2 02:56:01 2008
@@ -0,0 +1,297 @@
+/*
+ * $Header: /cvshome/build/info.dmtree/src/info/dmtree/spi/ReadWriteDataSession.java,v 1.4 2006/07/12 21:21:52 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2004, 2006). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package info.dmtree.spi;
+
+import info.dmtree.*;
+
+/**
+ * Provides non-atomic read-write access to the part of the tree handled by the
+ * plugin that created this session.
+ * <p>
+ * The <code>nodePath</code> parameters appearing in this interface always
+ * contain an array of path segments identifying a node in the subtree of this
+ * plugin. This parameter contains an absolute path, so the first segment is
+ * always ".". Special characters appear escaped in the segments.
+ * <p>
+ * <strong>Error handling</strong>
+ * <p>
+ * When a tree manipulation command is called on the DmtAdmin service, it must
+ * perform an extensive set of checks on the parameters and the authority of the
+ * caller before delegating the call to a plugin. Therefore plugins can take
+ * certain circumstances for granted: that the path is valid and is within the
+ * subtree of the plugin and the session, the command can be applied to the
+ * given node (e.g. the target of <code>setNodeValue</code> is a leaf node),
+ * etc. All errors described by the error codes {@link DmtException#INVALID_URI},
+ * {@link DmtException#URI_TOO_LONG}, {@link DmtException#PERMISSION_DENIED},
+ * {@link DmtException#COMMAND_NOT_ALLOWED} and
+ * {@link DmtException#TRANSACTION_ERROR} are fully filtered out before control
+ * reaches the plugin.
+ * <p>
+ * If the plugin provides meta-data for a node, the DmtAdmin service must also
+ * check the constraints specified by it, as described in {@link MetaNode}. If
+ * the plugin does not provide meta-data, it must perform the necessary checks
+ * for itself and use the {@link DmtException#METADATA_MISMATCH} error code to
+ * indicate such discrepancies.
+ * <p>
+ * The DmtAdmin also ensures that the targeted nodes exist before calling the
+ * plugin (or that they do not exist, in case of node creation). However, some
+ * small amount of time elapses between the check and the call, so in case of
+ * plugins where the node structure can change independantly from the DMT, the
+ * target node might appear/disappear in that time. For example, a whole subtree
+ * can disappear when a Monitorable application is unregistered, which might
+ * happen in the middle of a DMT session accessing it. Plugins managing such
+ * nodes always need to check the existance or non-existance of nodes and throw
+ * {@link DmtException#NODE_NOT_FOUND} or
+ * {@link DmtException#NODE_ALREADY_EXISTS} as necessary, but for more static
+ * subtrees there is no need for the plugin to use these error codes.
+ * <p>
+ * The plugin can use the remaining error codes as needed. If an error does not
+ * fit into any other category, the {@link DmtException#COMMAND_FAILED} code
+ * should be used.
+ */
+public interface ReadWriteDataSession extends ReadableDataSession {
+
+ /**
+ * Create a copy of a node or a whole subtree. Beside the structure and
+ * values of the nodes, most properties managed by the plugin must also be
+ * copied, with the exception of the Timestamp and Version properties.
+ *
+ * @param nodePath an absolute path specifying the node or the root of a
+ * subtree to be copied
+ * @param newNodePath the absolute path of the new node or root of a subtree
+ * @param recursive <code>false</code> if only a single node is copied,
+ * <code>true</code> if the whole subtree is copied
+ * @throws DmtException with the following possible error codes:
+ * <ul>
+ * <li><code>NODE_NOT_FOUND</code> if <code>nodePath</code>
+ * points to a non-existing node, or if <code>newNodePath</code>
+ * points to a node that cannot exist in the tree
+ * <li><code>NODE_ALREADY_EXISTS</code> if
+ * <code>newNodePath</code> points to a node that already exists
+ * <li><code>METADATA_MISMATCH</code> if the node could not be
+ * copied because of meta-data restrictions
+ * <li><code>FEATURE_NOT_SUPPORTED</code> if the copy operation
+ * is not supported by the plugin
+ * <li><code>DATA_STORE_FAILURE</code> if an error occurred while
+ * accessing the data store
+ * <li><code>COMMAND_FAILED</code> if some unspecified error is
+ * encountered while attempting to complete the command
+ * </ul>
+ * @throws SecurityException if the caller does not have the necessary
+ * permissions to execute the underlying management operation
+ * @see DmtSession#copy(String, String, boolean)
+ */
+ void copy(String[] nodePath, String[] newNodePath, boolean recursive)
+ throws DmtException;
+
+ /**
+ * Create an interior node with a given type. The type of interior node, if
+ * specified, is a URI identifying a DDF document.
+ *
+ * @param nodePath the absolute path of the node to create
+ * @param type the type URI of the interior node, can be <code>null</code>
+ * if no node type is defined
+ * @throws DmtException with the following possible error codes:
+ * <ul>
+ * <li><code>NODE_NOT_FOUND</code> if <code>nodePath</code>
+ * points to a node that cannot exist in the tree
+ * <li><code>NODE_ALREADY_EXISTS</code> if <code>nodeUri</code>
+ * points to a node that already exists
+ * <li><code>METADATA_MISMATCH</code> if the node could not be
+ * created because of meta-data restrictions
+ * <li><code>DATA_STORE_FAILURE</code> if an error occurred while
+ * accessing the data store
+ * <li><code>COMMAND_FAILED</code> if some unspecified error is
+ * encountered while attempting to complete the command
+ * </ul>
+ * @throws SecurityException if the caller does not have the necessary
+ * permissions to execute the underlying management operation
+ * @see DmtSession#createInteriorNode(String)
+ * @see DmtSession#createInteriorNode(String, String)
+ */
+ void createInteriorNode(String[] nodePath, String type) throws DmtException;
+
+ /**
+ * Create a leaf node with a given value and MIME type. If the specified
+ * value or MIME type is <code>null</code>, their default values must be
+ * taken.
+ *
+ * @param nodePath the absolute path of the node to create
+ * @param value the value to be given to the new node, can be
+ * <code>null</code>
+ * @param mimeType the MIME type to be given to the new node, can be
+ * <code>null</code>
+ * @throws DmtException with the following possible error codes:
+ * <ul>
+ * <li><code>NODE_NOT_FOUND</code> if <code>nodePath</code>
+ * points to a node that cannot exist in the tree
+ * <li><code>NODE_ALREADY_EXISTS</code> if <code>nodePath</code>
+ * points to a node that already exists
+ * <li><code>METADATA_MISMATCH</code> if the node could not be
+ * created because of meta-data restrictions
+ * <li><code>DATA_STORE_FAILURE</code> if an error occurred while
+ * accessing the data store
+ * <li><code>COMMAND_FAILED</code> if some unspecified error is
+ * encountered while attempting to complete the command
+ * </ul>
+ * @throws SecurityException if the caller does not have the necessary
+ * permissions to execute the underlying management operation
+ * @see DmtSession#createLeafNode(String)
+ * @see DmtSession#createLeafNode(String, DmtData)
+ * @see DmtSession#createLeafNode(String, DmtData, String)
+ */
+ void createLeafNode(String[] nodePath, DmtData value, String mimeType)
+ throws DmtException;
+
+ /**
+ * Delete the given node. Deleting interior nodes is recursive, the whole
+ * subtree under the given node is deleted.
+ *
+ * @param nodePath the absolute path of the node to delete
+ * @throws DmtException with the following possible error codes:
+ * <ul>
+ * <li><code>NODE_NOT_FOUND</code> if <code>nodePath</code>
+ * points to a non-existing node
+ * <li><code>METADATA_MISMATCH</code> if the node could not be
+ * deleted because of meta-data restrictions
+ * <li><code>DATA_STORE_FAILURE</code> if an error occurred while
+ * accessing the data store
+ * <li><code>COMMAND_FAILED</code> if some unspecified error is
+ * encountered while attempting to complete the command
+ * </ul>
+ * @throws SecurityException if the caller does not have the necessary
+ * permissions to execute the underlying management operation
+ * @see DmtSession#deleteNode(String)
+ */
+ void deleteNode(String[] nodePath) throws DmtException;
+
+ /**
+ * Rename a node. This operation only changes the name of the node (updating
+ * the timestamp and version properties if they are supported), the value
+ * and the other properties are not changed. The new name of the node must
+ * be provided, the new path is constructed from the base of the old path
+ * and the given name.
+ *
+ * @param nodePath the absolute path of the node to rename
+ * @param newName the new name property of the node
+ * @throws DmtException with the following possible error codes:
+ * <ul>
+ * <li><code>NODE_NOT_FOUND</code> if <code>nodePath</code>
+ * points to a non-existing node, or if the new node is not defined
+ * in the tree
+ * <li><code>NODE_ALREADY_EXISTS</code> if there already exists a
+ * sibling of <code>nodePath</code> with the name
+ * <code>newName</code>
+ * <li><code>METADATA_MISMATCH</code> if the node could not be
+ * renamed because of meta-data restrictions
+ * <li><code>DATA_STORE_FAILURE</code> if an error occurred while
+ * accessing the data store
+ * <li><code>COMMAND_FAILED</code> if some unspecified error is
+ * encountered while attempting to complete the command
+ * </ul>
+ * @throws SecurityException if the caller does not have the necessary
+ * permissions to execute the underlying management operation
+ * @see DmtSession#renameNode(String, String)
+ */
+ void renameNode(String[] nodePath, String newName) throws DmtException;
+
+ /**
+ * Set the title property of a node. The length of the title is guaranteed
+ * not to exceed the limit of 255 bytes in UTF-8 encoding.
+ *
+ * @param nodePath the absolute path of the node
+ * @param title the title text of the node, can be <code>null</code>
+ * @throws DmtException with the following possible error codes:
+ * <ul>
+ * <li><code>NODE_NOT_FOUND</code> if <code>nodePath</code>
+ * points to a non-existing node
+ * <li><code>METADATA_MISMATCH</code> if the title could not be
+ * set because of meta-data restrictions
+ * <li><code>FEATURE_NOT_SUPPORTED</code> if the Title property
+ * is not supported by the plugin
+ * <li><code>DATA_STORE_FAILURE</code> if an error occurred while
+ * accessing the data store
+ * <li><code>COMMAND_FAILED</code> if some unspecified error is
+ * encountered while attempting to complete the command
+ * </ul>
+ * @throws SecurityException if the caller does not have the necessary
+ * permissions to execute the underlying management operation
+ * @see DmtSession#setNodeTitle(String, String)
+ */
+ void setNodeTitle(String[] nodePath, String title) throws DmtException;
+
+ /**
+ * Set the type of a node. The type of leaf node is the MIME type of the
+ * data it contains. The type of an interior node is a URI identifying a DDF
+ * document.
+ * <p>
+ * For interior nodes, the <code>null</code> type should remove the
+ * reference (if any) to a DDF document overriding the tree structure
+ * defined by the ancestors. For leaf nodes, it requests that the default
+ * MIME type is used for the given node.
+ *
+ * @param nodePath the absolute path of the node
+ * @param type the type of the node, can be <code>null</code>
+ * @throws DmtException with the following possible error codes:
+ * <ul>
+ * <li><code>NODE_NOT_FOUND</code> if <code>nodePath</code>
+ * points to a non-existing node
+ * <li><code>METADATA_MISMATCH</code> if the type could not be
+ * set because of meta-data restrictions
+ * <li><code>DATA_STORE_FAILURE</code> if an error occurred while
+ * accessing the data store
+ * <li><code>COMMAND_FAILED</code> if some unspecified error is
+ * encountered while attempting to complete the command
+ * </ul>
+ * @throws SecurityException if the caller does not have the necessary
+ * permissions to execute the underlying management operation
+ * @see DmtSession#setNodeType(String, String)
+ */
+ void setNodeType(String[] nodePath, String type) throws DmtException;
+
+ /**
+ * Set the value of a leaf or interior node. The format of the node is
+ * contained in the <code>DmtData</code> object. For interior nodes, the
+ * format is <code>FORMAT_NODE</code>, while for leaf nodes this format is
+ * never used.
+ * <p>
+ * If the specified value is <code>null</code>, the default value must be
+ * taken; if there is no default value, a <code>DmtException</code> with
+ * error code <code>METADATA_MISMATCH</code> must be thrown.
+ *
+ * @param nodePath the absolute path of the node
+ * @param data the data to be set, can be <code>null</code>
+ * @throws DmtException with the following possible error codes:
+ * <ul>
+ * <li><code>NODE_NOT_FOUND</code> if <code>nodePath</code>
+ * points to a non-existing node
+ * <li><code>METADATA_MISMATCH</code> if the value could not be
+ * set because of meta-data restrictions
+ * <li><code>FEATURE_NOT_SUPPORTED</code> if the specified node is
+ * an interior node and does not support Java object values
+ * <li><code>DATA_STORE_FAILURE</code> if an error occurred while
+ * accessing the data store
+ * <li><code>COMMAND_FAILED</code> if some unspecified error is
+ * encountered while attempting to complete the command
+ * </ul>
+ * @throws SecurityException if the caller does not have the necessary
+ * permissions to execute the underlying management operation
+ * @see DmtSession#setNodeValue(String, DmtData)
+ */
+ void setNodeValue(String[] nodePath, DmtData data) throws DmtException;
+}
Added: felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/spi/ReadableDataSession.java
URL: http://svn.apache.org/viewvc/felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/spi/ReadableDataSession.java?rev=681945&view=auto
==============================================================================
--- felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/spi/ReadableDataSession.java (added)
+++ felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/spi/ReadableDataSession.java Sat Aug 2 02:56:01 2008
@@ -0,0 +1,360 @@
+/*
+ * $Header: /cvshome/build/info.dmtree/src/info/dmtree/spi/ReadableDataSession.java,v 1.4 2006/07/12 21:21:52 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2004, 2006). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package info.dmtree.spi;
+
+import info.dmtree.*;
+
+import java.util.Date;
+
+/**
+ * Provides read-only access to the part of the tree handled by the plugin that
+ * created this session.
+ * <p>
+ * Since the {@link ReadWriteDataSession} and {@link TransactionalDataSession}
+ * interfaces inherit from this interface, some of the method descriptions do
+ * not apply for an instance that is only a <code>ReadableDataSession</code>.
+ * For example, the {@link #close} method description also contains information
+ * about its behaviour when invoked as part of a transactional session.
+ * <p>
+ * The <code>nodePath</code> parameters appearing in this interface always
+ * contain an array of path segments identifying a node in the subtree of this
+ * plugin. This parameter contains an absolute path, so the first segment is
+ * always ".". Special characters appear escaped in the segments.
+ * <p>
+ * <strong>Error handling</strong>
+ * <p>
+ * When a tree access command is called on the DmtAdmin service, it must
+ * perform an extensive set of checks on the parameters and the authority of the
+ * caller before delegating the call to a plugin. Therefore plugins can take
+ * certain circumstances for granted: that the path is valid and is within the
+ * subtree of the plugin and the session, the command can be applied to the
+ * given node (e.g. the target of <code>getChildNodeNames</code> is an
+ * interior node), etc. All errors described by the error codes
+ * {@link DmtException#INVALID_URI}, {@link DmtException#URI_TOO_LONG},
+ * {@link DmtException#PERMISSION_DENIED},
+ * {@link DmtException#COMMAND_NOT_ALLOWED} and
+ * {@link DmtException#TRANSACTION_ERROR} are fully filtered out before control
+ * reaches the plugin.
+ * <p>
+ * If the plugin provides meta-data for a node, the DmtAdmin service must also
+ * check the constraints specified by it, as described in {@link MetaNode}. If
+ * the plugin does not provide meta-data, it must perform the necessary checks
+ * for itself and use the {@link DmtException#METADATA_MISMATCH} error code to
+ * indicate such discrepancies.
+ * <p>
+ * The DmtAdmin also ensures that the targeted nodes exist before calling the
+ * plugin (except, of course, before the <code>isNodeUri</code> call).
+ * However, some small amount of time elapses between the check and the call, so
+ * in case of plugins where the node structure can change independantly from the
+ * DMT, the target node might disappear in that time. For example, a whole
+ * subtree can disappear when a Monitorable application is unregistered, which
+ * might happen in the middle of a DMT session accessing it. Plugins managing
+ * such nodes always need to check whether they still exist and throw
+ * {@link DmtException#NODE_NOT_FOUND} as necessary, but for more static
+ * subtrees there is no need for the plugin to use this error code.
+ * <p>
+ * The plugin can use the remaining error codes as needed. If an error does not
+ * fit into any other category, the {@link DmtException#COMMAND_FAILED} code
+ * should be used.
+ */
+public interface ReadableDataSession {
+ /**
+ * Notifies the plugin that the given node has changed outside the scope of
+ * the plugin, therefore the Version and Timestamp properties must be
+ * updated (if supported). This method is needed because the ACL property of
+ * a node is managed by the DmtAdmin instead of the plugin. The DmtAdmin
+ * must call this method whenever the ACL property of a node changes.
+ *
+ * @param nodePath the absolute path of the node that has changed
+ * @throws DmtException with the following possible error codes:
+ * <ul>
+ * <li><code>NODE_NOT_FOUND</code> if <code>nodePath</code>
+ * points to a non-existing node
+ * <li><code>DATA_STORE_FAILURE</code> if an error occurred while
+ * accessing the data store
+ * <li><code>COMMAND_FAILED</code> if some unspecified error is
+ * encountered while attempting to complete the command
+ * </ul>
+ */
+ void nodeChanged(String[] nodePath) throws DmtException;
+
+ /**
+ * Closes a session. This method is always called when the session ends for
+ * any reason: if the session is closed, if a fatal error occurs in any
+ * method, or if any error occurs during commit or rollback. In case the
+ * session was invalidated due to an exception during commit or rollback, it
+ * is guaranteed that no methods are called on the plugin until it is
+ * closed. In case the session was invalidated due to a fatal exception in
+ * one of the tree manipulation methods, only the rollback method is called
+ * before this (and only in atomic sessions).
+ * <p>
+ * This method should not perform any data manipulation, only cleanup
+ * operations. In non-atomic read-write sessions the data manipulation
+ * should be done instantly during each tree operation, while in atomic
+ * sessions the <code>DmtAdmin</code> always calls
+ * {@link TransactionalDataSession#commit} automatically before the session
+ * is actually closed.
+ *
+ * @throws DmtException with the error code <code>COMMAND_FAILED</code> if
+ * the plugin failed to close for any reason
+ */
+ void close() throws DmtException;
+
+ /**
+ * Get the list of children names of a node. The returned array contains the
+ * names - not the URIs - of the immediate children nodes of the given node.
+ * The returned child names must be mangled ({@link info.dmtree.Uri#mangle}).
+ * The returned array may contain <code>null</code> entries, but these are
+ * removed by the DmtAdmin before returning it to the client.
+ *
+ * @param nodePath the absolute path of the node
+ * @return the list of child node names as a string array or an empty string
+ * array if the node has no children
+ * @throws DmtException with the following possible error codes:
+ * <ul>
+ * <li><code>NODE_NOT_FOUND</code> if <code>nodePath</code>
+ * points to a non-existing node
+ * <li><code>METADATA_MISMATCH</code> if the information could
+ * not be retrieved because of meta-data restrictions
+ * <li><code>DATA_STORE_FAILURE</code> if an error occurred while
+ * accessing the data store
+ * <li><code>COMMAND_FAILED</code> if some unspecified error is
+ * encountered while attempting to complete the command
+ * </ul>
+ * @throws SecurityException if the caller does not have the necessary
+ * permissions to execute the underlying management operation
+ */
+ String[] getChildNodeNames(String[] nodePath) throws DmtException;
+
+ /**
+ * Get the meta data which describes a given node. Meta data can be only
+ * inspected, it can not be changed.
+ * <p>
+ * Meta data support by plugins is an optional feature. It can be used, for
+ * example, when a data plugin is implemented on top of a data store or
+ * another API that has their own metadata, such as a relational database,
+ * in order to avoid metadata duplication and inconsistency. The meta data
+ * specific to the plugin returned by this method is complemented by meta
+ * data from the DmtAdmin before returning it to the client. If there are
+ * differences in the meta data elements known by the plugin and the
+ * <code>DmtAdmin</code> then the plugin specific elements take
+ * precedence.
+ * <p>
+ * Note, that a node does not have to exist for having meta-data associated
+ * with it. This method may provide meta-data for any node that can possibly
+ * exist in the tree (any node defined by the Management Object provided by
+ * the plugin). For nodes that are not defined, a <code>DmtException</code>
+ * may be thrown with the <code>NODE_NOT_FOUND</code> error code. To allow
+ * easier implementation of plugins that do not provide meta-data, it is
+ * allowed to return <code>null</code> for any node, regardless of whether
+ * it is defined or not.
+ *
+ * @param nodePath the absolute path of the node
+ * @return a MetaNode which describes meta data information, can be
+ * <code>null</code> if there is no meta data available for the
+ * given node
+ * @throws DmtException with the following possible error codes:
+ * <ul>
+ * <li><code>NODE_NOT_FOUND</code> if <code>nodeUri</code>
+ * points to a node that is not defined in the tree (see above)
+ * <li><code>DATA_STORE_FAILURE</code> if an error occurred while
+ * accessing the data store
+ * <li><code>COMMAND_FAILED</code> if some unspecified error is
+ * encountered while attempting to complete the command
+ * </ul>
+ * @throws SecurityException if the caller does not have the necessary
+ * permissions to execute the underlying management operation
+ */
+ MetaNode getMetaNode(String[] nodePath) throws DmtException;
+
+ /**
+ * Get the size of the data in a leaf node. The value to return depends on
+ * the format of the data in the node, see the description of the
+ * {@link DmtData#getSize()} method for the definition of node size for each
+ * format.
+ *
+ * @param nodePath the absolute path of the leaf node
+ * @return the size of the data in the node
+ * @throws DmtException with the following possible error codes:
+ * <ul>
+ * <li><code>NODE_NOT_FOUND</code> if <code>nodePath</code>
+ * points to a non-existing node
+ * <li><code>METADATA_MISMATCH</code> if the information could
+ * not be retrieved because of meta-data restrictions
+ * <li><code>FEATURE_NOT_SUPPORTED</code> if the Size property is
+ * not supported by the plugin
+ * <li><code>DATA_STORE_FAILURE</code> if an error occurred while
+ * accessing the data store
+ * <li><code>COMMAND_FAILED</code> if some unspecified error is
+ * encountered while attempting to complete the command
+ * </ul>
+ * @throws SecurityException if the caller does not have the necessary
+ * permissions to execute the underlying management operation
+ * @see DmtData#getSize
+ */
+ int getNodeSize(String[] nodePath) throws DmtException;
+
+ /**
+ * Get the timestamp when the node was last modified.
+ *
+ * @param nodePath the absolute path of the node
+ * @return the timestamp of the last modification
+ * @throws DmtException with the following possible error codes:
+ * <ul>
+ * <li><code>NODE_NOT_FOUND</code> if <code>nodePath</code>
+ * points to a non-existing node
+ * <li><code>METADATA_MISMATCH</code> if the information could
+ * not be retrieved because of meta-data restrictions
+ * <li><code>FEATURE_NOT_SUPPORTED</code> if the Timestamp
+ * property is not supported by the plugin
+ * <li><code>DATA_STORE_FAILURE</code> if an error occurred while
+ * accessing the data store
+ * <li><code>COMMAND_FAILED</code> if some unspecified error is
+ * encountered while attempting to complete the command
+ * </ul>
+ * @throws SecurityException if the caller does not have the necessary
+ * permissions to execute the underlying management operation
+ */
+ Date getNodeTimestamp(String[] nodePath) throws DmtException;
+
+ /**
+ * Get the title of a node. There might be no title property set for a node.
+ *
+ * @param nodePath the absolute path of the node
+ * @return the title of the node, or <code>null</code> if the node has no
+ * title
+ * @throws DmtException with the following possible error codes:
+ * <ul>
+ * <li><code>NODE_NOT_FOUND</code> if <code>nodePath</code>
+ * points to a non-existing node
+ * <li><code>METADATA_MISMATCH</code> if the information could
+ * not be retrieved because of meta-data restrictions
+ * <li><code>FEATURE_NOT_SUPPORTED</code> if the Title property
+ * is not supported by the plugin
+ * <li><code>DATA_STORE_FAILURE</code> if an error occurred while
+ * accessing the data store
+ * <li><code>COMMAND_FAILED</code> if some unspecified error is
+ * encountered while attempting to complete the command
+ * </ul>
+ * @throws SecurityException if the caller does not have the necessary
+ * permissions to execute the underlying management operation
+ */
+ String getNodeTitle(String[] nodePath) throws DmtException;
+
+ /**
+ * Get the type of a node. The type of leaf node is the MIME type of the
+ * data it contains. The type of an interior node is a URI identifying a DDF
+ * document; a <code>null</code> type means that there is no DDF document
+ * overriding the tree structure defined by the ancestors.
+ *
+ * @param nodePath the absolute path of the node
+ * @return the type of the node, can be <code>null</code>
+ * @throws DmtException with the following possible error codes:
+ * <ul>
+ * <li><code>NODE_NOT_FOUND</code> if <code>nodePath</code>
+ * points to a non-existing node
+ * <li><code>METADATA_MISMATCH</code> if the information could
+ * not be retrieved because of meta-data restrictions
+ * <li><code>DATA_STORE_FAILURE</code> if an error occurred while
+ * accessing the data store
+ * <li><code>COMMAND_FAILED</code> if some unspecified error is
+ * encountered while attempting to complete the command
+ * </ul>
+ * @throws SecurityException if the caller does not have the necessary
+ * permissions to execute the underlying management operation
+ */
+ String getNodeType(String[] nodePath) throws DmtException;
+
+ /**
+ * Check whether the specified path corresponds to a valid node in the DMT.
+ *
+ * @param nodePath the absolute path to check
+ * @return true if the given node exists in the DMT
+ */
+ boolean isNodeUri(String[] nodePath);
+
+ /**
+ * Tells whether a node is a leaf or an interior node of the DMT.
+ *
+ * @param nodePath the absolute path of the node
+ * @return true if the given node is a leaf node
+ * @throws DmtException with the following possible error codes:
+ * <ul>
+ * <li><code>NODE_NOT_FOUND</code> if <code>nodePath</code>
+ * points to a non-existing node
+ * <li><code>METADATA_MISMATCH</code> if the information could
+ * not be retrieved because of meta-data restrictions
+ * <li><code>DATA_STORE_FAILURE</code> if an error occurred while
+ * accessing the data store
+ * <li><code>COMMAND_FAILED</code> if some unspecified error is
+ * encountered while attempting to complete the command
+ * </ul>
+ * @throws SecurityException if the caller does not have the necessary
+ * permissions to execute the underlying management operation
+ */
+ boolean isLeafNode(String[] nodePath) throws DmtException;
+
+ /**
+ * Get the data contained in a leaf or interior node.
+ *
+ * @param nodePath the absolute path of the node to retrieve
+ * @return the data of the leaf node, must not be <code>null</code>
+ * @throws DmtException with the following possible error codes:
+ * <ul>
+ * <li><code>NODE_NOT_FOUND</code> if <code>nodePath</code>
+ * points to a non-existing node
+ * <li><code>METADATA_MISMATCH</code> if the information could
+ * not be retrieved because of meta-data restrictions
+ * <li><code>FEATURE_NOT_SUPPORTED</code> if the specified node is
+ * an interior node and does not support Java object values
+ * <li><code>DATA_STORE_FAILURE</code> if an error occurred while
+ * accessing the data store
+ * <li><code>COMMAND_FAILED</code> if some unspecified error is
+ * encountered while attempting to complete the command
+ * </ul>
+ * @throws SecurityException if the caller does not have the necessary
+ * permissions to execute the underlying management operation
+ */
+ DmtData getNodeValue(String[] nodePath) throws DmtException;
+
+ /**
+ * Get the version of a node. The version can not be set, it is calculated
+ * automatically by the device. It is incremented modulo 0x10000 at every
+ * modification of the value or any other property of the node, for both
+ * leaf and interior nodes. When a node is created the initial value is 0.
+ *
+ * @param nodePath the absolute path of the node
+ * @return the version of the node
+ * @throws DmtException with the following possible error codes:
+ * <ul>
+ * <li><code>NODE_NOT_FOUND</code> if <code>nodePath</code>
+ * points to a non-existing node
+ * <li><code>METADATA_MISMATCH</code> if the information could
+ * not be retrieved because of meta-data restrictions
+ * <li><code>FEATURE_NOT_SUPPORTED</code> if the Version property
+ * is not supported by the plugin
+ * <li><code>DATA_STORE_FAILURE</code> if an error occurred while
+ * accessing the data store
+ * <li><code>COMMAND_FAILED</code> if some unspecified error is
+ * encountered while attempting to complete the command
+ * </ul>
+ * @throws SecurityException if the caller does not have the necessary
+ * permissions to execute the underlying management operation
+ */
+ int getNodeVersion(String[] nodePath) throws DmtException;
+}
Added: felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/spi/TransactionalDataSession.java
URL: http://svn.apache.org/viewvc/felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/spi/TransactionalDataSession.java?rev=681945&view=auto
==============================================================================
--- felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/spi/TransactionalDataSession.java (added)
+++ felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/spi/TransactionalDataSession.java Sat Aug 2 02:56:01 2008
@@ -0,0 +1,77 @@
+/*
+ * $Header: /cvshome/build/info.dmtree/src/info/dmtree/spi/TransactionalDataSession.java,v 1.2 2006/06/16 16:31:59 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2004, 2006). All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package info.dmtree.spi;
+
+import info.dmtree.DmtException;
+
+/**
+ * Provides atomic read-write access to the part of the tree handled by the
+ * plugin that created this session.
+ */
+public interface TransactionalDataSession extends ReadWriteDataSession {
+
+ /**
+ * Commits a series of DMT operations issued in the current atomic session
+ * since the last transaction boundary. Transaction boundaries are the
+ * creation of this object that starts the session, and all subsequent
+ * {@link #commit} and {@link #rollback} calls.
+ * <p>
+ * This method can fail even if all operations were successful. This can
+ * happen due to some multi-node semantic constraints defined by a specific
+ * implementation. For example, node A can be required to always have
+ * children A/B, A/C and A/D. If this condition is broken when
+ * <code>commit()</code> is executed, the method will fail, and throw a
+ * <code>METADATA_MISMATCH</code> exception.
+ * <p>
+ * In many cases the tree is not the only way to manage a given part of the
+ * system. It may happen that while modifying some nodes in an atomic
+ * session, the underlying settings are modified parallelly outside the
+ * scope of the DMT. If this is detected during commit, an exception with
+ * the code <code>CONCURRENT_ACCESS</code> is thrown.
+ *
+ * @throws DmtException with the following possible error codes
+ * <ul>
+ * <li><code>METADATA_MISMATCH</code> if the operation failed
+ * because of meta-data restrictions
+ * <li><code>CONCURRENT_ACCESS</code> if it is detected that some
+ * modification has been made outside the scope of the DMT to the
+ * nodes affected in the session's operations
+ * <li><code>DATA_STORE_FAILURE</code> if an error occurred while
+ * accessing the data store
+ * <li><code>COMMAND_FAILED</code> if some unspecified error is
+ * encountered while attempting to complete the command
+ * </ul>
+ * @throws SecurityException if the caller does not have the necessary
+ * permissions to execute the underlying management operation
+ */
+ void commit() throws DmtException;
+
+ /**
+ * Rolls back a series of DMT operations issued in the current atomic
+ * session since the last transaction boundary. Transaction boundaries are
+ * the creation of this object that starts the session, and all subsequent
+ * {@link #commit} and {@link #rollback} calls.
+ *
+ * @throws DmtException with the error code <code>ROLLBACK_FAILED</code>
+ * in case the rollback did not succeed
+ * @throws SecurityException if the caller does not have the necessary
+ * permissions to execute the underlying management operation
+ */
+ void rollback() throws DmtException;
+}