You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by ch...@apache.org on 2008/08/02 11:56:04 UTC

svn commit: r681945 [2/9] - in /felix/trunk/org.osgi.compendium: ./ doc/ src/main/java/info/ src/main/java/info/dmtree/ src/main/java/info/dmtree/notification/ src/main/java/info/dmtree/notification/spi/ src/main/java/info/dmtree/registry/ src/main/jav...

Added: felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/DmtEvent.java
URL: http://svn.apache.org/viewvc/felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/DmtEvent.java?rev=681945&view=auto
==============================================================================
--- felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/DmtEvent.java (added)
+++ felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/DmtEvent.java Sat Aug  2 02:56:01 2008
@@ -0,0 +1,140 @@
+/*
+ * $Header: /cvshome/build/info.dmtree/src/info/dmtree/DmtEvent.java,v 1.8 2006/07/04 12:12:16 tszeredi Exp $
+ *
+ * Copyright (c) OSGi Alliance (2004, 2006). All Rights Reserved.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package info.dmtree;
+
+/**
+ * Event class storing the details of a change in the tree.
+ * <code>DmtEvent</code> is used by <code>DmtAdmin</code> to notify registered
+ * {@link DmtEventListener EventListeners} about important changes. Events are
+ * generated after every successful DMT change, and also when sessions are
+ * opened or closed. If a {@link DmtSession} is opened in atomic mode, DMT
+ * events are only sent when the session is committed, when the changes are
+ * actually performed.
+ * <p>
+ * An event is generated for each group of nodes added, deleted, replaced,
+ * renamed or copied, in this order.  Events are also generated when sessions
+ * are opened and closed.
+ * <p>
+ * The <code>type</code> of the event describes the change that triggered the
+ * event delivery. Each event carries the unique identifier of the session in
+ * which the described change happened. The events describing changes in the DMT
+ * carry the list of affected nodes. In case of {@link #COPIED} or
+ * {@link #RENAMED} events, the event carries the list of new nodes as well.
+ * <p>
+ * When a <code>DmtEvent</code> is delivered to a listener, the event contains
+ * only those node URIs that the listener has access to. This access control
+ * decision is based on the principal specified when the listener was
+ * registered:
+ * <ul>
+ * <li> If the listener was registered specifying an explicit principal, using
+ * the {@link DmtAdmin#addEventListener(String, int, String, DmtEventListener)}
+ * method, then the target node ACLs should be checked for providing GET access
+ * to the specified principal;
+ * <li> When the listener was registered without an explicit principal then the
+ * listener needs GET {@link info.dmtree.security.DmtPermission} for
+ * the corresponding node.
+ * </ul>
+ */
+public interface DmtEvent {
+
+    /**
+     * Event type indicating nodes that were added.
+     */
+    int ADDED = 0x01;
+
+    /**
+     * Event type indicating nodes that were copied.
+     */
+    int COPIED = 0x02;
+
+    /**
+     * Event type indicating nodes that were deleted.
+     */
+    int DELETED = 0x04;
+
+    /**
+     * Event type indicating nodes that were renamed.
+     */
+    int RENAMED = 0x08;
+
+    /**
+     * Event type indicating nodes that were replaced.
+     */
+    int REPLACED = 0x10;
+
+    /**
+     * Event type indicating that a new session was opened.
+     */
+    int SESSION_OPENED = 0x20;
+
+    /**
+     * Event type indicating that a session was closed.  This type of event is
+     * sent when the session is closed by the client or becomes inactive for any
+     * other reason (session timeout, fatal errors in business methods, etc.).
+     */
+    int SESSION_CLOSED = 0x40;
+
+    /**
+     * This method returns the type of this event.
+     * 
+     * @return the type of this event.
+     */
+    int getType();
+
+    /**
+     * This method returns the identifier of the session in which this event
+     * took place. The ID is guaranteed to be unique on a machine.
+     * 
+     * @return the unique indetifier of the session that triggered the event
+     */
+    int getSessionId();
+
+    /**
+     * This method can be used to query the subject nodes of this event. The
+     * method returns <code>null</code> for {@link #SESSION_OPENED} and
+     * {@link #SESSION_CLOSED}.
+     * <p>
+     * The method returns only those affected nodes that the caller has the GET
+     * permission for (or in case of {@link #COPIED} or {@link #RENAMED} events,
+     * where the caller has GET permissions for either the source or the
+     * destination nodes). Therefore, it is possible that the method returns an
+     * empty array. All returned URIs are absolute.
+     * 
+     * @return the array of affected nodes
+     * @see #getNewNodes
+     */
+    String[] getNodes();
+
+    /**
+     * This method can be used to query the new nodes, when the type of the
+     * event is {@link #COPIED} or {@link #RENAMED}. For all other event types
+     * this method returns <code>null</code>.
+     * <p>
+     * The array returned by this method runs parallel to the array returned by
+     * {@link #getNodes}, the elements in the two arrays contain the source and
+     * destination URIs for the renamed or copied nodes in the same order. All
+     * returned URIs are absolute.
+     * <p>
+     * This method returns only those nodes where the caller has the GET
+     * permission for the source or destination node of the operation.
+     * Therefore, it is possible that the method returns an empty array.
+     * 
+     * @return the array of newly created nodes
+     */
+    String[] getNewNodes();
+}

Added: felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/DmtEventListener.java
URL: http://svn.apache.org/viewvc/felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/DmtEventListener.java?rev=681945&view=auto
==============================================================================
--- felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/DmtEventListener.java (added)
+++ felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/DmtEventListener.java Sat Aug  2 02:56:01 2008
@@ -0,0 +1,37 @@
+/*
+ * $Header: /cvshome/build/info.dmtree/src/info/dmtree/DmtEventListener.java,v 1.6 2006/07/04 12:12:16 tszeredi Exp $
+ *
+ * Copyright (c) OSGi Alliance (2004, 2006). All Rights Reserved.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package info.dmtree;
+
+/**
+ * Registered implementations of this class are notified via {@link DmtEvent}
+ * objects about important changes in the tree. Events are generated after every
+ * successful DMT change, and also when sessions are opened or closed. If a
+ * {@link DmtSession} is opened in atomic mode, DMT events are only sent when
+ * the session is committed, when the changes are actually performed.
+ */
+public interface DmtEventListener {
+
+    /**
+     * <code>DmtAdmin</code> uses this method to notify the registered
+     * listeners about the change. This method is called asynchronously from the
+     * actual event occurrence.
+     * 
+     * @param event the <code>DmtEvent</code> describing the change in detail
+     */
+    void changeOccurred(DmtEvent event);
+}

Added: felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/DmtException.java
URL: http://svn.apache.org/viewvc/felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/DmtException.java?rev=681945&view=auto
==============================================================================
--- felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/DmtException.java (added)
+++ felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/DmtException.java Sat Aug  2 02:56:01 2008
@@ -0,0 +1,639 @@
+/*
+ * $Header: /cvshome/build/info.dmtree/src/info/dmtree/DmtException.java,v 1.9 2006/07/12 21:21:37 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2004, 2006). All Rights Reserved.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package info.dmtree;
+
+import java.io.PrintStream;
+import java.util.Vector;
+
+/**
+ * Checked exception received when a DMT operation fails. Beside the exception
+ * message, a <code>DmtException</code> always contains an error code (one of
+ * the constants specified in this class), and may optionally contain the URI of
+ * the related node, and information about the cause of the exception.
+ * <p>
+ * Some of the error codes defined in this class have a corresponding error code
+ * defined in OMA DM, in these cases the name and numerical value from OMA DM is
+ * used. Error codes without counterparts in OMA DM were given numbers from a
+ * different range, starting from 1.
+ * <p>
+ * The cause of the exception (if specified) can either be a single
+ * <code>Throwable</code> instance, or a list of such instances if several
+ * problems occurred during the execution of a method. An example for the latter
+ * is the <code>close</code> method of <code>DmtSession</code> that tries to
+ * close multiple plugins, and has to report the exceptions of all failures.
+ * <p>
+ * Each constructor has two variants, one accepts a <code>String</code> node
+ * URI, the other accepts a <code>String[]</code> node path. The former is
+ * used by the DmtAdmin implementation, the latter by the plugins, who receive
+ * the node URI as an array of segment names. The constructors are otherwise
+ * identical.
+ * <p>
+ * Getter methods are provided to retrieve the values of the additional
+ * parameters, and the <code>printStackTrace(PrintWriter)</code> method is
+ * extended to print the stack trace of all causing throwables as well.
+ */
+public class DmtException extends Exception {
+    private static final long serialVersionUID = -63006267148118655L;
+
+    // ----- Public constants -----//
+
+    /**
+     * The originator's authentication credentials specify a principal with
+     * insufficient rights to complete the command.
+     * <p>
+     * This status code is used as response to device originated sessions if the
+     * remote management server cannot authorize the device to perform the
+     * requested operation.
+     * <p>
+     * This error code corresponds to the OMA DM response status code 401
+     * &quot;Unauthorized&quot;.
+     */
+    public static final int UNAUTHORIZED = 401;
+
+    /**
+     * The requested target node was not found. No indication is given as to
+     * whether this is a temporary or permanent condition, unless otherwise
+     * noted.
+     * <p>
+     * This is only used when the requested node name is valid, otherwise the
+     * more specific error codes {@link #URI_TOO_LONG} or {@link #INVALID_URI}
+     * are used. This error code corresponds to the OMA DM response status code
+     * 404 &quot;Not Found&quot;.
+     */
+    public static final int NODE_NOT_FOUND = 404;
+
+    /**
+     * The requested command is not allowed on the target node. This includes
+     * the following situations:
+     * <ul>
+     * <li>an interior node operation is requested for a leaf node, or vice
+     * versa (e.g. trying to retrieve the children of a leaf node)
+     * <li>an attempt is made to create a node where the parent is a leaf node
+     * <li>an attempt is made to rename or delete the root node of the tree
+     * <li>an attempt is made to rename or delete the root node of the session
+     * <li>a write operation (other than setting the ACL) is performed in a
+     * non-atomic write session on a node provided by a plugin that is read-only
+     * or does not support non-atomic writing
+     * <li>a node is copied to its descendant
+     * <li>the ACL of the root node is changed not to include Add rights for
+     * all principals
+     * </ul>
+     * <p>
+     * This error code corresponds to the OMA DM response status code 405
+     * &quot;Command not allowed&quot;.
+     */
+    public static final int COMMAND_NOT_ALLOWED = 405;
+
+    /**
+     * The requested command failed because an optional feature required by the
+     * command is not supported. For example, opening an atomic session might
+     * return this error code if the DmtAdmin implementation does not support
+     * transactions. Similarly, accessing the optional node properties (Title,
+     * Timestamp, Version, Size) might not succeed if either the DmtAdmin
+     * implementation or the underlying plugin does not support the property.
+     * <p>
+     * When getting or setting values for interior nodes (an optional
+     * optimization feature), a plugin can use this error code to indicate that
+     * the given interior node does not support values.
+     * <p>
+     * This error code corresponds to the OMA DM response status code 406
+     * &quot;Optional feature not supported&quot;.
+     */
+    public static final int FEATURE_NOT_SUPPORTED = 406;
+    
+    /**
+     * The requested command failed because the target URI or one of its
+     * segments is too long for what the recipient is able or willing to
+     * process, or the target URI contains too many segments. The length and
+     * segment number limits are implementation dependent, their minimum values
+     * can be found in the Non Functional Requirements section of the OSGi
+     * specification.
+     * <p>
+     * The {@link Uri#mangle(String)} method provides support for ensuring that
+     * a URI segment conforms to the length limits set by the implementation.
+     * <p>
+     * This error code corresponds to the OMA DM response status code 414
+     * &quot;URI too long&quot;.
+     * 
+     * @see "OSGi Service Platform, Mobile Specification Release 4"
+     */
+    public static final int URI_TOO_LONG = 414;
+
+    /**
+     * The requested node creation operation failed because the target already
+     * exists. This can occur if the node is created directly (with one of the
+     * <code>create...</code> methods), or indirectly (during a
+     * <code>copy</code> operation).
+     * <p>
+     * This error code corresponds to the OMA DM response status code 418
+     * &quot;Already exists&quot;.
+     */
+    public static final int NODE_ALREADY_EXISTS = 418;
+
+    /**
+     * The requested command failed because the principal associated with the
+     * session does not have adequate access control permissions (ACL) on the
+     * target. This can only appear in case of remote sessions, i.e. if the
+     * session is associated with an authenticated principal.
+     * <p>
+     * This error code corresponds to the OMA DM response status code 425
+     * &quot;Permission denied&quot;.
+     */
+    public static final int PERMISSION_DENIED = 425;
+
+    /**
+     * The recipient encountered an error which prevented it from fulfilling the
+     * request.
+     * <p>
+     * This error code is only used in situations not covered by any of the
+     * other error codes that a method may use. Some methods specify more
+     * specific error situations for this code, but it can generally be used for
+     * any unexpected condition that causes the command to fail.
+     * <p>
+     * This error code corresponds to the OMA DM response status code 500
+     * &quot;Command Failed&quot;.
+     */
+    public static final int COMMAND_FAILED = 500;
+
+    /**
+     * An error related to the recipient data store occurred while processing
+     * the request. This error code may be thrown by any of the methods
+     * accessing the tree, but whether it is really used depends on the
+     * implementation, and the data store it uses.
+     * <p>
+     * This error code corresponds to the OMA DM response status code 510
+     * &quot;Data store failure&quot;.
+     */
+    public static final int DATA_STORE_FAILURE = 510;
+
+    /**
+     * The rollback command was not completed successfully. The tree might be in
+     * an inconsistent state after this error.
+     * <p>
+     * This error code corresponds to the OMA DM response status code 516
+     * &quot;Atomic roll back failed&quot;.
+     */
+    public static final int ROLLBACK_FAILED = 516;
+    
+
+    /**
+     * A device initiated remote operation failed. This is used when the
+     * protocol adapter fails to send an alert for any reason.
+     * <p>
+     * Alert routing errors (that occur while looking for the proper protocol
+     * adapter to use) are indicated by {@link #ALERT_NOT_ROUTED}, this code is
+     * only for errors encountered while sending the routed alert. This error
+     * code does not correspond to any OMA DM response status code. It should be
+     * translated to the code 500 &quot;Command Failed&quot; when transferring
+     * over OMA DM.
+     */
+    public static final int REMOTE_ERROR = 1;
+
+    /**
+     * Operation failed because of meta data restrictions. This covers any
+     * attempted deviation from the parameters defined by the
+     * <code>MetaNode</code> objects of the affected nodes, for example in the
+     * following situations:
+     * <ul>
+     * <li>creating, deleting or renaming a permanent node, or modifying its
+     * type or value
+     * <li>creating an interior node where the meta-node defines it as a leaf,
+     * or vice versa
+     * <li>any operation on a node which does not have the required access type
+     * (e.g. executing a node that lacks the <code>MetaNode.CMD_EXECUTE</code>
+     * access type)
+     * <li>any node creation or deletion that would violate the cardinality
+     * constraints
+     * <li>any leaf node value setting that would violate the allowed formats,
+     * values, mime types, etc.
+     * <li>any node creation that would violate the allowed node names
+     * </ul>
+     * <p>
+     * This error code can also be used to indicate any other meta data
+     * violation, even if it cannot be described by the <code>MetaNode</code>
+     * class. For example, detecting a multi-node constraint violation while
+     * committing an atomic session should result in this error.
+     * <p>
+     * This error code does not correspond to any OMA DM response status code.
+     * It should be translated to the code 405 &quot;Command not allowed&quot;
+     * when transferring over OMA DM.
+     */
+    public static final int METADATA_MISMATCH = 2;
+
+    /**
+     * The requested command failed because the target URI or node name is
+     * <code>null</code> or syntactically invalid. This covers the following
+     * cases:
+     * <ul>
+     * <li>the URI or node name ends with the '\' or '/' character
+     * <li>the URI is an empty string (only invalid if the method does not 
+     * accept relative URIs)
+     * <li>the URI contains the segment &quot;<code>.</code>&quot; at a position
+     * other than the beginning of the URI
+     * <li>the node name is &quot;<code>..</code>&quot; or the URI contains such
+     * a segment
+     * <li>the node name is an empty string or the URI contains an empty segment
+     * <li>the node name contains an unescaped '/' character
+     * </ul>
+     * <p>
+     * See the {@link Uri#mangle(String)} method for support on escaping invalid
+     * characters in a URI.
+     * <p>
+     * This code is only used if the URI or node name does not match any of the
+     * criteria for {@link #URI_TOO_LONG}. This error code does not correspond
+     * to any OMA DM response status code. It should be translated to the code
+     * 404 &quot;Not Found&quot; when transferring over OMA DM.
+     */
+    public static final int INVALID_URI = 3;
+
+    /**
+     * An error occurred related to concurrent access of nodes. This can happen
+     * for example if a configuration node was deleted directly through the
+     * Configuration Admin service, while the node was manipulated via the tree.
+     * <p>
+     * This error code does not correspond to any OMA DM response status code.
+     * It should be translated to the code 500 &quot;Command Failed&quot; when
+     * transferring over OMA DM.
+     */
+    public static final int CONCURRENT_ACCESS = 4;
+
+    /**
+     * An alert can not be sent from the device to the given principal. This can
+     * happen if there is no Remote Alert Sender willing to forward the alert to
+     * the given principal, or if no principal was given and the DmtAdmin did
+     * not find an appropriate default destination.
+     * <p>
+     * This error code does not correspond to any OMA DM response status code.
+     * It should be translated to the code 500 &quot;Command Failed&quot; when
+     * transferring over OMA DM.
+     */
+    public static final int ALERT_NOT_ROUTED = 5;
+
+    /**
+     * A transaction-related error occurred in an atomic session. This error is
+     * caused by one of the following situations:
+     * <ul>
+     * <li>an updating method within an atomic session can not be executed
+     * because the underlying plugin is read-only or does not support atomic
+     * writing</li>
+     * <li>a commit operation at the end of an atomic session failed because
+     * one of the underlying plugins failed to close</li>
+     * </ul>
+     * The latter case may leave the tree in an inconsistent state due to the
+     * lack of a two-phase commit system, see {@link DmtSession#commit} for
+     * details.
+     * <p>
+     * This error code does not correspond to any OMA DM response status code.
+     * It should be translated to the code 500 &quot;Command Failed&quot; when
+     * transferring over OMA DM.
+     */
+    public static final int TRANSACTION_ERROR = 6;
+
+    /**
+     * Creation of a session timed out because of another ongoing session. The
+     * length of time while the DmtAdmin waits for the blocking session(s) to
+     * finish is implementation dependant.
+     * <p>
+     * This error code does not correspond to any OMA DM response status code.
+     * OMA has several status codes related to timeout, but these are meant to
+     * be used when a request times out, not if a session can not be
+     * established. This error code should be translated to the code 500
+     * &quot;Command Failed&quot; when transferring over OMA DM.
+     */
+    public static final int SESSION_CREATION_TIMEOUT = 7;
+
+    // ----- Content fields -----//
+
+    /**
+     * The URI of the node on which the failed DMT operation was issued, or
+     * <code>null</code> if the operation was not associated with a node.
+     */
+    private final String uri;
+
+    /**
+     * The error code of the failure, one of the constants defined in this
+     * class.
+     */
+    private final int code;
+
+    /**
+     * The message associated with the exception, or <code>null</code> if
+     * there is no error message.
+     */
+    private final String message;
+
+    /**
+     * The list of originating exceptions, or empty list or <code>null</code>
+     * if there are no originating exceptions.
+     */
+    private final Throwable[] causes;
+
+    /**
+     * Determines whether the exception is fatal or not. This is basically a
+     * two-state severity indicator, with the 'fatal' severity being the more
+     * serious one.
+     */
+    private final boolean fatal;
+
+    // ----- Constructors -----//
+
+    /**
+     * Create an instance of the exception. The <code>uri</code> and
+     * <code>message</code> parameters are optional. No originating exception
+     * is specified.
+     * 
+     * @param uri the node on which the failed DMT operation was issued, or
+     *        <code>null</code> if the operation is not associated with a node
+     * @param code the error code of the failure
+     * @param message the message associated with the exception, or
+     *        <code>null</code> if there is no error message
+     */
+    public DmtException(String uri, int code, String message) {
+        this(uri, code, message, new Throwable[0], false);
+    }
+
+    /**
+     * Create an instance of the exception, specifying the cause exception. The
+     * <code>uri</code>, <code>message</code> and <code>cause</code>
+     * parameters are optional.
+     * 
+     * @param uri the node on which the failed DMT operation was issued, or
+     *        <code>null</code> if the operation is not associated with a node
+     * @param code the error code of the failure
+     * @param message the message associated with the exception, or
+     *        <code>null</code> if there is no error message
+     * @param cause the originating exception, or <code>null</code> if there
+     *        is no originating exception
+     */
+    public DmtException(String uri, int code, String message, Throwable cause) {
+        this(uri, code, message, (cause == null) ? new Throwable[0]
+                : new Throwable[] { cause }, false);
+    }
+
+    /**
+     * Create an instance of the exception, specifying the list of cause
+     * exceptions and whether the exception is a fatal one. This constructor is
+     * meant to be used by plugins wishing to indicate that a serious error
+     * occurred which should invalidate the ongoing atomic session. The
+     * <code>uri</code>, <code>message</code> and <code>causes</code>
+     * parameters are optional.
+     * <p>
+     * If a fatal exception is thrown, no further business methods will be
+     * called on the originator plugin. In case of atomic sessions, all other
+     * open plugins will be rolled back automatically, except if the fatal
+     * exception was thrown during commit.
+     * 
+     * @param uri the node on which the failed DMT operation was issued, or
+     *        <code>null</code> if the operation is not associated with a node
+     * @param code the error code of the failure
+     * @param message the message associated with the exception, or
+     *        <code>null</code> if there is no error message
+     * @param causes the list of originating exceptions, or empty list or
+     *        <code>null</code> if there are no originating exceptions
+     * @param fatal whether the exception is fatal
+     */
+    public DmtException(String uri, int code, String message, Vector causes,
+            boolean fatal) {
+        this(uri, code, message, (causes == null) ? new Throwable[0]
+                : (Throwable[]) causes.toArray(new Throwable[causes.size()]),
+                fatal);
+    }
+    
+    private DmtException(String uri, int code, String message, 
+            Throwable[] causes, boolean fatal) {
+        this.uri = uri;
+        this.code = code;
+        this.message = message;
+        this.causes = causes;
+        this.fatal = fatal;
+    }
+
+    /**
+     * Create an instance of the exception, specifying the target node as an
+     * array of path segments. This method behaves in exactly the same way as if
+     * the path was given as a URI string.
+     * 
+     * @param path the path of the node on which the failed DMT operation was
+     *        issued, or <code>null</code> if the operation is not associated
+     *        with a node
+     * @param code the error code of the failure
+     * @param message the message associated with the exception, or
+     *        <code>null</code> if there is no error message
+     * @see #DmtException(String, int, String)
+     */
+    public DmtException(String[] path, int code, String message) {
+        this(pathToUri(path), code, message);
+    }
+
+    /**
+     * Create an instance of the exception, specifying the target node as an
+     * array of path segments, and specifying the cause exception. This method
+     * behaves in exactly the same way as if the path was given as a URI string.
+     * 
+     * @param path the path of the node on which the failed DMT operation was
+     *        issued, or <code>null</code> if the operation is not associated
+     *        with a node
+     * @param code the error code of the failure
+     * @param message the message associated with the exception, or
+     *        <code>null</code> if there is no error message
+     * @param cause the originating exception, or <code>null</code> if there
+     *        is no originating exception
+     * @see #DmtException(String, int, String, Throwable)
+     */
+    public DmtException(String[] path, int code, String message, Throwable cause) {
+        this(pathToUri(path), code, message, cause);
+    }
+
+    /**
+     * Create an instance of the exception, specifying the target node as an
+     * array of path segments, the list of cause exceptions, and whether the
+     * exception is a fatal one. This method behaves in exactly the same way as
+     * if the path was given as a URI string.
+     * 
+     * @param path the path of the node on which the failed DMT operation was
+     *        issued, or <code>null</code> if the operation is not associated
+     *        with a node
+     * @param code the error code of the failure
+     * @param message the message associated with the exception, or
+     *        <code>null</code> if there is no error message
+     * @param causes the list of originating exceptions, or empty list or
+     *        <code>null</code> if there are no originating exceptions
+     * @param fatal whether the exception is fatal
+     * @see #DmtException(String, int, String, Vector, boolean)
+     */
+    public DmtException(String[] path, int code, String message, Vector causes,
+            boolean fatal) {
+        this(pathToUri(path), code, message, causes, fatal);
+    }
+
+    // ----- Public methods -----//
+
+    /**
+     * Get the node on which the failed DMT operation was issued. Some
+     * operations like <code>DmtSession.close()</code> don't require an URI,
+     * in this case this method returns <code>null</code>.
+     * 
+     * @return the URI of the node, or <code>null</code>
+     */
+    public String getURI() {
+        return uri;
+    }
+
+    /**
+     * Get the error code associated with this exception. Most of the error
+     * codes within this exception correspond to OMA DM error codes.
+     * 
+     * @return the error code
+     */
+    public int getCode() {
+        return code;
+    }
+
+    /**
+     * Get the message associated with this exception. The returned string also
+     * contains the associated URI (if any) and the exception code. The
+     * resulting message has the following format (parts in square brackets are
+     * only included if the field inside them is not <code>null</code>):
+     * 
+     * <pre>
+     *  &lt;exception_code&gt;[: '&lt;uri&gt;'][: &lt;error_message&gt;]
+     * </pre>
+     * 
+     * @return the error message in the format described above
+     */
+    public String getMessage() {
+        StringBuffer sb = new StringBuffer(getCodeText(code));
+        if (uri != null)
+            sb.append(": '").append(uri).append('\'');
+        if (message != null)
+            sb.append(": ").append(message);
+
+        return sb.toString();
+    }
+
+    /**
+     * Get the cause of this exception. Returns non-<code>null</code>, if
+     * this exception is caused by one or more other exceptions (like a
+     * <code>NullPointerException</code> in a DmtPlugin). If there are more
+     * than one cause exceptions, the first one is returned.
+     * 
+     * @return the cause of this exception, or <code>null</code> if no cause
+     *         was given
+     */
+    public Throwable getCause() {
+        return causes.length == 0 ? null : causes[0];
+    }
+
+    /**
+     * Get all causes of this exception. Returns the causing exceptions in an
+     * array. If no cause was specified, an empty array is returned.
+     * 
+     * @return the list of causes of this exception
+     */
+    public Throwable[] getCauses() {
+        return (Throwable[]) causes.clone();
+    }
+
+    /**
+     * Check whether this exception is marked as fatal in the session. Fatal
+     * exceptions trigger an automatic rollback of atomic sessions.
+     * 
+     * @return whether the exception is marked as fatal
+     */
+    public boolean isFatal() {
+        return fatal;
+    }
+
+    /**
+     * Prints the exception and its backtrace to the specified print stream. Any
+     * causes that were specified for this exception are also printed, together
+     * with their backtraces.
+     * 
+     * @param s <code>PrintStream</code> to use for output
+     */
+    public void printStackTrace(PrintStream s) {
+        super.printStackTrace(s);
+        for (int i = 0; i<causes.length; i++) {
+            s.print("Caused by" + (i > 0 ? " (" + (i+1) + ")" : "") + ": ");
+            causes[i].printStackTrace(s);
+        }
+    }
+
+    // ----- Utility methods -----//
+
+    /**
+     * Converts the given path, given as an array of path segments, to a single
+     * URI string.
+     * 
+     * @param path the path to convert
+     * @return the URI string representing the same node as the given path
+     */
+    static String pathToUri(String[] path) {
+        if (path == null)
+            return null;
+
+        return Uri.toUri(path);
+    }
+
+    /**
+     * Returns the name of the given error code.
+     * 
+     * @param code the error code
+     * @return a string containing the error code name
+     */
+    private static String getCodeText(int code) {
+        // todo sync codes
+        switch (code) {
+        case NODE_NOT_FOUND:
+            return "NODE_NOT_FOUND";
+        case COMMAND_NOT_ALLOWED:
+            return "COMMAND_NOT_ALLOWED";
+        case FEATURE_NOT_SUPPORTED:
+            return "FEATURE_NOT_SUPPORTED";
+        case URI_TOO_LONG:
+            return "URI_TOO_LONG";
+        case NODE_ALREADY_EXISTS:
+            return "NODE_ALREADY_EXISTS";
+        case PERMISSION_DENIED:
+            return "PERMISSION_DENIED";
+        case COMMAND_FAILED:
+            return "COMMAND_FAILED";
+        case DATA_STORE_FAILURE:
+            return "DATA_STORE_FAILURE";
+        case ROLLBACK_FAILED:
+            return "ROLLBACK_FAILED";
+
+        case REMOTE_ERROR:
+            return "REMOTE_ERROR";
+        case METADATA_MISMATCH:
+            return "METADATA_MISMATCH";
+        case INVALID_URI:
+            return "INVALID_URI";
+        case CONCURRENT_ACCESS:
+            return "CONCURRENT_ACCESS";
+        case ALERT_NOT_ROUTED:
+            return "ALERT_NOT_ROUTED";
+        case TRANSACTION_ERROR:
+            return "TRANSACTION_ERROR";
+        case SESSION_CREATION_TIMEOUT:
+            return "SESSION_CREATION_TIMEOUT";
+        default:
+            return "<unknown code>";
+        }
+    }
+}

Added: felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/DmtIllegalStateException.java
URL: http://svn.apache.org/viewvc/felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/DmtIllegalStateException.java?rev=681945&view=auto
==============================================================================
--- felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/DmtIllegalStateException.java (added)
+++ felix/trunk/org.osgi.compendium/src/main/java/info/dmtree/DmtIllegalStateException.java Sat Aug  2 02:56:01 2008
@@ -0,0 +1,84 @@
+/*
+ * $Header: /cvshome/build/info.dmtree/src/info/dmtree/DmtIllegalStateException.java,v 1.4 2006/07/13 13:42:12 tszeredi Exp $
+ *
+ * Copyright (c) OSGi Alliance (2006). All Rights Reserved.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package info.dmtree;
+
+/**
+ * Unchecked illegal state exception. This class is used in DMT because 
+ * java.lang.IllegalStateException does not exist in CLDC.
+ */
+public class DmtIllegalStateException extends RuntimeException {
+    private static final long serialVersionUID = 2015244852018469700L;
+
+    /**
+     * Nested exception.
+     */
+    private final Throwable cause;
+
+    /**
+     * Create an instance of the exception with no message.
+     */
+    public DmtIllegalStateException() {
+        super();
+        cause = null;
+    }
+
+    /**
+     * Create an instance of the exception with the specified message.
+     * 
+     * @param message the reason for the exception
+     */
+    public DmtIllegalStateException(String message) {
+        super(message);
+        cause = null;
+    }
+
+    /**
+     * Create an instance of the exception with the specified cause exception
+     * and no message.
+     * 
+     * @param cause the cause of the exception
+     */
+    public DmtIllegalStateException(Throwable cause) {
+        super();
+        this.cause = cause;
+    }
+
+    /**
+     * Create an instance of the exception with the specified message and cause
+     * exception.
+     * 
+     * @param message the reason for the exception
+     * @param cause the cause of the exception
+     */
+    public DmtIllegalStateException(String message, Throwable cause) {
+        super(message);
+        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
+     */
+    public Throwable getCause() {
+        return cause;
+    }
+}