You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by ma...@apache.org on 2008/01/30 17:46:39 UTC

svn commit: r616813 [7/9] - in /felix/trunk/deploymentadmin: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/felix/ src/main/java/org/apache/felix/deploymentadmin/ src/main/java/org/apache/felix/de...

Added: felix/trunk/deploymentadmin/src/main/java/org/osgi/service/metatype/ObjectClassDefinition.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/osgi/service/metatype/ObjectClassDefinition.java?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/osgi/service/metatype/ObjectClassDefinition.java (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/osgi/service/metatype/ObjectClassDefinition.java Wed Jan 30 08:46:24 2008
@@ -0,0 +1,121 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.metatype/src/org/osgi/service/metatype/ObjectClassDefinition.java,v 1.11 2006/06/16 16:31:23 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.metatype;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Description for the data type information of an objectclass.
+ * 
+ * @version $Revision: 1.11 $
+ */
+public interface ObjectClassDefinition {
+	/**
+	 * Argument for <code>getAttributeDefinitions(int)</code>.
+	 * <p>
+	 * <code>REQUIRED</code> indicates that only the required definitions are
+	 * returned. The value is 1.
+	 */
+	public static final int	REQUIRED	= 1;
+	/**
+	 * Argument for <code>getAttributeDefinitions(int)</code>.
+	 * <p>
+	 * <code>OPTIONAL</code> indicates that only the optional definitions are
+	 * returned. The value is 2.
+	 */
+	public static final int	OPTIONAL	= 2;
+	/**
+	 * Argument for <code>getAttributeDefinitions(int)</code>.
+	 * <p>
+	 * <code>ALL</code> indicates that all the definitions are returned. The value
+	 * is -1.
+	 */
+	public static final int	ALL			= 0xFFFFFFFF;
+
+	/**
+	 * Return the name of this object class.
+	 * 
+	 * The name may be localized.
+	 * 
+	 * @return The name of this object class.
+	 */
+	public String getName();
+
+	/**
+	 * Return the id of this object class.
+	 * 
+	 * <p>
+	 * <code>ObjectDefintion</code> objects share a global namespace in the
+	 * registry. They share this aspect with LDAP/X.500 attributes. In these
+	 * standards the OSI Object Identifier (OID) is used to uniquely identify
+	 * object classes. If such an OID exists, (which can be requested at several
+	 * standard organisations and many companies already have a node in the
+	 * tree) it can be returned here. Otherwise, a unique id should be returned
+	 * which can be a java class name (reverse domain name) or generated with a
+	 * GUID algorithm. Note that all LDAP defined object classes already have an
+	 * OID associated. It is strongly advised to define the object classes from
+	 * existing LDAP schemes which will give the OID for free. Many such schemes
+	 * exist ranging from postal addresses to DHCP parameters.
+	 * 
+	 * @return The id of this object class.
+	 */
+	public String getID();
+
+	/**
+	 * Return a description of this object class.
+	 * 
+	 * The description may be localized.
+	 * 
+	 * @return The description of this object class.
+	 */
+	public String getDescription();
+
+	/**
+	 * Return the attribute definitions for this object class.
+	 * 
+	 * <p>
+	 * Return a set of attributes. The filter parameter can distinguish between
+	 * <code>ALL</code>,<code>REQUIRED</code> or the <code>OPTIONAL</code>
+	 * attributes.
+	 * 
+	 * @param filter <code>ALL</code>,<code>REQUIRED</code>,<code>OPTIONAL</code>
+	 * @return An array of attribute definitions or <code>null</code> if no
+	 *         attributes are selected
+	 */
+	public AttributeDefinition[] getAttributeDefinitions(int filter);
+
+	/**
+	 * Return an <code>InputStream</code> object that can be used to create an
+	 * icon from.
+	 * 
+	 * <p>
+	 * Indicate the size and return an <code>InputStream</code> object containing
+	 * an icon. The returned icon maybe larger or smaller than the indicated
+	 * size.
+	 * 
+	 * <p>
+	 * The icon may depend on the localization.
+	 * 
+	 * @param size Requested size of an icon, e.g. a 16x16 pixels icon then size =
+	 *        16
+	 * @return An InputStream representing an icon or <code>null</code>
+	 * @throws IOException If the <code>InputStream</code> cannot be returned.
+	 */
+	public InputStream getIcon(int size) throws IOException;
+}

Added: felix/trunk/deploymentadmin/src/main/java/org/osgi/service/metatype/package.html
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/osgi/service/metatype/package.html?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/osgi/service/metatype/package.html (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/osgi/service/metatype/package.html Wed Jan 30 08:46:24 2008
@@ -0,0 +1 @@
+<!-- $Header: /cvshome/build/org.osgi.service.metatype/src/org/osgi/service/metatype/package.html,v 1.5 2006/07/12 21:07:16 hargrave Exp $ -->
<BODY>
<p>Metatype Package Version 1.1.
<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.metatype; version=1.1
</pre>
</BODY>
\ No newline at end of file

Added: felix/trunk/deploymentadmin/src/main/java/org/osgi/service/metatype/packageinfo
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/osgi/service/metatype/packageinfo?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/osgi/service/metatype/packageinfo (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/osgi/service/metatype/packageinfo Wed Jan 30 08:46:24 2008
@@ -0,0 +1 @@
+version 1.1

Added: felix/trunk/deploymentadmin/src/main/java/org/osgi/service/monitor/MonitorAdmin.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/osgi/service/monitor/MonitorAdmin.java?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/osgi/service/monitor/MonitorAdmin.java (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/osgi/service/monitor/MonitorAdmin.java Wed Jan 30 08:46:24 2008
@@ -0,0 +1,359 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.monitor/src/org/osgi/service/monitor/MonitorAdmin.java,v 1.25 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;
+
+/**
+ * The <code>MonitorAdmin</code> service is a singleton service that handles
+ * <code>StatusVariable</code> query requests and measurement job control
+ * requests.
+ * <p>
+ * Note that an alternative but not recommended way of obtaining
+ * <code>StatusVariable</code>s is that applications having the required
+ * <code>ServicePermissions</code> can query the list of
+ * <code>Monitorable</code> services from the service registry and then query
+ * the list of <code>StatusVariable</code> names from the
+ * <code>Monitorable</code> services. This way all services which publish
+ * <code>StatusVariable</code>s will be returned regardless of whether they
+ * do or do not hold the necessary <code>MonitorPermission</code> for
+ * publishing <code>StatusVariable</code>s. By using the
+ * <code>MonitorAdmin</code> to obtain the <code>StatusVariable</code>s it
+ * is guaranteed that only those <code>Monitorable</code> services will be
+ * accessed who are authorized to publish <code>StatusVariable</code>s. It is
+ * the responsibility of the <code>MonitorAdmin</code> implementation to check
+ * the required permissions and show only those variables which pass this check.
+ * <p>
+ * The events posted by <code>MonitorAdmin</code> contain the following
+ * properties:
+ * <ul>
+ * <li><code>mon.monitorable.pid</code>: The identifier of the
+ * <code>Monitorable</code>
+ * <li><code>mon.statusvariable.name</code>: The identifier of the
+ * <code>StatusVariable</code> within the given <code>Monitorable</code>
+ * <li><code>mon.statusvariable.value</code>: The value of the
+ * <code>StatusVariable</code>, represented as a <code>String</code>
+ * <li><code>mon.listener.id</code>: The identifier of the initiator of the
+ * monitoring job (only present if the event was generated due to a monitoring
+ * job)
+ * </ul>
+ * <p>
+ * Most of the methods require either a Monitorable ID or a Status Variable path
+ * parameter, the latter in [Monitorable_ID]/[StatusVariable_ID] format.  These
+ * parameters must not be <code>null</code>, and the IDs they contain must
+ * conform to their respective definitions in {@link Monitorable} and
+ * {@link StatusVariable}.  If any of the restrictions are violated, the method
+ * must throw an <code>IllegalArgumentException</code>.
+ */
+public interface MonitorAdmin {
+
+    /**
+     * Returns a <code>StatusVariable</code> addressed by its full path. 
+     * The entity which queries a <code>StatusVariable</code> needs to hold
+     * <code>MonitorPermission</code> for the given target with the
+     * <code>read</code> action present.
+     * 
+     * @param path the full path of the <code>StatusVariable</code> in
+     *        [Monitorable_ID]/[StatusVariable_ID] format
+     * @return the <code>StatusVariable</code> object
+     * @throws java.lang.IllegalArgumentException if <code>path</code> is
+     *         <code>null</code> or otherwise invalid, or points to a
+     *         non-existing <code>StatusVariable</code>
+     * @throws java.lang.SecurityException if the caller does not hold a
+     *         <code>MonitorPermission</code> for the
+     *         <code>StatusVariable</code> specified by <code>path</code>
+     *         with the <code>read</code> action present
+     */
+    public StatusVariable getStatusVariable(String path)
+            throws IllegalArgumentException, SecurityException;
+
+    /**
+     * Returns the names of the <code>Monitorable</code> services that are
+     * currently registered. The <code>Monitorable</code> instances are not
+     * accessible through the <code>MonitorAdmin</code>, so that requests to
+     * individual status variables can be filtered with respect to the
+     * publishing rights of the <code>Monitorable</code> and the reading
+     * rights of the caller.
+     * <p>
+     * The returned array contains the names in alphabetical order. It cannot be
+     * <code>null</code>, an empty array is returned if no
+     * <code>Monitorable</code> services are registered.
+     * 
+     * @return the array of <code>Monitorable</code> names
+     */
+    public String[] getMonitorableNames();
+
+    /**
+     * Returns the <code>StatusVariable</code> objects published by a
+     * <code>Monitorable</code> instance. The <code>StatusVariables</code>
+     * will hold the values taken at the time of this method call. Only those
+     * status variables are returned where the following two conditions are met:
+     * <ul>
+     * <li>the specified <code>Monitorable</code> holds a
+     * <code>MonitorPermission</code> for the status variable with the
+     * <code>publish</code> action present
+     * <li>the caller holds a <code>MonitorPermission</code> for the status
+     * variable with the <code>read</code> action present
+     * </ul>
+     * All other status variables are silently ignored, they are omitted from
+     * the result.
+     * <p>
+     * The elements in the returned array are in no particular order. The return
+     * value cannot be <code>null</code>, an empty array is returned if no 
+     * (authorized and readable) Status Variables are provided by the given 
+     * <code>Monitorable</code>.
+     * 
+     * @param monitorableId the identifier of a <code>Monitorable</code>
+     *        instance
+     * @return a list of <code>StatusVariable</code> objects published
+     *         by the specified <code>Monitorable</code>
+     * @throws java.lang.IllegalArgumentException if <code>monitorableId</code>
+     *         is <code>null</code> or otherwise invalid, or points to a
+     *         non-existing <code>Monitorable</code>
+     */
+    public StatusVariable[] getStatusVariables(String monitorableId)
+            throws IllegalArgumentException;
+
+    /**
+     * Returns the list of <code>StatusVariable</code> names published by a
+     * <code>Monitorable</code> instance. Only those status variables are
+     * listed where the following two conditions are met:
+     * <ul>
+     * <li>the specified <code>Monitorable</code> holds a
+     * <code>MonitorPermission</code> for the status variable with the
+     * <code>publish</code> action present
+     * <li>the caller holds a <code>MonitorPermission</code> for
+     * the status variable with the <code>read</code> action present
+     * </ul>
+     * All other status variables are silently ignored, their names are omitted
+     * from the list.
+     * <p>
+     * The returned array does not contain duplicates, and the elements are in 
+     * alphabetical order. It cannot be <code>null</code>, an empty array is 
+     * returned if no (authorized and readable) Status Variables are provided 
+     * by the given <code>Monitorable</code>.
+     * 
+     * @param monitorableId the identifier of a <code>Monitorable</code>
+     *        instance
+     * @return a list of <code>StatusVariable</code> objects names
+     *         published by the specified <code>Monitorable</code>
+     * @throws java.lang.IllegalArgumentException if <code>monitorableId</code>
+     *         is <code>null</code> or otherwise invalid, or points to a
+     *         non-existing <code>Monitorable</code>
+     */
+    public String[] getStatusVariableNames(String monitorableId)
+            throws IllegalArgumentException;
+
+    /**
+     * Switches event sending on or off for the specified 
+     * <code>StatusVariable</code>s. When the <code>MonitorAdmin</code> is
+     * notified about a <code>StatusVariable</code> being updated it sends an
+     * event unless this feature is switched off. Note that events within a
+     * monitoring job can not be switched off. The event sending state of the 
+     * <code>StatusVariables</code> must not be persistently stored. When a 
+     * <code>StatusVariable</code> is registered for the first time in a 
+     * framework session, its event sending state is set to ON by default.
+     * <p>
+     * Usage of the "*" wildcard is allowed in the path argument of this method
+     * as a convenience feature. The wildcard can be used in either or both path
+     * fragments, but only at the end of the fragments.  The semantics of the 
+     * wildcard is that it stands for any matching <code>StatusVariable</code> 
+     * at the time of the method call, it does not affect the event sending 
+     * status of <code>StatusVariable</code>s which are not yet registered. As 
+     * an example, when the <code>switchEvents("MyMonitorable/*", false)</code>
+     * method is executed, event sending from all <code>StatusVariables</code>
+     * of the MyMonitorable service are switched off. However, if the
+     * MyMonitorable service starts to publish a new <code>StatusVariable</code>
+     * later, it's event sending status is on by default.
+     * 
+     * @param path the identifier of the <code>StatusVariable</code>(s) in
+     *        [Monitorable_id]/[StatusVariable_id] format, possibly with the 
+     *        "*" wildcard at the end of either path fragment
+     * @param on <code>false</code> if event sending should be switched off, 
+     *        <code>true</code> if it should be switched on for the given path
+     * @throws java.lang.SecurityException if the caller does not hold
+     *         <code>MonitorPermission</code> with the
+     *         <code>switchevents</code> action or if there is any
+     *         <code>StatusVariable</code> in the <code>path</code> field for
+     *         which it is not allowed to switch event sending on or off as per 
+     *         the target field of the permission
+     * @throws java.lang.IllegalArgumentException if <code>path</code> is 
+     *         <code>null</code> or otherwise invalid, or points to a 
+     *         non-existing <code>StatusVariable</code>
+     */
+    public void switchEvents(String path, boolean on)
+        throws IllegalArgumentException, SecurityException;
+    
+    /**
+     * Issues a request to reset a given <code>StatusVariable</code>.
+     * Depending on the semantics of the <code>StatusVariable</code> this call
+     * may or may not succeed: it makes sense to reset a counter to its starting
+     * value, but e.g. a <code>StatusVariable</code> of type String might not
+     * have a meaningful default value. Note that for numeric
+     * <code>StatusVariable</code>s the starting value may not necessarily be
+     * 0. Resetting a <code>StatusVariable</code> triggers a monitor event if
+     * the <code>StatusVariable</code> supports update notifications.
+     * <p>
+     * The entity that wants to reset the <code>StatusVariable</code> needs to
+     * hold <code>MonitorPermission</code> with the <code>reset</code>
+     * action present. The target field of the permission must match the
+     * <code>StatusVariable</code> name to be reset.
+     * 
+     * @param path the identifier of the <code>StatusVariable</code> in
+     *        [Monitorable_id]/[StatusVariable_id] format
+     * @return <code>true</code> if the <code>Monitorable</code> could
+     *         successfully reset the given <code>StatusVariable</code>,
+     *         <code>false</code> otherwise
+     * @throws java.lang.IllegalArgumentException if <code>path</code> is 
+     *         <code>null</code> or otherwise invalid, or points to a 
+     *         non-existing <code>StatusVariable</code>
+     * @throws java.lang.SecurityException if the caller does not hold
+     *         <code>MonitorPermission</code> with the <code>reset</code>
+     *         action or if the specified <code>StatusVariable</code> is not
+     *         allowed to be reset as per the target field of the permission
+     */
+    public boolean resetStatusVariable(String path)
+            throws IllegalArgumentException, SecurityException;
+    
+    /**
+     * Returns a human readable description of the given 
+     * <code>StatusVariable</code>. The <code>null</code> value may be returned
+     * if there is no description for the given <code>StatusVariable</code>.
+     * <p>
+     * The entity that queries a <code>StatusVariable</code> needs to hold
+     * <code>MonitorPermission</code> for the given target with the
+     * <code>read</code> action present.
+     * 
+     * @param path the full path of the <code>StatusVariable</code> in
+     *        [Monitorable_ID]/[StatusVariable_ID] format
+     * @return the human readable description of this
+     *         <code>StatusVariable</code> or <code>null</code> if it is not
+     *         set
+     * @throws java.lang.IllegalArgumentException if <code>path</code> is 
+     *         <code>null</code> or otherwise invalid, or points to a 
+     *         non-existing <code>StatusVariable</code>
+     * @throws java.lang.SecurityException if the caller does not hold a
+     *         <code>MonitorPermission</code> for the
+     *         <code>StatusVariable</code> specified by <code>path</code>
+     *         with the <code>read</code> action present
+     */
+    public String getDescription(String path) 
+            throws IllegalArgumentException, SecurityException;
+
+    /**
+     * Starts a time based <code>MonitoringJob</code> with the parameters
+     * provided. Monitoring events will be sent according to the specified
+     * schedule. All specified <code>StatusVariable</code>s must exist when the
+     * job is started. The initiator string is used in the
+     * <code>mon.listener.id</code> field of all events triggered by the job,
+     * to allow filtering the events based on the initiator.
+     * <p>
+     * The <code>schedule</code> parameter specifies the time in seconds 
+     * between two measurements, it must be greater than 0.  The first 
+     * measurement will be taken when the timer expires for the first time, not 
+     * when this method is called.
+     * <p>
+     * The <code>count</code> parameter defines the number of measurements to be
+     * taken, and must either be a positive integer, or 0 if the measurement is
+     * to run until explicitely stopped.
+     * <p>
+     * The entity which initiates a <code>MonitoringJob</code> needs to hold
+     * <code>MonitorPermission</code> for all the specified target
+     * <code>StatusVariable</code>s with the <code>startjob</code> action
+     * present. If the permission's action string specifies a minimal sampling
+     * interval then the <code>schedule</code> parameter should be at least as
+     * great as the value in the action string.
+     * 
+     * @param initiator the identifier of the entity that initiated the job
+     * @param statusVariables the list of <code>StatusVariable</code>s to be
+     *        monitored, with each <code>StatusVariable</code> name given in
+     *        [Monitorable_PID]/[StatusVariable_ID] format
+     * @param schedule the time in seconds between two measurements
+     * @param count the number of measurements to be taken, or 0 for the
+     *        measurement to run until explicitely stopped
+     * @return the successfully started job object, cannot be <code>null</code>
+     * @throws java.lang.IllegalArgumentException if the list of
+     *         <code>StatusVariable</code> names contains an invalid or 
+     *         non-existing <code>StatusVariable</code>; if 
+     *         <code>initiator</code> is <code>null</code> or empty; or if the 
+     *         <code>schedule</code> or <code>count</code> parameters are 
+     *         invalid
+     * @throws java.lang.SecurityException if the caller does not hold
+     *         <code>MonitorPermission</code> for all the specified
+     *         <code>StatusVariable</code>s, with the <code>startjob</code>
+     *         action present, or if the permission does not allow starting the
+     *         job with the given frequency
+     */
+    public MonitoringJob startScheduledJob(String initiator,
+            String[] statusVariables, int schedule, int count)
+            throws IllegalArgumentException, SecurityException;
+
+    /**
+     * Starts a change based <code>MonitoringJob</code> with the parameters
+     * provided. Monitoring events will be sent when the
+     * <code>StatusVariable</code>s of this job are updated. All specified
+     * <code>StatusVariable</code>s must exist when the job is started, and
+     * all must support update notifications. The initiator string is used in
+     * the <code>mon.listener.id</code> field of all events triggered by the
+     * job, to allow filtering the events based on the initiator.
+     * <p>
+     * The <code>count</code> parameter specifies the number of changes that
+     * must happen to a <code>StatusVariable</code> before a new notification is
+     * sent, this must be a positive integer.
+     * <p>
+     * The entity which initiates a <code>MonitoringJob</code> needs to hold
+     * <code>MonitorPermission</code> for all the specified target
+     * <code>StatusVariable</code>s with the <code>startjob</code> action
+     * present.
+     * 
+     * @param initiator the identifier of the entity that initiated the job
+     * @param statusVariables the list of <code>StatusVariable</code>s to be
+     *        monitored, with each <code>StatusVariable</code> name given in
+     *        [Monitorable_PID]/[StatusVariable_ID] format
+     * @param count the number of changes that must happen to a 
+     *        <code>StatusVariable</code> before a new notification is sent
+     * @return the successfully started job object, cannot be <code>null</code>
+     * @throws java.lang.IllegalArgumentException if the list of
+     *         <code>StatusVariable</code> names contains an invalid or 
+     *         non-existing <code>StatusVariable</code>, or one that does not 
+     *         support notifications; if the <code>initiator</code> is 
+     *         <code>null</code> or empty; or if <code>count</code> is invalid
+     * @throws java.lang.SecurityException if the caller does not hold
+     *         <code>MonitorPermission</code> for all the specified
+     *         <code>StatusVariable</code>s, with the <code>startjob</code>
+     *         action present
+     */
+    public MonitoringJob startJob(String initiator, String[] statusVariables,
+            int count) throws IllegalArgumentException, SecurityException;
+
+    /**
+     * Returns the list of currently running <code>MonitoringJob</code>s.
+     * Jobs are only visible to callers that have the necessary permissions: to 
+     * receive a Monitoring Job in the returned list, the caller must hold all 
+     * permissions required for starting the job.  This means that if the caller
+     * does not have <code>MonitorPermission</code> with the proper
+     * <code>startjob</code> action for all the Status Variables monitored by a 
+     * job, then that job will be silently omitted from the results.
+     * <p>
+     * The returned array cannot be <code>null</code>, an empty array is
+     * returned if there are no running jobs visible to the caller at the time 
+     * of the call.
+     * 
+     * @return the list of running jobs visible to the caller
+     */
+    public MonitoringJob[] getRunningJobs();
+}

Added: felix/trunk/deploymentadmin/src/main/java/org/osgi/service/monitor/MonitorListener.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/osgi/service/monitor/MonitorListener.java?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/osgi/service/monitor/MonitorListener.java (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/osgi/service/monitor/MonitorListener.java Wed Jan 30 08:46:24 2008
@@ -0,0 +1,42 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.monitor/src/org/osgi/service/monitor/MonitorListener.java,v 1.11 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;
+
+/**
+ * The <code>MonitorListener</code> is used by <code>Monitorable</code>
+ * services to send notifications when a <code>StatusVariable</code> value is
+ * changed. The <code>MonitorListener</code> should register itself as a
+ * service at the OSGi Service Registry. This interface must (only) be 
+ * implemented by the Monitor Admin component.
+ */
+public interface MonitorListener {
+    /**
+     * Callback for notification of a <code>StatusVariable</code> change.
+     * 
+     * @param monitorableId the identifier of the <code>Monitorable</code>
+     *        instance reporting the change
+     * @param statusVariable the <code>StatusVariable</code> that has changed
+     * @throws java.lang.IllegalArgumentException if the specified monitorable
+     *         ID is invalid (<code>null</code>, empty, or contains illegal
+     *         characters) or points to a non-existing <code>Monitorable</code>, 
+     *         or if <code>statusVariable</code> is <code>null</code>
+     */
+    public void updated(String monitorableId, StatusVariable statusVariable)
+            throws IllegalArgumentException;
+}

Added: felix/trunk/deploymentadmin/src/main/java/org/osgi/service/monitor/MonitorPermission.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/osgi/service/monitor/MonitorPermission.java?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/osgi/service/monitor/MonitorPermission.java (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/osgi/service/monitor/MonitorPermission.java Wed Jan 30 08:46:24 2008
@@ -0,0 +1,366 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.monitor/src/org/osgi/service/monitor/MonitorPermission.java,v 1.17 2006/06/21 15:17:16 hargrave Exp $
+ * 
+ * Copyright (c) OSGi Alliance (2005, 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.security.Permission;
+import java.util.StringTokenizer;
+
+/**
+ * Indicates the callers authority to publish, read or reset
+ * <code>StatusVariable</code>s, to switch event sending on or off or to
+ * start monitoring jobs. The target of the permission is the identifier of the
+ * <code>StatusVariable</code>, the action can be <code>read</code>,
+ * <code>publish</code>, <code>reset</code>, <code>startjob</code>,
+ * <code>switchevents</code>, or the combination of these separated by
+ * commas.  Action names are interpreted case-insensitively, but the canonical 
+ * action string returned by {@link #getActions} uses the forms defined by the 
+ * action constants.
+ * <p>
+ * If the wildcard <code>*</code> appears in the actions field, all legal 
+ * monitoring commands are allowed on the designated target(s) by the owner of 
+ * the permission.
+ */
+public class MonitorPermission extends Permission {
+
+    /**
+	 * 
+	 */
+	private static final long	serialVersionUID	= -9084425194463274314L;
+
+	/**
+     * Holders of <code>MonitorPermission</code> with the <code>read</code>
+     * action present are allowed to read the value of the
+     * <code>StatusVariable</code>s specified in the permission's target field.
+     */
+    public static final String READ = "read";
+
+    /**
+     * Holders of <code>MonitorPermission</code> with the <code>reset</code>
+     * action present are allowed to reset the value of the
+     * <code>StatusVariable</code>s specified in the permission's target field.
+     */
+    public static final String RESET = "reset";
+
+    /**
+     * Holders of <code>MonitorPermission</code> with the <code>publish</code>
+     * action present are <code>Monitorable</code> services that are allowed
+     * to publish the <code>StatusVariable</code>s specified in the
+     * permission's target field.  Note, that this permission cannot be enforced 
+     * when a <code>Monitorable</code> registers to the framework, because the
+     * Service Registry does not know about this permission.  Instead, any
+     * <code>StatusVariable</code>s published by a <code>Monitorable</code>
+     * without the corresponding <code>publish</code> permission are silently
+     * ignored by <code>MonitorAdmin</code>, and are therefore invisible to the
+     * users of the monitoring service.   
+     */
+    public static final String PUBLISH = "publish";
+
+    /**
+     * Holders of <code>MonitorPermission</code> with the <code>startjob</code>
+     * action present are allowed to initiate monitoring jobs involving the 
+     * <code>StatusVariable</code>s specified in the permission's target field.
+     * <p>
+     * A minimal sampling interval can be optionally defined in the following
+     * form: <code>startjob:n</code>.  This allows the holder of the permission
+     * to initiate time based jobs with a measurement interval of at least
+     * <code>n</code> seconds. If <code>n</code> is not specified or 0 then the 
+     * holder of this permission is allowed to start monitoring jobs specifying 
+     * any frequency.
+     */
+    public static final String STARTJOB = "startjob";
+
+    /**
+     * Holders of <code>MonitorPermission</code> with the
+     * <code>switchevents</code> action present are allowed to switch event
+     * sending on or off for the value of the <code>StatusVariable</code>s
+     * specified in the permission's target field.
+     */
+    public static final String SWITCHEVENTS = "switchevents";
+
+    private static final int READ_FLAG         = 0x1;
+    private static final int RESET_FLAG        = 0x2;
+    private static final int PUBLISH_FLAG      = 0x4;
+    private static final int STARTJOB_FLAG     = 0x8;
+    private static final int SWITCHEVENTS_FLAG = 0x10;
+    
+    private static final int ALL_FLAGS = READ_FLAG | RESET_FLAG | 
+        PUBLISH_FLAG | STARTJOB_FLAG | SWITCHEVENTS_FLAG;
+
+    private String monId;
+    private String varId;
+    private boolean prefixMonId;
+    private boolean prefixVarId;
+    private int mask;
+    private int minJobInterval;
+
+    /**
+     * Create a <code>MonitorPermission</code> object, specifying the target
+     * and actions.
+     * <p>
+     * The <code>statusVariable</code> parameter is the target of the 
+     * permission, defining one or more status variable names to which the
+     * specified actions apply. Multiple status variable names can be selected
+     * by using the wildcard <code>*</code> in the target string.  The wildcard
+     * is allowed in both fragments, but only at the end of the fragments.
+     * <p>
+     * For example, the following targets are valid:
+     * <code>com.mycomp.myapp/queue_length</code>,
+     * <code>com.mycomp.myapp/*</code>, <code>com.mycomp.&#42;/*</code>,
+     * <code>&#42;/*</code>, <code>&#42;/queue_length</code>, 
+     * <code>&#42;/queue*</code>.
+     * <p>
+     * The following targets are invalid:
+     * <code>*.myapp/queue_length</code>, <code>com.*.myapp/*</code>,
+     * <code>*</code>.
+     * <p>
+     * The <code>actions</code> parameter specifies the allowed action(s): 
+     * <code>read</code>, <code>publish</code>, <code>startjob</code>,
+     * <code>reset</code>, <code>switchevents</code>, or the combination of 
+     * these separated by commas. String constants are defined in this class for
+     * each valid action.  Passing <code>&quot;*&quot;</code> as the action 
+     * string is equivalent to listing all actions. 
+     * 
+     * @param statusVariable the identifier of the <code>StatusVariable</code>
+     *        in [Monitorable_id]/[StatusVariable_id] format 
+     * @param actions the list of allowed actions separated by commas, or
+     *        <code>*</code> for all actions
+     * @throws java.lang.IllegalArgumentException if either parameter is 
+     *         <code>null</code>, or invalid with regard to the constraints
+     *         defined above and in the documentation of the used actions 
+     */
+    public MonitorPermission(String statusVariable, String actions) 
+            throws IllegalArgumentException {
+        super(statusVariable);
+
+        if(statusVariable == null)
+            throw new IllegalArgumentException(
+                    "Invalid StatusVariable path 'null'.");
+        
+        if(actions == null)
+            throw new IllegalArgumentException(
+                    "Invalid actions string 'null'.");
+        
+        int sep = statusVariable.indexOf('/');
+        int len = statusVariable.length();
+
+        if (sep == -1)
+            throw new IllegalArgumentException(
+                    "Invalid StatusVariable path: should contain '/' separator.");
+        if (sep == 0 || sep == statusVariable.length() - 1)
+            throw new IllegalArgumentException(
+                    "Invalid StatusVariable path: empty monitorable ID or StatusVariable name.");
+
+        prefixMonId = statusVariable.charAt(sep - 1) == '*';
+        prefixVarId = statusVariable.charAt(len - 1) == '*';
+        
+        monId = statusVariable.substring(0, prefixMonId ? sep - 1 : sep);
+        varId = statusVariable.substring(sep + 1, prefixVarId ? len - 1 : len);
+
+        checkId(monId, "Monitorable ID part of the target");
+        checkId(varId, "Status Variable ID part of the target");
+
+        minJobInterval = 0;
+
+        if(actions.equals("*"))
+            mask = ALL_FLAGS;
+        else {
+            mask = 0;
+            StringTokenizer st = new StringTokenizer(actions, ",");
+            while (st.hasMoreTokens()) {
+                String action = st.nextToken();
+                if (action.equalsIgnoreCase(READ)) {
+                    addToMask(READ_FLAG, READ);
+                } else if (action.equalsIgnoreCase(RESET)) {
+                    addToMask(RESET_FLAG, RESET);
+                } else if (action.equalsIgnoreCase(PUBLISH)) {
+                    addToMask(PUBLISH_FLAG, PUBLISH);
+                } else if (action.equalsIgnoreCase(SWITCHEVENTS)) {
+                    addToMask(SWITCHEVENTS_FLAG, SWITCHEVENTS);
+                } else if (action.toLowerCase().startsWith(STARTJOB)) {
+                    minJobInterval = 0;
+    
+                    int slen = STARTJOB.length();
+                    if (action.length() != slen) {
+                        if (action.charAt(slen) != ':')
+                            throw new IllegalArgumentException(
+                                    "Invalid action '" + action + "'.");
+    
+                        try {
+                            minJobInterval = Integer.parseInt(action
+                                    .substring(slen + 1));
+                        } catch (NumberFormatException e) {
+                            throw new IllegalArgumentException(
+                                    "Invalid parameter in startjob action '"
+                                            + action + "'.");
+                        }
+                    }
+                    addToMask(STARTJOB_FLAG, STARTJOB);
+                } else
+                    throw new IllegalArgumentException("Invalid action '" + 
+                            action + "'");
+            }
+        }
+    }
+    
+    private void addToMask(int action, String actionString) {
+        if((mask & action) != 0)
+            throw new IllegalArgumentException("Invalid action string: " + 
+                    actionString + " appears multiple times.");
+        
+        mask |= action;
+    }
+
+    private void checkId(String id, String idName)
+            throws IllegalArgumentException {
+        
+        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 > StatusVariable.MAX_ID_LENGTH)
+            throw new IllegalArgumentException(idName + " is too long (over " +
+                    StatusVariable.MAX_ID_LENGTH + " bytes in UTF-8 encoding).");
+
+        
+        if (id.equals(".") || id.equals(".."))
+            throw new IllegalArgumentException(idName + " is invalid.");
+        
+        char[] chars = id.toCharArray();
+        for (int i = 0; i < chars.length; i++)
+            if (StatusVariable.SYMBOLIC_NAME_CHARACTERS.indexOf(chars[i]) == -1)
+                throw new IllegalArgumentException(idName +
+                        " contains invalid characters.");
+    }
+    
+    /**
+     * Create an integer hash of the object. The hash codes of
+     * <code>MonitorPermission</code>s <code>p1</code> and <code>p2</code> are 
+     * the same if <code>p1.equals(p2)</code>.
+     * 
+     * @return the hash of the object
+     */
+    public int hashCode() {
+        return new Integer(mask).hashCode()
+                ^ new Integer(minJobInterval).hashCode() ^ monId.hashCode()
+                ^ new Boolean(prefixMonId).hashCode()
+                ^ varId.hashCode()
+                ^ new Boolean(prefixVarId).hashCode();
+    }
+
+    /**
+     * Determines the equality of two <code>MonitorPermission</code> objects.
+     * Two <code>MonitorPermission</code> objects are equal if their target
+     * strings are equal and the same set of actions are listed in their action
+     * strings.
+     * 
+     * @param o the object being compared for equality with this object
+     * @return <code>true</code> if the two permissions are equal
+     */
+    public boolean equals(Object o) {
+        if (!(o instanceof MonitorPermission))
+            return false;
+
+        MonitorPermission other = (MonitorPermission) o;
+
+        return mask == other.mask && minJobInterval == other.minJobInterval
+                && monId.equals(other.monId)
+                && prefixMonId == other.prefixMonId
+                && varId.equals(other.varId)
+                && prefixVarId == other.prefixVarId;
+    }
+
+    /**
+     * Get the action string associated with this permission.  The actions are
+     * returned in the following order: <code>read</code>, <code>reset</code>, 
+     * <code>publish</code>, <code>startjob</code>, <code>switchevents</code>.
+     * 
+     * @return the allowed actions separated by commas, cannot be
+     *         <code>null</code>
+     */
+    public String getActions() {
+        StringBuffer sb = new StringBuffer();
+
+        appendAction(sb, READ_FLAG,         READ);
+        appendAction(sb, RESET_FLAG,        RESET);
+        appendAction(sb, PUBLISH_FLAG,      PUBLISH);
+        appendAction(sb, STARTJOB_FLAG,     STARTJOB);
+        appendAction(sb, SWITCHEVENTS_FLAG, SWITCHEVENTS);
+
+        return sb.toString();
+    }
+
+    private void appendAction(StringBuffer sb, int flag, String actionName) {
+        if ((mask & flag) != 0) {
+            if(sb.length() != 0)
+                sb.append(',');
+            sb.append(actionName);
+            
+            if(flag == STARTJOB_FLAG && minJobInterval != 0)
+                sb.append(':').append(minJobInterval);
+        }
+    }
+
+    /**
+     * Determines if the specified permission is implied by this permission.
+     * <p>
+     * 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 <code>MonitorPermission</code>
+     * <li>it has a broader set of actions allowed than this one
+     * <li>it allows initiating time based monitoring jobs with a lower minimal
+     * sampling interval
+     * <li>the target set of <code>Monitorable</code>s is not the same nor a
+     * subset of the target set of <code>Monitorable</code>s of this permission
+     * <li>the target set of <code>StatusVariable</code>s is not the same
+     * nor a subset of the target set of <code>StatusVariable</code>s of this
+     * permission
+     * </ul>
+     * 
+     * @param p the permission to be checked
+     * @return <code>true</code> if the given permission is implied by this
+     *         permission
+     */
+    public boolean implies(Permission p) {
+        if (!(p instanceof MonitorPermission))
+            return false;
+
+        MonitorPermission other = (MonitorPermission) p;
+
+        if ((mask & other.mask) != other.mask)
+            return false;
+
+        if ((other.mask & STARTJOB_FLAG) != 0
+                && minJobInterval > other.minJobInterval)
+            return false;
+
+        return implies(monId, prefixMonId, other.monId, other.prefixMonId)
+                && implies(varId, prefixVarId, other.varId, other.prefixVarId);
+    }
+
+    private boolean implies(String id, boolean prefix, String oid,
+            boolean oprefix) {
+
+        return prefix ? oid.startsWith(id) : !oprefix && id.equals(oid);
+    }
+}

Added: felix/trunk/deploymentadmin/src/main/java/org/osgi/service/monitor/Monitorable.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/osgi/service/monitor/Monitorable.java?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/osgi/service/monitor/Monitorable.java (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/osgi/service/monitor/Monitorable.java Wed Jan 30 08:46:24 2008
@@ -0,0 +1,140 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.monitor/src/org/osgi/service/monitor/Monitorable.java,v 1.17 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;
+
+/**
+ * A <code>Monitorable</code> can provide information about itself in the form
+ * of <code>StatusVariables</code>. Instances of this interface should
+ * register themselves at the OSGi Service Registry. The
+ * <code>MonitorAdmin</code> listens to the registration of
+ * <code>Monitorable</code> services, and makes the information they provide
+ * available also through the Device Management Tree (DMT) for remote access.
+ * <p>
+ * The monitorable service is identified by its PID string which 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 PID must not exceed
+ * 20 characters.
+ * <p>
+ * A <code>Monitorable</code> may optionally support sending notifications
+ * when the status of its <code>StatusVariables</code> change. Support for
+ * change notifications can be defined per <code>StatusVariable</code>.
+ * <p>
+ * Publishing <code>StatusVariables</code> requires the presence of the
+ * <code>MonitorPermission</code> with the <code>publish</code> action
+ * string. This permission, however, is not checked during registration of the
+ * <code>Monitorable</code> service. Instead, the <code>MonitorAdmin</code>
+ * implemenatation must make sure that when a <code>StatusVariable</code> is
+ * queried, it is shown only if the <code>Monitorable</code> is authorized to
+ * publish the given <code>StatusVariable</code>.
+ */
+public interface Monitorable {
+    /**
+     * Returns the list of <code>StatusVariable</code> identifiers published
+     * by this <code>Monitorable</code>. A <code>StatusVariable</code> name
+     * is unique within the scope of a <code>Monitorable</code>. The array
+     * contains the elements in no particular order. The returned value must not
+     * be <code>null</code>.
+     * 
+     * @return the <code>StatusVariable<code> identifiers published by this 
+     *         object, or an empty array if none are published
+     */
+    public String[] getStatusVariableNames();
+    
+    /**
+     * Returns the <code>StatusVariable</code> object addressed by its
+     * identifier. The <code>StatusVariable</code> will hold the value taken
+     * at the time of this method call.
+     * <p>
+     * The given identifier does not contain the Monitorable PID, i.e. it 
+     * specifies the name and not the path of the Status Variable.
+     * 
+     * @param id the identifier of the <code>StatusVariable</code>, cannot be
+     *        <code>null</code> 
+     * @return the <code>StatusVariable</code> object
+     * @throws java.lang.IllegalArgumentException if <code>id</code> points to a
+     *         non-existing <code>StatusVariable</code>
+     */
+    public StatusVariable getStatusVariable(String id)
+            throws IllegalArgumentException;
+
+    /**
+     * Tells whether the <code>StatusVariable</code> provider is able to send
+     * instant notifications when the given <code>StatusVariable</code>
+     * changes. If the <code>Monitorable</code> supports sending change
+     * updates it must notify the <code>MonitorListener</code> when the value
+     * of the <code>StatusVariable</code> changes. The
+     * <code>Monitorable</code> finds the <code>MonitorListener</code>
+     * service through the Service Registry.
+     * <p>
+     * The given identifier does not contain the Monitorable PID, i.e. it 
+     * specifies the name and not the path of the Status Variable.
+     * 
+     * @param id the identifier of the <code>StatusVariable</code>, cannot be
+     *        <code>null</code> 
+     * @return <code>true</code> if the <code>Monitorable</code> can send
+     *         notification when the given <code>StatusVariable</code>
+     *         changes, <code>false</code> otherwise
+     * @throws java.lang.IllegalArgumentException if <code>id</code> points to a
+     *         non-existing <code>StatusVariable</code>
+     */
+    public boolean notifiesOnChange(String id) throws IllegalArgumentException;
+
+    /**
+     * Issues a request to reset a given <code>StatusVariable</code>.
+     * Depending on the semantics of the actual Status Variable this call may or
+     * may not succeed: it makes sense to reset a counter to its starting value,
+     * but for example a <code>StatusVariable</code> of type <code>String</code>
+     * might not have a meaningful default value. Note that for numeric
+     * <code>StatusVariables</code> the starting value may not necessarily be
+     * 0. Resetting a <code>StatusVariable</code> must trigger a monitor event.
+     * <p>
+     * The given identifier does not contain the Monitorable PID, i.e. it 
+     * specifies the name and not the path of the Status Variable.
+     * 
+     * @param id the identifier of the <code>StatusVariable</code>, cannot be
+     *        <code>null</code> 
+     * @return <code>true</code> if the <code>Monitorable</code> could
+     *         successfully reset the given <code>StatusVariable</code>,
+     *         <code>false</code> otherwise
+     * @throws java.lang.IllegalArgumentException if <code>id</code> points to a
+     *         non-existing <code>StatusVariable</code>
+     */
+    public boolean resetStatusVariable(String id)
+            throws IllegalArgumentException;
+    
+    /**
+     * Returns a human readable description of a <code>StatusVariable</code>.
+     * This can be used by management systems on their GUI. The 
+     * <code>null</code> return value is allowed if there is no description for
+     * the specified Status Variable.
+     * <p>
+     * The given identifier does not contain the Monitorable PID, i.e. it 
+     * specifies the name and not the path of the Status Variable.
+     * 
+     * @param id the identifier of the <code>StatusVariable</code>, cannot be
+     *        <code>null</code> 
+     * @return the human readable description of this
+     *         <code>StatusVariable</code> or <code>null</code> if it is not
+     *         set
+     * @throws java.lang.IllegalArgumentException if <code>id</code> points to a
+     *         non-existing <code>StatusVariable</code>
+     */
+    public String getDescription(String id) throws IllegalArgumentException;
+}

Added: felix/trunk/deploymentadmin/src/main/java/org/osgi/service/monitor/MonitoringJob.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/osgi/service/monitor/MonitoringJob.java?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/osgi/service/monitor/MonitoringJob.java (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/osgi/service/monitor/MonitoringJob.java Wed Jan 30 08:46:24 2008
@@ -0,0 +1,126 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.monitor/src/org/osgi/service/monitor/MonitoringJob.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;
+
+/**
+ * A Monitoring Job is a request for scheduled or event based notifications on
+ * update of a set of <code>StatusVariable</code>s. The job is a data
+ * structure that holds a non-empty list of <code>StatusVariable</code> names,
+ * an identification of the initiator of the job, and the sampling parameters.
+ * There are two kinds of monitoring jobs: time based and change based. Time
+ * based jobs take samples of all <code>StatusVariable</code>s with a
+ * specified frequency. The number of samples to be taken before the job
+ * finishes may be specified. Change based jobs are only interested in the
+ * changes of the monitored <code>StatusVariable</code>s. In this case, the
+ * number of changes that must take place between two notifications can be
+ * specified.
+ * <p>
+ * The job can be started on the <code>MonitorAdmin</code> interface. Running
+ * the job (querying the <code>StatusVariable</code>s, listening to changes,
+ * and sending out notifications on updates) is the task of the
+ * <code>MonitorAdmin</code> implementation.
+ * <p>
+ * Whether a monitoring job keeps track dynamically of the
+ * <code>StatusVariable</code>s it monitors is not specified. This means that
+ * if we monitor a <code>StatusVariable</code> of a <code>Monitorable</code>
+ * service which disappears and later reappears then it is implementation
+ * specific whether we still receive updates of the <code>StatusVariable</code>
+ * changes or not.
+ */
+public interface MonitoringJob {
+    /**
+     * Stops a Monitoring Job. Note that a time based job can also stop
+     * automatically if the specified number of samples have been taken.
+     */
+    public void stop();
+
+    /**
+     * Returns the identitifier of the principal who initiated the job. This is
+     * set at the time when
+     * {@link MonitorAdmin#startJob MonitorAdmin.startJob()} method is called.
+     * This string holds the ServerID if the operation was initiated from a
+     * remote manager, or an arbitrary ID of the initiator entity in the local
+     * case (used for addressing notification events).
+     * 
+     * @return the ID of the initiator, cannot be <code>null</code>
+     */
+    public String getInitiator();
+
+    /**
+     * Returns the list of <code>StatusVariable</code> names that are the
+     * targets of this measurement job. For time based jobs, the
+     * <code>MonitorAdmin</code> will iterate through this list and query all
+     * <code>StatusVariable</code>s when its timer set by the job's frequency
+     * rate expires.
+     * 
+     * @return the target list of the measurement job in
+     *         [Monitorable_ID]/[StatusVariable_ID] format, cannot be
+     *         <code>null</code>
+     */
+    public String[] getStatusVariableNames();
+
+    /**
+     * Returns the delay (in seconds) between two samples. If this call returns
+     * N (greater than 0) then the <code>MonitorAdmin</code> queries each
+     * <code>StatusVariable</code> that belongs to this job every N seconds.
+     * The value 0 means that the job is not scheduled but event based: in this
+     * case instant notification on changes is requested (at every nth change of
+     * the value, as specified by the report count parameter).
+     * 
+     * @return the delay (in seconds) between samples, or 0 for change based
+     *         jobs
+     */
+    public int getSchedule();
+
+    /**
+     * Returns the number of times <code>MonitorAdmin</code> will query the
+     * <code>StatusVariable</code>s (for time based jobs), or the number of
+     * changes of a <code>StatusVariable</code> between notifications (for
+     * change based jobs). Time based jobs with non-zero report count will take
+     * <code>getReportCount()</code>*<code>getSchedule()</code> time to
+     * finish. Time based jobs with 0 report count and change based jobs do not
+     * stop automatically, but all jobs can be stopped with the {@link #stop}
+     * method.
+     * 
+     * @return the number of measurements to be taken, or the number of changes
+     *         between notifications
+     */
+    public int getReportCount();
+
+    /**
+     * Returns whether the job was started locally or remotely.  Jobs started by
+     * the clients of this API are always local, remote jobs can only be started
+     * using the Device Management Tree.
+     * 
+     * @return <code>true</code> if the job was started from the local device,
+     *         <code>false</code> if the job was initiated from a management 
+     *         server through the device management tree
+     */
+    public boolean isLocal();
+    
+    /**
+     * Returns whether the job is running.   A job is running until it is
+     * explicitely stopped, or, in case of time based jobs with a finite report
+     * count, until the given number of measurements have been made.
+     *   
+     * @return <code>true</code> if the job is still running, <code>false</code>
+     *         if it has finished
+     */
+    public boolean isRunning();
+}

Added: felix/trunk/deploymentadmin/src/main/java/org/osgi/service/monitor/StatusVariable.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/osgi/service/monitor/StatusVariable.java?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/osgi/service/monitor/StatusVariable.java (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/osgi/service/monitor/StatusVariable.java Wed Jan 30 08:46:24 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/src/main/java/org/osgi/service/monitor/package.html
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/osgi/service/monitor/package.html?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/osgi/service/monitor/package.html (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/osgi/service/monitor/package.html Wed Jan 30 08:46:24 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/src/main/java/org/osgi/service/monitor/packageinfo
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/osgi/service/monitor/packageinfo?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/osgi/service/monitor/packageinfo (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/osgi/service/monitor/packageinfo Wed Jan 30 08:46:24 2008
@@ -0,0 +1 @@
+version 1.0

Added: felix/trunk/deploymentadmin/src/main/java/org/osgi/service/prefs/BackingStoreException.java
URL: http://svn.apache.org/viewvc/felix/trunk/deploymentadmin/src/main/java/org/osgi/service/prefs/BackingStoreException.java?rev=616813&view=auto
==============================================================================
--- felix/trunk/deploymentadmin/src/main/java/org/osgi/service/prefs/BackingStoreException.java (added)
+++ felix/trunk/deploymentadmin/src/main/java/org/osgi/service/prefs/BackingStoreException.java Wed Jan 30 08:46:24 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();
+	}
+
+}