001    /*
002    // $Id: //open/mondrian-release/3.1/src/main/mondrian/olap4j/MondrianOlap4jCell.java#4 $
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) 2007-2009 Julian Hyde
007    // All Rights Reserved.
008    // You must accept the terms of that agreement to use this software.
009    */
010    package mondrian.olap4j;
011    
012    import org.olap4j.*;
013    import org.olap4j.metadata.Property;
014    
015    import javax.sql.DataSource;
016    import java.util.*;
017    import java.sql.*;
018    import java.lang.reflect.Proxy;
019    
020    import mondrian.util.DelegatingInvocationHandler;
021    
022    /**
023     * Implementation of {@link Cell}
024     * for the Mondrian OLAP engine.
025     *
026     * @author jhyde
027     * @version $Id: //open/mondrian-release/3.1/src/main/mondrian/olap4j/MondrianOlap4jCell.java#4 $
028     * @since May 24, 2007
029     */
030    class MondrianOlap4jCell implements Cell {
031        private final int[] coordinates;
032        private final MondrianOlap4jCellSet olap4jCellSet;
033        private final mondrian.olap.Cell cell;
034    
035        /**
036         * Creates a MondrianOlap4jCell.
037         *
038         * @param coordinates Coordinates
039         * @param olap4jCellSet Cell set
040         * @param cell Cell in native Mondrian representation
041         */
042        MondrianOlap4jCell(
043            int[] coordinates,
044            MondrianOlap4jCellSet olap4jCellSet,
045            mondrian.olap.Cell cell)
046        {
047            assert coordinates != null;
048            assert olap4jCellSet != null;
049            assert cell != null;
050            this.coordinates = coordinates;
051            this.olap4jCellSet = olap4jCellSet;
052            this.cell = cell;
053        }
054    
055        public CellSet getCellSet() {
056            return olap4jCellSet;
057        }
058    
059        public int getOrdinal() {
060            return (Integer) cell.getPropertyValue(
061                mondrian.olap.Property.CELL_ORDINAL.name);
062        }
063    
064        public List<Integer> getCoordinateList() {
065            ArrayList<Integer> list = new ArrayList<Integer>(coordinates.length);
066            for (int coordinate : coordinates) {
067                list.add(coordinate);
068            }
069            return list;
070        }
071    
072        public Object getPropertyValue(Property property) {
073            // We assume that mondrian properties have the same name as olap4j
074            // properties.
075            return cell.getPropertyValue(property.getName());
076        }
077    
078        public boolean isEmpty() {
079            // FIXME
080            return cell.isNull();
081        }
082    
083        public boolean isError() {
084            return cell.isError();
085        }
086    
087        public boolean isNull() {
088            return cell.isNull();
089        }
090    
091        public double getDoubleValue() throws OlapException {
092            Object o = cell.getValue();
093            if (o instanceof Number) {
094                Number number = (Number) o;
095                return number.doubleValue();
096            }
097            throw olap4jCellSet.olap4jStatement.olap4jConnection.helper
098                .createException(this, "not a number");
099        }
100    
101        public String getErrorText() {
102            Object o = cell.getValue();
103            if (o instanceof Throwable) {
104                return ((Throwable) o).getMessage();
105            } else {
106                return null;
107            }
108        }
109    
110        public Object getValue() {
111            return cell.getValue();
112        }
113    
114        public String getFormattedValue() {
115            return cell.getFormattedValue();
116        }
117    
118        public ResultSet drillThrough() throws OlapException {
119            if (!cell.canDrillThrough()) {
120                return null;
121            }
122            final String sql = cell.getDrillThroughSQL(false);
123            final MondrianOlap4jConnection olap4jConnection =
124                this.olap4jCellSet.olap4jStatement.olap4jConnection;
125            final DataSource dataSource =
126                olap4jConnection.connection.getDataSource();
127            try {
128                final Connection connection = dataSource.getConnection();
129                final Statement statement = connection.createStatement();
130                final ResultSet resultSet = statement.executeQuery(sql);
131    
132                // To prevent a connection leak, wrap the result set in a proxy
133                // which automatically closes the connection (and hence also the
134                // statement and result set) when the result set is closed.
135                // The caller still has to remember to call ResultSet.close(), of
136                // course.
137                return (ResultSet) Proxy.newProxyInstance(
138                    null,
139                    new Class<?>[] {ResultSet.class},
140                    new MyDelegatingInvocationHandler(resultSet));
141            } catch (SQLException e) {
142                throw olap4jConnection.helper.toOlapException(e);
143            }
144        }
145    
146        public void setValue(
147            Object newValue,
148            AllocationPolicy allocationPolicy,
149            Object... allocationArgs)
150        {
151            throw new UnsupportedOperationException("writeback not yet supported");
152        }
153    
154        // must be public for reflection to work
155        public static class MyDelegatingInvocationHandler
156            extends DelegatingInvocationHandler
157        {
158            private final ResultSet resultSet;
159    
160            /**
161             * Creates a MyDelegatingInvocationHandler.
162             *
163             * @param resultSet Result set
164             */
165            MyDelegatingInvocationHandler(ResultSet resultSet) {
166                this.resultSet = resultSet;
167            }
168    
169            protected Object getTarget() {
170                return resultSet;
171            }
172    
173            /**
174             * Helper method to implement {@link java.sql.ResultSet#close()}.
175             *
176             * @throws SQLException on error
177             */
178            public void close() throws SQLException {
179                resultSet.getStatement().getConnection().close();
180            }
181        }
182    }
183    
184    // End MondrianOlap4jCell.java