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