001    /*
002    // $Id: OlapException.java 485 2012-01-17 06:57:57Z jhyde $
003    //
004    // Licensed to Julian Hyde under one or more contributor license
005    // agreements. See the NOTICE file distributed with this work for
006    // additional information regarding copyright ownership.
007    //
008    // Julian Hyde licenses this file to you under the Apache License,
009    // Version 2.0 (the "License"); you may not use this file except in
010    // compliance with the License. You may obtain a copy of the License at:
011    //
012    // http://www.apache.org/licenses/LICENSE-2.0
013    //
014    // Unless required by applicable law or agreed to in writing, software
015    // distributed under the License is distributed on an "AS IS" BASIS,
016    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017    // See the License for the specific language governing permissions and
018    // limitations under the License.
019    */
020    package org.olap4j;
021    
022    import java.sql.*;
023    
024    /**
025     * <p>An exception describing an error accessing an OLAP database.</p>
026     *
027     * <p>Since olap4j extends JDBC, it is natural that <code>OlapException</code>
028     * should extend JDBC's {@link SQLException}. The implementation by an olap4j
029     * driver of a JDBC method which is declared to throw a SQLException may, if the
030     * driver chooses, throw instead an OlapException.</p>
031     *
032     * <p>OlapException provides some additional information to help an OLAP client
033     * identify the location of the error. This information is
034     *
035     * @author jhyde
036     * @version $Id: OlapException.java 485 2012-01-17 06:57:57Z jhyde $
037     * @since Oct 23, 2006
038     */
039    public class OlapException extends SQLException {
040        private Region region;
041        private Object context;
042    
043        /**
044         * Constructs an <code>OlapException</code> object with a given
045         * <code>reason</code>, <code>SQLState</code>  and
046         * <code>vendorCode</code>.
047         *
048         * @param reason a description of the exception
049         * @param sqlState an XOPEN or SQL 99 code identifying the exception
050         * @param vendorCode a database vendor-specific exception code
051         */
052        public OlapException(String reason, String sqlState, int vendorCode) {
053            super(reason, sqlState, vendorCode);
054        }
055    
056        /**
057         * Constructs an <code>OlapException</code> object with the given reason and
058         * SQLState; the <code>vendorCode</code> field defaults to 0.
059         *
060         * @param reason a description of the exception
061         * @param sqlState an XOPEN or SQL 99 code identifying the exception
062         */
063        public OlapException(String reason, String sqlState) {
064            super(reason, sqlState);
065        }
066    
067        /**
068         * Constructs an <code>OlapException</code> object with a reason;
069         * the <code>sqlState</code> field defaults to <code>null</code>, and
070         * the <code>vendorCode</code> field defaults to 0.
071         *
072         * @param reason a description of the exception
073         */
074        public OlapException(String reason) {
075            super(reason);
076        }
077    
078        /**
079         * Constructs an <code>OlapException</code> object;
080         * the <code>reason</code> field defaults to null,
081         * the <code>sqlState</code> field defaults to <code>null</code>, and
082         * the <code>vendorCode</code> field defaults to 0.
083         */
084        public OlapException() {
085            super();
086        }
087    
088        /**
089         * Constructs an <code>OlapException</code> object with a given
090         * <code>cause</code>.
091         * The <code>SQLState</code> is initialized
092         * to <code>null</code> and the vendor code is initialized to 0.
093         * The <code>reason</code>  is initialized to <code>null</code> if
094         * <code>cause==null</code> or to <code>cause.toString()</code> if
095         * <code>cause!=null</code>.
096         * <p>
097         * @param cause the underlying reason for this <code>OlapException</code>
098         * (which is saved for later retrieval by the <code>getCause()</code>
099         * method); may be null indicating the cause is non-existent or unknown.
100         */
101        public OlapException(Throwable cause) {
102            super();
103            initCause(cause);
104        }
105    
106        /**
107         * Constructs an <code>OlapException</code> object with a given
108         * <code>reason</code> and <code>cause</code>.
109         *
110         * @param  reason the detail message (which is saved for later retrieval
111         *         by the {@link #getMessage()} method).
112         * @param  cause the cause (which is saved for later retrieval by the
113         *         {@link #getCause()} method).  (A <tt>null</tt> value is
114         *         permitted, and indicates that the cause is nonexistent or
115         *         unknown.)
116         */
117        public OlapException(String reason, Throwable cause) {
118            // Cannot call super(reason, cause) because
119            // SQLException(String, Throwable) only exists from JDK 1.6.
120            super(reason);
121            initCause(cause);
122        }
123    
124        /**
125         * Constructs an <code>OlapException</code> object with a given
126         * <code>reason</code>, <code>SQLState</code> and  <code>cause</code>.
127         * The vendor code is initialized to 0.
128         *
129         * @param reason a description of the exception.
130         * @param sqlState an XOPEN or SQL:2003 code identifying the exception
131         * @param cause the underlying reason for this <code>OlapException</code>
132         * (which is saved for later retrieval by the
133         * <code>getCause()</code> method); may be null indicating
134         *     the cause is non-existent or unknown.
135         */
136        public OlapException(String reason, String sqlState, Throwable cause) {
137            // Cannot call SQLException(String, String, Throwable); it only
138            // exists from JDK 1.6
139            super(reason, sqlState);
140            initCause(cause);
141        }
142    
143        /**
144         * Constructs an <code>OlapException</code> object with a given
145         * <code>reason</code>, <code>SQLState</code>, <code>vendorCode</code>
146         * and  <code>cause</code>.
147         *
148         * @param reason a description of the exception
149         * @param sqlState an XOPEN or SQL:2003 code identifying the exception
150         * @param vendorCode a database vendor-specific exception code
151         * @param cause the underlying reason for this <code>OlapException</code>
152         * (which is saved for later retrieval by the <code>getCause()</code>
153         * method);
154         * may be null indicating the cause is non-existent or unknown.
155         */
156        public OlapException(
157            String reason,
158            String sqlState,
159            int vendorCode,
160            Throwable cause)
161        {
162            // Cannot call SQLException(String, String, int, Throwable); it only
163            // exists from JDK 1.6
164            super(reason, sqlState, vendorCode);
165            initCause(cause);
166        }
167    
168        /**
169         * Sets the textual region where the exception occurred.
170         *
171         * @param region Textual region
172         */
173        public void setRegion(Region region) {
174            this.region = region;
175        }
176    
177        /**
178         * Returns the textual region where the exception occurred, or null if no
179         * region can be identified.
180         *
181         * @return Region where the exception occurred
182         */
183        public Region getRegion() {
184            return region;
185        }
186    
187        /**
188         * Sets the context where the exception occurred.
189         *
190         * @param context Context where the exception occurred
191         * @throws IllegalArgumentException If context is not a {@link Cell}
192         *   or a {@link Position}
193         */
194        public void setContext(Object context) {
195            if (!(context instanceof Cell)
196                && !(context instanceof Position))
197            {
198                throw new IllegalArgumentException(
199                    "expected Cell or Position");
200            }
201            this.context = context;
202        }
203    
204        /**
205         * Returns the context where the exception occurred.
206         * Typically a {@link Cell} or a {@link Position}, or null.
207         *
208         * @return context where the exception occurred, or null
209         */
210        public Object getContext() {
211            return context;
212        }
213    
214        /**
215         * Description of the position of a syntax or validation error in the source
216         * MDX string.
217         *
218         * <p>Row and column positions are 1-based and inclusive. For example,
219         * in</p>
220         *
221         * <blockquote>
222         * <pre>
223         * SELECT { [Measures].MEMBERS } ON COLUMNS,
224         *    { } ON ROWS
225         * FROM [Sales]
226         * </pre>
227         * </blockquote>
228         *
229         * <p>the <code>SELECT</code> keyword occupies positions (1, 1) through
230         * (1, 6), and would have a <code>Region(startLine=1, startColumn=1,
231         * endColumn=1, endLine=6)</code>.</p>
232         */
233        public static final class Region {
234            public final int startLine;
235            public final int startColumn;
236            public final int endLine;
237            public final int endColumn;
238    
239            protected Region(
240                int startLine,
241                int startColumn,
242                int endLine,
243                int endColumn)
244            {
245                this.startLine = startLine;
246                this.startColumn = startColumn;
247                this.endColumn = endLine;
248                this.endLine = endColumn;
249            }
250    
251            public String toString() {
252                if (startLine == endColumn && startColumn == endLine) {
253                    return "line " + startLine + ", column " + startColumn;
254                } else {
255                    return "line " + startLine + ", column " + startColumn
256                        + " through line " + endLine + ", column " + endColumn;
257                }
258            }
259        }
260    }
261    
262    // End OlapException.java