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*/
020package org.olap4j;
021
022import 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 */
039public 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