All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.osgi.service.dmt.DmtException Maven / Gradle / Ivy

There is a newer version: 0.10.0
Show newest version
/*
 * Copyright (c) OSGi Alliance (2004, 2013). 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.dmt;

import java.io.PrintStream;
import java.util.Vector;

/**
 * Checked exception received when a DMT operation fails. Beside the exception
 * message, a {@code DmtException} 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.
 * 

* 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. *

* The cause of the exception (if specified) can either be a single * {@code Throwable} 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} method of {@code DmtSession} that tries to close multiple * plugins, and has to report the exceptions of all failures. *

* Each constructor has two variants, one accepts a {@code String} node URI, the * other accepts a {@code String[]} 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. *

* Getter methods are provided to retrieve the values of the additional * parameters, and the {@code printStackTrace(PrintWriter)} method is extended * to print the stack trace of all causing throwables as well. * * @author $Id: d56c95a49eed00fce7fd6eadb7b6f5c41ae18588 $ */ 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. *

* 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. *

* 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. *

* 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: *

    *
  • an interior node operation is requested for a leaf node, or vice * versa (e.g. trying to retrieve the children of a leaf node)
  • *
  • an attempt is made to create a node where the parent is a leaf node
  • *
  • an attempt is made to rename or delete the root node of the tree
  • *
  • an attempt is made to rename or delete the root node of the session
  • *
  • 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
  • *
  • a node is copied to its descendant
  • *
  • the ACL of the root node is changed not to include Add rights for all * principals
  • *
*

* 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. *

* 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. *

* 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 operation failed because a specific limit was exceeded, * e.g. if a requested resource exceeds a size limit. *

* This error code corresponds to the OMA DM response status code 413 * "Request entity too large". * * @since 2.0 */ public static final int LIMIT_EXCEEDED = 413; /** * The requested command failed because the target URI is too long for what * the recipient is able or willing to process. *

* 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...} methods), or indirectly (during a {@code copy} * operation). *

* 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. *

* 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. *

* 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. *

* 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. *

* 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. *

* 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. *

* 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} * objects of the affected nodes, for example in the following situations: *

    *
  • creating, deleting or renaming a permanent node, or modifying its * type
  • *
  • creating an interior node where the meta-node defines it as a leaf, * or vice versa
  • *
  • 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} access * type)
  • *
  • any node creation or deletion that would violate the cardinality * constraints
  • *
  • any leaf node value setting that would violate the allowed formats, * values, mime types, etc.
  • *
  • any node creation that would violate the allowed node names
  • *
*

* This error code can also be used to indicate any other meta data * violation, even if it cannot be described by the {@code MetaNode} class. * For example, detecting a multi-node constraint violation while committing * an atomic session should result in this error. *

* 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} or syntactically invalid. This covers the following cases: *

    *
  • the URI or node name ends with the '\' or '/' character
  • *
  • the URI is an empty string (only invalid if the method does not * accept relative URIs)
  • *
  • the URI contains the segment "{@code .}" at a position * other than the beginning of the URI
  • *
  • the node name is "{@code ..}" or the URI contains such a * segment
  • *
  • the node name contains an unescaped '/' character
  • *
*

* See the {@link Uri#encode(String)} method for support on escaping invalid * characters in a URI. *

* 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. *

* 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. *

* 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: *

    *
  • an updating method within an atomic session can not be executed * because the underlying plugin is read-only or does not support atomic * writing
  • *
  • a commit operation at the end of an atomic session failed because one * of the underlying plugins failed to close
  • *
* 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. *

* 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 dependent. *

* 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} 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} if there is no * error message. */ private final String message; /** * The list of originating exceptions, or empty list or {@code null} 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} and {@code message} * parameters are optional. No originating exception is specified. * * @param uri the node on which the failed DMT operation was issued, or * {@code null} 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} * 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 message} and {@code cause} parameters are optional. * * @param uri the node on which the failed DMT operation was issued, or * {@code null} 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} * if there is no error message * @param cause the originating exception, or {@code null} 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 message} and {@code causes} parameters are optional. *

* 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} 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} * if there is no error message * @param causes the list of originating exceptions, or empty list or * {@code null} 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) { super((Throwable) null); 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} 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} * 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} 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} * if there is no error message * @param cause the originating exception, or {@code null} 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} 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} * if there is no error message * @param causes the list of originating exceptions, or empty list or * {@code null} 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()} don't require an URI, in this * case this method returns {@code null}. * * @return the URI of the node, or {@code null} */ 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}): * *

     *  <exception_code>[: '<uri>'][: <error_message>]
     * 
* * @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}, if this * exception is caused by one or more other exceptions (like a * {@code NullPointerException} 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} 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} 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 ""; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy