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 + * [EMAIL PROTECTED] DmtEventListener EventListeners} about important changes. Events are + * generated after every successful DMT change, and also when sessions are + * opened or closed. If a [EMAIL PROTECTED] 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 [EMAIL PROTECTED] #COPIED} or + * [EMAIL PROTECTED] #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 [EMAIL PROTECTED] 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 [EMAIL PROTECTED] 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 [EMAIL PROTECTED] #SESSION_OPENED} and + * [EMAIL PROTECTED] #SESSION_CLOSED}. + * <p> + * The method returns only those affected nodes that the caller has the GET + * permission for (or in case of [EMAIL PROTECTED] #COPIED} or [EMAIL PROTECTED] #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 [EMAIL PROTECTED] #COPIED} or [EMAIL PROTECTED] #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 + * [EMAIL PROTECTED] #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 [EMAIL PROTECTED] 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 + * [EMAIL PROTECTED] 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 + * "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 [EMAIL PROTECTED] #URI_TOO_LONG} or [EMAIL PROTECTED] #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 [EMAIL PROTECTED] 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 [EMAIL PROTECTED] #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 [EMAIL PROTECTED] 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 [EMAIL PROTECTED] #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 [EMAIL PROTECTED] 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>"; + } + } +} 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; + } +}
