001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.transaction.file;
018
019import java.io.PrintWriter;
020import java.io.StringWriter;
021
022/**
023 * Signals any kind of error or failure state in a {@link ResourceManager}.
024 * 
025 * @version $Id: ResourceManagerException.java 493628 2007-01-07 01:42:48Z joerg $
026 */
027public class ResourceManagerException extends Exception implements ResourceManagerErrorCodes {
028
029    private static final int[] ERROR_CODES =
030        {
031            ERR_SYSTEM,
032            ERR_SYSTEM_INCONSISTENT,
033            ERR_NO_TX,
034            ERR_TXID_INVALID,
035            ERR_TX_INACTIVE,
036            ERR_TX_INCONSISTENT,
037            ERR_DUP_TX,
038            ERR_THREAD_INVALID,
039            ERR_ISOLATION_LEVEL_UNSUPPORTED,
040            ERR_RESOURCEID_INVALID,
041            ERR_RESOURCE_EXISTS,
042            ERR_NO_SUCH_RESOURCE,
043            ERR_LOCK,
044            ERR_NO_LOCK,
045            ERR_MARKED_FOR_ROLLBACK,
046            };
047
048    private static final String[] ERROR_CODE_STRINGS =
049        {
050            "ERR_SYSTEM",
051            "ERR_SYSTEM_INCONSISTENT",
052            "ERR_NO_TX",
053            "ERR_TXID_INVALID",
054            "ERR_TX_INACTIVE",
055            "ERR_TX_INCONSISTENT",
056            "ERR_DUP_TX",
057            "ERR_THREAD_INVALID",
058            "ERR_ISOLATION_LEVEL_UNSUPPORTED",
059            "ERR_RESOURCEID_INVALID",
060            "ERR_RESOURCE_EXISTS",
061            "ERR_NO_SUCH_RESOURCE",
062            "ERR_LOCK",
063            "ERR_NO_LOCK",
064            "ERR_MARKED_FOR_ROLLBACK",
065            };
066
067    private static final String[] ERROR_CODE_TEXTS =
068        {
069            "System error",
070            "Inconsistent system data",
071            "Unknown transaction",
072            "Invalid transaction id",
073            "Transaction inactive",
074            "Inconsistent transaction data",
075            "Duplicate transaction id",
076            "Thread of control is the one that not start tx",
077            "Isolation level unsupported",
078            "Specified resource id is invalid",
079            "Resource already exists",
080            "No such resource",
081            "Locking error",
082            "Could not acquire lock",
083            "Transaction already marked for rollback" };
084
085    public static final String ERR_UNKNOWN_TEXT = "Unknown error";
086    public static final String ERR_UNKNOWN_CODE = "ERR_UNKNOWN";
087
088    protected final int status;
089    protected final Object txId;
090
091    protected static final String composeMessage(String msg, int status, Object txId, Throwable cause) {
092        String message = composeMessage(msg, status, txId);
093        StringBuffer messageBuffer = new StringBuffer(message);
094        messageBuffer.append("\nCaused by: ");
095        StringWriter sw = new StringWriter();
096        cause.printStackTrace(new PrintWriter(sw));
097        messageBuffer.append(sw.getBuffer());
098        return messageBuffer.toString();
099    }
100    
101    protected static final String composeMessage(String msg, int status, Object txId) {
102        StringBuffer composed = new StringBuffer();
103        if (txId != null) {
104            composed.append(txId).append(": ");
105        }
106        if (msg != null) {
107            composed.append(msg);
108            if (status != -1) {
109                composed.append(" (").append(statusToCode(status)).append(')');
110            }
111        } else if (status != -1) {
112            composed.append(statusToText(status));
113        }
114
115        return composed.toString();
116    }
117
118    public static final String statusToText(int status) {
119        if (status == ERR_UNKNOWN) {
120            return ERR_UNKNOWN_TEXT;
121        } else {
122            int pos = -1;
123            for (int i = 0; i < ERROR_CODES.length; i++) {
124                int code = ERROR_CODES[i];
125                if (status == code) {
126                    pos = i;
127                    break;
128                }
129            }
130            if (pos == -1) {
131                return ERR_UNKNOWN_TEXT + ", code: " + status;
132            } else {
133                return ERROR_CODE_TEXTS[pos];
134            }
135        }
136    }
137
138    public static final String statusToCode(int status) {
139        if (status == ERR_UNKNOWN) {
140            return ERR_UNKNOWN_CODE;
141        } else {
142            int pos = -1;
143            for (int i = 0; i < ERROR_CODES.length; i++) {
144                int code = ERROR_CODES[i];
145                if (status == code) {
146                    pos = i;
147                    break;
148                }
149            }
150            if (pos == -1) {
151                return ERR_UNKNOWN_CODE + ": " + status;
152            } else {
153                return ERROR_CODE_STRINGS[pos];
154            }
155        }
156    }
157
158    public ResourceManagerException(String message, int status, Object txId) {
159        super(ResourceManagerException.composeMessage(message, status, txId));
160        this.status = status;
161        this.txId = txId;
162    }
163
164    public ResourceManagerException(int status, Object txId) {
165        this(null, status, txId);
166    }
167
168    public ResourceManagerException(String message) {
169        super(message);
170        this.status = ERR_UNKNOWN;
171        this.txId = null;
172    }
173
174    public ResourceManagerException(String message, int status, Object txId, Throwable cause) {
175        // XXX can not do this, as 1.3 Throwable does not allow cause in ctor :( 
176//        super(ResourceManagerException.composeMessage(message, status, txId), cause);
177        // for now format cause by ourselves
178        super(ResourceManagerException.composeMessage(message, status, txId, cause));
179        this.status = status;
180        this.txId = txId;
181    }
182
183    public ResourceManagerException(String message, int status, Throwable cause) {
184        this(message, status, null, cause);
185    }
186
187    public ResourceManagerException(String message, Throwable cause) {
188        this(message, ERR_UNKNOWN, cause);
189    }
190
191    public ResourceManagerException(int status, Object txId, Throwable cause) {
192        this(null, status, txId, cause);
193    }
194
195    public String statusToString() {
196        return ResourceManagerException.statusToText(status);
197    }
198
199    public int getStatus() {
200        return status;
201    }
202
203}