FELIX-514 Updated compendium bundle to R4.1 OSGi API
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@681945 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/org.osgi.compendium/src/main/java/info/dmtree/DmtException.java b/org.osgi.compendium/src/main/java/info/dmtree/DmtException.java
new file mode 100644
index 0000000..c723bc0
--- /dev/null
+++ b/org.osgi.compendium/src/main/java/info/dmtree/DmtException.java
@@ -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
+ * "Unauthorized".
+ */
+ 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 "Not Found".
+ */
+ 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
+ * "Command not allowed".
+ */
+ 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
+ * "Optional feature not supported".
+ */
+ 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
+ * "URI too long".
+ *
+ * @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
+ * "Already exists".
+ */
+ 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
+ * "Permission denied".
+ */
+ 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
+ * "Command Failed".
+ */
+ 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
+ * "Data store failure".
+ */
+ 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
+ * "Atomic roll back failed".
+ */
+ 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 "Command Failed" 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 "Command not allowed"
+ * 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 "<code>.</code>" at a position
+ * other than the beginning of the URI
+ * <li>the node name is "<code>..</code>" 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 "Not Found" 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 "Command Failed" 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 "Command Failed" 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 "Command Failed" 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
+ * "Command Failed" 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>
+ * <exception_code>[: '<uri>'][: <error_message>]
+ * </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>";
+ }
+ }
+}