001    /*
002    // $Id: OlapException.java 247 2009-06-20 05:52:40Z jhyde $
003    // This software is subject to the terms of the Eclipse Public License v1.0
004    // Agreement, available at the following URL:
005    // http://www.eclipse.org/legal/epl-v10.html.
006    // Copyright (C) 2006-2009 Julian Hyde
007    // All Rights Reserved.
008    // You must accept the terms of that agreement to use this software.
009    */
010    package org.olap4j;
011    
012    import java.sql.SQLException;
013    
014    /**
015     * <p>An exception describing an error accessing an OLAP database.</p>
016     *
017     * <p>Since olap4j extends JDBC, it is natural that <code>OlapException</code>
018     * should extend JDBC's {@link SQLException}. The implementation by an olap4j
019     * driver of a JDBC method which is declared to throw a SQLException may, if the
020     * driver chooses, throw instead an OlapException.</p>
021     *
022     * <p>OlapException provides some additional information to help an OLAP client
023     * identify the location of the error. This information is
024     *
025     * @author jhyde
026     * @version $Id: OlapException.java 247 2009-06-20 05:52:40Z jhyde $
027     * @since Oct 23, 2006
028     */
029    public class OlapException extends SQLException {
030        private Region region;
031        private Object context;
032    
033        /**
034         * Constructs a fully-specified <code>SQLException</code> object.
035         *
036         * @param reason a description of the exception
037         * @param sqlState an XOPEN or SQL 99 code identifying the exception
038         * @param vendorCode a database vendor-specific exception code
039         */
040        public OlapException(String reason, String sqlState, int vendorCode) {
041            super(reason, sqlState, vendorCode);
042        }
043    
044        /**
045         * Constructs an <code>SQLException</code> object with the given reason and
046         * SQLState; the <code>vendorCode</code> field defaults to 0.
047         *
048         * @param reason a description of the exception
049         * @param sqlState an XOPEN or SQL 99 code identifying the exception
050         */
051        public OlapException(String reason, String sqlState) {
052            super(reason, sqlState);
053        }
054    
055        /**
056         * Constructs an <code>SQLException</code> object with a reason;
057         * the <code>sqlState</code> field defaults to <code>null</code>, and
058         * the <code>vendorCode</code> field defaults to 0.
059         *
060         * @param reason a description of the exception
061         */
062        public OlapException(String reason) {
063            super(reason);
064        }
065    
066        /**
067         * Constructs an <code>SQLException</code> object;
068         * the <code>reason</code> field defaults to null,
069         * the <code>sqlState</code> field defaults to <code>null</code>, and
070         * the <code>vendorCode</code> field defaults to 0.
071         */
072        public OlapException() {
073            super();
074        }
075    
076        /**
077         * Constructs an <code>OlapException</code> object with a given
078         * <code>reason</code> and <code>cause</code>.
079         *
080         * @param  reason the detail message (which is saved for later retrieval
081         *         by the {@link #getMessage()} method).
082         * @param  cause the cause (which is saved for later retrieval by the
083         *         {@link #getCause()} method).  (A <tt>null</tt> value is
084         *         permitted, and indicates that the cause is nonexistent or
085         *         unknown.)
086         */
087        public OlapException(String reason, Throwable cause) {
088            // Cannot call super(reason, cause) because
089            // SQLException(String, Throwable) only exists from JDK 1.6.
090            super(reason);
091            initCause(cause);
092        }
093    
094        /**
095         * Sets the textual region where the exception occurred.
096         *
097         * @param region Textual region
098         */
099        public void setRegion(Region region) {
100            this.region = region;
101        }
102    
103        /**
104         * Returns the textual region where the exception occurred, or null if no
105         * region can be identified.
106         *
107         * @return Region where the exception occurred
108         */
109        public Region getRegion() {
110            return region;
111        }
112    
113        /**
114         * Sets the context where the exception occurred.
115         *
116         * @param context Context where the exception occurred
117         * @throws IllegalArgumentException If context is not a {@link Cell}
118         *   or a {@link Position}
119         */
120        public void setContext(Object context) {
121            if (!(context instanceof Cell)
122                && !(context instanceof Position))
123            {
124                throw new IllegalArgumentException(
125                    "expected Cell or Position");
126            }
127            this.context = context;
128        }
129    
130        /**
131         * Returns the context where the exception occurred.
132         * Typically a {@link Cell} or a {@link Position}, or null.
133         *
134         * @return context where the exception occurred, or null
135         */
136        public Object getContext() {
137            return context;
138        }
139    
140        /**
141         * Description of the position of a syntax or validation error in the source
142         * MDX string.
143         *
144         * <p>Row and column positions are 1-based and inclusive. For example,
145         * in</p>
146         *
147         * <blockquote>
148         * <pre>
149         * SELECT { [Measures].MEMBERS } ON COLUMNS,
150         *    { } ON ROWS
151         * FROM [Sales]
152         * </pre>
153         * </blockquote>
154         *
155         * <p>the <code>SELECT</code> keyword occupies positions (1, 1) through
156         * (1, 6), and would have a <code>Region(startLine=1, startColumn=1,
157         * endColumn=1, endLine=6)</code>.</p>
158         */
159        public static final class Region {
160            public final int startLine;
161            public final int startColumn;
162            public final int endLine;
163            public final int endColumn;
164    
165            protected Region(
166                int startLine,
167                int startColumn,
168                int endLine,
169                int endColumn)
170            {
171                this.startLine = startLine;
172                this.startColumn = startColumn;
173                this.endColumn = endLine;
174                this.endLine = endColumn;
175            }
176    
177            public String toString() {
178                if (startLine == endColumn && startColumn == endLine) {
179                    return "line " + startLine + ", column " + startColumn;
180                } else {
181                    return "line " + startLine + ", column " + startColumn
182                        + " through line " + endLine + ", column " + endColumn;
183                }
184            }
185        }
186    }
187    
188    // End OlapException.java