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     */
017    package org.apache.commons.transaction.file;
018    
019    import java.io.PrintWriter;
020    import 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     */
027    public 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    }