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