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/06/02 13:40:01 UTC

svn commit: r662399 [8/9] - in /felix/trunk/deploymentadmin: ./ service/ service/src/ service/src/main/ service/src/main/java/ service/src/main/java/org/ service/src/main/java/org/apache/ service/src/main/java/org/apache/felix/ service/src/main/java/or...

Added: felix/trunk/deploymentadmin/service/src/main/java/org/osgi/service/monitor/StatusVariable.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/service/src/main/java/org/osgi/service/monitor/StatusVariable.java?rev=662399&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/service/src/main/java/org/osgi/service/monitor/StatusVariable.java (added)
+++ felix/trunk/deploymentadmin/service/src/main/java/org/osgi/service/monitor/StatusVariable.java Mon Jun  2 04:39:58 2008
@@ -0,0 +1,433 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.monitor/src/org/osgi/service/monitor/StatusVariable.java,v 1.14 2006/06/16 16:31:25 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 org.osgi.service.monitor;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Date;
+
+/**
+ * A <code>StatusVariable</code> object represents the value of a status
+ * variable taken with a certain collection method at a certain point of time.
+ * The type of the <code>StatusVariable</code> can be <code>int</code>,
+ * <code>float</code>, <code>boolean</code> or <code>String</code>.
+ * <p>
+ * A <code>StatusVariable</code> is identified by an ID string that is unique
+ * within the scope of a <code>Monitorable</code>. The ID must be a non-
+ * <code>null</code>, non-empty string that conforms to the "symbolic-name"
+ * definition in the OSGi core specification. This means that only the
+ * characters [-_.a-zA-Z0-9] may be used. The length of the ID must not exceed
+ * 32 bytes when UTF-8 encoded.
+ */
+public final class StatusVariable {
+    //----- Public constants -----//
+    /**
+     * Constant for identifying <code>int</code> data type.
+     */
+    public static final int    TYPE_INTEGER   = 0;
+
+    /**
+     * Constant for identifying <code>float</code> data type.
+     */
+    public static final int    TYPE_FLOAT = 1;
+
+    /**
+     * Constant for identifying <code>String</code> data type.
+     */
+    public static final int    TYPE_STRING = 2;
+
+    /**
+     * Constant for identifying <code>boolean</code> data type.
+     */
+   public static final int    TYPE_BOOLEAN = 3;
+
+    /**
+     * Constant for identifying 'Cumulative Counter' data collection method. 
+     */
+    public static final int    CM_CC        = 0;
+
+    /**
+     * Constant for identifying 'Discrete Event Registration' data collection
+     * method.
+     */
+    public static final int    CM_DER       = 1;
+
+    /**
+     * Constant for identifying 'Gauge' data collection method. 
+     */
+    public static final int    CM_GAUGE     = 2;
+
+    /**
+     * Constant for identifying 'Status Inspection' data collection method.
+     */
+    public static final int    CM_SI        = 3;
+
+    //----- Package private constants -----//
+
+    static final String SYMBOLIC_NAME_CHARACTERS =
+        "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789" +
+        "-_.";   // a subset of the characters allowed in DMT URIs 
+
+    static final int MAX_ID_LENGTH = 32;
+    
+    //----- Private fields -----//
+    private String  id;
+    private Date    timeStamp;
+    private int     cm;
+    private int     type;
+
+    private int     intData;
+    private float   floatData;
+    private String  stringData;
+    private boolean booleanData;
+
+
+    //----- Constructors -----//
+    /**
+     * Constructor for a <code>StatusVariable</code> of <code>int</code>
+     * type.
+     * 
+     * @param id the identifier of the <code>StatusVariable</code>
+     * @param cm the collection method, one of the <code>CM_</code> constants
+     * @param data the <code>int</code> value of the
+     *        <code>StatusVariable</code>
+     * @throws java.lang.IllegalArgumentException if the given <code>id</code>
+     *         is not a valid <code>StatusVariable</code> name, or if 
+     *         <code>cm</code> is not one of the collection method constants
+     * @throws java.lang.NullPointerException if the <code>id</code>
+     *         parameter is <code>null</code>
+     */
+    public StatusVariable(String id, int cm, int data) {
+        setCommon(id, cm);
+        type = TYPE_INTEGER;
+        intData = data;
+    }
+
+    /**
+     * Constructor for a <code>StatusVariable</code> of <code>float</code>
+     * type.
+     * 
+     * @param id the identifier of the <code>StatusVariable</code>
+     * @param cm the collection method, one of the <code>CM_</code> constants
+     * @param data the <code>float</code> value of the
+     *        <code>StatusVariable</code>
+     * @throws java.lang.IllegalArgumentException if the given <code>id</code>
+     *         is not a valid <code>StatusVariable</code> name, or if
+     *         <code>cm</code> is not one of the collection method constants
+     * @throws java.lang.NullPointerException if the <code>id</code> parameter
+     *         is <code>null</code>
+     */
+    public StatusVariable(String id, int cm, float data) {
+        setCommon(id, cm);
+        type = TYPE_FLOAT;
+        floatData = data;
+    }
+
+    /**
+     * Constructor for a <code>StatusVariable</code> of <code>boolean</code>
+     * type.
+     * 
+     * @param id the identifier of the <code>StatusVariable</code>
+     * @param cm the collection method, one of the <code>CM_</code> constants
+     * @param data the <code>boolean</code> value of the
+     *        <code>StatusVariable</code>
+     * @throws java.lang.IllegalArgumentException if the given <code>id</code>
+     *         is not a valid <code>StatusVariable</code> name, or if 
+     *         <code>cm</code> is not one of the collection method constants
+     * @throws java.lang.NullPointerException if the <code>id</code> parameter
+     *         is <code>null</code>
+     */
+    public StatusVariable(String id, int cm, boolean data) {
+        setCommon(id, cm);
+        type = TYPE_BOOLEAN;
+        booleanData = data;
+    }
+
+    /**
+     * Constructor for a <code>StatusVariable</code> of <code>String</code>
+     * type.
+     * 
+     * @param id the identifier of the <code>StatusVariable</code>
+     * @param cm the collection method, one of the <code>CM_</code> constants
+     * @param data the <code>String</code> value of the
+     *        <code>StatusVariable</code>, can be <code>null</code>
+     * @throws java.lang.IllegalArgumentException if the given <code>id</code>
+     *         is not a valid <code>StatusVariable</code> name, or if 
+     *         <code>cm</code> is not one of the collection method constants
+     * @throws java.lang.NullPointerException if the <code>id</code> parameter
+     *         is <code>null</code>
+     */
+    public StatusVariable(String id, int cm, String data) {
+        setCommon(id, cm);
+        type = TYPE_STRING;
+        stringData = data;
+    }
+
+    
+    // ----- Public methods -----//
+    /**
+     * Returns the ID of this <code>StatusVariable</code>. The ID is unique 
+     * within the scope of a <code>Monitorable</code>.
+     * 
+     * @return the ID of this <code>StatusVariable</code>
+     */
+    public String getID() {
+        return id;
+    }
+
+    /**
+     * Returns information on the data type of this <code>StatusVariable</code>.
+     * 
+     * @return one of the <code>TYPE_</code> constants indicating the type of
+     *         this <code>StatusVariable</code>
+     */
+    public int getType() {
+        return type;
+    }
+
+    /**
+     * Returns the timestamp associated with the <code>StatusVariable</code>.
+     * The timestamp is stored when the <code>StatusVariable</code> instance is
+     * created, generally during the {@link Monitorable#getStatusVariable} 
+     * method call.
+     * 
+     * @return the time when the <code>StatusVariable</code> value was
+     *         queried, cannot be <code>null</code>
+     * 
+     */
+    public Date getTimeStamp() {
+        return timeStamp;
+    }
+
+    /**
+     * Returns the <code>StatusVariable</code> value if its type is
+     * <code>String</code>.
+     * 
+     * @return the <code>StatusVariable</code> value as a <code>String</code>
+     * @throws java.lang.IllegalStateException if the type of the 
+     * <code>StatusVariable</code> is not <code>String</code>
+     */
+    public String getString() throws IllegalStateException {
+        if (type != TYPE_STRING)
+            throw new IllegalStateException(
+                    "This StatusVariable does not contain a String value.");
+        return stringData;
+    }
+
+    /**
+     * Returns the <code>StatusVariable</code> value if its type is
+     * <code>int</code>.
+     * 
+     * @return the <code>StatusVariable</code> value as an <code>int</code>
+     * @throws java.lang.IllegalStateException if the type of this
+     *         <code>StatusVariable</code> is not <code>int</code>
+     */
+    public int getInteger() throws IllegalStateException {
+        if (type != TYPE_INTEGER)
+            throw new IllegalStateException(
+                    "This StatusVariable does not contain an integer value.");
+        return intData;
+    }
+
+    /**
+     * Returns the <code>StatusVariable</code> value if its type is
+     * <code>float</code>.
+     * 
+     * @return the <code>StatusVariable</code> value as a <code>float</code>
+     * @throws java.lang.IllegalStateException if the type of this
+     *         <code>StatusVariable</code> is not <code>float</code>
+     */
+    public float getFloat() throws IllegalStateException {
+        if (type != TYPE_FLOAT)
+            throw new IllegalStateException(
+                    "This StatusVariable does not contain a float value.");
+        return floatData;
+    }
+
+    /**
+     * Returns the <code>StatusVariable</code> value if its type is
+     * <code>boolean</code>.
+     * 
+     * @return the <code>StatusVariable</code> value as a <code>boolean</code>
+     * @throws java.lang.IllegalStateException if the type of this
+     *         <code>StatusVariable</code> is not <code>boolean</code>
+     */
+    public boolean getBoolean() throws IllegalStateException {
+        if (type != TYPE_BOOLEAN)
+            throw new IllegalStateException(
+                    "This StatusVariable does not contain a boolean value.");
+        return booleanData;
+    }
+    
+    /**
+     * Returns the collection method of this <code>StatusVariable</code>. See
+     * section 3.3 b) in [ETSI TS 132 403]
+     * 
+     * @return one of the <code>CM_</code> constants
+     */
+    public int getCollectionMethod() {
+        return cm;
+    }
+
+    /**
+     * Compares the specified object with this <code>StatusVariable</code>.
+     * Two <code>StatusVariable</code> objects are considered equal if their
+     * full path, collection method and type are identical, and the data
+     * (selected by their type) is equal.
+     * 
+     * @param obj the object to compare with this <code>StatusVariable</code>
+     * @return <code>true</code> if the argument represents the same
+     *         <code>StatusVariable</code> as this object
+     */
+    public boolean equals(Object obj) {
+        if (!(obj instanceof StatusVariable))
+            return false;
+        
+        StatusVariable other = (StatusVariable) obj;
+        
+        if (!equals(id, other.id) || cm != other.cm || type != other.type)
+            return false;
+        
+        switch (type) {
+        case TYPE_INTEGER: return intData == other.intData;
+        case TYPE_FLOAT:   return floatData == other.floatData;
+        case TYPE_STRING:  return equals(stringData, other.stringData);
+        case TYPE_BOOLEAN: return booleanData == other.booleanData;
+        }
+        
+        return false; // never reached
+    }
+
+    /**
+     * Returns the hash code value for this <code>StatusVariable</code>. The
+     * hash code is calculated based on the full path, collection method and
+     * value of the <code>StatusVariable</code>.
+     * 
+     * @return the hash code of this object
+     */
+    public int hashCode() {
+        int hash = hashCode(id) ^ cm;
+
+        switch (type) {
+        case TYPE_INTEGER: return hash ^ intData;
+        case TYPE_FLOAT:   return hash ^ hashCode(new Float(floatData));
+        case TYPE_BOOLEAN: return hash ^ hashCode(new Boolean(booleanData));
+        case TYPE_STRING:  return hash ^ hashCode(stringData);
+        }
+        
+        return 0; // never reached
+    }
+
+    //  String representation: StatusVariable(path, cm, time, type, value)
+    /**
+     * Returns a <code>String</code> representation of this
+     * <code>StatusVariable</code>. The returned <code>String</code>
+     * contains the full path, collection method, timestamp, type and value 
+     * parameters of the <code>StatusVariable</code> in the following format:
+     * <pre>StatusVariable(&lt;path&gt;, &lt;cm&gt;, &lt;timestamp&gt;, &lt;type&gt;, &lt;value&gt;)</pre>
+     * The collection method identifiers used in the string representation are
+     * "CC", "DER", "GAUGE" and "SI" (without the quotes).  The format of the 
+     * timestamp is defined by the <code>Date.toString</code> method, while the 
+     * type is identified by one of the strings "INTEGER", "FLOAT", "STRING" and
+     * "BOOLEAN".  The final field contains the string representation of the 
+     * value of the status variable.   
+     * 
+     * @return the <code>String</code> representation of this
+     *         <code>StatusVariable</code>
+     */
+    public String toString() {
+        String cmName = null;
+        switch (cm) {
+        case CM_CC:    cmName = "CC";    break;
+        case CM_DER:   cmName = "DER";   break;
+        case CM_GAUGE: cmName = "GAUGE"; break;
+        case CM_SI:    cmName = "SI";    break;
+        }
+        
+        String beg = "StatusVariable(" + id + ", " + cmName + ", "
+                + timeStamp + ", ";
+        
+        switch (type) {
+        case TYPE_INTEGER: return beg + "INTEGER, " + intData + ")";
+        case TYPE_FLOAT:   return beg + "FLOAT, " + floatData + ")";
+        case TYPE_STRING:  return beg + "STRING, " + stringData + ")";
+        case TYPE_BOOLEAN: return beg + "BOOLEAN, " + booleanData + ")";
+        }
+        
+        return null; // never reached
+    }
+
+    //----- Private methods -----//
+    
+    private void setCommon(String id, int cm)
+            throws IllegalArgumentException, NullPointerException {
+        checkId(id, "StatusVariable ID");
+        
+        if (cm != CM_CC && cm != CM_DER && cm != CM_GAUGE && cm != CM_SI)
+            throw new IllegalArgumentException(
+                    "Unknown data collection method constant '" + cm + "'.");
+        
+        this.id = id;
+        this.cm = cm;
+        timeStamp = new Date();
+    }
+
+    
+    private boolean equals(Object o1, Object o2) {
+        return o1 == null ? o2 == null : o1.equals(o2);
+    }
+
+    private int hashCode(Object o) {
+        return o == null ? 0 : o.hashCode();
+    }
+
+    private static void checkId(String id, String idName)
+            throws IllegalArgumentException, NullPointerException {
+        if (id == null)
+            throw new NullPointerException(idName + " is null.");
+        if(id.length() == 0)
+            throw new IllegalArgumentException(idName + " is empty.");
+        
+        byte[] nameBytes;
+        try {
+            nameBytes = id.getBytes("UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            // never happens, "UTF-8" must always be supported
+            throw new IllegalStateException(e.getMessage());
+        }
+        if(nameBytes.length > MAX_ID_LENGTH)
+            throw new IllegalArgumentException(idName + " is too long " + 
+                    "(over " + MAX_ID_LENGTH + " bytes in UTF-8 encoding).");
+
+        if(id.equals(".") || id.equals(".."))
+            throw new IllegalArgumentException(idName + " is invalid.");
+        
+        if(!containsValidChars(id))
+            throw new IllegalArgumentException(idName + 
+                    " contains invalid characters.");
+    }
+    
+    private static boolean containsValidChars(String name) {
+        char[] chars = name.toCharArray();
+        for(int i = 0; i < chars.length; i++)
+            if(SYMBOLIC_NAME_CHARACTERS.indexOf(chars[i]) == -1)
+                return false;
+        
+        return true;        
+    }
+}

Added: felix/trunk/deploymentadmin/service/src/main/java/org/osgi/service/monitor/package.html
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/service/src/main/java/org/osgi/service/monitor/package.html?rev=662399&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/service/src/main/java/org/osgi/service/monitor/package.html (added)
+++ felix/trunk/deploymentadmin/service/src/main/java/org/osgi/service/monitor/package.html Mon Jun  2 04:39:58 2008
@@ -0,0 +1,10 @@
+<!-- $Header: /cvshome/build/org.osgi.service.monitor/src/org/osgi/service/monitor/package.html,v 1.4 2006/07/12 21:07:13 hargrave Exp $ -->
+<BODY>
+<p>Monitor Admin Package Version 1.0.
+<p>Bundles wishing to use this package must list the package
+in the <TT>Import-Package</TT> header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.service.monitor; version=1.0
+</pre>
+</BODY>

Added: felix/trunk/deploymentadmin/service/src/main/java/org/osgi/service/monitor/packageinfo
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/service/src/main/java/org/osgi/service/monitor/packageinfo?rev=662399&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/service/src/main/java/org/osgi/service/monitor/packageinfo (added)
+++ felix/trunk/deploymentadmin/service/src/main/java/org/osgi/service/monitor/packageinfo Mon Jun  2 04:39:58 2008
@@ -0,0 +1 @@
+version 1.0

Added: felix/trunk/deploymentadmin/service/src/main/java/org/osgi/service/prefs/BackingStoreException.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/service/src/main/java/org/osgi/service/prefs/BackingStoreException.java?rev=662399&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/service/src/main/java/org/osgi/service/prefs/BackingStoreException.java (added)
+++ felix/trunk/deploymentadmin/service/src/main/java/org/osgi/service/prefs/BackingStoreException.java Mon Jun  2 04:39:58 2008
@@ -0,0 +1,83 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.prefs/src/org/osgi/service/prefs/BackingStoreException.java,v 1.12 2006/07/11 13:15:55 hargrave Exp $
+ * 
+ * Copyright (c) OSGi Alliance (2001, 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 org.osgi.service.prefs;
+
+/**
+ * Thrown to indicate that a preferences operation could not complete because of
+ * a failure in the backing store, or a failure to contact the backing store.
+ * 
+ * @version $Revision: 1.12 $
+ */
+public class BackingStoreException extends Exception {
+    static final long serialVersionUID = -1415637364122829574L;
+	/**
+	 * Nested exception.
+	 */
+	private final Throwable	cause;
+
+	/**
+	 * Constructs a <code>BackingStoreException</code> with the specified detail
+	 * message.
+	 * 
+	 * @param s The detail message.
+	 */
+	public BackingStoreException(String s) {
+		super(s);
+		this.cause = null;
+	}
+	
+	/**
+	 * Constructs a <code>BackingStoreException</code> with the specified detail
+	 * message.
+	 * 
+	 * @param s The detail message.
+	 * @param cause The cause of the exception. May be <code>null</code>.
+	 * @since 1.1 
+	 */
+	public BackingStoreException(String s, Throwable cause) {
+		super(s);
+		this.cause = cause;
+	}
+	
+	/**
+	 * Returns the cause of this exception or <code>null</code> if no cause was
+	 * specified when this exception was created.
+	 * 
+	 * @return The cause of this exception or <code>null</code> if no cause was
+	 *         specified.
+	 * @since 1.1 
+	 */
+	public Throwable getCause() {
+		return cause;
+	}
+
+	/**
+	 * The cause of this exception can only be set when constructed.
+	 * 
+	 * @param cause Cause of the exception.
+	 * @return This object.
+	 * @throws java.lang.IllegalStateException This method will always throw an
+	 *         <code>IllegalStateException</code> since the cause of this
+	 *         exception can only be set when constructed.
+	 * @since 1.1 
+	 */
+	public Throwable initCause(Throwable cause) {
+		throw new IllegalStateException();
+	}
+
+}

Added: felix/trunk/deploymentadmin/service/src/main/java/org/osgi/service/prefs/Preferences.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/service/src/main/java/org/osgi/service/prefs/Preferences.java?rev=662399&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/service/src/main/java/org/osgi/service/prefs/Preferences.java (added)
+++ felix/trunk/deploymentadmin/service/src/main/java/org/osgi/service/prefs/Preferences.java Mon Jun  2 04:39:58 2008
@@ -0,0 +1,702 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.prefs/src/org/osgi/service/prefs/Preferences.java,v 1.11 2006/07/11 00:54:04 hargrave Exp $
+ * 
+ * Copyright (c) OSGi Alliance (2001, 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 org.osgi.service.prefs;
+
+/**
+ * A node in a hierarchical collection of preference data.
+ * 
+ * <p>
+ * This interface allows applications to store and retrieve user and system
+ * preference data. This data is stored persistently in an
+ * implementation-dependent backing store. Typical implementations include flat
+ * files, OS-specific registries, directory servers and SQL databases.
+ * 
+ * <p>
+ * For each bundle, there is a separate tree of nodes for each user, and one for
+ * system preferences. The precise description of "user" and "system" will vary
+ * from one bundle to another. Typical information stored in the user preference
+ * tree might include font choice, and color choice for a bundle which interacts
+ * with the user via a servlet. Typical information stored in the system
+ * preference tree might include installation data, or things like high score
+ * information for a game program.
+ * 
+ * <p>
+ * Nodes in a preference tree are named in a similar fashion to directories in a
+ * hierarchical file system. Every node in a preference tree has a <i>node name
+ * </i> (which is not necessarily unique), a unique <i>absolute path name </i>,
+ * and a path name <i>relative </i> to each ancestor including itself.
+ * 
+ * <p>
+ * The root node has a node name of the empty <code>String</code> object ("").
+ * Every other node has an arbitrary node name, specified at the time it is
+ * created. The only restrictions on this name are that it cannot be the empty
+ * string, and it cannot contain the slash character ('/').
+ * 
+ * <p>
+ * The root node has an absolute path name of <code>"/"</code>. Children of the
+ * root node have absolute path names of <code>"/" + </code> <i>&lt;node name&gt;
+ * </i>. All other nodes have absolute path names of <i>&lt;parent's absolute
+ * path name&gt; </i> <code> + "/" + </code> <i>&lt;node name&gt; </i>. Note that
+ * all absolute path names begin with the slash character.
+ * 
+ * <p>
+ * A node <i>n </i>'s path name relative to its ancestor <i>a </i> is simply the
+ * string that must be appended to <i>a </i>'s absolute path name in order to
+ * form <i>n </i>'s absolute path name, with the initial slash character (if
+ * present) removed. Note that:
+ * <ul>
+ * <li>No relative path names begin with the slash character.
+ * <li>Every node's path name relative to itself is the empty string.
+ * <li>Every node's path name relative to its parent is its node name (except
+ * for the root node, which does not have a parent).
+ * <li>Every node's path name relative to the root is its absolute path name
+ * with the initial slash character removed.
+ * </ul>
+ * 
+ * <p>
+ * Note finally that:
+ * <ul>
+ * <li>No path name contains multiple consecutive slash characters.
+ * <li>No path name with the exception of the root's absolute path name end in
+ * the slash character.
+ * <li>Any string that conforms to these two rules is a valid path name.
+ * </ul>
+ * 
+ * <p>
+ * Each <code>Preference</code> node has zero or more properties associated with
+ * it, where a property consists of a name and a value. The bundle writer is
+ * free to choose any appropriate names for properties. Their values can be of
+ * type <code>String</code>,<code>long</code>,<code>int</code>,<code>boolean</code>,
+ * <code>byte[]</code>,<code>float</code>, or <code>double</code> but they can
+ * always be accessed as if they were <code>String</code> objects.
+ * 
+ * <p>
+ * All node name and property name comparisons are case-sensitive.
+ * 
+ * <p>
+ * All of the methods that modify preference data are permitted to operate
+ * asynchronously; they may return immediately, and changes will eventually
+ * propagate to the persistent backing store, with an implementation-dependent
+ * delay. The <code>flush</code> method may be used to synchronously force updates
+ * to the backing store.
+ * 
+ * <p>
+ * Implementations must automatically attempt to flush to the backing store any
+ * pending updates for a bundle's preferences when the bundle is stopped or
+ * otherwise ungets the Preferences Service.
+ * 
+ * <p>
+ * The methods in this class may be invoked concurrently by multiple threads in
+ * a single Java Virtual Machine (JVM) without the need for external
+ * synchronization, and the results will be equivalent to some serial execution.
+ * If this class is used concurrently <i>by multiple JVMs </i> that store their
+ * preference data in the same backing store, the data store will not be
+ * corrupted, but no other guarantees are made concerning the consistency of the
+ * preference data.
+ * 
+ * 
+ * @version $Revision: 1.11 $
+ */
+public interface Preferences {
+	/**
+	 * Associates the specified value with the specified key in this node.
+	 * 
+	 * @param key key with which the specified value is to be associated.
+	 * @param value value to be associated with the specified key.
+	 * @throws NullPointerException if <code>key</code> or <code>value</code> is
+	 *         <code>null</code>.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()} method.
+	 */
+	public void put(String key, String value);
+
+	/**
+	 * Returns the value associated with the specified <code>key</code> in this
+	 * node. Returns the specified default if there is no value associated with
+	 * the <code>key</code>, or the backing store is inaccessible.
+	 * 
+	 * @param key key whose associated value is to be returned.
+	 * @param def the value to be returned in the event that this node has no
+	 *        value associated with <code>key</code> or the backing store is
+	 *        inaccessible.
+	 * @return the value associated with <code>key</code>, or <code>def</code> if
+	 *         no value is associated with <code>key</code>.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()} method.
+	 * @throws NullPointerException if <code>key</code> is <code>null</code>. (A
+	 *         <code>null</code> default <i>is </i> permitted.)
+	 */
+	public String get(String key, String def);
+
+	/**
+	 * Removes the value associated with the specified <code>key</code> in this
+	 * node, if any.
+	 * 
+	 * @param key key whose mapping is to be removed from this node.
+	 * @see #get(String,String)
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()} method.
+	 */
+	public void remove(String key);
+
+	/**
+	 * Removes all of the properties (key-value associations) in this node. This
+	 * call has no effect on any descendants of this node.
+	 * 
+	 * @throws BackingStoreException if this operation cannot be completed due
+	 *         to a failure in the backing store, or inability to communicate
+	 *         with it.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()} method.
+	 * @see #remove(String)
+	 */
+	public void clear() throws BackingStoreException;
+
+	/**
+	 * Associates a <code>String</code> object representing the specified
+	 * <code>int</code> value with the specified <code>key</code> in this node. The
+	 * associated string is the one that would be returned if the <code>int</code>
+	 * value were passed to <code>Integer.toString(int)</code>. This method is
+	 * intended for use in conjunction with {@link #getInt} method.
+	 * 
+	 * <p>
+	 * Implementor's note: it is <i>not </i> necessary that the property value
+	 * be represented by a <code>String</code> object in the backing store. If the
+	 * backing store supports integer values, it is not unreasonable to use
+	 * them. This implementation detail is not visible through the
+	 * <code>Preferences</code> API, which allows the value to be read as an
+	 * <code>int</code> (with <code>getInt</code> or a <code>String</code> (with
+	 * <code>get</code>) type.
+	 * 
+	 * @param key key with which the string form of value is to be associated.
+	 * @param value <code>value</code> whose string form is to be associated with
+	 *        <code>key</code>.
+	 * @throws NullPointerException if <code>key</code> is <code>null</code>.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()} method.
+	 * @see #getInt(String,int)
+	 */
+	public void putInt(String key, int value);
+
+	/**
+	 * Returns the <code>int</code> value represented by the <code>String</code>
+	 * object associated with the specified <code>key</code> in this node. The
+	 * <code>String</code> object is converted to an <code>int</code> as by
+	 * <code>Integer.parseInt(String)</code>. Returns the specified default if
+	 * there is no value associated with the <code>key</code>, the backing store
+	 * is inaccessible, or if <code>Integer.parseInt(String)</code> would throw a
+	 * <code>NumberFormatException</code> if the associated <code>value</code> were
+	 * passed. This method is intended for use in conjunction with the
+	 * {@link #putInt} method.
+	 * 
+	 * @param key key whose associated value is to be returned as an
+	 *        <code>int</code>.
+	 * @param def the value to be returned in the event that this node has no
+	 *        value associated with <code>key</code> or the associated value
+	 *        cannot be interpreted as an <code>int</code> or the backing store is
+	 *        inaccessible.
+	 * @return the <code>int</code> value represented by the <code>String</code>
+	 *         object associated with <code>key</code> in this node, or
+	 *         <code>def</code> if the associated value does not exist or cannot
+	 *         be interpreted as an <code>int</code> type.
+	 * @throws NullPointerException if <code>key</code> is <code>null</code>.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()} method.
+	 * @see #putInt(String,int)
+	 * @see #get(String,String)
+	 */
+	public int getInt(String key, int def);
+
+	/**
+	 * Associates a <code>String</code> object representing the specified
+	 * <code>long</code> value with the specified <code>key</code> in this node. The
+	 * associated <code>String</code> object is the one that would be returned if
+	 * the <code>long</code> value were passed to <code>Long.toString(long)</code>.
+	 * This method is intended for use in conjunction with the {@link #getLong}
+	 * method.
+	 * 
+	 * <p>
+	 * Implementor's note: it is <i>not </i> necessary that the <code>value</code>
+	 * be represented by a <code>String</code> type in the backing store. If the
+	 * backing store supports <code>long</code> values, it is not unreasonable to
+	 * use them. This implementation detail is not visible through the <code>
+	 * Preferences</code> API, which allows the value to be read as a
+	 * <code>long</code> (with <code>getLong</code> or a <code>String</code> (with
+	 * <code>get</code>) type.
+	 * 
+	 * @param key <code>key</code> with which the string form of <code>value</code>
+	 *        is to be associated.
+	 * @param value <code>value</code> whose string form is to be associated with
+	 *        <code>key</code>.
+	 * @throws NullPointerException if <code>key</code> is <code>null</code>.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()} method.
+	 * @see #getLong(String,long)
+	 */
+	public void putLong(String key, long value);
+
+	/**
+	 * Returns the <code>long</code> value represented by the <code>String</code>
+	 * object associated with the specified <code>key</code> in this node. The
+	 * <code>String</code> object is converted to a <code>long</code> as by
+	 * <code>Long.parseLong(String)</code>. Returns the specified default if
+	 * there is no value associated with the <code>key</code>, the backing store
+	 * is inaccessible, or if <code>Long.parseLong(String)</code> would throw a
+	 * <code>NumberFormatException</code> if the associated <code>value</code> were
+	 * passed. This method is intended for use in conjunction with the
+	 * {@link #putLong} method.
+	 * 
+	 * @param key <code>key</code> whose associated value is to be returned as a
+	 *        <code>long</code> value.
+	 * @param def the value to be returned in the event that this node has no
+	 *        value associated with <code>key</code> or the associated value
+	 *        cannot be interpreted as a <code>long</code> type or the backing
+	 *        store is inaccessible.
+	 * @return the <code>long</code> value represented by the <code>String</code>
+	 *         object associated with <code>key</code> in this node, or
+	 *         <code>def</code> if the associated value does not exist or cannot
+	 *         be interpreted as a <code>long</code> type.
+	 * @throws NullPointerException if <code>key</code> is <code>null</code>.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()} method.
+	 * @see #putLong(String,long)
+	 * @see #get(String,String)
+	 */
+	public long getLong(String key, long def);
+
+	/**
+	 * Associates a <code>String</code> object representing the specified
+	 * <code>boolean</code> value with the specified key in this node. The
+	 * associated string is "true" if the value is <code>true</code>, and "false"
+	 * if it is <code>false</code>. This method is intended for use in
+	 * conjunction with the {@link #getBoolean} method.
+	 * 
+	 * <p>
+	 * Implementor's note: it is <i>not </i> necessary that the value be
+	 * represented by a string in the backing store. If the backing store
+	 * supports <code>boolean</code> values, it is not unreasonable to use them.
+	 * This implementation detail is not visible through the <code>Preferences
+	 * </code> API, which allows the value to be read as a <code>boolean</code>
+	 * (with <code>getBoolean</code>) or a <code>String</code> (with <code>get</code>)
+	 * type.
+	 * 
+	 * @param key <code>key</code> with which the string form of value is to be
+	 *        associated.
+	 * @param value value whose string form is to be associated with
+	 *        <code>key</code>.
+	 * @throws NullPointerException if <code>key</code> is <code>null</code>.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()} method.
+	 * @see #getBoolean(String,boolean)
+	 * @see #get(String,String)
+	 */
+	public void putBoolean(String key, boolean value);
+
+	/**
+	 * Returns the <code>boolean</code> value represented by the <code>String</code>
+	 * object associated with the specified <code>key</code> in this node. Valid
+	 * strings are "true", which represents <code>true</code>, and "false", which
+	 * represents <code>false</code>. Case is ignored, so, for example, "TRUE"
+	 * and "False" are also valid. This method is intended for use in
+	 * conjunction with the {@link #putBoolean} method.
+	 * 
+	 * <p>
+	 * Returns the specified default if there is no value associated with the
+	 * <code>key</code>, the backing store is inaccessible, or if the associated
+	 * value is something other than "true" or "false", ignoring case.
+	 * 
+	 * @param key <code>key</code> whose associated value is to be returned as a
+	 *        <code>boolean</code>.
+	 * @param def the value to be returned in the event that this node has no
+	 *        value associated with <code>key</code> or the associated value
+	 *        cannot be interpreted as a <code>boolean</code> or the backing store
+	 *        is inaccessible.
+	 * @return the <code>boolean</code> value represented by the <code>String</code>
+	 *         object associated with <code>key</code> in this node, or
+	 *         <code>null</code> if the associated value does not exist or cannot
+	 *         be interpreted as a <code>boolean</code>.
+	 * @throws NullPointerException if <code>key</code> is <code>null</code>.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()} method.
+	 * @see #get(String,String)
+	 * @see #putBoolean(String,boolean)
+	 */
+	public boolean getBoolean(String key, boolean def);
+
+	/**
+	 * Associates a <code>String</code> object representing the specified
+	 * <code>float</code> value with the specified <code>key</code> in this node.
+	 * The associated <code>String</code> object is the one that would be returned
+	 * if the <code>float</code> value were passed to
+	 * <code>Float.toString(float)</code>. This method is intended for use in
+	 * conjunction with the {@link #getFloat} method.
+	 * 
+	 * <p>
+	 * Implementor's note: it is <i>not </i> necessary that the value be
+	 * represented by a string in the backing store. If the backing store
+	 * supports <code>float</code> values, it is not unreasonable to use them.
+	 * This implementation detail is not visible through the <code>Preferences
+	 * </code> API, which allows the value to be read as a <code>float</code> (with
+	 * <code>getFloat</code>) or a <code>String</code> (with <code>get</code>) type.
+	 * 
+	 * @param key <code>key</code> with which the string form of value is to be
+	 *        associated.
+	 * @param value value whose string form is to be associated with
+	 *        <code>key</code>.
+	 * @throws NullPointerException if <code>key</code> is <code>null</code>.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()} method.
+	 * @see #getFloat(String,float)
+	 */
+	public void putFloat(String key, float value);
+
+	/**
+	 * Returns the float <code>value</code> represented by the <code>String</code>
+	 * object associated with the specified <code>key</code> in this node. The
+	 * <code>String</code> object is converted to a <code>float</code> value as by
+	 * <code>Float.parseFloat(String)</code>. Returns the specified default if
+	 * there is no value associated with the <code>key</code>, the backing store
+	 * is inaccessible, or if <code>Float.parseFloat(String)</code> would throw a
+	 * <code>NumberFormatException</code> if the associated value were passed.
+	 * This method is intended for use in conjunction with the {@link #putFloat}
+	 * method.
+	 * 
+	 * @param key <code>key</code> whose associated value is to be returned as a
+	 *        <code>float</code> value.
+	 * @param def the value to be returned in the event that this node has no
+	 *        value associated with <code>key</code> or the associated value
+	 *        cannot be interpreted as a <code>float</code> type or the backing
+	 *        store is inaccessible.
+	 * @return the <code>float</code> value represented by the string associated
+	 *         with <code>key</code> in this node, or <code>def</code> if the
+	 *         associated value does not exist or cannot be interpreted as a
+	 *         <code>float</code> type.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()} method.
+	 * @throws NullPointerException if <code>key</code> is <code>null</code>.
+	 * @see #putFloat(String,float)
+	 * @see #get(String,String)
+	 */
+	public float getFloat(String key, float def);
+
+	/**
+	 * Associates a <code>String</code> object representing the specified
+	 * <code>double</code> value with the specified <code>key</code> in this node.
+	 * The associated <code>String</code> object is the one that would be returned
+	 * if the <code>double</code> value were passed to
+	 * <code>Double.toString(double)</code>. This method is intended for use in
+	 * conjunction with the {@link #getDouble} method
+	 * 
+	 * <p>
+	 * Implementor's note: it is <i>not </i> necessary that the value be
+	 * represented by a string in the backing store. If the backing store
+	 * supports <code>double</code> values, it is not unreasonable to use them.
+	 * This implementation detail is not visible through the <code>Preferences
+	 * </code> API, which allows the value to be read as a <code>double</code> (with
+	 * <code>getDouble</code>) or a <code>String</code> (with <code>get</code>)
+	 * type.
+	 * 
+	 * @param key <code>key</code> with which the string form of value is to be
+	 *        associated.
+	 * @param value value whose string form is to be associated with
+	 *        <code>key</code>.
+	 * @throws NullPointerException if <code>key</code> is <code>null</code>.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()} method.
+	 * @see #getDouble(String,double)
+	 */
+	public void putDouble(String key, double value);
+
+	/**
+	 * Returns the <code>double</code> value represented by the <code>String</code>
+	 * object associated with the specified <code>key</code> in this node. The
+	 * <code>String</code> object is converted to a <code>double</code> value as by
+	 * <code>Double.parseDouble(String)</code>. Returns the specified default if
+	 * there is no value associated with the <code>key</code>, the backing store
+	 * is inaccessible, or if <code>Double.parseDouble(String)</code> would throw
+	 * a <code>NumberFormatException</code> if the associated value were passed.
+	 * This method is intended for use in conjunction with the
+	 * {@link #putDouble} method.
+	 * 
+	 * @param key <code>key</code> whose associated value is to be returned as a
+	 *        <code>double</code> value.
+	 * @param def the value to be returned in the event that this node has no
+	 *        value associated with <code>key</code> or the associated value
+	 *        cannot be interpreted as a <code>double</code> type or the backing
+	 *        store is inaccessible.
+	 * @return the <code>double</code> value represented by the <code>String</code>
+	 *         object associated with <code>key</code> in this node, or
+	 *         <code>def</code> if the associated value does not exist or cannot
+	 *         be interpreted as a <code>double</code> type.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the the {@link #removeNode()} method.
+	 * @throws NullPointerException if <code>key</code> is <code>null</code>.
+	 * @see #putDouble(String,double)
+	 * @see #get(String,String)
+	 */
+	public double getDouble(String key, double def);
+
+	/**
+	 * Associates a <code>String</code> object representing the specified
+	 * <code>byte[]</code> with the specified <code>key</code> in this node. The
+	 * associated <code>String</code> object the <i>Base64 </i> encoding of the
+	 * <code>byte[]</code>, as defined in <a
+	 * href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 </a>, Section 6.8,
+	 * with one minor change: the string will consist solely of characters from
+	 * the <i>Base64 Alphabet </i>; it will not contain any newline characters.
+	 * This method is intended for use in conjunction with the
+	 * {@link #getByteArray} method.
+	 * 
+	 * <p>
+	 * Implementor's note: it is <i>not </i> necessary that the value be
+	 * represented by a <code>String</code> type in the backing store. If the
+	 * backing store supports <code>byte[]</code> values, it is not unreasonable
+	 * to use them. This implementation detail is not visible through the <code>
+	 * Preferences</code> API, which allows the value to be read as an a
+	 * <code>byte[]</code> object (with <code>getByteArray</code>) or a
+	 * <code>String</code> object (with <code>get</code>).
+	 * 
+	 * @param key <code>key</code> with which the string form of <code>value</code>
+	 *        is to be associated.
+	 * @param value <code>value</code> whose string form is to be associated with
+	 *        <code>key</code>.
+	 * @throws NullPointerException if <code>key</code> or <code>value</code> is
+	 *         <code>null</code>.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()} method.
+	 * @see #getByteArray(String,byte[])
+	 * @see #get(String,String)
+	 */
+	public void putByteArray(String key, byte[] value);
+
+	/**
+	 * Returns the <code>byte[]</code> value represented by the <code>String</code>
+	 * object associated with the specified <code>key</code> in this node. Valid
+	 * <code>String</code> objects are <i>Base64 </i> encoded binary data, as
+	 * defined in <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 </a>,
+	 * Section 6.8, with one minor change: the string must consist solely of
+	 * characters from the <i>Base64 Alphabet </i>; no newline characters or
+	 * extraneous characters are permitted. This method is intended for use in
+	 * conjunction with the {@link #putByteArray} method.
+	 * 
+	 * <p>
+	 * Returns the specified default if there is no value associated with the
+	 * <code>key</code>, the backing store is inaccessible, or if the associated
+	 * value is not a valid Base64 encoded byte array (as defined above).
+	 * 
+	 * @param key <code>key</code> whose associated value is to be returned as a
+	 *        <code>byte[]</code> object.
+	 * @param def the value to be returned in the event that this node has no
+	 *        value associated with <code>key</code> or the associated value
+	 *        cannot be interpreted as a <code>byte[]</code> type, or the backing
+	 *        store is inaccessible.
+	 * @return the <code>byte[]</code> value represented by the <code>String</code>
+	 *         object associated with <code>key</code> in this node, or
+	 *         <code>def</code> if the associated value does not exist or cannot
+	 *         be interpreted as a <code>byte[]</code>.
+	 * @throws NullPointerException if <code>key</code> is <code>null</code>. (A
+	 *         <code>null</code> value for <code>def</code> <i>is </i> permitted.)
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()} method.
+	 * @see #get(String,String)
+	 * @see #putByteArray(String,byte[])
+	 */
+	public byte[] getByteArray(String key, byte[] def);
+
+	/**
+	 * Returns all of the keys that have an associated value in this node. (The
+	 * returned array will be of size zero if this node has no preferences and
+	 * not <code>null</code>!)
+	 * 
+	 * @return an array of the keys that have an associated value in this node.
+	 * @throws BackingStoreException if this operation cannot be completed due
+	 *         to a failure in the backing store, or inability to communicate
+	 *         with it.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()} method.
+	 */
+	public String[] keys() throws BackingStoreException;
+
+	/**
+	 * Returns the names of the children of this node. (The returned array will
+	 * be of size zero if this node has no children and not <code>null</code>!)
+	 * 
+	 * @return the names of the children of this node.
+	 * @throws BackingStoreException if this operation cannot be completed due
+	 *         to a failure in the backing store, or inability to communicate
+	 *         with it.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()} method.
+	 */
+	public String[] childrenNames() throws BackingStoreException;
+
+	/**
+	 * Returns the parent of this node, or <code>null</code> if this is the root.
+	 * 
+	 * @return the parent of this node.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()} method.
+	 */
+	public Preferences parent();
+
+	/**
+	 * Returns a named <code>Preferences</code> object (node), creating it and any
+	 * of its ancestors if they do not already exist. Accepts a relative or
+	 * absolute pathname. Absolute pathnames (which begin with <code>'/'</code>)
+	 * are interpreted relative to the root of this node. Relative pathnames
+	 * (which begin with any character other than <code>'/'</code>) are
+	 * interpreted relative to this node itself. The empty string (<code>""</code>)
+	 * is a valid relative pathname, referring to this node itself.
+	 * 
+	 * <p>
+	 * If the returned node did not exist prior to this call, this node and any
+	 * ancestors that were created by this call are not guaranteed to become
+	 * persistent until the <code>flush</code> method is called on the returned
+	 * node (or one of its descendants).
+	 * 
+	 * @param pathName the path name of the <code>Preferences</code> object to
+	 *        return.
+	 * @return the specified <code>Preferences</code> object.
+	 * @throws IllegalArgumentException if the path name is invalid.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()} method.
+	 * @throws NullPointerException if path name is <code>null</code>.
+	 * @see #flush()
+	 */
+	public Preferences node(String pathName);
+
+	/**
+	 * Returns true if the named node exists. Accepts a relative or absolute
+	 * pathname. Absolute pathnames (which begin with <code>'/'</code>) are
+	 * interpreted relative to the root of this node. Relative pathnames (which
+	 * begin with any character other than <code>'/'</code>) are interpreted
+	 * relative to this node itself. The pathname <code>""</code> is valid, and
+	 * refers to this node itself.
+	 * 
+	 * <p>
+	 * If this node (or an ancestor) has already been removed with the
+	 * {@link #removeNode()} method, it <i>is </i> legal to invoke this method,
+	 * but only with the pathname <code>""</code>; the invocation will return
+	 * <code>false</code>. Thus, the idiom <code>p.nodeExists("")</code> may be
+	 * used to test whether <code>p</code> has been removed.
+	 * 
+	 * @param pathName the path name of the node whose existence is to be
+	 *        checked.
+	 * @return true if the specified node exists.
+	 * @throws BackingStoreException if this operation cannot be completed due
+	 *         to a failure in the backing store, or inability to communicate
+	 *         with it.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()} method and
+	 *         <code>pathname</code> is not the empty string (<code>""</code>).
+	 * @throws IllegalArgumentException if the path name is invalid (i.e., it
+	 *         contains multiple consecutive slash characters, or ends with a
+	 *         slash character and is more than one character long).
+	 */
+	public boolean nodeExists(String pathName)
+			throws BackingStoreException;
+
+	/**
+	 * Removes this node and all of its descendants, invalidating any properties
+	 * contained in the removed nodes. Once a node has been removed, attempting
+	 * any method other than <code>name()</code>,<code>absolutePath()</code> or
+	 * <code>nodeExists("")</code> on the corresponding <code>Preferences</code>
+	 * instance will fail with an <code>IllegalStateException</code>. (The
+	 * methods defined on <code>Object</code> can still be invoked on a node after
+	 * it has been removed; they will not throw <code>IllegalStateException</code>.)
+	 * 
+	 * <p>
+	 * The removal is not guaranteed to be persistent until the <code>flush</code>
+	 * method is called on the parent of this node.
+	 * 
+	 * @throws IllegalStateException if this node (or an ancestor) has already
+	 *         been removed with the {@link #removeNode()} method.
+	 * @throws BackingStoreException if this operation cannot be completed due
+	 *         to a failure in the backing store, or inability to communicate
+	 *         with it.
+	 * @see #flush()
+	 */
+	public void removeNode() throws BackingStoreException;
+
+	/**
+	 * Returns this node's name, relative to its parent.
+	 * 
+	 * @return this node's name, relative to its parent.
+	 */
+	public String name();
+
+	/**
+	 * Returns this node's absolute path name. Note that:
+	 * <ul>
+	 * <li>Root node - The path name of the root node is <code>"/"</code>.
+	 * <li>Slash at end - Path names other than that of the root node may not
+	 * end in slash (<code>'/'</code>).
+	 * <li>Unusual names -<code>"."</code> and <code>".."</code> have <i>no </i>
+	 * special significance in path names.
+	 * <li>Illegal names - The only illegal path names are those that contain
+	 * multiple consecutive slashes, or that end in slash and are not the root.
+	 * </ul>
+	 * 
+	 * @return this node's absolute path name.
+	 */
+	public String absolutePath();
+
+	/**
+	 * Forces any changes in the contents of this node and its descendants to
+	 * the persistent store.
+	 * 
+	 * <p>
+	 * Once this method returns successfully, it is safe to assume that all
+	 * changes made in the subtree rooted at this node prior to the method
+	 * invocation have become permanent.
+	 * 
+	 * <p>
+	 * Implementations are free to flush changes into the persistent store at
+	 * any time. They do not need to wait for this method to be called.
+	 * 
+	 * <p>
+	 * When a flush occurs on a newly created node, it is made persistent, as
+	 * are any ancestors (and descendants) that have yet to be made persistent.
+	 * Note however that any properties value changes in ancestors are <i>not
+	 * </i> guaranteed to be made persistent.
+	 * 
+	 * @throws BackingStoreException if this operation cannot be completed due
+	 *         to a failure in the backing store, or inability to communicate
+	 *         with it.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()} method.
+	 * @see #sync()
+	 */
+	public void flush() throws BackingStoreException;
+
+	/**
+	 * Ensures that future reads from this node and its descendants reflect any
+	 * changes that were committed to the persistent store (from any VM) prior
+	 * to the <code>sync</code> invocation. As a side-effect, forces any changes
+	 * in the contents of this node and its descendants to the persistent store,
+	 * as if the <code>flush</code> method had been invoked on this node.
+	 * 
+	 * @throws BackingStoreException if this operation cannot be completed due
+	 *         to a failure in the backing store, or inability to communicate
+	 *         with it.
+	 * @throws IllegalStateException if this node (or an ancestor) has been
+	 *         removed with the {@link #removeNode()} method.
+	 * @see #flush()
+	 */
+	public void sync() throws BackingStoreException;
+}

Added: felix/trunk/deploymentadmin/service/src/main/java/org/osgi/service/prefs/PreferencesService.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/service/src/main/java/org/osgi/service/prefs/PreferencesService.java?rev=662399&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/service/src/main/java/org/osgi/service/prefs/PreferencesService.java (added)
+++ felix/trunk/deploymentadmin/service/src/main/java/org/osgi/service/prefs/PreferencesService.java Mon Jun  2 04:39:58 2008
@@ -0,0 +1,56 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.prefs/src/org/osgi/service/prefs/PreferencesService.java,v 1.10 2006/06/16 16:31:30 hargrave Exp $
+ * 
+ * Copyright (c) OSGi Alliance (2001, 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 org.osgi.service.prefs;
+
+/**
+ * The Preferences Service.
+ * 
+ * <p>
+ * Each bundle using this service has its own set of preference trees: one for
+ * system preferences, and one for each user.
+ * 
+ * <p>
+ * A <code>PreferencesService</code> object is specific to the bundle which
+ * obtained it from the service registry. If a bundle wishes to allow another
+ * bundle to access its preferences, it should pass its
+ * <code>PreferencesService</code> object to that bundle.
+ *  
+ */
+public interface PreferencesService {
+	/**
+	 * Returns the root system node for the calling bundle.
+	 * 
+	 * @return The root system node for the calling bundle.
+	 */
+	public Preferences getSystemPreferences();
+
+	/**
+	 * Returns the root node for the specified user and the calling bundle.
+	 * 
+	 * @param name The user for which to return the preference root node. 
+	 * @return The root node for the specified user and the calling bundle.
+	 */
+	public Preferences getUserPreferences(String name);
+
+	/**
+	 * Returns the names of users for which node trees exist.
+	 * 
+	 * @return The names of users for which node trees exist.
+	 */
+	public String[] getUsers();
+}

Added: felix/trunk/deploymentadmin/service/src/main/java/org/osgi/service/prefs/package.html
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/service/src/main/java/org/osgi/service/prefs/package.html?rev=662399&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/service/src/main/java/org/osgi/service/prefs/package.html (added)
+++ felix/trunk/deploymentadmin/service/src/main/java/org/osgi/service/prefs/package.html Mon Jun  2 04:39:58 2008
@@ -0,0 +1 @@
+<!-- $Header: /cvshome/build/org.osgi.service.prefs/src/org/osgi/service/prefs/package.html,v 1.4 2006/07/12 21:06:58 hargrave Exp $ -->
<BODY>
<p>Preferences Service Package Version 1.1.
<p>Bundles wishing to use this package must list the package
in the Import-Package header of the bundle's manifest.
For example:
<pre>
Import-Package: org.osgi.service.prefs; version=1.1
</pre>
</BODY>
\ No newline at end of file

Added: felix/trunk/deploymentadmin/service/src/main/java/org/osgi/service/prefs/packageinfo
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/service/src/main/java/org/osgi/service/prefs/packageinfo?rev=662399&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/service/src/main/java/org/osgi/service/prefs/packageinfo (added)
+++ felix/trunk/deploymentadmin/service/src/main/java/org/osgi/service/prefs/packageinfo Mon Jun  2 04:39:58 2008
@@ -0,0 +1 @@
+version 1.1

Added: felix/trunk/deploymentadmin/service/src/main/java/org/osgi/util/gsm/IMEICondition.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/service/src/main/java/org/osgi/util/gsm/IMEICondition.java?rev=662399&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/service/src/main/java/org/osgi/util/gsm/IMEICondition.java (added)
+++ felix/trunk/deploymentadmin/service/src/main/java/org/osgi/util/gsm/IMEICondition.java Mon Jun  2 04:39:58 2008
@@ -0,0 +1,85 @@
+/*
+ * $Header: /cvshome/build/org.osgi.util.gsm/src/org/osgi/util/gsm/IMEICondition.java,v 1.20 2006/07/12 21:21:32 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 org.osgi.util.gsm;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+import org.osgi.framework.Bundle;
+import org.osgi.service.condpermadmin.Condition;
+import org.osgi.service.condpermadmin.ConditionInfo;
+
+/**
+ * Class representing an IMEI condition. Instances of this class contain a
+ * string value that is matched against the IMEI of the device.
+ */
+public class IMEICondition {
+	private static final String ORG_OSGI_UTIL_GSM_IMEI = "org.osgi.util.gsm.imei";
+	private static final String imei ;
+		
+	static {
+		imei = (String)
+		AccessController.doPrivileged(
+				new PrivilegedAction() {
+					public Object run() {
+					return System.getProperty(ORG_OSGI_UTIL_GSM_IMEI);
+					}
+				}
+				);
+	}
+	
+	private IMEICondition() {
+	}
+
+	/**
+	 * Creates an IMEICondition object.
+	 * 
+	 * @param bundle ignored, as the IMEI number is the property of the mobile device,
+	 * 					and thus the same for all bundles.
+	 * @param conditionInfo contains the IMEI value to match the device's IMEI against. Its
+	 * 		{@link ConditionInfo#getArgs()} method should return a String array with one value, the
+	 * 		IMEI string. The IMEI is 15 digits without hypens. Limited pattern matching is allowed,
+	 * 		then the string is 0 to 14 digits, followed by an asterisk(<code>*</code>).
+	 * @return An IMEICondition object, that can tell whether its IMEI number matches that of the device.
+	 * 			If the number contains an asterisk(<code>*</code>), then the beginning
+	 * 			of the imei is compared to the pattern.
+	 * @throws NullPointerException if one of the parameters is <code>null</code>.
+	 * @throws IllegalArgumentException if the IMEI is not a string of 15 digits, or 
+	 * 		0 to 14 digits with an <code>*</code> at the end.
+	 */
+	public static Condition getCondition(Bundle bundle, ConditionInfo conditionInfo) {
+		if (bundle==null) throw new NullPointerException("bundle");
+		String imei = conditionInfo.getArgs()[0];
+		if (imei.length()>15) throw new IllegalArgumentException("imei too long: "+imei);
+		if (imei.endsWith("*")) {
+			imei = imei.substring(0,imei.length()-1);
+		} else {
+			if (imei.length()!=15) throw new IllegalArgumentException("not a valid imei: "+imei);
+		}
+		for(int i=0;i<imei.length();i++) {
+			int c = imei.charAt(i);
+			if (c<'0'||c>'9') throw new IllegalArgumentException("not a valid imei: "+imei);
+		}
+		if (IMEICondition.imei==null) {
+			System.err.println("The OSGI Reference Implementation of org.osgi.util.gsm.IMEICondition ");
+			System.err.println("needs the system property "+ORG_OSGI_UTIL_GSM_IMEI+" set.");
+			return Condition.FALSE;
+		}
+		return IMEICondition.imei.startsWith(imei)?Condition.TRUE:Condition.FALSE;
+	}
+}

Added: felix/trunk/deploymentadmin/service/src/main/java/org/osgi/util/gsm/IMSICondition.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/service/src/main/java/org/osgi/util/gsm/IMSICondition.java?rev=662399&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/service/src/main/java/org/osgi/util/gsm/IMSICondition.java (added)
+++ felix/trunk/deploymentadmin/service/src/main/java/org/osgi/util/gsm/IMSICondition.java Mon Jun  2 04:39:58 2008
@@ -0,0 +1,84 @@
+/*
+ * $Header: /cvshome/build/org.osgi.util.gsm/src/org/osgi/util/gsm/IMSICondition.java,v 1.22 2006/07/12 21:21:32 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 org.osgi.util.gsm;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+import org.osgi.framework.Bundle;
+import org.osgi.service.condpermadmin.Condition;
+import org.osgi.service.condpermadmin.ConditionInfo;
+
+/**
+ * Class representing an IMSI condition. Instances of this class contain a
+ * string value that is matched against the IMSI of the subscriber.
+ */
+public class IMSICondition {
+	private static final String ORG_OSGI_UTIL_GSM_IMSI = "org.osgi.util.gsm.imsi";
+	private static final String imsi;
+	
+	static {
+		imsi = (String)
+		AccessController.doPrivileged(
+				new PrivilegedAction() {
+					public Object run() {
+					return System.getProperty(ORG_OSGI_UTIL_GSM_IMSI);
+					}
+				}
+				);
+	}
+
+	private IMSICondition() {}
+
+	/**
+	 * Creates an IMSI condition object.
+	 * 
+	 * @param bundle ignored, as the IMSI number is the same for all bundles.
+	 * @param conditionInfo contains the IMSI value to match the device's IMSI against. Its
+	 * 		{@link ConditionInfo#getArgs()} method should return a String array with one value, the
+	 * 		IMSI string. The IMSI is 15 digits without hypens. Limited pattern matching is allowed,
+	 * 		then the string is 0 to 14 digits, followed by an asterisk(<code>*</code>).
+	 * @return An IMSICondition object, that can tell whether its IMSI number matches that of the device.
+	 * 			If the number contains an asterisk(<code>*</code>), then the beginning
+	 * 			of the IMSI is compared to the pattern.
+	 * @throws NullPointerException if one of the parameters is <code>null</code>.
+	 * @throws IllegalArgumentException if the IMSI is not a string of 15 digits, or 
+	 * 		0 to 14 digits with an <code>*</code> at the end.
+	 */
+	public static Condition getCondition(Bundle bundle, ConditionInfo conditionInfo) {
+		if (bundle==null) throw new NullPointerException("bundle");
+		if (conditionInfo==null) throw new NullPointerException("conditionInfo");
+		String imsi = conditionInfo.getArgs()[0];
+		if (imsi.length()>15) throw new IllegalArgumentException("imsi too long: "+imsi);
+		if (imsi.endsWith("*")) {
+			imsi = imsi.substring(0,imsi.length()-1);
+		} else {
+			if (imsi.length()!=15) throw new IllegalArgumentException("not a valid imei: "+imsi);
+		}
+		for(int i=0;i<imsi.length();i++) {
+			int c = imsi.charAt(i);
+			if (c<'0'||c>'9') throw new IllegalArgumentException("not a valid imei: "+imsi);
+		}
+		if (IMSICondition.imsi==null) {
+			System.err.println("The OSGI Reference Implementation of org.osgi.util.gsm.IMSICondition ");
+			System.err.println("needs the system property "+ORG_OSGI_UTIL_GSM_IMSI+" set.");
+			return Condition.FALSE;
+		}
+		return (IMSICondition.imsi.startsWith(imsi))?Condition.TRUE:Condition.FALSE;
+	}
+}

Added: felix/trunk/deploymentadmin/service/src/main/java/org/osgi/util/gsm/package.html
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/service/src/main/java/org/osgi/util/gsm/package.html?rev=662399&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/service/src/main/java/org/osgi/util/gsm/package.html (added)
+++ felix/trunk/deploymentadmin/service/src/main/java/org/osgi/util/gsm/package.html Mon Jun  2 04:39:58 2008
@@ -0,0 +1,10 @@
+<!-- $Header: /cvshome/build/org.osgi.util.gsm/src/org/osgi/util/gsm/package.html,v 1.2 2006/07/12 21:06:54 hargrave Exp $ -->
+<BODY>
+<p>Mobile GSM Conditions Package Version 1.0.
+<p>Bundles wishing to use this package must list the package
+in the Import-Package header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.util.gsm; version=1.0
+</pre>
+</BODY>

Added: felix/trunk/deploymentadmin/service/src/main/java/org/osgi/util/gsm/packageinfo
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/service/src/main/java/org/osgi/util/gsm/packageinfo?rev=662399&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/service/src/main/java/org/osgi/util/gsm/packageinfo (added)
+++ felix/trunk/deploymentadmin/service/src/main/java/org/osgi/util/gsm/packageinfo Mon Jun  2 04:39:58 2008
@@ -0,0 +1 @@
+version 1.0
\ No newline at end of file

Added: felix/trunk/deploymentadmin/service/src/main/java/org/osgi/util/mobile/UserPromptCondition.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/service/src/main/java/org/osgi/util/mobile/UserPromptCondition.java?rev=662399&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/service/src/main/java/org/osgi/util/mobile/UserPromptCondition.java (added)
+++ felix/trunk/deploymentadmin/service/src/main/java/org/osgi/util/mobile/UserPromptCondition.java Mon Jun  2 04:39:58 2008
@@ -0,0 +1,256 @@
+/*
+ * $Header: /cvshome/build/org.osgi.util.mobile/src/org/osgi/util/mobile/UserPromptCondition.java,v 1.26 2006/07/10 08:18:30 pnagy 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 org.osgi.util.mobile;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Dictionary;
+
+import org.osgi.framework.Bundle;
+import org.osgi.service.condpermadmin.Condition;
+import org.osgi.service.condpermadmin.ConditionInfo;
+
+/**
+ * Class representing a user prompt condition. Instances of this class hold two
+ * values: a prompt string that is to be displayed to the user and the
+ * permission level string according to MIDP2.0 (oneshot, session, blanket).
+ *  
+ */
+public class UserPromptCondition implements Condition {
+	
+	/*
+	 * NOTE: An implementor may also choose to replace this class in
+	 * their distribution with a class that directly interfaces with the
+	 * policy implementation. This replacement class MUST NOT alter the
+	 * public/protected signature of this class.
+	 */
+	// this will need to be set by the implementation class
+	static Method factory = null;
+	Condition realUserPromptCondition;
+
+	private final Bundle bundle;
+	private final String levels;
+	private final String defaultLevel;
+	private final String catalogName;
+	private final String message;
+	
+	/**
+	 * Returns a UserPromptCondition object with the given prompt string and permission
+	 * level. The user should be given choice as to what level of permission is
+	 * given. Thus, the lifetime of the permission is controlled by the user.
+	 *
+	 * @param bundle the bundle to ask about.
+	 * @param conditionInfo the conditionInfo containing the construction information. Its 
+	 * 			{@link ConditionInfo#getArgs()} method should return a String array with 4
+	 * 			strings in it:
+	 * <ol start="0">
+	 * <li>the possible permission levels. This is a comma-separated list that can contain
+	 * 		following strings: ONESHOT SESSION BLANKET. The order is not important. This
+	 * 		parameter is case-insensitive.
+	 * 		</li>
+	 * <li>the default permission level, one chosen from the possible permission levels. If
+	 * 		it is an empty string, then there is no default. This parameter
+	 * 		is case-insensitive.</li>
+	 * <li>the message catalog base name. It will be loaded by a {@link java.util.ResourceBundle},
+	 * 		or equivalent
+	 * 		from an exporting OSGi Bundle. Thus, if the catalogName is "com.provider.messages.userprompt",
+	 * 		then there should be an OSGi Bundle exporting the "com.provider.messages" package, and inside
+	 * 		it files like "userprompt_en_US.properties".</li>
+	 * <li>textual description of the condition, to be displayed to the user. If
+	 * 		it starts with a '%' sign, then the message is looked up from the catalog specified previously.
+	 * 		The key is the rest of the string after the '%' sign.</li>
+	 * </ol>
+	 * @return The requested UserPromptCondition.
+	 * @throws IllegalArgumentException if the parameters are malformed.
+	 * @throws NullPointerException if one of the parameters is <code>null</code>.
+	 */
+	public static Condition getCondition(Bundle bundle,ConditionInfo conditionInfo)
+	{
+		String[] args = conditionInfo.getArgs();
+		if (args==null) throw new NullPointerException("args");
+		if (args.length!=4) throw new IllegalArgumentException("args.length=="+args.length+" (should be 4)");
+		if (bundle==null) throw new NullPointerException("bundle");
+		String levels = args[0];
+		String defaultLevel = args[1];
+		String catalogName = args[2];
+		String message = args[3];
+		if (levels==null) throw new NullPointerException("levels");
+		if (defaultLevel==null) throw new NullPointerException("defaultLevel");
+		if (catalogName==null) throw new NullPointerException("catalogName");
+		if (message==null) throw new NullPointerException("message");
+		
+		if (factory==null) {
+			// the bundle implementing the UserPromptCondition has not started yet.
+			// Do wrapping magick.
+			return new UserPromptCondition(bundle,levels,defaultLevel,catalogName,message);
+		} else {
+			// there is already a factory, no need to do any wrapping magic
+			try {
+				return (Condition) factory.invoke(null,new Object[]{bundle,levels,defaultLevel,catalogName,message});
+			} catch (IllegalAccessException e) {
+				e.printStackTrace();
+			} catch (InvocationTargetException e) {
+				Throwable original = e.getTargetException();
+				if (original instanceof NullPointerException) throw (NullPointerException) original;
+				if (original instanceof IllegalArgumentException) throw (IllegalArgumentException) original;
+				e.printStackTrace();
+			}
+			// the factory method is not working, fallback behavior:
+			factory = null;
+			return new UserPromptCondition(bundle,levels,defaultLevel,catalogName,message);
+		}
+	}
+
+	/**
+	 * Instances of the UserPromptCondition are simply store the construction parameters
+	 * until a "real" UserPromptCondition is registered in setFactory(). At that point, it
+	 * will delegate all calls there.
+	 * @param unused this parameter is here so that ConditionalPermissionAdmin would not
+	 * 		use this as the constructor instead of the getInstance
+	 * @param bundle
+	 * @param levels
+	 * @param defaultLevel
+	 * @param catalogName
+	 * @param message
+	 */
+	private UserPromptCondition(Bundle bundle,String levels,String defaultLevel,String catalogName,String message) {
+		this.bundle=bundle;
+		this.levels=levels;
+		this.defaultLevel=defaultLevel;
+		this.catalogName=catalogName;
+		this.message=message;
+	}
+	
+	/**
+	 * Check if a factory is registered, and if yes, create userprompt to delegate calls to.
+	 */
+	private void lookForImplementation() {
+		if ((realUserPromptCondition==null)&&(factory!=null)) {
+			try {
+				realUserPromptCondition = (Condition) factory.invoke(null,new Object[]{bundle,levels,defaultLevel,catalogName,message});
+				return;
+			} catch (IllegalAccessException e) {
+				e.printStackTrace();
+			} catch (InvocationTargetException e) {
+				e.printStackTrace();
+			}
+			// only if the factory call fails with some invocation exception
+			factory = null;
+		}
+	}
+	
+	/**
+	 * Checks if the {@link #isSatisfied()} method needs to prompt the user, thus cannot
+	 * give results instantly. 
+	 * This depends on the permission level given in 
+	 * {@link UserPromptCondition#getCondition(Bundle, ConditionInfo)}. 
+	 * <ul>
+	 * <li>ONESHOT - isPostponed always returns true. The user is prompted for question every time.</li>
+	 * <li>SESSION - isPostponed returns true until the user decides either yes or no for the current session.</li>
+	 * <li>BLANKET - isPostponed returns true until the user decides either always or never.</li>
+	 * </ul>
+	 * Regardless of the session level, the user is always given the option to reject the prompt
+	 * permanently, as if BLANKET/never was chosen. In this case, the question is not postponed
+	 * anymore, and {@link #isSatisfied()} returns false.<br/>
+	 * If the system supports an separately accessible permission management GUI,
+	 * that may reset the condition
+	 * to its initial state.
+	 * 
+	 * @return True, if user interaction is needed.
+	 */
+	public boolean isPostponed() {
+		lookForImplementation();
+		if (realUserPromptCondition!=null) {
+			return realUserPromptCondition.isPostponed();
+		} else {
+			return true;
+		}
+	}
+
+	/**
+	 * Checks whether the condition may change during the lifetime of the UserPromptCondition object.
+	 * This depends on the permission level given in 
+	 * {@link UserPromptCondition#getCondition(Bundle, ConditionInfo)}. 
+	 * <ul>
+	 * 	<li>ONESHOT - true</li>
+	 *  <li>SESSION - true, if the application model's session lifetime is
+	 *  		shorter than the UserPromptCondition object lifetime</li>
+	 *  <li>BLANKET - false</li>
+	 * </ul>
+	 * If the system supports separately accessible permission management GUI,
+	 * then this function may also return true for SESSION and BLANKET.
+	 * 
+	 * @return True, if the condition can change.
+	 */
+	public boolean isMutable() {
+		lookForImplementation();
+		if (realUserPromptCondition!=null) {
+			return realUserPromptCondition.isMutable();
+		} else {
+			// since we don't know what the actual status is, we cannot say
+			// "the condition cannot change anymore"
+			return true;
+		}
+	}
+
+	/**
+	 * Displays the prompt string to
+	 * the user and returns true if the user accepts. Depending on the
+	 * amount of levels the condition is assigned to, the prompt may have
+	 * multiple accept buttons and one of them can be selected by default (see
+	 * default level parameter at {@link UserPromptCondition#getCondition(Bundle, ConditionInfo)}).
+	 * It must always be possible for the user
+	 * to stop further prompting of this question, even with ONESHOT and SESSION levels.
+	 * In case of BLANKET
+	 * and SESSION levels, it is possible that the user has already answered the question,
+	 * in this case there will be no prompting, but immediate return with the previous answer.
+	 * 
+	 * @return True if the user accepts the prompt (or accepts any prompt in
+	 *         case there are multiple permission levels).
+	 */
+	public boolean isSatisfied() {
+		lookForImplementation();
+		if (realUserPromptCondition!=null) {
+			return realUserPromptCondition.isSatisfied();
+		} else {
+			// paranoid security option
+			return false;
+		}
+	}
+
+	/**
+	 * Checks an array of UserPrompt conditions.
+	 * 
+	 * @param conds The array containing the UserPrompt conditions to evaluate.
+	 * @param context Storage area for evaluation. The {@link org.osgi.service.condpermadmin.ConditionalPermissionAdmin}
+	 * 		may evaluate a condition several times for one permission check, so this context
+	 * 		will be used to store results of ONESHOT questions. This way asking the same question
+	 * 		twice in a row can be avoided. If context is null, temporary results will not be stored.
+	 * @return True, if all conditions are satisfied.
+	 * @throws NullPointerException if conds is null.
+	 */
+	public boolean isSatisfied(Condition[] conds, Dictionary context) {
+		lookForImplementation();
+		if (realUserPromptCondition!=null) {
+			return realUserPromptCondition.isSatisfied(conds,context);
+		} else {
+			// paranoid security option
+			return false;
+		}
+	}
+}

Added: felix/trunk/deploymentadmin/service/src/main/java/org/osgi/util/mobile/package.html
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/service/src/main/java/org/osgi/util/mobile/package.html?rev=662399&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/service/src/main/java/org/osgi/util/mobile/package.html (added)
+++ felix/trunk/deploymentadmin/service/src/main/java/org/osgi/util/mobile/package.html Mon Jun  2 04:39:58 2008
@@ -0,0 +1,10 @@
+<!-- $Header: /cvshome/build/org.osgi.util.mobile/src/org/osgi/util/mobile/package.html,v 1.2 2006/07/12 21:07:11 hargrave Exp $ -->
+<BODY>
+<p>Mobile Conditions Package Version 1.0.
+<p>Bundles wishing to use this package must list the package
+in the Import-Package header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.util.mobile; version=1.0
+</pre>
+</BODY>

Added: felix/trunk/deploymentadmin/service/src/main/java/org/osgi/util/mobile/packageinfo
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/service/src/main/java/org/osgi/util/mobile/packageinfo?rev=662399&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/service/src/main/java/org/osgi/util/mobile/packageinfo (added)
+++ felix/trunk/deploymentadmin/service/src/main/java/org/osgi/util/mobile/packageinfo Mon Jun  2 04:39:58 2008
@@ -0,0 +1 @@
+version 1.0
\ No newline at end of file