From 1e25fee24d25bedad3b3bb552a4ee4f58f6bbb5b Mon Sep 17 00:00:00 2001 From: Julian Hyde Date: Thu, 14 Aug 2008 22:22:01 +0000 Subject: [PATCH] Update source code to enforce coding standards (spaces, tabs, braces, etc.). No functionality changes. git-svn-id: https://olap4j.svn.sourceforge.net/svnroot/olap4j/trunk@109 c6a108a4-781c-0410-a6c6-c2d559e19af0 --- src/org/olap4j/CellSetAxisMetaData.java | 2 +- src/org/olap4j/OlapConnection.java | 2 +- src/org/olap4j/OlapDataSource.java | 78 +- src/org/olap4j/OlapDatabaseMetaData.java | 4 +- src/org/olap4j/Position.java | 96 +- .../olap4j/driver/xmla/EmptyResultSet.java | 1470 +++---- src/org/olap4j/driver/xmla/Factory.java | 108 +- .../olap4j/driver/xmla/FactoryJdbc3Impl.java | 258 +- .../olap4j/driver/xmla/FactoryJdbc4Impl.java | 1612 ++++---- .../olap4j/driver/xmla/MetadataReader.java | 176 +- .../olap4j/driver/xmla/XmlaOlap4jCatalog.java | 4 +- .../olap4j/driver/xmla/XmlaOlap4jCellSet.java | 2730 ++++++------- .../xmla/XmlaOlap4jCellSetAxisMetaData.java | 138 +- .../xmla/XmlaOlap4jCellSetMetaData.java | 436 +- .../driver/xmla/XmlaOlap4jConnection.java | 3498 +++++++++-------- .../olap4j/driver/xmla/XmlaOlap4jCube.java | 10 +- .../xmla/XmlaOlap4jDatabaseMetaData.java | 2290 +++++------ .../olap4j/driver/xmla/XmlaOlap4jDriver.java | 33 +- .../xmla/XmlaOlap4jPreparedStatement.java | 874 ++-- .../driver/xmla/XmlaOlap4jProperty.java | 4 +- .../olap4j/driver/xmla/XmlaOlap4jSchema.java | 178 +- .../driver/xmla/XmlaOlap4jStatement.java | 768 ++-- .../olap4j/driver/xmla/XmlaOlap4jUtil.java | 6 +- .../driver/xmla/cache/XmlaOlap4jCache.java | 187 +- .../xmla/cache/XmlaOlap4jCacheElement.java | 140 +- .../XmlaOlap4jConcurrentMemoryCache.java | 619 +-- .../XmlaOlap4jInvalidStateException.java | 52 +- .../cache/XmlaOlap4jNamedMemoryCache.java | 467 +-- .../xmla/cache/XmlaOlap4jSHAEncoder.java | 127 +- .../proxy/XmlaOlap4jAbstractHttpProxy.java | 476 ++- .../xmla/proxy/XmlaOlap4jCachedProxy.java | 95 +- .../xmla/proxy/XmlaOlap4jCookieManager.java | 502 +-- .../xmla/proxy/XmlaOlap4jHttpProxy.java | 214 +- .../driver/xmla/proxy/XmlaOlap4jProxy.java | 96 +- src/org/olap4j/impl/ArrayNamedListImpl.java | 108 +- src/org/olap4j/impl/Olap4jUtil.java | 34 +- src/org/olap4j/mdx/ParseTreeVisitor.java | 2 +- src/org/olap4j/mdx/ParseTreeWriter.java | 2 +- src/org/olap4j/mdx/parser/MdxValidator.java | 2 +- src/org/olap4j/metadata/Catalog.java | 2 +- src/org/olap4j/metadata/Cube.java | 4 +- src/org/olap4j/metadata/Level.java | 6 +- src/org/olap4j/metadata/Member.java | 2 +- src/org/olap4j/metadata/MetadataElement.java | 2 +- src/org/olap4j/metadata/Schema.java | 2 +- src/org/olap4j/query/Query.java | 162 +- src/org/olap4j/query/QueryAxis.java | 2 +- src/org/olap4j/query/QueryDimension.java | 19 +- src/org/olap4j/query/SelectionFactory.java | 19 +- src/org/olap4j/query/SelectionImpl.java | 2 +- src/org/olap4j/type/LevelType.java | 2 +- src/org/olap4j/type/MemberType.java | 2 +- testsrc/org/olap4j/ConnectionTest.java | 35 +- testsrc/org/olap4j/MetadataTest.java | 982 ++--- testsrc/org/olap4j/MondrianTester.java | 146 +- testsrc/org/olap4j/OlapTest.java | 34 +- testsrc/org/olap4j/XmlaCachedProxyTest.java | 661 ++-- testsrc/org/olap4j/XmlaConnectionTest.java | 93 +- testsrc/org/olap4j/XmlaCookieManagerTest.java | 224 +- testsrc/org/olap4j/XmlaSHAEncoderTest.java | 94 +- testsrc/org/olap4j/XmlaTester.java | 252 +- testsrc/org/olap4j/impl/Olap4jUtilTest.java | 2 +- testsrc/org/olap4j/mdx/MdxTest.java | 2 +- testsrc/org/olap4j/test/TestContext.java | 9 +- 64 files changed, 10337 insertions(+), 10321 deletions(-) diff --git a/src/org/olap4j/CellSetAxisMetaData.java b/src/org/olap4j/CellSetAxisMetaData.java index 3f1db1e..7ae4d26 100755 --- a/src/org/olap4j/CellSetAxisMetaData.java +++ b/src/org/olap4j/CellSetAxisMetaData.java @@ -76,7 +76,7 @@ public interface CellSetAxisMetaData { * the properties are not necessarily unique; for example, there might be * two hierarchies on the axis, each of which returns the DISPLAY_INFO * property.

- * + * * @return list of member properties on this Axis */ List getProperties(); diff --git a/src/org/olap4j/OlapConnection.java b/src/org/olap4j/OlapConnection.java index 25cbeb3..0c8b249 100644 --- a/src/org/olap4j/OlapConnection.java +++ b/src/org/olap4j/OlapConnection.java @@ -80,7 +80,7 @@ public interface OlapConnection extends Connection, OlapWrapper { /** * Sets the current locale of this connection. The value must not be null. - * + * *

If the locale is not set, the JDK's current locale is used (see * {@link java.util.Locale#getDefault()}). * diff --git a/src/org/olap4j/OlapDataSource.java b/src/org/olap4j/OlapDataSource.java index 03380a4..153a8e3 100644 --- a/src/org/olap4j/OlapDataSource.java +++ b/src/org/olap4j/OlapDataSource.java @@ -1,39 +1,39 @@ -/* -// This software is subject to the terms of the Common Public License -// Agreement, available at the following URL: -// http://www.opensource.org/licenses/cpl.html. -// Copyright (C) 2008-2008 Julian Hyde -// All Rights Reserved. -// You must accept the terms of that agreement to use this software. -*/ -package org.olap4j; - -import javax.sql.DataSource; -import java.sql.SQLException; - -/** - *

A factory for connections to the physical OLAP data source that this - * OlapDataSource object represents. - * - *

OlapDataSource is a refinement of - * {@link javax.sql.DataSource} whose getConnection methods - * return {@link org.olap4j.OlapConnection} objects rather than mere - * {@link java.sql.Connection}s. - * - * @author jhyde - * @version $Id: $ - * @since Mar 25, 2008 - */ -public interface OlapDataSource extends DataSource { - - // override with more specific return type - OlapConnection getConnection() throws SQLException; - - // override with more specific return type - OlapConnection getConnection( - String username, - String password) - throws SQLException; -} - -// End OlapDataSource.java +/* +// This software is subject to the terms of the Common Public License +// Agreement, available at the following URL: +// http://www.opensource.org/licenses/cpl.html. +// Copyright (C) 2008-2008 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j; + +import javax.sql.DataSource; +import java.sql.SQLException; + +/** + *

A factory for connections to the physical OLAP data source that this + * OlapDataSource object represents. + * + *

OlapDataSource is a refinement of + * {@link javax.sql.DataSource} whose getConnection methods + * return {@link org.olap4j.OlapConnection} objects rather than mere + * {@link java.sql.Connection}s. + * + * @author jhyde + * @version $Id: $ + * @since Mar 25, 2008 + */ +public interface OlapDataSource extends DataSource { + + // override with more specific return type + OlapConnection getConnection() throws SQLException; + + // override with more specific return type + OlapConnection getConnection( + String username, + String password) + throws SQLException; +} + +// End OlapDataSource.java diff --git a/src/org/olap4j/OlapDatabaseMetaData.java b/src/org/olap4j/OlapDatabaseMetaData.java index 85fd47c..70801df 100644 --- a/src/org/olap4j/OlapDatabaseMetaData.java +++ b/src/org/olap4j/OlapDatabaseMetaData.java @@ -477,7 +477,7 @@ ResultSet getDimensions( * function name as it is stored in the database; null * means that the function name should not be used to narrow the * search - * + * * @return a ResultSet object in which each row is a * function description * @@ -840,7 +840,7 @@ ResultSet getMeasures( * to the member whose unique name was specified; or null to return * just the member itself. * Ignored if memberUniqueName is not specified. - * + * * @return a ResultSet object in which each row is a * member description * diff --git a/src/org/olap4j/Position.java b/src/org/olap4j/Position.java index 10338b0..4b63fd8 100755 --- a/src/org/olap4j/Position.java +++ b/src/org/olap4j/Position.java @@ -22,63 +22,63 @@ * query

* *
- * SELECT {[Measures].[Unit Sales], [Measures].[Store Sales]} ON - * COLUMNS,
+ * SELECT {[Measures].[Unit Sales], [Measures].[Store Sales]} ON + * COLUMNS,
*     CrossJoin(
*         {[Gender].Members},
*         {[Product].[Food], - * [Product].[Drink]}) ON ROWS
- * FROM [Sales]
+ * [Product].[Drink]}) ON ROWS
+ * FROM [Sales]
*
* *

the COLUMNS axis has dimensionality * {[Measures]} and the ROWS axis has dimensionality * {[Gender], [Product]}. In the result,

* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
GenderProductUnit SalesStore Sales
All GenderFood191,940409,035.59
All GenderDrink24,59748,836.21
FFood94,814203,094.17
FDrink12,20224,457.37
MFood97,126205,941.42
MDrink12,39524,378.84
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
GenderProductUnit SalesStore Sales
All GenderFood191,940409,035.59
All GenderDrink24,59748,836.21
FFood94,814203,094.17
FDrink12,20224,457.37
MFood97,126205,941.42
MDrink12,39524,378.84
* *

each of the six positions on the ROWS axis has two members, * consistent with its dimensionality of 2. The COLUMNS axis has diff --git a/src/org/olap4j/driver/xmla/EmptyResultSet.java b/src/org/olap4j/driver/xmla/EmptyResultSet.java index 6f412ac..69e18ec 100644 --- a/src/org/olap4j/driver/xmla/EmptyResultSet.java +++ b/src/org/olap4j/driver/xmla/EmptyResultSet.java @@ -1,735 +1,735 @@ -/* -// This software is subject to the terms of the Common Public License -// Agreement, available at the following URL: -// http://www.opensource.org/licenses/cpl.html. -// Copyright (C) 2007-2007 Julian Hyde -// All Rights Reserved. -// You must accept the terms of that agreement to use this software. -*/ -package org.olap4j.driver.xmla; - -import org.olap4j.OlapWrapper; - -import javax.sql.rowset.RowSetMetaDataImpl; -import java.sql.*; -import java.sql.Date; -import java.math.BigDecimal; -import java.io.InputStream; -import java.io.Reader; -import java.util.*; -import java.net.URL; - -/** - * Implementation of {@link ResultSet} which returns 0 rows. - * - *

This class is used to implement {@link java.sql.DatabaseMetaData} - * methods for querying object types where those object types never have - * any instances for this particular driver.

- * - *

This class has sub-classes which implement JDBC 3.0 and JDBC 4.0 APIs; - * it is instantiated using {@link Factory#newEmptyResultSet}.

- * - * @author jhyde - * @version $Id$ - * @since May 24, 2007 - */ -abstract class EmptyResultSet implements ResultSet, OlapWrapper { - final XmlaOlap4jConnection olap4jConnection; - private final List headerList; - private final List> rowList; - private int rowOrdinal = -1; - private final RowSetMetaDataImpl metaData = new RowSetMetaDataImpl(); - - EmptyResultSet( - XmlaOlap4jConnection olap4jConnection, - List headerList, - List> rowList) - { - this.olap4jConnection = olap4jConnection; - this.headerList = headerList; - this.rowList = rowList; - try { - metaData.setColumnCount(headerList.size()); - for (int i = 0; i < headerList.size(); i++) { - metaData.setColumnName(i + 1, headerList.get(i)); - } - } catch (SQLException e) { - throw new RuntimeException(e); - } - } - - /** - * Returns the value of a given column - * @param columnOrdinal 0-based ordinal - * @return Value - */ - private Object getColumn(int columnOrdinal) { - return rowList.get(rowOrdinal).get(columnOrdinal); - } - - private Object getColumn(String columnLabel) throws SQLException { - int column = headerList.indexOf(columnLabel); - if (column < 0) { - throw new SQLException("Column not found: " + columnLabel); - } - return rowList.get(rowOrdinal).get(column); - } - - // implement ResultSet - - public boolean next() throws SQLException { - // note that if rowOrdinal == rowList.size - 1, we move but then return - // false - if (rowOrdinal < rowList.size()) { - ++rowOrdinal; - } - return rowOrdinal < rowList.size(); - } - - public void close() throws SQLException { - } - - public boolean wasNull() throws SQLException { - throw new UnsupportedOperationException(); - } - - public String getString(int columnIndex) throws SQLException { - return String.valueOf(getColumn(columnIndex - 1)); - } - - public boolean getBoolean(int columnIndex) throws SQLException { - Object o = getColumn(columnIndex - 1); - if (o instanceof Boolean) { - return (Boolean) o; - } else if (o instanceof String) { - return Boolean.valueOf((String) o); - } else { - return !o.equals(0); - } - } - - public byte getByte(int columnIndex) throws SQLException { - Object o = getColumn(columnIndex - 1); - return ((Number) o).byteValue(); - } - - public short getShort(int columnIndex) throws SQLException { - Object o = getColumn(columnIndex - 1); - return ((Number) o).shortValue(); - } - - public int getInt(int columnIndex) throws SQLException { - Object o = getColumn(columnIndex - 1); - return ((Number) o).intValue(); - } - - public long getLong(int columnIndex) throws SQLException { - Object o = getColumn(columnIndex - 1); - return ((Number) o).longValue(); - } - - public float getFloat(int columnIndex) throws SQLException { - Object o = getColumn(columnIndex - 1); - return ((Number) o).floatValue(); - } - - public double getDouble(int columnIndex) throws SQLException { - Object o = getColumn(columnIndex - 1); - return ((Number) o).doubleValue(); - } - - public BigDecimal getBigDecimal( - int columnIndex, int scale) throws SQLException { - throw new UnsupportedOperationException(); - } - - public byte[] getBytes(int columnIndex) throws SQLException { - Object o = getColumn(columnIndex - 1); - return (byte[]) o; - } - - public Date getDate(int columnIndex) throws SQLException { - Object o = getColumn(columnIndex - 1); - return (Date) o; - } - - public Time getTime(int columnIndex) throws SQLException { - Object o = getColumn(columnIndex - 1); - return (Time) o; - } - - public Timestamp getTimestamp(int columnIndex) throws SQLException { - Object o = getColumn(columnIndex - 1); - return (Timestamp) o; - } - - public InputStream getAsciiStream(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public InputStream getUnicodeStream(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public InputStream getBinaryStream(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public String getString(String columnLabel) throws SQLException { - Object o = getColumn(columnLabel); - return String.valueOf(o); - } - - public boolean getBoolean(String columnLabel) throws SQLException { - Object o = getColumn(columnLabel); - if (o instanceof Boolean) { - return (Boolean) o; - } else if (o instanceof String) { - return Boolean.valueOf((String) o); - } else { - return !o.equals(0); - } - } - - public byte getByte(String columnLabel) throws SQLException { - Object o = getColumn(columnLabel); - return ((Number) o).byteValue(); - } - - public short getShort(String columnLabel) throws SQLException { - Object o = getColumn(columnLabel); - return ((Number) o).shortValue(); - } - - public int getInt(String columnLabel) throws SQLException { - Object o = getColumn(columnLabel); - return ((Number) o).intValue(); - } - - public long getLong(String columnLabel) throws SQLException { - Object o = getColumn(columnLabel); - return ((Number) o).longValue(); - } - - public float getFloat(String columnLabel) throws SQLException { - Object o = getColumn(columnLabel); - return ((Number) o).floatValue(); - } - - public double getDouble(String columnLabel) throws SQLException { - Object o = getColumn(columnLabel); - return ((Number) o).doubleValue(); - } - - public BigDecimal getBigDecimal( - String columnLabel, int scale) throws SQLException { - throw new UnsupportedOperationException(); - } - - public byte[] getBytes(String columnLabel) throws SQLException { - Object o = getColumn(columnLabel); - return (byte[]) o; - } - - public Date getDate(String columnLabel) throws SQLException { - Object o = getColumn(columnLabel); - return (Date) o; - } - - public Time getTime(String columnLabel) throws SQLException { - Object o = getColumn(columnLabel); - return (Time) o; - } - - public Timestamp getTimestamp(String columnLabel) throws SQLException { - Object o = getColumn(columnLabel); - return (Timestamp) o; - } - - public InputStream getAsciiStream(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public InputStream getUnicodeStream(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public InputStream getBinaryStream(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public SQLWarning getWarnings() throws SQLException { - throw new UnsupportedOperationException(); - } - - public void clearWarnings() throws SQLException { - throw new UnsupportedOperationException(); - } - - public String getCursorName() throws SQLException { - throw new UnsupportedOperationException(); - } - - public ResultSetMetaData getMetaData() throws SQLException { - return metaData; - } - - public Object getObject(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Object getObject(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public int findColumn(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Reader getCharacterStream(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Reader getCharacterStream(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public BigDecimal getBigDecimal(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public BigDecimal getBigDecimal(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean isBeforeFirst() throws SQLException { - return rowOrdinal < 0; - } - - public boolean isAfterLast() throws SQLException { - return rowOrdinal >= rowList.size(); - } - - public boolean isFirst() throws SQLException { - return rowOrdinal == 0; - } - - public boolean isLast() throws SQLException { - return rowOrdinal == rowList.size() - 1; - } - - public void beforeFirst() throws SQLException { - rowOrdinal = -1; - } - - public void afterLast() throws SQLException { - rowOrdinal = rowList.size(); - } - - public boolean first() throws SQLException { - if (rowList.size() == 0) { - return false; - } else { - rowOrdinal = 0; - return true; - } - } - - public boolean last() throws SQLException { - if (rowList.size() == 0) { - return false; - } else { - rowOrdinal = rowList.size() - 1; - return true; - } - } - - public int getRow() throws SQLException { - return rowOrdinal + 1; // 1-based - } - - public boolean absolute(int row) throws SQLException { - int newRowOrdinal = row - 1;// convert to 0-based - if (newRowOrdinal >= 0 && newRowOrdinal < rowList.size()) { - rowOrdinal = newRowOrdinal; - return true; - } else { - return false; - } - } - - public boolean relative(int rows) throws SQLException { - int newRowOrdinal = rowOrdinal + (rows - 1); - if (newRowOrdinal >= 0 && newRowOrdinal < rowList.size()) { - rowOrdinal = newRowOrdinal; - return true; - } else { - return false; - } - } - - public boolean previous() throws SQLException { - // converse of next(); note that if rowOrdinal == 0, we decrement - // but return false - if (rowOrdinal >= 0) { - --rowOrdinal; - } - return rowOrdinal >= 0; - } - - public void setFetchDirection(int direction) throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getFetchDirection() throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setFetchSize(int rows) throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getFetchSize() throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getType() throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getConcurrency() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean rowUpdated() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean rowInserted() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean rowDeleted() throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateNull(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateBoolean(int columnIndex, boolean x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateByte(int columnIndex, byte x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateShort(int columnIndex, short x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateInt(int columnIndex, int x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateLong(int columnIndex, long x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateFloat(int columnIndex, float x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateDouble(int columnIndex, double x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateBigDecimal( - int columnIndex, BigDecimal x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateString(int columnIndex, String x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateBytes(int columnIndex, byte x[]) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateDate(int columnIndex, Date x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateTime(int columnIndex, Time x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateTimestamp( - int columnIndex, Timestamp x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateAsciiStream( - int columnIndex, InputStream x, int length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateBinaryStream( - int columnIndex, InputStream x, int length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateCharacterStream( - int columnIndex, Reader x, int length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateObject( - int columnIndex, Object x, int scaleOrLength) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateObject(int columnIndex, Object x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateNull(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateBoolean( - String columnLabel, boolean x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateByte(String columnLabel, byte x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateShort(String columnLabel, short x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateInt(String columnLabel, int x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateLong(String columnLabel, long x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateFloat(String columnLabel, float x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateDouble(String columnLabel, double x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateBigDecimal( - String columnLabel, BigDecimal x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateString(String columnLabel, String x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateBytes(String columnLabel, byte x[]) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateDate(String columnLabel, Date x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateTime(String columnLabel, Time x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateTimestamp( - String columnLabel, Timestamp x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateAsciiStream( - String columnLabel, InputStream x, int length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateBinaryStream( - String columnLabel, InputStream x, int length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateCharacterStream( - String columnLabel, Reader reader, int length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateObject( - String columnLabel, Object x, int scaleOrLength) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateObject(String columnLabel, Object x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void insertRow() throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateRow() throws SQLException { - throw new UnsupportedOperationException(); - } - - public void deleteRow() throws SQLException { - throw new UnsupportedOperationException(); - } - - public void refreshRow() throws SQLException { - throw new UnsupportedOperationException(); - } - - public void cancelRowUpdates() throws SQLException { - throw new UnsupportedOperationException(); - } - - public void moveToInsertRow() throws SQLException { - throw new UnsupportedOperationException(); - } - - public void moveToCurrentRow() throws SQLException { - throw new UnsupportedOperationException(); - } - - public Statement getStatement() throws SQLException { - throw new UnsupportedOperationException(); - } - - public Object getObject( - int columnIndex, Map> map) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Ref getRef(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Blob getBlob(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Clob getClob(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Array getArray(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Object getObject( - String columnLabel, Map> map) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Ref getRef(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Blob getBlob(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Clob getClob(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Array getArray(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Date getDate(int columnIndex, Calendar cal) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Date getDate(String columnLabel, Calendar cal) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Time getTime(int columnIndex, Calendar cal) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Time getTime(String columnLabel, Calendar cal) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Timestamp getTimestamp( - int columnIndex, Calendar cal) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Timestamp getTimestamp( - String columnLabel, Calendar cal) throws SQLException { - throw new UnsupportedOperationException(); - } - - public URL getURL(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public URL getURL(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateRef(int columnIndex, Ref x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateRef(String columnLabel, Ref x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateBlob(int columnIndex, Blob x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateBlob(String columnLabel, Blob x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateClob(int columnIndex, Clob x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateClob(String columnLabel, Clob x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateArray(int columnIndex, Array x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateArray(String columnLabel, Array x) throws SQLException { - throw new UnsupportedOperationException(); - } - - // implement Wrapper - - public T unwrap(Class iface) throws SQLException { - if (iface.isInstance(this)) { - return iface.cast(this); - } - throw olap4jConnection.helper.createException("cannot cast"); - } - - public boolean isWrapperFor(Class iface) throws SQLException { - return iface.isInstance(this); - } -} - -// End EmptyResultSet.java +/* +// This software is subject to the terms of the Common Public License +// Agreement, available at the following URL: +// http://www.opensource.org/licenses/cpl.html. +// Copyright (C) 2007-2007 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j.driver.xmla; + +import org.olap4j.OlapWrapper; + +import javax.sql.rowset.RowSetMetaDataImpl; +import java.sql.*; +import java.sql.Date; +import java.math.BigDecimal; +import java.io.InputStream; +import java.io.Reader; +import java.util.*; +import java.net.URL; + +/** + * Implementation of {@link ResultSet} which returns 0 rows. + * + *

This class is used to implement {@link java.sql.DatabaseMetaData} + * methods for querying object types where those object types never have + * any instances for this particular driver.

+ * + *

This class has sub-classes which implement JDBC 3.0 and JDBC 4.0 APIs; + * it is instantiated using {@link Factory#newEmptyResultSet}.

+ * + * @author jhyde + * @version $Id$ + * @since May 24, 2007 + */ +abstract class EmptyResultSet implements ResultSet, OlapWrapper { + final XmlaOlap4jConnection olap4jConnection; + private final List headerList; + private final List> rowList; + private int rowOrdinal = -1; + private final RowSetMetaDataImpl metaData = new RowSetMetaDataImpl(); + + EmptyResultSet( + XmlaOlap4jConnection olap4jConnection, + List headerList, + List> rowList) + { + this.olap4jConnection = olap4jConnection; + this.headerList = headerList; + this.rowList = rowList; + try { + metaData.setColumnCount(headerList.size()); + for (int i = 0; i < headerList.size(); i++) { + metaData.setColumnName(i + 1, headerList.get(i)); + } + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + /** + * Returns the value of a given column + * @param columnOrdinal 0-based ordinal + * @return Value + */ + private Object getColumn(int columnOrdinal) { + return rowList.get(rowOrdinal).get(columnOrdinal); + } + + private Object getColumn(String columnLabel) throws SQLException { + int column = headerList.indexOf(columnLabel); + if (column < 0) { + throw new SQLException("Column not found: " + columnLabel); + } + return rowList.get(rowOrdinal).get(column); + } + + // implement ResultSet + + public boolean next() throws SQLException { + // note that if rowOrdinal == rowList.size - 1, we move but then return + // false + if (rowOrdinal < rowList.size()) { + ++rowOrdinal; + } + return rowOrdinal < rowList.size(); + } + + public void close() throws SQLException { + } + + public boolean wasNull() throws SQLException { + throw new UnsupportedOperationException(); + } + + public String getString(int columnIndex) throws SQLException { + return String.valueOf(getColumn(columnIndex - 1)); + } + + public boolean getBoolean(int columnIndex) throws SQLException { + Object o = getColumn(columnIndex - 1); + if (o instanceof Boolean) { + return (Boolean) o; + } else if (o instanceof String) { + return Boolean.valueOf((String) o); + } else { + return !o.equals(0); + } + } + + public byte getByte(int columnIndex) throws SQLException { + Object o = getColumn(columnIndex - 1); + return ((Number) o).byteValue(); + } + + public short getShort(int columnIndex) throws SQLException { + Object o = getColumn(columnIndex - 1); + return ((Number) o).shortValue(); + } + + public int getInt(int columnIndex) throws SQLException { + Object o = getColumn(columnIndex - 1); + return ((Number) o).intValue(); + } + + public long getLong(int columnIndex) throws SQLException { + Object o = getColumn(columnIndex - 1); + return ((Number) o).longValue(); + } + + public float getFloat(int columnIndex) throws SQLException { + Object o = getColumn(columnIndex - 1); + return ((Number) o).floatValue(); + } + + public double getDouble(int columnIndex) throws SQLException { + Object o = getColumn(columnIndex - 1); + return ((Number) o).doubleValue(); + } + + public BigDecimal getBigDecimal( + int columnIndex, int scale) throws SQLException { + throw new UnsupportedOperationException(); + } + + public byte[] getBytes(int columnIndex) throws SQLException { + Object o = getColumn(columnIndex - 1); + return (byte[]) o; + } + + public Date getDate(int columnIndex) throws SQLException { + Object o = getColumn(columnIndex - 1); + return (Date) o; + } + + public Time getTime(int columnIndex) throws SQLException { + Object o = getColumn(columnIndex - 1); + return (Time) o; + } + + public Timestamp getTimestamp(int columnIndex) throws SQLException { + Object o = getColumn(columnIndex - 1); + return (Timestamp) o; + } + + public InputStream getAsciiStream(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public InputStream getUnicodeStream(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public InputStream getBinaryStream(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public String getString(String columnLabel) throws SQLException { + Object o = getColumn(columnLabel); + return String.valueOf(o); + } + + public boolean getBoolean(String columnLabel) throws SQLException { + Object o = getColumn(columnLabel); + if (o instanceof Boolean) { + return (Boolean) o; + } else if (o instanceof String) { + return Boolean.valueOf((String) o); + } else { + return !o.equals(0); + } + } + + public byte getByte(String columnLabel) throws SQLException { + Object o = getColumn(columnLabel); + return ((Number) o).byteValue(); + } + + public short getShort(String columnLabel) throws SQLException { + Object o = getColumn(columnLabel); + return ((Number) o).shortValue(); + } + + public int getInt(String columnLabel) throws SQLException { + Object o = getColumn(columnLabel); + return ((Number) o).intValue(); + } + + public long getLong(String columnLabel) throws SQLException { + Object o = getColumn(columnLabel); + return ((Number) o).longValue(); + } + + public float getFloat(String columnLabel) throws SQLException { + Object o = getColumn(columnLabel); + return ((Number) o).floatValue(); + } + + public double getDouble(String columnLabel) throws SQLException { + Object o = getColumn(columnLabel); + return ((Number) o).doubleValue(); + } + + public BigDecimal getBigDecimal( + String columnLabel, int scale) throws SQLException { + throw new UnsupportedOperationException(); + } + + public byte[] getBytes(String columnLabel) throws SQLException { + Object o = getColumn(columnLabel); + return (byte[]) o; + } + + public Date getDate(String columnLabel) throws SQLException { + Object o = getColumn(columnLabel); + return (Date) o; + } + + public Time getTime(String columnLabel) throws SQLException { + Object o = getColumn(columnLabel); + return (Time) o; + } + + public Timestamp getTimestamp(String columnLabel) throws SQLException { + Object o = getColumn(columnLabel); + return (Timestamp) o; + } + + public InputStream getAsciiStream(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public InputStream getUnicodeStream(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public InputStream getBinaryStream(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public SQLWarning getWarnings() throws SQLException { + throw new UnsupportedOperationException(); + } + + public void clearWarnings() throws SQLException { + throw new UnsupportedOperationException(); + } + + public String getCursorName() throws SQLException { + throw new UnsupportedOperationException(); + } + + public ResultSetMetaData getMetaData() throws SQLException { + return metaData; + } + + public Object getObject(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Object getObject(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public int findColumn(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Reader getCharacterStream(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Reader getCharacterStream(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public BigDecimal getBigDecimal(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public BigDecimal getBigDecimal(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean isBeforeFirst() throws SQLException { + return rowOrdinal < 0; + } + + public boolean isAfterLast() throws SQLException { + return rowOrdinal >= rowList.size(); + } + + public boolean isFirst() throws SQLException { + return rowOrdinal == 0; + } + + public boolean isLast() throws SQLException { + return rowOrdinal == rowList.size() - 1; + } + + public void beforeFirst() throws SQLException { + rowOrdinal = -1; + } + + public void afterLast() throws SQLException { + rowOrdinal = rowList.size(); + } + + public boolean first() throws SQLException { + if (rowList.size() == 0) { + return false; + } else { + rowOrdinal = 0; + return true; + } + } + + public boolean last() throws SQLException { + if (rowList.size() == 0) { + return false; + } else { + rowOrdinal = rowList.size() - 1; + return true; + } + } + + public int getRow() throws SQLException { + return rowOrdinal + 1; // 1-based + } + + public boolean absolute(int row) throws SQLException { + int newRowOrdinal = row - 1;// convert to 0-based + if (newRowOrdinal >= 0 && newRowOrdinal < rowList.size()) { + rowOrdinal = newRowOrdinal; + return true; + } else { + return false; + } + } + + public boolean relative(int rows) throws SQLException { + int newRowOrdinal = rowOrdinal + (rows - 1); + if (newRowOrdinal >= 0 && newRowOrdinal < rowList.size()) { + rowOrdinal = newRowOrdinal; + return true; + } else { + return false; + } + } + + public boolean previous() throws SQLException { + // converse of next(); note that if rowOrdinal == 0, we decrement + // but return false + if (rowOrdinal >= 0) { + --rowOrdinal; + } + return rowOrdinal >= 0; + } + + public void setFetchDirection(int direction) throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getFetchDirection() throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setFetchSize(int rows) throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getFetchSize() throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getType() throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getConcurrency() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean rowUpdated() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean rowInserted() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean rowDeleted() throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateNull(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateBoolean(int columnIndex, boolean x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateByte(int columnIndex, byte x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateShort(int columnIndex, short x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateInt(int columnIndex, int x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateLong(int columnIndex, long x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateFloat(int columnIndex, float x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateDouble(int columnIndex, double x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateBigDecimal( + int columnIndex, BigDecimal x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateString(int columnIndex, String x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateBytes(int columnIndex, byte x[]) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateDate(int columnIndex, Date x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateTime(int columnIndex, Time x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateTimestamp( + int columnIndex, Timestamp x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateAsciiStream( + int columnIndex, InputStream x, int length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateBinaryStream( + int columnIndex, InputStream x, int length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateCharacterStream( + int columnIndex, Reader x, int length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateObject( + int columnIndex, Object x, int scaleOrLength) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateObject(int columnIndex, Object x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateNull(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateBoolean( + String columnLabel, boolean x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateByte(String columnLabel, byte x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateShort(String columnLabel, short x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateInt(String columnLabel, int x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateLong(String columnLabel, long x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateFloat(String columnLabel, float x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateDouble(String columnLabel, double x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateBigDecimal( + String columnLabel, BigDecimal x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateString(String columnLabel, String x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateBytes(String columnLabel, byte x[]) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateDate(String columnLabel, Date x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateTime(String columnLabel, Time x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateTimestamp( + String columnLabel, Timestamp x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateAsciiStream( + String columnLabel, InputStream x, int length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateBinaryStream( + String columnLabel, InputStream x, int length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateCharacterStream( + String columnLabel, Reader reader, int length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateObject( + String columnLabel, Object x, int scaleOrLength) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateObject(String columnLabel, Object x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void insertRow() throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateRow() throws SQLException { + throw new UnsupportedOperationException(); + } + + public void deleteRow() throws SQLException { + throw new UnsupportedOperationException(); + } + + public void refreshRow() throws SQLException { + throw new UnsupportedOperationException(); + } + + public void cancelRowUpdates() throws SQLException { + throw new UnsupportedOperationException(); + } + + public void moveToInsertRow() throws SQLException { + throw new UnsupportedOperationException(); + } + + public void moveToCurrentRow() throws SQLException { + throw new UnsupportedOperationException(); + } + + public Statement getStatement() throws SQLException { + throw new UnsupportedOperationException(); + } + + public Object getObject( + int columnIndex, Map> map) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Ref getRef(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Blob getBlob(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Clob getClob(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Array getArray(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Object getObject( + String columnLabel, Map> map) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Ref getRef(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Blob getBlob(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Clob getClob(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Array getArray(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Date getDate(int columnIndex, Calendar cal) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Date getDate(String columnLabel, Calendar cal) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Time getTime(int columnIndex, Calendar cal) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Time getTime(String columnLabel, Calendar cal) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Timestamp getTimestamp( + int columnIndex, Calendar cal) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Timestamp getTimestamp( + String columnLabel, Calendar cal) throws SQLException { + throw new UnsupportedOperationException(); + } + + public URL getURL(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public URL getURL(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateRef(int columnIndex, Ref x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateRef(String columnLabel, Ref x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateBlob(int columnIndex, Blob x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateBlob(String columnLabel, Blob x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateClob(int columnIndex, Clob x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateClob(String columnLabel, Clob x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateArray(int columnIndex, Array x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateArray(String columnLabel, Array x) throws SQLException { + throw new UnsupportedOperationException(); + } + + // implement Wrapper + + public T unwrap(Class iface) throws SQLException { + if (iface.isInstance(this)) { + return iface.cast(this); + } + throw olap4jConnection.helper.createException("cannot cast"); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return iface.isInstance(this); + } +} + +// End EmptyResultSet.java diff --git a/src/org/olap4j/driver/xmla/Factory.java b/src/org/olap4j/driver/xmla/Factory.java index 5e17517..88b8696 100644 --- a/src/org/olap4j/driver/xmla/Factory.java +++ b/src/org/olap4j/driver/xmla/Factory.java @@ -1,54 +1,54 @@ -/* -// This software is subject to the terms of the Common Public License -// Agreement, available at the following URL: -// http://www.opensource.org/licenses/cpl.html. -// Copyright (C) 2007-2007 Julian Hyde -// All Rights Reserved. -// You must accept the terms of that agreement to use this software. -*/ -package org.olap4j.driver.xmla; - -import org.olap4j.OlapException; -import org.olap4j.driver.xmla.proxy.XmlaOlap4jProxy; - -import java.sql.*; -import java.util.Properties; -import java.util.List; - -/** - * Instantiates classes to implement the olap4j API against the - * an XML for Analysis provider. - * - *

There are implementations for JDBC 3.0 (which occurs in JDK 1.5) - * and JDBC 4.0 (which occurs in JDK 1.6). - * - * @author jhyde - * @version $Id$ - * @since Jun 14, 2007 - */ -interface Factory { - Connection newConnection( - XmlaOlap4jProxy proxy, - String url, - Properties info) throws SQLException; - - EmptyResultSet newEmptyResultSet( - XmlaOlap4jConnection olap4jConnection); - - ResultSet newFixedResultSet( - XmlaOlap4jConnection olap4jConnection, - List headerList, - List> rowList); - - XmlaOlap4jCellSet newCellSet( - XmlaOlap4jStatement olap4jStatement) throws OlapException; - - XmlaOlap4jPreparedStatement newPreparedStatement( - String mdx, - XmlaOlap4jConnection olap4jConnection) throws OlapException; - - XmlaOlap4jDatabaseMetaData newDatabaseMetaData( - XmlaOlap4jConnection olap4jConnection); -} - -// End Factory.java +/* +// This software is subject to the terms of the Common Public License +// Agreement, available at the following URL: +// http://www.opensource.org/licenses/cpl.html. +// Copyright (C) 2007-2007 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j.driver.xmla; + +import org.olap4j.OlapException; +import org.olap4j.driver.xmla.proxy.XmlaOlap4jProxy; + +import java.sql.*; +import java.util.Properties; +import java.util.List; + +/** + * Instantiates classes to implement the olap4j API against the + * an XML for Analysis provider. + * + *

There are implementations for JDBC 3.0 (which occurs in JDK 1.5) + * and JDBC 4.0 (which occurs in JDK 1.6). + * + * @author jhyde + * @version $Id$ + * @since Jun 14, 2007 + */ +interface Factory { + Connection newConnection( + XmlaOlap4jProxy proxy, + String url, + Properties info) throws SQLException; + + EmptyResultSet newEmptyResultSet( + XmlaOlap4jConnection olap4jConnection); + + ResultSet newFixedResultSet( + XmlaOlap4jConnection olap4jConnection, + List headerList, + List> rowList); + + XmlaOlap4jCellSet newCellSet( + XmlaOlap4jStatement olap4jStatement) throws OlapException; + + XmlaOlap4jPreparedStatement newPreparedStatement( + String mdx, + XmlaOlap4jConnection olap4jConnection) throws OlapException; + + XmlaOlap4jDatabaseMetaData newDatabaseMetaData( + XmlaOlap4jConnection olap4jConnection); +} + +// End Factory.java diff --git a/src/org/olap4j/driver/xmla/FactoryJdbc3Impl.java b/src/org/olap4j/driver/xmla/FactoryJdbc3Impl.java index d478263..1753c45 100644 --- a/src/org/olap4j/driver/xmla/FactoryJdbc3Impl.java +++ b/src/org/olap4j/driver/xmla/FactoryJdbc3Impl.java @@ -1,129 +1,129 @@ -/* -// This software is subject to the terms of the Common Public License -// Agreement, available at the following URL: -// http://www.opensource.org/licenses/cpl.html. -// Copyright (C) 2007-2007 Julian Hyde -// All Rights Reserved. -// You must accept the terms of that agreement to use this software. -*/ -package org.olap4j.driver.xmla; - -import org.olap4j.OlapException; -import org.olap4j.driver.xmla.proxy.XmlaOlap4jProxy; - -import java.sql.*; -import java.util.*; - -/** - * Implementation of {@link Factory} for JDBC 3.0. - * - * @author jhyde - * @version $Id$ - * @since Jun 14, 2007 - */ -class FactoryJdbc3Impl implements Factory { - public Connection newConnection( - XmlaOlap4jProxy proxy, - String url, - Properties info) - throws SQLException - { - return new FactoryJdbc3Impl.XmlaOlap4jConnectionJdbc3( - proxy, url, info); - } - - public EmptyResultSet newEmptyResultSet( - XmlaOlap4jConnection olap4jConnection) - { - List headerList = Collections.emptyList(); - List> rowList = Collections.emptyList(); - return new FactoryJdbc3Impl.EmptyResultSetJdbc3( - olap4jConnection, headerList, rowList); - } - - public ResultSet newFixedResultSet( - XmlaOlap4jConnection olap4jConnection, - List headerList, - List> rowList) - { - return new EmptyResultSetJdbc3(olap4jConnection, headerList, rowList); - } - - public XmlaOlap4jCellSet newCellSet( - XmlaOlap4jStatement olap4jStatement) throws OlapException - { - return new FactoryJdbc3Impl.XmlaOlap4jCellSetJdbc3( - olap4jStatement); - } - - public XmlaOlap4jPreparedStatement newPreparedStatement( - String mdx, - XmlaOlap4jConnection olap4jConnection) throws OlapException - { - return new FactoryJdbc3Impl.XmlaOlap4jPreparedStatementJdbc3( - olap4jConnection, mdx); - } - - public XmlaOlap4jDatabaseMetaData newDatabaseMetaData( - XmlaOlap4jConnection olap4jConnection) - { - return new FactoryJdbc3Impl.XmlaOlap4jDatabaseMetaDataJdbc3( - olap4jConnection); - } - - // Inner classes - - private static class XmlaOlap4jPreparedStatementJdbc3 - extends XmlaOlap4jPreparedStatement - { - public XmlaOlap4jPreparedStatementJdbc3( - XmlaOlap4jConnection olap4jConnection, - String mdx) throws OlapException - { - super(olap4jConnection, mdx); - } - } - - private static class XmlaOlap4jCellSetJdbc3 - extends XmlaOlap4jCellSet - { - public XmlaOlap4jCellSetJdbc3( - XmlaOlap4jStatement olap4jStatement) throws OlapException - { - super(olap4jStatement); - } - } - - private static class EmptyResultSetJdbc3 extends EmptyResultSet { - public EmptyResultSetJdbc3( - XmlaOlap4jConnection olap4jConnection, - List headerList, - List> rowList) - { - super(olap4jConnection, headerList, rowList); - } - } - - private class XmlaOlap4jConnectionJdbc3 extends XmlaOlap4jConnection { - public XmlaOlap4jConnectionJdbc3( - XmlaOlap4jProxy proxy, - String url, - Properties info) - throws SQLException - { - super(FactoryJdbc3Impl.this, proxy, url, info); - } - } - - private static class XmlaOlap4jDatabaseMetaDataJdbc3 - extends XmlaOlap4jDatabaseMetaData - { - public XmlaOlap4jDatabaseMetaDataJdbc3( - XmlaOlap4jConnection olap4jConnection) - { - super(olap4jConnection); - } - } -} - -// End FactoryJdbc3Impl.java +/* +// This software is subject to the terms of the Common Public License +// Agreement, available at the following URL: +// http://www.opensource.org/licenses/cpl.html. +// Copyright (C) 2007-2007 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j.driver.xmla; + +import org.olap4j.OlapException; +import org.olap4j.driver.xmla.proxy.XmlaOlap4jProxy; + +import java.sql.*; +import java.util.*; + +/** + * Implementation of {@link Factory} for JDBC 3.0. + * + * @author jhyde + * @version $Id$ + * @since Jun 14, 2007 + */ +class FactoryJdbc3Impl implements Factory { + public Connection newConnection( + XmlaOlap4jProxy proxy, + String url, + Properties info) + throws SQLException + { + return new FactoryJdbc3Impl.XmlaOlap4jConnectionJdbc3( + proxy, url, info); + } + + public EmptyResultSet newEmptyResultSet( + XmlaOlap4jConnection olap4jConnection) + { + List headerList = Collections.emptyList(); + List> rowList = Collections.emptyList(); + return new FactoryJdbc3Impl.EmptyResultSetJdbc3( + olap4jConnection, headerList, rowList); + } + + public ResultSet newFixedResultSet( + XmlaOlap4jConnection olap4jConnection, + List headerList, + List> rowList) + { + return new EmptyResultSetJdbc3(olap4jConnection, headerList, rowList); + } + + public XmlaOlap4jCellSet newCellSet( + XmlaOlap4jStatement olap4jStatement) throws OlapException + { + return new FactoryJdbc3Impl.XmlaOlap4jCellSetJdbc3( + olap4jStatement); + } + + public XmlaOlap4jPreparedStatement newPreparedStatement( + String mdx, + XmlaOlap4jConnection olap4jConnection) throws OlapException + { + return new FactoryJdbc3Impl.XmlaOlap4jPreparedStatementJdbc3( + olap4jConnection, mdx); + } + + public XmlaOlap4jDatabaseMetaData newDatabaseMetaData( + XmlaOlap4jConnection olap4jConnection) + { + return new FactoryJdbc3Impl.XmlaOlap4jDatabaseMetaDataJdbc3( + olap4jConnection); + } + + // Inner classes + + private static class XmlaOlap4jPreparedStatementJdbc3 + extends XmlaOlap4jPreparedStatement + { + public XmlaOlap4jPreparedStatementJdbc3( + XmlaOlap4jConnection olap4jConnection, + String mdx) throws OlapException + { + super(olap4jConnection, mdx); + } + } + + private static class XmlaOlap4jCellSetJdbc3 + extends XmlaOlap4jCellSet + { + public XmlaOlap4jCellSetJdbc3( + XmlaOlap4jStatement olap4jStatement) throws OlapException + { + super(olap4jStatement); + } + } + + private static class EmptyResultSetJdbc3 extends EmptyResultSet { + public EmptyResultSetJdbc3( + XmlaOlap4jConnection olap4jConnection, + List headerList, + List> rowList) + { + super(olap4jConnection, headerList, rowList); + } + } + + private class XmlaOlap4jConnectionJdbc3 extends XmlaOlap4jConnection { + public XmlaOlap4jConnectionJdbc3( + XmlaOlap4jProxy proxy, + String url, + Properties info) + throws SQLException + { + super(FactoryJdbc3Impl.this, proxy, url, info); + } + } + + private static class XmlaOlap4jDatabaseMetaDataJdbc3 + extends XmlaOlap4jDatabaseMetaData + { + public XmlaOlap4jDatabaseMetaDataJdbc3( + XmlaOlap4jConnection olap4jConnection) + { + super(olap4jConnection); + } + } +} + +// End FactoryJdbc3Impl.java diff --git a/src/org/olap4j/driver/xmla/FactoryJdbc4Impl.java b/src/org/olap4j/driver/xmla/FactoryJdbc4Impl.java index 1e66c9d..749c615 100644 --- a/src/org/olap4j/driver/xmla/FactoryJdbc4Impl.java +++ b/src/org/olap4j/driver/xmla/FactoryJdbc4Impl.java @@ -1,806 +1,806 @@ -/* -// This software is subject to the terms of the Common Public License -// Agreement, available at the following URL: -// http://www.opensource.org/licenses/cpl.html. -// Copyright (C) 2007-2007 Julian Hyde -// All Rights Reserved. -// You must accept the terms of that agreement to use this software. -*/ -package org.olap4j.driver.xmla; - -import java.sql.*; -import java.util.*; -import java.io.Reader; -import java.io.InputStream; - -import org.olap4j.*; -import org.olap4j.driver.xmla.proxy.XmlaOlap4jProxy; - -/** - * Implementation of {@link Factory} for JDBC 4.0. - * - * @author jhyde - * @version $Id$ - * @since Jun 14, 2007 - */ -class FactoryJdbc4Impl implements Factory { - public Connection newConnection( - XmlaOlap4jProxy proxy, - String url, - Properties info) - throws SQLException - { - return new XmlaOlap4jConnectionJdbc4( - this, proxy, url, info); - } - - public EmptyResultSet newEmptyResultSet( - XmlaOlap4jConnection olap4jConnection) - { - List headerList = Collections.emptyList(); - List> rowList = Collections.emptyList(); - return new EmptyResultSetJdbc4(olap4jConnection, headerList, rowList); - } - - public ResultSet newFixedResultSet( - XmlaOlap4jConnection olap4jConnection, - List headerList, - List> rowList) - { - return new EmptyResultSetJdbc4( - olap4jConnection, headerList, rowList); - } - - public XmlaOlap4jCellSet newCellSet( - XmlaOlap4jStatement olap4jStatement) throws OlapException - { - return new XmlaOlap4jCellSetJdbc4(olap4jStatement); - } - - public XmlaOlap4jPreparedStatement newPreparedStatement( - String mdx, - XmlaOlap4jConnection olap4jConnection) throws OlapException - { - return new XmlaOlap4jPreparedStatementJdbc4(olap4jConnection, mdx); - } - - public XmlaOlap4jDatabaseMetaData newDatabaseMetaData( - XmlaOlap4jConnection olap4jConnection) - { - return new XmlaOlap4jDatabaseMetaDataJdbc4(olap4jConnection); - } - - // Inner classes - - private static class EmptyResultSetJdbc4 extends EmptyResultSet { - EmptyResultSetJdbc4( - XmlaOlap4jConnection olap4jConnection, - List headerList, - List> rowList) - { - super(olap4jConnection, headerList, rowList); - } - - // implement java.sql.ResultSet methods - // introduced in JDBC 4.0/JDK 1.6 - - public RowId getRowId(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public RowId getRowId(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateRowId(int columnIndex, RowId x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateRowId(String columnLabel, RowId x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getHoldability() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean isClosed() throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateNString( - int columnIndex, String nString) throws SQLException - { - throw new UnsupportedOperationException(); - } - - public void updateNString( - String columnLabel, String nString) throws SQLException - { - throw new UnsupportedOperationException(); - } - - public void updateNClob(int columnIndex, NClob nClob) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateNClob( - String columnLabel, NClob nClob) throws SQLException - { - throw new UnsupportedOperationException(); - } - - public NClob getNClob(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public NClob getNClob(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public SQLXML getSQLXML(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public SQLXML getSQLXML(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateSQLXML( - int columnIndex, SQLXML xmlObject) throws SQLException - { - throw new UnsupportedOperationException(); - } - - public void updateSQLXML( - String columnLabel, SQLXML xmlObject) throws SQLException - { - throw new UnsupportedOperationException(); - } - - public String getNString(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public String getNString(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Reader getNCharacterStream(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Reader getNCharacterStream(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateNCharacterStream( - int columnIndex, Reader x, long length) throws SQLException - { - throw new UnsupportedOperationException(); - } - - public void updateNCharacterStream( - String columnLabel, Reader reader, long length) throws SQLException - { - throw new UnsupportedOperationException(); - } - - public void updateAsciiStream( - int columnIndex, InputStream x, long length) throws SQLException - { - throw new UnsupportedOperationException(); - } - - public void updateBinaryStream( - int columnIndex, InputStream x, long length) throws SQLException - { - throw new UnsupportedOperationException(); - } - - public void updateCharacterStream( - int columnIndex, Reader x, long length) throws SQLException - { - throw new UnsupportedOperationException(); - } - - public void updateAsciiStream( - String columnLabel, InputStream x, long length) throws SQLException - { - throw new UnsupportedOperationException(); - } - - public void updateBinaryStream( - String columnLabel, InputStream x, long length) throws SQLException - { - throw new UnsupportedOperationException(); - } - - public void updateCharacterStream( - String columnLabel, Reader reader, long length) throws SQLException - { - throw new UnsupportedOperationException(); - } - - public void updateBlob( - int columnIndex, - InputStream inputStream, - long length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateBlob( - String columnLabel, - InputStream inputStream, - long length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateClob( - int columnIndex, Reader reader, long length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateClob( - String columnLabel, Reader reader, long length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateNClob( - int columnIndex, Reader reader, long length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateNClob( - String columnLabel, Reader reader, long length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateNCharacterStream( - int columnIndex, Reader x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateNCharacterStream( - String columnLabel, Reader reader) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateAsciiStream( - int columnIndex, InputStream x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateBinaryStream( - int columnIndex, InputStream x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateCharacterStream( - int columnIndex, Reader x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateAsciiStream( - String columnLabel, InputStream x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateBinaryStream( - String columnLabel, InputStream x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateCharacterStream( - String columnLabel, Reader reader) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateBlob( - int columnIndex, InputStream inputStream) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateBlob( - String columnLabel, InputStream inputStream) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateClob(int columnIndex, Reader reader) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateClob( - String columnLabel, Reader reader) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateNClob( - int columnIndex, Reader reader) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateNClob( - String columnLabel, Reader reader) throws SQLException { - throw new UnsupportedOperationException(); - } - } - - private static class XmlaOlap4jConnectionJdbc4 - extends XmlaOlap4jConnection - implements OlapConnection - { - public XmlaOlap4jConnectionJdbc4( - Factory factory, - XmlaOlap4jProxy proxy, - String url, - Properties info) throws SQLException - { - super(factory, proxy, url, info); - } - - public OlapStatement createStatement() { - return super.createStatement(); - } - - public OlapDatabaseMetaData getMetaData() { - return super.getMetaData(); - } - - // implement java.sql.Connection methods - // introduced in JDBC 4.0/JDK 1.6 - - public Clob createClob() throws SQLException { - throw new UnsupportedOperationException(); - } - - public Blob createBlob() throws SQLException { - throw new UnsupportedOperationException(); - } - - public NClob createNClob() throws SQLException { - throw new UnsupportedOperationException(); - } - - public SQLXML createSQLXML() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean isValid(int timeout) throws SQLException { - return !isClosed(); - } - - public void setClientInfo( - String name, String value) throws SQLClientInfoException { - throw new UnsupportedOperationException(); - } - - public void setClientInfo(Properties properties) throws SQLClientInfoException { - throw new UnsupportedOperationException(); - } - - public String getClientInfo(String name) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Properties getClientInfo() throws SQLException { - throw new UnsupportedOperationException(); - } - - public Array createArrayOf( - String typeName, Object[] elements) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Struct createStruct( - String typeName, Object[] attributes) throws SQLException { - throw new UnsupportedOperationException(); - } - } - - private static class XmlaOlap4jCellSetJdbc4 extends XmlaOlap4jCellSet { - XmlaOlap4jCellSetJdbc4( - XmlaOlap4jStatement olap4jStatement) - throws OlapException - { - super(olap4jStatement); - } - - public CellSetMetaData getMetaData() { - return super.getMetaData(); - } - - // implement java.sql.CellSet methods - // introduced in JDBC 4.0/JDK 1.6 - - public RowId getRowId(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public RowId getRowId(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateRowId(int columnIndex, RowId x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateRowId(String columnLabel, RowId x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getHoldability() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean isClosed() throws SQLException { - return closed; - } - - public void updateNString( - int columnIndex, String nString) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateNString( - String columnLabel, String nString) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateNClob(int columnIndex, NClob nClob) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateNClob( - String columnLabel, NClob nClob) throws SQLException { - throw new UnsupportedOperationException(); - } - - public NClob getNClob(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public NClob getNClob(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public SQLXML getSQLXML(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public SQLXML getSQLXML(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateSQLXML( - int columnIndex, SQLXML xmlObject) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateSQLXML( - String columnLabel, SQLXML xmlObject) throws SQLException { - throw new UnsupportedOperationException(); - } - - public String getNString(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public String getNString(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Reader getNCharacterStream(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Reader getNCharacterStream(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateNCharacterStream( - int columnIndex, Reader x, long length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateNCharacterStream( - String columnLabel, Reader reader, long length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateAsciiStream( - int columnIndex, InputStream x, long length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateBinaryStream( - int columnIndex, InputStream x, long length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateCharacterStream( - int columnIndex, Reader x, long length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateAsciiStream( - String columnLabel, InputStream x, long length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateBinaryStream( - String columnLabel, InputStream x, long length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateCharacterStream( - String columnLabel, Reader reader, long length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateBlob( - int columnIndex, - InputStream inputStream, - long length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateBlob( - String columnLabel, - InputStream inputStream, - long length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateClob( - int columnIndex, Reader reader, long length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateClob( - String columnLabel, Reader reader, long length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateNClob( - int columnIndex, Reader reader, long length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateNClob( - String columnLabel, Reader reader, long length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateNCharacterStream( - int columnIndex, Reader x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateNCharacterStream( - String columnLabel, Reader reader) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateAsciiStream( - int columnIndex, InputStream x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateBinaryStream( - int columnIndex, InputStream x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateCharacterStream( - int columnIndex, Reader x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateAsciiStream( - String columnLabel, InputStream x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateBinaryStream( - String columnLabel, InputStream x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateCharacterStream( - String columnLabel, Reader reader) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateBlob( - int columnIndex, InputStream inputStream) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateBlob( - String columnLabel, InputStream inputStream) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateClob(int columnIndex, Reader reader) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateClob( - String columnLabel, Reader reader) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateNClob( - int columnIndex, Reader reader) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateNClob( - String columnLabel, Reader reader) throws SQLException { - throw new UnsupportedOperationException(); - } - } - - private static class XmlaOlap4jPreparedStatementJdbc4 - extends XmlaOlap4jPreparedStatement - { - XmlaOlap4jPreparedStatementJdbc4( - XmlaOlap4jConnection olap4jConnection, - String mdx) throws OlapException - { - super(olap4jConnection, mdx); - } - - public CellSetMetaData getMetaData() { - return super.getMetaData(); - } - - // implement java.sql.PreparedStatement methods - // introduced in JDBC 4.0/JDK 1.6 - - public void setRowId(int parameterIndex, RowId x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setNString( - int parameterIndex, String value) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setNCharacterStream( - int parameterIndex, Reader value, long length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setNClob(int parameterIndex, NClob value) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setClob( - int parameterIndex, Reader reader, long length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setBlob( - int parameterIndex, - InputStream inputStream, - long length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setNClob( - int parameterIndex, Reader reader, long length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setSQLXML( - int parameterIndex, SQLXML xmlObject) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setAsciiStream( - int parameterIndex, InputStream x, long length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setBinaryStream( - int parameterIndex, InputStream x, long length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setCharacterStream( - int parameterIndex, Reader reader, long length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setAsciiStream( - int parameterIndex, InputStream x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setBinaryStream( - int parameterIndex, InputStream x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setCharacterStream( - int parameterIndex, Reader reader) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setNCharacterStream( - int parameterIndex, Reader value) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setClob(int parameterIndex, Reader reader) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setBlob( - int parameterIndex, InputStream inputStream) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setNClob( - int parameterIndex, Reader reader) throws SQLException { - throw new UnsupportedOperationException(); - } - } - - private static class XmlaOlap4jDatabaseMetaDataJdbc4 - extends XmlaOlap4jDatabaseMetaData - { - XmlaOlap4jDatabaseMetaDataJdbc4( - XmlaOlap4jConnection olap4jConnection) - { - super(olap4jConnection); - } - - public OlapConnection getConnection() { - return super.getConnection(); - } - - // implement java.sql.DatabaseMetaData methods - // introduced in JDBC 4.0/JDK 1.6 - - public RowIdLifetime getRowIdLifetime() throws SQLException { - throw new UnsupportedOperationException(); - } - - public ResultSet getSchemas( - String catalog, String schemaPattern) throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsStoredFunctionsUsingCallSyntax() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean autoCommitFailureClosesAllResultSets() throws SQLException { - throw new UnsupportedOperationException(); - } - - public ResultSet getClientInfoProperties() throws SQLException { - throw new UnsupportedOperationException(); - } - - public ResultSet getFunctions( - String catalog, - String schemaPattern, - String functionNamePattern) throws SQLException { - throw new UnsupportedOperationException(); - } - - public ResultSet getFunctionColumns( - String catalog, - String schemaPattern, - String functionNamePattern, - String columnNamePattern) throws SQLException { - throw new UnsupportedOperationException(); - } - } -} - -// End FactoryJdbc4Impl.java +/* +// This software is subject to the terms of the Common Public License +// Agreement, available at the following URL: +// http://www.opensource.org/licenses/cpl.html. +// Copyright (C) 2007-2007 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j.driver.xmla; + +import java.sql.*; +import java.util.*; +import java.io.Reader; +import java.io.InputStream; + +import org.olap4j.*; +import org.olap4j.driver.xmla.proxy.XmlaOlap4jProxy; + +/** + * Implementation of {@link Factory} for JDBC 4.0. + * + * @author jhyde + * @version $Id$ + * @since Jun 14, 2007 + */ +class FactoryJdbc4Impl implements Factory { + public Connection newConnection( + XmlaOlap4jProxy proxy, + String url, + Properties info) + throws SQLException + { + return new XmlaOlap4jConnectionJdbc4( + this, proxy, url, info); + } + + public EmptyResultSet newEmptyResultSet( + XmlaOlap4jConnection olap4jConnection) + { + List headerList = Collections.emptyList(); + List> rowList = Collections.emptyList(); + return new EmptyResultSetJdbc4(olap4jConnection, headerList, rowList); + } + + public ResultSet newFixedResultSet( + XmlaOlap4jConnection olap4jConnection, + List headerList, + List> rowList) + { + return new EmptyResultSetJdbc4( + olap4jConnection, headerList, rowList); + } + + public XmlaOlap4jCellSet newCellSet( + XmlaOlap4jStatement olap4jStatement) throws OlapException + { + return new XmlaOlap4jCellSetJdbc4(olap4jStatement); + } + + public XmlaOlap4jPreparedStatement newPreparedStatement( + String mdx, + XmlaOlap4jConnection olap4jConnection) throws OlapException + { + return new XmlaOlap4jPreparedStatementJdbc4(olap4jConnection, mdx); + } + + public XmlaOlap4jDatabaseMetaData newDatabaseMetaData( + XmlaOlap4jConnection olap4jConnection) + { + return new XmlaOlap4jDatabaseMetaDataJdbc4(olap4jConnection); + } + + // Inner classes + + private static class EmptyResultSetJdbc4 extends EmptyResultSet { + EmptyResultSetJdbc4( + XmlaOlap4jConnection olap4jConnection, + List headerList, + List> rowList) + { + super(olap4jConnection, headerList, rowList); + } + + // implement java.sql.ResultSet methods + // introduced in JDBC 4.0/JDK 1.6 + + public RowId getRowId(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public RowId getRowId(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateRowId(int columnIndex, RowId x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateRowId(String columnLabel, RowId x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getHoldability() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean isClosed() throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateNString( + int columnIndex, String nString) throws SQLException + { + throw new UnsupportedOperationException(); + } + + public void updateNString( + String columnLabel, String nString) throws SQLException + { + throw new UnsupportedOperationException(); + } + + public void updateNClob(int columnIndex, NClob nClob) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateNClob( + String columnLabel, NClob nClob) throws SQLException + { + throw new UnsupportedOperationException(); + } + + public NClob getNClob(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public NClob getNClob(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public SQLXML getSQLXML(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public SQLXML getSQLXML(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateSQLXML( + int columnIndex, SQLXML xmlObject) throws SQLException + { + throw new UnsupportedOperationException(); + } + + public void updateSQLXML( + String columnLabel, SQLXML xmlObject) throws SQLException + { + throw new UnsupportedOperationException(); + } + + public String getNString(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public String getNString(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Reader getNCharacterStream(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Reader getNCharacterStream(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateNCharacterStream( + int columnIndex, Reader x, long length) throws SQLException + { + throw new UnsupportedOperationException(); + } + + public void updateNCharacterStream( + String columnLabel, Reader reader, long length) throws SQLException + { + throw new UnsupportedOperationException(); + } + + public void updateAsciiStream( + int columnIndex, InputStream x, long length) throws SQLException + { + throw new UnsupportedOperationException(); + } + + public void updateBinaryStream( + int columnIndex, InputStream x, long length) throws SQLException + { + throw new UnsupportedOperationException(); + } + + public void updateCharacterStream( + int columnIndex, Reader x, long length) throws SQLException + { + throw new UnsupportedOperationException(); + } + + public void updateAsciiStream( + String columnLabel, InputStream x, long length) throws SQLException + { + throw new UnsupportedOperationException(); + } + + public void updateBinaryStream( + String columnLabel, InputStream x, long length) throws SQLException + { + throw new UnsupportedOperationException(); + } + + public void updateCharacterStream( + String columnLabel, Reader reader, long length) throws SQLException + { + throw new UnsupportedOperationException(); + } + + public void updateBlob( + int columnIndex, + InputStream inputStream, + long length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateBlob( + String columnLabel, + InputStream inputStream, + long length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateClob( + int columnIndex, Reader reader, long length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateClob( + String columnLabel, Reader reader, long length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateNClob( + int columnIndex, Reader reader, long length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateNClob( + String columnLabel, Reader reader, long length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateNCharacterStream( + int columnIndex, Reader x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateNCharacterStream( + String columnLabel, Reader reader) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateAsciiStream( + int columnIndex, InputStream x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateBinaryStream( + int columnIndex, InputStream x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateCharacterStream( + int columnIndex, Reader x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateAsciiStream( + String columnLabel, InputStream x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateBinaryStream( + String columnLabel, InputStream x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateCharacterStream( + String columnLabel, Reader reader) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateBlob( + int columnIndex, InputStream inputStream) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateBlob( + String columnLabel, InputStream inputStream) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateClob(int columnIndex, Reader reader) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateClob( + String columnLabel, Reader reader) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateNClob( + int columnIndex, Reader reader) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateNClob( + String columnLabel, Reader reader) throws SQLException { + throw new UnsupportedOperationException(); + } + } + + private static class XmlaOlap4jConnectionJdbc4 + extends XmlaOlap4jConnection + implements OlapConnection + { + public XmlaOlap4jConnectionJdbc4( + Factory factory, + XmlaOlap4jProxy proxy, + String url, + Properties info) throws SQLException + { + super(factory, proxy, url, info); + } + + public OlapStatement createStatement() { + return super.createStatement(); + } + + public OlapDatabaseMetaData getMetaData() { + return super.getMetaData(); + } + + // implement java.sql.Connection methods + // introduced in JDBC 4.0/JDK 1.6 + + public Clob createClob() throws SQLException { + throw new UnsupportedOperationException(); + } + + public Blob createBlob() throws SQLException { + throw new UnsupportedOperationException(); + } + + public NClob createNClob() throws SQLException { + throw new UnsupportedOperationException(); + } + + public SQLXML createSQLXML() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean isValid(int timeout) throws SQLException { + return !isClosed(); + } + + public void setClientInfo( + String name, String value) throws SQLClientInfoException { + throw new UnsupportedOperationException(); + } + + public void setClientInfo(Properties properties) throws SQLClientInfoException { + throw new UnsupportedOperationException(); + } + + public String getClientInfo(String name) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Properties getClientInfo() throws SQLException { + throw new UnsupportedOperationException(); + } + + public Array createArrayOf( + String typeName, Object[] elements) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Struct createStruct( + String typeName, Object[] attributes) throws SQLException { + throw new UnsupportedOperationException(); + } + } + + private static class XmlaOlap4jCellSetJdbc4 extends XmlaOlap4jCellSet { + XmlaOlap4jCellSetJdbc4( + XmlaOlap4jStatement olap4jStatement) + throws OlapException + { + super(olap4jStatement); + } + + public CellSetMetaData getMetaData() { + return super.getMetaData(); + } + + // implement java.sql.CellSet methods + // introduced in JDBC 4.0/JDK 1.6 + + public RowId getRowId(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public RowId getRowId(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateRowId(int columnIndex, RowId x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateRowId(String columnLabel, RowId x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getHoldability() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean isClosed() throws SQLException { + return closed; + } + + public void updateNString( + int columnIndex, String nString) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateNString( + String columnLabel, String nString) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateNClob(int columnIndex, NClob nClob) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateNClob( + String columnLabel, NClob nClob) throws SQLException { + throw new UnsupportedOperationException(); + } + + public NClob getNClob(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public NClob getNClob(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public SQLXML getSQLXML(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public SQLXML getSQLXML(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateSQLXML( + int columnIndex, SQLXML xmlObject) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateSQLXML( + String columnLabel, SQLXML xmlObject) throws SQLException { + throw new UnsupportedOperationException(); + } + + public String getNString(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public String getNString(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Reader getNCharacterStream(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Reader getNCharacterStream(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateNCharacterStream( + int columnIndex, Reader x, long length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateNCharacterStream( + String columnLabel, Reader reader, long length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateAsciiStream( + int columnIndex, InputStream x, long length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateBinaryStream( + int columnIndex, InputStream x, long length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateCharacterStream( + int columnIndex, Reader x, long length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateAsciiStream( + String columnLabel, InputStream x, long length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateBinaryStream( + String columnLabel, InputStream x, long length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateCharacterStream( + String columnLabel, Reader reader, long length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateBlob( + int columnIndex, + InputStream inputStream, + long length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateBlob( + String columnLabel, + InputStream inputStream, + long length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateClob( + int columnIndex, Reader reader, long length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateClob( + String columnLabel, Reader reader, long length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateNClob( + int columnIndex, Reader reader, long length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateNClob( + String columnLabel, Reader reader, long length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateNCharacterStream( + int columnIndex, Reader x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateNCharacterStream( + String columnLabel, Reader reader) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateAsciiStream( + int columnIndex, InputStream x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateBinaryStream( + int columnIndex, InputStream x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateCharacterStream( + int columnIndex, Reader x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateAsciiStream( + String columnLabel, InputStream x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateBinaryStream( + String columnLabel, InputStream x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateCharacterStream( + String columnLabel, Reader reader) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateBlob( + int columnIndex, InputStream inputStream) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateBlob( + String columnLabel, InputStream inputStream) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateClob(int columnIndex, Reader reader) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateClob( + String columnLabel, Reader reader) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateNClob( + int columnIndex, Reader reader) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateNClob( + String columnLabel, Reader reader) throws SQLException { + throw new UnsupportedOperationException(); + } + } + + private static class XmlaOlap4jPreparedStatementJdbc4 + extends XmlaOlap4jPreparedStatement + { + XmlaOlap4jPreparedStatementJdbc4( + XmlaOlap4jConnection olap4jConnection, + String mdx) throws OlapException + { + super(olap4jConnection, mdx); + } + + public CellSetMetaData getMetaData() { + return super.getMetaData(); + } + + // implement java.sql.PreparedStatement methods + // introduced in JDBC 4.0/JDK 1.6 + + public void setRowId(int parameterIndex, RowId x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setNString( + int parameterIndex, String value) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setNCharacterStream( + int parameterIndex, Reader value, long length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setNClob(int parameterIndex, NClob value) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setClob( + int parameterIndex, Reader reader, long length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setBlob( + int parameterIndex, + InputStream inputStream, + long length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setNClob( + int parameterIndex, Reader reader, long length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setSQLXML( + int parameterIndex, SQLXML xmlObject) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setAsciiStream( + int parameterIndex, InputStream x, long length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setBinaryStream( + int parameterIndex, InputStream x, long length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setCharacterStream( + int parameterIndex, Reader reader, long length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setAsciiStream( + int parameterIndex, InputStream x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setBinaryStream( + int parameterIndex, InputStream x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setCharacterStream( + int parameterIndex, Reader reader) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setNCharacterStream( + int parameterIndex, Reader value) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setClob(int parameterIndex, Reader reader) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setBlob( + int parameterIndex, InputStream inputStream) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setNClob( + int parameterIndex, Reader reader) throws SQLException { + throw new UnsupportedOperationException(); + } + } + + private static class XmlaOlap4jDatabaseMetaDataJdbc4 + extends XmlaOlap4jDatabaseMetaData + { + XmlaOlap4jDatabaseMetaDataJdbc4( + XmlaOlap4jConnection olap4jConnection) + { + super(olap4jConnection); + } + + public OlapConnection getConnection() { + return super.getConnection(); + } + + // implement java.sql.DatabaseMetaData methods + // introduced in JDBC 4.0/JDK 1.6 + + public RowIdLifetime getRowIdLifetime() throws SQLException { + throw new UnsupportedOperationException(); + } + + public ResultSet getSchemas( + String catalog, String schemaPattern) throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsStoredFunctionsUsingCallSyntax() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean autoCommitFailureClosesAllResultSets() throws SQLException { + throw new UnsupportedOperationException(); + } + + public ResultSet getClientInfoProperties() throws SQLException { + throw new UnsupportedOperationException(); + } + + public ResultSet getFunctions( + String catalog, + String schemaPattern, + String functionNamePattern) throws SQLException { + throw new UnsupportedOperationException(); + } + + public ResultSet getFunctionColumns( + String catalog, + String schemaPattern, + String functionNamePattern, + String columnNamePattern) throws SQLException { + throw new UnsupportedOperationException(); + } + } +} + +// End FactoryJdbc4Impl.java diff --git a/src/org/olap4j/driver/xmla/MetadataReader.java b/src/org/olap4j/driver/xmla/MetadataReader.java index b53fee6..100d687 100644 --- a/src/org/olap4j/driver/xmla/MetadataReader.java +++ b/src/org/olap4j/driver/xmla/MetadataReader.java @@ -1,88 +1,88 @@ -/* -// This software is subject to the terms of the Common Public License -// Agreement, available at the following URL: -// http://www.opensource.org/licenses/cpl.html. -// Copyright (C) 2008-2008 Julian Hyde -// All Rights Reserved. -// You must accept the terms of that agreement to use this software. -*/ -package org.olap4j.driver.xmla; - -import org.olap4j.OlapException; -import org.olap4j.metadata.Member; - -import java.util.*; - -/** - * Can read metadata, in particular members. - * - * @author jhyde - * @version $Id: $ - * @since Jan 14, 2008 - */ -interface MetadataReader { - /** - * Looks up a member by its unique name. - * - *

Not part of public olap4j API. - * - * @param memberUniqueName Unique name of member - * @return Member, or null if not found - * @throws org.olap4j.OlapException if error occurs - */ - XmlaOlap4jMember lookupMemberByUniqueName( - String memberUniqueName) - throws OlapException; - - /** - * Looks up a list of members by their unique name and writes the results - * into a map. - * - *

Not part of public olap4j API. - * - * @param memberUniqueNames List of unique names of member - * - * @param memberMap Map to populate with members - * - * @throws org.olap4j.OlapException if error occurs - */ - void lookupMembersByUniqueName( - List memberUniqueNames, - Map memberMap) - throws OlapException; - - /** - * Looks a member by its unique name and returns members related by - * the specified tree-operations. - * - *

Not part of public olap4j API. - * - * @param memberUniqueName Unique name of member - * - * @param treeOps Collection of tree operations to travel relative to - * given member in order to create list of members - * - * @param list list to be populated with members related to the given - * member, or empty set if the member is not found - * - * @throws org.olap4j.OlapException if error occurs - */ - void lookupMemberRelatives( - Set treeOps, - String memberUniqueName, - List list) throws OlapException; - - /** - * Looks up members of a given level. - * - * @param level Level - * - * @throws org.olap4j.OlapException if error occurs - * - * @return list of members at in the level - */ - List getLevelMembers(XmlaOlap4jLevel level) - throws OlapException; -} - -// End MetadataReader.java +/* +// This software is subject to the terms of the Common Public License +// Agreement, available at the following URL: +// http://www.opensource.org/licenses/cpl.html. +// Copyright (C) 2008-2008 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j.driver.xmla; + +import org.olap4j.OlapException; +import org.olap4j.metadata.Member; + +import java.util.*; + +/** + * Can read metadata, in particular members. + * + * @author jhyde + * @version $Id: $ + * @since Jan 14, 2008 + */ +interface MetadataReader { + /** + * Looks up a member by its unique name. + * + *

Not part of public olap4j API. + * + * @param memberUniqueName Unique name of member + * @return Member, or null if not found + * @throws org.olap4j.OlapException if error occurs + */ + XmlaOlap4jMember lookupMemberByUniqueName( + String memberUniqueName) + throws OlapException; + + /** + * Looks up a list of members by their unique name and writes the results + * into a map. + * + *

Not part of public olap4j API. + * + * @param memberUniqueNames List of unique names of member + * + * @param memberMap Map to populate with members + * + * @throws org.olap4j.OlapException if error occurs + */ + void lookupMembersByUniqueName( + List memberUniqueNames, + Map memberMap) + throws OlapException; + + /** + * Looks a member by its unique name and returns members related by + * the specified tree-operations. + * + *

Not part of public olap4j API. + * + * @param memberUniqueName Unique name of member + * + * @param treeOps Collection of tree operations to travel relative to + * given member in order to create list of members + * + * @param list list to be populated with members related to the given + * member, or empty set if the member is not found + * + * @throws org.olap4j.OlapException if error occurs + */ + void lookupMemberRelatives( + Set treeOps, + String memberUniqueName, + List list) throws OlapException; + + /** + * Looks up members of a given level. + * + * @param level Level + * + * @throws org.olap4j.OlapException if error occurs + * + * @return list of members at in the level + */ + List getLevelMembers(XmlaOlap4jLevel level) + throws OlapException; +} + +// End MetadataReader.java diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jCatalog.java b/src/org/olap4j/driver/xmla/XmlaOlap4jCatalog.java index d0fbe6a..7d657ba 100644 --- a/src/org/olap4j/driver/xmla/XmlaOlap4jCatalog.java +++ b/src/org/olap4j/driver/xmla/XmlaOlap4jCatalog.java @@ -35,13 +35,13 @@ class XmlaOlap4jCatalog implements Catalog, Named { assert name != null; this.olap4jDatabaseMetaData = olap4jDatabaseMetaData; this.name = name; - + /* * Fetching the schemas is a tricky part. There are no XMLA requests to obtain the * available schemas for a given catalog. We therefore need to ask for the cubes, * restricting results on the catalog, and while iterating on the cubes, take the schema * name from this recordset. - * + * * Many servers (SSAS for example) won't support the schema name column in the * returned rowset. This has to be taken into account. */ diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jCellSet.java b/src/org/olap4j/driver/xmla/XmlaOlap4jCellSet.java index 04cc76c..84b4171 100644 --- a/src/org/olap4j/driver/xmla/XmlaOlap4jCellSet.java +++ b/src/org/olap4j/driver/xmla/XmlaOlap4jCellSet.java @@ -1,1364 +1,1366 @@ -/* -// This software is subject to the terms of the Common Public License -// Agreement, available at the following URL: -// http://www.opensource.org/licenses/cpl.html. -// Copyright (C) 2007-2007 Julian Hyde -// All Rights Reserved. -// You must accept the terms of that agreement to use this software. -*/ -package org.olap4j.driver.xmla; - -import org.olap4j.*; -import org.olap4j.mdx.ParseTreeNode; -import org.olap4j.impl.Olap4jUtil; -import static org.olap4j.driver.xmla.XmlaOlap4jUtil.*; -import org.olap4j.metadata.*; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.xml.sax.SAXException; - -import java.io.*; -import java.math.BigDecimal; -import java.net.URL; -import java.sql.*; -import java.sql.Date; -import java.util.*; - -/** - * Implementation of {@link org.olap4j.CellSet} - * for XML/A providers. - * - *

This class has sub-classes which implement JDBC 3.0 and JDBC 4.0 APIs; - * it is instantiated using {@link Factory#newCellSet}.

- * - * @author jhyde - * @version $Id$ - * @since May 24, 2007 - */ -abstract class XmlaOlap4jCellSet implements CellSet { - final XmlaOlap4jStatement olap4jStatement; - protected boolean closed; - private XmlaOlap4jCellSetMetaData metaData; - private final Map cellMap = - new HashMap(); - private final List axisList = - new ArrayList(); - private final List immutableAxisList = - Olap4jUtil.cast(Collections.unmodifiableList(axisList)); - private XmlaOlap4jCellSetAxis filterAxis; - private static final boolean DEBUG = false; - - private static final List standardProperties = Arrays.asList( - "UName", "Caption", "LName", "LNum", "DisplayInfo"); - - /** - * Creates an XmlaOlap4jCellSet. - * - * @param olap4jStatement Statement - */ - XmlaOlap4jCellSet( - XmlaOlap4jStatement olap4jStatement) - { - assert olap4jStatement != null; - this.olap4jStatement = olap4jStatement; - this.closed = false; - } - - /** - * Gets response from the XMLA request and populates cell set axes and cells - * with it. - * - * @throws OlapException on error - */ - void populate() throws OlapException { - byte[] bytes = olap4jStatement.getBytes(); - - Document doc; - try { - doc = parse(bytes); - } catch (IOException e) { - throw olap4jStatement.olap4jConnection.helper.createException( - "error creating CellSet", e); - } catch (SAXException e) { - throw olap4jStatement.olap4jConnection.helper.createException( - "error creating CellSet", e); - } - // - // - // - // - // - // - // (see below) - // - // - // - // - // - final Element envelope = doc.getDocumentElement(); - if (DEBUG) System.out.println(XmlaOlap4jUtil.toString(doc,true)); - assert envelope.getLocalName().equals("Envelope"); - assert envelope.getNamespaceURI().equals(SOAP_NS); - Element body = - findChild(envelope, SOAP_NS, "Body"); - Element fault = - findChild(body, SOAP_NS, "Fault"); - if (fault != null) { - /* - Example: - - - SOAP-ENV:Client.00HSBC01 - XMLA connection datasource not found - Mondrian - - - 00HSBC01 - The Mondrian XML: Mondrian Error:Internal - error: no catalog named 'LOCALDB' - - - - */ - // TODO: log doc to logfile - final Element faultstring = findChild(fault, null, "faultstring"); - String message = faultstring.getTextContent(); - throw olap4jStatement.olap4jConnection.helper.createException( - "XMLA provider gave exception: " + message); - } - Element executeResponse = - findChild(body, XMLA_NS, "ExecuteResponse"); - Element returnElement = - findChild(executeResponse, XMLA_NS, "return"); - // has children - // - // - // - // - // FOO - // - // - // - // ... - // - // - // - // - // - // - // ... - // - // - // - // ... - // - final Element root = - findChild(returnElement, MDDATASET_NS, "root"); - - if (olap4jStatement instanceof XmlaOlap4jPreparedStatement) { - this.metaData = - ((XmlaOlap4jPreparedStatement) olap4jStatement) - .cellSetMetaData; - } else { - this.metaData = createMetaData(root); - } - - // todo: use CellInfo element to determine mapping of cell properties - // to XML tags - /* - - - - - - */ - - final Element axesNode = findChild(root, MDDATASET_NS, "Axes"); - for (Element axisNode : findChildren(axesNode, MDDATASET_NS, "Axis")) { - final String axisName = axisNode.getAttribute("name"); - final Axis axis = lookupAxis(axisName); - final XmlaOlap4jCellSetAxis cellSetAxis = - new XmlaOlap4jCellSetAxis(this, axis); - switch (axis) { - case FILTER: - filterAxis = cellSetAxis; - break; - default: - axisList.add(cellSetAxis); - break; - } - final Element tuplesNode = - findChild(axisNode, MDDATASET_NS, "Tuples"); - int ordinal = 0; - final Map propertyValues = - new HashMap(); - - // First pass, gather up a list of member unique names to fetch - // all at once. - // - // NOTE: This approach allows the driver to fetch a large number - // of members in one round trip, which is much more efficient. - // However, if the axis has a very large number of members, the map - // may use too much memory. This is an unresolved issue. - final MetadataReader metadataReader = - metaData.cube.getMetadataReader(); - final Map memberMap = - new HashMap(); - List uniqueNames = new ArrayList(); - for (Element tupleNode - : findChildren(tuplesNode, MDDATASET_NS, "Tuple")) - { - for (Element memberNode - : findChildren(tupleNode, MDDATASET_NS, "Member")) - { - final String uname = stringElement(memberNode, "UName"); - uniqueNames.add(uname); - } - } - metadataReader.lookupMembersByUniqueName(uniqueNames, memberMap); - - // Second pass, populate the axis. - for (Element tupleNode - : findChildren(tuplesNode, MDDATASET_NS, "Tuple")) - { - final List members = new ArrayList(); - for (Element memberNode - : findChildren(tupleNode, MDDATASET_NS, "Member")) - { - String hierarchyName = - memberNode.getAttribute("Hierarchy"); - final String uname = stringElement(memberNode, "UName"); - Member member = memberMap.get(uname); - if (member == null) { - final String caption = - stringElement(memberNode, "Caption"); - final int lnum = integerElement(memberNode, "LNum"); - final Hierarchy hierarchy = - lookupHierarchy(metaData.cube, hierarchyName); - final Level level = hierarchy.getLevels().get(lnum); - member = new XmlaOlap4jSurpriseMember( - level, hierarchy, lnum, caption, uname); - } - propertyValues.clear(); - for (Element childNode : childElements(memberNode)) { - XmlaOlap4jCellSetMemberProperty property = - ((XmlaOlap4jCellSetAxisMetaData) - cellSetAxis.getAxisMetaData()).lookupProperty( - hierarchyName, - childNode.getLocalName()); - if (property != null) { - String value = childNode.getTextContent(); - propertyValues.put(property, value); - } - } - if (!propertyValues.isEmpty()) { - member = - new XmlaOlap4jPositionMember( - member, propertyValues); - } - members.add(member); - } - cellSetAxis.positions.add( - new XmlaOlap4jPosition(members, ordinal++)); - } - } - - final Map propertyValues = - new HashMap(); - final Element cellDataNode = findChild(root, MDDATASET_NS, "CellData"); - for (Element cell : findChildren(cellDataNode, MDDATASET_NS, "Cell")) { - propertyValues.clear(); - final int cellOrdinal = - Integer.valueOf(cell.getAttribute("CellOrdinal")); - final Object value = getTypedValue(cell); - final String formattedValue = stringElement(cell, "FmtValue"); - final String formatString = stringElement(cell, "FormatString"); - Olap4jUtil.discard(formatString); - for (Element element : childElements(cell)) { - String tag = element.getLocalName(); - final Property property = - metaData.propertiesByTag.get(tag); - if (property != null) { - propertyValues.put(property, element.getTextContent()); - } - } - cellMap.put( - cellOrdinal, - new XmlaOlap4jCell( - this, - cellOrdinal, - value, - formattedValue, - propertyValues)); - } - } - - /** - * Returns the value of a cell, cast to the appropriate Java object type - * corresponding to the XML schema (XSD) type of the value. - * - *

The value type must conform to XSD definitions of the XML element. See - * RELAX - * NG, Chapter 19 for a full list of possible data types. - * - *

This method does not currently support all types; must numeric types - * are supported, but no dates are yet supported. Those not supported - * fall back to Strings. - * - * @param cell The cell of which we want the casted object. - * @return The object with a correct value. - * @throws OlapException if any error is encountered while casting the cell - * value - */ - private Object getTypedValue(Element cell) throws OlapException { - Element elm = findChild(cell, MDDATASET_NS, "Value"); - if (elm == null) { - // Cell is null. - return null; - } - - // The object type is contained in xsi:type attribute. - String type = elm.getAttribute("xsi:type"); - try { - if (type.equals( "xsd:int")) { - return XmlaOlap4jUtil.intElement(cell, "Value"); - } else if (type.equals( "xsd:integer")) { - return XmlaOlap4jUtil.integerElement(cell, "Value"); - } else if (type.equals( "xsd:double")) { - return XmlaOlap4jUtil.doubleElement(cell, "Value"); - } else if (type.equals( "xsd:float")) { - return XmlaOlap4jUtil.floatElement(cell, "Value"); - } else if (type.equals( "xsd:long")) { - return XmlaOlap4jUtil.longElement(cell, "Value"); - } else if (type.equals( "xsd:boolean")) { - return XmlaOlap4jUtil.booleanElement(cell, "Value"); - } else { - return XmlaOlap4jUtil.stringElement(cell, "Value"); - } - } catch (Exception e) { - throw new OlapException( - "Error while casting a cell value to the correct java type for" - + " its XSD type " + type, - e); - } - } - - /** - * Creates metadata for a cell set, given the DOM of the XMLA result. - * - * @param root Root node of XMLA result - * @return Metadata describing this cell set - * @throws OlapException on error - */ - private XmlaOlap4jCellSetMetaData createMetaData(Element root) - throws OlapException - { - final Element olapInfo = - findChild(root, MDDATASET_NS, "OlapInfo"); - final Element cubeInfo = - findChild(olapInfo, MDDATASET_NS, "CubeInfo"); - final Element cubeNode = - findChild(cubeInfo, MDDATASET_NS, "Cube"); - final Element cubeNameNode = - findChild(cubeNode, MDDATASET_NS, "CubeName"); - final String cubeName = gatherText(cubeNameNode); - final XmlaOlap4jCube cube = - (XmlaOlap4jCube) - this.olap4jStatement.olap4jConnection.getSchema().getCubes().get( - cubeName); - if (cube == null) { - throw olap4jStatement.olap4jConnection.helper.createException( - "Internal error: cube '" + cubeName + "' not found"); - } - final Element axesInfo = - findChild(olapInfo, MDDATASET_NS, "AxesInfo"); - final List axisInfos = - findChildren(axesInfo, MDDATASET_NS, "AxisInfo"); - final List axisMetaDataList = - new ArrayList(); - XmlaOlap4jCellSetAxisMetaData filterAxisMetaData = null; - for (Element axisInfo : axisInfos) { - final String axisName = axisInfo.getAttribute("name"); - Axis axis = lookupAxis(axisName); - final List hierarchyInfos = - findChildren(axisInfo, MDDATASET_NS, "HierarchyInfo"); - final List hierarchyList = - new ArrayList(); - /* - - - - - - - - - - - - ... - - - - - - - - */ - final List propertyList = - new ArrayList(); - for (Element hierarchyInfo : hierarchyInfos) { - final String hierarchyName = hierarchyInfo.getAttribute("name"); - Hierarchy hierarchy = lookupHierarchy(cube, hierarchyName); - hierarchyList.add(hierarchy); - for (Element childNode : childElements(hierarchyInfo)) { - String tag = childNode.getLocalName(); - if (standardProperties.contains(tag)) { - continue; - } - final String propertyUniqueName = - childNode.getAttribute("name"); - final XmlaOlap4jCellSetMemberProperty property = - new XmlaOlap4jCellSetMemberProperty( - propertyUniqueName, - hierarchy, - tag); - propertyList.add(property); - } - } - final XmlaOlap4jCellSetAxisMetaData axisMetaData = - new XmlaOlap4jCellSetAxisMetaData( - olap4jStatement.olap4jConnection, - axis, - hierarchyList, - propertyList); - switch (axis) { - case FILTER: - filterAxisMetaData = axisMetaData; - break; - default: - axisMetaDataList.add(axisMetaData); - break; - } - } - final Element cellInfo = - findChild(olapInfo, MDDATASET_NS, "CellInfo"); - List cellProperties = - new ArrayList(); - for (Element element : childElements(cellInfo)) { - cellProperties.add( - new XmlaOlap4jCellProperty( - element.getLocalName(), - element.getAttribute("name"))); - } - return - new XmlaOlap4jCellSetMetaData( - olap4jStatement, - cube, - filterAxisMetaData, - axisMetaDataList, - cellProperties); - } - - /** - * Looks up a hierarchy in a cube with a given name or, failing that, a - * given unique name. Throws if not found. - * - * @param cube Cube - * @param hierarchyName Name (or unique name) of hierarchy. - * @return Hierarchy - * @throws OlapException - */ - private Hierarchy lookupHierarchy(XmlaOlap4jCube cube, String hierarchyName) - throws OlapException - { - Hierarchy hierarchy = cube.getHierarchies().get(hierarchyName); - if (hierarchy == null) { - for (Hierarchy hierarchy1 : cube.getHierarchies()) { - if (hierarchy1.getUniqueName().equals(hierarchyName)) { - hierarchy = hierarchy1; - break; - } - } - if (hierarchy == null) { - throw this.olap4jStatement.olap4jConnection.helper - .createException( - "Internal error: hierarchy '" + hierarchyName - + "' not found in cube '" + cube.getName() - + "'"); - } - } - return hierarchy; - } - - /** - * Looks up an Axis with a given name. - * - * @param axisName Name of axis - * @return Axis - */ - private Axis lookupAxis(String axisName) { - if (axisName.startsWith("Axis")) { - final Integer ordinal = - Integer.valueOf(axisName.substring("Axis".length())); - return Axis.values()[Axis.COLUMNS.ordinal() + ordinal]; - } else { - return Axis.FILTER; - } - } - - public CellSetMetaData getMetaData() { - return metaData; - } - - public Cell getCell(List coordinates) { - return getCellInternal(coordinatesToOrdinal(coordinates)); - } - - public Cell getCell(int ordinal) { - return getCellInternal(ordinal); - } - - public Cell getCell(Position... positions) { - if (positions.length != getAxes().size()) { - throw new IllegalArgumentException( - "cell coordinates should have dimension " + getAxes().size()); - } - List coords = new ArrayList(positions.length); - for (Position position : positions) { - coords.add(position.getOrdinal()); - } - return getCell(coords); - } - - /** - * Returns a cell given its ordinal. - * - * @param pos Ordinal - * @return Cell - * @throws IndexOutOfBoundsException if ordinal is not in range - */ - private Cell getCellInternal(int pos) { - final Cell cell = cellMap.get(pos); - if (cell == null) { - if (pos < 0 || pos >= maxOrdinal()) { - throw new IndexOutOfBoundsException(); - } else { - // Cell is within bounds, but is not held in the cache because - // it has no value. Manufacture a cell with an empty value. - return new XmlaOlap4jCell( - this, pos, null, "", - Collections.emptyMap()); - } - } - return cell; - } - - /** - * Returns a string describing the maximum coordinates of this cell set; - * for example "2, 3" for a cell set with 2 columns and 3 rows. - * - * @return description of cell set bounds - */ - private String getBoundsAsString() { - StringBuilder buf = new StringBuilder(); - int k = 0; - for (CellSetAxis axis : getAxes()) { - if (k++ > 0) { - buf.append(", "); - } - buf.append(axis.getPositionCount()); - } - return buf.toString(); - } - - public List getAxes() { - return immutableAxisList; - } - - public CellSetAxis getFilterAxis() { - return filterAxis; - } - - /** - * Returns the ordinal of the last cell in this cell set. This is the - * product of the cardinalities of all axes. - * - * @return ordinal of last cell in cell set - */ - private int maxOrdinal() { - int modulo = 1; - for (CellSetAxis axis : axisList) { - modulo *= axis.getPositionCount(); - } - return modulo; - } - - public List ordinalToCoordinates(int ordinal) { - List axes = getAxes(); - final List list = new ArrayList(axes.size()); - int modulo = 1; - for (CellSetAxis axis : axes) { - int prevModulo = modulo; - modulo *= axis.getPositionCount(); - list.add((ordinal % modulo) / prevModulo); - } - if (ordinal < 0 || ordinal >= modulo) { - throw new IndexOutOfBoundsException( - "Cell ordinal " + ordinal - + ") lies outside CellSet bounds (" - + getBoundsAsString() + ")"); - } - return list; - } - - public int coordinatesToOrdinal(List coordinates) { - List axes = getAxes(); - if (coordinates.size() != axes.size()) { - throw new IllegalArgumentException( - "Coordinates have different dimension " + coordinates.size() - + " than axes " + axes.size()); - } - int modulo = 1; - int ordinal = 0; - int k = 0; - for (CellSetAxis axis : axes) { - final Integer coordinate = coordinates.get(k++); - if (coordinate < 0 || coordinate >= axis.getPositionCount()) { - throw new IndexOutOfBoundsException( - "Coordinate " + coordinate - + " of axis " + k - + " is out of range (" - + getBoundsAsString() + ")"); - } - ordinal += coordinate * modulo; - modulo *= axis.getPositionCount(); - } - return ordinal; - } - - public boolean next() throws SQLException { - throw new UnsupportedOperationException(); - } - - public void close() throws SQLException { - this.closed = true; - } - - public boolean wasNull() throws SQLException { - throw new UnsupportedOperationException(); - } - - public String getString(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean getBoolean(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public byte getByte(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public short getShort(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getInt(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public long getLong(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public float getFloat(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public double getDouble(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public BigDecimal getBigDecimal( - int columnIndex, int scale) throws SQLException { - throw new UnsupportedOperationException(); - } - - public byte[] getBytes(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Date getDate(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Time getTime(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Timestamp getTimestamp(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public InputStream getAsciiStream(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public InputStream getUnicodeStream(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public InputStream getBinaryStream(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public String getString(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean getBoolean(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public byte getByte(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public short getShort(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getInt(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public long getLong(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public float getFloat(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public double getDouble(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public BigDecimal getBigDecimal( - String columnLabel, int scale) throws SQLException { - throw new UnsupportedOperationException(); - } - - public byte[] getBytes(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Date getDate(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Time getTime(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Timestamp getTimestamp(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public InputStream getAsciiStream(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public InputStream getUnicodeStream(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public InputStream getBinaryStream(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public SQLWarning getWarnings() throws SQLException { - throw new UnsupportedOperationException(); - } - - public void clearWarnings() throws SQLException { - throw new UnsupportedOperationException(); - } - - public String getCursorName() throws SQLException { - throw new UnsupportedOperationException(); - } - - public Object getObject(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Object getObject(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public int findColumn(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Reader getCharacterStream(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Reader getCharacterStream(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public BigDecimal getBigDecimal(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public BigDecimal getBigDecimal(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean isBeforeFirst() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean isAfterLast() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean isFirst() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean isLast() throws SQLException { - throw new UnsupportedOperationException(); - } - - public void beforeFirst() throws SQLException { - throw new UnsupportedOperationException(); - } - - public void afterLast() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean first() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean last() throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getRow() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean absolute(int row) throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean relative(int rows) throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean previous() throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setFetchDirection(int direction) throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getFetchDirection() throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setFetchSize(int rows) throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getFetchSize() throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getType() throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getConcurrency() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean rowUpdated() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean rowInserted() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean rowDeleted() throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateNull(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateBoolean(int columnIndex, boolean x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateByte(int columnIndex, byte x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateShort(int columnIndex, short x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateInt(int columnIndex, int x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateLong(int columnIndex, long x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateFloat(int columnIndex, float x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateDouble(int columnIndex, double x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateBigDecimal( - int columnIndex, BigDecimal x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateString(int columnIndex, String x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateBytes(int columnIndex, byte x[]) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateDate(int columnIndex, Date x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateTime(int columnIndex, Time x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateTimestamp( - int columnIndex, Timestamp x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateAsciiStream( - int columnIndex, InputStream x, int length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateBinaryStream( - int columnIndex, InputStream x, int length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateCharacterStream( - int columnIndex, Reader x, int length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateObject( - int columnIndex, Object x, int scaleOrLength) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateObject(int columnIndex, Object x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateNull(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateBoolean( - String columnLabel, boolean x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateByte(String columnLabel, byte x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateShort(String columnLabel, short x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateInt(String columnLabel, int x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateLong(String columnLabel, long x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateFloat(String columnLabel, float x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateDouble(String columnLabel, double x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateBigDecimal( - String columnLabel, BigDecimal x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateString(String columnLabel, String x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateBytes(String columnLabel, byte x[]) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateDate(String columnLabel, Date x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateTime(String columnLabel, Time x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateTimestamp( - String columnLabel, Timestamp x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateAsciiStream( - String columnLabel, InputStream x, int length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateBinaryStream( - String columnLabel, InputStream x, int length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateCharacterStream( - String columnLabel, Reader reader, int length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateObject( - String columnLabel, Object x, int scaleOrLength) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateObject(String columnLabel, Object x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void insertRow() throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateRow() throws SQLException { - throw new UnsupportedOperationException(); - } - - public void deleteRow() throws SQLException { - throw new UnsupportedOperationException(); - } - - public void refreshRow() throws SQLException { - throw new UnsupportedOperationException(); - } - - public void cancelRowUpdates() throws SQLException { - throw new UnsupportedOperationException(); - } - - public void moveToInsertRow() throws SQLException { - throw new UnsupportedOperationException(); - } - - public void moveToCurrentRow() throws SQLException { - throw new UnsupportedOperationException(); - } - - public Statement getStatement() throws SQLException { - throw new UnsupportedOperationException(); - } - - public Object getObject( - int columnIndex, Map> map) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Ref getRef(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Blob getBlob(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Clob getClob(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Array getArray(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Object getObject( - String columnLabel, Map> map) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Ref getRef(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Blob getBlob(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Clob getClob(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Array getArray(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Date getDate(int columnIndex, Calendar cal) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Date getDate(String columnLabel, Calendar cal) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Time getTime(int columnIndex, Calendar cal) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Time getTime(String columnLabel, Calendar cal) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Timestamp getTimestamp( - int columnIndex, Calendar cal) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Timestamp getTimestamp( - String columnLabel, Calendar cal) throws SQLException { - throw new UnsupportedOperationException(); - } - - public URL getURL(int columnIndex) throws SQLException { - throw new UnsupportedOperationException(); - } - - public URL getURL(String columnLabel) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateRef(int columnIndex, Ref x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateRef(String columnLabel, Ref x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateBlob(int columnIndex, Blob x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateBlob(String columnLabel, Blob x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateClob(int columnIndex, Clob x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateClob(String columnLabel, Clob x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateArray(int columnIndex, Array x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void updateArray(String columnLabel, Array x) throws SQLException { - throw new UnsupportedOperationException(); - } - - // implement Wrapper - - public T unwrap(Class iface) throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean isWrapperFor(Class iface) throws SQLException { - throw new UnsupportedOperationException(); - } - - /** - * Implementation of {@link Member} for a member which is not present - * in the cube (probably because the member is a calculated member - * defined in the query). - */ - private static class XmlaOlap4jSurpriseMember implements Member { - private final Level level; - private final Hierarchy hierarchy; - private final int lnum; - private final String caption; - private final String uname; - - /** - * Creates an XmlaOlap4jSurpriseMember. - * - * @param level Level - * @param hierarchy Hierarchy - * @param lnum Level number - * @param caption Caption - * @param uname Member unique name - */ - XmlaOlap4jSurpriseMember( - Level level, - Hierarchy hierarchy, - int lnum, - String caption, - String uname) - { - this.level = level; - this.hierarchy = hierarchy; - this.lnum = lnum; - this.caption = caption; - this.uname = uname; - } - - public NamedList getChildMembers() - { - return Olap4jUtil.emptyNamedList(); - } - - public int getChildMemberCount() { - return 0; - } - - public Member getParentMember() { - return null; - } - - public Level getLevel() { - return level; - } - - public Hierarchy getHierarchy() { - return hierarchy; - } - - public Dimension getDimension() { - return hierarchy.getDimension(); - } - - public Type getMemberType() { - return Type.UNKNOWN; - } - - public boolean isAll() { - return false; // FIXME - } - - public boolean isChildOrEqualTo(Member member) { - return false; // FIXME - } - - public boolean isCalculated() { - return false; // FIXME - } - - public int getSolveOrder() { - return 0; // FIXME - } - - public ParseTreeNode getExpression() { - return null; - } - - public List getAncestorMembers() { - return Collections.emptyList(); // FIXME - } - - public boolean isCalculatedInQuery() { - return true; // probably - } - - public Object getPropertyValue(Property property) { - return null; - } - - public String getPropertyFormattedValue(Property property) { - return null; - } - - public void setProperty(Property property, Object value) - { - throw new UnsupportedOperationException(); - } - - public NamedList getProperties() { - return Olap4jUtil.emptyNamedList(); - } - - public int getOrdinal() { - return -1; // FIXME - } - - public boolean isHidden() { - return false; - } - - public int getDepth() { - return lnum; - } - - public Member getDataMember() { - return null; - } - - public String getName() { - return caption; - } - - public String getUniqueName() { - return uname; - } - - public String getCaption(Locale locale) { - return caption; - } - - public String getDescription(Locale locale) { - return null; - } - } -} - -// End XmlaOlap4jCellSet.java +/* +// This software is subject to the terms of the Common Public License +// Agreement, available at the following URL: +// http://www.opensource.org/licenses/cpl.html. +// Copyright (C) 2007-2007 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j.driver.xmla; + +import org.olap4j.*; +import org.olap4j.mdx.ParseTreeNode; +import org.olap4j.impl.Olap4jUtil; +import static org.olap4j.driver.xmla.XmlaOlap4jUtil.*; +import org.olap4j.metadata.*; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.SAXException; + +import java.io.*; +import java.math.BigDecimal; +import java.net.URL; +import java.sql.*; +import java.sql.Date; +import java.util.*; + +/** + * Implementation of {@link org.olap4j.CellSet} + * for XML/A providers. + * + *

This class has sub-classes which implement JDBC 3.0 and JDBC 4.0 APIs; + * it is instantiated using {@link Factory#newCellSet}.

+ * + * @author jhyde + * @version $Id$ + * @since May 24, 2007 + */ +abstract class XmlaOlap4jCellSet implements CellSet { + final XmlaOlap4jStatement olap4jStatement; + protected boolean closed; + private XmlaOlap4jCellSetMetaData metaData; + private final Map cellMap = + new HashMap(); + private final List axisList = + new ArrayList(); + private final List immutableAxisList = + Olap4jUtil.cast(Collections.unmodifiableList(axisList)); + private XmlaOlap4jCellSetAxis filterAxis; + private static final boolean DEBUG = false; + + private static final List standardProperties = Arrays.asList( + "UName", "Caption", "LName", "LNum", "DisplayInfo"); + + /** + * Creates an XmlaOlap4jCellSet. + * + * @param olap4jStatement Statement + */ + XmlaOlap4jCellSet( + XmlaOlap4jStatement olap4jStatement) + { + assert olap4jStatement != null; + this.olap4jStatement = olap4jStatement; + this.closed = false; + } + + /** + * Gets response from the XMLA request and populates cell set axes and cells + * with it. + * + * @throws OlapException on error + */ + void populate() throws OlapException { + byte[] bytes = olap4jStatement.getBytes(); + + Document doc; + try { + doc = parse(bytes); + } catch (IOException e) { + throw olap4jStatement.olap4jConnection.helper.createException( + "error creating CellSet", e); + } catch (SAXException e) { + throw olap4jStatement.olap4jConnection.helper.createException( + "error creating CellSet", e); + } + // + // + // + // + // + // + // (see below) + // + // + // + // + // + final Element envelope = doc.getDocumentElement(); + if (DEBUG) { + System.out.println(XmlaOlap4jUtil.toString(doc, true)); + } + assert envelope.getLocalName().equals("Envelope"); + assert envelope.getNamespaceURI().equals(SOAP_NS); + Element body = + findChild(envelope, SOAP_NS, "Body"); + Element fault = + findChild(body, SOAP_NS, "Fault"); + if (fault != null) { + /* + Example: + + + SOAP-ENV:Client.00HSBC01 + XMLA connection datasource not found + Mondrian + + + 00HSBC01 + The Mondrian XML: Mondrian Error:Internal + error: no catalog named 'LOCALDB' + + + + */ + // TODO: log doc to logfile + final Element faultstring = findChild(fault, null, "faultstring"); + String message = faultstring.getTextContent(); + throw olap4jStatement.olap4jConnection.helper.createException( + "XMLA provider gave exception: " + message); + } + Element executeResponse = + findChild(body, XMLA_NS, "ExecuteResponse"); + Element returnElement = + findChild(executeResponse, XMLA_NS, "return"); + // has children + // + // + // + // + // FOO + // + // + // + // ... + // + // + // + // + // + // + // ... + // + // + // + // ... + // + final Element root = + findChild(returnElement, MDDATASET_NS, "root"); + + if (olap4jStatement instanceof XmlaOlap4jPreparedStatement) { + this.metaData = + ((XmlaOlap4jPreparedStatement) olap4jStatement) + .cellSetMetaData; + } else { + this.metaData = createMetaData(root); + } + + // todo: use CellInfo element to determine mapping of cell properties + // to XML tags + /* + + + + + + */ + + final Element axesNode = findChild(root, MDDATASET_NS, "Axes"); + for (Element axisNode : findChildren(axesNode, MDDATASET_NS, "Axis")) { + final String axisName = axisNode.getAttribute("name"); + final Axis axis = lookupAxis(axisName); + final XmlaOlap4jCellSetAxis cellSetAxis = + new XmlaOlap4jCellSetAxis(this, axis); + switch (axis) { + case FILTER: + filterAxis = cellSetAxis; + break; + default: + axisList.add(cellSetAxis); + break; + } + final Element tuplesNode = + findChild(axisNode, MDDATASET_NS, "Tuples"); + int ordinal = 0; + final Map propertyValues = + new HashMap(); + + // First pass, gather up a list of member unique names to fetch + // all at once. + // + // NOTE: This approach allows the driver to fetch a large number + // of members in one round trip, which is much more efficient. + // However, if the axis has a very large number of members, the map + // may use too much memory. This is an unresolved issue. + final MetadataReader metadataReader = + metaData.cube.getMetadataReader(); + final Map memberMap = + new HashMap(); + List uniqueNames = new ArrayList(); + for (Element tupleNode + : findChildren(tuplesNode, MDDATASET_NS, "Tuple")) + { + for (Element memberNode + : findChildren(tupleNode, MDDATASET_NS, "Member")) + { + final String uname = stringElement(memberNode, "UName"); + uniqueNames.add(uname); + } + } + metadataReader.lookupMembersByUniqueName(uniqueNames, memberMap); + + // Second pass, populate the axis. + for (Element tupleNode + : findChildren(tuplesNode, MDDATASET_NS, "Tuple")) + { + final List members = new ArrayList(); + for (Element memberNode + : findChildren(tupleNode, MDDATASET_NS, "Member")) + { + String hierarchyName = + memberNode.getAttribute("Hierarchy"); + final String uname = stringElement(memberNode, "UName"); + Member member = memberMap.get(uname); + if (member == null) { + final String caption = + stringElement(memberNode, "Caption"); + final int lnum = integerElement(memberNode, "LNum"); + final Hierarchy hierarchy = + lookupHierarchy(metaData.cube, hierarchyName); + final Level level = hierarchy.getLevels().get(lnum); + member = new XmlaOlap4jSurpriseMember( + level, hierarchy, lnum, caption, uname); + } + propertyValues.clear(); + for (Element childNode : childElements(memberNode)) { + XmlaOlap4jCellSetMemberProperty property = + ((XmlaOlap4jCellSetAxisMetaData) + cellSetAxis.getAxisMetaData()).lookupProperty( + hierarchyName, + childNode.getLocalName()); + if (property != null) { + String value = childNode.getTextContent(); + propertyValues.put(property, value); + } + } + if (!propertyValues.isEmpty()) { + member = + new XmlaOlap4jPositionMember( + member, propertyValues); + } + members.add(member); + } + cellSetAxis.positions.add( + new XmlaOlap4jPosition(members, ordinal++)); + } + } + + final Map propertyValues = + new HashMap(); + final Element cellDataNode = findChild(root, MDDATASET_NS, "CellData"); + for (Element cell : findChildren(cellDataNode, MDDATASET_NS, "Cell")) { + propertyValues.clear(); + final int cellOrdinal = + Integer.valueOf(cell.getAttribute("CellOrdinal")); + final Object value = getTypedValue(cell); + final String formattedValue = stringElement(cell, "FmtValue"); + final String formatString = stringElement(cell, "FormatString"); + Olap4jUtil.discard(formatString); + for (Element element : childElements(cell)) { + String tag = element.getLocalName(); + final Property property = + metaData.propertiesByTag.get(tag); + if (property != null) { + propertyValues.put(property, element.getTextContent()); + } + } + cellMap.put( + cellOrdinal, + new XmlaOlap4jCell( + this, + cellOrdinal, + value, + formattedValue, + propertyValues)); + } + } + + /** + * Returns the value of a cell, cast to the appropriate Java object type + * corresponding to the XML schema (XSD) type of the value. + * + *

The value type must conform to XSD definitions of the XML element. See + * RELAX + * NG, Chapter 19 for a full list of possible data types. + * + *

This method does not currently support all types; must numeric types + * are supported, but no dates are yet supported. Those not supported + * fall back to Strings. + * + * @param cell The cell of which we want the casted object. + * @return The object with a correct value. + * @throws OlapException if any error is encountered while casting the cell + * value + */ + private Object getTypedValue(Element cell) throws OlapException { + Element elm = findChild(cell, MDDATASET_NS, "Value"); + if (elm == null) { + // Cell is null. + return null; + } + + // The object type is contained in xsi:type attribute. + String type = elm.getAttribute("xsi:type"); + try { + if (type.equals("xsd:int")) { + return XmlaOlap4jUtil.intElement(cell, "Value"); + } else if (type.equals("xsd:integer")) { + return XmlaOlap4jUtil.integerElement(cell, "Value"); + } else if (type.equals("xsd:double")) { + return XmlaOlap4jUtil.doubleElement(cell, "Value"); + } else if (type.equals("xsd:float")) { + return XmlaOlap4jUtil.floatElement(cell, "Value"); + } else if (type.equals("xsd:long")) { + return XmlaOlap4jUtil.longElement(cell, "Value"); + } else if (type.equals("xsd:boolean")) { + return XmlaOlap4jUtil.booleanElement(cell, "Value"); + } else { + return XmlaOlap4jUtil.stringElement(cell, "Value"); + } + } catch (Exception e) { + throw new OlapException( + "Error while casting a cell value to the correct java type for" + + " its XSD type " + type, + e); + } + } + + /** + * Creates metadata for a cell set, given the DOM of the XMLA result. + * + * @param root Root node of XMLA result + * @return Metadata describing this cell set + * @throws OlapException on error + */ + private XmlaOlap4jCellSetMetaData createMetaData(Element root) + throws OlapException + { + final Element olapInfo = + findChild(root, MDDATASET_NS, "OlapInfo"); + final Element cubeInfo = + findChild(olapInfo, MDDATASET_NS, "CubeInfo"); + final Element cubeNode = + findChild(cubeInfo, MDDATASET_NS, "Cube"); + final Element cubeNameNode = + findChild(cubeNode, MDDATASET_NS, "CubeName"); + final String cubeName = gatherText(cubeNameNode); + final XmlaOlap4jCube cube = + (XmlaOlap4jCube) + this.olap4jStatement.olap4jConnection.getSchema().getCubes().get( + cubeName); + if (cube == null) { + throw olap4jStatement.olap4jConnection.helper.createException( + "Internal error: cube '" + cubeName + "' not found"); + } + final Element axesInfo = + findChild(olapInfo, MDDATASET_NS, "AxesInfo"); + final List axisInfos = + findChildren(axesInfo, MDDATASET_NS, "AxisInfo"); + final List axisMetaDataList = + new ArrayList(); + XmlaOlap4jCellSetAxisMetaData filterAxisMetaData = null; + for (Element axisInfo : axisInfos) { + final String axisName = axisInfo.getAttribute("name"); + Axis axis = lookupAxis(axisName); + final List hierarchyInfos = + findChildren(axisInfo, MDDATASET_NS, "HierarchyInfo"); + final List hierarchyList = + new ArrayList(); + /* + + + + + + + + + + + + ... + + + + + + + + */ + final List propertyList = + new ArrayList(); + for (Element hierarchyInfo : hierarchyInfos) { + final String hierarchyName = hierarchyInfo.getAttribute("name"); + Hierarchy hierarchy = lookupHierarchy(cube, hierarchyName); + hierarchyList.add(hierarchy); + for (Element childNode : childElements(hierarchyInfo)) { + String tag = childNode.getLocalName(); + if (standardProperties.contains(tag)) { + continue; + } + final String propertyUniqueName = + childNode.getAttribute("name"); + final XmlaOlap4jCellSetMemberProperty property = + new XmlaOlap4jCellSetMemberProperty( + propertyUniqueName, + hierarchy, + tag); + propertyList.add(property); + } + } + final XmlaOlap4jCellSetAxisMetaData axisMetaData = + new XmlaOlap4jCellSetAxisMetaData( + olap4jStatement.olap4jConnection, + axis, + hierarchyList, + propertyList); + switch (axis) { + case FILTER: + filterAxisMetaData = axisMetaData; + break; + default: + axisMetaDataList.add(axisMetaData); + break; + } + } + final Element cellInfo = + findChild(olapInfo, MDDATASET_NS, "CellInfo"); + List cellProperties = + new ArrayList(); + for (Element element : childElements(cellInfo)) { + cellProperties.add( + new XmlaOlap4jCellProperty( + element.getLocalName(), + element.getAttribute("name"))); + } + return + new XmlaOlap4jCellSetMetaData( + olap4jStatement, + cube, + filterAxisMetaData, + axisMetaDataList, + cellProperties); + } + + /** + * Looks up a hierarchy in a cube with a given name or, failing that, a + * given unique name. Throws if not found. + * + * @param cube Cube + * @param hierarchyName Name (or unique name) of hierarchy. + * @return Hierarchy + * @throws OlapException + */ + private Hierarchy lookupHierarchy(XmlaOlap4jCube cube, String hierarchyName) + throws OlapException + { + Hierarchy hierarchy = cube.getHierarchies().get(hierarchyName); + if (hierarchy == null) { + for (Hierarchy hierarchy1 : cube.getHierarchies()) { + if (hierarchy1.getUniqueName().equals(hierarchyName)) { + hierarchy = hierarchy1; + break; + } + } + if (hierarchy == null) { + throw this.olap4jStatement.olap4jConnection.helper + .createException( + "Internal error: hierarchy '" + hierarchyName + + "' not found in cube '" + cube.getName() + + "'"); + } + } + return hierarchy; + } + + /** + * Looks up an Axis with a given name. + * + * @param axisName Name of axis + * @return Axis + */ + private Axis lookupAxis(String axisName) { + if (axisName.startsWith("Axis")) { + final Integer ordinal = + Integer.valueOf(axisName.substring("Axis".length())); + return Axis.values()[Axis.COLUMNS.ordinal() + ordinal]; + } else { + return Axis.FILTER; + } + } + + public CellSetMetaData getMetaData() { + return metaData; + } + + public Cell getCell(List coordinates) { + return getCellInternal(coordinatesToOrdinal(coordinates)); + } + + public Cell getCell(int ordinal) { + return getCellInternal(ordinal); + } + + public Cell getCell(Position... positions) { + if (positions.length != getAxes().size()) { + throw new IllegalArgumentException( + "cell coordinates should have dimension " + getAxes().size()); + } + List coords = new ArrayList(positions.length); + for (Position position : positions) { + coords.add(position.getOrdinal()); + } + return getCell(coords); + } + + /** + * Returns a cell given its ordinal. + * + * @param pos Ordinal + * @return Cell + * @throws IndexOutOfBoundsException if ordinal is not in range + */ + private Cell getCellInternal(int pos) { + final Cell cell = cellMap.get(pos); + if (cell == null) { + if (pos < 0 || pos >= maxOrdinal()) { + throw new IndexOutOfBoundsException(); + } else { + // Cell is within bounds, but is not held in the cache because + // it has no value. Manufacture a cell with an empty value. + return new XmlaOlap4jCell( + this, pos, null, "", + Collections.emptyMap()); + } + } + return cell; + } + + /** + * Returns a string describing the maximum coordinates of this cell set; + * for example "2, 3" for a cell set with 2 columns and 3 rows. + * + * @return description of cell set bounds + */ + private String getBoundsAsString() { + StringBuilder buf = new StringBuilder(); + int k = 0; + for (CellSetAxis axis : getAxes()) { + if (k++ > 0) { + buf.append(", "); + } + buf.append(axis.getPositionCount()); + } + return buf.toString(); + } + + public List getAxes() { + return immutableAxisList; + } + + public CellSetAxis getFilterAxis() { + return filterAxis; + } + + /** + * Returns the ordinal of the last cell in this cell set. This is the + * product of the cardinalities of all axes. + * + * @return ordinal of last cell in cell set + */ + private int maxOrdinal() { + int modulo = 1; + for (CellSetAxis axis : axisList) { + modulo *= axis.getPositionCount(); + } + return modulo; + } + + public List ordinalToCoordinates(int ordinal) { + List axes = getAxes(); + final List list = new ArrayList(axes.size()); + int modulo = 1; + for (CellSetAxis axis : axes) { + int prevModulo = modulo; + modulo *= axis.getPositionCount(); + list.add((ordinal % modulo) / prevModulo); + } + if (ordinal < 0 || ordinal >= modulo) { + throw new IndexOutOfBoundsException( + "Cell ordinal " + ordinal + + ") lies outside CellSet bounds (" + + getBoundsAsString() + ")"); + } + return list; + } + + public int coordinatesToOrdinal(List coordinates) { + List axes = getAxes(); + if (coordinates.size() != axes.size()) { + throw new IllegalArgumentException( + "Coordinates have different dimension " + coordinates.size() + + " than axes " + axes.size()); + } + int modulo = 1; + int ordinal = 0; + int k = 0; + for (CellSetAxis axis : axes) { + final Integer coordinate = coordinates.get(k++); + if (coordinate < 0 || coordinate >= axis.getPositionCount()) { + throw new IndexOutOfBoundsException( + "Coordinate " + coordinate + + " of axis " + k + + " is out of range (" + + getBoundsAsString() + ")"); + } + ordinal += coordinate * modulo; + modulo *= axis.getPositionCount(); + } + return ordinal; + } + + public boolean next() throws SQLException { + throw new UnsupportedOperationException(); + } + + public void close() throws SQLException { + this.closed = true; + } + + public boolean wasNull() throws SQLException { + throw new UnsupportedOperationException(); + } + + public String getString(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean getBoolean(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public byte getByte(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public short getShort(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getInt(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public long getLong(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public float getFloat(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public double getDouble(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public BigDecimal getBigDecimal( + int columnIndex, int scale) throws SQLException { + throw new UnsupportedOperationException(); + } + + public byte[] getBytes(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Date getDate(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Time getTime(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Timestamp getTimestamp(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public InputStream getAsciiStream(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public InputStream getUnicodeStream(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public InputStream getBinaryStream(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public String getString(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean getBoolean(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public byte getByte(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public short getShort(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getInt(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public long getLong(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public float getFloat(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public double getDouble(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public BigDecimal getBigDecimal( + String columnLabel, int scale) throws SQLException { + throw new UnsupportedOperationException(); + } + + public byte[] getBytes(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Date getDate(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Time getTime(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Timestamp getTimestamp(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public InputStream getAsciiStream(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public InputStream getUnicodeStream(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public InputStream getBinaryStream(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public SQLWarning getWarnings() throws SQLException { + throw new UnsupportedOperationException(); + } + + public void clearWarnings() throws SQLException { + throw new UnsupportedOperationException(); + } + + public String getCursorName() throws SQLException { + throw new UnsupportedOperationException(); + } + + public Object getObject(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Object getObject(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public int findColumn(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Reader getCharacterStream(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Reader getCharacterStream(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public BigDecimal getBigDecimal(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public BigDecimal getBigDecimal(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean isBeforeFirst() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean isAfterLast() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean isFirst() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean isLast() throws SQLException { + throw new UnsupportedOperationException(); + } + + public void beforeFirst() throws SQLException { + throw new UnsupportedOperationException(); + } + + public void afterLast() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean first() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean last() throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getRow() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean absolute(int row) throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean relative(int rows) throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean previous() throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setFetchDirection(int direction) throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getFetchDirection() throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setFetchSize(int rows) throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getFetchSize() throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getType() throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getConcurrency() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean rowUpdated() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean rowInserted() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean rowDeleted() throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateNull(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateBoolean(int columnIndex, boolean x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateByte(int columnIndex, byte x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateShort(int columnIndex, short x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateInt(int columnIndex, int x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateLong(int columnIndex, long x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateFloat(int columnIndex, float x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateDouble(int columnIndex, double x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateBigDecimal( + int columnIndex, BigDecimal x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateString(int columnIndex, String x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateBytes(int columnIndex, byte x[]) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateDate(int columnIndex, Date x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateTime(int columnIndex, Time x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateTimestamp( + int columnIndex, Timestamp x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateAsciiStream( + int columnIndex, InputStream x, int length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateBinaryStream( + int columnIndex, InputStream x, int length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateCharacterStream( + int columnIndex, Reader x, int length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateObject( + int columnIndex, Object x, int scaleOrLength) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateObject(int columnIndex, Object x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateNull(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateBoolean( + String columnLabel, boolean x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateByte(String columnLabel, byte x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateShort(String columnLabel, short x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateInt(String columnLabel, int x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateLong(String columnLabel, long x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateFloat(String columnLabel, float x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateDouble(String columnLabel, double x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateBigDecimal( + String columnLabel, BigDecimal x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateString(String columnLabel, String x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateBytes(String columnLabel, byte x[]) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateDate(String columnLabel, Date x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateTime(String columnLabel, Time x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateTimestamp( + String columnLabel, Timestamp x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateAsciiStream( + String columnLabel, InputStream x, int length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateBinaryStream( + String columnLabel, InputStream x, int length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateCharacterStream( + String columnLabel, Reader reader, int length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateObject( + String columnLabel, Object x, int scaleOrLength) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateObject(String columnLabel, Object x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void insertRow() throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateRow() throws SQLException { + throw new UnsupportedOperationException(); + } + + public void deleteRow() throws SQLException { + throw new UnsupportedOperationException(); + } + + public void refreshRow() throws SQLException { + throw new UnsupportedOperationException(); + } + + public void cancelRowUpdates() throws SQLException { + throw new UnsupportedOperationException(); + } + + public void moveToInsertRow() throws SQLException { + throw new UnsupportedOperationException(); + } + + public void moveToCurrentRow() throws SQLException { + throw new UnsupportedOperationException(); + } + + public Statement getStatement() throws SQLException { + throw new UnsupportedOperationException(); + } + + public Object getObject( + int columnIndex, Map> map) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Ref getRef(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Blob getBlob(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Clob getClob(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Array getArray(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Object getObject( + String columnLabel, Map> map) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Ref getRef(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Blob getBlob(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Clob getClob(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Array getArray(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Date getDate(int columnIndex, Calendar cal) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Date getDate(String columnLabel, Calendar cal) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Time getTime(int columnIndex, Calendar cal) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Time getTime(String columnLabel, Calendar cal) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Timestamp getTimestamp( + int columnIndex, Calendar cal) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Timestamp getTimestamp( + String columnLabel, Calendar cal) throws SQLException { + throw new UnsupportedOperationException(); + } + + public URL getURL(int columnIndex) throws SQLException { + throw new UnsupportedOperationException(); + } + + public URL getURL(String columnLabel) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateRef(int columnIndex, Ref x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateRef(String columnLabel, Ref x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateBlob(int columnIndex, Blob x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateBlob(String columnLabel, Blob x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateClob(int columnIndex, Clob x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateClob(String columnLabel, Clob x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateArray(int columnIndex, Array x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void updateArray(String columnLabel, Array x) throws SQLException { + throw new UnsupportedOperationException(); + } + + // implement Wrapper + + public T unwrap(Class iface) throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + throw new UnsupportedOperationException(); + } + + /** + * Implementation of {@link Member} for a member which is not present + * in the cube (probably because the member is a calculated member + * defined in the query). + */ + private static class XmlaOlap4jSurpriseMember implements Member { + private final Level level; + private final Hierarchy hierarchy; + private final int lnum; + private final String caption; + private final String uname; + + /** + * Creates an XmlaOlap4jSurpriseMember. + * + * @param level Level + * @param hierarchy Hierarchy + * @param lnum Level number + * @param caption Caption + * @param uname Member unique name + */ + XmlaOlap4jSurpriseMember( + Level level, + Hierarchy hierarchy, + int lnum, + String caption, + String uname) + { + this.level = level; + this.hierarchy = hierarchy; + this.lnum = lnum; + this.caption = caption; + this.uname = uname; + } + + public NamedList getChildMembers() + { + return Olap4jUtil.emptyNamedList(); + } + + public int getChildMemberCount() { + return 0; + } + + public Member getParentMember() { + return null; + } + + public Level getLevel() { + return level; + } + + public Hierarchy getHierarchy() { + return hierarchy; + } + + public Dimension getDimension() { + return hierarchy.getDimension(); + } + + public Type getMemberType() { + return Type.UNKNOWN; + } + + public boolean isAll() { + return false; // FIXME + } + + public boolean isChildOrEqualTo(Member member) { + return false; // FIXME + } + + public boolean isCalculated() { + return false; // FIXME + } + + public int getSolveOrder() { + return 0; // FIXME + } + + public ParseTreeNode getExpression() { + return null; + } + + public List getAncestorMembers() { + return Collections.emptyList(); // FIXME + } + + public boolean isCalculatedInQuery() { + return true; // probably + } + + public Object getPropertyValue(Property property) { + return null; + } + + public String getPropertyFormattedValue(Property property) { + return null; + } + + public void setProperty(Property property, Object value) + { + throw new UnsupportedOperationException(); + } + + public NamedList getProperties() { + return Olap4jUtil.emptyNamedList(); + } + + public int getOrdinal() { + return -1; // FIXME + } + + public boolean isHidden() { + return false; + } + + public int getDepth() { + return lnum; + } + + public Member getDataMember() { + return null; + } + + public String getName() { + return caption; + } + + public String getUniqueName() { + return uname; + } + + public String getCaption(Locale locale) { + return caption; + } + + public String getDescription(Locale locale) { + return null; + } + } +} + +// End XmlaOlap4jCellSet.java diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jCellSetAxisMetaData.java b/src/org/olap4j/driver/xmla/XmlaOlap4jCellSetAxisMetaData.java index 2ad0c17..5859989 100755 --- a/src/org/olap4j/driver/xmla/XmlaOlap4jCellSetAxisMetaData.java +++ b/src/org/olap4j/driver/xmla/XmlaOlap4jCellSetAxisMetaData.java @@ -1,69 +1,69 @@ -/* -// This software is subject to the terms of the Common Public License -// Agreement, available at the following URL: -// http://www.opensource.org/licenses/cpl.html. -// Copyright (C) 2007-2007 Julian Hyde -// All Rights Reserved. -// You must accept the terms of that agreement to use this software. -*/ -package org.olap4j.driver.xmla; - -import org.olap4j.Axis; -import org.olap4j.CellSetAxisMetaData; -import org.olap4j.impl.Olap4jUtil; -import org.olap4j.metadata.Hierarchy; -import org.olap4j.metadata.Property; - -import java.util.*; - -/** - * Implementation of {@link org.olap4j.CellSetMetaData} - * for XML/A providers. - * - * @author jhyde - * @version $Id: MondrianOlap4jCellSetAxisMetaData.java 43 2007-11-21 01:57:47Z jhyde $ -* @since Nov 17, 2007 -*/ -class XmlaOlap4jCellSetAxisMetaData implements CellSetAxisMetaData { - private final Axis axis; - private final List hierarchyList; - private final List propertyList; - - XmlaOlap4jCellSetAxisMetaData( - XmlaOlap4jConnection olap4jConnection, - Axis axis, - List hierarchyList, - List propertyList) - { - this.axis = axis; - this.hierarchyList = hierarchyList; - this.propertyList = propertyList; - } - - public Axis getAxisOrdinal() { - return axis; - } - - public List getHierarchies() { - return hierarchyList; - } - - public List getProperties() { - return Olap4jUtil.cast(propertyList); - } - - XmlaOlap4jCellSetMemberProperty lookupProperty( - String hierarchyName, - String tag) - { - for (XmlaOlap4jCellSetMemberProperty property : propertyList) { - if (property.hierarchy.getName().equals(hierarchyName) - && property.tag.equals(tag)) { - return property; - } - } - return null; - } -} - -// End XmlaOlap4jCellSetAxisMetaData.java +/* +// This software is subject to the terms of the Common Public License +// Agreement, available at the following URL: +// http://www.opensource.org/licenses/cpl.html. +// Copyright (C) 2007-2007 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j.driver.xmla; + +import org.olap4j.Axis; +import org.olap4j.CellSetAxisMetaData; +import org.olap4j.impl.Olap4jUtil; +import org.olap4j.metadata.Hierarchy; +import org.olap4j.metadata.Property; + +import java.util.*; + +/** + * Implementation of {@link org.olap4j.CellSetMetaData} + * for XML/A providers. + * + * @author jhyde + * @version $Id: MondrianOlap4jCellSetAxisMetaData.java 43 2007-11-21 01:57:47Z jhyde $ +* @since Nov 17, 2007 +*/ +class XmlaOlap4jCellSetAxisMetaData implements CellSetAxisMetaData { + private final Axis axis; + private final List hierarchyList; + private final List propertyList; + + XmlaOlap4jCellSetAxisMetaData( + XmlaOlap4jConnection olap4jConnection, + Axis axis, + List hierarchyList, + List propertyList) + { + this.axis = axis; + this.hierarchyList = hierarchyList; + this.propertyList = propertyList; + } + + public Axis getAxisOrdinal() { + return axis; + } + + public List getHierarchies() { + return hierarchyList; + } + + public List getProperties() { + return Olap4jUtil.cast(propertyList); + } + + XmlaOlap4jCellSetMemberProperty lookupProperty( + String hierarchyName, + String tag) + { + for (XmlaOlap4jCellSetMemberProperty property : propertyList) { + if (property.hierarchy.getName().equals(hierarchyName) + && property.tag.equals(tag)) { + return property; + } + } + return null; + } +} + +// End XmlaOlap4jCellSetAxisMetaData.java diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jCellSetMetaData.java b/src/org/olap4j/driver/xmla/XmlaOlap4jCellSetMetaData.java index de1abf0..60f9bbf 100644 --- a/src/org/olap4j/driver/xmla/XmlaOlap4jCellSetMetaData.java +++ b/src/org/olap4j/driver/xmla/XmlaOlap4jCellSetMetaData.java @@ -1,218 +1,218 @@ -/* -// This software is subject to the terms of the Common Public License -// Agreement, available at the following URL: -// http://www.opensource.org/licenses/cpl.html. -// Copyright (C) 2007-2007 Julian Hyde -// All Rights Reserved. -// You must accept the terms of that agreement to use this software. -*/ -package org.olap4j.driver.xmla; - -import org.olap4j.CellSetAxisMetaData; -import org.olap4j.CellSetMetaData; -import org.olap4j.impl.ArrayNamedListImpl; -import org.olap4j.impl.Olap4jUtil; -import org.olap4j.metadata.*; - -import java.sql.SQLException; -import java.util.*; - -/** - * Implementation of {@link org.olap4j.CellSetMetaData} - * for XML/A providers. - * - * @author jhyde - * @version $Id$ - * @since Jun 13, 2007 - */ -class XmlaOlap4jCellSetMetaData implements CellSetMetaData { - final XmlaOlap4jCube cube; - private final NamedList axisMetaDataList = - new ArrayNamedListImpl() { - protected String getName(CellSetAxisMetaData axisMetaData) { - return axisMetaData.getAxisOrdinal().name(); - } - }; - private final XmlaOlap4jCellSetAxisMetaData filterAxisMetaData; - private final NamedList cellProperties = - new ArrayNamedListImpl() { - protected String getName(Property property) { - return property.getName(); - } - }; - final Map propertiesByTag; - - XmlaOlap4jCellSetMetaData( - XmlaOlap4jStatement olap4jStatement, - XmlaOlap4jCube cube, - XmlaOlap4jCellSetAxisMetaData filterAxisMetaData, - List axisMetaDataList, - List cellProperties) - { - assert olap4jStatement != null; - assert cube != null; - assert filterAxisMetaData != null; - this.cube = cube; - this.filterAxisMetaData = filterAxisMetaData; - this.axisMetaDataList.addAll(axisMetaDataList); - this.propertiesByTag = new HashMap(); - for (XmlaOlap4jCellProperty cellProperty : cellProperties) { - Property property; - try { - property = Property.StandardCellProperty.valueOf( - cellProperty.propertyName); - this.propertiesByTag.put(cellProperty.tag, property); - } catch (IllegalArgumentException e) { - property = cellProperty; - this.propertiesByTag.put(property.getName(), property); - } - this.cellProperties.add(property); - } - } - - private XmlaOlap4jCellSetMetaData( - XmlaOlap4jStatement olap4jStatement, - XmlaOlap4jCube cube, - XmlaOlap4jCellSetAxisMetaData filterAxisMetaData, - List axisMetaDataList, - Map propertiesByTag, - List cellProperties) - { - assert olap4jStatement != null; - assert cube != null; - assert filterAxisMetaData != null; - this.cube = cube; - this.filterAxisMetaData = filterAxisMetaData; - this.axisMetaDataList.addAll(axisMetaDataList); - this.propertiesByTag = propertiesByTag; - this.cellProperties.addAll(cellProperties); - } - - XmlaOlap4jCellSetMetaData cloneFor( - XmlaOlap4jPreparedStatement preparedStatement) - { - return new XmlaOlap4jCellSetMetaData( - preparedStatement, - cube, - filterAxisMetaData, - axisMetaDataList, - propertiesByTag, - cellProperties); - } - - // implement CellSetMetaData - - public NamedList getCellProperties() { - return Olap4jUtil.cast(cellProperties); - } - - public Cube getCube() { - return cube; - } - - public NamedList getAxesMetaData() { - return axisMetaDataList; - } - - public CellSetAxisMetaData getFilterAxisMetaData() { - return filterAxisMetaData; - } - -// implement ResultSetMetaData - - public int getColumnCount() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean isAutoIncrement(int column) throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean isCaseSensitive(int column) throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean isSearchable(int column) throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean isCurrency(int column) throws SQLException { - throw new UnsupportedOperationException(); - } - - public int isNullable(int column) throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean isSigned(int column) throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getColumnDisplaySize(int column) throws SQLException { - throw new UnsupportedOperationException(); - } - - public String getColumnLabel(int column) throws SQLException { - throw new UnsupportedOperationException(); - } - - public String getColumnName(int column) throws SQLException { - throw new UnsupportedOperationException(); - } - - public String getSchemaName(int column) throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getPrecision(int column) throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getScale(int column) throws SQLException { - throw new UnsupportedOperationException(); - } - - public String getTableName(int column) throws SQLException { - throw new UnsupportedOperationException(); - } - - public String getCatalogName(int column) throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getColumnType(int column) throws SQLException { - throw new UnsupportedOperationException(); - } - - public String getColumnTypeName(int column) throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean isReadOnly(int column) throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean isWritable(int column) throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean isDefinitelyWritable(int column) throws SQLException { - throw new UnsupportedOperationException(); - } - - public String getColumnClassName(int column) throws SQLException { - throw new UnsupportedOperationException(); - } - - // implement Wrapper - - public T unwrap(Class iface) throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean isWrapperFor(Class iface) throws SQLException { - throw new UnsupportedOperationException(); - } -} - -// End XmlaOlap4jCellSetMetaData.java +/* +// This software is subject to the terms of the Common Public License +// Agreement, available at the following URL: +// http://www.opensource.org/licenses/cpl.html. +// Copyright (C) 2007-2007 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j.driver.xmla; + +import org.olap4j.CellSetAxisMetaData; +import org.olap4j.CellSetMetaData; +import org.olap4j.impl.ArrayNamedListImpl; +import org.olap4j.impl.Olap4jUtil; +import org.olap4j.metadata.*; + +import java.sql.SQLException; +import java.util.*; + +/** + * Implementation of {@link org.olap4j.CellSetMetaData} + * for XML/A providers. + * + * @author jhyde + * @version $Id$ + * @since Jun 13, 2007 + */ +class XmlaOlap4jCellSetMetaData implements CellSetMetaData { + final XmlaOlap4jCube cube; + private final NamedList axisMetaDataList = + new ArrayNamedListImpl() { + protected String getName(CellSetAxisMetaData axisMetaData) { + return axisMetaData.getAxisOrdinal().name(); + } + }; + private final XmlaOlap4jCellSetAxisMetaData filterAxisMetaData; + private final NamedList cellProperties = + new ArrayNamedListImpl() { + protected String getName(Property property) { + return property.getName(); + } + }; + final Map propertiesByTag; + + XmlaOlap4jCellSetMetaData( + XmlaOlap4jStatement olap4jStatement, + XmlaOlap4jCube cube, + XmlaOlap4jCellSetAxisMetaData filterAxisMetaData, + List axisMetaDataList, + List cellProperties) + { + assert olap4jStatement != null; + assert cube != null; + assert filterAxisMetaData != null; + this.cube = cube; + this.filterAxisMetaData = filterAxisMetaData; + this.axisMetaDataList.addAll(axisMetaDataList); + this.propertiesByTag = new HashMap(); + for (XmlaOlap4jCellProperty cellProperty : cellProperties) { + Property property; + try { + property = Property.StandardCellProperty.valueOf( + cellProperty.propertyName); + this.propertiesByTag.put(cellProperty.tag, property); + } catch (IllegalArgumentException e) { + property = cellProperty; + this.propertiesByTag.put(property.getName(), property); + } + this.cellProperties.add(property); + } + } + + private XmlaOlap4jCellSetMetaData( + XmlaOlap4jStatement olap4jStatement, + XmlaOlap4jCube cube, + XmlaOlap4jCellSetAxisMetaData filterAxisMetaData, + List axisMetaDataList, + Map propertiesByTag, + List cellProperties) + { + assert olap4jStatement != null; + assert cube != null; + assert filterAxisMetaData != null; + this.cube = cube; + this.filterAxisMetaData = filterAxisMetaData; + this.axisMetaDataList.addAll(axisMetaDataList); + this.propertiesByTag = propertiesByTag; + this.cellProperties.addAll(cellProperties); + } + + XmlaOlap4jCellSetMetaData cloneFor( + XmlaOlap4jPreparedStatement preparedStatement) + { + return new XmlaOlap4jCellSetMetaData( + preparedStatement, + cube, + filterAxisMetaData, + axisMetaDataList, + propertiesByTag, + cellProperties); + } + + // implement CellSetMetaData + + public NamedList getCellProperties() { + return Olap4jUtil.cast(cellProperties); + } + + public Cube getCube() { + return cube; + } + + public NamedList getAxesMetaData() { + return axisMetaDataList; + } + + public CellSetAxisMetaData getFilterAxisMetaData() { + return filterAxisMetaData; + } + +// implement ResultSetMetaData + + public int getColumnCount() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean isAutoIncrement(int column) throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean isCaseSensitive(int column) throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean isSearchable(int column) throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean isCurrency(int column) throws SQLException { + throw new UnsupportedOperationException(); + } + + public int isNullable(int column) throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean isSigned(int column) throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getColumnDisplaySize(int column) throws SQLException { + throw new UnsupportedOperationException(); + } + + public String getColumnLabel(int column) throws SQLException { + throw new UnsupportedOperationException(); + } + + public String getColumnName(int column) throws SQLException { + throw new UnsupportedOperationException(); + } + + public String getSchemaName(int column) throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getPrecision(int column) throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getScale(int column) throws SQLException { + throw new UnsupportedOperationException(); + } + + public String getTableName(int column) throws SQLException { + throw new UnsupportedOperationException(); + } + + public String getCatalogName(int column) throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getColumnType(int column) throws SQLException { + throw new UnsupportedOperationException(); + } + + public String getColumnTypeName(int column) throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean isReadOnly(int column) throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean isWritable(int column) throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean isDefinitelyWritable(int column) throws SQLException { + throw new UnsupportedOperationException(); + } + + public String getColumnClassName(int column) throws SQLException { + throw new UnsupportedOperationException(); + } + + // implement Wrapper + + public T unwrap(Class iface) throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + throw new UnsupportedOperationException(); + } +} + +// End XmlaOlap4jCellSetMetaData.java diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java b/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java index 9375e7e..30fa025 100644 --- a/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java +++ b/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java @@ -1,1748 +1,1750 @@ -/* -// This software is subject to the terms of the Common Public License -// Agreement, available at the following URL: -// http://www.opensource.org/licenses/cpl.html. -// Copyright (C) 2007-2007 Julian Hyde -// All Rights Reserved. -// You must accept the terms of that agreement to use this software. -*/ -package org.olap4j.driver.xmla; - -import org.olap4j.*; - -import static org.olap4j.driver.xmla.XmlaOlap4jUtil.*; - -import org.olap4j.driver.xmla.proxy.*; -import org.olap4j.impl.*; -import org.olap4j.mdx.ParseTreeWriter; -import org.olap4j.mdx.SelectNode; -import org.olap4j.mdx.parser.*; -import org.olap4j.mdx.parser.impl.DefaultMdxParserImpl; -import org.olap4j.metadata.*; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.xml.sax.SAXException; - -import java.io.*; -import java.net.MalformedURLException; -import java.net.URL; -import java.sql.*; -import java.util.*; -import java.util.Map.*; -import java.util.regex.*; - -/** - * Implementation of {@link org.olap4j.OlapConnection} - * for XML/A providers. - * - *

This class has sub-classes which implement JDBC 3.0 and JDBC 4.0 APIs; - * it is instantiated using {@link Factory#newConnection}.

- * - * @author jhyde - * @version $Id$ - * @since May 23, 2007 - */ -abstract class XmlaOlap4jConnection implements OlapConnection { - /** - *

Handler for errors. - */ - final Helper helper = new Helper(); - - /** - *

Current schema. - */ - private XmlaOlap4jSchema olap4jSchema; - - private final XmlaOlap4jDatabaseMetaData olap4jDatabaseMetaData; - - private static final String CONNECT_STRING_PREFIX = "jdbc:xmla:"; - - final Factory factory; - - final XmlaOlap4jProxy proxy; - - private boolean closed; - - /** - *

URL of the HTTP server to which to send XML requests. - */ - final URL serverUrl; - - private Locale locale; - private String catalogName; - private static final boolean DEBUG = false; - private String roleName; - - /** - *

Holds on to the provider name - */ - private String providerName; - - /** - *

Holds on to the datasource name. - */ - private String datasourceName; - - /** - * Holds the datasource name as specified by the server. Necessary because - * some servers (such as mondrian) return both the provider - * name and the datasource name in their response. - * - *

It's this value that we use inside queries, and not the jdbc - * query value. - */ - private String nativeDatasourceName; - private boolean autoCommit; - private boolean readOnly; - - /** - * Name of the "DATA_SOURCE_NAME" column returned from - * {@link org.olap4j.OlapDatabaseMetaData#getDatasources()}. - */ - private static final String DATA_SOURCE_NAME = "DATA_SOURCE_NAME"; - - /** - * Name of the "PROVIDER_NAME" column returned from - * {@link org.olap4j.OlapDatabaseMetaData#getDatasources()}. - */ - private static final String PROVIDER_NAME = "PROVIDER_NAME"; - - /** - * Creates an Olap4j connection an XML/A provider. - * - *

This method is intentionally package-protected. The public API - * uses the traditional JDBC {@link java.sql.DriverManager}. - * See {@link org.olap4j.driver.xmla.XmlaOlap4jDriver} for more details. - * - *

Note that this constructor should make zero non-trivial calls, which - * could cause deadlocks due to java.sql.DriverManager synchronization - * issues. - * - * @pre acceptsURL(url) - * - * @param factory Factory - * @param proxy Proxy object which receives XML requests - * @param url Connect-string URL - * @param info Additional properties - * @throws java.sql.SQLException if there is an error - */ - XmlaOlap4jConnection( - Factory factory, - XmlaOlap4jProxy proxy, - String url, - Properties info) - throws SQLException - { - this.factory = factory; - this.proxy = proxy; - if (!acceptsURL(url)) { - // This is not a URL we can handle. - // DriverManager should not have invoked us. - throw new AssertionError( - "does not start with '" + CONNECT_STRING_PREFIX + "'"); - } - Map map = parseConnectString(url, info); - - this.providerName = map.get(XmlaOlap4jDriver.Property.Provider.name()); - this.datasourceName = map.get(XmlaOlap4jDriver.Property.DataSource.name()); - this.catalogName = map.get(XmlaOlap4jDriver.Property.Catalog.name()); - - // Set URL of HTTP server. - String serverUrl = map.get(XmlaOlap4jDriver.Property.Server.name()); - if (serverUrl == null) { - throw helper.createException("Connection property '" - + XmlaOlap4jDriver.Property.Server.name() - + "' must be specified"); - } - - // Basic authentication. Make sure the credentials passed as standard - // JDBC parameters override any credentials already included in the URL - // as part of the standard URL scheme. - if (map.containsKey("user") && map.containsKey("password")) { - serverUrl = serverUrl.replaceFirst( - ":\\/\\/([^@]*@){0,1}", - "://" - .concat(map.get("user")) - .concat(":") - .concat(map.get("password") - .concat("@"))); - } - - // Initialize the SOAP cache if needed - initSoapCache(map); - - try { - this.serverUrl = new URL(serverUrl); - } catch (MalformedURLException e) { - throw helper.createException( - "Error while creating connection", e); - } - - this.olap4jDatabaseMetaData = - factory.newDatabaseMetaData(this); - } - - - /** - * Initializes a cache object and configures it if cache - * parameters were specified in the jdbc url. - * - * @param map The parameters from the jdbc url. - * @throws OlapException Thrown when there is an error encountered - * while creating the cache. - */ - private void initSoapCache(Map map) throws OlapException { - - // Test if a SOAP cache class was defined - if (map.containsKey(XmlaOlap4jDriver.Property.Cache.name() - .toUpperCase())) - { - // Create a properties object to pass to the proxy - // so it can configure it's cache - Map props = new HashMap(); - // Iterate over map entries to find those related to - // the cache config - for (Entry entry : map.entrySet()) { - // Check if the current entry relates to cache config. - if (entry.getKey().startsWith( - XmlaOlap4jDriver.Property.Cache.name().toUpperCase() - + ".")) //$NON-NLS-1$ - { - props.put(entry.getKey().substring( - XmlaOlap4jDriver.Property.Cache.name() - .length() + 1), entry.getValue()); - } - } - - // Init the cache - ((XmlaOlap4jCachedProxy) this.proxy).setCache(map, props); - } - } - - - - static Map parseConnectString(String url, Properties info) { - String x = url.substring(CONNECT_STRING_PREFIX.length()); - Map map = - ConnectStringParser.parseConnectString(x); - for (Map.Entry entry : toMap(info).entrySet()) { - map.put(entry.getKey(), entry.getValue()); - } - return map; - } - - static boolean acceptsURL(String url) { - return url.startsWith(CONNECT_STRING_PREFIX); - } - - /** - * Returns the native datasource name, using the cached value if already - * computed. - * - *

Not part of public API. - * - * @return native datasource name - * @throws OlapException if cannot find a datasource that matches - */ - String getDataSourceInfo() throws OlapException { - // If we already know it, return it. - if (this.nativeDatasourceName != null) { - return this.nativeDatasourceName; - } - - ResultSet rSet = null; - try { - // We need to query for it - rSet = this.olap4jDatabaseMetaData.getDatasources(); - - // Check if the user requested a particular one. - if (this.datasourceName != null || this.providerName != null) { - // We iterate through the datasources - while (rSet.next()) { - // Get current values - String currentDatasource = rSet.getString(DATA_SOURCE_NAME); - String currentProvider = rSet.getString(PROVIDER_NAME); - - // If datasource and provider match, we got it. - // If datasource matches but no provider is specified, we - // got it. - // If provider matches but no datasource specified, we - // consider it good. - if (currentDatasource.equals(this.datasourceName) - && currentProvider.equals(this.providerName) - || currentDatasource.equals(this.datasourceName) - && this.providerName == null - || currentProvider.equals(this.providerName) - && this.datasourceName == null) - { - // Got it - this.nativeDatasourceName = currentDatasource; - break; - } - } - } else { - // Use first - if (rSet.first()) { - this.nativeDatasourceName = rSet.getString(DATA_SOURCE_NAME); - } - } - - // Throws exception to the client. - //Tells that there are no datasource corresponding to the search criterias. - if (this.nativeDatasourceName == null) { - throw new OlapException("No datasource could be found."); - } - - // If there is a provider - return this.nativeDatasourceName; - } catch (OlapException e) { - throw e; - } catch (SQLException e) { - throw new OlapException("Datasource name not found.", e); - } finally { - try { - if (rSet != null) { - rSet.close(); - } - } catch (SQLException e) { - // ignore - } - } - } - - public OlapStatement createStatement() { - return new XmlaOlap4jStatement(this); - } - - public PreparedStatement prepareStatement(String sql) throws SQLException { - throw new UnsupportedOperationException(); - } - - public CallableStatement prepareCall(String sql) throws SQLException { - throw new UnsupportedOperationException(); - } - - public String nativeSQL(String sql) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setAutoCommit(boolean autoCommit) throws SQLException { - this.autoCommit = autoCommit; - } - - public boolean getAutoCommit() throws SQLException { - return autoCommit; - } - - public void commit() throws SQLException { - throw new UnsupportedOperationException(); - } - - public void rollback() throws SQLException { - throw new UnsupportedOperationException(); - } - - public void close() throws SQLException { - closed = true; - } - - public boolean isClosed() throws SQLException { - return closed; - } - - public OlapDatabaseMetaData getMetaData() { - return olap4jDatabaseMetaData; - } - - public NamedList getCatalogs() { - return olap4jDatabaseMetaData.getCatalogObjects(); - } - - public void setReadOnly(boolean readOnly) throws SQLException { - this.readOnly = readOnly; - } - - public boolean isReadOnly() throws SQLException { - return readOnly; - } - - public void setCatalog(String catalog) throws SQLException { - this.catalogName = catalog; - } - - public String getCatalog() { - return catalogName; - } - - public void setTransactionIsolation(int level) throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getTransactionIsolation() throws SQLException { - throw new UnsupportedOperationException(); - } - - public SQLWarning getWarnings() throws SQLException { - throw new UnsupportedOperationException(); - } - - public void clearWarnings() throws SQLException { - // this driver does not support warnings, so nothing to do - } - - public Statement createStatement( - int resultSetType, int resultSetConcurrency) throws SQLException { - throw new UnsupportedOperationException(); - } - - public PreparedStatement prepareStatement( - String sql, - int resultSetType, - int resultSetConcurrency) throws SQLException { - throw new UnsupportedOperationException(); - } - - public CallableStatement prepareCall( - String sql, - int resultSetType, - int resultSetConcurrency) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Map> getTypeMap() throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setTypeMap(Map> map) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setHoldability(int holdability) throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getHoldability() throws SQLException { - throw new UnsupportedOperationException(); - } - - public Savepoint setSavepoint() throws SQLException { - throw new UnsupportedOperationException(); - } - - public Savepoint setSavepoint(String name) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void rollback(Savepoint savepoint) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void releaseSavepoint(Savepoint savepoint) throws SQLException { - throw new UnsupportedOperationException(); - } - - public Statement createStatement( - int resultSetType, - int resultSetConcurrency, - int resultSetHoldability) throws SQLException { - throw new UnsupportedOperationException(); - } - - public PreparedStatement prepareStatement( - String sql, - int resultSetType, - int resultSetConcurrency, - int resultSetHoldability) throws SQLException { - throw new UnsupportedOperationException(); - } - - public CallableStatement prepareCall( - String sql, - int resultSetType, - int resultSetConcurrency, - int resultSetHoldability) throws SQLException { - throw new UnsupportedOperationException(); - } - - public PreparedStatement prepareStatement( - String sql, int autoGeneratedKeys) throws SQLException { - throw new UnsupportedOperationException(); - } - - public PreparedStatement prepareStatement( - String sql, int columnIndexes[]) throws SQLException { - throw new UnsupportedOperationException(); - } - - public PreparedStatement prepareStatement( - String sql, String columnNames[]) throws SQLException { - throw new UnsupportedOperationException(); - } - - // implement Wrapper - - public T unwrap(Class iface) throws SQLException { - if (iface.isInstance(this)) { - return iface.cast(this); - } - throw helper.createException("does not implement '" + iface + "'"); - } - - public boolean isWrapperFor(Class iface) throws SQLException { - return iface.isInstance(this); - } - - // implement OlapConnection - - public PreparedOlapStatement prepareOlapStatement( - String mdx) - throws OlapException { - return factory.newPreparedStatement(mdx, this); - } - - public MdxParserFactory getParserFactory() { - return new MdxParserFactory() { - public MdxParser createMdxParser(OlapConnection connection) { - return new DefaultMdxParserImpl(connection); - } - - public MdxValidator createMdxValidator(OlapConnection connection) { - return new XmlaOlap4jMdxValidator(connection); - } - }; - } - - public synchronized org.olap4j.metadata.Schema getSchema() throws OlapException { - // initializes the olap4jSchema if necessary - if (this.olap4jSchema == null) { - final XmlaOlap4jCatalog catalog = - (XmlaOlap4jCatalog) - this.olap4jDatabaseMetaData.getCatalogObjects().get( - catalogName); - this.olap4jSchema = (XmlaOlap4jSchema) catalog.getSchemas() - .get(0); - } - return olap4jSchema; - } - - public static Map toMap(final Properties properties) { - return new AbstractMap() { - public Set> entrySet() { - return Olap4jUtil.cast(properties.entrySet()); - } - }; - } - - /** - * Returns the URL which was used to create this connection. - * - * @return URL - */ - String getURL() { - throw Olap4jUtil.needToImplement(this); - } - - public void setLocale(Locale locale) { - if (locale == null) { - throw new IllegalArgumentException("locale must not be null"); - } - this.locale = locale; - } - - public Locale getLocale() { - if (locale == null) { - return Locale.getDefault(); - } - return locale; - } - - public void setRoleName(String roleName) throws OlapException { - this.roleName = roleName; - } - - public String getRoleName() { - return roleName; - } - - void populateList( - List list, - Context context, - MetadataRequest metadataRequest, - Handler handler, - Object[] restrictions) throws OlapException - { - String request = - generateRequest(context, metadataRequest, restrictions); - Element root = xxx(request); - for (Element o : childElements(root)) { - if (o.getLocalName().equals("row")) { - handler.handle(o, context, list); - } - } - handler.sortList(list); - } - - Element xxx(String request) throws OlapException { - byte[] bytes; - try { - bytes = proxy.get(serverUrl, request); - } catch (IOException e) { - throw helper.createException(null, e); - } - Document doc; - try { - doc = parse(bytes); - } catch (IOException e) { - throw helper.createException( - "error discovering metadata", e); - } catch (SAXException e) { - throw helper.createException( - "error discovering metadata", e); - } - // - // - // - // - // - // - // (see below) - // - // - // - // - // - final Element envelope = doc.getDocumentElement(); - if (DEBUG) System.out.println(XmlaOlap4jUtil.toString(doc,true)); - assert envelope.getLocalName().equals("Envelope"); - assert envelope.getNamespaceURI().equals(SOAP_NS); - Element body = - findChild(envelope, SOAP_NS, "Body"); - Element fault = - findChild(body, SOAP_NS, "Fault"); - if (fault != null) { - /* - - SOAP-ENV:Client.00HSBC01 - XMLA connection datasource not found - Mondrian - - - 00HSBC01 - The Mondrian XML: Mondrian Error:Internal - error: no catalog named 'LOCALDB' - - - - */ - // TODO: log doc to logfile - final Element faultstring = findChild(fault, null, "faultstring"); - String message = faultstring.getTextContent(); - throw helper.createException( - "XMLA provider gave exception: " + message - + "; request: " + request); - } - Element discoverResponse = - findChild(body, XMLA_NS, "DiscoverResponse"); - Element returnElement = - findChild(discoverResponse, XMLA_NS, "return"); - return findChild(returnElement, ROWSET_NS, "root"); - } - - /** - * Generates a metadata request. - * - *

The list of restrictions must have even length. Even elements must - * be a string (the name of the restriction); odd elements must be either - * a string (the value of the restriction) or a list of strings (multiple - * values of the restriction) - * - * @param context Context - * @param metadataRequest Metadata request - * @param restrictions List of restrictions - * @return XMLA SOAP request as a string. - * - * @throws OlapException when the query depends on a datasource name but - * the one specified doesn't exist at the url, or there are no default - * datasource (should use the first one) - */ - public String generateRequest( - Context context, - MetadataRequest metadataRequest, - Object[] restrictions) throws OlapException - { - final boolean datasourceDependentRequest = - metadataRequest.requiresDatasourceName(); - final String catalog = - context.olap4jConnection.getCatalog(); - final String content = "Data"; - final String encoding = proxy.getEncodingCharsetName(); - final StringBuilder buf = new StringBuilder( - "\n" - + "\n" - + " \n" - + " \n" - + " "); - buf.append(metadataRequest.name()); - buf.append("\n" - + " \n" - + " \n"); - if (restrictions.length > 0) { - if (restrictions.length % 2 != 0) { - throw new IllegalArgumentException(); - } - for (int i = 0; i < restrictions.length; i += 2) { - final String restriction = (String) restrictions[i]; - final Object o = restrictions[i + 1]; - if (o instanceof String) { - buf.append("<").append(restriction).append(">"); - final String value = (String) o; - buf.append(xmlEncode(value)); - buf.append(""); - - } else { - //noinspection unchecked - List valueList = (List) o; - for (String value : valueList) { - buf.append("<").append(restriction).append(">"); - buf.append(xmlEncode(value)); - buf.append(""); - } - } - } - } - buf.append(" \n" - + " \n" - + " \n" - + " \n"); - - // Add the datasource node only if this request requires it. - if (datasourceDependentRequest) { - buf.append(" "); - buf.append(xmlEncode(context.olap4jConnection.getDataSourceInfo())); - buf.append("\n" - + " "); - buf.append(xmlEncode(catalog)); - buf.append("\n"); - } - - buf.append(" "); - buf.append(xmlEncode(content)); - buf.append("\n" - + " \n" - + " \n" - + " \n" - + "\n" - + ""); - return buf.toString(); - } - - /** - * Encodes a string for use in an XML CDATA section. - * - * @param value to be xml encoded - * @return an XML encode string or the value is not required. - */ - private static String xmlEncode(String value) { - value = Olap4jUtil.replace(value, "&", "&"); - value = Olap4jUtil.replace(value, "<", "<"); - value = Olap4jUtil.replace(value, ">", ">"); - value = Olap4jUtil.replace(value, "\"", """); - value = Olap4jUtil.replace(value, "'", "'"); - return value; - } - - // ~ inner classes -------------------------------------------------------- - @SuppressWarnings({"ThrowableInstanceNeverThrown"}) - static class Helper { - OlapException createException(String msg) { - return new OlapException(msg); - } - - OlapException createException(String msg, Throwable cause) { - return new OlapException(msg, cause); - } - - OlapException createException(Cell context, String msg) { - OlapException exception = new OlapException(msg); - exception.setContext(context); - return exception; - } - - OlapException createException( - Cell context, String msg, Throwable cause) - { - OlapException exception = new OlapException(msg, cause); - exception.setContext(context); - return exception; - } - - public OlapException toOlapException(SQLException e) { - if (e instanceof OlapException) { - return (OlapException) e; - } else { - return new OlapException(null, e); - } - } - } - - static class CatalogHandler - extends HandlerImpl - { - public void handle(Element row, Context context, List list) { - /* - Example: - - - FoodMart - No description available - California manager,No HR Cube - - */ - String catalogName = XmlaOlap4jUtil.stringElement(row, "CATALOG_NAME"); - // Unused: DESCRIPTION, ROLES - list.add( - new XmlaOlap4jCatalog( - context.olap4jDatabaseMetaData, catalogName)); - } - } - - static class CubeHandler extends HandlerImpl { - - public void handle(Element row, Context context, - List list) - throws OlapException - { - /* - Example: - - - FoodMart - FoodMart - HR - CUBE - true - false - false - false - FoodMart Schema - HR Cube - - */ - // Unused: CATALOG_NAME, SCHEMA_NAME, CUBE_TYPE, - // IS_DRILLTHROUGH_ENABLED, IS_WRITE_ENABLED, IS_LINKABLE, - // IS_SQL_ENABLED - String cubeName = stringElement(row, "CUBE_NAME"); - String description = stringElement(row, "DESCRIPTION"); - list.add( - new XmlaOlap4jCube( - context.olap4jSchema, cubeName, description)); - } - } - - static class DimensionHandler extends HandlerImpl { - public void handle(Element row, Context context, List list) { - /* - Example: - - - FoodMart - FoodMart - HR - Department - [Department] - Department - 6 - 3 - 13 - [Department] - HR Cube - Department Dimension - false - false - 0 - true - - - */ - final String dimensionName = - stringElement(row, "DIMENSION_NAME"); - final String dimensionUniqueName = - stringElement(row, "DIMENSION_UNIQUE_NAME"); - final String dimensionCaption = - stringElement(row, "DIMENSION_CAPTION"); - final String description = - stringElement(row, "DESCRIPTION"); - final int dimensionType = - integerElement(row, "DIMENSION_TYPE"); - final Dimension.Type type = - Dimension.Type.values()[dimensionType]; - final String defaultHierarchyUniqueName = - stringElement(row, "DEFAULT_HIERARCHY"); - list.add( - new XmlaOlap4jDimension( - context.olap4jCube, dimensionUniqueName, dimensionName, - dimensionCaption, description, type, - defaultHierarchyUniqueName)); - } - } - - static class HierarchyHandler extends HandlerImpl { - public void handle( - Element row, Context context, List list) - throws OlapException - { - /* - Example: - - - FoodMart - FoodMart - Sales - [Customers] - Customers - [Customers] - Customers - 3 - 10407 - [Customers].[All Customers] - [Customers].[All Customers] - Sales Cube - Customers Hierarchy - 0 - false - false - 0 - true - 9 - true - false - - - */ - final String dimensionUniqueName = - stringElement(row, "DIMENSION_UNIQUE_NAME"); - final XmlaOlap4jDimension dimension = - context.olap4jCube.dimensionsByUname.get(dimensionUniqueName); - final String hierarchyName = - stringElement(row, "HIERARCHY_NAME"); - final String hierarchyUniqueName = - stringElement(row, "HIERARCHY_UNIQUE_NAME"); - final String hierarchyCaption = - stringElement(row, "HIERARCHY_CAPTION"); - final String description = - stringElement(row, "DESCRIPTION"); - final String allMember = - stringElement(row, "ALL_MEMBER"); - final String defaultMemberUniqueName = - stringElement(row, "DEFAULT_MEMBER"); - list.add( - new XmlaOlap4jHierarchy( - context.getDimension(row), hierarchyUniqueName, - hierarchyName, hierarchyCaption, description, - allMember != null, defaultMemberUniqueName)); - } - } - - static class LevelHandler extends HandlerImpl { - public void handle(Element row, Context context, List list) { - /* - Example: - - - FoodMart - FoodMart - Sales - [Customers] - [Customers] - (All) - [Customers].[(All)] - (All) - 0 - 1 - 1 - 0 - 3 - true - Sales Cube - Customers Hierarchy(All) Level - - - */ - final String levelName = - stringElement(row, "LEVEL_NAME"); - final String levelUniqueName = - stringElement(row, "LEVEL_UNIQUE_NAME"); - final String levelCaption = - stringElement(row, "LEVEL_CAPTION"); - final String description = - stringElement(row, "DESCRIPTION"); - final int levelNumber = - integerElement(row, "LEVEL_NUMBER"); - final Level.Type levelType = - Level.Type.forXmlaOrdinal(integerElement(row, "LEVEL_TYPE")); - final int levelCardinality = - integerElement(row, "LEVEL_CARDINALITY"); - list.add( - new XmlaOlap4jLevel( - context.getHierarchy(row), levelUniqueName, levelName, - levelCaption, description, levelNumber, levelType, - levelCardinality)); - } - } - - static class MeasureHandler extends HandlerImpl { - public void handle(Element row, Context context, List list) - throws OlapException { - /* - Example: - - - FoodMart - FoodMart - Sales - Profit - [Measures].[Profit] - Profit - 127 - 130 - true - Sales Cube - Profit Member - - - */ - final String measureName = - stringElement(row, "MEASURE_NAME"); - final String measureUniqueName = - stringElement(row, "MEASURE_UNIQUE_NAME"); - final String measureCaption = - stringElement(row, "MEASURE_CAPTION"); - final String description = - stringElement(row, "DESCRIPTION"); - final Measure.Aggregator measureAggregator = - Measure.Aggregator.forXmlaOrdinal( - integerElement(row, "MEASURE_AGGREGATOR")); - final Datatype datatype = - Datatype.forXmlaOrdinal( - integerElement(row, "DATA_TYPE")); - final boolean measureIsVisible = - booleanElement(row, "MEASURE_IS_VISIBLE"); - // REVIEW: We're making a lot of assumptions about where Measures - // live. - final XmlaOlap4jLevel measuresLevel = - (XmlaOlap4jLevel) - context.getCube(row).getHierarchies().get("Measures") - .getLevels().get(0); - - // Every measure is a member. MDSCHEMA_MEASURES does not return all - // properties of measures, so lookup the corresponding member. In - // particular, we need the ordinal. - if (list.isEmpty()) { - // First call this method, ask for all members of the measures - // level. This should ensures that we get all members in one - // round trip. - final List measureMembers = measuresLevel.getMembers(); - Olap4jUtil.discard(measureMembers); - } - Member member = - context.getCube(row).getMetadataReader() - .lookupMemberByUniqueName( - measureUniqueName); - final int ordinal; - if (member != null) { - ordinal = member.getOrdinal(); - } else { - ordinal = -1; - } - - list.add( - new XmlaOlap4jMeasure( - measuresLevel, measureUniqueName, measureName, - measureCaption, description, null, measureAggregator, - datatype, measureIsVisible, ordinal)); - } - - public void sortList(List list) { - Collections.sort( - list, - new Comparator() { - public int compare( - XmlaOlap4jMeasure o1, - XmlaOlap4jMeasure o2) - { - return o1.getOrdinal() - o2.getOrdinal(); - } - } - ); - } - } - - static class MemberHandler extends HandlerImpl { - public void handle(Element row, Context context, List list) { - /* - Example: - - - FoodMart - FoodMart - Sales - [Gender] - [Gender] - [Gender].[Gender] - 1 - 1 - F - [Gender].[All Gender].[F] - 1 - F - 0 - 0 - [Gender].[All Gender] - 1 - 1 - - - */ - int levelNumber = integerElement(row, "LEVEL_NUMBER"); - int memberOrdinal = integerElement(row, "MEMBER_ORDINAL"); - String memberUniqueName = - stringElement(row, "MEMBER_UNIQUE_NAME"); - String memberName = - stringElement(row, "MEMBER_NAME"); - String parentUniqueName = - stringElement(row, "PARENT_UNIQUE_NAME"); - Member.Type memberType = - Member.Type.values()[ - integerElement(row, "MEMBER_TYPE")]; - String memberCaption = - stringElement(row, "MEMBER_CAPTION"); - int childrenCardinality = - integerElement(row, "CHILDREN_CARDINALITY"); - // If this member is a measure, we want to return an object that - // implements the Measure interface to all API calls. But we also - // need to retrieve the properties that occur in MDSCHEMA_MEMBERS - // that are not available in MDSCHEMA_MEASURES, so we create a - // member for internal use. - list.add( - new XmlaOlap4jMember( - context.getLevel(row), memberUniqueName, memberName, - memberCaption, "", parentUniqueName, memberType, - childrenCardinality, memberOrdinal)); - } - } - - static class NamedSetHandler extends HandlerImpl { - public void handle(Element row, Context context, List list) { - /* - Example: - - - FoodMart - FoodMart - Warehouse - [Top Sellers] - 1 - - - */ - final String setName = - stringElement(row, "SET_NAME"); - list.add( - new XmlaOlap4jNamedSet( - context.getCube(row), setName)); - } - } - - static class SchemaHandler extends HandlerImpl { - public void handle(Element row, Context context, List list) throws OlapException { - /* - - LOCALDB - FoodMart - dbo - - */ - String schemaName = stringElement(row, "SCHEMA_NAME"); - list.add( - new XmlaOlap4jSchema( - context.getCatalog(row), - schemaName)); - } - } - - static class CatalogSchemaHandler extends HandlerImpl { - - private String catalogName; - - public CatalogSchemaHandler(String catalogName) { - super(); - if (catalogName == null) - throw new RuntimeException("The CatalogSchemaHandler handler requires a catalog name."); - this.catalogName = catalogName; - } - - public void handle(Element row, Context context, List list) throws OlapException - { - /* - - CatalogName - FoodMart - dbo - - */ - - /* - * We are looking for a schema name from the cubes query restricted on the - * catalog name. Some servers don't support nor include the SCHEMA_NAME column - * in it's response. If it's null, we convert it to an empty string as to not cause - * problems later on. - */ - - String schemaName = stringElement(row, "SCHEMA_NAME"); - String catalogName = stringElement(row, "CATALOG_NAME"); - - if (this.catalogName.equals(catalogName)) { - list.add( - new XmlaOlap4jSchema( - context.getCatalog(row), - (schemaName == null) ? "" : schemaName)); - } - } - } - - static class PropertyHandler extends HandlerImpl { - public void handle( - Element row, - Context context, List list) throws OlapException - { - /* - Example: - - - FoodMart - FoodMart - HR - [Store] - [Store] - [Store].[Store Name] - Store Manager - Store Manager - 1 - 130 - 0 - HR Cube - Store Hierarchy - Store - Name Level - Store Manager Property - - */ - String cubeName = stringElement(row, "CUBE_NAME"); - String description = stringElement(row, "DESCRIPTION"); - String uniqueName = stringElement(row, "DESCRIPTION"); - String caption = stringElement(row, "PROPERTY_CAPTION"); - String name = stringElement(row, "PROPERTY_NAME"); - Datatype dataType = - Datatype.forXmlaOrdinal( - integerElement(row, "DATA_TYPE")); - final Integer contentTypeOrdinal = - integerElement(row, "PROPERTY_CONTENT_TYPE"); - Property.ContentType contentType = - contentTypeOrdinal == null - ? null - : Property.ContentType.forXmlaOrdinal(contentTypeOrdinal); - int propertyType = integerElement(row, "PROPERTY_TYPE"); - Set type = - Property.TypeFlag.forMask(propertyType); - list.add( - new XmlaOlap4jProperty( - uniqueName, name, caption, description, dataType, type, - contentType)); - } - } - - /** - * Callback for converting XMLA results into metadata elements. - */ - interface Handler { - /** - * Converts an XML element from an XMLA result set into a metadata - * element and appends it to a list of metadata elements. - * - * @param row XMLA element - * - * @param context Context (schema, cube, dimension, etc.) that the - * request was executed in and that the element will belong to - * - * @param list List of metadata elements to append new metadata element - * - * @throws OlapException on error - */ - void handle( - Element row, - Context context, - List list) throws OlapException; - - /** - * Sorts a list of metadata elements. - * - *

For most element types, the order returned by XMLA is correct, and - * this method will no-op. - * - * @param list List of metadata elements - */ - void sortList(List list); - } - - static abstract class HandlerImpl implements Handler { - public void sortList(List list) { - // do nothing - assume XMLA returned list in correct order - } - - } - - static class Context { - final XmlaOlap4jConnection olap4jConnection; - final XmlaOlap4jDatabaseMetaData olap4jDatabaseMetaData; - final XmlaOlap4jCatalog olap4jCatalog; - final XmlaOlap4jSchema olap4jSchema; - final XmlaOlap4jCube olap4jCube; - final XmlaOlap4jDimension olap4jDimension; - final XmlaOlap4jHierarchy olap4jHierarchy; - final XmlaOlap4jLevel olap4jLevel; - - /** - * Creates a Context. - * - * @param olap4jConnection Connection (must not be null) - * @param olap4jDatabaseMetaData DatabaseMetaData (may be null) - * @param olap4jCatalog Catalog (may be null if DatabaseMetaData is null) - * @param olap4jSchema Schema (may be null if Catalog is null) - * @param olap4jCube Cube (may be null if Schema is null) - * @param olap4jDimension Dimension (may be null if Cube is null) - * @param olap4jHierarchy Hierarchy (may be null if Dimension is null) - * @param olap4jLevel Level (may be null if Hierarchy is null) - */ - Context( - XmlaOlap4jConnection olap4jConnection, - XmlaOlap4jDatabaseMetaData olap4jDatabaseMetaData, - XmlaOlap4jCatalog olap4jCatalog, - XmlaOlap4jSchema olap4jSchema, - XmlaOlap4jCube olap4jCube, - XmlaOlap4jDimension olap4jDimension, - XmlaOlap4jHierarchy olap4jHierarchy, - XmlaOlap4jLevel olap4jLevel) - { - this.olap4jConnection = olap4jConnection; - this.olap4jDatabaseMetaData = olap4jDatabaseMetaData; - this.olap4jCatalog = olap4jCatalog; - this.olap4jSchema = olap4jSchema; - this.olap4jCube = olap4jCube; - this.olap4jDimension = olap4jDimension; - this.olap4jHierarchy = olap4jHierarchy; - this.olap4jLevel = olap4jLevel; - assert (olap4jDatabaseMetaData != null || olap4jCatalog == null) - && (olap4jCatalog != null || olap4jSchema == null) - && (olap4jSchema != null || olap4jCube == null) - && (olap4jCube != null || olap4jDimension == null) - && (olap4jDimension != null || olap4jHierarchy == null) - && (olap4jHierarchy != null || olap4jLevel == null); - } - - /** - * Shorthand way to create a Context at Cube level or finer. - * - * @param olap4jCube Cube (must not be null) - * @param olap4jDimension Dimension (may be null) - * @param olap4jHierarchy Hierarchy (may be null if Dimension is null) - * @param olap4jLevel Level (may be null if Hierarchy is null) - */ - Context( - XmlaOlap4jCube olap4jCube, - XmlaOlap4jDimension olap4jDimension, - XmlaOlap4jHierarchy olap4jHierarchy, - XmlaOlap4jLevel olap4jLevel) - { - this( - olap4jCube.olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData - .olap4jConnection, - olap4jCube.olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData, - olap4jCube.olap4jSchema.olap4jCatalog, - olap4jCube.olap4jSchema, - olap4jCube, - olap4jDimension, - olap4jHierarchy, - olap4jLevel); - } - - /** - * Shorthand way to create a Context at Level level. - * - * @param olap4jLevel Level (must not be null) - */ - Context(XmlaOlap4jLevel olap4jLevel) - { - this( - olap4jLevel.olap4jHierarchy.olap4jDimension.olap4jCube, - olap4jLevel.olap4jHierarchy.olap4jDimension, - olap4jLevel.olap4jHierarchy, - olap4jLevel); - } - - XmlaOlap4jHierarchy getHierarchy(Element row) { - if (olap4jHierarchy != null) { - return olap4jHierarchy; - } - final String hierarchyUniqueName = - stringElement(row, "HIERARCHY_UNIQUE_NAME"); - return getCube(row).hierarchiesByUname.get(hierarchyUniqueName); - } - - XmlaOlap4jCube getCube(Element row) { - if (olap4jCube != null) { - return olap4jCube; - } - throw new UnsupportedOperationException(); // todo: - } - - XmlaOlap4jDimension getDimension(Element row) { - if (olap4jDimension != null) { - return olap4jDimension; - } - final String dimensionUniqueName = - stringElement(row, "DIMENSION_UNIQUE_NAME"); - return getCube(row).dimensionsByUname.get(dimensionUniqueName); - } - - public XmlaOlap4jLevel getLevel(Element row) { - if (olap4jLevel != null) { - return olap4jLevel; - } - final String levelUniqueName = - stringElement(row, "LEVEL_UNIQUE_NAME"); - return getCube(row).levelsByUname.get(levelUniqueName); - } - - public XmlaOlap4jCatalog getCatalog(Element row) throws OlapException { - if (olap4jCatalog != null) { - return olap4jCatalog; - } - final String catalogName = - stringElement(row, "CATALOG_NAME"); - return (XmlaOlap4jCatalog) olap4jConnection.getCatalogs().get( - catalogName); - } - } - - enum MetadataRequest { - DISCOVER_DATASOURCES( - new MetadataColumn("DataSourceName"), - new MetadataColumn("DataSourceDescription"), - new MetadataColumn("URL"), - new MetadataColumn("DataSourceInfo"), - new MetadataColumn("ProviderName"), - new MetadataColumn("ProviderType"), - new MetadataColumn("AuthenticationMode")), - DISCOVER_SCHEMA_ROWSETS( - new MetadataColumn("SchemaName"), - new MetadataColumn("SchemaGuid"), - new MetadataColumn("Restrictions"), - new MetadataColumn("Description")), - DISCOVER_ENUMERATORS( - new MetadataColumn("EnumName"), - new MetadataColumn("EnumDescription"), - new MetadataColumn("EnumType"), - new MetadataColumn("ElementName"), - new MetadataColumn("ElementDescription"), - new MetadataColumn("ElementValue")), - DISCOVER_PROPERTIES( - new MetadataColumn("PropertyName"), - new MetadataColumn("PropertyDescription"), - new MetadataColumn("PropertyType"), - new MetadataColumn("PropertyAccessType"), - new MetadataColumn("IsRequired"), - new MetadataColumn("Value")), - DISCOVER_KEYWORDS( - new MetadataColumn("Keyword")), - DISCOVER_LITERALS( - new MetadataColumn("LiteralName"), - new MetadataColumn("LiteralValue"), - new MetadataColumn("LiteralInvalidChars"), - new MetadataColumn("LiteralInvalidStartingChars"), - new MetadataColumn("LiteralMaxLength")), - DBSCHEMA_CATALOGS( - new MetadataColumn("CATALOG_NAME"), - new MetadataColumn("DESCRIPTION"), - new MetadataColumn("ROLES"), - new MetadataColumn("DATE_MODIFIED")), - DBSCHEMA_COLUMNS( - new MetadataColumn("TABLE_CATALOG"), - new MetadataColumn("TABLE_SCHEMA"), - new MetadataColumn("TABLE_NAME"), - new MetadataColumn("COLUMN_NAME"), - new MetadataColumn("ORDINAL_POSITION"), - new MetadataColumn("COLUMN_HAS_DEFAULT"), - new MetadataColumn("COLUMN_FLAGS"), - new MetadataColumn("IS_NULLABLE"), - new MetadataColumn("DATA_TYPE"), - new MetadataColumn("CHARACTER_MAXIMUM_LENGTH"), - new MetadataColumn("CHARACTER_OCTET_LENGTH"), - new MetadataColumn("NUMERIC_PRECISION"), - new MetadataColumn("NUMERIC_SCALE")), - DBSCHEMA_PROVIDER_TYPES( - new MetadataColumn("TYPE_NAME"), - new MetadataColumn("DATA_TYPE"), - new MetadataColumn("COLUMN_SIZE"), - new MetadataColumn("LITERAL_PREFIX"), - new MetadataColumn("LITERAL_SUFFIX"), - new MetadataColumn("IS_NULLABLE"), - new MetadataColumn("CASE_SENSITIVE"), - new MetadataColumn("SEARCHABLE"), - new MetadataColumn("UNSIGNED_ATTRIBUTE"), - new MetadataColumn("FIXED_PREC_SCALE"), - new MetadataColumn("AUTO_UNIQUE_VALUE"), - new MetadataColumn("IS_LONG"), - new MetadataColumn("BEST_MATCH")), - DBSCHEMA_TABLES( - new MetadataColumn("TABLE_CATALOG"), - new MetadataColumn("TABLE_SCHEMA"), - new MetadataColumn("TABLE_NAME"), - new MetadataColumn("TABLE_TYPE"), - new MetadataColumn("TABLE_GUID"), - new MetadataColumn("DESCRIPTION"), - new MetadataColumn("TABLE_PROPID"), - new MetadataColumn("DATE_CREATED"), - new MetadataColumn("DATE_MODIFIED")), - DBSCHEMA_TABLES_INFO( - new MetadataColumn("TABLE_CATALOG"), - new MetadataColumn("TABLE_SCHEMA"), - new MetadataColumn("TABLE_NAME"), - new MetadataColumn("TABLE_TYPE"), - new MetadataColumn("TABLE_GUID"), - new MetadataColumn("BOOKMARKS"), - new MetadataColumn("BOOKMARK_TYPE"), - new MetadataColumn("BOOKMARK_DATATYPE"), - new MetadataColumn("BOOKMARK_MAXIMUM_LENGTH"), - new MetadataColumn("BOOKMARK_INFORMATION"), - new MetadataColumn("TABLE_VERSION"), - new MetadataColumn("CARDINALITY"), - new MetadataColumn("DESCRIPTION"), - new MetadataColumn("TABLE_PROPID")), - DBSCHEMA_SCHEMATA( - new MetadataColumn("CATALOG_NAME"), - new MetadataColumn("SCHEMA_NAME"), - new MetadataColumn("SCHEMA_OWNER")), - MDSCHEMA_ACTIONS( - new MetadataColumn("SCHEMA_NAME"), - new MetadataColumn("CUBE_NAME"), - new MetadataColumn("ACTION_NAME"), - new MetadataColumn("COORDINATE"), - new MetadataColumn("COORDINATE_TYPE")), - MDSCHEMA_CUBES( - new MetadataColumn("CATALOG_NAME"), - new MetadataColumn("SCHEMA_NAME"), - new MetadataColumn("CUBE_NAME"), - new MetadataColumn("CUBE_TYPE"), - new MetadataColumn("CUBE_GUID"), - new MetadataColumn("CREATED_ON"), - new MetadataColumn("LAST_SCHEMA_UPDATE"), - new MetadataColumn("SCHEMA_UPDATED_BY"), - new MetadataColumn("LAST_DATA_UPDATE"), - new MetadataColumn("DATA_UPDATED_BY"), - new MetadataColumn("IS_DRILLTHROUGH_ENABLED"), - new MetadataColumn("IS_WRITE_ENABLED"), - new MetadataColumn("IS_LINKABLE"), - new MetadataColumn("IS_SQL_ENABLED"), - new MetadataColumn("DESCRIPTION")), - MDSCHEMA_DIMENSIONS( - new MetadataColumn("CATALOG_NAME"), - new MetadataColumn("SCHEMA_NAME"), - new MetadataColumn("CUBE_NAME"), - new MetadataColumn("DIMENSION_NAME"), - new MetadataColumn("DIMENSION_UNIQUE_NAME"), - new MetadataColumn("DIMENSION_GUID"), - new MetadataColumn("DIMENSION_CAPTION"), - new MetadataColumn("DIMENSION_ORDINAL"), - new MetadataColumn("DIMENSION_TYPE"), - new MetadataColumn("DIMENSION_CARDINALITY"), - new MetadataColumn("DEFAULT_HIERARCHY"), - new MetadataColumn("DESCRIPTION"), - new MetadataColumn("IS_VIRTUAL"), - new MetadataColumn("IS_READWRITE"), - new MetadataColumn("DIMENSION_UNIQUE_SETTINGS"), - new MetadataColumn("DIMENSION_MASTER_UNIQUE_NAME"), - new MetadataColumn("DIMENSION_IS_VISIBLE")), - MDSCHEMA_FUNCTIONS( - new MetadataColumn("FUNCTION_NAME"), - new MetadataColumn("DESCRIPTION"), - new MetadataColumn("PARAMETER_LIST"), - new MetadataColumn("RETURN_TYPE"), - new MetadataColumn("ORIGIN"), - new MetadataColumn("INTERFACE_NAME"), - new MetadataColumn("LIBRARY_NAME"), - new MetadataColumn("CAPTION")), - MDSCHEMA_HIERARCHIES( - new MetadataColumn("CATALOG_NAME"), - new MetadataColumn("SCHEMA_NAME"), - new MetadataColumn("CUBE_NAME"), - new MetadataColumn("DIMENSION_UNIQUE_NAME"), - new MetadataColumn("HIERARCHY_NAME"), - new MetadataColumn("HIERARCHY_UNIQUE_NAME"), - new MetadataColumn("HIERARCHY_GUID"), - new MetadataColumn("HIERARCHY_CAPTION"), - new MetadataColumn("DIMENSION_TYPE"), - new MetadataColumn("HIERARCHY_CARDINALITY"), - new MetadataColumn("DEFAULT_MEMBER"), - new MetadataColumn("ALL_MEMBER"), - new MetadataColumn("DESCRIPTION"), - new MetadataColumn("STRUCTURE"), - new MetadataColumn("IS_VIRTUAL"), - new MetadataColumn("IS_READWRITE"), - new MetadataColumn("DIMENSION_UNIQUE_SETTINGS"), - new MetadataColumn("DIMENSION_IS_VISIBLE"), - new MetadataColumn("HIERARCHY_ORDINAL"), - new MetadataColumn("DIMENSION_IS_SHARED"), - new MetadataColumn("PARENT_CHILD")), - MDSCHEMA_LEVELS( - new MetadataColumn("CATALOG_NAME"), - new MetadataColumn("SCHEMA_NAME"), - new MetadataColumn("CUBE_NAME"), - new MetadataColumn("DIMENSION_UNIQUE_NAME"), - new MetadataColumn("HIERARCHY_UNIQUE_NAME"), - new MetadataColumn("LEVEL_NAME"), - new MetadataColumn("LEVEL_UNIQUE_NAME"), - new MetadataColumn("LEVEL_GUID"), - new MetadataColumn("LEVEL_CAPTION"), - new MetadataColumn("LEVEL_NUMBER"), - new MetadataColumn("LEVEL_CARDINALITY"), - new MetadataColumn("LEVEL_TYPE"), - new MetadataColumn("CUSTOM_ROLLUP_SETTINGS"), - new MetadataColumn("LEVEL_UNIQUE_SETTINGS"), - new MetadataColumn("LEVEL_IS_VISIBLE"), - new MetadataColumn("DESCRIPTION")), - MDSCHEMA_MEASURES( - new MetadataColumn("CATALOG_NAME"), - new MetadataColumn("SCHEMA_NAME"), - new MetadataColumn("CUBE_NAME"), - new MetadataColumn("MEASURE_NAME"), - new MetadataColumn("MEASURE_UNIQUE_NAME"), - new MetadataColumn("MEASURE_CAPTION"), - new MetadataColumn("MEASURE_GUID"), - new MetadataColumn("MEASURE_AGGREGATOR"), - new MetadataColumn("DATA_TYPE"), - new MetadataColumn("MEASURE_IS_VISIBLE"), - new MetadataColumn("LEVELS_LIST"), - new MetadataColumn("DESCRIPTION")), - MDSCHEMA_MEMBERS( - new MetadataColumn("CATALOG_NAME"), - new MetadataColumn("SCHEMA_NAME"), - new MetadataColumn("CUBE_NAME"), - new MetadataColumn("DIMENSION_UNIQUE_NAME"), - new MetadataColumn("HIERARCHY_UNIQUE_NAME"), - new MetadataColumn("LEVEL_UNIQUE_NAME"), - new MetadataColumn("LEVEL_NUMBER"), - new MetadataColumn("MEMBER_ORDINAL"), - new MetadataColumn("MEMBER_NAME"), - new MetadataColumn("MEMBER_UNIQUE_NAME"), - new MetadataColumn("MEMBER_TYPE"), - new MetadataColumn("MEMBER_GUID"), - new MetadataColumn("MEMBER_CAPTION"), - new MetadataColumn("CHILDREN_CARDINALITY"), - new MetadataColumn("PARENT_LEVEL"), - new MetadataColumn("PARENT_UNIQUE_NAME"), - new MetadataColumn("PARENT_COUNT"), - new MetadataColumn("TREE_OP"), - new MetadataColumn("DEPTH")), - MDSCHEMA_PROPERTIES( - new MetadataColumn("CATALOG_NAME"), - new MetadataColumn("SCHEMA_NAME"), - new MetadataColumn("CUBE_NAME"), - new MetadataColumn("DIMENSION_UNIQUE_NAME"), - new MetadataColumn("HIERARCHY_UNIQUE_NAME"), - new MetadataColumn("LEVEL_UNIQUE_NAME"), - new MetadataColumn("MEMBER_UNIQUE_NAME"), - new MetadataColumn("PROPERTY_NAME"), - new MetadataColumn("PROPERTY_CAPTION"), - new MetadataColumn("PROPERTY_TYPE"), - new MetadataColumn("DATA_TYPE"), - new MetadataColumn("PROPERTY_CONTENT_TYPE"), - new MetadataColumn("DESCRIPTION")), - MDSCHEMA_SETS( - new MetadataColumn("CATALOG_NAME"), - new MetadataColumn("SCHEMA_NAME"), - new MetadataColumn("CUBE_NAME"), - new MetadataColumn("SET_NAME"), - new MetadataColumn("SCOPE")); - - final List columns; - - MetadataRequest(MetadataColumn... columns) { - if (name().equals("DBSCHEMA_CATALOGS")) { - // DatabaseMetaData.getCatalogs() is defined by JDBC not XMLA, - // so has just one column. Ignore the 4 columns from XMLA. - columns = new MetadataColumn[] { - new MetadataColumn("CATALOG_NAME", "TABLE_CAT") - }; - } else if (name().equals("DBSCHEMA_SCHEMATA")) { - // DatabaseMetaData.getCatalogs() is defined by JDBC not XMLA, - // so has just one column. Ignore the 4 columns from XMLA. - columns = new MetadataColumn[] { - new MetadataColumn("SCHEMA_NAME", "TABLE_SCHEM"), - new MetadataColumn("CATALOG_NAME", "TABLE_CAT") - }; - } - this.columns = - Collections.unmodifiableList( - Arrays.asList(columns)); - } - - /** - * Returns whether this request requires a - * {@code <DatasourceName>} element. - * - * @return whether this request requires a DatasourceName element - */ - public boolean requiresDatasourceName() { - return this != DISCOVER_DATASOURCES; - } - } - - private static final Pattern LOWERCASE_PATTERN = Pattern.compile(".*[a-z].*"); - - static class MetadataColumn { - final String name; - final String xmlaName; - - MetadataColumn(String xmlaName, String name) { - this.xmlaName = xmlaName; - this.name = name; - } - - MetadataColumn(String xmlaName) { - this.xmlaName = xmlaName; - String name = xmlaName; - if (LOWERCASE_PATTERN.matcher(name).matches()) { - name = Olap4jUtil.camelToUpper(name); - } - // VALUE is a SQL reserved word - if (name.equals("VALUE")) { - name = "PROPERTY_VALUE"; - } - this.name = name; - } - } - - private static class XmlaOlap4jMdxValidator implements MdxValidator { - private final OlapConnection connection; - - XmlaOlap4jMdxValidator(OlapConnection connection) { - this.connection = connection; - } - - public SelectNode validateSelect(SelectNode selectNode) throws OlapException { - StringWriter sw = new StringWriter(); - selectNode.unparse(new ParseTreeWriter(new PrintWriter(sw))); - String mdx = sw.toString(); - final XmlaOlap4jConnection olap4jConnection = - (XmlaOlap4jConnection) connection; - return selectNode; - } - } -} - -// End XmlaOlap4jConnection.java +/* +// This software is subject to the terms of the Common Public License +// Agreement, available at the following URL: +// http://www.opensource.org/licenses/cpl.html. +// Copyright (C) 2007-2007 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j.driver.xmla; + +import org.olap4j.*; + +import static org.olap4j.driver.xmla.XmlaOlap4jUtil.*; + +import org.olap4j.driver.xmla.proxy.*; +import org.olap4j.impl.*; +import org.olap4j.mdx.ParseTreeWriter; +import org.olap4j.mdx.SelectNode; +import org.olap4j.mdx.parser.*; +import org.olap4j.mdx.parser.impl.DefaultMdxParserImpl; +import org.olap4j.metadata.*; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.SAXException; + +import java.io.*; +import java.net.MalformedURLException; +import java.net.URL; +import java.sql.*; +import java.util.*; +import java.util.Map.*; +import java.util.regex.*; + +/** + * Implementation of {@link org.olap4j.OlapConnection} + * for XML/A providers. + * + *

This class has sub-classes which implement JDBC 3.0 and JDBC 4.0 APIs; + * it is instantiated using {@link Factory#newConnection}.

+ * + * @author jhyde + * @version $Id$ + * @since May 23, 2007 + */ +abstract class XmlaOlap4jConnection implements OlapConnection { + /** + *

Handler for errors. + */ + final Helper helper = new Helper(); + + /** + *

Current schema. + */ + private XmlaOlap4jSchema olap4jSchema; + + private final XmlaOlap4jDatabaseMetaData olap4jDatabaseMetaData; + + private static final String CONNECT_STRING_PREFIX = "jdbc:xmla:"; + + final Factory factory; + + final XmlaOlap4jProxy proxy; + + private boolean closed; + + /** + *

URL of the HTTP server to which to send XML requests. + */ + final URL serverUrl; + + private Locale locale; + private String catalogName; + private static final boolean DEBUG = false; + private String roleName; + + /** + *

Holds on to the provider name + */ + private String providerName; + + /** + *

Holds on to the datasource name. + */ + private String datasourceName; + + /** + * Holds the datasource name as specified by the server. Necessary because + * some servers (such as mondrian) return both the provider + * name and the datasource name in their response. + * + *

It's this value that we use inside queries, and not the jdbc + * query value. + */ + private String nativeDatasourceName; + private boolean autoCommit; + private boolean readOnly; + + /** + * Name of the "DATA_SOURCE_NAME" column returned from + * {@link org.olap4j.OlapDatabaseMetaData#getDatasources()}. + */ + private static final String DATA_SOURCE_NAME = "DATA_SOURCE_NAME"; + + /** + * Name of the "PROVIDER_NAME" column returned from + * {@link org.olap4j.OlapDatabaseMetaData#getDatasources()}. + */ + private static final String PROVIDER_NAME = "PROVIDER_NAME"; + + /** + * Creates an Olap4j connection an XML/A provider. + * + *

This method is intentionally package-protected. The public API + * uses the traditional JDBC {@link java.sql.DriverManager}. + * See {@link org.olap4j.driver.xmla.XmlaOlap4jDriver} for more details. + * + *

Note that this constructor should make zero non-trivial calls, which + * could cause deadlocks due to java.sql.DriverManager synchronization + * issues. + * + * @pre acceptsURL(url) + * + * @param factory Factory + * @param proxy Proxy object which receives XML requests + * @param url Connect-string URL + * @param info Additional properties + * @throws java.sql.SQLException if there is an error + */ + XmlaOlap4jConnection( + Factory factory, + XmlaOlap4jProxy proxy, + String url, + Properties info) + throws SQLException + { + this.factory = factory; + this.proxy = proxy; + if (!acceptsURL(url)) { + // This is not a URL we can handle. + // DriverManager should not have invoked us. + throw new AssertionError( + "does not start with '" + CONNECT_STRING_PREFIX + "'"); + } + Map map = parseConnectString(url, info); + + this.providerName = map.get(XmlaOlap4jDriver.Property.Provider.name()); + this.datasourceName = map.get(XmlaOlap4jDriver.Property.DataSource.name()); + this.catalogName = map.get(XmlaOlap4jDriver.Property.Catalog.name()); + + // Set URL of HTTP server. + String serverUrl = map.get(XmlaOlap4jDriver.Property.Server.name()); + if (serverUrl == null) { + throw helper.createException("Connection property '" + + XmlaOlap4jDriver.Property.Server.name() + + "' must be specified"); + } + + // Basic authentication. Make sure the credentials passed as standard + // JDBC parameters override any credentials already included in the URL + // as part of the standard URL scheme. + if (map.containsKey("user") && map.containsKey("password")) { + serverUrl = serverUrl.replaceFirst( + ":\\/\\/([^@]*@){0,1}", + "://" + .concat(map.get("user")) + .concat(":") + .concat(map.get("password") + .concat("@"))); + } + + // Initialize the SOAP cache if needed + initSoapCache(map); + + try { + this.serverUrl = new URL(serverUrl); + } catch (MalformedURLException e) { + throw helper.createException( + "Error while creating connection", e); + } + + this.olap4jDatabaseMetaData = + factory.newDatabaseMetaData(this); + } + + + /** + * Initializes a cache object and configures it if cache + * parameters were specified in the jdbc url. + * + * @param map The parameters from the jdbc url. + * @throws OlapException Thrown when there is an error encountered + * while creating the cache. + */ + private void initSoapCache(Map map) throws OlapException { + + // Test if a SOAP cache class was defined + if (map.containsKey(XmlaOlap4jDriver.Property.Cache.name() + .toUpperCase())) + { + // Create a properties object to pass to the proxy + // so it can configure it's cache + Map props = new HashMap(); + // Iterate over map entries to find those related to + // the cache config + for (Entry entry : map.entrySet()) { + // Check if the current entry relates to cache config. + if (entry.getKey().startsWith( + XmlaOlap4jDriver.Property.Cache.name().toUpperCase() + + ".")) //$NON-NLS-1$ + { + props.put(entry.getKey().substring( + XmlaOlap4jDriver.Property.Cache.name() + .length() + 1), entry.getValue()); + } + } + + // Init the cache + ((XmlaOlap4jCachedProxy) this.proxy).setCache(map, props); + } + } + + + + static Map parseConnectString(String url, Properties info) { + String x = url.substring(CONNECT_STRING_PREFIX.length()); + Map map = + ConnectStringParser.parseConnectString(x); + for (Map.Entry entry : toMap(info).entrySet()) { + map.put(entry.getKey(), entry.getValue()); + } + return map; + } + + static boolean acceptsURL(String url) { + return url.startsWith(CONNECT_STRING_PREFIX); + } + + /** + * Returns the native datasource name, using the cached value if already + * computed. + * + *

Not part of public API. + * + * @return native datasource name + * @throws OlapException if cannot find a datasource that matches + */ + String getDataSourceInfo() throws OlapException { + // If we already know it, return it. + if (this.nativeDatasourceName != null) { + return this.nativeDatasourceName; + } + + ResultSet rSet = null; + try { + // We need to query for it + rSet = this.olap4jDatabaseMetaData.getDatasources(); + + // Check if the user requested a particular one. + if (this.datasourceName != null || this.providerName != null) { + // We iterate through the datasources + while (rSet.next()) { + // Get current values + String currentDatasource = rSet.getString(DATA_SOURCE_NAME); + String currentProvider = rSet.getString(PROVIDER_NAME); + + // If datasource and provider match, we got it. + // If datasource matches but no provider is specified, we + // got it. + // If provider matches but no datasource specified, we + // consider it good. + if (currentDatasource.equals(this.datasourceName) + && currentProvider.equals(this.providerName) + || currentDatasource.equals(this.datasourceName) + && this.providerName == null + || currentProvider.equals(this.providerName) + && this.datasourceName == null) + { + // Got it + this.nativeDatasourceName = currentDatasource; + break; + } + } + } else { + // Use first + if (rSet.first()) { + this.nativeDatasourceName = rSet.getString(DATA_SOURCE_NAME); + } + } + + // Throws exception to the client. + //Tells that there are no datasource corresponding to the search criterias. + if (this.nativeDatasourceName == null) { + throw new OlapException("No datasource could be found."); + } + + // If there is a provider + return this.nativeDatasourceName; + } catch (OlapException e) { + throw e; + } catch (SQLException e) { + throw new OlapException("Datasource name not found.", e); + } finally { + try { + if (rSet != null) { + rSet.close(); + } + } catch (SQLException e) { + // ignore + } + } + } + + public OlapStatement createStatement() { + return new XmlaOlap4jStatement(this); + } + + public PreparedStatement prepareStatement(String sql) throws SQLException { + throw new UnsupportedOperationException(); + } + + public CallableStatement prepareCall(String sql) throws SQLException { + throw new UnsupportedOperationException(); + } + + public String nativeSQL(String sql) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setAutoCommit(boolean autoCommit) throws SQLException { + this.autoCommit = autoCommit; + } + + public boolean getAutoCommit() throws SQLException { + return autoCommit; + } + + public void commit() throws SQLException { + throw new UnsupportedOperationException(); + } + + public void rollback() throws SQLException { + throw new UnsupportedOperationException(); + } + + public void close() throws SQLException { + closed = true; + } + + public boolean isClosed() throws SQLException { + return closed; + } + + public OlapDatabaseMetaData getMetaData() { + return olap4jDatabaseMetaData; + } + + public NamedList getCatalogs() { + return olap4jDatabaseMetaData.getCatalogObjects(); + } + + public void setReadOnly(boolean readOnly) throws SQLException { + this.readOnly = readOnly; + } + + public boolean isReadOnly() throws SQLException { + return readOnly; + } + + public void setCatalog(String catalog) throws SQLException { + this.catalogName = catalog; + } + + public String getCatalog() { + return catalogName; + } + + public void setTransactionIsolation(int level) throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getTransactionIsolation() throws SQLException { + throw new UnsupportedOperationException(); + } + + public SQLWarning getWarnings() throws SQLException { + throw new UnsupportedOperationException(); + } + + public void clearWarnings() throws SQLException { + // this driver does not support warnings, so nothing to do + } + + public Statement createStatement( + int resultSetType, int resultSetConcurrency) throws SQLException { + throw new UnsupportedOperationException(); + } + + public PreparedStatement prepareStatement( + String sql, + int resultSetType, + int resultSetConcurrency) throws SQLException { + throw new UnsupportedOperationException(); + } + + public CallableStatement prepareCall( + String sql, + int resultSetType, + int resultSetConcurrency) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Map> getTypeMap() throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setTypeMap(Map> map) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setHoldability(int holdability) throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getHoldability() throws SQLException { + throw new UnsupportedOperationException(); + } + + public Savepoint setSavepoint() throws SQLException { + throw new UnsupportedOperationException(); + } + + public Savepoint setSavepoint(String name) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void rollback(Savepoint savepoint) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + throw new UnsupportedOperationException(); + } + + public Statement createStatement( + int resultSetType, + int resultSetConcurrency, + int resultSetHoldability) throws SQLException { + throw new UnsupportedOperationException(); + } + + public PreparedStatement prepareStatement( + String sql, + int resultSetType, + int resultSetConcurrency, + int resultSetHoldability) throws SQLException { + throw new UnsupportedOperationException(); + } + + public CallableStatement prepareCall( + String sql, + int resultSetType, + int resultSetConcurrency, + int resultSetHoldability) throws SQLException { + throw new UnsupportedOperationException(); + } + + public PreparedStatement prepareStatement( + String sql, int autoGeneratedKeys) throws SQLException { + throw new UnsupportedOperationException(); + } + + public PreparedStatement prepareStatement( + String sql, int columnIndexes[]) throws SQLException { + throw new UnsupportedOperationException(); + } + + public PreparedStatement prepareStatement( + String sql, String columnNames[]) throws SQLException { + throw new UnsupportedOperationException(); + } + + // implement Wrapper + + public T unwrap(Class iface) throws SQLException { + if (iface.isInstance(this)) { + return iface.cast(this); + } + throw helper.createException("does not implement '" + iface + "'"); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return iface.isInstance(this); + } + + // implement OlapConnection + + public PreparedOlapStatement prepareOlapStatement( + String mdx) + throws OlapException { + return factory.newPreparedStatement(mdx, this); + } + + public MdxParserFactory getParserFactory() { + return new MdxParserFactory() { + public MdxParser createMdxParser(OlapConnection connection) { + return new DefaultMdxParserImpl(connection); + } + + public MdxValidator createMdxValidator(OlapConnection connection) { + return new XmlaOlap4jMdxValidator(connection); + } + }; + } + + public synchronized org.olap4j.metadata.Schema getSchema() throws OlapException { + // initializes the olap4jSchema if necessary + if (this.olap4jSchema == null) { + final XmlaOlap4jCatalog catalog = + (XmlaOlap4jCatalog) + this.olap4jDatabaseMetaData.getCatalogObjects().get( + catalogName); + this.olap4jSchema = (XmlaOlap4jSchema) catalog.getSchemas() + .get(0); + } + return olap4jSchema; + } + + public static Map toMap(final Properties properties) { + return new AbstractMap() { + public Set> entrySet() { + return Olap4jUtil.cast(properties.entrySet()); + } + }; + } + + /** + * Returns the URL which was used to create this connection. + * + * @return URL + */ + String getURL() { + throw Olap4jUtil.needToImplement(this); + } + + public void setLocale(Locale locale) { + if (locale == null) { + throw new IllegalArgumentException("locale must not be null"); + } + this.locale = locale; + } + + public Locale getLocale() { + if (locale == null) { + return Locale.getDefault(); + } + return locale; + } + + public void setRoleName(String roleName) throws OlapException { + this.roleName = roleName; + } + + public String getRoleName() { + return roleName; + } + + void populateList( + List list, + Context context, + MetadataRequest metadataRequest, + Handler handler, + Object[] restrictions) throws OlapException + { + String request = + generateRequest(context, metadataRequest, restrictions); + Element root = xxx(request); + for (Element o : childElements(root)) { + if (o.getLocalName().equals("row")) { + handler.handle(o, context, list); + } + } + handler.sortList(list); + } + + Element xxx(String request) throws OlapException { + byte[] bytes; + try { + bytes = proxy.get(serverUrl, request); + } catch (IOException e) { + throw helper.createException(null, e); + } + Document doc; + try { + doc = parse(bytes); + } catch (IOException e) { + throw helper.createException( + "error discovering metadata", e); + } catch (SAXException e) { + throw helper.createException( + "error discovering metadata", e); + } + // + // + // + // + // + // + // (see below) + // + // + // + // + // + final Element envelope = doc.getDocumentElement(); + if (DEBUG) { + System.out.println(XmlaOlap4jUtil.toString(doc, true)); + } + assert envelope.getLocalName().equals("Envelope"); + assert envelope.getNamespaceURI().equals(SOAP_NS); + Element body = + findChild(envelope, SOAP_NS, "Body"); + Element fault = + findChild(body, SOAP_NS, "Fault"); + if (fault != null) { + /* + + SOAP-ENV:Client.00HSBC01 + XMLA connection datasource not found + Mondrian + + + 00HSBC01 + The Mondrian XML: Mondrian Error:Internal + error: no catalog named 'LOCALDB' + + + + */ + // TODO: log doc to logfile + final Element faultstring = findChild(fault, null, "faultstring"); + String message = faultstring.getTextContent(); + throw helper.createException( + "XMLA provider gave exception: " + message + + "; request: " + request); + } + Element discoverResponse = + findChild(body, XMLA_NS, "DiscoverResponse"); + Element returnElement = + findChild(discoverResponse, XMLA_NS, "return"); + return findChild(returnElement, ROWSET_NS, "root"); + } + + /** + * Generates a metadata request. + * + *

The list of restrictions must have even length. Even elements must + * be a string (the name of the restriction); odd elements must be either + * a string (the value of the restriction) or a list of strings (multiple + * values of the restriction) + * + * @param context Context + * @param metadataRequest Metadata request + * @param restrictions List of restrictions + * @return XMLA SOAP request as a string. + * + * @throws OlapException when the query depends on a datasource name but + * the one specified doesn't exist at the url, or there are no default + * datasource (should use the first one) + */ + public String generateRequest( + Context context, + MetadataRequest metadataRequest, + Object[] restrictions) throws OlapException + { + final boolean datasourceDependentRequest = + metadataRequest.requiresDatasourceName(); + final String catalog = + context.olap4jConnection.getCatalog(); + final String content = "Data"; + final String encoding = proxy.getEncodingCharsetName(); + final StringBuilder buf = new StringBuilder( + "\n" + + "\n" + + " \n" + + " \n" + + " "); + buf.append(metadataRequest.name()); + buf.append("\n" + + " \n" + + " \n"); + if (restrictions.length > 0) { + if (restrictions.length % 2 != 0) { + throw new IllegalArgumentException(); + } + for (int i = 0; i < restrictions.length; i += 2) { + final String restriction = (String) restrictions[i]; + final Object o = restrictions[i + 1]; + if (o instanceof String) { + buf.append("<").append(restriction).append(">"); + final String value = (String) o; + buf.append(xmlEncode(value)); + buf.append(""); + + } else { + //noinspection unchecked + List valueList = (List) o; + for (String value : valueList) { + buf.append("<").append(restriction).append(">"); + buf.append(xmlEncode(value)); + buf.append(""); + } + } + } + } + buf.append(" \n" + + " \n" + + " \n" + + " \n"); + + // Add the datasource node only if this request requires it. + if (datasourceDependentRequest) { + buf.append(" "); + buf.append(xmlEncode(context.olap4jConnection.getDataSourceInfo())); + buf.append("\n" + + " "); + buf.append(xmlEncode(catalog)); + buf.append("\n"); + } + + buf.append(" "); + buf.append(xmlEncode(content)); + buf.append("\n" + + " \n" + + " \n" + + " \n" + + "\n" + + ""); + return buf.toString(); + } + + /** + * Encodes a string for use in an XML CDATA section. + * + * @param value to be xml encoded + * @return an XML encode string or the value is not required. + */ + private static String xmlEncode(String value) { + value = Olap4jUtil.replace(value, "&", "&"); + value = Olap4jUtil.replace(value, "<", "<"); + value = Olap4jUtil.replace(value, ">", ">"); + value = Olap4jUtil.replace(value, "\"", """); + value = Olap4jUtil.replace(value, "'", "'"); + return value; + } + + // ~ inner classes -------------------------------------------------------- + @SuppressWarnings({"ThrowableInstanceNeverThrown"}) + static class Helper { + OlapException createException(String msg) { + return new OlapException(msg); + } + + OlapException createException(String msg, Throwable cause) { + return new OlapException(msg, cause); + } + + OlapException createException(Cell context, String msg) { + OlapException exception = new OlapException(msg); + exception.setContext(context); + return exception; + } + + OlapException createException( + Cell context, String msg, Throwable cause) + { + OlapException exception = new OlapException(msg, cause); + exception.setContext(context); + return exception; + } + + public OlapException toOlapException(SQLException e) { + if (e instanceof OlapException) { + return (OlapException) e; + } else { + return new OlapException(null, e); + } + } + } + + static class CatalogHandler + extends HandlerImpl + { + public void handle(Element row, Context context, List list) { + /* + Example: + + + FoodMart + No description available + California manager,No HR Cube + + */ + String catalogName = XmlaOlap4jUtil.stringElement(row, "CATALOG_NAME"); + // Unused: DESCRIPTION, ROLES + list.add( + new XmlaOlap4jCatalog( + context.olap4jDatabaseMetaData, catalogName)); + } + } + + static class CubeHandler extends HandlerImpl { + + public void handle(Element row, Context context, + List list) + throws OlapException + { + /* + Example: + + + FoodMart + FoodMart + HR + CUBE + true + false + false + false + FoodMart Schema - HR Cube + + */ + // Unused: CATALOG_NAME, SCHEMA_NAME, CUBE_TYPE, + // IS_DRILLTHROUGH_ENABLED, IS_WRITE_ENABLED, IS_LINKABLE, + // IS_SQL_ENABLED + String cubeName = stringElement(row, "CUBE_NAME"); + String description = stringElement(row, "DESCRIPTION"); + list.add( + new XmlaOlap4jCube( + context.olap4jSchema, cubeName, description)); + } + } + + static class DimensionHandler extends HandlerImpl { + public void handle(Element row, Context context, List list) { + /* + Example: + + + FoodMart + FoodMart + HR + Department + [Department] + Department + 6 + 3 + 13 + [Department] + HR Cube - Department Dimension + false + false + 0 + true + + + */ + final String dimensionName = + stringElement(row, "DIMENSION_NAME"); + final String dimensionUniqueName = + stringElement(row, "DIMENSION_UNIQUE_NAME"); + final String dimensionCaption = + stringElement(row, "DIMENSION_CAPTION"); + final String description = + stringElement(row, "DESCRIPTION"); + final int dimensionType = + integerElement(row, "DIMENSION_TYPE"); + final Dimension.Type type = + Dimension.Type.values()[dimensionType]; + final String defaultHierarchyUniqueName = + stringElement(row, "DEFAULT_HIERARCHY"); + list.add( + new XmlaOlap4jDimension( + context.olap4jCube, dimensionUniqueName, dimensionName, + dimensionCaption, description, type, + defaultHierarchyUniqueName)); + } + } + + static class HierarchyHandler extends HandlerImpl { + public void handle( + Element row, Context context, List list) + throws OlapException + { + /* + Example: + + + FoodMart + FoodMart + Sales + [Customers] + Customers + [Customers] + Customers + 3 + 10407 + [Customers].[All Customers] + [Customers].[All Customers] + Sales Cube - Customers Hierarchy + 0 + false + false + 0 + true + 9 + true + false + + + */ + final String dimensionUniqueName = + stringElement(row, "DIMENSION_UNIQUE_NAME"); + final XmlaOlap4jDimension dimension = + context.olap4jCube.dimensionsByUname.get(dimensionUniqueName); + final String hierarchyName = + stringElement(row, "HIERARCHY_NAME"); + final String hierarchyUniqueName = + stringElement(row, "HIERARCHY_UNIQUE_NAME"); + final String hierarchyCaption = + stringElement(row, "HIERARCHY_CAPTION"); + final String description = + stringElement(row, "DESCRIPTION"); + final String allMember = + stringElement(row, "ALL_MEMBER"); + final String defaultMemberUniqueName = + stringElement(row, "DEFAULT_MEMBER"); + list.add( + new XmlaOlap4jHierarchy( + context.getDimension(row), hierarchyUniqueName, + hierarchyName, hierarchyCaption, description, + allMember != null, defaultMemberUniqueName)); + } + } + + static class LevelHandler extends HandlerImpl { + public void handle(Element row, Context context, List list) { + /* + Example: + + + FoodMart + FoodMart + Sales + [Customers] + [Customers] + (All) + [Customers].[(All)] + (All) + 0 + 1 + 1 + 0 + 3 + true + Sales Cube - Customers Hierarchy(All) Level + + + */ + final String levelName = + stringElement(row, "LEVEL_NAME"); + final String levelUniqueName = + stringElement(row, "LEVEL_UNIQUE_NAME"); + final String levelCaption = + stringElement(row, "LEVEL_CAPTION"); + final String description = + stringElement(row, "DESCRIPTION"); + final int levelNumber = + integerElement(row, "LEVEL_NUMBER"); + final Level.Type levelType = + Level.Type.forXmlaOrdinal(integerElement(row, "LEVEL_TYPE")); + final int levelCardinality = + integerElement(row, "LEVEL_CARDINALITY"); + list.add( + new XmlaOlap4jLevel( + context.getHierarchy(row), levelUniqueName, levelName, + levelCaption, description, levelNumber, levelType, + levelCardinality)); + } + } + + static class MeasureHandler extends HandlerImpl { + public void handle(Element row, Context context, List list) + throws OlapException { + /* + Example: + + + FoodMart + FoodMart + Sales + Profit + [Measures].[Profit] + Profit + 127 + 130 + true + Sales Cube - Profit Member + + + */ + final String measureName = + stringElement(row, "MEASURE_NAME"); + final String measureUniqueName = + stringElement(row, "MEASURE_UNIQUE_NAME"); + final String measureCaption = + stringElement(row, "MEASURE_CAPTION"); + final String description = + stringElement(row, "DESCRIPTION"); + final Measure.Aggregator measureAggregator = + Measure.Aggregator.forXmlaOrdinal( + integerElement(row, "MEASURE_AGGREGATOR")); + final Datatype datatype = + Datatype.forXmlaOrdinal( + integerElement(row, "DATA_TYPE")); + final boolean measureIsVisible = + booleanElement(row, "MEASURE_IS_VISIBLE"); + // REVIEW: We're making a lot of assumptions about where Measures + // live. + final XmlaOlap4jLevel measuresLevel = + (XmlaOlap4jLevel) + context.getCube(row).getHierarchies().get("Measures") + .getLevels().get(0); + + // Every measure is a member. MDSCHEMA_MEASURES does not return all + // properties of measures, so lookup the corresponding member. In + // particular, we need the ordinal. + if (list.isEmpty()) { + // First call this method, ask for all members of the measures + // level. This should ensures that we get all members in one + // round trip. + final List measureMembers = measuresLevel.getMembers(); + Olap4jUtil.discard(measureMembers); + } + Member member = + context.getCube(row).getMetadataReader() + .lookupMemberByUniqueName( + measureUniqueName); + final int ordinal; + if (member != null) { + ordinal = member.getOrdinal(); + } else { + ordinal = -1; + } + + list.add( + new XmlaOlap4jMeasure( + measuresLevel, measureUniqueName, measureName, + measureCaption, description, null, measureAggregator, + datatype, measureIsVisible, ordinal)); + } + + public void sortList(List list) { + Collections.sort( + list, + new Comparator() { + public int compare( + XmlaOlap4jMeasure o1, + XmlaOlap4jMeasure o2) + { + return o1.getOrdinal() - o2.getOrdinal(); + } + } + ); + } + } + + static class MemberHandler extends HandlerImpl { + public void handle(Element row, Context context, List list) { + /* + Example: + + + FoodMart + FoodMart + Sales + [Gender] + [Gender] + [Gender].[Gender] + 1 + 1 + F + [Gender].[All Gender].[F] + 1 + F + 0 + 0 + [Gender].[All Gender] + 1 + 1 + + + */ + int levelNumber = integerElement(row, "LEVEL_NUMBER"); + int memberOrdinal = integerElement(row, "MEMBER_ORDINAL"); + String memberUniqueName = + stringElement(row, "MEMBER_UNIQUE_NAME"); + String memberName = + stringElement(row, "MEMBER_NAME"); + String parentUniqueName = + stringElement(row, "PARENT_UNIQUE_NAME"); + Member.Type memberType = + Member.Type.values()[ + integerElement(row, "MEMBER_TYPE")]; + String memberCaption = + stringElement(row, "MEMBER_CAPTION"); + int childrenCardinality = + integerElement(row, "CHILDREN_CARDINALITY"); + // If this member is a measure, we want to return an object that + // implements the Measure interface to all API calls. But we also + // need to retrieve the properties that occur in MDSCHEMA_MEMBERS + // that are not available in MDSCHEMA_MEASURES, so we create a + // member for internal use. + list.add( + new XmlaOlap4jMember( + context.getLevel(row), memberUniqueName, memberName, + memberCaption, "", parentUniqueName, memberType, + childrenCardinality, memberOrdinal)); + } + } + + static class NamedSetHandler extends HandlerImpl { + public void handle(Element row, Context context, List list) { + /* + Example: + + + FoodMart + FoodMart + Warehouse + [Top Sellers] + 1 + + + */ + final String setName = + stringElement(row, "SET_NAME"); + list.add( + new XmlaOlap4jNamedSet( + context.getCube(row), setName)); + } + } + + static class SchemaHandler extends HandlerImpl { + public void handle(Element row, Context context, List list) throws OlapException { + /* + + LOCALDB + FoodMart + dbo + + */ + String schemaName = stringElement(row, "SCHEMA_NAME"); + list.add( + new XmlaOlap4jSchema( + context.getCatalog(row), + schemaName)); + } + } + + static class CatalogSchemaHandler extends HandlerImpl { + + private String catalogName; + + public CatalogSchemaHandler(String catalogName) { + super(); + if (catalogName == null) + throw new RuntimeException("The CatalogSchemaHandler handler requires a catalog name."); + this.catalogName = catalogName; + } + + public void handle(Element row, Context context, List list) throws OlapException + { + /* + + CatalogName + FoodMart + dbo + + */ + + /* + * We are looking for a schema name from the cubes query restricted on the + * catalog name. Some servers don't support nor include the SCHEMA_NAME column + * in it's response. If it's null, we convert it to an empty string as to not cause + * problems later on. + */ + + String schemaName = stringElement(row, "SCHEMA_NAME"); + String catalogName = stringElement(row, "CATALOG_NAME"); + + if (this.catalogName.equals(catalogName)) { + list.add( + new XmlaOlap4jSchema( + context.getCatalog(row), + (schemaName == null) ? "" : schemaName)); + } + } + } + + static class PropertyHandler extends HandlerImpl { + public void handle( + Element row, + Context context, List list) throws OlapException + { + /* + Example: + + + FoodMart + FoodMart + HR + [Store] + [Store] + [Store].[Store Name] + Store Manager + Store Manager + 1 + 130 + 0 + HR Cube - Store Hierarchy - Store + Name Level - Store Manager Property + + */ + String cubeName = stringElement(row, "CUBE_NAME"); + String description = stringElement(row, "DESCRIPTION"); + String uniqueName = stringElement(row, "DESCRIPTION"); + String caption = stringElement(row, "PROPERTY_CAPTION"); + String name = stringElement(row, "PROPERTY_NAME"); + Datatype dataType = + Datatype.forXmlaOrdinal( + integerElement(row, "DATA_TYPE")); + final Integer contentTypeOrdinal = + integerElement(row, "PROPERTY_CONTENT_TYPE"); + Property.ContentType contentType = + contentTypeOrdinal == null + ? null + : Property.ContentType.forXmlaOrdinal(contentTypeOrdinal); + int propertyType = integerElement(row, "PROPERTY_TYPE"); + Set type = + Property.TypeFlag.forMask(propertyType); + list.add( + new XmlaOlap4jProperty( + uniqueName, name, caption, description, dataType, type, + contentType)); + } + } + + /** + * Callback for converting XMLA results into metadata elements. + */ + interface Handler { + /** + * Converts an XML element from an XMLA result set into a metadata + * element and appends it to a list of metadata elements. + * + * @param row XMLA element + * + * @param context Context (schema, cube, dimension, etc.) that the + * request was executed in and that the element will belong to + * + * @param list List of metadata elements to append new metadata element + * + * @throws OlapException on error + */ + void handle( + Element row, + Context context, + List list) throws OlapException; + + /** + * Sorts a list of metadata elements. + * + *

For most element types, the order returned by XMLA is correct, and + * this method will no-op. + * + * @param list List of metadata elements + */ + void sortList(List list); + } + + static abstract class HandlerImpl implements Handler { + public void sortList(List list) { + // do nothing - assume XMLA returned list in correct order + } + + } + + static class Context { + final XmlaOlap4jConnection olap4jConnection; + final XmlaOlap4jDatabaseMetaData olap4jDatabaseMetaData; + final XmlaOlap4jCatalog olap4jCatalog; + final XmlaOlap4jSchema olap4jSchema; + final XmlaOlap4jCube olap4jCube; + final XmlaOlap4jDimension olap4jDimension; + final XmlaOlap4jHierarchy olap4jHierarchy; + final XmlaOlap4jLevel olap4jLevel; + + /** + * Creates a Context. + * + * @param olap4jConnection Connection (must not be null) + * @param olap4jDatabaseMetaData DatabaseMetaData (may be null) + * @param olap4jCatalog Catalog (may be null if DatabaseMetaData is null) + * @param olap4jSchema Schema (may be null if Catalog is null) + * @param olap4jCube Cube (may be null if Schema is null) + * @param olap4jDimension Dimension (may be null if Cube is null) + * @param olap4jHierarchy Hierarchy (may be null if Dimension is null) + * @param olap4jLevel Level (may be null if Hierarchy is null) + */ + Context( + XmlaOlap4jConnection olap4jConnection, + XmlaOlap4jDatabaseMetaData olap4jDatabaseMetaData, + XmlaOlap4jCatalog olap4jCatalog, + XmlaOlap4jSchema olap4jSchema, + XmlaOlap4jCube olap4jCube, + XmlaOlap4jDimension olap4jDimension, + XmlaOlap4jHierarchy olap4jHierarchy, + XmlaOlap4jLevel olap4jLevel) + { + this.olap4jConnection = olap4jConnection; + this.olap4jDatabaseMetaData = olap4jDatabaseMetaData; + this.olap4jCatalog = olap4jCatalog; + this.olap4jSchema = olap4jSchema; + this.olap4jCube = olap4jCube; + this.olap4jDimension = olap4jDimension; + this.olap4jHierarchy = olap4jHierarchy; + this.olap4jLevel = olap4jLevel; + assert (olap4jDatabaseMetaData != null || olap4jCatalog == null) + && (olap4jCatalog != null || olap4jSchema == null) + && (olap4jSchema != null || olap4jCube == null) + && (olap4jCube != null || olap4jDimension == null) + && (olap4jDimension != null || olap4jHierarchy == null) + && (olap4jHierarchy != null || olap4jLevel == null); + } + + /** + * Shorthand way to create a Context at Cube level or finer. + * + * @param olap4jCube Cube (must not be null) + * @param olap4jDimension Dimension (may be null) + * @param olap4jHierarchy Hierarchy (may be null if Dimension is null) + * @param olap4jLevel Level (may be null if Hierarchy is null) + */ + Context( + XmlaOlap4jCube olap4jCube, + XmlaOlap4jDimension olap4jDimension, + XmlaOlap4jHierarchy olap4jHierarchy, + XmlaOlap4jLevel olap4jLevel) + { + this( + olap4jCube.olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData + .olap4jConnection, + olap4jCube.olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData, + olap4jCube.olap4jSchema.olap4jCatalog, + olap4jCube.olap4jSchema, + olap4jCube, + olap4jDimension, + olap4jHierarchy, + olap4jLevel); + } + + /** + * Shorthand way to create a Context at Level level. + * + * @param olap4jLevel Level (must not be null) + */ + Context(XmlaOlap4jLevel olap4jLevel) + { + this( + olap4jLevel.olap4jHierarchy.olap4jDimension.olap4jCube, + olap4jLevel.olap4jHierarchy.olap4jDimension, + olap4jLevel.olap4jHierarchy, + olap4jLevel); + } + + XmlaOlap4jHierarchy getHierarchy(Element row) { + if (olap4jHierarchy != null) { + return olap4jHierarchy; + } + final String hierarchyUniqueName = + stringElement(row, "HIERARCHY_UNIQUE_NAME"); + return getCube(row).hierarchiesByUname.get(hierarchyUniqueName); + } + + XmlaOlap4jCube getCube(Element row) { + if (olap4jCube != null) { + return olap4jCube; + } + throw new UnsupportedOperationException(); // todo: + } + + XmlaOlap4jDimension getDimension(Element row) { + if (olap4jDimension != null) { + return olap4jDimension; + } + final String dimensionUniqueName = + stringElement(row, "DIMENSION_UNIQUE_NAME"); + return getCube(row).dimensionsByUname.get(dimensionUniqueName); + } + + public XmlaOlap4jLevel getLevel(Element row) { + if (olap4jLevel != null) { + return olap4jLevel; + } + final String levelUniqueName = + stringElement(row, "LEVEL_UNIQUE_NAME"); + return getCube(row).levelsByUname.get(levelUniqueName); + } + + public XmlaOlap4jCatalog getCatalog(Element row) throws OlapException { + if (olap4jCatalog != null) { + return olap4jCatalog; + } + final String catalogName = + stringElement(row, "CATALOG_NAME"); + return (XmlaOlap4jCatalog) olap4jConnection.getCatalogs().get( + catalogName); + } + } + + enum MetadataRequest { + DISCOVER_DATASOURCES( + new MetadataColumn("DataSourceName"), + new MetadataColumn("DataSourceDescription"), + new MetadataColumn("URL"), + new MetadataColumn("DataSourceInfo"), + new MetadataColumn("ProviderName"), + new MetadataColumn("ProviderType"), + new MetadataColumn("AuthenticationMode")), + DISCOVER_SCHEMA_ROWSETS( + new MetadataColumn("SchemaName"), + new MetadataColumn("SchemaGuid"), + new MetadataColumn("Restrictions"), + new MetadataColumn("Description")), + DISCOVER_ENUMERATORS( + new MetadataColumn("EnumName"), + new MetadataColumn("EnumDescription"), + new MetadataColumn("EnumType"), + new MetadataColumn("ElementName"), + new MetadataColumn("ElementDescription"), + new MetadataColumn("ElementValue")), + DISCOVER_PROPERTIES( + new MetadataColumn("PropertyName"), + new MetadataColumn("PropertyDescription"), + new MetadataColumn("PropertyType"), + new MetadataColumn("PropertyAccessType"), + new MetadataColumn("IsRequired"), + new MetadataColumn("Value")), + DISCOVER_KEYWORDS( + new MetadataColumn("Keyword")), + DISCOVER_LITERALS( + new MetadataColumn("LiteralName"), + new MetadataColumn("LiteralValue"), + new MetadataColumn("LiteralInvalidChars"), + new MetadataColumn("LiteralInvalidStartingChars"), + new MetadataColumn("LiteralMaxLength")), + DBSCHEMA_CATALOGS( + new MetadataColumn("CATALOG_NAME"), + new MetadataColumn("DESCRIPTION"), + new MetadataColumn("ROLES"), + new MetadataColumn("DATE_MODIFIED")), + DBSCHEMA_COLUMNS( + new MetadataColumn("TABLE_CATALOG"), + new MetadataColumn("TABLE_SCHEMA"), + new MetadataColumn("TABLE_NAME"), + new MetadataColumn("COLUMN_NAME"), + new MetadataColumn("ORDINAL_POSITION"), + new MetadataColumn("COLUMN_HAS_DEFAULT"), + new MetadataColumn("COLUMN_FLAGS"), + new MetadataColumn("IS_NULLABLE"), + new MetadataColumn("DATA_TYPE"), + new MetadataColumn("CHARACTER_MAXIMUM_LENGTH"), + new MetadataColumn("CHARACTER_OCTET_LENGTH"), + new MetadataColumn("NUMERIC_PRECISION"), + new MetadataColumn("NUMERIC_SCALE")), + DBSCHEMA_PROVIDER_TYPES( + new MetadataColumn("TYPE_NAME"), + new MetadataColumn("DATA_TYPE"), + new MetadataColumn("COLUMN_SIZE"), + new MetadataColumn("LITERAL_PREFIX"), + new MetadataColumn("LITERAL_SUFFIX"), + new MetadataColumn("IS_NULLABLE"), + new MetadataColumn("CASE_SENSITIVE"), + new MetadataColumn("SEARCHABLE"), + new MetadataColumn("UNSIGNED_ATTRIBUTE"), + new MetadataColumn("FIXED_PREC_SCALE"), + new MetadataColumn("AUTO_UNIQUE_VALUE"), + new MetadataColumn("IS_LONG"), + new MetadataColumn("BEST_MATCH")), + DBSCHEMA_TABLES( + new MetadataColumn("TABLE_CATALOG"), + new MetadataColumn("TABLE_SCHEMA"), + new MetadataColumn("TABLE_NAME"), + new MetadataColumn("TABLE_TYPE"), + new MetadataColumn("TABLE_GUID"), + new MetadataColumn("DESCRIPTION"), + new MetadataColumn("TABLE_PROPID"), + new MetadataColumn("DATE_CREATED"), + new MetadataColumn("DATE_MODIFIED")), + DBSCHEMA_TABLES_INFO( + new MetadataColumn("TABLE_CATALOG"), + new MetadataColumn("TABLE_SCHEMA"), + new MetadataColumn("TABLE_NAME"), + new MetadataColumn("TABLE_TYPE"), + new MetadataColumn("TABLE_GUID"), + new MetadataColumn("BOOKMARKS"), + new MetadataColumn("BOOKMARK_TYPE"), + new MetadataColumn("BOOKMARK_DATATYPE"), + new MetadataColumn("BOOKMARK_MAXIMUM_LENGTH"), + new MetadataColumn("BOOKMARK_INFORMATION"), + new MetadataColumn("TABLE_VERSION"), + new MetadataColumn("CARDINALITY"), + new MetadataColumn("DESCRIPTION"), + new MetadataColumn("TABLE_PROPID")), + DBSCHEMA_SCHEMATA( + new MetadataColumn("CATALOG_NAME"), + new MetadataColumn("SCHEMA_NAME"), + new MetadataColumn("SCHEMA_OWNER")), + MDSCHEMA_ACTIONS( + new MetadataColumn("SCHEMA_NAME"), + new MetadataColumn("CUBE_NAME"), + new MetadataColumn("ACTION_NAME"), + new MetadataColumn("COORDINATE"), + new MetadataColumn("COORDINATE_TYPE")), + MDSCHEMA_CUBES( + new MetadataColumn("CATALOG_NAME"), + new MetadataColumn("SCHEMA_NAME"), + new MetadataColumn("CUBE_NAME"), + new MetadataColumn("CUBE_TYPE"), + new MetadataColumn("CUBE_GUID"), + new MetadataColumn("CREATED_ON"), + new MetadataColumn("LAST_SCHEMA_UPDATE"), + new MetadataColumn("SCHEMA_UPDATED_BY"), + new MetadataColumn("LAST_DATA_UPDATE"), + new MetadataColumn("DATA_UPDATED_BY"), + new MetadataColumn("IS_DRILLTHROUGH_ENABLED"), + new MetadataColumn("IS_WRITE_ENABLED"), + new MetadataColumn("IS_LINKABLE"), + new MetadataColumn("IS_SQL_ENABLED"), + new MetadataColumn("DESCRIPTION")), + MDSCHEMA_DIMENSIONS( + new MetadataColumn("CATALOG_NAME"), + new MetadataColumn("SCHEMA_NAME"), + new MetadataColumn("CUBE_NAME"), + new MetadataColumn("DIMENSION_NAME"), + new MetadataColumn("DIMENSION_UNIQUE_NAME"), + new MetadataColumn("DIMENSION_GUID"), + new MetadataColumn("DIMENSION_CAPTION"), + new MetadataColumn("DIMENSION_ORDINAL"), + new MetadataColumn("DIMENSION_TYPE"), + new MetadataColumn("DIMENSION_CARDINALITY"), + new MetadataColumn("DEFAULT_HIERARCHY"), + new MetadataColumn("DESCRIPTION"), + new MetadataColumn("IS_VIRTUAL"), + new MetadataColumn("IS_READWRITE"), + new MetadataColumn("DIMENSION_UNIQUE_SETTINGS"), + new MetadataColumn("DIMENSION_MASTER_UNIQUE_NAME"), + new MetadataColumn("DIMENSION_IS_VISIBLE")), + MDSCHEMA_FUNCTIONS( + new MetadataColumn("FUNCTION_NAME"), + new MetadataColumn("DESCRIPTION"), + new MetadataColumn("PARAMETER_LIST"), + new MetadataColumn("RETURN_TYPE"), + new MetadataColumn("ORIGIN"), + new MetadataColumn("INTERFACE_NAME"), + new MetadataColumn("LIBRARY_NAME"), + new MetadataColumn("CAPTION")), + MDSCHEMA_HIERARCHIES( + new MetadataColumn("CATALOG_NAME"), + new MetadataColumn("SCHEMA_NAME"), + new MetadataColumn("CUBE_NAME"), + new MetadataColumn("DIMENSION_UNIQUE_NAME"), + new MetadataColumn("HIERARCHY_NAME"), + new MetadataColumn("HIERARCHY_UNIQUE_NAME"), + new MetadataColumn("HIERARCHY_GUID"), + new MetadataColumn("HIERARCHY_CAPTION"), + new MetadataColumn("DIMENSION_TYPE"), + new MetadataColumn("HIERARCHY_CARDINALITY"), + new MetadataColumn("DEFAULT_MEMBER"), + new MetadataColumn("ALL_MEMBER"), + new MetadataColumn("DESCRIPTION"), + new MetadataColumn("STRUCTURE"), + new MetadataColumn("IS_VIRTUAL"), + new MetadataColumn("IS_READWRITE"), + new MetadataColumn("DIMENSION_UNIQUE_SETTINGS"), + new MetadataColumn("DIMENSION_IS_VISIBLE"), + new MetadataColumn("HIERARCHY_ORDINAL"), + new MetadataColumn("DIMENSION_IS_SHARED"), + new MetadataColumn("PARENT_CHILD")), + MDSCHEMA_LEVELS( + new MetadataColumn("CATALOG_NAME"), + new MetadataColumn("SCHEMA_NAME"), + new MetadataColumn("CUBE_NAME"), + new MetadataColumn("DIMENSION_UNIQUE_NAME"), + new MetadataColumn("HIERARCHY_UNIQUE_NAME"), + new MetadataColumn("LEVEL_NAME"), + new MetadataColumn("LEVEL_UNIQUE_NAME"), + new MetadataColumn("LEVEL_GUID"), + new MetadataColumn("LEVEL_CAPTION"), + new MetadataColumn("LEVEL_NUMBER"), + new MetadataColumn("LEVEL_CARDINALITY"), + new MetadataColumn("LEVEL_TYPE"), + new MetadataColumn("CUSTOM_ROLLUP_SETTINGS"), + new MetadataColumn("LEVEL_UNIQUE_SETTINGS"), + new MetadataColumn("LEVEL_IS_VISIBLE"), + new MetadataColumn("DESCRIPTION")), + MDSCHEMA_MEASURES( + new MetadataColumn("CATALOG_NAME"), + new MetadataColumn("SCHEMA_NAME"), + new MetadataColumn("CUBE_NAME"), + new MetadataColumn("MEASURE_NAME"), + new MetadataColumn("MEASURE_UNIQUE_NAME"), + new MetadataColumn("MEASURE_CAPTION"), + new MetadataColumn("MEASURE_GUID"), + new MetadataColumn("MEASURE_AGGREGATOR"), + new MetadataColumn("DATA_TYPE"), + new MetadataColumn("MEASURE_IS_VISIBLE"), + new MetadataColumn("LEVELS_LIST"), + new MetadataColumn("DESCRIPTION")), + MDSCHEMA_MEMBERS( + new MetadataColumn("CATALOG_NAME"), + new MetadataColumn("SCHEMA_NAME"), + new MetadataColumn("CUBE_NAME"), + new MetadataColumn("DIMENSION_UNIQUE_NAME"), + new MetadataColumn("HIERARCHY_UNIQUE_NAME"), + new MetadataColumn("LEVEL_UNIQUE_NAME"), + new MetadataColumn("LEVEL_NUMBER"), + new MetadataColumn("MEMBER_ORDINAL"), + new MetadataColumn("MEMBER_NAME"), + new MetadataColumn("MEMBER_UNIQUE_NAME"), + new MetadataColumn("MEMBER_TYPE"), + new MetadataColumn("MEMBER_GUID"), + new MetadataColumn("MEMBER_CAPTION"), + new MetadataColumn("CHILDREN_CARDINALITY"), + new MetadataColumn("PARENT_LEVEL"), + new MetadataColumn("PARENT_UNIQUE_NAME"), + new MetadataColumn("PARENT_COUNT"), + new MetadataColumn("TREE_OP"), + new MetadataColumn("DEPTH")), + MDSCHEMA_PROPERTIES( + new MetadataColumn("CATALOG_NAME"), + new MetadataColumn("SCHEMA_NAME"), + new MetadataColumn("CUBE_NAME"), + new MetadataColumn("DIMENSION_UNIQUE_NAME"), + new MetadataColumn("HIERARCHY_UNIQUE_NAME"), + new MetadataColumn("LEVEL_UNIQUE_NAME"), + new MetadataColumn("MEMBER_UNIQUE_NAME"), + new MetadataColumn("PROPERTY_NAME"), + new MetadataColumn("PROPERTY_CAPTION"), + new MetadataColumn("PROPERTY_TYPE"), + new MetadataColumn("DATA_TYPE"), + new MetadataColumn("PROPERTY_CONTENT_TYPE"), + new MetadataColumn("DESCRIPTION")), + MDSCHEMA_SETS( + new MetadataColumn("CATALOG_NAME"), + new MetadataColumn("SCHEMA_NAME"), + new MetadataColumn("CUBE_NAME"), + new MetadataColumn("SET_NAME"), + new MetadataColumn("SCOPE")); + + final List columns; + + MetadataRequest(MetadataColumn... columns) { + if (name().equals("DBSCHEMA_CATALOGS")) { + // DatabaseMetaData.getCatalogs() is defined by JDBC not XMLA, + // so has just one column. Ignore the 4 columns from XMLA. + columns = new MetadataColumn[] { + new MetadataColumn("CATALOG_NAME", "TABLE_CAT") + }; + } else if (name().equals("DBSCHEMA_SCHEMATA")) { + // DatabaseMetaData.getCatalogs() is defined by JDBC not XMLA, + // so has just one column. Ignore the 4 columns from XMLA. + columns = new MetadataColumn[] { + new MetadataColumn("SCHEMA_NAME", "TABLE_SCHEM"), + new MetadataColumn("CATALOG_NAME", "TABLE_CAT") + }; + } + this.columns = + Collections.unmodifiableList( + Arrays.asList(columns)); + } + + /** + * Returns whether this request requires a + * {@code <DatasourceName>} element. + * + * @return whether this request requires a DatasourceName element + */ + public boolean requiresDatasourceName() { + return this != DISCOVER_DATASOURCES; + } + } + + private static final Pattern LOWERCASE_PATTERN = Pattern.compile(".*[a-z].*"); + + static class MetadataColumn { + final String name; + final String xmlaName; + + MetadataColumn(String xmlaName, String name) { + this.xmlaName = xmlaName; + this.name = name; + } + + MetadataColumn(String xmlaName) { + this.xmlaName = xmlaName; + String name = xmlaName; + if (LOWERCASE_PATTERN.matcher(name).matches()) { + name = Olap4jUtil.camelToUpper(name); + } + // VALUE is a SQL reserved word + if (name.equals("VALUE")) { + name = "PROPERTY_VALUE"; + } + this.name = name; + } + } + + private static class XmlaOlap4jMdxValidator implements MdxValidator { + private final OlapConnection connection; + + XmlaOlap4jMdxValidator(OlapConnection connection) { + this.connection = connection; + } + + public SelectNode validateSelect(SelectNode selectNode) throws OlapException { + StringWriter sw = new StringWriter(); + selectNode.unparse(new ParseTreeWriter(new PrintWriter(sw))); + String mdx = sw.toString(); + final XmlaOlap4jConnection olap4jConnection = + (XmlaOlap4jConnection) connection; + return selectNode; + } + } +} + +// End XmlaOlap4jConnection.java diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jCube.java b/src/org/olap4j/driver/xmla/XmlaOlap4jCube.java index d20e23b..43d1e08 100644 --- a/src/org/olap4j/driver/xmla/XmlaOlap4jCube.java +++ b/src/org/olap4j/driver/xmla/XmlaOlap4jCube.java @@ -52,7 +52,7 @@ class XmlaOlap4jCube implements Cube, Named * @param olap4jSchema Schema * @param name Name * @param description Description - * @param connection + * @param connection */ XmlaOlap4jCube( XmlaOlap4jSchema olap4jSchema, @@ -442,7 +442,7 @@ public void lookupMembersByUniqueName( memberMap.putAll(this.genericMembersLookup(memberUniqueNames)); } } - + /** * This is an optimized method for Mondrian servers members lookup. * @param memberUniqueNames A list of the members to lookup @@ -455,7 +455,7 @@ private Map mondrianMembersLookup( final XmlaOlap4jConnection.Context context = new XmlaOlap4jConnection.Context( XmlaOlap4jCube.this, null, null, null); - final List memberList = + final List memberList = new ArrayList(); olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData.olap4jConnection .populateList( @@ -478,7 +478,7 @@ private Map mondrianMembersLookup( } return memberMap; } - + /** * This is an generic method for members lookup. * @param memberUniqueNames A list of the members to lookup @@ -494,7 +494,7 @@ private Map genericMembersLookup( for (String currentMemberName : memberUniqueNames) { // Only lookup if it is not in the map yet if (!memberMap.containsKey(currentMemberName)) { - XmlaOlap4jMember member = + XmlaOlap4jMember member = this.lookupMemberByUniqueName(currentMemberName); // Null members might mean calculated members if (member != null) { diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jDatabaseMetaData.java b/src/org/olap4j/driver/xmla/XmlaOlap4jDatabaseMetaData.java index 488b9c3..4cbb414 100644 --- a/src/org/olap4j/driver/xmla/XmlaOlap4jDatabaseMetaData.java +++ b/src/org/olap4j/driver/xmla/XmlaOlap4jDatabaseMetaData.java @@ -1,1145 +1,1145 @@ -/* -// This software is subject to the terms of the Common Public License -// Agreement, available at the following URL: -// http://www.opensource.org/licenses/cpl.html. -// Copyright (C) 2007-2007 Julian Hyde -// All Rights Reserved. -// You must accept the terms of that agreement to use this software. -*/ -package org.olap4j.driver.xmla; - -import org.olap4j.*; -import org.olap4j.impl.ArrayMap; -import org.olap4j.impl.Olap4jUtil; -import org.olap4j.metadata.*; -import org.w3c.dom.Element; - -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Implementation of {@link org.olap4j.OlapDatabaseMetaData} - * for XML/A providers. - * - *

This class has sub-classes which implement JDBC 3.0 and JDBC 4.0 APIs; - * it is instantiated using {@link Factory#newDatabaseMetaData}.

- * - * @author jhyde - * @version $Id$ - * @since May 23, 2007 - */ -abstract class XmlaOlap4jDatabaseMetaData implements OlapDatabaseMetaData { - final XmlaOlap4jConnection olap4jConnection; - - private final NamedList catalogs; - - /** - * Creates an XmlaOlap4jDatabaseMetaData. - * - *

Note that this constructor should make zero non-trivial calls, which - * could cause deadlocks due to java.sql.DriverManager synchronization - * issues. - * - * @param olap4jConnection Connection - */ - XmlaOlap4jDatabaseMetaData( - XmlaOlap4jConnection olap4jConnection) - { - this.olap4jConnection = olap4jConnection; - this.catalogs = - new DeferredNamedListImpl( - XmlaOlap4jConnection.MetadataRequest.DBSCHEMA_CATALOGS, - new XmlaOlap4jConnection.Context( - olap4jConnection, this, null, null, null, null, null, - null), - new XmlaOlap4jConnection.CatalogHandler()); - } - - /** - * Returns a list of catalogs in this database. - * - *

Package-local because not part of olap4j API. - * - * @return List of catalog objects - */ - NamedList getCatalogObjects() { - return Olap4jUtil.cast(catalogs); - } - - /** - * Executes a metadata query and returns the result as a JDBC - * {@link ResultSet}. - * - * @param metadataRequest Name of the metadata request. Corresponds to the XMLA - * method name, e.g. "MDSCHEMA_CUBES" - * - * @param patternValues Array of alternating parameter name and value - * pairs. If the parameter value is null, it is ignored. - * - * @return Result set of metadata - * - * @throws org.olap4j.OlapException on error - */ - private ResultSet getMetadata( - XmlaOlap4jConnection.MetadataRequest metadataRequest, - Object... patternValues) throws OlapException - { - assert patternValues.length % 2 == 0; - final XmlaOlap4jConnection.Context context = - new XmlaOlap4jConnection.Context( - olap4jConnection, null, null, null, null, null, null, null); - List patternValueList = new ArrayList(); - Map predicateList = new ArrayMap(); - for (int i = 0; i < patternValues.length; i += 2) { - String name = (String) patternValues[i]; - Object value = patternValues[i + 1]; - if (value == null) { - // ignore - } else if (value instanceof Wildcard) { - final Wildcard wildcard = (Wildcard) value; - if (wildcard.pattern.indexOf('%') < 0 - && wildcard.pattern.indexOf('_') < 0) { - patternValueList.add(name); - patternValueList.add(wildcard.pattern); - } else { - String regexp = - Olap4jUtil.wildcardToRegexp( - Collections.singletonList(wildcard.pattern)); - final Matcher matcher = Pattern.compile(regexp).matcher(""); - predicateList.put(name, matcher); - } - } else { - patternValueList.add(name); - patternValueList.add((String) value); - } - } - - String request = - olap4jConnection.generateRequest( - context, - metadataRequest, - patternValueList.toArray( - new String[patternValueList.size()])); - - final Element root = olap4jConnection.xxx(request); - List> rowList = new ArrayList>(); - rowLoop: - for (Element row : XmlaOlap4jUtil.childElements(root)) { - final ArrayList valueList = new ArrayList(); - for (Map.Entry entry : predicateList.entrySet()) { - final String column = entry.getKey(); - final String value = - XmlaOlap4jUtil.stringElement(row, column); - final Matcher matcher = entry.getValue(); - if (!matcher.reset(value).matches()) { - continue rowLoop; - } - } - for (XmlaOlap4jConnection.MetadataColumn column - : metadataRequest.columns) - { - final String value = - XmlaOlap4jUtil.stringElement(row, column.xmlaName); - valueList.add(value); - } - rowList.add(valueList); - } - List headerList = new ArrayList(); - for (XmlaOlap4jConnection.MetadataColumn column - : metadataRequest.columns) - { - headerList.add(column.name); - } - return olap4jConnection.factory.newFixedResultSet( - olap4jConnection, headerList, rowList); - } - - /** - * Converts a string to a wildcard object. - * - * @param pattern String pattern - * @return wildcard object, or null if pattern was null - */ - private Wildcard wildcard(String pattern) { - return pattern == null - ? null - : new Wildcard(pattern); - } - - // implement DatabaseMetaData - - public boolean allProceduresAreCallable() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean allTablesAreSelectable() throws SQLException { - throw new UnsupportedOperationException(); - } - - public String getURL() throws SQLException { - return olap4jConnection.getURL(); - } - - public String getUserName() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean isReadOnly() throws SQLException { - // olap4j does not currently support writeback - return true; - } - - public boolean nullsAreSortedHigh() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean nullsAreSortedLow() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean nullsAreSortedAtStart() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean nullsAreSortedAtEnd() throws SQLException { - throw new UnsupportedOperationException(); - } - - public String getDatabaseProductName() throws SQLException { - throw Olap4jUtil.needToImplement(this); - } - - public String getDatabaseProductVersion() throws SQLException { - throw Olap4jUtil.needToImplement(this); - } - - public String getDriverName() throws SQLException { - return XmlaOlap4jDriver.NAME; - } - - public String getDriverVersion() throws SQLException { - return XmlaOlap4jDriver.VERSION; - } - - public int getDriverMajorVersion() { - return XmlaOlap4jDriver.MAJOR_VERSION; - } - - public int getDriverMinorVersion() { - return XmlaOlap4jDriver.MINOR_VERSION; - } - - public boolean usesLocalFiles() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean usesLocalFilePerTable() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsMixedCaseIdentifiers() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean storesUpperCaseIdentifiers() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean storesLowerCaseIdentifiers() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean storesMixedCaseIdentifiers() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean storesUpperCaseQuotedIdentifiers() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean storesLowerCaseQuotedIdentifiers() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean storesMixedCaseQuotedIdentifiers() throws SQLException { - throw new UnsupportedOperationException(); - } - - public String getIdentifierQuoteString() throws SQLException { - throw new UnsupportedOperationException(); - } - - public String getSQLKeywords() throws SQLException { - throw new UnsupportedOperationException(); - } - - public String getNumericFunctions() throws SQLException { - throw new UnsupportedOperationException(); - } - - public String getStringFunctions() throws SQLException { - throw new UnsupportedOperationException(); - } - - public String getSystemFunctions() throws SQLException { - throw new UnsupportedOperationException(); - } - - public String getTimeDateFunctions() throws SQLException { - throw new UnsupportedOperationException(); - } - - public String getSearchStringEscape() throws SQLException { - throw new UnsupportedOperationException(); - } - - public String getExtraNameCharacters() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsAlterTableWithAddColumn() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsAlterTableWithDropColumn() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsColumnAliasing() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean nullPlusNonNullIsNull() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsConvert() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsConvert( - int fromType, int toType) throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsTableCorrelationNames() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsDifferentTableCorrelationNames() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsExpressionsInOrderBy() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsOrderByUnrelated() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsGroupBy() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsGroupByUnrelated() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsGroupByBeyondSelect() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsLikeEscapeClause() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsMultipleResultSets() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsMultipleTransactions() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsNonNullableColumns() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsMinimumSQLGrammar() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsCoreSQLGrammar() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsExtendedSQLGrammar() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsANSI92EntryLevelSQL() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsANSI92IntermediateSQL() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsANSI92FullSQL() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsIntegrityEnhancementFacility() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsOuterJoins() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsFullOuterJoins() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsLimitedOuterJoins() throws SQLException { - throw new UnsupportedOperationException(); - } - - public String getSchemaTerm() throws SQLException { - throw new UnsupportedOperationException(); - } - - public String getProcedureTerm() throws SQLException { - throw new UnsupportedOperationException(); - } - - public String getCatalogTerm() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean isCatalogAtStart() throws SQLException { - throw new UnsupportedOperationException(); - } - - public String getCatalogSeparator() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsSchemasInDataManipulation() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsSchemasInProcedureCalls() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsSchemasInTableDefinitions() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsSchemasInIndexDefinitions() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsCatalogsInDataManipulation() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsCatalogsInProcedureCalls() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsCatalogsInTableDefinitions() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsCatalogsInIndexDefinitions() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsPositionedDelete() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsPositionedUpdate() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsSelectForUpdate() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsStoredProcedures() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsSubqueriesInComparisons() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsSubqueriesInExists() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsSubqueriesInIns() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsSubqueriesInQuantifieds() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsCorrelatedSubqueries() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsUnion() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsUnionAll() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsOpenCursorsAcrossCommit() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsOpenCursorsAcrossRollback() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsOpenStatementsAcrossCommit() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsOpenStatementsAcrossRollback() throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getMaxBinaryLiteralLength() throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getMaxCharLiteralLength() throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getMaxColumnNameLength() throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getMaxColumnsInGroupBy() throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getMaxColumnsInIndex() throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getMaxColumnsInOrderBy() throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getMaxColumnsInSelect() throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getMaxColumnsInTable() throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getMaxConnections() throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getMaxCursorNameLength() throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getMaxIndexLength() throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getMaxSchemaNameLength() throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getMaxProcedureNameLength() throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getMaxCatalogNameLength() throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getMaxRowSize() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean doesMaxRowSizeIncludeBlobs() throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getMaxStatementLength() throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getMaxStatements() throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getMaxTableNameLength() throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getMaxTablesInSelect() throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getMaxUserNameLength() throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getDefaultTransactionIsolation() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsTransactions() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsTransactionIsolationLevel(int level) throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsDataDefinitionAndDataManipulationTransactions() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsDataManipulationTransactionsOnly() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean dataDefinitionCausesTransactionCommit() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean dataDefinitionIgnoredInTransactions() throws SQLException { - throw new UnsupportedOperationException(); - } - - public ResultSet getProcedures( - String catalog, - String schemaPattern, - String procedureNamePattern) throws SQLException { - throw new UnsupportedOperationException(); - } - - public ResultSet getProcedureColumns( - String catalog, - String schemaPattern, - String procedureNamePattern, - String columnNamePattern) throws SQLException { - throw new UnsupportedOperationException(); - } - - public ResultSet getTables( - String catalog, - String schemaPattern, - String tableNamePattern, - String types[]) throws SQLException { - throw new UnsupportedOperationException(); - } - - public ResultSet getSchemas() throws SQLException { - return getMetadata( - XmlaOlap4jConnection.MetadataRequest.DBSCHEMA_SCHEMATA); - } - - public ResultSet getCatalogs() throws SQLException { - return getMetadata( - XmlaOlap4jConnection.MetadataRequest.DBSCHEMA_CATALOGS); - } - - public ResultSet getTableTypes() throws SQLException { - throw new UnsupportedOperationException(); - } - - public ResultSet getColumns( - String catalog, - String schemaPattern, - String tableNamePattern, - String columnNamePattern) throws SQLException { - throw new UnsupportedOperationException(); - } - - public ResultSet getColumnPrivileges( - String catalog, - String schema, - String table, - String columnNamePattern) throws SQLException { - throw new UnsupportedOperationException(); - } - - public ResultSet getTablePrivileges( - String catalog, - String schemaPattern, - String tableNamePattern) throws SQLException { - throw new UnsupportedOperationException(); - } - - public ResultSet getBestRowIdentifier( - String catalog, - String schema, - String table, - int scope, - boolean nullable) throws SQLException { - throw new UnsupportedOperationException(); - } - - public ResultSet getVersionColumns( - String catalog, String schema, String table) throws SQLException { - throw new UnsupportedOperationException(); - } - - public ResultSet getPrimaryKeys( - String catalog, String schema, String table) throws SQLException { - throw new UnsupportedOperationException(); - } - - public ResultSet getImportedKeys( - String catalog, String schema, String table) throws SQLException { - throw new UnsupportedOperationException(); - } - - public ResultSet getExportedKeys( - String catalog, String schema, String table) throws SQLException { - throw new UnsupportedOperationException(); - } - - public ResultSet getCrossReference( - String parentCatalog, - String parentSchema, - String parentTable, - String foreignCatalog, - String foreignSchema, - String foreignTable) throws SQLException { - throw new UnsupportedOperationException(); - } - - public ResultSet getTypeInfo() throws SQLException { - throw new UnsupportedOperationException(); - } - - public ResultSet getIndexInfo( - String catalog, - String schema, - String table, - boolean unique, - boolean approximate) throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsResultSetType(int type) throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsResultSetConcurrency( - int type, int concurrency) throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean ownUpdatesAreVisible(int type) throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean ownDeletesAreVisible(int type) throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean ownInsertsAreVisible(int type) throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean othersUpdatesAreVisible(int type) throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean othersDeletesAreVisible(int type) throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean othersInsertsAreVisible(int type) throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean updatesAreDetected(int type) throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean deletesAreDetected(int type) throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean insertsAreDetected(int type) throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsBatchUpdates() throws SQLException { - throw new UnsupportedOperationException(); - } - - public ResultSet getUDTs( - String catalog, - String schemaPattern, - String typeNamePattern, - int[] types) throws SQLException { - throw new UnsupportedOperationException(); - } - - public OlapConnection getConnection() { - return olap4jConnection; - } - - public boolean supportsSavepoints() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsNamedParameters() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsMultipleOpenResults() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsGetGeneratedKeys() throws SQLException { - throw new UnsupportedOperationException(); - } - - public ResultSet getSuperTypes( - String catalog, - String schemaPattern, - String typeNamePattern) throws SQLException { - throw new UnsupportedOperationException(); - } - - public ResultSet getSuperTables( - String catalog, - String schemaPattern, - String tableNamePattern) throws SQLException { - throw new UnsupportedOperationException(); - } - - public ResultSet getAttributes( - String catalog, - String schemaPattern, - String typeNamePattern, - String attributeNamePattern) throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsResultSetHoldability(int holdability) throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getResultSetHoldability() throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getDatabaseMajorVersion() throws SQLException { - throw Olap4jUtil.needToImplement(this); - } - - public int getDatabaseMinorVersion() throws SQLException { - throw Olap4jUtil.needToImplement(this); - } - - public int getJDBCMajorVersion() throws SQLException { - // this driver supports jdbc 3.0 and jdbc 4.0 - // FIXME: should return 3 if the current connection is jdbc 3.0 - return 4; - } - - public int getJDBCMinorVersion() throws SQLException { - // this driver supports jdbc 3.0 and jdbc 4.0 - return 0; - } - - public int getSQLStateType() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean locatorsUpdateCopy() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean supportsStatementPooling() throws SQLException { - throw new UnsupportedOperationException(); - } - - // implement java.sql.Wrapper - - // straightforward implementation of unwrap and isWrapperFor, since this - // class already implements the interface they most likely require: - // DatabaseMetaData and OlapDatabaseMetaData - - public T unwrap(Class iface) throws SQLException { - if (iface.isInstance(this)) { - return iface.cast(this); - } - throw olap4jConnection.helper.createException( - "does not implement '" + iface + "'"); - } - - public boolean isWrapperFor(Class iface) throws SQLException { - return iface.isInstance(this); - } - - // implement OlapDatabaseMetaData - - public ResultSet getActions( - String catalog, - String schemaPattern, - String cubeNamePattern, - String actionNamePattern) throws OlapException - { - return getMetadata( - XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_ACTIONS, - "SCHEMA_NAME", wildcard(schemaPattern), - "CUBE_NAME", wildcard(cubeNamePattern), - "ACTION_NAME", wildcard(actionNamePattern)); - } - - public ResultSet getDatasources() throws OlapException { - return getMetadata( - XmlaOlap4jConnection.MetadataRequest.DISCOVER_DATASOURCES); - } - - public ResultSet getLiterals() throws OlapException { - return getMetadata( - XmlaOlap4jConnection.MetadataRequest.DISCOVER_LITERALS); - } - - public ResultSet getDatabaseProperties( - String dataSourceName, - String propertyNamePattern) throws OlapException - { - return getMetadata( - XmlaOlap4jConnection.MetadataRequest.DISCOVER_PROPERTIES); - } - - public ResultSet getProperties( - String catalog, - String schemaPattern, - String cubeNamePattern, - String dimensionUniqueName, - String hierarchyUniqueName, - String levelUniqueName, - String memberUniqueName, - String propertyNamePattern) throws OlapException - { - return getMetadata( - XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_PROPERTIES, - "CATALOG_NAME", catalog, - "SCHEMA_NAME", wildcard(schemaPattern), - "CUBE_NAME", wildcard(cubeNamePattern), - "DIMENSION_UNIQUE_NAME", dimensionUniqueName, - "HIERARCHY_UNIQUE_NAME", hierarchyUniqueName, - "LEVEL_UNIQUE_NAME", levelUniqueName, - "MEMBER_UNIQUE_NAME", memberUniqueName, - "PROPERTY_NAME", wildcard(propertyNamePattern)); - } - - public String getMdxKeywords() throws OlapException { - final XmlaOlap4jConnection.MetadataRequest metadataRequest = - XmlaOlap4jConnection.MetadataRequest.DISCOVER_KEYWORDS; - final XmlaOlap4jConnection.Context context = - new XmlaOlap4jConnection.Context( - olap4jConnection, null, null, null, null, null, null, null); - String request = - olap4jConnection.generateRequest( - context, metadataRequest, new Object[0]); - final Element root = olap4jConnection.xxx(request); - StringBuilder buf = new StringBuilder(); - for (Element row : XmlaOlap4jUtil.childElements(root)) { - if (buf.length() > 0) { - buf.append(','); - } - final String keyword = - XmlaOlap4jUtil.stringElement(row, "Keyword"); - buf.append(keyword); - } - return buf.toString(); - } - - public ResultSet getCubes( - String catalog, - String schemaPattern, - String cubeNamePattern) - throws OlapException - { - return getMetadata( - XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_CUBES, - "CATALOG_NAME", catalog, - "SCHEMA_NAME", wildcard(schemaPattern), - "CUBE_NAME", wildcard(cubeNamePattern)); - } - - public ResultSet getDimensions( - String catalog, - String schemaPattern, - String cubeNamePattern, - String dimensionNamePattern) - throws OlapException - { - return getMetadata( - XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_DIMENSIONS, - "SCHEMA_NAME", wildcard(schemaPattern), - "CUBE_NAME", wildcard(cubeNamePattern), - "DIMSENSION_NAME", wildcard(dimensionNamePattern)); - } - - public ResultSet getOlapFunctions( - String functionNamePattern) throws OlapException - { - return getMetadata( - XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_FUNCTIONS, - "FUNCTION_NAME", wildcard(functionNamePattern)); - } - - public ResultSet getHierarchies( - String catalog, - String schemaPattern, - String cubeNamePattern, - String dimensionNamePattern, - String hierarchyNamePattern) - throws OlapException - { - return getMetadata( - XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_HIERARCHIES, - "CATALOG_NAME", catalog, - "SCHEMA_NAME", wildcard(schemaPattern), - "CUBE_NAME", wildcard(cubeNamePattern), - "DIMENSION_NAME", wildcard(dimensionNamePattern), - "HIERARCHY_NAME", wildcard(hierarchyNamePattern)); - } - - public ResultSet getMeasures( - String catalog, - String schemaPattern, - String cubeNamePattern, - String measureNamePattern, - String measureUniqueName) throws OlapException - { - return getMetadata( - XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_MEASURES, - "CATALOG_NAME", catalog, - "SCHEMA_NAME", wildcard(schemaPattern), - "CUBE_NAME", wildcard(cubeNamePattern), - "MEASURE_NAME", wildcard(measureNamePattern), - "MEASURE_UNIQUE_NAME", measureUniqueName); - } - - public ResultSet getMembers( - String catalog, - String schemaPattern, - String cubeNamePattern, - String dimensionUniqueName, - String hierarchyUniqueName, - String levelUniqueName, - String memberUniqueName, - Set treeOps) throws OlapException - { - String treeOpString; - if (treeOps != null) { - int op = 0; - for (Member.TreeOp treeOp : treeOps) { - op |= treeOp.xmlaOrdinal(); - } - treeOpString = String.valueOf(op); - } else { - treeOpString = null; - } - return getMetadata( - XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_MEMBERS, - "CATALOG_NAME", catalog, - "SCHEMA_NAME", wildcard(schemaPattern), - "CUBE_NAME", wildcard(cubeNamePattern), - "DIMENSION_UNIQUE_NAME", dimensionUniqueName, - "HIERARCHY_UNIQUE_NAME", hierarchyUniqueName, - "LEVEL_UNIQUE_NAME", levelUniqueName, - "MEMBER_UNIQUE_NAME", memberUniqueName, - "TREE_OP", treeOpString); - } - - public ResultSet getLevels( - String catalog, - String schemaPattern, - String cubeNamePattern, - String dimensionUniqueName, - String hierarchyUniqueName, - String levelNamePattern) throws OlapException - { - return getMetadata( - XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_LEVELS, - "CATALOG_NAME", catalog, - "SCHEMA_NAME", wildcard(schemaPattern), - "CUBE_NAME", wildcard(cubeNamePattern), - "DIMENSION_UNIQUE_NAME", dimensionUniqueName, - "HIERARCHY_UNIQUE_NAME", hierarchyUniqueName, - "LEVEL_NAME", wildcard(levelNamePattern)); - } - - public ResultSet getSets( - String catalog, - String schemaPattern, - String cubeNamePattern, - String setNamePattern) throws OlapException - { - return getMetadata( - XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_SETS, - "CATALOG_NAME", catalog, - "SCHEMA_NAME", wildcard(schemaPattern), - "CUBE_NAME", wildcard(cubeNamePattern), - "SET_NAME", wildcard(setNamePattern)); - } - - - /** - * Wrapper which indicates that a restriction is to be treated as a - * SQL-style wildcard match. - */ - static class Wildcard { - final String pattern; - - /** - * Creates a Wildcard. - * - * @param pattern Pattern - */ - Wildcard(String pattern) { - assert pattern != null; - this.pattern = pattern; - } - } -} - -// End XmlaOlap4jDatabaseMetaData.java +/* +// This software is subject to the terms of the Common Public License +// Agreement, available at the following URL: +// http://www.opensource.org/licenses/cpl.html. +// Copyright (C) 2007-2007 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j.driver.xmla; + +import org.olap4j.*; +import org.olap4j.impl.ArrayMap; +import org.olap4j.impl.Olap4jUtil; +import org.olap4j.metadata.*; +import org.w3c.dom.Element; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Implementation of {@link org.olap4j.OlapDatabaseMetaData} + * for XML/A providers. + * + *

This class has sub-classes which implement JDBC 3.0 and JDBC 4.0 APIs; + * it is instantiated using {@link Factory#newDatabaseMetaData}.

+ * + * @author jhyde + * @version $Id$ + * @since May 23, 2007 + */ +abstract class XmlaOlap4jDatabaseMetaData implements OlapDatabaseMetaData { + final XmlaOlap4jConnection olap4jConnection; + + private final NamedList catalogs; + + /** + * Creates an XmlaOlap4jDatabaseMetaData. + * + *

Note that this constructor should make zero non-trivial calls, which + * could cause deadlocks due to java.sql.DriverManager synchronization + * issues. + * + * @param olap4jConnection Connection + */ + XmlaOlap4jDatabaseMetaData( + XmlaOlap4jConnection olap4jConnection) + { + this.olap4jConnection = olap4jConnection; + this.catalogs = + new DeferredNamedListImpl( + XmlaOlap4jConnection.MetadataRequest.DBSCHEMA_CATALOGS, + new XmlaOlap4jConnection.Context( + olap4jConnection, this, null, null, null, null, null, + null), + new XmlaOlap4jConnection.CatalogHandler()); + } + + /** + * Returns a list of catalogs in this database. + * + *

Package-local because not part of olap4j API. + * + * @return List of catalog objects + */ + NamedList getCatalogObjects() { + return Olap4jUtil.cast(catalogs); + } + + /** + * Executes a metadata query and returns the result as a JDBC + * {@link ResultSet}. + * + * @param metadataRequest Name of the metadata request. Corresponds to the XMLA + * method name, e.g. "MDSCHEMA_CUBES" + * + * @param patternValues Array of alternating parameter name and value + * pairs. If the parameter value is null, it is ignored. + * + * @return Result set of metadata + * + * @throws org.olap4j.OlapException on error + */ + private ResultSet getMetadata( + XmlaOlap4jConnection.MetadataRequest metadataRequest, + Object... patternValues) throws OlapException + { + assert patternValues.length % 2 == 0; + final XmlaOlap4jConnection.Context context = + new XmlaOlap4jConnection.Context( + olap4jConnection, null, null, null, null, null, null, null); + List patternValueList = new ArrayList(); + Map predicateList = new ArrayMap(); + for (int i = 0; i < patternValues.length; i += 2) { + String name = (String) patternValues[i]; + Object value = patternValues[i + 1]; + if (value == null) { + // ignore + } else if (value instanceof Wildcard) { + final Wildcard wildcard = (Wildcard) value; + if (wildcard.pattern.indexOf('%') < 0 + && wildcard.pattern.indexOf('_') < 0) { + patternValueList.add(name); + patternValueList.add(wildcard.pattern); + } else { + String regexp = + Olap4jUtil.wildcardToRegexp( + Collections.singletonList(wildcard.pattern)); + final Matcher matcher = Pattern.compile(regexp).matcher(""); + predicateList.put(name, matcher); + } + } else { + patternValueList.add(name); + patternValueList.add((String) value); + } + } + + String request = + olap4jConnection.generateRequest( + context, + metadataRequest, + patternValueList.toArray( + new String[patternValueList.size()])); + + final Element root = olap4jConnection.xxx(request); + List> rowList = new ArrayList>(); + rowLoop: + for (Element row : XmlaOlap4jUtil.childElements(root)) { + final ArrayList valueList = new ArrayList(); + for (Map.Entry entry : predicateList.entrySet()) { + final String column = entry.getKey(); + final String value = + XmlaOlap4jUtil.stringElement(row, column); + final Matcher matcher = entry.getValue(); + if (!matcher.reset(value).matches()) { + continue rowLoop; + } + } + for (XmlaOlap4jConnection.MetadataColumn column + : metadataRequest.columns) + { + final String value = + XmlaOlap4jUtil.stringElement(row, column.xmlaName); + valueList.add(value); + } + rowList.add(valueList); + } + List headerList = new ArrayList(); + for (XmlaOlap4jConnection.MetadataColumn column + : metadataRequest.columns) + { + headerList.add(column.name); + } + return olap4jConnection.factory.newFixedResultSet( + olap4jConnection, headerList, rowList); + } + + /** + * Converts a string to a wildcard object. + * + * @param pattern String pattern + * @return wildcard object, or null if pattern was null + */ + private Wildcard wildcard(String pattern) { + return pattern == null + ? null + : new Wildcard(pattern); + } + + // implement DatabaseMetaData + + public boolean allProceduresAreCallable() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean allTablesAreSelectable() throws SQLException { + throw new UnsupportedOperationException(); + } + + public String getURL() throws SQLException { + return olap4jConnection.getURL(); + } + + public String getUserName() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean isReadOnly() throws SQLException { + // olap4j does not currently support writeback + return true; + } + + public boolean nullsAreSortedHigh() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean nullsAreSortedLow() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean nullsAreSortedAtStart() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean nullsAreSortedAtEnd() throws SQLException { + throw new UnsupportedOperationException(); + } + + public String getDatabaseProductName() throws SQLException { + throw Olap4jUtil.needToImplement(this); + } + + public String getDatabaseProductVersion() throws SQLException { + throw Olap4jUtil.needToImplement(this); + } + + public String getDriverName() throws SQLException { + return XmlaOlap4jDriver.NAME; + } + + public String getDriverVersion() throws SQLException { + return XmlaOlap4jDriver.VERSION; + } + + public int getDriverMajorVersion() { + return XmlaOlap4jDriver.MAJOR_VERSION; + } + + public int getDriverMinorVersion() { + return XmlaOlap4jDriver.MINOR_VERSION; + } + + public boolean usesLocalFiles() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean usesLocalFilePerTable() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsMixedCaseIdentifiers() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean storesUpperCaseIdentifiers() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean storesLowerCaseIdentifiers() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean storesMixedCaseIdentifiers() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean storesUpperCaseQuotedIdentifiers() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean storesLowerCaseQuotedIdentifiers() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean storesMixedCaseQuotedIdentifiers() throws SQLException { + throw new UnsupportedOperationException(); + } + + public String getIdentifierQuoteString() throws SQLException { + throw new UnsupportedOperationException(); + } + + public String getSQLKeywords() throws SQLException { + throw new UnsupportedOperationException(); + } + + public String getNumericFunctions() throws SQLException { + throw new UnsupportedOperationException(); + } + + public String getStringFunctions() throws SQLException { + throw new UnsupportedOperationException(); + } + + public String getSystemFunctions() throws SQLException { + throw new UnsupportedOperationException(); + } + + public String getTimeDateFunctions() throws SQLException { + throw new UnsupportedOperationException(); + } + + public String getSearchStringEscape() throws SQLException { + throw new UnsupportedOperationException(); + } + + public String getExtraNameCharacters() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsAlterTableWithAddColumn() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsAlterTableWithDropColumn() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsColumnAliasing() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean nullPlusNonNullIsNull() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsConvert() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsConvert( + int fromType, int toType) throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsTableCorrelationNames() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsDifferentTableCorrelationNames() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsExpressionsInOrderBy() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsOrderByUnrelated() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsGroupBy() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsGroupByUnrelated() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsGroupByBeyondSelect() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsLikeEscapeClause() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsMultipleResultSets() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsMultipleTransactions() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsNonNullableColumns() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsMinimumSQLGrammar() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsCoreSQLGrammar() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsExtendedSQLGrammar() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsANSI92EntryLevelSQL() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsANSI92IntermediateSQL() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsANSI92FullSQL() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsIntegrityEnhancementFacility() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsOuterJoins() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsFullOuterJoins() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsLimitedOuterJoins() throws SQLException { + throw new UnsupportedOperationException(); + } + + public String getSchemaTerm() throws SQLException { + throw new UnsupportedOperationException(); + } + + public String getProcedureTerm() throws SQLException { + throw new UnsupportedOperationException(); + } + + public String getCatalogTerm() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean isCatalogAtStart() throws SQLException { + throw new UnsupportedOperationException(); + } + + public String getCatalogSeparator() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsSchemasInDataManipulation() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsSchemasInProcedureCalls() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsSchemasInTableDefinitions() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsSchemasInIndexDefinitions() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsCatalogsInDataManipulation() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsCatalogsInProcedureCalls() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsCatalogsInTableDefinitions() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsCatalogsInIndexDefinitions() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsPositionedDelete() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsPositionedUpdate() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsSelectForUpdate() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsStoredProcedures() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsSubqueriesInComparisons() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsSubqueriesInExists() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsSubqueriesInIns() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsSubqueriesInQuantifieds() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsCorrelatedSubqueries() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsUnion() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsUnionAll() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsOpenCursorsAcrossCommit() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsOpenCursorsAcrossRollback() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsOpenStatementsAcrossCommit() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsOpenStatementsAcrossRollback() throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getMaxBinaryLiteralLength() throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getMaxCharLiteralLength() throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getMaxColumnNameLength() throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getMaxColumnsInGroupBy() throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getMaxColumnsInIndex() throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getMaxColumnsInOrderBy() throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getMaxColumnsInSelect() throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getMaxColumnsInTable() throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getMaxConnections() throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getMaxCursorNameLength() throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getMaxIndexLength() throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getMaxSchemaNameLength() throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getMaxProcedureNameLength() throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getMaxCatalogNameLength() throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getMaxRowSize() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean doesMaxRowSizeIncludeBlobs() throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getMaxStatementLength() throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getMaxStatements() throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getMaxTableNameLength() throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getMaxTablesInSelect() throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getMaxUserNameLength() throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getDefaultTransactionIsolation() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsTransactions() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsTransactionIsolationLevel(int level) throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsDataDefinitionAndDataManipulationTransactions() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsDataManipulationTransactionsOnly() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean dataDefinitionCausesTransactionCommit() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean dataDefinitionIgnoredInTransactions() throws SQLException { + throw new UnsupportedOperationException(); + } + + public ResultSet getProcedures( + String catalog, + String schemaPattern, + String procedureNamePattern) throws SQLException { + throw new UnsupportedOperationException(); + } + + public ResultSet getProcedureColumns( + String catalog, + String schemaPattern, + String procedureNamePattern, + String columnNamePattern) throws SQLException { + throw new UnsupportedOperationException(); + } + + public ResultSet getTables( + String catalog, + String schemaPattern, + String tableNamePattern, + String types[]) throws SQLException { + throw new UnsupportedOperationException(); + } + + public ResultSet getSchemas() throws SQLException { + return getMetadata( + XmlaOlap4jConnection.MetadataRequest.DBSCHEMA_SCHEMATA); + } + + public ResultSet getCatalogs() throws SQLException { + return getMetadata( + XmlaOlap4jConnection.MetadataRequest.DBSCHEMA_CATALOGS); + } + + public ResultSet getTableTypes() throws SQLException { + throw new UnsupportedOperationException(); + } + + public ResultSet getColumns( + String catalog, + String schemaPattern, + String tableNamePattern, + String columnNamePattern) throws SQLException { + throw new UnsupportedOperationException(); + } + + public ResultSet getColumnPrivileges( + String catalog, + String schema, + String table, + String columnNamePattern) throws SQLException { + throw new UnsupportedOperationException(); + } + + public ResultSet getTablePrivileges( + String catalog, + String schemaPattern, + String tableNamePattern) throws SQLException { + throw new UnsupportedOperationException(); + } + + public ResultSet getBestRowIdentifier( + String catalog, + String schema, + String table, + int scope, + boolean nullable) throws SQLException { + throw new UnsupportedOperationException(); + } + + public ResultSet getVersionColumns( + String catalog, String schema, String table) throws SQLException { + throw new UnsupportedOperationException(); + } + + public ResultSet getPrimaryKeys( + String catalog, String schema, String table) throws SQLException { + throw new UnsupportedOperationException(); + } + + public ResultSet getImportedKeys( + String catalog, String schema, String table) throws SQLException { + throw new UnsupportedOperationException(); + } + + public ResultSet getExportedKeys( + String catalog, String schema, String table) throws SQLException { + throw new UnsupportedOperationException(); + } + + public ResultSet getCrossReference( + String parentCatalog, + String parentSchema, + String parentTable, + String foreignCatalog, + String foreignSchema, + String foreignTable) throws SQLException { + throw new UnsupportedOperationException(); + } + + public ResultSet getTypeInfo() throws SQLException { + throw new UnsupportedOperationException(); + } + + public ResultSet getIndexInfo( + String catalog, + String schema, + String table, + boolean unique, + boolean approximate) throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsResultSetType(int type) throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsResultSetConcurrency( + int type, int concurrency) throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean ownUpdatesAreVisible(int type) throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean ownDeletesAreVisible(int type) throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean ownInsertsAreVisible(int type) throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean othersUpdatesAreVisible(int type) throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean othersDeletesAreVisible(int type) throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean othersInsertsAreVisible(int type) throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean updatesAreDetected(int type) throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean deletesAreDetected(int type) throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean insertsAreDetected(int type) throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsBatchUpdates() throws SQLException { + throw new UnsupportedOperationException(); + } + + public ResultSet getUDTs( + String catalog, + String schemaPattern, + String typeNamePattern, + int[] types) throws SQLException { + throw new UnsupportedOperationException(); + } + + public OlapConnection getConnection() { + return olap4jConnection; + } + + public boolean supportsSavepoints() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsNamedParameters() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsMultipleOpenResults() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsGetGeneratedKeys() throws SQLException { + throw new UnsupportedOperationException(); + } + + public ResultSet getSuperTypes( + String catalog, + String schemaPattern, + String typeNamePattern) throws SQLException { + throw new UnsupportedOperationException(); + } + + public ResultSet getSuperTables( + String catalog, + String schemaPattern, + String tableNamePattern) throws SQLException { + throw new UnsupportedOperationException(); + } + + public ResultSet getAttributes( + String catalog, + String schemaPattern, + String typeNamePattern, + String attributeNamePattern) throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsResultSetHoldability(int holdability) throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getResultSetHoldability() throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getDatabaseMajorVersion() throws SQLException { + throw Olap4jUtil.needToImplement(this); + } + + public int getDatabaseMinorVersion() throws SQLException { + throw Olap4jUtil.needToImplement(this); + } + + public int getJDBCMajorVersion() throws SQLException { + // this driver supports jdbc 3.0 and jdbc 4.0 + // FIXME: should return 3 if the current connection is jdbc 3.0 + return 4; + } + + public int getJDBCMinorVersion() throws SQLException { + // this driver supports jdbc 3.0 and jdbc 4.0 + return 0; + } + + public int getSQLStateType() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean locatorsUpdateCopy() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean supportsStatementPooling() throws SQLException { + throw new UnsupportedOperationException(); + } + + // implement java.sql.Wrapper + + // straightforward implementation of unwrap and isWrapperFor, since this + // class already implements the interface they most likely require: + // DatabaseMetaData and OlapDatabaseMetaData + + public T unwrap(Class iface) throws SQLException { + if (iface.isInstance(this)) { + return iface.cast(this); + } + throw olap4jConnection.helper.createException( + "does not implement '" + iface + "'"); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return iface.isInstance(this); + } + + // implement OlapDatabaseMetaData + + public ResultSet getActions( + String catalog, + String schemaPattern, + String cubeNamePattern, + String actionNamePattern) throws OlapException + { + return getMetadata( + XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_ACTIONS, + "SCHEMA_NAME", wildcard(schemaPattern), + "CUBE_NAME", wildcard(cubeNamePattern), + "ACTION_NAME", wildcard(actionNamePattern)); + } + + public ResultSet getDatasources() throws OlapException { + return getMetadata( + XmlaOlap4jConnection.MetadataRequest.DISCOVER_DATASOURCES); + } + + public ResultSet getLiterals() throws OlapException { + return getMetadata( + XmlaOlap4jConnection.MetadataRequest.DISCOVER_LITERALS); + } + + public ResultSet getDatabaseProperties( + String dataSourceName, + String propertyNamePattern) throws OlapException + { + return getMetadata( + XmlaOlap4jConnection.MetadataRequest.DISCOVER_PROPERTIES); + } + + public ResultSet getProperties( + String catalog, + String schemaPattern, + String cubeNamePattern, + String dimensionUniqueName, + String hierarchyUniqueName, + String levelUniqueName, + String memberUniqueName, + String propertyNamePattern) throws OlapException + { + return getMetadata( + XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_PROPERTIES, + "CATALOG_NAME", catalog, + "SCHEMA_NAME", wildcard(schemaPattern), + "CUBE_NAME", wildcard(cubeNamePattern), + "DIMENSION_UNIQUE_NAME", dimensionUniqueName, + "HIERARCHY_UNIQUE_NAME", hierarchyUniqueName, + "LEVEL_UNIQUE_NAME", levelUniqueName, + "MEMBER_UNIQUE_NAME", memberUniqueName, + "PROPERTY_NAME", wildcard(propertyNamePattern)); + } + + public String getMdxKeywords() throws OlapException { + final XmlaOlap4jConnection.MetadataRequest metadataRequest = + XmlaOlap4jConnection.MetadataRequest.DISCOVER_KEYWORDS; + final XmlaOlap4jConnection.Context context = + new XmlaOlap4jConnection.Context( + olap4jConnection, null, null, null, null, null, null, null); + String request = + olap4jConnection.generateRequest( + context, metadataRequest, new Object[0]); + final Element root = olap4jConnection.xxx(request); + StringBuilder buf = new StringBuilder(); + for (Element row : XmlaOlap4jUtil.childElements(root)) { + if (buf.length() > 0) { + buf.append(','); + } + final String keyword = + XmlaOlap4jUtil.stringElement(row, "Keyword"); + buf.append(keyword); + } + return buf.toString(); + } + + public ResultSet getCubes( + String catalog, + String schemaPattern, + String cubeNamePattern) + throws OlapException + { + return getMetadata( + XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_CUBES, + "CATALOG_NAME", catalog, + "SCHEMA_NAME", wildcard(schemaPattern), + "CUBE_NAME", wildcard(cubeNamePattern)); + } + + public ResultSet getDimensions( + String catalog, + String schemaPattern, + String cubeNamePattern, + String dimensionNamePattern) + throws OlapException + { + return getMetadata( + XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_DIMENSIONS, + "SCHEMA_NAME", wildcard(schemaPattern), + "CUBE_NAME", wildcard(cubeNamePattern), + "DIMSENSION_NAME", wildcard(dimensionNamePattern)); + } + + public ResultSet getOlapFunctions( + String functionNamePattern) throws OlapException + { + return getMetadata( + XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_FUNCTIONS, + "FUNCTION_NAME", wildcard(functionNamePattern)); + } + + public ResultSet getHierarchies( + String catalog, + String schemaPattern, + String cubeNamePattern, + String dimensionNamePattern, + String hierarchyNamePattern) + throws OlapException + { + return getMetadata( + XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_HIERARCHIES, + "CATALOG_NAME", catalog, + "SCHEMA_NAME", wildcard(schemaPattern), + "CUBE_NAME", wildcard(cubeNamePattern), + "DIMENSION_NAME", wildcard(dimensionNamePattern), + "HIERARCHY_NAME", wildcard(hierarchyNamePattern)); + } + + public ResultSet getMeasures( + String catalog, + String schemaPattern, + String cubeNamePattern, + String measureNamePattern, + String measureUniqueName) throws OlapException + { + return getMetadata( + XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_MEASURES, + "CATALOG_NAME", catalog, + "SCHEMA_NAME", wildcard(schemaPattern), + "CUBE_NAME", wildcard(cubeNamePattern), + "MEASURE_NAME", wildcard(measureNamePattern), + "MEASURE_UNIQUE_NAME", measureUniqueName); + } + + public ResultSet getMembers( + String catalog, + String schemaPattern, + String cubeNamePattern, + String dimensionUniqueName, + String hierarchyUniqueName, + String levelUniqueName, + String memberUniqueName, + Set treeOps) throws OlapException + { + String treeOpString; + if (treeOps != null) { + int op = 0; + for (Member.TreeOp treeOp : treeOps) { + op |= treeOp.xmlaOrdinal(); + } + treeOpString = String.valueOf(op); + } else { + treeOpString = null; + } + return getMetadata( + XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_MEMBERS, + "CATALOG_NAME", catalog, + "SCHEMA_NAME", wildcard(schemaPattern), + "CUBE_NAME", wildcard(cubeNamePattern), + "DIMENSION_UNIQUE_NAME", dimensionUniqueName, + "HIERARCHY_UNIQUE_NAME", hierarchyUniqueName, + "LEVEL_UNIQUE_NAME", levelUniqueName, + "MEMBER_UNIQUE_NAME", memberUniqueName, + "TREE_OP", treeOpString); + } + + public ResultSet getLevels( + String catalog, + String schemaPattern, + String cubeNamePattern, + String dimensionUniqueName, + String hierarchyUniqueName, + String levelNamePattern) throws OlapException + { + return getMetadata( + XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_LEVELS, + "CATALOG_NAME", catalog, + "SCHEMA_NAME", wildcard(schemaPattern), + "CUBE_NAME", wildcard(cubeNamePattern), + "DIMENSION_UNIQUE_NAME", dimensionUniqueName, + "HIERARCHY_UNIQUE_NAME", hierarchyUniqueName, + "LEVEL_NAME", wildcard(levelNamePattern)); + } + + public ResultSet getSets( + String catalog, + String schemaPattern, + String cubeNamePattern, + String setNamePattern) throws OlapException + { + return getMetadata( + XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_SETS, + "CATALOG_NAME", catalog, + "SCHEMA_NAME", wildcard(schemaPattern), + "CUBE_NAME", wildcard(cubeNamePattern), + "SET_NAME", wildcard(setNamePattern)); + } + + + /** + * Wrapper which indicates that a restriction is to be treated as a + * SQL-style wildcard match. + */ + static class Wildcard { + final String pattern; + + /** + * Creates a Wildcard. + * + * @param pattern Pattern + */ + Wildcard(String pattern) { + assert pattern != null; + this.pattern = pattern; + } + } +} + +// End XmlaOlap4jDatabaseMetaData.java diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jDriver.java b/src/org/olap4j/driver/xmla/XmlaOlap4jDriver.java index 2f562f2..38038ad 100644 --- a/src/org/olap4j/driver/xmla/XmlaOlap4jDriver.java +++ b/src/org/olap4j/driver/xmla/XmlaOlap4jDriver.java @@ -54,24 +54,24 @@ * Property Description * * Server URL of HTTP server. Required. - * + * * Catalog Catalog name to use. Required. - * + * * Provider Name of the XMLA provider. - * + * * DataSource Name of the XMLA datasource. When using a * Mondrian backed XMLA server, be sure to * include the full datasource name between * quotes. - * + * * Cache

Class name of the SOAP cache to use. A built in - * memory cache is available with + * memory cache is available with * org.olap4j.driver.xmla.cache.XmlaOlap4jNamedMemoryCache. * Has to be an implementation of IXmlaOlap4jCache. *

By default, no SOAP query cache will be used. * - * - * Cache.* Properties to transfer to the selected cache + * + * Cache.* Properties to transfer to the selected cache * implementation. See IXmlaOlap4jCache or your * selected implementation for properties details. * @@ -84,7 +84,7 @@ * * * @author jhyde, Luc Boudreau - * @version $Id:$ + * @version $Id$ * @since May 22, 2007 */ public class XmlaOlap4jDriver implements Driver { @@ -151,20 +151,20 @@ private static void register() throws SQLException { * @see java.sql.Driver#connect(java.lang.String, java.util.Properties) */ public Connection connect(String url, Properties info) throws SQLException { - + // Checks if this driver handles this connection, exit otherwise. if (!XmlaOlap4jConnection.acceptsURL(url)) { return null; } - + // Parses the connection string Map map = XmlaOlap4jConnection.parseConnectString(url, info); - + // Creates a connection proxy XmlaOlap4jProxy proxy = createProxy(map); - - // returns a connection object to the java API + + // returns a connection object to the java API return factory.newConnection(proxy, url, info); } @@ -249,7 +249,7 @@ public byte[] call() throws Exception { * For testing. Map from a cookie value (which is uniquely generated for * each test) to a proxy object. Uses a weak hash map so that, if the code * that created the proxy 'forgets' the cookie value, then the proxy can - * be garbage-collected. + * be garbage-collected. */ public static final Map PROXY_MAP = Collections.synchronizedMap(new WeakHashMap()); @@ -285,7 +285,7 @@ public enum Property { Olap4jUtil.discard(description); } } - + /** * This is a mock subclass to prevent retro-compatibility issues. * If you're using this class, please change your code to @@ -294,7 +294,8 @@ public enum Property { * */ @Deprecated - public static interface Proxy extends XmlaOlap4jProxy {} + public static interface Proxy extends XmlaOlap4jProxy { + } } // End XmlaOlap4jDriver.java diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jPreparedStatement.java b/src/org/olap4j/driver/xmla/XmlaOlap4jPreparedStatement.java index f493ff0..f590700 100644 --- a/src/org/olap4j/driver/xmla/XmlaOlap4jPreparedStatement.java +++ b/src/org/olap4j/driver/xmla/XmlaOlap4jPreparedStatement.java @@ -1,437 +1,437 @@ -/* -// This software is subject to the terms of the Common Public License -// Agreement, available at the following URL: -// http://www.opensource.org/licenses/cpl.html. -// Copyright (C) 2007-2007 Julian Hyde -// All Rights Reserved. -// You must accept the terms of that agreement to use this software. -*/ -package org.olap4j.driver.xmla; - -import org.olap4j.*; -import org.olap4j.impl.Olap4jUtil; -import org.olap4j.metadata.*; -import org.olap4j.type.*; - -import java.io.InputStream; -import java.io.Reader; -import java.math.BigDecimal; -import java.net.URL; -import java.sql.*; -import java.sql.Date; -import java.util.*; - -/** - * Implementation of {@link org.olap4j.PreparedOlapStatement} - * for XML/A providers. - * - *

This class has sub-classes which implement JDBC 3.0 and JDBC 4.0 APIs; - * it is instantiated using {@link Factory#newPreparedStatement}.

- * - * @author jhyde - * @version $Id$ - * @since Jun 12, 2007 - */ -abstract class XmlaOlap4jPreparedStatement - extends XmlaOlap4jStatement - implements PreparedOlapStatement, OlapParameterMetaData -{ - final XmlaOlap4jCellSetMetaData cellSetMetaData; - private final String mdx; - - XmlaOlap4jPreparedStatement( - XmlaOlap4jConnection olap4jConnection, - String mdx) throws OlapException - { - super(olap4jConnection); - - // Execute a statement and steal its metadata. - final OlapStatement statement = olap4jConnection.createStatement(); - try { - final CellSet cellSet = statement.executeOlapQuery(mdx); - final XmlaOlap4jCellSetMetaData cellSetMetaData1 = - (XmlaOlap4jCellSetMetaData) cellSet.getMetaData(); - this.cellSetMetaData = cellSetMetaData1.cloneFor(this); - cellSet.close(); - statement.close(); - - } catch (SQLException e) { - throw olap4jConnection.helper.createException( - "Error while preparing statement '" + mdx + "'", - e); - } - - this.mdx = mdx; - } - - // override OlapStatement - - public CellSet executeOlapQuery(String mdx) throws OlapException { - return super.executeOlapQuery(mdx); - } - - // implement PreparedOlapStatement - - public CellSet executeQuery() throws OlapException { - return executeOlapQuery(mdx); - } - - public OlapParameterMetaData getParameterMetaData() throws OlapException { - return this; - } - - public Cube getCube() { - return cellSetMetaData.cube; - } - - // implement PreparedStatement - - public int executeUpdate() throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setNull(int parameterIndex, int sqlType) throws SQLException { - getParameter(parameterIndex).setValue(null); - } - - public void setBoolean(int parameterIndex, boolean x) throws SQLException { - getParameter(parameterIndex).setValue(x); - } - - public void setByte(int parameterIndex, byte x) throws SQLException { - getParameter(parameterIndex).setValue(x); - } - - public void setShort(int parameterIndex, short x) throws SQLException { - getParameter(parameterIndex).setValue(x); - } - - public void setInt(int parameterIndex, int x) throws SQLException { - getParameter(parameterIndex).setValue(x); - } - - public void setLong(int parameterIndex, long x) throws SQLException { - getParameter(parameterIndex).setValue(x); - } - - public void setFloat(int parameterIndex, float x) throws SQLException { - getParameter(parameterIndex).setValue(x); - } - - public void setDouble(int parameterIndex, double x) throws SQLException { - getParameter(parameterIndex).setValue(x); - } - - public void setBigDecimal( - int parameterIndex, BigDecimal x) throws SQLException { - getParameter(parameterIndex).setValue(x); - } - - public void setString(int parameterIndex, String x) throws SQLException { - getParameter(parameterIndex).setValue(x); - } - - public void setBytes(int parameterIndex, byte x[]) throws SQLException { - getParameter(parameterIndex).setValue(x); - } - - public void setDate(int parameterIndex, Date x) throws SQLException { - getParameter(parameterIndex).setValue(x); - } - - public void setTime(int parameterIndex, Time x) throws SQLException { - getParameter(parameterIndex).setValue(x); - } - - public void setTimestamp( - int parameterIndex, Timestamp x) throws SQLException { - getParameter(parameterIndex).setValue(x); - } - - public void setAsciiStream( - int parameterIndex, InputStream x, int length) throws SQLException { - getParameter(parameterIndex).setValue(x); - } - - public void setUnicodeStream( - int parameterIndex, InputStream x, int length) throws SQLException { - getParameter(parameterIndex).setValue(x); - } - - public void setBinaryStream( - int parameterIndex, InputStream x, int length) throws SQLException { - getParameter(parameterIndex).setValue(x); - } - - public void clearParameters() throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setObject( - int parameterIndex, Object x, int targetSqlType) throws SQLException { - getParameter(parameterIndex).setValue(x); - } - - public void setObject(int parameterIndex, Object x) throws SQLException { - final Parameter parameter = getParameter(parameterIndex); - parameter.setValue(x); - } - - public boolean execute() throws SQLException { - throw new UnsupportedOperationException(); - } - - public void addBatch() throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setCharacterStream( - int parameterIndex, Reader reader, int length) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setRef(int parameterIndex, Ref x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setBlob(int parameterIndex, Blob x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setClob(int parameterIndex, Clob x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setArray(int parameterIndex, Array x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public CellSetMetaData getMetaData() { - return cellSetMetaData; - } - - public void setDate( - int parameterIndex, Date x, Calendar cal) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setTime( - int parameterIndex, Time x, Calendar cal) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setTimestamp( - int parameterIndex, Timestamp x, Calendar cal) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setNull( - int parameterIndex, int sqlType, String typeName) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setURL(int parameterIndex, URL x) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setObject( - int parameterIndex, - Object x, - int targetSqlType, - int scaleOrLength) throws SQLException { - throw new UnsupportedOperationException(); - } - - // implement OlapParameterMetaData - - public String getParameterName(int param) throws OlapException { - Parameter paramDef = getParameter(param); - return paramDef.getName(); - } - - private Parameter getParameter(int param) throws OlapException { - final List parameters = getParameters(); - if (param < 1 || param > parameters.size()) { - throw olap4jConnection.helper.toOlapException( - olap4jConnection.helper.createException( - "parameter ordinal " + param + " out of range")); - } - return parameters.get(param - 1); - } - - private List getParameters() { - // XMLA statements do not have parameters yet - return Collections.emptyList(); - } - - public Type getParameterOlapType(int param) throws OlapException { - throw Olap4jUtil.needToImplement(this); - } - - public int getParameterCount() { - return getParameters().size(); - } - - public int isNullable(int param) throws SQLException { - return ParameterMetaData.parameterNullableUnknown; - } - - public boolean isSigned(int param) throws SQLException { - final Type type = getParameterOlapType(param); - return type instanceof NumericType; - } - - public int getPrecision(int param) throws SQLException { - final Type type = getParameterOlapType(param); - if (type instanceof NumericType) { - return 0; // precision not applicable - } - if (type instanceof StringType) { - return Integer.MAX_VALUE; - } - return 0; - } - - public int getScale(int param) throws SQLException { - return 0; // scale not applicable - } - - public int getParameterType(int param) throws SQLException { - final Type type = getParameterOlapType(param); - if (type instanceof NumericType) { - return Types.NUMERIC; - } else if (type instanceof StringType) { - return Types.VARCHAR; - } else if (type instanceof NullType) { - return Types.NULL; - } else { - return Types.OTHER; - } - } - - public String getParameterTypeName(int param) throws SQLException { - final Type type = getParameterOlapType(param); - return type.toString(); - } - - public String getParameterClassName(int param) throws SQLException { - final Type type = getParameterOlapType(param); - return foo( - new XmlaOlap4jPreparedStatement.TypeHelper() { - public Class booleanType(BooleanType type) { - return Boolean.class; - } - - public Class cubeType(CubeType cubeType) { - return Cube.class; - } - - public Class decimalType(DecimalType decimalType) { - return Number.class; - } - - public Class dimensionType(DimensionType dimensionType) { - return Dimension.class; - } - - public Class hierarchyType(HierarchyType hierarchyType) { - return Hierarchy.class; - } - - public Class levelType(LevelType levelType) { - return Level.class; - } - - public Class memberType(MemberType memberType) { - return Member.class; - } - - public Class nullType(NullType nullType) { - return Void.class; - } - - public Class numericType(NumericType numericType) { - return Number.class; - } - - public Class setType(SetType setType) { - return Iterable.class; - } - - public Class stringType(StringType stringType) { - return String.class; - } - - public Class tupleType(TupleType tupleType) { - return Member[].class; - } - - public Class symbolType(SymbolType symbolType) { - // parameters cannot be of this type - throw new UnsupportedOperationException(); - } - }, - type).getName(); - } - - public int getParameterMode(int param) throws SQLException { - throw Olap4jUtil.needToImplement(this); - } - - // Helper classes - - private interface TypeHelper { - T booleanType(BooleanType type); - T cubeType(CubeType cubeType); - T decimalType(DecimalType decimalType); - T dimensionType(DimensionType dimensionType); - T hierarchyType(HierarchyType hierarchyType); - T levelType(LevelType levelType); - T memberType(MemberType memberType); - T nullType(NullType nullType); - T numericType(NumericType numericType); - T setType(SetType setType); - T stringType(StringType stringType); - T tupleType(TupleType tupleType); - T symbolType(SymbolType symbolType); - } - - T foo(XmlaOlap4jPreparedStatement.TypeHelper helper, Type type) { - if (type instanceof BooleanType) { - return helper.booleanType((BooleanType) type); - } else if (type instanceof CubeType) { - return helper.cubeType((CubeType) type); - } else if (type instanceof DecimalType) { - return helper.decimalType((DecimalType) type); - } else if (type instanceof DimensionType) { - return helper.dimensionType((DimensionType) type); - } else if (type instanceof HierarchyType) { - return helper.hierarchyType((HierarchyType) type); - } else if (type instanceof LevelType) { - return helper.levelType((LevelType) type); - } else if (type instanceof MemberType) { - return helper.memberType((MemberType) type); - } else if (type instanceof NullType) { - return helper.nullType((NullType) type); - } else if (type instanceof NumericType) { - return helper.numericType((NumericType) type); - } else if (type instanceof SetType) { - return helper.setType((SetType) type); - } else if (type instanceof StringType) { - return helper.stringType((StringType) type); - } else if (type instanceof TupleType) { - return helper.tupleType((TupleType) type); - } else if (type instanceof SymbolType) { - return helper.symbolType((SymbolType) type); - } else { - throw new UnsupportedOperationException(); - } - } - - private interface Parameter { - String getName(); - void setValue(Object o); - } -} - -// End XmlaOlap4jPreparedStatement.java +/* +// This software is subject to the terms of the Common Public License +// Agreement, available at the following URL: +// http://www.opensource.org/licenses/cpl.html. +// Copyright (C) 2007-2007 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j.driver.xmla; + +import org.olap4j.*; +import org.olap4j.impl.Olap4jUtil; +import org.olap4j.metadata.*; +import org.olap4j.type.*; + +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.net.URL; +import java.sql.*; +import java.sql.Date; +import java.util.*; + +/** + * Implementation of {@link org.olap4j.PreparedOlapStatement} + * for XML/A providers. + * + *

This class has sub-classes which implement JDBC 3.0 and JDBC 4.0 APIs; + * it is instantiated using {@link Factory#newPreparedStatement}.

+ * + * @author jhyde + * @version $Id$ + * @since Jun 12, 2007 + */ +abstract class XmlaOlap4jPreparedStatement + extends XmlaOlap4jStatement + implements PreparedOlapStatement, OlapParameterMetaData +{ + final XmlaOlap4jCellSetMetaData cellSetMetaData; + private final String mdx; + + XmlaOlap4jPreparedStatement( + XmlaOlap4jConnection olap4jConnection, + String mdx) throws OlapException + { + super(olap4jConnection); + + // Execute a statement and steal its metadata. + final OlapStatement statement = olap4jConnection.createStatement(); + try { + final CellSet cellSet = statement.executeOlapQuery(mdx); + final XmlaOlap4jCellSetMetaData cellSetMetaData1 = + (XmlaOlap4jCellSetMetaData) cellSet.getMetaData(); + this.cellSetMetaData = cellSetMetaData1.cloneFor(this); + cellSet.close(); + statement.close(); + + } catch (SQLException e) { + throw olap4jConnection.helper.createException( + "Error while preparing statement '" + mdx + "'", + e); + } + + this.mdx = mdx; + } + + // override OlapStatement + + public CellSet executeOlapQuery(String mdx) throws OlapException { + return super.executeOlapQuery(mdx); + } + + // implement PreparedOlapStatement + + public CellSet executeQuery() throws OlapException { + return executeOlapQuery(mdx); + } + + public OlapParameterMetaData getParameterMetaData() throws OlapException { + return this; + } + + public Cube getCube() { + return cellSetMetaData.cube; + } + + // implement PreparedStatement + + public int executeUpdate() throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setNull(int parameterIndex, int sqlType) throws SQLException { + getParameter(parameterIndex).setValue(null); + } + + public void setBoolean(int parameterIndex, boolean x) throws SQLException { + getParameter(parameterIndex).setValue(x); + } + + public void setByte(int parameterIndex, byte x) throws SQLException { + getParameter(parameterIndex).setValue(x); + } + + public void setShort(int parameterIndex, short x) throws SQLException { + getParameter(parameterIndex).setValue(x); + } + + public void setInt(int parameterIndex, int x) throws SQLException { + getParameter(parameterIndex).setValue(x); + } + + public void setLong(int parameterIndex, long x) throws SQLException { + getParameter(parameterIndex).setValue(x); + } + + public void setFloat(int parameterIndex, float x) throws SQLException { + getParameter(parameterIndex).setValue(x); + } + + public void setDouble(int parameterIndex, double x) throws SQLException { + getParameter(parameterIndex).setValue(x); + } + + public void setBigDecimal( + int parameterIndex, BigDecimal x) throws SQLException { + getParameter(parameterIndex).setValue(x); + } + + public void setString(int parameterIndex, String x) throws SQLException { + getParameter(parameterIndex).setValue(x); + } + + public void setBytes(int parameterIndex, byte x[]) throws SQLException { + getParameter(parameterIndex).setValue(x); + } + + public void setDate(int parameterIndex, Date x) throws SQLException { + getParameter(parameterIndex).setValue(x); + } + + public void setTime(int parameterIndex, Time x) throws SQLException { + getParameter(parameterIndex).setValue(x); + } + + public void setTimestamp( + int parameterIndex, Timestamp x) throws SQLException { + getParameter(parameterIndex).setValue(x); + } + + public void setAsciiStream( + int parameterIndex, InputStream x, int length) throws SQLException { + getParameter(parameterIndex).setValue(x); + } + + public void setUnicodeStream( + int parameterIndex, InputStream x, int length) throws SQLException { + getParameter(parameterIndex).setValue(x); + } + + public void setBinaryStream( + int parameterIndex, InputStream x, int length) throws SQLException { + getParameter(parameterIndex).setValue(x); + } + + public void clearParameters() throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setObject( + int parameterIndex, Object x, int targetSqlType) throws SQLException { + getParameter(parameterIndex).setValue(x); + } + + public void setObject(int parameterIndex, Object x) throws SQLException { + final Parameter parameter = getParameter(parameterIndex); + parameter.setValue(x); + } + + public boolean execute() throws SQLException { + throw new UnsupportedOperationException(); + } + + public void addBatch() throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setCharacterStream( + int parameterIndex, Reader reader, int length) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setRef(int parameterIndex, Ref x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setBlob(int parameterIndex, Blob x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setClob(int parameterIndex, Clob x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setArray(int parameterIndex, Array x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public CellSetMetaData getMetaData() { + return cellSetMetaData; + } + + public void setDate( + int parameterIndex, Date x, Calendar cal) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setTime( + int parameterIndex, Time x, Calendar cal) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setTimestamp( + int parameterIndex, Timestamp x, Calendar cal) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setNull( + int parameterIndex, int sqlType, String typeName) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setURL(int parameterIndex, URL x) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setObject( + int parameterIndex, + Object x, + int targetSqlType, + int scaleOrLength) throws SQLException { + throw new UnsupportedOperationException(); + } + + // implement OlapParameterMetaData + + public String getParameterName(int param) throws OlapException { + Parameter paramDef = getParameter(param); + return paramDef.getName(); + } + + private Parameter getParameter(int param) throws OlapException { + final List parameters = getParameters(); + if (param < 1 || param > parameters.size()) { + throw olap4jConnection.helper.toOlapException( + olap4jConnection.helper.createException( + "parameter ordinal " + param + " out of range")); + } + return parameters.get(param - 1); + } + + private List getParameters() { + // XMLA statements do not have parameters yet + return Collections.emptyList(); + } + + public Type getParameterOlapType(int param) throws OlapException { + throw Olap4jUtil.needToImplement(this); + } + + public int getParameterCount() { + return getParameters().size(); + } + + public int isNullable(int param) throws SQLException { + return ParameterMetaData.parameterNullableUnknown; + } + + public boolean isSigned(int param) throws SQLException { + final Type type = getParameterOlapType(param); + return type instanceof NumericType; + } + + public int getPrecision(int param) throws SQLException { + final Type type = getParameterOlapType(param); + if (type instanceof NumericType) { + return 0; // precision not applicable + } + if (type instanceof StringType) { + return Integer.MAX_VALUE; + } + return 0; + } + + public int getScale(int param) throws SQLException { + return 0; // scale not applicable + } + + public int getParameterType(int param) throws SQLException { + final Type type = getParameterOlapType(param); + if (type instanceof NumericType) { + return Types.NUMERIC; + } else if (type instanceof StringType) { + return Types.VARCHAR; + } else if (type instanceof NullType) { + return Types.NULL; + } else { + return Types.OTHER; + } + } + + public String getParameterTypeName(int param) throws SQLException { + final Type type = getParameterOlapType(param); + return type.toString(); + } + + public String getParameterClassName(int param) throws SQLException { + final Type type = getParameterOlapType(param); + return foo( + new XmlaOlap4jPreparedStatement.TypeHelper() { + public Class booleanType(BooleanType type) { + return Boolean.class; + } + + public Class cubeType(CubeType cubeType) { + return Cube.class; + } + + public Class decimalType(DecimalType decimalType) { + return Number.class; + } + + public Class dimensionType(DimensionType dimensionType) { + return Dimension.class; + } + + public Class hierarchyType(HierarchyType hierarchyType) { + return Hierarchy.class; + } + + public Class levelType(LevelType levelType) { + return Level.class; + } + + public Class memberType(MemberType memberType) { + return Member.class; + } + + public Class nullType(NullType nullType) { + return Void.class; + } + + public Class numericType(NumericType numericType) { + return Number.class; + } + + public Class setType(SetType setType) { + return Iterable.class; + } + + public Class stringType(StringType stringType) { + return String.class; + } + + public Class tupleType(TupleType tupleType) { + return Member[].class; + } + + public Class symbolType(SymbolType symbolType) { + // parameters cannot be of this type + throw new UnsupportedOperationException(); + } + }, + type).getName(); + } + + public int getParameterMode(int param) throws SQLException { + throw Olap4jUtil.needToImplement(this); + } + + // Helper classes + + private interface TypeHelper { + T booleanType(BooleanType type); + T cubeType(CubeType cubeType); + T decimalType(DecimalType decimalType); + T dimensionType(DimensionType dimensionType); + T hierarchyType(HierarchyType hierarchyType); + T levelType(LevelType levelType); + T memberType(MemberType memberType); + T nullType(NullType nullType); + T numericType(NumericType numericType); + T setType(SetType setType); + T stringType(StringType stringType); + T tupleType(TupleType tupleType); + T symbolType(SymbolType symbolType); + } + + T foo(XmlaOlap4jPreparedStatement.TypeHelper helper, Type type) { + if (type instanceof BooleanType) { + return helper.booleanType((BooleanType) type); + } else if (type instanceof CubeType) { + return helper.cubeType((CubeType) type); + } else if (type instanceof DecimalType) { + return helper.decimalType((DecimalType) type); + } else if (type instanceof DimensionType) { + return helper.dimensionType((DimensionType) type); + } else if (type instanceof HierarchyType) { + return helper.hierarchyType((HierarchyType) type); + } else if (type instanceof LevelType) { + return helper.levelType((LevelType) type); + } else if (type instanceof MemberType) { + return helper.memberType((MemberType) type); + } else if (type instanceof NullType) { + return helper.nullType((NullType) type); + } else if (type instanceof NumericType) { + return helper.numericType((NumericType) type); + } else if (type instanceof SetType) { + return helper.setType((SetType) type); + } else if (type instanceof StringType) { + return helper.stringType((StringType) type); + } else if (type instanceof TupleType) { + return helper.tupleType((TupleType) type); + } else if (type instanceof SymbolType) { + return helper.symbolType((SymbolType) type); + } else { + throw new UnsupportedOperationException(); + } + } + + private interface Parameter { + String getName(); + void setValue(Object o); + } +} + +// End XmlaOlap4jPreparedStatement.java diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jProperty.java b/src/org/olap4j/driver/xmla/XmlaOlap4jProperty.java index 0879c47..87fa868 100644 --- a/src/org/olap4j/driver/xmla/XmlaOlap4jProperty.java +++ b/src/org/olap4j/driver/xmla/XmlaOlap4jProperty.java @@ -16,7 +16,7 @@ /** * Implementation of {@link org.olap4j.metadata.Property} - * for properties defined as part of the definition of a level or measure + * for properties defined as part of the definition of a level or measure * from XML/A providers. * * @see org.olap4j.driver.xmla.XmlaOlap4jCellProperty @@ -27,7 +27,7 @@ * @since Dec 9, 2007 */ class XmlaOlap4jProperty - extends XmlaOlap4jElement + extends XmlaOlap4jElement implements Property, Named { private final Datatype datatype; diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jSchema.java b/src/org/olap4j/driver/xmla/XmlaOlap4jSchema.java index a456db2..097542d 100644 --- a/src/org/olap4j/driver/xmla/XmlaOlap4jSchema.java +++ b/src/org/olap4j/driver/xmla/XmlaOlap4jSchema.java @@ -1,89 +1,89 @@ -/* -// This software is subject to the terms of the Common Public License -// Agreement, available at the following URL: -// http://www.opensource.org/licenses/cpl.html. -// Copyright (C) 2007-2007 Julian Hyde -// All Rights Reserved. -// You must accept the terms of that agreement to use this software. -*/ -package org.olap4j.driver.xmla; - -import org.olap4j.OlapException; -import org.olap4j.impl.*; -import org.olap4j.metadata.*; - -import java.util.*; - -/** - * Implementation of {@link org.olap4j.metadata.Schema} - * for XML/A providers. - * - * @author jhyde - * @version $Id$ - * @since May 24, 2007 - */ -class XmlaOlap4jSchema implements Schema, Named { - final XmlaOlap4jCatalog olap4jCatalog; - private final String name; - final NamedList cubes; - - XmlaOlap4jSchema( - XmlaOlap4jCatalog olap4jCatalog, - String name) - { - if (olap4jCatalog == null) { - throw new NullPointerException("Catalog cannot be null."); - } - if (name == null) { - throw new NullPointerException("Name cannot be null."); - } - - this.olap4jCatalog = olap4jCatalog; - this.name = name; - this.cubes = new DeferredNamedListImpl( - XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_CUBES, - new XmlaOlap4jConnection.Context( - olap4jCatalog.olap4jDatabaseMetaData.olap4jConnection, - olap4jCatalog.olap4jDatabaseMetaData, - olap4jCatalog, - this, - null, null, null, null), - new XmlaOlap4jConnection.CubeHandler()); - } - - public int hashCode() { - return name.hashCode(); - } - - public boolean equals(Object obj) { - if (obj instanceof XmlaOlap4jSchema) { - XmlaOlap4jSchema that = (XmlaOlap4jSchema) obj; - return this.name.equals(that.name) - && this.olap4jCatalog.equals(that.olap4jCatalog); - } - return false; - } - - public Catalog getCatalog() { - return olap4jCatalog; - } - - public String getName() { - return name; - } - - public NamedList getCubes() throws OlapException { - return Olap4jUtil.cast(cubes); - } - - public NamedList getSharedDimensions() throws OlapException { - // No shared dimensions - return Olap4jUtil.cast(new NamedListImpl()); - } - - public Collection getSupportedLocales() throws OlapException { - return Collections.emptyList(); - } -} - -// End XmlaOlap4jSchema.java +/* +// This software is subject to the terms of the Common Public License +// Agreement, available at the following URL: +// http://www.opensource.org/licenses/cpl.html. +// Copyright (C) 2007-2007 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j.driver.xmla; + +import org.olap4j.OlapException; +import org.olap4j.impl.*; +import org.olap4j.metadata.*; + +import java.util.*; + +/** + * Implementation of {@link org.olap4j.metadata.Schema} + * for XML/A providers. + * + * @author jhyde + * @version $Id$ + * @since May 24, 2007 + */ +class XmlaOlap4jSchema implements Schema, Named { + final XmlaOlap4jCatalog olap4jCatalog; + private final String name; + final NamedList cubes; + + XmlaOlap4jSchema( + XmlaOlap4jCatalog olap4jCatalog, + String name) + { + if (olap4jCatalog == null) { + throw new NullPointerException("Catalog cannot be null."); + } + if (name == null) { + throw new NullPointerException("Name cannot be null."); + } + + this.olap4jCatalog = olap4jCatalog; + this.name = name; + this.cubes = new DeferredNamedListImpl( + XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_CUBES, + new XmlaOlap4jConnection.Context( + olap4jCatalog.olap4jDatabaseMetaData.olap4jConnection, + olap4jCatalog.olap4jDatabaseMetaData, + olap4jCatalog, + this, + null, null, null, null), + new XmlaOlap4jConnection.CubeHandler()); + } + + public int hashCode() { + return name.hashCode(); + } + + public boolean equals(Object obj) { + if (obj instanceof XmlaOlap4jSchema) { + XmlaOlap4jSchema that = (XmlaOlap4jSchema) obj; + return this.name.equals(that.name) + && this.olap4jCatalog.equals(that.olap4jCatalog); + } + return false; + } + + public Catalog getCatalog() { + return olap4jCatalog; + } + + public String getName() { + return name; + } + + public NamedList getCubes() throws OlapException { + return Olap4jUtil.cast(cubes); + } + + public NamedList getSharedDimensions() throws OlapException { + // No shared dimensions + return Olap4jUtil.cast(new NamedListImpl()); + } + + public Collection getSupportedLocales() throws OlapException { + return Collections.emptyList(); + } +} + +// End XmlaOlap4jSchema.java diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jStatement.java b/src/org/olap4j/driver/xmla/XmlaOlap4jStatement.java index 13d87d4..7a5995e 100644 --- a/src/org/olap4j/driver/xmla/XmlaOlap4jStatement.java +++ b/src/org/olap4j/driver/xmla/XmlaOlap4jStatement.java @@ -1,384 +1,384 @@ -/* -// This software is subject to the terms of the Common Public License -// Agreement, available at the following URL: -// http://www.opensource.org/licenses/cpl.html. -// Copyright (C) 2007-2007 Julian Hyde -// All Rights Reserved. -// You must accept the terms of that agreement to use this software. -*/ -package org.olap4j.driver.xmla; - -import org.olap4j.*; -import org.olap4j.mdx.SelectNode; -import org.olap4j.mdx.ParseTreeNode; -import org.olap4j.mdx.ParseTreeWriter; - -import java.sql.*; -import java.io.*; -import java.util.concurrent.*; - -/** - * Implementation of {@link org.olap4j.OlapStatement} - * for XML/A providers. - * - * @author jhyde - * @version $Id$ - * @since May 24, 2007 - */ -class XmlaOlap4jStatement implements OlapStatement { - final XmlaOlap4jConnection olap4jConnection; - private boolean closed; - - /** - * Current cell set, or null if the statement is not executing anything. - * Any method which modifies this member must synchronize - * on the {@link XmlaOlap4jStatement}. - */ - XmlaOlap4jCellSet openCellSet; - private boolean canceled; - int timeoutSeconds; - Future future; - - XmlaOlap4jStatement( - XmlaOlap4jConnection olap4jConnection) - { - assert olap4jConnection != null; - this.olap4jConnection = olap4jConnection; - this.closed = false; - } - - // implement Statement - - public ResultSet executeQuery(String sql) throws SQLException { - throw new UnsupportedOperationException(); - } - - private void checkOpen() throws SQLException { - if (closed) { - throw olap4jConnection.helper.createException("closed"); - } - } - - public int executeUpdate(String sql) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void close() throws SQLException { - if (!closed) { - closed = true; - if (openCellSet != null) { - CellSet c = openCellSet; - openCellSet = null; - c.close(); - } - } - } - - public int getMaxFieldSize() throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setMaxFieldSize(int max) throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getMaxRows() throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setMaxRows(int max) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setEscapeProcessing(boolean enable) throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getQueryTimeout() throws SQLException { - return timeoutSeconds; - } - - public void setQueryTimeout(int seconds) throws SQLException { - if (seconds < 0) { - throw olap4jConnection.helper.createException( - "illegal timeout value " + seconds); - } - this.timeoutSeconds = seconds; - } - - public synchronized void cancel() { - if (!canceled) { - canceled = true; - if (future != null) { - future.cancel(true); - } - } - } - - public SQLWarning getWarnings() throws SQLException { - throw new UnsupportedOperationException(); - } - - public void clearWarnings() throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setCursorName(String name) throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean execute(String sql) throws SQLException { - throw new UnsupportedOperationException(); - } - - public ResultSet getResultSet() throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getUpdateCount() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean getMoreResults() throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setFetchDirection(int direction) throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getFetchDirection() throws SQLException { - throw new UnsupportedOperationException(); - } - - public void setFetchSize(int rows) throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getFetchSize() throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getResultSetConcurrency() throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getResultSetType() throws SQLException { - throw new UnsupportedOperationException(); - } - - public void addBatch(String sql) throws SQLException { - throw new UnsupportedOperationException(); - } - - public void clearBatch() throws SQLException { - throw new UnsupportedOperationException(); - } - - public int[] executeBatch() throws SQLException { - throw new UnsupportedOperationException(); - } - - public Connection getConnection() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean getMoreResults(int current) throws SQLException { - throw new UnsupportedOperationException(); - } - - public ResultSet getGeneratedKeys() throws SQLException { - throw new UnsupportedOperationException(); - } - - public int executeUpdate( - String sql, int autoGeneratedKeys) throws SQLException { - throw new UnsupportedOperationException(); - } - - public int executeUpdate( - String sql, int columnIndexes[]) throws SQLException { - throw new UnsupportedOperationException(); - } - - public int executeUpdate( - String sql, String columnNames[]) throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean execute( - String sql, int autoGeneratedKeys) throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean execute( - String sql, int columnIndexes[]) throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean execute( - String sql, String columnNames[]) throws SQLException { - throw new UnsupportedOperationException(); - } - - public int getResultSetHoldability() throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean isClosed() throws SQLException { - return closed; - } - - public void setPoolable(boolean poolable) throws SQLException { - throw new UnsupportedOperationException(); - } - - public boolean isPoolable() throws SQLException { - throw new UnsupportedOperationException(); - } - - // implement Wrapper - - public T unwrap(Class iface) throws SQLException { - if (iface.isInstance(this)) { - return iface.cast(this); - } - throw olap4jConnection.helper.createException( - "does not implement '" + iface + "'"); - } - - public boolean isWrapperFor(Class iface) throws SQLException { - return iface.isInstance(this); - } - - // implement OlapStatement - - public CellSet executeOlapQuery(String mdx) throws OlapException { - final String catalog = olap4jConnection.getCatalog(); - final String dataSourceInfo = olap4jConnection.getDataSourceInfo(); - StringBuilder buf = new StringBuilder( - "\n" + - "\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n"); - if (catalog != null) { - buf.append(" "); - buf.append(catalog); - buf.append("\n"); - } - if (dataSourceInfo != null) { - buf.append(" "); - buf.append(dataSourceInfo); - buf.append("\n"); - } - buf.append( - " Multidimensional\n" + - " TupleFormat\n" + - " \n" + - " \n" + - "\n" + - "\n" + - ""); - final String request = buf.toString(); - - // Close the previous open CellSet, if there is one. - synchronized (this) { - if (openCellSet != null) { - final XmlaOlap4jCellSet cs = openCellSet; - openCellSet = null; - try { - cs.close(); - } catch (SQLException e) { - throw olap4jConnection.helper.createException( - "Error while closing previous CellSet", e); - } - } - - this.future = - olap4jConnection.proxy.submit( - olap4jConnection.serverUrl, request); - openCellSet = olap4jConnection.factory.newCellSet(this); - } - // Release the monitor before calling populate, so that cancel can - // grab the monitor if it needs to. - openCellSet.populate(); - return openCellSet; - } - - public CellSet executeOlapQuery(SelectNode selectNode) throws OlapException { - final String mdx = toString(selectNode); - return executeOlapQuery(mdx); - } - - /** - * Waits for an XMLA request to complete. - * - *

You must not hold the monitor on this Statement when calling this - * method; otherwise {@link #cancel()} will not be able to operate. - * - * @return Byte array resulting from successful request - * - * @throws OlapException if error occurred, or request timed out or - * was canceled - */ - byte[] getBytes() throws OlapException { - synchronized (this) { - if (future == null) { - throw new IllegalArgumentException(); - } - } - try { - // Wait for the request to complete, with timeout if necessary. - // Whether or not timeout is used, the request can still be - // canceled. - if (timeoutSeconds > 0) { - return future.get(timeoutSeconds, TimeUnit.SECONDS); - } else { - return future.get(); - } - } catch (InterruptedException e) { - throw olap4jConnection.helper.createException(null, e); - } catch (ExecutionException e) { - throw olap4jConnection.helper.createException(null, e.getCause()); - } catch (TimeoutException e) { - throw olap4jConnection.helper.createException( - "Query timeout of " + timeoutSeconds + " seconds exceeded"); - } catch (CancellationException e) { - throw olap4jConnection.helper.createException("Query canceled"); - } finally { - synchronized (this) { - if (future == null) { - throw new IllegalArgumentException(); - } - future = null; - } - } - } - - /** - * Converts a {@link org.olap4j.mdx.ParseTreeNode} to MDX string. - * - * @param node Parse tree node - * @return MDX text - */ - private static String toString(ParseTreeNode node) { - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - ParseTreeWriter parseTreeWriter = new ParseTreeWriter(pw); - node.unparse(parseTreeWriter); - pw.flush(); - return sw.toString(); - } -} - -// End XmlaOlap4jStatement.java +/* +// This software is subject to the terms of the Common Public License +// Agreement, available at the following URL: +// http://www.opensource.org/licenses/cpl.html. +// Copyright (C) 2007-2007 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j.driver.xmla; + +import org.olap4j.*; +import org.olap4j.mdx.SelectNode; +import org.olap4j.mdx.ParseTreeNode; +import org.olap4j.mdx.ParseTreeWriter; + +import java.sql.*; +import java.io.*; +import java.util.concurrent.*; + +/** + * Implementation of {@link org.olap4j.OlapStatement} + * for XML/A providers. + * + * @author jhyde + * @version $Id$ + * @since May 24, 2007 + */ +class XmlaOlap4jStatement implements OlapStatement { + final XmlaOlap4jConnection olap4jConnection; + private boolean closed; + + /** + * Current cell set, or null if the statement is not executing anything. + * Any method which modifies this member must synchronize + * on the {@link XmlaOlap4jStatement}. + */ + XmlaOlap4jCellSet openCellSet; + private boolean canceled; + int timeoutSeconds; + Future future; + + XmlaOlap4jStatement( + XmlaOlap4jConnection olap4jConnection) + { + assert olap4jConnection != null; + this.olap4jConnection = olap4jConnection; + this.closed = false; + } + + // implement Statement + + public ResultSet executeQuery(String sql) throws SQLException { + throw new UnsupportedOperationException(); + } + + private void checkOpen() throws SQLException { + if (closed) { + throw olap4jConnection.helper.createException("closed"); + } + } + + public int executeUpdate(String sql) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void close() throws SQLException { + if (!closed) { + closed = true; + if (openCellSet != null) { + CellSet c = openCellSet; + openCellSet = null; + c.close(); + } + } + } + + public int getMaxFieldSize() throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setMaxFieldSize(int max) throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getMaxRows() throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setMaxRows(int max) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setEscapeProcessing(boolean enable) throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getQueryTimeout() throws SQLException { + return timeoutSeconds; + } + + public void setQueryTimeout(int seconds) throws SQLException { + if (seconds < 0) { + throw olap4jConnection.helper.createException( + "illegal timeout value " + seconds); + } + this.timeoutSeconds = seconds; + } + + public synchronized void cancel() { + if (!canceled) { + canceled = true; + if (future != null) { + future.cancel(true); + } + } + } + + public SQLWarning getWarnings() throws SQLException { + throw new UnsupportedOperationException(); + } + + public void clearWarnings() throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setCursorName(String name) throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean execute(String sql) throws SQLException { + throw new UnsupportedOperationException(); + } + + public ResultSet getResultSet() throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getUpdateCount() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean getMoreResults() throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setFetchDirection(int direction) throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getFetchDirection() throws SQLException { + throw new UnsupportedOperationException(); + } + + public void setFetchSize(int rows) throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getFetchSize() throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getResultSetConcurrency() throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getResultSetType() throws SQLException { + throw new UnsupportedOperationException(); + } + + public void addBatch(String sql) throws SQLException { + throw new UnsupportedOperationException(); + } + + public void clearBatch() throws SQLException { + throw new UnsupportedOperationException(); + } + + public int[] executeBatch() throws SQLException { + throw new UnsupportedOperationException(); + } + + public Connection getConnection() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean getMoreResults(int current) throws SQLException { + throw new UnsupportedOperationException(); + } + + public ResultSet getGeneratedKeys() throws SQLException { + throw new UnsupportedOperationException(); + } + + public int executeUpdate( + String sql, int autoGeneratedKeys) throws SQLException { + throw new UnsupportedOperationException(); + } + + public int executeUpdate( + String sql, int columnIndexes[]) throws SQLException { + throw new UnsupportedOperationException(); + } + + public int executeUpdate( + String sql, String columnNames[]) throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean execute( + String sql, int autoGeneratedKeys) throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean execute( + String sql, int columnIndexes[]) throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean execute( + String sql, String columnNames[]) throws SQLException { + throw new UnsupportedOperationException(); + } + + public int getResultSetHoldability() throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean isClosed() throws SQLException { + return closed; + } + + public void setPoolable(boolean poolable) throws SQLException { + throw new UnsupportedOperationException(); + } + + public boolean isPoolable() throws SQLException { + throw new UnsupportedOperationException(); + } + + // implement Wrapper + + public T unwrap(Class iface) throws SQLException { + if (iface.isInstance(this)) { + return iface.cast(this); + } + throw olap4jConnection.helper.createException( + "does not implement '" + iface + "'"); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return iface.isInstance(this); + } + + // implement OlapStatement + + public CellSet executeOlapQuery(String mdx) throws OlapException { + final String catalog = olap4jConnection.getCatalog(); + final String dataSourceInfo = olap4jConnection.getDataSourceInfo(); + StringBuilder buf = new StringBuilder( + "\n" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n"); + if (catalog != null) { + buf.append(" "); + buf.append(catalog); + buf.append("\n"); + } + if (dataSourceInfo != null) { + buf.append(" "); + buf.append(dataSourceInfo); + buf.append("\n"); + } + buf.append( + " Multidimensional\n" + + " TupleFormat\n" + + " \n" + + " \n" + + "\n" + + "\n" + + ""); + final String request = buf.toString(); + + // Close the previous open CellSet, if there is one. + synchronized (this) { + if (openCellSet != null) { + final XmlaOlap4jCellSet cs = openCellSet; + openCellSet = null; + try { + cs.close(); + } catch (SQLException e) { + throw olap4jConnection.helper.createException( + "Error while closing previous CellSet", e); + } + } + + this.future = + olap4jConnection.proxy.submit( + olap4jConnection.serverUrl, request); + openCellSet = olap4jConnection.factory.newCellSet(this); + } + // Release the monitor before calling populate, so that cancel can + // grab the monitor if it needs to. + openCellSet.populate(); + return openCellSet; + } + + public CellSet executeOlapQuery(SelectNode selectNode) throws OlapException { + final String mdx = toString(selectNode); + return executeOlapQuery(mdx); + } + + /** + * Waits for an XMLA request to complete. + * + *

You must not hold the monitor on this Statement when calling this + * method; otherwise {@link #cancel()} will not be able to operate. + * + * @return Byte array resulting from successful request + * + * @throws OlapException if error occurred, or request timed out or + * was canceled + */ + byte[] getBytes() throws OlapException { + synchronized (this) { + if (future == null) { + throw new IllegalArgumentException(); + } + } + try { + // Wait for the request to complete, with timeout if necessary. + // Whether or not timeout is used, the request can still be + // canceled. + if (timeoutSeconds > 0) { + return future.get(timeoutSeconds, TimeUnit.SECONDS); + } else { + return future.get(); + } + } catch (InterruptedException e) { + throw olap4jConnection.helper.createException(null, e); + } catch (ExecutionException e) { + throw olap4jConnection.helper.createException(null, e.getCause()); + } catch (TimeoutException e) { + throw olap4jConnection.helper.createException( + "Query timeout of " + timeoutSeconds + " seconds exceeded"); + } catch (CancellationException e) { + throw olap4jConnection.helper.createException("Query canceled"); + } finally { + synchronized (this) { + if (future == null) { + throw new IllegalArgumentException(); + } + future = null; + } + } + } + + /** + * Converts a {@link org.olap4j.mdx.ParseTreeNode} to MDX string. + * + * @param node Parse tree node + * @return MDX text + */ + private static String toString(ParseTreeNode node) { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + ParseTreeWriter parseTreeWriter = new ParseTreeWriter(pw); + node.unparse(parseTreeWriter); + pw.flush(); + return sw.toString(); + } +} + +// End XmlaOlap4jStatement.java diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jUtil.java b/src/org/olap4j/driver/xmla/XmlaOlap4jUtil.java index 3d140ac..efc2b8d 100644 --- a/src/org/olap4j/driver/xmla/XmlaOlap4jUtil.java +++ b/src/org/olap4j/driver/xmla/XmlaOlap4jUtil.java @@ -40,7 +40,7 @@ abstract class XmlaOlap4jUtil { "urn:schemas-microsoft-com:xml-analysis:mddataset"; static final String ROWSET_NS = "urn:schemas-microsoft-com:xml-analysis:rowset"; - + static final String XSD_PREFIX = "xsd"; static final String XMLNS = "xmlns"; @@ -126,7 +126,7 @@ static void checkForParseError(DOMParser parser, Throwable t) { throw new RuntimeException(errorStr, t); } } else { - System.out.println("errorHandler=" +errorHandler); + System.out.println("errorHandler=" + errorHandler); } } @@ -283,7 +283,7 @@ public static String toString(Node node, boolean prettyPrint) { writer.write(LINE_SEP); } } else { - writer.write("node class = " +node.getClass().getName()); + writer.write("node class = " + node.getClass().getName()); if (prettyPrint) { writer.write(LINE_SEP); } else { diff --git a/src/org/olap4j/driver/xmla/cache/XmlaOlap4jCache.java b/src/org/olap4j/driver/xmla/cache/XmlaOlap4jCache.java index 33f623b..b500cf4 100644 --- a/src/org/olap4j/driver/xmla/cache/XmlaOlap4jCache.java +++ b/src/org/olap4j/driver/xmla/cache/XmlaOlap4jCache.java @@ -1,87 +1,100 @@ -/* -// $Id: XmlaOlap4jCache.java 92 2008-07-17 07:41:10Z lucboudreau $ -// This software is subject to the terms of the Common Public License -// Agreement, available at the following URL: -// http://www.opensource.org/licenses/cpl.html. -// Copyright (C) 2007-2007 Julian Hyde -// All Rights Reserved. -// You must accept the terms of that agreement to use this software. -*/ -package org.olap4j.driver.xmla.cache; - -import java.net.URL; -import java.util.Map; - -/** - * XMLA driver cache. Implementations will have to declare those methods. - * - *

The XMLA driver will call the cache before each SOAP request to see - * if it wasn't sent previously and if a SOAP response doesn't already - * exist in it. - * - *

Any implementations have to declare a constructor which takes a String - * as a parameter. This string value is the unique name of the connection - * which triggered the request. - * - * @author Luc Boudreau - * @version $Id: XmlaOlap4jCache.java 92 2008-07-17 07:41:10Z lucboudreau $ - */ -public interface XmlaOlap4jCache { - - /** - * Fetches a SOAP response from the cache. Returns null - * if there are no cached response corresponding to the SOAP - * message and the URL. - * @param name The connection unique name which called this cache. - * @param url The URL where the SOAP message was sent. - * @param request The SOAP complete message. - * @throws XmlaOlap4jInvalidStateException This internal exception gets thrown - * when operations to the cache are performed but it hasn't been - * initialized. Make sure you call the setParameters method. - * @return The SOAP response, null if there are no corresponding - * response in the cache. - */ - public byte[] get(final String id, final URL url, final byte[] request) - throws XmlaOlap4jInvalidStateException; - - /** - * Adds a SOAP response to the cache. It has to be relative to the - * URL of the SOAP service. - * @param name The connection unique name which called this cache. - * @param url The URL of the SOAP endpoint. - * @param request The full SOAP message from which we want to cache it's - * response. - * @throws XmlaOlap4jInvalidStateException This internal exception gets thrown when - * operations to the cache are performed but it hasn't been initialized. - * Make sure you call the setParameters method. - * @param response The response to cache. - */ - public void put(final String id, final URL url, final byte[] request, - final byte[] response) throws XmlaOlap4jInvalidStateException; - - /** - * This tells the cache to flush all cached entries. - */ - public void flushCache(); - - /** - * Convenience method to receive custom properties. - * - *

The XMLA driver takes cache properties as - * "Cache.[property name]=[value]". in it's JDBC url. All those properties - * should be striped of their "Cache." prefix and sent to this method - * as the properties parameter. - * - *

Also, the complete config map of the current connection - * should be passed as the config parameter. - * - * @param config The complete configuration parameters which were used to - * create the current connection. - * @param props The properties received from the JDBC url. - * @return Returns a string object which gives a reference id to the - * caller for future use. This id has to be passed along with any future - * get and put requests. - */ - public String setParameters(final Map config, - final Map props); -} +/* +// $Id: XmlaOlap4jCache.java 92 2008-07-17 07:41:10Z lucboudreau $ +// This software is subject to the terms of the Common Public License +// Agreement, available at the following URL: +// http://www.opensource.org/licenses/cpl.html. +// Copyright (C) 2007-2007 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j.driver.xmla.cache; + +import java.net.URL; +import java.util.Map; + +/** + * XMLA driver cache. Implementations will have to declare those methods. + * + *

The XMLA driver will call the cache before each SOAP request to see + * if it wasn't sent previously and if a SOAP response doesn't already + * exist in it. + * + *

Any implementations have to declare a constructor which takes a String + * as a parameter. This string value is the unique name of the connection + * which triggered the request. + * + * @author Luc Boudreau + * @version $Id: XmlaOlap4jCache.java 92 2008-07-17 07:41:10Z lucboudreau $ + */ +public interface XmlaOlap4jCache { + + /** + * Fetches a SOAP response from the cache. Returns null + * if there are no cached response corresponding to the SOAP + * message and the URL. + * + * @param name The connection unique name which called this cache. + * @param url The URL where the SOAP message was sent. + * @param request The SOAP complete message. + * @throws XmlaOlap4jInvalidStateException This internal exception gets thrown + * when operations to the cache are performed but it hasn't been + * initialized. Make sure you call the setParameters method. + * + * @return The SOAP response, null if there are no corresponding + * response in the cache. + */ + public byte[] get( + String id, + URL url, + byte[] request) + throws XmlaOlap4jInvalidStateException; + + /** + * Adds a SOAP response to the cache. It has to be relative to the + * URL of the SOAP service. + * + * @param name The connection unique name which called this cache. + * @param url The URL of the SOAP endpoint. + * @param request The full SOAP message from which we want to cache its + * response. + * @param response The response to cache. + * + * @throws XmlaOlap4jInvalidStateException This internal exception gets thrown when + * operations to the cache are performed but it hasn't been initialized. + * Make sure you call the setParameters method. + */ + public void put( + String id, + URL url, + byte[] request, + byte[] response) throws XmlaOlap4jInvalidStateException; + + /** + * This tells the cache to flush all cached entries. + */ + public void flushCache(); + + /** + * Convenience method to receive custom properties. + * + *

The XMLA driver takes cache properties as + * "Cache.[property name]=[value]" in its JDBC url. All those + * properties should be striped of their "Cache." prefix and + * sent to this method as the properties parameter. + * + *

Also, the complete config map of the current connection + * should be passed as the config parameter. + * + * @param config The complete configuration parameters which were used to + * create the current connection. + * @param props The properties received from the JDBC url. + * @return Returns a string object which gives a reference id to the + * caller for future use. This id has to be passed along with any future + * get and put requests. + */ + public String setParameters( + Map config, + Map props); +} + +// End XmlaOlap4jCache.java diff --git a/src/org/olap4j/driver/xmla/cache/XmlaOlap4jCacheElement.java b/src/org/olap4j/driver/xmla/cache/XmlaOlap4jCacheElement.java index 3258e05..c822fed 100644 --- a/src/org/olap4j/driver/xmla/cache/XmlaOlap4jCacheElement.java +++ b/src/org/olap4j/driver/xmla/cache/XmlaOlap4jCacheElement.java @@ -1,69 +1,71 @@ -/* -// $Id: XmlaOlap4jCacheElement.java 92 2008-07-17 07:41:10Z lucboudreau $ -// This software is subject to the terms of the Common Public License -// Agreement, available at the following URL: -// http://www.opensource.org/licenses/cpl.html. -// Copyright (C) 2007-2007 Julian Hyde -// All Rights Reserved. -// You must accept the terms of that agreement to use this software. -*/ -package org.olap4j.driver.xmla.cache; - -import java.util.Calendar; -import java.util.concurrent.atomic.AtomicLong; - -/** - * Internal POJO class definition for the XmlaOlap4jMemoryCache. - * @author Luc Boudreau - * @version $Id: XmlaOlap4jCacheElement.java 92 2008-07-17 07:41:10Z lucboudreau $ - */ -class XmlaOlap4jCacheElement { - - /** - * The time in miliseconds when the entry was created. - */ - private AtomicLong timestamp = new AtomicLong(Calendar.getInstance().getTimeInMillis()); - - - /** - * This holds the number of times the entry was used. - */ - private AtomicLong hitMeter = new AtomicLong(new Long("1")); - - - /** - * The cached SOAP response. - */ - private byte[] response = null; - - - /** - * Updates it's internal time stamp. - */ - public void refreshTimestamp() { - this.timestamp.compareAndSet(this.timestamp.longValue(), Calendar.getInstance().getTimeInMillis()); - } - - /** - * Updates it's internal time stamp. - */ - public void incrementHitCount() { - this.hitMeter.incrementAndGet(); - } - - public byte[] getResponse() { - return response; - } - - public void setResponse(byte[] response) { - this.response = response; - } - - public AtomicLong getTimestamp() { - return timestamp; - } - - public AtomicLong getHitCount() { - return hitMeter; - } -} \ No newline at end of file +/* +// $Id: XmlaOlap4jCacheElement.java 92 2008-07-17 07:41:10Z lucboudreau $ +// This software is subject to the terms of the Common Public License +// Agreement, available at the following URL: +// http://www.opensource.org/licenses/cpl.html. +// Copyright (C) 2007-2007 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j.driver.xmla.cache; + +import java.util.Calendar; +import java.util.concurrent.atomic.AtomicLong; + +/** + * Internal POJO class definition for the XmlaOlap4jMemoryCache. + * @author Luc Boudreau + * @version $Id: XmlaOlap4jCacheElement.java 92 2008-07-17 07:41:10Z lucboudreau $ + */ +class XmlaOlap4jCacheElement { + + /** + * The time in miliseconds when the entry was created. + */ + private AtomicLong timestamp = new AtomicLong(Calendar.getInstance().getTimeInMillis()); + + + /** + * This holds the number of times the entry was used. + */ + private AtomicLong hitMeter = new AtomicLong(new Long("1")); + + + /** + * The cached SOAP response. + */ + private byte[] response = null; + + + /** + * Updates it's internal time stamp. + */ + public void refreshTimestamp() { + this.timestamp.compareAndSet(this.timestamp.longValue(), Calendar.getInstance().getTimeInMillis()); + } + + /** + * Updates it's internal time stamp. + */ + public void incrementHitCount() { + this.hitMeter.incrementAndGet(); + } + + public byte[] getResponse() { + return response; + } + + public void setResponse(byte[] response) { + this.response = response; + } + + public AtomicLong getTimestamp() { + return timestamp; + } + + public AtomicLong getHitCount() { + return hitMeter; + } +} + +// End XmlaOlap4jCacheElement.java diff --git a/src/org/olap4j/driver/xmla/cache/XmlaOlap4jConcurrentMemoryCache.java b/src/org/olap4j/driver/xmla/cache/XmlaOlap4jConcurrentMemoryCache.java index f8528dd..3d7f720 100644 --- a/src/org/olap4j/driver/xmla/cache/XmlaOlap4jConcurrentMemoryCache.java +++ b/src/org/olap4j/driver/xmla/cache/XmlaOlap4jConcurrentMemoryCache.java @@ -1,308 +1,311 @@ -/* -// $Id: XmlaOlap4jConcurrentMemoryCache.java 92 2008-07-17 07:41:10Z lucboudreau $ -// This software is subject to the terms of the Common Public License -// Agreement, available at the following URL: -// http://www.opensource.org/licenses/cpl.html. -// Copyright (C) 2007-2007 Julian Hyde -// All Rights Reserved. -// You must accept the terms of that agreement to use this software. -*/ -package org.olap4j.driver.xmla.cache; - -import java.net.*; -import java.util.*; -import java.util.Map.*; -import java.util.concurrent.*; - -import org.olap4j.driver.xmla.cache.XmlaOlap4jNamedMemoryCache.MODE; -import org.olap4j.driver.xmla.cache.XmlaOlap4jNamedMemoryCache.Property; - -/** - *

Thread-safe cache object which supports concurrent access. - *

It keeps it's cache element objects in memory in an internal hash - * table. Instantiate it and use. As simple as that. - * @author Luc Boudreau - * @version $Id: XmlaOlap4jConcurrentMemoryCache.java 92 2008-07-17 07:41:10Z lucboudreau $ - */ -class XmlaOlap4jConcurrentMemoryCache { - - /** - * This defines the default cache timeout of 1 minute. The value - * has to be in seconds. - */ - private final static int DEFAULT_CACHE_TIMEOUT = 60; - - - - - /** - * This defines the default cache size of 10. - */ - private final static int DEFAULT_CACHE_SIZE = 10; - - - - - - /** - * This defines the current eviction mode. Defaults to LFU. - */ - private final static MODE DEFAULT_EVICTION_MODE = MODE.LFU; - - - /** - *

Thread safe hashmap which will be used as a cache. - * - *

The cache is a map structured as follows : - * - *

    - *
  • key -> String : SHA-1 encoding of the full URL - */ - private Map cacheEntries = - new ConcurrentHashMap(); - - - /** - * Holds on to the current cache size - */ - private int cacheSize = DEFAULT_CACHE_SIZE; - - - /** - * Holds on to the current eviction mode - */ - private MODE evictionMode = DEFAULT_EVICTION_MODE; - - - /** - * Holds on to the current cache timeout - */ - private int cacheTimeout = DEFAULT_CACHE_TIMEOUT; - - - - - public XmlaOlap4jConcurrentMemoryCache(Map props) throws IllegalArgumentException { - for (Entry entry : props.entrySet()) { - if (Property.Size.name() - .equalsIgnoreCase(entry.getKey().toString())) { - this.setCacheSize( - Integer.parseInt(entry.getValue().toString())); - } else if (Property.Timeout.name() - .equalsIgnoreCase(entry.getKey().toString())) { - this.setCacheTimeout( - Integer.parseInt(entry.getValue().toString())); - } else if (Property.Mode.name() - .equalsIgnoreCase(entry.getKey().toString())) { - this.setCacheMode( - entry.getValue().toString()); - } - } - } - - /** - * Sets the number of cached entries. - * @param size The number of cached entries. - */ - private void setCacheSize(int size) { - if (size > 0) { - this.cacheSize = size; - } else { - throw new IllegalArgumentException( - "The XMLAOLap4jMemoryCache size cannot be less or equal to 0."); - } - } - - - - /** - * Sets the number of cached entries. - * @param size The number of cached entries. - */ - private void setCacheMode(String mode) { - if ( MODE.valueOf(mode) != null ) { - this.evictionMode = MODE.valueOf(mode); - } else { - throw new IllegalArgumentException( - "The XMLAOLap4jMemoryCache mode has to be one of XmlaOlap4jMemoryCache.MODE"); - } - } - - - - /** - * Sets the cache expiration timeout. - * @param seconds The number of seconds to hold the entries in cache. - */ - private void setCacheTimeout(int seconds) { - if (seconds > 0) { - this.cacheTimeout = seconds; - } else { - throw new IllegalArgumentException( - "The XMLAOLap4jMemoryCache timeout cannot be less or equal to 0."); - } - } - - - public byte[] get(final URL url, final byte[] request) { - // Take the cache for ourself - synchronized (this.cacheEntries) { - // Clean expired values - cleanExpired(false); - - // Extract the data from the cache - XmlaOlap4jCacheElement entry = this.cacheEntries.get( - XmlaOlap4jSHAEncoder.SHA1( url.toExternalForm() - + new String(request) ) ); - - // Increment it's counter - if (entry != null) { - entry.incrementHitCount(); - entry.refreshTimestamp(); - } - - // Return a copy to prevent corruption - return ( entry != null ) - ? new String(entry.getResponse()).getBytes() - : null; - } - } - - - public void put(final URL url, final byte[] request, - final byte[] response) - { - // Take the cache for ourself - synchronized (this.cacheEntries) { - // Make some cleanup - cleanExpired(true); - - if ( this.cacheEntries.size() < cacheSize ) { - // Create the entry - XmlaOlap4jCacheElement entry = new XmlaOlap4jCacheElement(); - entry.setResponse(response); - - this.cacheEntries.put( - XmlaOlap4jSHAEncoder.SHA1( - String.valueOf(url.toExternalForm()) - + new String(request) ), - entry ); - } else { - throw new RuntimeException("Concurrency error detected."); - } - } - } - - - /** - * Cleans expired cache entries. - * @param makeRoom Whether to make room for later appending by - * evicting an entry based on the selected eviction mode. - */ - private void cleanExpired(boolean makeRoom) { - - String toBeEvicted = null; - - if ( evictionMode == MODE.FIFO || evictionMode == MODE.LIFO ) - toBeEvicted = timeBasedEviction(makeRoom); - if ( evictionMode == MODE.LFU || evictionMode == MODE.MFU ) - toBeEvicted = hitBasedEviction(makeRoom); - - - // Make some space if required - if (makeRoom && this.cacheEntries.size() >= cacheSize - && toBeEvicted != null) - { - this.cacheEntries.remove(toBeEvicted); - } - } - - /** - * Scans for the key of the cache entry to be evicted based - * on the selected time based eviction mode. - * @param makeRoom Whether to make room for later appending by - * evicting an entry. if false is specified, there might not - * be an evicted entry if the cache is not full. - * @return The key of the entry to remove, null otherwise. - */ - private String timeBasedEviction(boolean makeRoom) - { - // This is a flag to find the oldest entry. - long currentEvictedTimestamp = evictionMode == MODE.LIFO - ? Long.MAX_VALUE - : Long.MIN_VALUE; - - String toBeEvicted = null; - - // Iterate over entries - for ( Entry entry - : this.cacheEntries.entrySet() ) - { - // Check if not expired - if ( Calendar.getInstance().getTimeInMillis() > - (entry.getValue().getTimestamp().longValue() + ( cacheTimeout * 1000 ) ) ) - { - // Evicts it. - this.cacheEntries.remove(entry.getKey()); - continue; - } - - // Checks if this is the oldest entry - if ( makeRoom && - (evictionMode == MODE.LIFO - && entry.getValue().getTimestamp().longValue() < currentEvictedTimestamp) - || (evictionMode == MODE.FIFO - && entry.getValue().getTimestamp().longValue() > currentEvictedTimestamp)) - { - currentEvictedTimestamp = entry.getValue().getTimestamp().longValue(); - toBeEvicted = entry.getKey(); - } - } - return toBeEvicted; - } - - - /** - * Scans for the key of the cache entry to be evicted based - * on the selected hit based eviction mode. - * @param makeRoom Whether to make room for later appending by evicting an entry. - * if false is specified, there might not be an evicted entry if the cache - * is not full. - * @return The key of the entry to remove, null otherwise. - */ - private String hitBasedEviction(boolean makeRoom) - { - // Flag to find the oldest entry. - long currentEvictedHits = (evictionMode == MODE.LFU) - ? Long.MAX_VALUE - : Long.MIN_VALUE; - - String toBeEvicted = null; - - // Iterates over entries - for ( Entry entry - : this.cacheEntries.entrySet() ) - { - // Checks if not expired - if ( Calendar.getInstance().getTimeInMillis() > - (entry.getValue().getTimestamp().longValue() + ( cacheTimeout * 1000 ) ) ) - { - // Evicts it - this.cacheEntries.remove(entry.getKey()); - continue; - } - - // Checks if this is the oldest entry - if ( makeRoom && - (evictionMode == MODE.LFU - && entry.getValue().getHitCount().longValue() < currentEvictedHits) - || (evictionMode == MODE.MFU - && entry.getValue().getHitCount().longValue() > currentEvictedHits)) - { - currentEvictedHits = entry.getValue().getHitCount().longValue(); - toBeEvicted = entry.getKey(); - } - } - return toBeEvicted; - } -} \ No newline at end of file +/* +// $Id: XmlaOlap4jConcurrentMemoryCache.java 92 2008-07-17 07:41:10Z lucboudreau $ +// This software is subject to the terms of the Common Public License +// Agreement, available at the following URL: +// http://www.opensource.org/licenses/cpl.html. +// Copyright (C) 2007-2007 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j.driver.xmla.cache; + +import java.net.*; +import java.util.*; +import java.util.Map.*; +import java.util.concurrent.*; + +import org.olap4j.driver.xmla.cache.XmlaOlap4jNamedMemoryCache.MODE; +import org.olap4j.driver.xmla.cache.XmlaOlap4jNamedMemoryCache.Property; + +/** + *

    Thread-safe cache object which supports concurrent access. + *

    It keeps it's cache element objects in memory in an internal hash + * table. Instantiate it and use. As simple as that. + * @author Luc Boudreau + * @version $Id: XmlaOlap4jConcurrentMemoryCache.java 92 2008-07-17 07:41:10Z lucboudreau $ + */ +class XmlaOlap4jConcurrentMemoryCache { + + /** + * This defines the default cache timeout of 1 minute. The value + * has to be in seconds. + */ + private final static int DEFAULT_CACHE_TIMEOUT = 60; + + + + + /** + * This defines the default cache size of 10. + */ + private final static int DEFAULT_CACHE_SIZE = 10; + + + + + + /** + * This defines the current eviction mode. Defaults to LFU. + */ + private final static MODE DEFAULT_EVICTION_MODE = MODE.LFU; + + + /** + *

    Thread safe hashmap which will be used as a cache. + * + *

    The cache is a map structured as follows : + * + *

      + *
    • key -> String : SHA-1 encoding of the full URL + */ + private Map cacheEntries = + new ConcurrentHashMap(); + + + /** + * Holds on to the current cache size + */ + private int cacheSize = DEFAULT_CACHE_SIZE; + + + /** + * Holds on to the current eviction mode + */ + private MODE evictionMode = DEFAULT_EVICTION_MODE; + + + /** + * Holds on to the current cache timeout + */ + private int cacheTimeout = DEFAULT_CACHE_TIMEOUT; + + + + + public XmlaOlap4jConcurrentMemoryCache(Map props) throws IllegalArgumentException { + for (Entry entry : props.entrySet()) { + if (Property.Size.name() + .equalsIgnoreCase(entry.getKey().toString())) { + this.setCacheSize( + Integer.parseInt(entry.getValue().toString())); + } else if (Property.Timeout.name() + .equalsIgnoreCase(entry.getKey().toString())) { + this.setCacheTimeout( + Integer.parseInt(entry.getValue().toString())); + } else if (Property.Mode.name() + .equalsIgnoreCase(entry.getKey().toString())) { + this.setCacheMode( + entry.getValue().toString()); + } + } + } + + /** + * Sets the number of cached entries. + * @param size The number of cached entries. + */ + private void setCacheSize(int size) { + if (size > 0) { + this.cacheSize = size; + } else { + throw new IllegalArgumentException( + "The XMLAOLap4jMemoryCache size cannot be less or equal to 0."); + } + } + + + + /** + * Sets the number of cached entries. + * @param size The number of cached entries. + */ + private void setCacheMode(String mode) { + if (MODE.valueOf(mode) != null) { + this.evictionMode = MODE.valueOf(mode); + } else { + throw new IllegalArgumentException( + "The XMLAOLap4jMemoryCache mode has to be one of XmlaOlap4jMemoryCache.MODE"); + } + } + + + + /** + * Sets the cache expiration timeout. + * @param seconds The number of seconds to hold the entries in cache. + */ + private void setCacheTimeout(int seconds) { + if (seconds > 0) { + this.cacheTimeout = seconds; + } else { + throw new IllegalArgumentException( + "The XMLAOLap4jMemoryCache timeout cannot be less or equal to 0."); + } + } + + + public byte[] get(final URL url, final byte[] request) { + // Take the cache for ourself + synchronized (this.cacheEntries) { + // Clean expired values + cleanExpired(false); + + // Extract the data from the cache + XmlaOlap4jCacheElement entry = this.cacheEntries.get( + XmlaOlap4jSHAEncoder.SHA1( + url.toExternalForm() + new String(request))); + + // Increment its counter + if (entry != null) { + entry.incrementHitCount(); + entry.refreshTimestamp(); + } + + // Return a copy to prevent corruption + return entry != null + ? new String(entry.getResponse()).getBytes() + : null; + } + } + + + public void put(final URL url, final byte[] request, + final byte[] response) + { + // Take the cache for ourself + synchronized (this.cacheEntries) { + // Make some cleanup + cleanExpired(true); + + if (this.cacheEntries.size() < cacheSize) { + // Create the entry + XmlaOlap4jCacheElement entry = new XmlaOlap4jCacheElement(); + entry.setResponse(response); + + this.cacheEntries.put( + XmlaOlap4jSHAEncoder.SHA1( + String.valueOf(url.toExternalForm()) + + new String(request)), + entry); + } else { + throw new RuntimeException("Concurrency error detected."); + } + } + } + + + /** + * Cleans expired cache entries. + * @param makeRoom Whether to make room for later appending by + * evicting an entry based on the selected eviction mode. + */ + private void cleanExpired(boolean makeRoom) { + + String toBeEvicted = null; + + if (evictionMode == MODE.FIFO || evictionMode == MODE.LIFO) { + toBeEvicted = timeBasedEviction(makeRoom); + } + if (evictionMode == MODE.LFU || evictionMode == MODE.MFU) { + toBeEvicted = hitBasedEviction(makeRoom); + } + + // Make some space if required + if (makeRoom && this.cacheEntries.size() >= cacheSize + && toBeEvicted != null) + { + this.cacheEntries.remove(toBeEvicted); + } + } + + /** + * Scans for the key of the cache entry to be evicted based + * on the selected time based eviction mode. + * @param makeRoom Whether to make room for later appending by + * evicting an entry. if false is specified, there might not + * be an evicted entry if the cache is not full. + * @return The key of the entry to remove, null otherwise. + */ + private String timeBasedEviction(boolean makeRoom) + { + // This is a flag to find the oldest entry. + long currentEvictedTimestamp = evictionMode == MODE.LIFO + ? Long.MAX_VALUE + : Long.MIN_VALUE; + + String toBeEvicted = null; + + // Iterate over entries + for (Entry entry + : this.cacheEntries.entrySet()) + { + // Check if not expired + if (Calendar.getInstance().getTimeInMillis() > + (entry.getValue().getTimestamp().longValue() + (cacheTimeout * 1000))) + { + // Evicts it. + this.cacheEntries.remove(entry.getKey()); + continue; + } + + // Checks if this is the oldest entry + if (makeRoom && + (evictionMode == MODE.LIFO + && entry.getValue().getTimestamp().longValue() < currentEvictedTimestamp) + || (evictionMode == MODE.FIFO + && entry.getValue().getTimestamp().longValue() > currentEvictedTimestamp)) + { + currentEvictedTimestamp = entry.getValue().getTimestamp().longValue(); + toBeEvicted = entry.getKey(); + } + } + return toBeEvicted; + } + + + /** + * Scans for the key of the cache entry to be evicted based + * on the selected hit based eviction mode. + * @param makeRoom Whether to make room for later appending by evicting an entry. + * if false is specified, there might not be an evicted entry if the cache + * is not full. + * @return The key of the entry to remove, null otherwise. + */ + private String hitBasedEviction(boolean makeRoom) + { + // Flag to find the oldest entry. + long currentEvictedHits = (evictionMode == MODE.LFU) + ? Long.MAX_VALUE + : Long.MIN_VALUE; + + String toBeEvicted = null; + + // Iterates over entries + for (Entry entry + : this.cacheEntries.entrySet()) + { + // Checks if not expired + if (Calendar.getInstance().getTimeInMillis() > + (entry.getValue().getTimestamp().longValue() + (cacheTimeout * 1000))) + { + // Evicts it + this.cacheEntries.remove(entry.getKey()); + continue; + } + + // Checks if this is the oldest entry + if (makeRoom && + (evictionMode == MODE.LFU + && entry.getValue().getHitCount().longValue() < currentEvictedHits) + || (evictionMode == MODE.MFU + && entry.getValue().getHitCount().longValue() > currentEvictedHits)) + { + currentEvictedHits = entry.getValue().getHitCount().longValue(); + toBeEvicted = entry.getKey(); + } + } + return toBeEvicted; + } +} + +// End XmlaOlap4jConcurrentMemoryCache.java diff --git a/src/org/olap4j/driver/xmla/cache/XmlaOlap4jInvalidStateException.java b/src/org/olap4j/driver/xmla/cache/XmlaOlap4jInvalidStateException.java index 9442c25..5c8734d 100644 --- a/src/org/olap4j/driver/xmla/cache/XmlaOlap4jInvalidStateException.java +++ b/src/org/olap4j/driver/xmla/cache/XmlaOlap4jInvalidStateException.java @@ -1,25 +1,27 @@ -/* -// $Id: InvalidStateException.java 92 2008-07-17 07:41:10Z lucboudreau $ -// This software is subject to the terms of the Common Public License -// Agreement, available at the following URL: -// http://www.opensource.org/licenses/cpl.html. -// Copyright (C) 2007-2007 Julian Hyde -// All Rights Reserved. -// You must accept the terms of that agreement to use this software. -*/ -package org.olap4j.driver.xmla.cache; - -/** - *

      Internal exception which gets thrown when operations to the cache - * are performed but it hasn't been initialized. - * - *

      It extends RuntimeException so it cannot be catched by the - * regular catch(Exception) mechanism. Those exceptions should get right - * to the system level since it's a programming error. - * - * @author Luc Boudreau - * @version $Id: InvalidStateException.java 92 2008-07-17 07:41:10Z lucboudreau $ - */ -public class XmlaOlap4jInvalidStateException extends RuntimeException { - private static final long serialVersionUID = 7265273715459263740L; -} \ No newline at end of file +/* +// $Id: InvalidStateException.java 92 2008-07-17 07:41:10Z lucboudreau $ +// This software is subject to the terms of the Common Public License +// Agreement, available at the following URL: +// http://www.opensource.org/licenses/cpl.html. +// Copyright (C) 2007-2007 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j.driver.xmla.cache; + +/** + *

      Internal exception which gets thrown when operations to the cache + * are performed but it hasn't been initialized. + * + *

      It extends RuntimeException so it cannot be catched by the + * regular catch(Exception) mechanism. Those exceptions should get right + * to the system level since it's a programming error. + * + * @author Luc Boudreau + * @version $Id: InvalidStateException.java 92 2008-07-17 07:41:10Z lucboudreau $ + */ +public class XmlaOlap4jInvalidStateException extends RuntimeException { + private static final long serialVersionUID = 7265273715459263740L; +} + +// End XmlaOlap4jInvalidStateException.java diff --git a/src/org/olap4j/driver/xmla/cache/XmlaOlap4jNamedMemoryCache.java b/src/org/olap4j/driver/xmla/cache/XmlaOlap4jNamedMemoryCache.java index 9f535bc..4d1e8fd 100644 --- a/src/org/olap4j/driver/xmla/cache/XmlaOlap4jNamedMemoryCache.java +++ b/src/org/olap4j/driver/xmla/cache/XmlaOlap4jNamedMemoryCache.java @@ -1,231 +1,236 @@ -/* -// $Id: XmlaOlap4jNamedMemoryCache.java 92 2008-07-17 07:41:10Z lucboudreau $ -// This software is subject to the terms of the Common Public License -// Agreement, available at the following URL: -// http://www.opensource.org/licenses/cpl.html. -// Copyright (C) 2007-2007 Julian Hyde -// All Rights Reserved. -// You must accept the terms of that agreement to use this software. -*/ -package org.olap4j.driver.xmla.cache; - -import java.net.*; -import java.util.*; -import java.util.concurrent.*; - -import org.olap4j.impl.Olap4jUtil; - -/** - *

      Implementation of the XMLA SOAP cache places it's cache entries - * in memory for later use. It is thread safe and at static class level. - * - *

      It supports cache sharing through the Name property. - * - *

      All parameters are optional. - * - *

        - *
      • Name
        A unique identifier which allows two connections - * to share a same cache space. Setting this to an already existing cache - * space will cause the cache manager to ignore other configuration properties, - * such as eviction mode and so on. Not setting this property will - * assign a random name to the cache space, thus creating a unique space.
      • - *
      • Size
        The number of entries to maintain in cache under - * the given cache name.
      • - *
      • Timeout
        The number of seconds to maintain entries in - * cache before expiration.
      • - *
      • Mode
        Supported eviction modes are LIFO (last in first out), - * FIFO (first in first out), LFU (least frequently used) and MFU - * (most frequently used)
      • - *
      - * - * @see XmlaOlap4jNamedMemoryCache.Properties - * @version $Id: XmlaOlap4jNamedMemoryCache.java 92 2008-07-17 07:41:10Z lucboudreau $ - */ -public class XmlaOlap4jNamedMemoryCache implements XmlaOlap4jCache { - - /** - *

      Thread safe hashmap which will be used to keep track of - * the current caches. The unique ID is the URL. - */ - private static Map caches = null; - - - /** - * Properties which will be considered for configuration. - * - *

      All parameters are optional. - * - *

        - *
      • Name
        A unique identifier which allows two connections - * to share a same cache space. Setting this to an already existing cache - * space will cause the cache manager to ignore other configuration - * properties, such as eviction mode and so on. Not setting this property will - * assign a random name to the cache space, thus creating a unique - * space.
      • - *
      • Size
        The number of entries to maintain in cache under - * the given cache name.
      • - *
      • Timeout
        The number of seconds to maintain - * entries in cache before expiration.
      • - *
      • Mode
        Supported eviction modes are - * LIFO (last in first out), FIFO (first in first out), - * LFU (least frequently used) and MFU (most frequently used)
      • - *
      - */ - public static enum Property { - Name("Name of a cache to create or to share."), - Size("Maximum number of SOAP requests which will be cached under the given cache name."), - Timeout("Maximum TTL of SOAP requests which will be cached under the given cache name."), - Mode("Eviction mode to set to the given cache name."); - - /** - * Creates a property. - * - * @param description Description of property - */ - Property(String description) { - Olap4jUtil.discard(description); - } - } - - - /** - * Defines the supported eviction modes. - */ - public static enum MODE { - LIFO, - FIFO, - LFU, - MFU - } - - - /** - * Makes sure that the cache is not accessed before it is configured. - */ - private boolean initDone = false; - - - /** - * Default constructor which instantiates the concurrent hash map. - */ - public XmlaOlap4jNamedMemoryCache() { - XmlaOlap4jNamedMemoryCache.initCaches(); - } - - - /** - * Initializes the caches in a static and thread safe way. - */ - private static synchronized void initCaches() { - if ( caches == null ) { - caches = new ConcurrentHashMap(); - } - - } - - - /* (non-Javadoc) - * @see org.olap4j.driver.xmla.cache.IXmlaOlap4jCache - * #setParameters(java.util.Properties) - */ - public String setParameters(final Map config, - final Map props) - { - String refId; - - // Make sure there's a name for the cache. Generate a - // random one if needed. - if (props.containsKey( - XmlaOlap4jNamedMemoryCache.Property.Name.name())) - { - refId = (String)props.get( - XmlaOlap4jNamedMemoryCache.Property.Name.name()); - } else { - refId = String.valueOf(UUID.randomUUID ( )); - props.put(XmlaOlap4jNamedMemoryCache.Property.Name.name(), refId); - } - - - // Wait for exclusive access to the caches - synchronized (caches) { - // Create a cache for this URL if it is not created yet - if ( !caches.containsKey(props.get( - XmlaOlap4jNamedMemoryCache.Property.Name.name())) ) { - caches.put( - (String)props.get( - XmlaOlap4jNamedMemoryCache.Property.Name.name()), - new XmlaOlap4jConcurrentMemoryCache(props)); - } - } - - // Mark this cache as inited. - this.initDone = true; - - // Give back the reference id. - return refId; - } - - - /* (non-Javadoc) - * @see org.olap4j.driver.xmla.cache.IXmlaOlap4jCache - * #get(java.lang.String, java.net.URL, byte[]) - */ - public byte[] get(String id, URL url, byte[] request) - throws XmlaOlap4jInvalidStateException - { - this.validateState(); - - // Wait for exclusive access to the caches - synchronized (caches) { - if ( caches.containsKey(id) ) { - return caches.get(id).get(url, request); - } else { - throw new RuntimeException( - "There are no configured caches of this name yet configured."); - } - } - } - - - /* (non-Javadoc) - * @see org.olap4j.driver.xmla.cache.IXmlaOlap4jCache - * #put(java.lang.String, java.net.URL, byte[], byte[]) - */ - public void put(String id, URL url, byte[] request, byte[] response) - throws XmlaOlap4jInvalidStateException - { - this.validateState(); - - // Wait for exclusive access to the caches - synchronized (caches) { - if ( caches.containsKey(id) ) { - caches.get(id).put(url, request, response); - } else { - throw new RuntimeException( - "There are no configured caches of this name yet configured."); - } - } - } - - - /* (non-Javadoc) - * @see org.olap4j.driver.xmla.cache.IXmlaOlap4jCache#flushCache() - */ - public void flushCache() { - // Wait for exclusive access to the caches - synchronized (caches) { - caches.clear(); - } - } - - - /** - * Helper method to validate that the cache is initialized. - * @throws XmlaOlap4jInvalidStateException When the cache is not initialized. - */ - private void validateState() throws XmlaOlap4jInvalidStateException { - if (!this.initDone) { - throw new XmlaOlap4jInvalidStateException(); - } - } -} +/* +// $Id: XmlaOlap4jNamedMemoryCache.java 92 2008-07-17 07:41:10Z lucboudreau $ +// This software is subject to the terms of the Common Public License +// Agreement, available at the following URL: +// http://www.opensource.org/licenses/cpl.html. +// Copyright (C) 2007-2007 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j.driver.xmla.cache; + +import java.net.*; +import java.util.*; +import java.util.concurrent.*; + +import org.olap4j.impl.Olap4jUtil; + +/** + *

      Implementation of the XMLA SOAP cache places it's cache entries + * in memory for later use. It is thread safe and at static class level. + * + *

      It supports cache sharing through the Name property. + * + *

      All parameters are optional. + * + *

        + *
      • Name
        A unique identifier which allows two connections + * to share a same cache space. Setting this to an already existing cache + * space will cause the cache manager to ignore other configuration properties, + * such as eviction mode and so on. Not setting this property will + * assign a random name to the cache space, thus creating a unique space.
      • + *
      • Size
        The number of entries to maintain in cache under + * the given cache name.
      • + *
      • Timeout
        The number of seconds to maintain entries in + * cache before expiration.
      • + *
      • Mode
        Supported eviction modes are LIFO (last in first out), + * FIFO (first in first out), LFU (least frequently used) and MFU + * (most frequently used)
      • + *
      + * + * @see XmlaOlap4jNamedMemoryCache.Property + * @version $Id: XmlaOlap4jNamedMemoryCache.java 92 2008-07-17 07:41:10Z lucboudreau $ + */ +public class XmlaOlap4jNamedMemoryCache implements XmlaOlap4jCache { + + /** + *

      Thread safe hashmap which will be used to keep track of + * the current caches. The unique ID is the URL. + */ + private static Map caches = null; + + /** + * Properties which will be considered for configuration. + * + *

      All parameters are optional. + */ + public static enum Property { + /** + * A unique identifier which allows two connections to share a same + * cache space. Setting this to an already existing cache + * space will cause the cache manager to ignore other configuration + * properties, such as eviction mode and so on. Not setting this + * property will assign a random name to the cache space, thus creating + * a unique space. + */ + Name("Name of a cache to create or to share."), + + /** + * The number of entries to maintain in cache under + * the given cache name. + */ + Size("Maximum number of SOAP requests which will be cached under the given cache name."), + + /** + * The number of seconds to maintain + * entries in cache before expiration. + */ + Timeout("Maximum TTL of SOAP requests which will be cached under the given cache name."), + + /** + * Eviction mode. Supported eviction modes are + * LIFO (last in first out), FIFO (first in first out), + * LFU (least frequently used) and MFU (most frequently used). + */ + Mode("Eviction mode to set to the given cache name."); + + /** + * Creates a property. + * + * @param description Description of property + */ + Property(String description) { + Olap4jUtil.discard(description); + } + } + + + /** + * Defines the supported eviction modes. + */ + public static enum MODE { + LIFO, + FIFO, + LFU, + MFU + } + + + /** + * Makes sure that the cache is not accessed before it is configured. + */ + private boolean initDone = false; + + + /** + * Default constructor which instantiates the concurrent hash map. + */ + public XmlaOlap4jNamedMemoryCache() { + XmlaOlap4jNamedMemoryCache.initCaches(); + } + + + /** + * Initializes the caches in a static and thread safe way. + */ + private static synchronized void initCaches() { + if (caches == null) { + caches = new ConcurrentHashMap(); + } + + } + + // implement XmlaOlap4jCache + public String setParameters( + Map config, + Map props) + { + String refId; + + // Make sure there's a name for the cache. Generate a + // random one if needed. + if (props.containsKey( + XmlaOlap4jNamedMemoryCache.Property.Name.name())) + { + refId = (String)props.get( + XmlaOlap4jNamedMemoryCache.Property.Name.name()); + } else { + refId = String.valueOf(UUID.randomUUID()); + props.put(XmlaOlap4jNamedMemoryCache.Property.Name.name(), refId); + } + + + // Wait for exclusive access to the caches + synchronized (caches) { + // Create a cache for this URL if it is not created yet + if (!caches.containsKey( + props.get( + XmlaOlap4jNamedMemoryCache.Property.Name.name()))) { + caches.put( + (String) props.get( + XmlaOlap4jNamedMemoryCache.Property.Name.name()), + new XmlaOlap4jConcurrentMemoryCache(props)); + } + } + + // Mark this cache as inited. + this.initDone = true; + + // Give back the reference id. + return refId; + } + + + // implement XmlaOlap4jCache + public byte[] get( + String id, + URL url, + byte[] request) + throws XmlaOlap4jInvalidStateException + { + this.validateState(); + + // Wait for exclusive access to the caches + synchronized (caches) { + if (caches.containsKey(id)) { + return caches.get(id).get(url, request); + } else { + throw new RuntimeException( + "There are no configured caches of this name yet configured."); + } + } + } + + + // implement XmlaOlap4jCache + public void put( + String id, + URL url, + byte[] request, + byte[] response) + throws XmlaOlap4jInvalidStateException + { + this.validateState(); + + // Wait for exclusive access to the caches + synchronized (caches) { + if (caches.containsKey(id)) { + caches.get(id).put(url, request, response); + } else { + throw new RuntimeException( + "There are no configured caches of this name yet configured."); + } + } + } + + // implement XmlaOlap4jCache + public void flushCache() { + // Wait for exclusive access to the caches + synchronized (caches) { + caches.clear(); + } + } + + /** + * Helper method to validate that the cache is initialized. + * + * @throws XmlaOlap4jInvalidStateException When the cache is not initialized. + */ + private void validateState() throws XmlaOlap4jInvalidStateException { + if (!this.initDone) { + throw new XmlaOlap4jInvalidStateException(); + } + } +} + +// End XmlaOlap4jNamedMemoryCache.java diff --git a/src/org/olap4j/driver/xmla/cache/XmlaOlap4jSHAEncoder.java b/src/org/olap4j/driver/xmla/cache/XmlaOlap4jSHAEncoder.java index 9c3acf5..e611857 100644 --- a/src/org/olap4j/driver/xmla/cache/XmlaOlap4jSHAEncoder.java +++ b/src/org/olap4j/driver/xmla/cache/XmlaOlap4jSHAEncoder.java @@ -1,64 +1,63 @@ -/* -// $Id: XmlaOlap4jSHAEncoder.java 92 2008-07-17 07:41:10Z lucboudreau $ -// This software is subject to the terms of the Common Public License -// Agreement, available at the following URL: -// http://www.opensource.org/licenses/cpl.html. -// Copyright (C) 2007-2007 Julian Hyde -// All Rights Reserved. -// You must accept the terms of that agreement to use this software. -*/ -package org.olap4j.driver.xmla.cache; - -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - -/** - * SHA encoder to create unique hash strings for cache elements. - * - * @author Luc Boudreau - * @version $Id: XmlaOlap4jSHAEncoder.java 92 2008-07-17 07:41:10Z lucboudreau $ - * - */ -public class XmlaOlap4jSHAEncoder { - - private static String convertToHex(byte[] data) { - - StringBuffer buf = new StringBuffer(); - - for (int i = 0; i < data.length; i++) { - int halfbyte = (data[i] >>> 4) & 0x0F; - int two_halfs = 0; - do { - if ((0 <= halfbyte) && (halfbyte <= 9)) - buf.append((char) ('0' + halfbyte)); - else - buf.append((char) ('a' + (halfbyte - 10))); - halfbyte = data[i] & 0x0F; - } while (two_halfs++ < 1); - } - return buf.toString(); - } - - public static String SHA1(String text) { - - MessageDigest md; - - try { - md = MessageDigest.getInstance("SHA-1"); - } catch (NoSuchAlgorithmException e) { - try { - md = MessageDigest.getInstance("MD5"); - } catch (NoSuchAlgorithmException e1) { - throw new RuntimeException(e1); - } - } - - byte[] sha1hash = new byte[40]; - - md.update(text.getBytes(), 0, text.length()); - - sha1hash = md.digest(); - - return convertToHex(sha1hash); - } -} +/* +// $Id: XmlaOlap4jSHAEncoder.java 92 2008-07-17 07:41:10Z lucboudreau $ +// This software is subject to the terms of the Common Public License +// Agreement, available at the following URL: +// http://www.opensource.org/licenses/cpl.html. +// Copyright (C) 2007-2007 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j.driver.xmla.cache; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * SHA encoder to create unique hash strings for cache elements. + * + * @author Luc Boudreau + * @version $Id: XmlaOlap4jSHAEncoder.java 92 2008-07-17 07:41:10Z lucboudreau $ + * + */ +public class XmlaOlap4jSHAEncoder { + + private static String convertToHex(byte[] data) { + StringBuilder buf = new StringBuilder(); + for (int i = 0; i < data.length; i++) { + int halfbyte = (data[i] >>> 4) & 0x0F; + int two_halfs = 0; + do { + if ((0 <= halfbyte) && (halfbyte <= 9)) { + buf.append((char) ('0' + halfbyte)); + } else { + buf.append((char) ('a' + (halfbyte - 10))); + } + halfbyte = data[i] & 0x0F; + } while (two_halfs++ < 1); + } + return buf.toString(); + } + + public static String SHA1(String text) { + MessageDigest md; + try { + md = MessageDigest.getInstance("SHA-1"); + } catch (NoSuchAlgorithmException e) { + try { + md = MessageDigest.getInstance("MD5"); + } catch (NoSuchAlgorithmException e1) { + throw new RuntimeException(e1); + } + } + + byte[] sha1hash = new byte[40]; + + md.update(text.getBytes(), 0, text.length()); + + sha1hash = md.digest(); + + return convertToHex(sha1hash); + } +} + +// End XmlaOlap4jSHAEncoder.java diff --git a/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jAbstractHttpProxy.java b/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jAbstractHttpProxy.java index 258fd24..bfc2501 100644 --- a/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jAbstractHttpProxy.java +++ b/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jAbstractHttpProxy.java @@ -1,245 +1,231 @@ -/* -// $Id: AbstractHttpProxy.java 92 2008-07-17 07:41:10Z lucboudreau $ -// This software is subject to the terms of the Common Public License -// Agreement, available at the following URL: -// http://www.opensource.org/licenses/cpl.html. -// Copyright (C) 2007-2007 Julian Hyde -// All Rights Reserved. -// You must accept the terms of that agreement to use this software. -*/ -package org.olap4j.driver.xmla.proxy; - -import java.io.*; -import java.net.*; -import java.util.*; -import java.util.concurrent.*; - -import org.olap4j.OlapException; -import org.olap4j.driver.xmla.XmlaOlap4jDriver; -import org.olap4j.driver.xmla.cache.XmlaOlap4jCache; - -/** - *

      Abstract implementation of Proxy which adds a SOAP - * cache layer between the driver and it's proxy implementations. - * It can be configured via the setCache() method, as instructed in - * CachedProxy interface. - * - *

      It also offers helper methods to keep track of - * the HTTP cookies and sends them back - * to the server along with queries. The useful methods are - * saveCookies(URL) and useCookies(URL). - * - * @author Luc Boudreau - * @version $Id: AbstractHttpProxy.java 92 2008-07-17 07:41:10Z lucboudreau $ - */ -public abstract class XmlaOlap4jAbstractHttpProxy implements XmlaOlap4jCachedProxy -{ - /** - * Holds on to the cache implementation. - */ - private XmlaOlap4jCache cache = null; - - - /** - * Holds on to the connection name which is associated to this proxy. - */ - private String cacheId; - - - /** - * Keeps a link to the cookie manager instance. - */ - private XmlaOlap4jCookieManager cookieManager = null; - - - /** - * Sends a request to a URL and returns the response. - * - * @param name The connection name which requested this execution - * @param url Target URL - * @param request Request string - * @return Response - * @throws IOException - */ - abstract public byte[] getResponse(URL url, String request) - throws IOException; - - - /** - * Submits a request for background execution. - * - * @param name The connection name which requested this execution - * @param url URL - * @param request Request - * @return Future object representing the submitted job - */ - abstract public Future getResponseViaSubmit(final URL url, - final String request); - - - /** - * Helper method to save cookies for later use. - * @param urlConn The url connection for which we want the cookies - * saved for later use. - * @throws IOException An io exception gets thrown if the given url - * connection has not been opened yet. - */ - protected void useCookies(URLConnection urlConn) throws IOException { - // Initializes the cookie manager - this.initCookieManager(); - - // Saves the current cookies - this.cookieManager.setCookies(urlConn); - } - - - /** - * Helper method to add cookies to a given connection. - * @param urlConn The url connection to which we want the cookies - * applied to. - * @throws IOException An io exception gets thrown if the given url - * connection has already been opened. - */ - protected void saveCookies(URLConnection urlConn) throws IOException { - // Initializes the cookie manager - this.initCookieManager(); - - // Saves the current cookies - this.cookieManager.storeCookies(urlConn); - } - - - /* (non-Javadoc) - * @see org.olap4j.driver.xmla.XmlaOlap4jDriver.Proxy#setCache( - * java.lang.String, java.util.Properties) - */ - @SuppressWarnings("unchecked") - public void setCache(Map config, Map properties) - throws OlapException - { - try { - // Loads the cache class - Class clazz = Class.forName(config.get( - XmlaOlap4jDriver.Property.Cache.name())); - - // Instantiates it - this.cache = (XmlaOlap4jCache) clazz.newInstance(); - - // Configures it - this.cacheId = this.cache.setParameters(config, properties); - } - catch (ClassNotFoundException e) { - throw new OlapException( - "The specified cache class name could not be found : " - + config.get(XmlaOlap4jDriver.Property.Cache.name()), e); - } - catch (InstantiationException e) { - throw new OlapException( - "The specified cache class name could not be instanciated : " - + config.get(XmlaOlap4jDriver.Property.Cache.name()), e); - } - catch (IllegalAccessException e) { - throw new OlapException( - "An error was encountered while instanciating the cache : " - + config.get(XmlaOlap4jDriver.Property.Cache.name()), e); - } - catch (IllegalArgumentException e) { - throw new OlapException( - "An error was encountered while instanciating the cache : " - + config.get(XmlaOlap4jDriver.Property.Cache.name()), e); - } - catch (SecurityException e) { - throw new OlapException( - "An error was encountered while instanciating the cache : " - + config.get(XmlaOlap4jDriver.Property.Cache.name()), e); - } - } - - - - /* (non-Javadoc) - * @see org.olap4j.driver.xmla.XmlaOlap4jDriver.Proxy#get( - * java.net.URL, java.lang.String) - */ - public byte[] get(URL url, String request) throws IOException { - - byte[] response; - - // Tries to fetch from cache - response = getFromCache(url, - request.getBytes(getEncodingCharsetName())); - - // Returns the cached value if found - if ( response != null ) - { - return response; - } - - // Executes the query - response = getResponse(url, request); - - // Adds to cache - addToCache(url, - request.getBytes(getEncodingCharsetName()), response); - - // Returns result - return response; - } - - - /** - * Tries to fetch a cached response from the cache implementation. - * @param url The url used to send the - * @param request - * @return returns either a response in a byte array or null - * if the response - */ - private byte[] getFromCache(final URL url, final byte[] request) { - return (this.cache != null) - ? this.cache.get(this.cacheId, url, request) - : null; - } - - - /** - * Caches an entry using the current cache implementation. - * @param url The URL from which originated the request - * @param request The SOAP request to cache - * @param response The SOAP response to cache - */ - private void addToCache(URL url, byte[] request, byte[] response) { - if (this.cache != null) { - this.cache.put(this.cacheId, url, request, response); - } - } - - - - /* (non-Javadoc) - * @see org.olap4j.driver.xmla.XmlaOlap4jDriver.Proxy - * #submit(java.net.URL, java.lang.String) - */ - public Future submit( final URL url, final String request) { - - /* - * The submit operation doesn't need to be cached yet, since it will call the - * get operation to fetch the data later on. It will get cached then. - * - * I still overridden the submit method in case we need some caching done - * in the end. - */ - return getResponseViaSubmit(url, request); - } - - - /** - * Initializes the cookie manager. It is not initialized - * by default because some proxy implementation might not need this - * functionnality. - */ - private void initCookieManager() { - if (this.cookieManager == null) { - this.cookieManager = new XmlaOlap4jCookieManager(); - } - } -} \ No newline at end of file +/* +// $Id: AbstractHttpProxy.java 92 2008-07-17 07:41:10Z lucboudreau $ +// This software is subject to the terms of the Common Public License +// Agreement, available at the following URL: +// http://www.opensource.org/licenses/cpl.html. +// Copyright (C) 2007-2007 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j.driver.xmla.proxy; + +import java.io.*; +import java.net.*; +import java.util.*; +import java.util.concurrent.*; + +import org.olap4j.OlapException; +import org.olap4j.driver.xmla.XmlaOlap4jDriver; +import org.olap4j.driver.xmla.cache.XmlaOlap4jCache; + +/** + *

      Abstract implementation of Proxy which adds a SOAP + * cache layer between the driver and it's proxy implementations. + * It can be configured via the setCache() method, as instructed in + * CachedProxy interface. + * + *

      It also offers helper methods to keep track of + * the HTTP cookies and sends them back + * to the server along with queries. The useful methods are + * saveCookies(URL) and useCookies(URL). + * + * @author Luc Boudreau + * @version $Id: AbstractHttpProxy.java 92 2008-07-17 07:41:10Z lucboudreau $ + */ +public abstract class XmlaOlap4jAbstractHttpProxy + implements XmlaOlap4jCachedProxy +{ + /** + * Holds on to the cache implementation. + */ + private XmlaOlap4jCache cache = null; + + + /** + * Holds on to the connection name which is associated to this proxy. + */ + private String cacheId; + + + /** + * Keeps a link to the cookie manager instance. + */ + private XmlaOlap4jCookieManager cookieManager = null; + + + /** + * Sends a request to a URL and returns the response. + * + * @param url Target URL + * @param request Request string + * @return Response + * @throws IOException + */ + abstract public byte[] getResponse(URL url, String request) + throws IOException; + + + /** + * Submits a request for background execution. + * + * @param url URL + * @param request Request + * @return Future object representing the submitted job + */ + abstract public Future getResponseViaSubmit( + URL url, + String request); + + /** + * Helper method to save cookies for later use. + * @param urlConn The url connection for which we want the cookies + * saved for later use. + * @throws IOException An io exception gets thrown if the given url + * connection has not been opened yet. + */ + protected void useCookies(URLConnection urlConn) throws IOException { + // Initializes the cookie manager + this.initCookieManager(); + + // Saves the current cookies + this.cookieManager.setCookies(urlConn); + } + + + /** + * Helper method to add cookies to a given connection. + * @param urlConn The url connection to which we want the cookies + * applied to. + * @throws IOException An io exception gets thrown if the given url + * connection has already been opened. + */ + protected void saveCookies(URLConnection urlConn) throws IOException { + // Initializes the cookie manager + this.initCookieManager(); + + // Saves the current cookies + this.cookieManager.storeCookies(urlConn); + } + + + /* (non-Javadoc) + * @see org.olap4j.driver.xmla.XmlaOlap4jDriver.Proxy#setCache( + * java.lang.String, java.util.Properties) + */ + @SuppressWarnings("unchecked") + public void setCache(Map config, Map properties) + throws OlapException + { + try { + // Loads the cache class + Class clazz = Class.forName(config.get( + XmlaOlap4jDriver.Property.Cache.name())); + + // Instantiates it + this.cache = (XmlaOlap4jCache) clazz.newInstance(); + + // Configures it + this.cacheId = this.cache.setParameters(config, properties); + } catch (ClassNotFoundException e) { + throw new OlapException( + "The specified cache class name could not be found : " + + config.get(XmlaOlap4jDriver.Property.Cache.name()), e); + } catch (InstantiationException e) { + throw new OlapException( + "The specified cache class name could not be instanciated : " + + config.get(XmlaOlap4jDriver.Property.Cache.name()), e); + } catch (IllegalAccessException e) { + throw new OlapException( + "An error was encountered while instanciating the cache : " + + config.get(XmlaOlap4jDriver.Property.Cache.name()), e); + } catch (IllegalArgumentException e) { + throw new OlapException( + "An error was encountered while instanciating the cache : " + + config.get(XmlaOlap4jDriver.Property.Cache.name()), e); + } catch (SecurityException e) { + throw new OlapException( + "An error was encountered while instanciating the cache : " + + config.get(XmlaOlap4jDriver.Property.Cache.name()), e); + } + } + + // implement XmlaOlap4jProxy + public byte[] get(URL url, String request) throws IOException { + // Tries to fetch from cache + byte[] response = + getFromCache( + url, + request.getBytes(getEncodingCharsetName())); + + // Returns the cached value if found + if (response != null) { + return response; + } + + // Executes the query + response = getResponse(url, request); + + // Adds to cache + addToCache( + url, + request.getBytes(getEncodingCharsetName()), + response); + + // Returns result + return response; + } + + + /** + * Tries to fetch a cached response from the cache implementation. + * + * @param url The url used to send the request + * + * @param request The SOAP request to cache + * + * @return either a response in a byte array or null + * if the response is not in cache + */ + private byte[] getFromCache(final URL url, final byte[] request) { + return (this.cache != null) + ? this.cache.get(this.cacheId, url, request) + : null; + } + + + /** + * Caches an entry using the current cache implementation. + * @param url The URL from which originated the request + * @param request The SOAP request to cache + * @param response The SOAP response to cache + */ + private void addToCache(URL url, byte[] request, byte[] response) { + if (this.cache != null) { + this.cache.put(this.cacheId, url, request, response); + } + } + + // implement XmlaOlap4jProxy + public Future submit(final URL url, final String request) { + // The submit operation doesn't need to be cached yet, since it will + // call the get operation to fetch the data later on. It will get cached + // then. + // + // I still overridden the submit method in case we need some caching done + // in the end. - Luc + return getResponseViaSubmit(url, request); + } + + /** + * Initializes the cookie manager. It is not initialized + * by default because some proxy implementation might not need this + * functionnality. + */ + private void initCookieManager() { + if (this.cookieManager == null) { + this.cookieManager = new XmlaOlap4jCookieManager(); + } + } +} + +// End XmlaOlap4jAbstractHttpProxy.java diff --git a/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jCachedProxy.java b/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jCachedProxy.java index f64f076..6946bac 100644 --- a/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jCachedProxy.java +++ b/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jCachedProxy.java @@ -1,46 +1,49 @@ -/* -// $Id: CachedProxy.java 92 2008-07-17 07:41:10Z lucboudreau $ -// This software is subject to the terms of the Common Public License -// Agreement, available at the following URL: -// http://www.opensource.org/licenses/cpl.html. -// Copyright (C) 2007-2007 Julian Hyde -// All Rights Reserved. -// You must accept the terms of that agreement to use this software. -*/ -package org.olap4j.driver.xmla.proxy; - -import java.util.Map; - -import org.olap4j.OlapException; -import org.olap4j.driver.xmla.cache.XmlaOlap4jCache; - -/** - * - * Extended Proxy interface which supports cached SOAP calls. - * - * @author Luc Boudreau - * @version $Id: CachedProxy.java 92 2008-07-17 07:41:10Z lucboudreau $ - * - */ -public interface XmlaOlap4jCachedProxy extends XmlaOlap4jProxy { - - /** - *

      Sets the cache class to use as a SOAP message cache. - * - *

      Calling this method is not mandatory. If it isn't called, - * no cache will be used and all SOAP requests will be sent to - * the service end-point. - * - * @param configParameters This contains all the parameters used - * to configure the Olap4j driver. It contains the full class name - * of the cache implementation to use as well as the raw Cache - * config parameters. - * @param properties The properties to configure the cache, - * so all config parameters which started - * by Cache.* are inside this convenient thigny. - * @see XmlaOlap4jCache - */ - void setCache(Map configParameters, - Map properties) throws OlapException; - -} \ No newline at end of file +/* +// $Id: CachedProxy.java 92 2008-07-17 07:41:10Z lucboudreau $ +// This software is subject to the terms of the Common Public License +// Agreement, available at the following URL: +// http://www.opensource.org/licenses/cpl.html. +// Copyright (C) 2007-2007 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j.driver.xmla.proxy; + +import java.util.Map; + +import org.olap4j.OlapException; +import org.olap4j.driver.xmla.cache.XmlaOlap4jCache; + +/** + * + * Extended Proxy interface which supports cached SOAP calls. + * + * @author Luc Boudreau + * @version $Id: CachedProxy.java 92 2008-07-17 07:41:10Z lucboudreau $ + * + */ +public interface XmlaOlap4jCachedProxy extends XmlaOlap4jProxy { + + /** + *

      Sets the cache class to use as a SOAP message cache. + * + *

      Calling this method is not mandatory. If it isn't called, + * no cache will be used and all SOAP requests will be sent to + * the service end-point. + * + * @param configParameters This contains all the parameters used + * to configure the Olap4j driver. It contains the full class name + * of the cache implementation to use as well as the raw Cache + * config parameters. + * @param properties The properties to configure the cache, + * so all config parameters which started + * by Cache.* are inside this convenient thigny. + * @see XmlaOlap4jCache + */ + void setCache( + Map configParameters, + Map properties) throws OlapException; + +} + +// End XmlaOlap4jCachedProxy.java diff --git a/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jCookieManager.java b/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jCookieManager.java index a934bb8..1340c22 100644 --- a/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jCookieManager.java +++ b/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jCookieManager.java @@ -1,250 +1,252 @@ -/* -// $Id: CookieManager.java 92 2008-07-17 07:41:10Z lucboudreau $ -// This software is subject to the terms of the Common Public License -// Agreement, available at the following URL: -// http://www.opensource.org/licenses/cpl.html. -// Copyright (C) 2007-2007 Julian Hyde -// All Rights Reserved. -// You must accept the terms of that agreement to use this software. -*/ -package org.olap4j.driver.xmla.proxy; - -import java.io.IOException; -import java.net.URL; -import java.net.URLConnection; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Iterator; -import java.util.Map; -import java.util.StringTokenizer; -import java.util.concurrent.ConcurrentHashMap; - -/** - *

      CookieManager is a simple utility for handling cookies when working - * with java.net.URL and java.net.URLConnection - * objects. - * - *

      This code was taken from http://www.hccp.org/java-net-cookie-how-to.html - * and modified by Luc Boudreau to support concurrent access and be more - * thread safe. - * - *

      Here's a few use cases examples... - * - *


      - * - *

      Cookiemanager cm = new CookieManager(); - *

      URL url = new URL("http://www.hccp.org/test/cookieTest.jsp"); - * - *

      . . . - * - *

      // getting cookies: - *

      URLConnection conn = url.openConnection(); - *

      conn.connect(); - * - *

      // setting cookies - *

      cm.storeCookies(conn); - *

      cm.setCookies(url.openConnection()); - * - *


      - * - * @author Ian Brown - * @version $Id: CookieManager.java 92 2008-07-17 07:41:10Z lucboudreau $ - **/ - -@SuppressWarnings("unchecked") -public class XmlaOlap4jCookieManager { - - private Map store; - - private static final String SET_COOKIE = "Set-Cookie"; - private static final String COOKIE_VALUE_DELIMITER = ";"; - private static final String PATH = "path"; - private static final String EXPIRES = "expires"; - private static final String DATE_FORMAT = "EEE, dd-MMM-yyyy hh:mm:ss z"; - private static final String SET_COOKIE_SEPARATOR = "; "; - private static final String COOKIE = "Cookie"; - - private static final char NAME_VALUE_SEPARATOR = '='; - private static final char DOT = '.'; - - private DateFormat dateFormat; - - private boolean debug = false; - - public XmlaOlap4jCookieManager() { - store = new ConcurrentHashMap(); - dateFormat = new SimpleDateFormat(DATE_FORMAT); - } - - /** - * Retrieves and stores cookies returned by the host on the other side - * of the the open java.net.URLConnection. - * - * The connection MUST have been opened using the connect() - * method or a IOException will be thrown. - * - * @param conn a java.net.URLConnection - must be open, - * or IOException will be thrown - * @throws java.io.IOException Thrown if conn is not open. - */ - public void storeCookies(URLConnection conn) throws IOException { - - // Determines the domain from where these cookies are being sent - String domain = getDomainFromHost(conn.getURL().getHost()); - - Map domainStore; // Where we will store cookies for this domain - - // Checks the store to see if we have an entry for this domain - if (store.containsKey(domain)) { - // we do, so lets retrieve it from the store - domainStore = (Map) store.get(domain); - } else { - // we don't, so let's create it and put it in the store - domainStore = new ConcurrentHashMap(); - store.put(domain, domainStore); - } - - // OK, now we are ready to get the cookies out of the URLConnection - - String headerName = null; - for (int i = 1; (headerName = conn.getHeaderFieldKey(i)) != null; i++) { - if (headerName.equalsIgnoreCase(SET_COOKIE)) { - Map cookie = new ConcurrentHashMap(); - StringTokenizer st = new StringTokenizer( - conn.getHeaderField(i), COOKIE_VALUE_DELIMITER); - - // the specification dictates that the first name/value pair - // in the string is the cookie name and value, so let's handle - // them as a special case: - - if (st.hasMoreTokens()) { - String token = st.nextToken(); - String name = token.substring(0, token - .indexOf(NAME_VALUE_SEPARATOR)); - String value = token.substring( - token .indexOf(NAME_VALUE_SEPARATOR) + 1, - token.length()); - domainStore.put(name, cookie); - cookie.put(name, value); - - if (this.debug == true) { - System.out.println("Saving cookie : " + name + "=" + value); - } - - } - - while (st.hasMoreTokens()) { - String token = st.nextToken(); - cookie.put(token.substring(0, - token.indexOf(NAME_VALUE_SEPARATOR)).toLowerCase(), - token.substring( - token.indexOf(NAME_VALUE_SEPARATOR) + 1, - token.length())); - - if (this.debug == true) { - System.out.println("Saving cookie : " + token.substring(0, - token.indexOf(NAME_VALUE_SEPARATOR)).toLowerCase() + "=" - + token.substring( - token.indexOf(NAME_VALUE_SEPARATOR) + 1, - token.length())); - } - } - } - } - } - - /** - * Prior to opening a URLConnection, calling this method will set all - * unexpired cookies that match the path or subpaths for thi underlying URL - * - * The connection MUST NOT have been opened - * method or an IOException will be thrown. - * - * @param conn a java.net.URLConnection - must NOT be open, or IOException will be thrown - * @throws java.io.IOException Thrown if conn has already been opened. - */ - public void setCookies(URLConnection conn) throws IOException { - - // Determines the domain and path to retrieve the appropriate cookies - URL url = conn.getURL(); - String domain = getDomainFromHost(url.getHost()); - String path = url.getPath(); - - Map domainStore = (Map) store.get(domain); - if (domainStore == null) - return; - StringBuffer cookieStringBuffer = new StringBuffer(); - - Iterator cookieNames = domainStore.keySet().iterator(); - while (cookieNames.hasNext()) { - String cookieName = (String) cookieNames.next(); - Map cookie = (Map) domainStore.get(cookieName); - // check cookie to ensure path matches and cookie is not expired - // if all is cool, add cookie to header string - if (comparePaths((String) cookie.get(PATH), path) - && isNotExpired((String) cookie.get(EXPIRES))) { - cookieStringBuffer.append(cookieName); - cookieStringBuffer.append("="); - cookieStringBuffer.append((String) cookie.get(cookieName)); - if (cookieNames.hasNext()) - cookieStringBuffer.append(SET_COOKIE_SEPARATOR); - } - } - try { - if (this.debug == true - && !(cookieStringBuffer.toString().equals("")) ) - { - System.out.println( - "Using cookie : " + cookieStringBuffer.toString()); - } - conn.setRequestProperty(COOKIE, cookieStringBuffer.toString()); - } catch (java.lang.IllegalStateException ise) { - IOException ioe = new IOException( - "Illegal State! Cookies cannot be set on a URLConnection that is already connected. Only call setCookies(java.net.URLConnection) AFTER calling java.net.URLConnection.connect()."); - throw ioe; - } - } - - private String getDomainFromHost(String host) { - if (host.indexOf(DOT) != host.lastIndexOf(DOT)) { - return host.substring(host.indexOf(DOT) + 1); - } else { - return host; - } - } - - private boolean isNotExpired(String cookieExpires) { - if (cookieExpires == null) - return true; - Date now = new Date(); - try { - return (now.compareTo(dateFormat.parse(cookieExpires))) <= 0; - } catch (java.text.ParseException pe) { - pe.printStackTrace(); - return false; - } - } - - private boolean comparePaths(String cookiePath, String targetPath) { - if (cookiePath == null) { - return true; - } else if (cookiePath.equals("/")) { - return true; - } else if (targetPath.regionMatches(0, cookiePath, 0, cookiePath - .length())) { - return true; - } else { - return false; - } - - } - - /** - * Returns a string representation of stored cookies organized by domain. - */ - - public String toString() { - return store.toString(); - } -} +/* +// $Id: CookieManager.java 92 2008-07-17 07:41:10Z lucboudreau $ +// This software is subject to the terms of the Common Public License +// Agreement, available at the following URL: +// http://www.opensource.org/licenses/cpl.html. +// Copyright (C) 2007-2007 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j.driver.xmla.proxy; + +import java.io.IOException; +import java.net.URL; +import java.net.URLConnection; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Iterator; +import java.util.Map; +import java.util.StringTokenizer; +import java.util.concurrent.ConcurrentHashMap; + +/** + *

      CookieManager is a simple utility for handling cookies when working + * with java.net.URL and java.net.URLConnection + * objects. + * + *

      This code was taken from http://www.hccp.org/java-net-cookie-how-to.html + * and modified by Luc Boudreau to support concurrent access and be more + * thread safe. + * + *

      Here's a few use cases examples... + * + *


      + * + *

      Cookiemanager cm = new CookieManager(); + *

      URL url = new URL("http://www.hccp.org/test/cookieTest.jsp"); + * + *

      . . . + * + *

      // getting cookies: + *

      URLConnection conn = url.openConnection(); + *

      conn.connect(); + * + *

      // setting cookies + *

      cm.storeCookies(conn); + *

      cm.setCookies(url.openConnection()); + * + *


      + * + * @author Ian Brown + * @version $Id: CookieManager.java 92 2008-07-17 07:41:10Z lucboudreau $ + **/ + +@SuppressWarnings("unchecked") +public class XmlaOlap4jCookieManager { + + private Map store; + + private static final String SET_COOKIE = "Set-Cookie"; + private static final String COOKIE_VALUE_DELIMITER = ";"; + private static final String PATH = "path"; + private static final String EXPIRES = "expires"; + private static final String DATE_FORMAT = "EEE, dd-MMM-yyyy hh:mm:ss z"; + private static final String SET_COOKIE_SEPARATOR = "; "; + private static final String COOKIE = "Cookie"; + + private static final char NAME_VALUE_SEPARATOR = '='; + private static final char DOT = '.'; + + private DateFormat dateFormat; + + private boolean debug = false; + + public XmlaOlap4jCookieManager() { + store = new ConcurrentHashMap(); + dateFormat = new SimpleDateFormat(DATE_FORMAT); + } + + /** + * Retrieves and stores cookies returned by the host on the other side + * of the the open java.net.URLConnection. + * + * The connection MUST have been opened using the connect() + * method or a IOException will be thrown. + * + * @param conn a java.net.URLConnection - must be open, + * or IOException will be thrown + * @throws java.io.IOException Thrown if conn is not open. + */ + public void storeCookies(URLConnection conn) throws IOException { + + // Determines the domain from where these cookies are being sent + String domain = getDomainFromHost(conn.getURL().getHost()); + + Map domainStore; // Where we will store cookies for this domain + + // Checks the store to see if we have an entry for this domain + if (store.containsKey(domain)) { + // we do, so lets retrieve it from the store + domainStore = (Map) store.get(domain); + } else { + // we don't, so let's create it and put it in the store + domainStore = new ConcurrentHashMap(); + store.put(domain, domainStore); + } + + // OK, now we are ready to get the cookies out of the URLConnection + + String headerName = null; + for (int i = 1; (headerName = conn.getHeaderFieldKey(i)) != null; i++) { + if (headerName.equalsIgnoreCase(SET_COOKIE)) { + Map cookie = new ConcurrentHashMap(); + StringTokenizer st = new StringTokenizer( + conn.getHeaderField(i), COOKIE_VALUE_DELIMITER); + + // the specification dictates that the first name/value pair + // in the string is the cookie name and value, so let's handle + // them as a special case: + + if (st.hasMoreTokens()) { + String token = st.nextToken(); + String name = token.substring(0, token + .indexOf(NAME_VALUE_SEPARATOR)); + String value = token.substring( + token .indexOf(NAME_VALUE_SEPARATOR) + 1, + token.length()); + domainStore.put(name, cookie); + cookie.put(name, value); + + if (this.debug == true) { + System.out.println("Saving cookie : " + name + "=" + value); + } + + } + + while (st.hasMoreTokens()) { + String token = st.nextToken(); + cookie.put(token.substring(0, + token.indexOf(NAME_VALUE_SEPARATOR)).toLowerCase(), + token.substring( + token.indexOf(NAME_VALUE_SEPARATOR) + 1, + token.length())); + + if (this.debug == true) { + System.out.println("Saving cookie : " + token.substring(0, + token.indexOf(NAME_VALUE_SEPARATOR)).toLowerCase() + "=" + + token.substring( + token.indexOf(NAME_VALUE_SEPARATOR) + 1, + token.length())); + } + } + } + } + } + + /** + * Prior to opening a URLConnection, calling this method will set all + * unexpired cookies that match the path or subpaths for thi underlying URL + * + * The connection MUST NOT have been opened + * method or an IOException will be thrown. + * + * @param conn a java.net.URLConnection - must NOT be open, or IOException will be thrown + * @throws java.io.IOException Thrown if conn has already been opened. + */ + public void setCookies(URLConnection conn) throws IOException { + + // Determines the domain and path to retrieve the appropriate cookies + URL url = conn.getURL(); + String domain = getDomainFromHost(url.getHost()); + String path = url.getPath(); + + Map domainStore = (Map) store.get(domain); + if (domainStore == null) + return; + StringBuffer cookieStringBuffer = new StringBuffer(); + + Iterator cookieNames = domainStore.keySet().iterator(); + while (cookieNames.hasNext()) { + String cookieName = (String) cookieNames.next(); + Map cookie = (Map) domainStore.get(cookieName); + // check cookie to ensure path matches and cookie is not expired + // if all is cool, add cookie to header string + if (comparePaths((String) cookie.get(PATH), path) + && isNotExpired((String) cookie.get(EXPIRES))) { + cookieStringBuffer.append(cookieName); + cookieStringBuffer.append("="); + cookieStringBuffer.append((String) cookie.get(cookieName)); + if (cookieNames.hasNext()) + cookieStringBuffer.append(SET_COOKIE_SEPARATOR); + } + } + try { + if (this.debug == true + && !(cookieStringBuffer.toString().equals(""))) + { + System.out.println( + "Using cookie : " + cookieStringBuffer.toString()); + } + conn.setRequestProperty(COOKIE, cookieStringBuffer.toString()); + } catch (java.lang.IllegalStateException ise) { + IOException ioe = new IOException( + "Illegal State! Cookies cannot be set on a URLConnection that is already connected. Only call setCookies(java.net.URLConnection) AFTER calling java.net.URLConnection.connect()."); + throw ioe; + } + } + + private String getDomainFromHost(String host) { + if (host.indexOf(DOT) != host.lastIndexOf(DOT)) { + return host.substring(host.indexOf(DOT) + 1); + } else { + return host; + } + } + + private boolean isNotExpired(String cookieExpires) { + if (cookieExpires == null) + return true; + Date now = new Date(); + try { + return (now.compareTo(dateFormat.parse(cookieExpires))) <= 0; + } catch (java.text.ParseException pe) { + pe.printStackTrace(); + return false; + } + } + + private boolean comparePaths(String cookiePath, String targetPath) { + if (cookiePath == null) { + return true; + } else if (cookiePath.equals("/")) { + return true; + } else if (targetPath.regionMatches(0, cookiePath, 0, cookiePath + .length())) { + return true; + } else { + return false; + } + + } + + /** + * Returns a string representation of stored cookies organized by domain. + */ + + public String toString() { + return store.toString(); + } +} + +// End XmlaOlap4jCookieManager.java diff --git a/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jHttpProxy.java b/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jHttpProxy.java index 8ed01aa..9c5f98c 100644 --- a/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jHttpProxy.java +++ b/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jHttpProxy.java @@ -1,108 +1,106 @@ -/* -// $Id: HttpProxy.java 92 2008-07-17 07:41:10Z lucboudreau $ -// This software is subject to the terms of the Common Public License -// Agreement, available at the following URL: -// http://www.opensource.org/licenses/cpl.html. -// Copyright (C) 2007-2007 Julian Hyde -// All Rights Reserved. -// You must accept the terms of that agreement to use this software. -*/ -package org.olap4j.driver.xmla.proxy; - -import java.io.*; -import java.net.*; -import java.util.concurrent.*; - -import org.olap4j.driver.xmla.XmlaOlap4jDriver; -import org.olap4j.impl.Base64; - -/** - * Extends the AbstractCachedProxy and serves as - * a production ready http communication class. Every SOAP request - * sends a POST call to the destination XMLA server and returns - * the response as a byte array, conforming to the Proxy interface. - * - *

      It also takes advantage of the AbstractHttpProxy cookie - * managing facilities. All cookies received from the end point - * server will be sent back if they are not expired and they also - * conform to cookie domain rules. - * - * @author Luc Boudreau and Julian Hyde - * @version $Id: HttpProxy.java 92 2008-07-17 07:41:10Z lucboudreau $ - */ -public class XmlaOlap4jHttpProxy extends XmlaOlap4jAbstractHttpProxy -{ - /* (non-Javadoc) - * @see org.olap4j.driver.xmla.proxy.AbstractHttpProxy#getResponse(java.net.URL, java.lang.String) - */ - public byte[] getResponse(URL url, String request) - throws IOException - { - // Open connection to manipulate the properties - URLConnection urlConnection = url.openConnection(); - urlConnection.setDoOutput(true); - - // Set headers - urlConnection.setRequestProperty( - "content-type", "text/xml"); - urlConnection.setRequestProperty ( - "User-Agent", "Olap4j(" - .concat(XmlaOlap4jDriver.VERSION) - .concat(")")) ; - urlConnection.setRequestProperty ( - "Accept", "text/xml;q=1" ); - urlConnection.setRequestProperty ( - "Accept-Charset", getEncodingCharsetName() - .concat(";q=1") ) ; - - // Encode credentials for basic authentication - if (url.getUserInfo() != null) { - String encoding = - Base64.encodeBytes(url.getUserInfo().getBytes(), 0); - urlConnection.setRequestProperty( - "Authorization", "Basic " + encoding); - } - - // Set correct cookies - this.useCookies(urlConnection); - - // Send data (i.e. POST). Use same encoding as specified in the - // header. - final String encoding = getEncodingCharsetName(); - urlConnection.getOutputStream().write(request.getBytes(encoding)); - - // Get the response, again assuming default encoding. - InputStream is = urlConnection.getInputStream(); - final ByteArrayOutputStream baos = new ByteArrayOutputStream(); - byte[] buf = new byte[1024]; - int count; - - while ((count = is.read(buf)) > 0) { - baos.write(buf, 0, count); - } - - // Save the returned cookies for later use - this.saveCookies(urlConnection); - - return baos.toByteArray(); - - } - - /* (non-Javadoc) - * @see org.olap4j.driver.xmla.proxy.AbstractHttpProxy#getResponseViaSubmit(java.net.URL, java.lang.String) - */ - public Future getResponseViaSubmit( - final URL url, - final String request) - { - return XmlaOlap4jDriver.getFuture(this, url, request); - } - - /* (non-Javadoc) - * @see org.olap4j.driver.xmla.proxy.Proxy#getEncodingCharsetName() - */ - public String getEncodingCharsetName() { - return "UTF-8"; - } - -} \ No newline at end of file +/* +// $Id: HttpProxy.java 92 2008-07-17 07:41:10Z lucboudreau $ +// This software is subject to the terms of the Common Public License +// Agreement, available at the following URL: +// http://www.opensource.org/licenses/cpl.html. +// Copyright (C) 2007-2007 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j.driver.xmla.proxy; + +import java.io.*; +import java.net.*; +import java.util.concurrent.*; + +import org.olap4j.driver.xmla.XmlaOlap4jDriver; +import org.olap4j.impl.Base64; + +/** + * Extends the AbstractCachedProxy and serves as + * a production ready http communication class. Every SOAP request + * sends a POST call to the destination XMLA server and returns + * the response as a byte array, conforming to the Proxy interface. + * + *

      It also takes advantage of the AbstractHttpProxy cookie + * managing facilities. All cookies received from the end point + * server will be sent back if they are not expired and they also + * conform to cookie domain rules. + * + * @author Luc Boudreau and Julian Hyde + * @version $Id: HttpProxy.java 92 2008-07-17 07:41:10Z lucboudreau $ + */ +public class XmlaOlap4jHttpProxy extends XmlaOlap4jAbstractHttpProxy +{ + @Override + public byte[] getResponse(URL url, String request) + throws IOException + { + // Open connection to manipulate the properties + URLConnection urlConnection = url.openConnection(); + urlConnection.setDoOutput(true); + + // Set headers + urlConnection.setRequestProperty( + "content-type", + "text/xml"); + urlConnection.setRequestProperty( + "User-Agent", + "Olap4j(" + .concat(XmlaOlap4jDriver.VERSION) + .concat(")")); + urlConnection.setRequestProperty( + "Accept", + "text/xml;q=1"); + urlConnection.setRequestProperty( + "Accept-Charset", + getEncodingCharsetName() + .concat(";q=1")); + + // Encode credentials for basic authentication + if (url.getUserInfo() != null) { + String encoding = + Base64.encodeBytes(url.getUserInfo().getBytes(), 0); + urlConnection.setRequestProperty( + "Authorization", "Basic " + encoding); + } + + // Set correct cookies + this.useCookies(urlConnection); + + // Send data (i.e. POST). Use same encoding as specified in the + // header. + final String encoding = getEncodingCharsetName(); + urlConnection.getOutputStream().write(request.getBytes(encoding)); + + // Get the response, again assuming default encoding. + InputStream is = urlConnection.getInputStream(); + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] buf = new byte[1024]; + int count; + + while ((count = is.read(buf)) > 0) { + baos.write(buf, 0, count); + } + + // Save the returned cookies for later use + this.saveCookies(urlConnection); + + return baos.toByteArray(); + } + + @Override + public Future getResponseViaSubmit( + final URL url, + final String request) + { + return XmlaOlap4jDriver.getFuture(this, url, request); + } + + // implement XmlaOlap4jProxy + public String getEncodingCharsetName() { + return "UTF-8"; + } +} + +// End XmlaOlap4jHttpProxy.java diff --git a/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jProxy.java b/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jProxy.java index a1bbc8b..f74a3a4 100644 --- a/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jProxy.java +++ b/src/org/olap4j/driver/xmla/proxy/XmlaOlap4jProxy.java @@ -1,47 +1,49 @@ -/* -// $Id: Proxy.java 92 2008-07-17 07:41:10Z lucboudreau $ -// This software is subject to the terms of the Common Public License -// Agreement, available at the following URL: -// http://www.opensource.org/licenses/cpl.html. -// Copyright (C) 2007-2007 Julian Hyde -// All Rights Reserved. -// You must accept the terms of that agreement to use this software. -*/ -package org.olap4j.driver.xmla.proxy; - -import java.io.IOException; -import java.net.URL; -import java.util.concurrent.Future; - -/** - * Defines a common set of methods for proxy objects. - * @version $Id: Proxy.java 92 2008-07-17 07:41:10Z lucboudreau $ - */ -public interface XmlaOlap4jProxy { - /** - * Sends a request to a URL and returns the response. - * - * @param url Target URL - * @param request Request string - * @return Response - * @throws IOException - */ - byte[] get(URL url, String request) throws IOException; - - /** - * Submits a request for background execution. - * - * @param url URL - * @param request Request - * @return Future object representing the submitted job - */ - Future submit( - URL url, - String request); - - /** - * Returns the name of the character set use for encoding the XML - * string. - */ - String getEncodingCharsetName(); -} \ No newline at end of file +/* +// $Id: Proxy.java 92 2008-07-17 07:41:10Z lucboudreau $ +// This software is subject to the terms of the Common Public License +// Agreement, available at the following URL: +// http://www.opensource.org/licenses/cpl.html. +// Copyright (C) 2007-2007 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j.driver.xmla.proxy; + +import java.io.IOException; +import java.net.URL; +import java.util.concurrent.Future; + +/** + * Defines a common set of methods for proxy objects. + * @version $Id: Proxy.java 92 2008-07-17 07:41:10Z lucboudreau $ + */ +public interface XmlaOlap4jProxy { + /** + * Sends a request to a URL and returns the response. + * + * @param url Target URL + * @param request Request string + * @return Response + * @throws IOException + */ + byte[] get(URL url, String request) throws IOException; + + /** + * Submits a request for background execution. + * + * @param url URL + * @param request Request + * @return Future object representing the submitted job + */ + Future submit( + URL url, + String request); + + /** + * Returns the name of the character set use for encoding the XML + * string. + */ + String getEncodingCharsetName(); +} + +// End XmlaOlap4jProxy.java diff --git a/src/org/olap4j/impl/ArrayNamedListImpl.java b/src/org/olap4j/impl/ArrayNamedListImpl.java index 04da81c..3f1f294 100644 --- a/src/org/olap4j/impl/ArrayNamedListImpl.java +++ b/src/org/olap4j/impl/ArrayNamedListImpl.java @@ -1,54 +1,54 @@ -/* -// This software is subject to the terms of the Common Public License -// Agreement, available at the following URL: -// http://www.opensource.org/licenses/cpl.html. -// Copyright (C) 2007-2007 Julian Hyde -// All Rights Reserved. -// You must accept the terms of that agreement to use this software. -*/ -package org.olap4j.impl; - -import org.olap4j.metadata.NamedList; - -import java.util.ArrayList; - -/** - * Implementation of {@link org.olap4j.metadata.NamedList} which uses - * {@link java.util.ArrayList} for storage. - * - *

      Derived class must implement {@link #getName(Object)}, to indicate how - * elements are named. - * - * @see NamedListImpl - * - * @author jhyde - * @version $Id$ - * @since Nov 12, 2007 - */ -public abstract class ArrayNamedListImpl - extends ArrayList - implements NamedList -{ - protected abstract String getName(T t); - - public T get(String name) { - for (T t : this) { - if (getName(t).equals(name)) { - return t; - } - } - return null; - } - - public int indexOfName(String name) { - for (int i = 0; i < size(); ++i) { - T t = get(i); - if (getName(t).equals(name)) { - return i; - } - } - return -1; - } -} - -// End ArrayNamedListImpl.java +/* +// This software is subject to the terms of the Common Public License +// Agreement, available at the following URL: +// http://www.opensource.org/licenses/cpl.html. +// Copyright (C) 2007-2007 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j.impl; + +import org.olap4j.metadata.NamedList; + +import java.util.ArrayList; + +/** + * Implementation of {@link org.olap4j.metadata.NamedList} which uses + * {@link java.util.ArrayList} for storage. + * + *

      Derived class must implement {@link #getName(Object)}, to indicate how + * elements are named. + * + * @see NamedListImpl + * + * @author jhyde + * @version $Id$ + * @since Nov 12, 2007 + */ +public abstract class ArrayNamedListImpl + extends ArrayList + implements NamedList +{ + protected abstract String getName(T t); + + public T get(String name) { + for (T t : this) { + if (getName(t).equals(name)) { + return t; + } + } + return null; + } + + public int indexOfName(String name) { + for (int i = 0; i < size(); ++i) { + T t = get(i); + if (getName(t).equals(name)) { + return i; + } + } + return -1; + } +} + +// End ArrayNamedListImpl.java diff --git a/src/org/olap4j/impl/Olap4jUtil.java b/src/org/olap4j/impl/Olap4jUtil.java index f186f67..bf03143 100644 --- a/src/org/olap4j/impl/Olap4jUtil.java +++ b/src/org/olap4j/impl/Olap4jUtil.java @@ -73,31 +73,40 @@ public class Olap4jUtil { } @SuppressWarnings({"UnusedDeclaration"}) - public static void discard(boolean b) { } + public static void discard(boolean b) { + } @SuppressWarnings({"UnusedDeclaration"}) - public static void discard(byte b) { } + public static void discard(byte b) { + } @SuppressWarnings({"UnusedDeclaration"}) - public static void discard(char c) { } + public static void discard(char c) { + } @SuppressWarnings({"UnusedDeclaration"}) - public static void discard(double v) { } + public static void discard(double v) { + } @SuppressWarnings({"UnusedDeclaration"}) - public static void discard(float v) { } + public static void discard(float v) { + } @SuppressWarnings({"UnusedDeclaration"}) - public static void discard(int i) { } + public static void discard(int i) { + } @SuppressWarnings({"UnusedDeclaration"}) - public static void discard(long l) { } + public static void discard(long l) { + } @SuppressWarnings({"UnusedDeclaration"}) - public static void discard(Object o) { } + public static void discard(Object o) { + } @SuppressWarnings({"UnusedDeclaration"}) - public static void discard(short i) { } + public static void discard(short i) { + } /** * Casts a Set to a Set with a different element type. @@ -186,7 +195,7 @@ public static String replace( replace(sb, 0, find, replace); } else { for (;;) { - sb.append(chars, start, found-start); + sb.append(chars, start, found - start); if (found == s.length()) { break; } @@ -343,7 +352,8 @@ public static NamedList emptyNamedList() { return (NamedList) EMPTY_NAMED_LIST; } - private enum DummyEnum {} + private enum DummyEnum { + } /** * Implementation of {@link NamedList} whih is immutable and empty. @@ -358,7 +368,7 @@ public int size() { } public T get(int index) { - throw new IndexOutOfBoundsException("Index: "+index); + throw new IndexOutOfBoundsException("Index: " + index); } // Preserves singleton property diff --git a/src/org/olap4j/mdx/ParseTreeVisitor.java b/src/org/olap4j/mdx/ParseTreeVisitor.java index 90b80d3..b4aba74 100644 --- a/src/org/olap4j/mdx/ParseTreeVisitor.java +++ b/src/org/olap4j/mdx/ParseTreeVisitor.java @@ -17,7 +17,7 @@ * class implementing this interface implements a visitor pattern, to allow * an algorithm to efficiently traverse a parse tree and perform an action at * each node dependent upon the type of each node. - * + * * @author jhyde * @version $Id$ * @since Jul 21, 2006 diff --git a/src/org/olap4j/mdx/ParseTreeWriter.java b/src/org/olap4j/mdx/ParseTreeWriter.java index f4ea2d5..4f04021 100644 --- a/src/org/olap4j/mdx/ParseTreeWriter.java +++ b/src/org/olap4j/mdx/ParseTreeWriter.java @@ -16,7 +16,7 @@ * *

      Typical use is with the {@link ParseTreeNode#unparse(ParseTreeWriter)} * method as follows: - * + * *

      *
        * ParseTreeNode node;
      diff --git a/src/org/olap4j/mdx/parser/MdxValidator.java b/src/org/olap4j/mdx/parser/MdxValidator.java
      index 79746d4..f380580 100644
      --- a/src/org/olap4j/mdx/parser/MdxValidator.java
      +++ b/src/org/olap4j/mdx/parser/MdxValidator.java
      @@ -46,7 +46,7 @@ public interface MdxValidator {
            * {@link org.olap4j.mdx.ParseTreeNode#getType()} method.
            *
            * @param selectNode Parse tree node representing a SELECT statement
      -     * 
      +     *
            * @return Validated parse tree
            *
            * @throws OlapException if node is invalid
      diff --git a/src/org/olap4j/metadata/Catalog.java b/src/org/olap4j/metadata/Catalog.java
      index 62313e4..ddf7894 100644
      --- a/src/org/olap4j/metadata/Catalog.java
      +++ b/src/org/olap4j/metadata/Catalog.java
      @@ -23,7 +23,7 @@
        * 

      To obtain the collection of catalogs in the current server, call the * {@link org.olap4j.OlapConnection#getCatalogs()} method. * - *

      The hierarchy of metadata objects, rooted at the connection from which + *

      The hierarchy of metadata objects, rooted at the connection from which * they are accessed, is as follows: *

      *
        diff --git a/src/org/olap4j/metadata/Cube.java b/src/org/olap4j/metadata/Cube.java index 03ee78b..2baa35b 100644 --- a/src/org/olap4j/metadata/Cube.java +++ b/src/org/olap4j/metadata/Cube.java @@ -93,7 +93,7 @@ public interface Cube extends MetadataElement { * languages is confusing; the portal would figure out the best common * language, in this case French. This method allows the client to choose * the most appropriate locale.

        - * + * *

        The list is advisory: a client is free to choose another locale, * in which case, the server will probably revert to the base locale for * locale-specific behavior such as captions and formatting.

        @@ -122,7 +122,7 @@ public interface Cube extends MetadataElement { * dimension. * * @param nameParts Components of the fully-qualified member name - * + * * @return member with the given name, or null if not found * * @throws OlapException if error occurs diff --git a/src/org/olap4j/metadata/Level.java b/src/org/olap4j/metadata/Level.java index b83e5b1..bb87e69 100644 --- a/src/org/olap4j/metadata/Level.java +++ b/src/org/olap4j/metadata/Level.java @@ -79,7 +79,7 @@ public interface Level extends MetadataElement { *

        The members of a level do not have unique names, so unlike * {@link Hierarchy#getRootMembers()} and * {@link Member#getChildMembers()} the result type - * is a {@link List} not a {@link NamedList}. + * is a {@link List} not a {@link NamedList}. * * @return List of members in this Level */ @@ -208,7 +208,7 @@ public enum Type { private final int xmlaOrdinal; - private static final Map xmlaMap = + private static final Map xmlaMap = new HashMap(); static { @@ -226,7 +226,7 @@ private Type(int code) { * *

        For example, the XMLA specification says that the ordinal of * {@link #CUSTOMER_HOUSEHOLD} is 0x1023. - * + * * @return ordinal code as specified by XMLA. */ public int xmlaOrdinal() { diff --git a/src/org/olap4j/metadata/Member.java b/src/org/olap4j/metadata/Member.java index 8dc2b0b..309328f 100644 --- a/src/org/olap4j/metadata/Member.java +++ b/src/org/olap4j/metadata/Member.java @@ -242,7 +242,7 @@ private Type(int ordinal) { * {@link org.olap4j.metadata.Property.StandardMemberProperty} * enumeration), as well as extra properties defined for its Level * (see {@link Level#getProperties()}).

        - * + * * @param property property * * @param value Property value diff --git a/src/org/olap4j/metadata/MetadataElement.java b/src/org/olap4j/metadata/MetadataElement.java index e251bb4..11c871d 100644 --- a/src/org/olap4j/metadata/MetadataElement.java +++ b/src/org/olap4j/metadata/MetadataElement.java @@ -32,7 +32,7 @@ public interface MetadataElement { * @return unique name of this element */ String getUniqueName(); - + /** * Returns the caption of this element in the given locale. * diff --git a/src/org/olap4j/metadata/Schema.java b/src/org/olap4j/metadata/Schema.java index 2ad77af..359f140 100644 --- a/src/org/olap4j/metadata/Schema.java +++ b/src/org/olap4j/metadata/Schema.java @@ -63,7 +63,7 @@ public interface Schema { * @see org.olap4j.OlapDatabaseMetaData#getDimensions(String,String,String,String) * * @return list of shared dimensions - * + * * @throws OlapException if database error occurs */ NamedList getSharedDimensions() throws OlapException; diff --git a/src/org/olap4j/query/Query.java b/src/org/olap4j/query/Query.java index e723b3e..ab9ab5f 100644 --- a/src/org/olap4j/query/Query.java +++ b/src/org/olap4j/query/Query.java @@ -153,7 +153,7 @@ public Locale getLocale() { public SelectionFactory getSelectionFactory() { return selectionFactory; } - + private static class Olap4jNodeConverter { public SelectNode toOlap4j(Query query) { @@ -182,48 +182,44 @@ public SelectNode toOlap4j(Query query) { } private CallNode generateSetCall(ParseTreeNode... args) { - final CallNode callNode = new CallNode( + return + new CallNode( null, "{}", Syntax.Braces, - args - ); - - return callNode; + args); } private CallNode generateListSetCall(List cnodes) { - final CallNode callNode = new CallNode( + return + new CallNode( null, "{}", Syntax.Braces, - cnodes - ); - return callNode; + cnodes); } private CallNode generateListTupleCall(List cnodes) { - final CallNode callNode = new CallNode( + return + new CallNode( null, "()", Syntax.Parentheses, - cnodes - ); - return callNode; + cnodes); } protected CallNode getMemberSet(QueryDimension dimension) { - final CallNode cnode = new CallNode( + return + new CallNode( null, "{}", Syntax.Braces, - toOlap4j(dimension) - ); - return cnode; + toOlap4j(dimension)); } protected CallNode crossJoin(QueryDimension dim1, QueryDimension dim2) { - return new CallNode( + return + new CallNode( null, "CrossJoin", Syntax.Function, @@ -233,45 +229,47 @@ protected CallNode crossJoin(QueryDimension dim1, QueryDimension dim2) { // // This method merges the selections into a single - // MDX axis selection. Right now we do a simple + // MDX axis selection. Right now we do a simple // crossjoin // private AxisNode toOlap4j(QueryAxis axis) { CallNode callNode = null; int numDimensions = axis.getDimensions().size(); - if( axis.getLocation() == Axis.FILTER ) { + if (axis.getLocation() == Axis.FILTER) { // need a tuple // need a crossjoin List members = new ArrayList(); - for( int dimNo = 0; dimNo < numDimensions; dimNo++ ) { - QueryDimension dimension = - axis.getDimensions().get( dimNo ); - if( dimension.getSelections().size() == 1 ) { + for (int dimNo = 0; dimNo < numDimensions; dimNo++) { + QueryDimension dimension = + axis.getDimensions().get(dimNo); + if (dimension.getSelections().size() == 1) { members.addAll(toOlap4j(dimension)); } } callNode = generateListTupleCall(members); - } else if( numDimensions == 1 ) { - QueryDimension dimension = axis.getDimensions().get( 0 ); + } else if (numDimensions == 1) { + QueryDimension dimension = axis.getDimensions().get(0); List members = toOlap4j(dimension); callNode = generateListSetCall(members); - } else if( numDimensions == 2 ) { - callNode = - crossJoin( axis.getDimensions().get(0), + } else if (numDimensions == 2) { + callNode = + crossJoin( + axis.getDimensions().get(0), axis.getDimensions().get(1)); } else { // need a longer crossjoin // start from the back of the list; List dims = axis.getDimensions(); callNode = getMemberSet(dims.get(dims.size() - 1)); - for( int i = dims.size() - 2; i >= 0; i-- ) { + for (int i = dims.size() - 2; i >= 0; i--) { CallNode memberSet = getMemberSet(dims.get(i)); - callNode = new CallNode( - null, - "CrossJoin", - Syntax.Function, - memberSet, - callNode); + callNode = + new CallNode( + null, + "CrossJoin", + Syntax.Function, + memberSet, + callNode); } } return new AxisNode( @@ -280,7 +278,7 @@ private AxisNode toOlap4j(QueryAxis axis) { axis.getLocation(), new ArrayList(), callNode); - + } private List toOlap4j(QueryDimension dimension) { @@ -303,50 +301,50 @@ private ParseTreeNode toOlap4j(Selection selection) { private ParseTreeNode toOlap4j(Member member, Selection.Operator oper) { ParseTreeNode node = null; try { - switch(oper) { - case MEMBER: - node = new MemberNode(null, member); - break; - case SIBLINGS: - node = new CallNode( - null, - "Siblings", - Syntax.Property, - new MemberNode(null, member) - ); - break; - case CHILDREN: - node = new CallNode( - null, - "Children", - Syntax.Property, - new MemberNode(null, member) - ); - break; - case INCLUDE_CHILDREN: - node = generateSetCall( - new MemberNode(null, member), - toOlap4j(member, Selection.Operator.CHILDREN) - ); - break; - case DESCENDANTS: - node = new CallNode( - null, - "Descendants", - Syntax.Function, - new MemberNode(null, member) - ); - break; - case ANCESTORS: - node = new CallNode( - null, - "Ascendants", - Syntax.Function, - new MemberNode(null, member) - ); - break; - default: - System.out.println("NOT IMPLEMENTED: " + oper); + switch (oper) { + case MEMBER: + node = new MemberNode(null, member); + break; + case SIBLINGS: + node = + new CallNode( + null, + "Siblings", + Syntax.Property, + new MemberNode(null, member)); + break; + case CHILDREN: + node = + new CallNode( + null, + "Children", + Syntax.Property, + new MemberNode(null, member)); + break; + case INCLUDE_CHILDREN: + node = + generateSetCall( + new MemberNode(null, member), + toOlap4j(member, Selection.Operator.CHILDREN)); + break; + case DESCENDANTS: + node = + new CallNode( + null, + "Descendants", + Syntax.Function, + new MemberNode(null, member)); + break; + case ANCESTORS: + node = + new CallNode( + null, + "Ascendants", + Syntax.Function, + new MemberNode(null, member)); + break; + default: + System.out.println("NOT IMPLEMENTED: " + oper); } } catch (Exception e) { e.printStackTrace(); diff --git a/src/org/olap4j/query/QueryAxis.java b/src/org/olap4j/query/QueryAxis.java index 3939005..5f90028 100644 --- a/src/org/olap4j/query/QueryAxis.java +++ b/src/org/olap4j/query/QueryAxis.java @@ -41,7 +41,7 @@ public QueryAxis(Query query, Axis location) { /** * Returns the location of this QueryAxis in the query; * null if unused. - * + * * @return location of this axis in the query */ public Axis getLocation() { diff --git a/src/org/olap4j/query/QueryDimension.java b/src/org/olap4j/query/QueryDimension.java index dbbf2f5..c8a373b 100644 --- a/src/org/olap4j/query/QueryDimension.java +++ b/src/org/olap4j/query/QueryDimension.java @@ -82,7 +82,7 @@ public static String[] getNameParts(String sel) { } return nameParts; } - + public List resolve(Selection selection) throws OlapException { assert selection != null; @@ -92,23 +92,23 @@ public List resolve(Selection selection) throws OlapException case CHILDREN: op = Member.TreeOp.CHILDREN; break; - + case SIBLINGS: op = Member.TreeOp.SIBLINGS; break; - + case INCLUDE_CHILDREN: op = Member.TreeOp.SELF; secondOp = Member.TreeOp.CHILDREN; break; - + case MEMBER: op = Member.TreeOp.SELF; break; - + default: throw new OlapException("Operation not supported: " + selection.getOperator()); - + } Set set = new TreeSet(); set.add(op); @@ -116,11 +116,10 @@ public List resolve(Selection selection) throws OlapException set.add(secondOp); } try { - return + return query.getCube().lookupMembers( - set, - getNameParts(selection.getName()) - ); + set, + getNameParts(selection.getName())); } catch (Exception e) { throw new OlapException("Error while resolving selection " + selection.toString(), e); } diff --git a/src/org/olap4j/query/SelectionFactory.java b/src/org/olap4j/query/SelectionFactory.java index 7c75a98..2191888 100644 --- a/src/org/olap4j/query/SelectionFactory.java +++ b/src/org/olap4j/query/SelectionFactory.java @@ -25,7 +25,7 @@ public class SelectionFactory { /** * Creates a SelectionFactory. Called from {@link Query}. - * + * * @param query Owning query */ SelectionFactory(Query query) { @@ -33,16 +33,15 @@ public class SelectionFactory { } Selection createMemberSelection(Member member, Selection.Operator operator) { - SelectionImpl selectionImpl = + return new SelectionImpl( - member, - member.getDimension(), - member.getHierarchy().getUniqueName(), - member.getLevel().getUniqueName(), - member.getUniqueName(), - operator - ) {}; - return selectionImpl; + member, + member.getDimension(), + member.getHierarchy().getUniqueName(), + member.getLevel().getUniqueName(), + member.getUniqueName(), + operator) { + }; } } diff --git a/src/org/olap4j/query/SelectionImpl.java b/src/org/olap4j/query/SelectionImpl.java index 22a34cf..288a455 100644 --- a/src/org/olap4j/query/SelectionImpl.java +++ b/src/org/olap4j/query/SelectionImpl.java @@ -70,7 +70,7 @@ public void setDimension(Dimension dimension) { public Member getMember() { return member; } - + public String getDimensionName() { return dimensionName; } diff --git a/src/org/olap4j/type/LevelType.java b/src/org/olap4j/type/LevelType.java index 7cff078..a8e2c6e 100755 --- a/src/org/olap4j/type/LevelType.java +++ b/src/org/olap4j/type/LevelType.java @@ -41,7 +41,7 @@ public class LevelType implements Type { */ public LevelType( Dimension dimension, - Hierarchy hierarchy, + Hierarchy hierarchy, Level level) { this.dimension = dimension; diff --git a/src/org/olap4j/type/MemberType.java b/src/org/olap4j/type/MemberType.java index 60027f0..22634a8 100644 --- a/src/org/olap4j/type/MemberType.java +++ b/src/org/olap4j/type/MemberType.java @@ -37,7 +37,7 @@ public class MemberType implements Type { * Creates a type representing a member. * * @param dimension Dimension the member belongs to, or null if not known. - * + * * @param hierarchy Hierarchy the member belongs to, or null if not known. * * @param level Level the member belongs to, or null if not known diff --git a/testsrc/org/olap4j/ConnectionTest.java b/testsrc/org/olap4j/ConnectionTest.java index d90472c..9bae735 100644 --- a/testsrc/org/olap4j/ConnectionTest.java +++ b/testsrc/org/olap4j/ConnectionTest.java @@ -157,7 +157,7 @@ void assertIsClosed(Object o, boolean b) { // assertTrue(statment.isClosed()); try { Class clazz; - if (o instanceof Statement){ + if (o instanceof Statement) { clazz = Statement.class; } else if (o instanceof ResultSet) { clazz = ResultSet.class; @@ -410,7 +410,13 @@ public void testInvalidStatement() throws SQLException { connection.close(); } - private enum Method { ClassName, Mode, Type, TypeName, OlapType } + private enum Method { + ClassName, + Mode, + Type, + TypeName, + OlapType + } public void testPreparedStatement() throws SQLException { connection = tester.createConnection(); @@ -586,7 +592,9 @@ public void testPreparedStatement() throws SQLException { assertIsClosed(cellSet6, true); // todo: test all of the PreparedOlapStatement.setXxx methods - if (false) pstmt.getCube(); + if (false) { + pstmt.getCube(); + } } public void testCellSetMetaData() throws SQLException { @@ -1033,7 +1041,7 @@ public void testParsing() throws SQLException { if (tester.getFlavor() == TestContext.Tester.Flavor.XMLA) { // This test requires validator support. return; - } + } MdxValidator validator = olapConnection.getParserFactory().createMdxValidator( olapConnection); @@ -1113,9 +1121,8 @@ public void testUnparsing() { Syntax.Braces, Arrays.asList( (ParseTreeNode) - new IdentifierNode( - new IdentifierNode.Segment("Gender")))) - )); + new IdentifierNode( + new IdentifierNode.Segment("Gender")))))); select.getAxisList().add( new AxisNode( null, @@ -1137,7 +1144,7 @@ public void testUnparsing() { new IdentifierNode.Segment("Time"), new IdentifierNode.Segment("1997"), new IdentifierNode.Segment("Q4"))); - + checkUnparsedMdx(select); } @@ -1290,7 +1297,7 @@ public void testCubeLookupMembers() throws Exception { TestContext.fold("[Customers].[All Customers].[USA].[CA]\n" + "[Customers].[All Customers].[USA].[OR]\n" + "[Customers].[All Customers].[USA].[WA]\n"), - memberListToString(memberList)); + memberListToString(memberList)); } /** @@ -1324,7 +1331,7 @@ public void testMetadata() throws Exception { assertNotNull(dimension.getDefaultHierarchy()); assertEquals( dimension.getName().equals("Time") - ? Dimension.Type.TIME + ? Dimension.Type.TIME : dimension.getName().equals("Measures") ? Dimension.Type.MEASURE : Dimension.Type.OTHER, @@ -1419,7 +1426,7 @@ public void testMetadata() throws Exception { assertNotNull(member); Member member2 = cube.lookupMember("Product", "All Products", "Food"); assertEquals(member, member2); - assertEquals("[Product].[All Products].[Food]", + assertEquals("[Product].[All Products].[Food]", member.getUniqueName()); assertEquals("Food", member.getName()); assertEquals("[Product].[Product Family]", @@ -1474,7 +1481,7 @@ public void testMetadata() throws Exception { assertEquals(Member.Type.FORMULA, measure.getMemberType()); assertTrue(measure.isCalculated()); } else { - assertEquals(Member.Type.MEASURE, measure.getMemberType()); + assertEquals(Member.Type.MEASURE, measure.getMemberType()); assertFalse(measure.isCalculated()); } assertNotNull(measure.getName()); @@ -1562,7 +1569,7 @@ public void testCubeType() throws Throwable { } /** - * Tests the type-derivation for query axes + * Tests the type-derivation for query axes * ({@link org.olap4j.mdx.SelectNode#getAxisList()} and * {@link org.olap4j.mdx.SelectNode#getFilterAxis()}), and the * {@link org.olap4j.type.SetType}, @@ -1649,7 +1656,7 @@ public void testAxisType() throws Throwable { assertFalse(memberType.usesDimension(storeDimension, false)); assertTrue(memberType.usesDimension(customersDimension, false)); assertTrue(memberType.usesDimension(customersDimension, true)); - + // Filter final AxisNode filterAxis = select.getFilterAxis(); diff --git a/testsrc/org/olap4j/MetadataTest.java b/testsrc/org/olap4j/MetadataTest.java index 476acec..e9cd0d9 100644 --- a/testsrc/org/olap4j/MetadataTest.java +++ b/testsrc/org/olap4j/MetadataTest.java @@ -1,491 +1,491 @@ -/* -// This software is subject to the terms of the Common Public License -// Agreement, available at the following URL: -// http://www.opensource.org/licenses/cpl.html. -// Copyright (C) 2007-2007 Julian Hyde -// All Rights Reserved. -// You must accept the terms of that agreement to use this software. -*/ -package org.olap4j; - -import junit.framework.TestCase; -import org.olap4j.metadata.*; -import org.olap4j.test.TestContext; - -import java.sql.*; -import java.util.*; - -/** - * Unit test for olap4j metadata methods. - * - * @version $Id$ - */ -public class MetadataTest extends TestCase { - private static final String NL = System.getProperty("line.separator"); - - private final TestContext.Tester tester; - private Connection connection; - private String catalogName; - private OlapConnection olapConnection; - private OlapDatabaseMetaData olapDatabaseMetaData; - private final String propertyNamePattern = null; - private final String dataSourceName = "xx"; - - private static final List CUBE_COLUMN_NAMES = Arrays.asList("CATALOG_NAME", "SCHEMA_NAME", "CUBE_NAME", "CUBE_TYPE", "CUBE_GUID", "CREATED_ON", "LAST_SCHEMA_UPDATE", "SCHEMA_UPDATED_BY", "LAST_DATA_UPDATE", "DATA_UPDATED_BY", "IS_DRILLTHROUGH_ENABLED", "IS_WRITE_ENABLED", "IS_LINKABLE", "IS_SQL_ENABLED", "DESCRIPTION"); - private static final List LITERALS_COLUMN_NAMES = Arrays.asList("LITERAL_NAME", "LITERAL_VALUE", "LITERAL_INVALID_CHARS", "LITERAL_INVALID_STARTING_CHARS", "LITERAL_MAX_LENGTH"); - private static final List SETS_COLUMN_NAMES = Arrays.asList("CATALOG_NAME", "SCHEMA_NAME", "CUBE_NAME", "SET_NAME", "SCOPE"); - private static final List PROPERTIES_COLUMN_NAMES = Arrays.asList("CATALOG_NAME", "SCHEMA_NAME", "CUBE_NAME", "DIMENSION_UNIQUE_NAME", "HIERARCHY_UNIQUE_NAME", "LEVEL_UNIQUE_NAME", "MEMBER_UNIQUE_NAME", "PROPERTY_NAME", "PROPERTY_CAPTION", "PROPERTY_TYPE", "DATA_TYPE", "PROPERTY_CONTENT_TYPE", "DESCRIPTION"); - private static final List MEMBERS_COLUMN_NAMES = Arrays.asList("CATALOG_NAME", "SCHEMA_NAME", "CUBE_NAME", "DIMENSION_UNIQUE_NAME", "HIERARCHY_UNIQUE_NAME", "LEVEL_UNIQUE_NAME", "LEVEL_NUMBER", "MEMBER_ORDINAL", "MEMBER_NAME", "MEMBER_UNIQUE_NAME", "MEMBER_TYPE", "MEMBER_GUID", "MEMBER_CAPTION", "CHILDREN_CARDINALITY", "PARENT_LEVEL", "PARENT_UNIQUE_NAME", "PARENT_COUNT", "TREE_OP", "DEPTH"); - private static final List MEASURES_COLUMN_NAMES = Arrays.asList("CATALOG_NAME", "SCHEMA_NAME", "CUBE_NAME", "MEASURE_NAME", "MEASURE_UNIQUE_NAME", "MEASURE_CAPTION", "MEASURE_GUID", "MEASURE_AGGREGATOR", "DATA_TYPE", "MEASURE_IS_VISIBLE", "LEVELS_LIST", "DESCRIPTION"); - private static final List LEVELS_COLUMN_NAMES = Arrays.asList("CATALOG_NAME", "SCHEMA_NAME", "CUBE_NAME", "DIMENSION_UNIQUE_NAME", "HIERARCHY_UNIQUE_NAME", "LEVEL_NAME", "LEVEL_UNIQUE_NAME", "LEVEL_GUID", "LEVEL_CAPTION", "LEVEL_NUMBER", "LEVEL_CARDINALITY", "LEVEL_TYPE", "CUSTOM_ROLLUP_SETTINGS", "LEVEL_UNIQUE_SETTINGS", "LEVEL_IS_VISIBLE", "DESCRIPTION"); - private static final List HIERARCHIES_COLUMN_NAMES = Arrays.asList("CATALOG_NAME", "SCHEMA_NAME", "CUBE_NAME", "DIMENSION_UNIQUE_NAME", "HIERARCHY_NAME", "HIERARCHY_UNIQUE_NAME", "HIERARCHY_GUID", "HIERARCHY_CAPTION", "DIMENSION_TYPE", "HIERARCHY_CARDINALITY", "DEFAULT_MEMBER", "ALL_MEMBER", "DESCRIPTION", "STRUCTURE", "IS_VIRTUAL", "IS_READWRITE", "DIMENSION_UNIQUE_SETTINGS", "DIMENSION_IS_VISIBLE", "HIERARCHY_ORDINAL", "DIMENSION_IS_SHARED", "PARENT_CHILD"); - private static final List FUNCTIONS_COLUMN_NAMES = Arrays.asList("FUNCTION_NAME", "DESCRIPTION", "PARAMETER_LIST", "RETURN_TYPE", "ORIGIN", "INTERFACE_NAME", "LIBRARY_NAME", "CAPTION"); - private static final List DIMENSIONS_COLUMN_NAMES = Arrays.asList("CATALOG_NAME", "SCHEMA_NAME", "CUBE_NAME", "DIMENSION_NAME", "DIMENSION_UNIQUE_NAME", "DIMENSION_GUID", "DIMENSION_CAPTION", "DIMENSION_ORDINAL", "DIMENSION_TYPE", "DIMENSION_CARDINALITY", "DEFAULT_HIERARCHY", "DESCRIPTION", "IS_VIRTUAL", "IS_READWRITE", "DIMENSION_UNIQUE_SETTINGS", "DIMENSION_MASTER_UNIQUE_NAME", "DIMENSION_IS_VISIBLE"); - private static final List DATABASE_PROPERTIES_COLUMN_NAMES = Arrays.asList("PROPERTY_NAME", "PROPERTY_DESCRIPTION", "PROPERTY_TYPE", "PROPERTY_ACCESS_TYPE", "IS_REQUIRED", "PROPERTY_VALUE"); - private static final List DATASOURCES_COLUMN_NAMES = Arrays.asList("DATA_SOURCE_NAME", "DATA_SOURCE_DESCRIPTION", "URL", "DATA_SOURCE_INFO", "PROVIDER_NAME", "PROVIDER_TYPE", "AUTHENTICATION_MODE"); - private static final List CATALOGS_COLUMN_NAMES = Arrays.asList("TABLE_CAT"); - private static final List SCHEMAS_COLUMN_NAMES = Arrays.asList("TABLE_SCHEM", "TABLE_CAT"); - private static final List ACTIONS_COLUMN_NAMES = Arrays.asList("SCHEMA_NAME", "CUBE_NAME", "ACTION_NAME", "COORDINATE", "COORDINATE_TYPE"); - - public MetadataTest() throws SQLException { - tester = TestContext.instance().getTester(); - } - - protected void setUp() throws SQLException { - connection = tester.createConnection(); - catalogName = connection.getCatalog(); - olapConnection = - tester.getWrapper().unwrap(connection, OlapConnection.class); - olapDatabaseMetaData = olapConnection.getMetaData(); - } - - protected void tearDown() throws Exception { - if (connection != null && !connection.isClosed()) { - connection.close(); - connection = null; - } - } - - // ~ Helper methods ---------- - - private void assertContains(String seek, String s) { - if (s.indexOf(seek) < 0) { - fail("expected to find '" + seek + "' in '" + s + "'"); - } - } - - private void assertNotContains(String seek, String s) { - if (s.indexOf(seek) >= 0) { - fail("expected not to find '" + seek + "' in '" + s + "'"); - } - } - - private int linecount(String s) { - int i = 0; - int count = 0; - while (i < s.length()) { - int nl = s.indexOf('\n', i); - if (nl < 0) { - break; - } - i = nl + 1; - ++count; - } - return count; - } - - // ~ Tests follow ------------- - - public void testDatabaseMetaData() throws SQLException { - assertEquals("" + catalogName + "", catalogName); - - DatabaseMetaData databaseMetaData = connection.getMetaData(); - switch (tester.getFlavor()) { - case XMLA: - // FIXME: implement getDatabaseXxxVersion in XMLA driver - break; - default: - assertTrue(databaseMetaData.getDatabaseMajorVersion() > 0); - assertTrue(databaseMetaData.getDatabaseMinorVersion() >= 0); -// assertTrue(databaseMetaData.getDatabaseProductName() != null); - assertTrue(databaseMetaData.getDatabaseProductVersion() != null); - break; - } - assertTrue(databaseMetaData.getDriverName() != null); - assertTrue(databaseMetaData.getDriverVersion() != null); - - // mondrian-specific - switch (tester.getFlavor()) { - case MONDRIAN: - assertTrue(databaseMetaData.isReadOnly()); - assertNull(databaseMetaData.getUserName()); - assertNotNull(databaseMetaData.getURL()); - break; - } - - // unwrap connection; may or may not be the same object as connection; - // check extended methods - - // also unwrap metadata from regular connection - assertTrue( - ((OlapWrapper) databaseMetaData).isWrapperFor( - OlapDatabaseMetaData.class)); - assertFalse( - ((OlapWrapper) databaseMetaData).isWrapperFor( - OlapStatement.class)); - OlapDatabaseMetaData olapDatabaseMetaData1 = - ((OlapWrapper) databaseMetaData).unwrap( - OlapDatabaseMetaData.class); - assertTrue( - olapDatabaseMetaData1.getDriverName().equals( - olapDatabaseMetaData.getDriverName())); - switch (tester.getFlavor()) { - case XMLA: - // FIXME: implement getDatabaseXxxVersion in XMLA driver - break; - default: - assertTrue( - olapDatabaseMetaData1.getDatabaseProductVersion().equals( - olapDatabaseMetaData.getDatabaseProductVersion())); - } - } - - public void testSchema() throws OlapException { - // check schema - final Schema schema1 = olapConnection.getSchema(); - assertEquals(schema1.getName(), "FoodMart"); - } - - public void testDatabaseMetaDataGetActions() throws SQLException { - String s = checkResultSet( - olapDatabaseMetaData.getActions( - catalogName, null, null, null), - ACTIONS_COLUMN_NAMES); - assertEquals("", s); // mondrian has no actions - } - - public void testDatabaseMetaDataGetDatasources() throws SQLException { - String s = checkResultSet( - olapDatabaseMetaData.getDatasources(), - DATASOURCES_COLUMN_NAMES); - switch (tester.getFlavor()) { - case MONDRIAN: - assertEquals(TestContext.fold("DATA_SOURCE_NAME=xxx," - + " DATA_SOURCE_DESCRIPTION=null," - + " URL=null," - + " DATA_SOURCE_INFO=xxx," - + " PROVIDER_NAME=null," - + " PROVIDER_TYPE=MDP," - + " AUTHENTICATION_MODE=null\n"), - s); - break; - case XMLA: - assertEquals(TestContext.fold("DATA_SOURCE_NAME=MondrianFoodMart," - + " DATA_SOURCE_DESCRIPTION=Mondrian FoodMart data source," - + " URL=http://localhost:8080/mondrian/xmla," - + " DATA_SOURCE_INFO=MondrianFoodMart," - + " PROVIDER_NAME=Mondrian," - + " PROVIDER_TYPE=MDP," - + " AUTHENTICATION_MODE=Unauthenticated\n"), - s); - break; - } - } - - public void testDatabaseMetaDataGetCatalogs() throws SQLException { - String s = checkResultSet( - olapDatabaseMetaData.getCatalogs(), - CATALOGS_COLUMN_NAMES); - assertEquals(TestContext.fold("TABLE_CAT=" + catalogName + "\n"), s); - } - - public void testDatabaseMetaDataGetSchemas() throws SQLException { - String s = checkResultSet( - olapDatabaseMetaData.getSchemas(), - SCHEMAS_COLUMN_NAMES); - assertEquals(TestContext.fold("TABLE_SCHEM=FoodMart, TABLE_CAT=" + catalogName + "\n"), s); - } - - public void testDatabaseMetaDataGetLiterals() throws SQLException { - String s = checkResultSet( - olapDatabaseMetaData.getLiterals(), - LITERALS_COLUMN_NAMES); - assertContains("LITERAL_NAME=DBLITERAL_QUOTE, LITERAL_VALUE=[, ", s); - } - - public void testDatabaseMetaDataGetDatabaseProperties() throws SQLException { - String s = checkResultSet( - olapDatabaseMetaData.getDatabaseProperties( - dataSourceName, propertyNamePattern), - DATABASE_PROPERTIES_COLUMN_NAMES); - assertContains("PROPERTY_NAME=ProviderName, ", s); - } - - public void testDatabaseMetaDataGetProperties() throws SQLException { - String s = checkResultSet( - olapDatabaseMetaData.getProperties( - catalogName, null, null, null, null, null, null, null), - PROPERTIES_COLUMN_NAMES); - assertContains("CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Warehouse and Sales, DIMENSION_UNIQUE_NAME=[Store], HIERARCHY_UNIQUE_NAME=[Store], LEVEL_UNIQUE_NAME=[Store].[Store Name], MEMBER_UNIQUE_NAME=null, PROPERTY_NAME=Frozen Sqft, PROPERTY_CAPTION=Frozen Sqft, PROPERTY_TYPE=1, DATA_TYPE=5, PROPERTY_CONTENT_TYPE=0, DESCRIPTION=Warehouse and Sales Cube - Store Hierarchy - Store Name Level - Frozen Sqft Property", s); - assertEquals(s, 70, linecount(s)); - - s = checkResultSet( - olapDatabaseMetaData.getProperties( - catalogName, "FoodMart", "Sales", - null, null, "[Store].[Store Name]", - null, null), - PROPERTIES_COLUMN_NAMES); - assertContains("CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Store], HIERARCHY_UNIQUE_NAME=[Store], LEVEL_UNIQUE_NAME=[Store].[Store Name], MEMBER_UNIQUE_NAME=null, PROPERTY_NAME=Has coffee bar, PROPERTY_CAPTION=Has coffee bar, PROPERTY_TYPE=1, DATA_TYPE=11, PROPERTY_CONTENT_TYPE=0, DESCRIPTION=Sales Cube - Store Hierarchy - Store Name Level - Has coffee bar Property", s); - assertNotContains("CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Warehouse and Sales, ", s); - assertEquals(8, linecount(s)); - } - - public void testDatabaseMetaDataGetMdxKeywords() throws SQLException { - String keywords = olapDatabaseMetaData.getMdxKeywords(); - assertNotNull(keywords); - assertContains(",From,", keywords); - } - - public void testDatabaseMetaDataGetCubes() throws SQLException { - String s = checkResultSet( - olapDatabaseMetaData.getCubes( - catalogName, - null, - null), - CUBE_COLUMN_NAMES); - assertContains("CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, ", s); - - s = checkResultSet( - olapDatabaseMetaData.getCubes( - catalogName, - null, - "Warehouse and Sales"), - CUBE_COLUMN_NAMES); - assertContains(", CUBE_NAME=Warehouse and Sales,", s); - assertNotContains(", CUBE_NAME=Warehouse,", s); - - s = checkResultSet( - olapDatabaseMetaData.getCubes( - catalogName, - null, - "Warehouse%"), - CUBE_COLUMN_NAMES); - assertTrue(s.contains(", CUBE_NAME=Warehouse and Sales")); - assertTrue(s.contains(", CUBE_NAME=Warehouse")); - } - - public void testGetCatalogs() throws SQLException { - int k = 0; - for (Catalog catalog : olapConnection.getCatalogs()) { - ++k; - assertEquals(catalog.getMetaData(), olapDatabaseMetaData); - for (Schema schema : catalog.getSchemas()) { - ++k; - assertEquals(schema.getCatalog(), catalog); - for (Cube cube : schema.getCubes()) { - ++k; - assertEquals(cube.getSchema(), schema); - } - for (Dimension dimension : schema.getSharedDimensions()) { - ++k; - } - for (Locale locale : schema.getSupportedLocales()) { - ++k; - } - } - } - assertTrue(k > 0); - } - - public void testDatabaseMetaDataGetDimensions() throws SQLException { - String s = checkResultSet( - olapDatabaseMetaData.getDimensions( - catalogName, null, null, null), - DIMENSIONS_COLUMN_NAMES); - assertContains("CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_NAME=Education Level, DIMENSION_UNIQUE_NAME=[Education Level], DIMENSION_GUID=null, DIMENSION_CAPTION=Education Level, DIMENSION_ORDINAL=9, DIMENSION_TYPE=3, DIMENSION_CARDINALITY=6, DEFAULT_HIERARCHY=[Education Level], DESCRIPTION=Sales Cube - Education Level Dimension, IS_VIRTUAL=false, IS_READWRITE=false, DIMENSION_UNIQUE_SETTINGS=0, DIMENSION_MASTER_UNIQUE_NAME=null, DIMENSION_IS_VISIBLE=true", s); - assertEquals(62, linecount(s)); - } - - public void testDatabaseMetaDataGetFunctions() throws SQLException { - String s = checkResultSet( - olapDatabaseMetaData.getOlapFunctions(null), - FUNCTIONS_COLUMN_NAMES); - assertContains("FUNCTION_NAME=Name, DESCRIPTION=Returns the name of a member., PARAMETER_LIST=Member, RETURN_TYPE=8, ORIGIN=1, INTERFACE_NAME=, LIBRARY_NAME=null, CAPTION=Name", s); - // Mondrian has 361 functions (as of 2008/1/23) - final int functionCount = linecount(s); - assertTrue(functionCount + " functions", functionCount > 360); - - // Mondrian has 7 variants of the Ascendants and Descendants functions - s = checkResultSet( - olapDatabaseMetaData.getOlapFunctions("%scendants"), - FUNCTIONS_COLUMN_NAMES); - assertEquals(s, 7, linecount(s)); - } - - public void testDatabaseMetaDataGetHierarchies() throws SQLException { - String s = checkResultSet( - olapDatabaseMetaData.getHierarchies( - catalogName, null, null, null, null), - HIERARCHIES_COLUMN_NAMES); - assertContains("CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=HR, DIMENSION_UNIQUE_NAME=[Employees], HIERARCHY_NAME=Employees, HIERARCHY_UNIQUE_NAME=[Employees], HIERARCHY_GUID=null, HIERARCHY_CAPTION=Employees, DIMENSION_TYPE=3, HIERARCHY_CARDINALITY=1156, DEFAULT_MEMBER=[Employees].[All Employees], ALL_MEMBER=[Employees].[All Employees], DESCRIPTION=HR Cube - Employees Hierarchy, STRUCTURE=0, IS_VIRTUAL=false, IS_READWRITE=false, DIMENSION_UNIQUE_SETTINGS=0, DIMENSION_IS_VISIBLE=true, HIERARCHY_ORDINAL=7, DIMENSION_IS_SHARED=true, PARENT_CHILD=true", s); - - s = checkResultSet( - olapDatabaseMetaData.getHierarchies( - catalogName, null, "Sales", null, "Store"), - HIERARCHIES_COLUMN_NAMES); - assertEquals(TestContext.fold("CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Store], HIERARCHY_NAME=Store, HIERARCHY_UNIQUE_NAME=[Store], HIERARCHY_GUID=null, HIERARCHY_CAPTION=Store, DIMENSION_TYPE=3, HIERARCHY_CARDINALITY=63, DEFAULT_MEMBER=[Store].[All Stores], ALL_MEMBER=[Store].[All Stores], DESCRIPTION=Sales Cube - Store Hierarchy, STRUCTURE=0, IS_VIRTUAL=false, IS_READWRITE=false, DIMENSION_UNIQUE_SETTINGS=0, DIMENSION_IS_VISIBLE=true, HIERARCHY_ORDINAL=1, DIMENSION_IS_SHARED=true, PARENT_CHILD=false\n"), s); - } - - public void testDatabaseMetaDataGetLevels() throws SQLException { - String s = checkResultSet( - olapDatabaseMetaData.getLevels( - catalogName, null, null, null, null, null), - LEVELS_COLUMN_NAMES); - assertContains("CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Product], HIERARCHY_UNIQUE_NAME=[Product], LEVEL_NAME=Product Category, LEVEL_UNIQUE_NAME=[Product].[Product Category], LEVEL_GUID=null, LEVEL_CAPTION=Product Category, LEVEL_NUMBER=3, LEVEL_CARDINALITY=55, LEVEL_TYPE=0, CUSTOM_ROLLUP_SETTINGS=0, LEVEL_UNIQUE_SETTINGS=0, LEVEL_IS_VISIBLE=true, DESCRIPTION=Sales Cube - Product HierarchyProduct Category Level", s); - - s = checkResultSet( - olapDatabaseMetaData.getLevels( - catalogName, null, "Sales", null, "[Store]", null), - LEVELS_COLUMN_NAMES); - assertEquals(s, 5, linecount(s)); - } - - public void testDatabaseMetaDataGetLiterals2() throws SQLException { - String s = checkResultSet( - olapDatabaseMetaData.getLiterals(), - LITERALS_COLUMN_NAMES); - assertContains("LITERAL_NAME=DBLITERAL_QUOTE, LITERAL_VALUE=[, LITERAL_INVALID_CHARS=null, LITERAL_INVALID_STARTING_CHARS=null, LITERAL_MAX_LENGTH=-1", s); - assertEquals(17, linecount(s)); - } - - public void testDatabaseMetaDataGetMeasures() throws SQLException { - String s = checkResultSet( - olapDatabaseMetaData.getMeasures( - catalogName, null, null, null, null), - MEASURES_COLUMN_NAMES); - assertContains("CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, MEASURE_NAME=Profit, MEASURE_UNIQUE_NAME=[Measures].[Profit], MEASURE_CAPTION=Profit, MEASURE_GUID=null, MEASURE_AGGREGATOR=127, DATA_TYPE=130, MEASURE_IS_VISIBLE=true, LEVELS_LIST=null, DESCRIPTION=Sales Cube - Profit Member", s); - - // wildcard match - s = checkResultSet( - olapDatabaseMetaData.getMeasures( - catalogName, null, "Sales", "%Sales", null), - MEASURES_COLUMN_NAMES); - assertEquals(s, 3, linecount(s)); - - // wildcard match - s = checkResultSet( - olapDatabaseMetaData.getMeasures( - catalogName, null, "Sales", null, "[Measures].[Unit Sales]"), - MEASURES_COLUMN_NAMES); - assertEquals(s, 1, linecount(s)); - } - - public void testDatabaseMetaDataGetMembers() throws SQLException { - String s = checkResultSet( - olapDatabaseMetaData.getMembers( - catalogName, "FoodMart", "Sales", null, "[Gender]", null, null, - null), - MEMBERS_COLUMN_NAMES); - assertEquals( - TestContext.fold("CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Gender], HIERARCHY_UNIQUE_NAME=[Gender], LEVEL_UNIQUE_NAME=[Gender].[(All)], LEVEL_NUMBER=0, MEMBER_ORDINAL=0, MEMBER_NAME=All Gender, MEMBER_UNIQUE_NAME=[Gender].[All Gender], MEMBER_TYPE=2, MEMBER_GUID=null, MEMBER_CAPTION=All Gender, CHILDREN_CARDINALITY=2, PARENT_LEVEL=0, PARENT_UNIQUE_NAME=null, PARENT_COUNT=0, TREE_OP=null, DEPTH=0\n" - + "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Gender], HIERARCHY_UNIQUE_NAME=[Gender], LEVEL_UNIQUE_NAME=[Gender].[Gender], LEVEL_NUMBER=1, MEMBER_ORDINAL=1, MEMBER_NAME=F, MEMBER_UNIQUE_NAME=[Gender].[All Gender].[F], MEMBER_TYPE=1, MEMBER_GUID=null, MEMBER_CAPTION=F, CHILDREN_CARDINALITY=0, PARENT_LEVEL=0, PARENT_UNIQUE_NAME=[Gender].[All Gender], PARENT_COUNT=1, TREE_OP=null, DEPTH=1\n" - + "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Gender], HIERARCHY_UNIQUE_NAME=[Gender], LEVEL_UNIQUE_NAME=[Gender].[Gender], LEVEL_NUMBER=1, MEMBER_ORDINAL=2, MEMBER_NAME=M, MEMBER_UNIQUE_NAME=[Gender].[All Gender].[M], MEMBER_TYPE=1, MEMBER_GUID=null, MEMBER_CAPTION=M, CHILDREN_CARDINALITY=0, PARENT_LEVEL=0, PARENT_UNIQUE_NAME=[Gender].[All Gender], PARENT_COUNT=1, TREE_OP=null, DEPTH=1\n"), - s); - - // by member unique name - s = checkResultSet( - olapDatabaseMetaData.getMembers( - catalogName, "FoodMart", "Sales", null, null, null, - "[Time].[1997].[Q2].[4]", null), - MEMBERS_COLUMN_NAMES); - assertEquals(TestContext.fold("CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Time], HIERARCHY_UNIQUE_NAME=[Time], LEVEL_UNIQUE_NAME=[Time].[Month], LEVEL_NUMBER=2, MEMBER_ORDINAL=6, MEMBER_NAME=4, MEMBER_UNIQUE_NAME=[Time].[1997].[Q2].[4], MEMBER_TYPE=1, MEMBER_GUID=null, MEMBER_CAPTION=4, CHILDREN_CARDINALITY=0, PARENT_LEVEL=1, PARENT_UNIQUE_NAME=[Time].[1997].[Q2], PARENT_COUNT=1, TREE_OP=null, DEPTH=2\n"), - s); - - // with treeop - s = checkResultSet( - olapDatabaseMetaData.getMembers( - catalogName, "FoodMart", "Sales", null, null, null, - "[Customers].[USA].[CA]", - EnumSet.of(Member.TreeOp.ANCESTORS, Member.TreeOp.SIBLINGS)), - MEMBERS_COLUMN_NAMES); - switch (tester.getFlavor()) { - case MONDRIAN: - // TODO: fix mondrian driver so that members are returned sorted - // by level depth - assertEquals( - TestContext.fold("CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Customers], HIERARCHY_UNIQUE_NAME=[Customers], LEVEL_UNIQUE_NAME=[Customers].[State Province], LEVEL_NUMBER=2, MEMBER_ORDINAL=7235, MEMBER_NAME=OR, MEMBER_UNIQUE_NAME=[Customers].[All Customers].[USA].[OR], MEMBER_TYPE=1, MEMBER_GUID=null, MEMBER_CAPTION=OR, CHILDREN_CARDINALITY=11, PARENT_LEVEL=1, PARENT_UNIQUE_NAME=[Customers].[All Customers].[USA], PARENT_COUNT=1, TREE_OP=null, DEPTH=2\n" - + "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Customers], HIERARCHY_UNIQUE_NAME=[Customers], LEVEL_UNIQUE_NAME=[Customers].[State Province], LEVEL_NUMBER=2, MEMBER_ORDINAL=8298, MEMBER_NAME=WA, MEMBER_UNIQUE_NAME=[Customers].[All Customers].[USA].[WA], MEMBER_TYPE=1, MEMBER_GUID=null, MEMBER_CAPTION=WA, CHILDREN_CARDINALITY=22, PARENT_LEVEL=1, PARENT_UNIQUE_NAME=[Customers].[All Customers].[USA], PARENT_COUNT=1, TREE_OP=null, DEPTH=2\n" - + "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Customers], HIERARCHY_UNIQUE_NAME=[Customers], LEVEL_UNIQUE_NAME=[Customers].[Country], LEVEL_NUMBER=1, MEMBER_ORDINAL=2966, MEMBER_NAME=USA, MEMBER_UNIQUE_NAME=[Customers].[All Customers].[USA], MEMBER_TYPE=1, MEMBER_GUID=null, MEMBER_CAPTION=USA, CHILDREN_CARDINALITY=3, PARENT_LEVEL=0, PARENT_UNIQUE_NAME=[Customers].[All Customers], PARENT_COUNT=1, TREE_OP=null, DEPTH=1\n" - + "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Customers], HIERARCHY_UNIQUE_NAME=[Customers], LEVEL_UNIQUE_NAME=[Customers].[(All)], LEVEL_NUMBER=0, MEMBER_ORDINAL=0, MEMBER_NAME=All Customers, MEMBER_UNIQUE_NAME=[Customers].[All Customers], MEMBER_TYPE=2, MEMBER_GUID=null, MEMBER_CAPTION=All Customers, CHILDREN_CARDINALITY=3, PARENT_LEVEL=0, PARENT_UNIQUE_NAME=null, PARENT_COUNT=0, TREE_OP=null, DEPTH=0\n"), - s); - break; - default: - assertEquals( - TestContext.fold("CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Customers], HIERARCHY_UNIQUE_NAME=[Customers], LEVEL_UNIQUE_NAME=[Customers].[(All)], LEVEL_NUMBER=0, MEMBER_ORDINAL=0, MEMBER_NAME=All Customers, MEMBER_UNIQUE_NAME=[Customers].[All Customers], MEMBER_TYPE=2, MEMBER_GUID=null, MEMBER_CAPTION=All Customers, CHILDREN_CARDINALITY=3, PARENT_LEVEL=0, PARENT_UNIQUE_NAME=null, PARENT_COUNT=0, TREE_OP=null, DEPTH=0\n" - + "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Customers], HIERARCHY_UNIQUE_NAME=[Customers], LEVEL_UNIQUE_NAME=[Customers].[Country], LEVEL_NUMBER=1, MEMBER_ORDINAL=2966, MEMBER_NAME=USA, MEMBER_UNIQUE_NAME=[Customers].[All Customers].[USA], MEMBER_TYPE=1, MEMBER_GUID=null, MEMBER_CAPTION=USA, CHILDREN_CARDINALITY=3, PARENT_LEVEL=0, PARENT_UNIQUE_NAME=[Customers].[All Customers], PARENT_COUNT=1, TREE_OP=null, DEPTH=1\n" - + "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Customers], HIERARCHY_UNIQUE_NAME=[Customers], LEVEL_UNIQUE_NAME=[Customers].[State Province], LEVEL_NUMBER=2, MEMBER_ORDINAL=7235, MEMBER_NAME=OR, MEMBER_UNIQUE_NAME=[Customers].[All Customers].[USA].[OR], MEMBER_TYPE=1, MEMBER_GUID=null, MEMBER_CAPTION=OR, CHILDREN_CARDINALITY=11, PARENT_LEVEL=1, PARENT_UNIQUE_NAME=[Customers].[All Customers].[USA], PARENT_COUNT=1, TREE_OP=null, DEPTH=2\n" - + "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Customers], HIERARCHY_UNIQUE_NAME=[Customers], LEVEL_UNIQUE_NAME=[Customers].[State Province], LEVEL_NUMBER=2, MEMBER_ORDINAL=8298, MEMBER_NAME=WA, MEMBER_UNIQUE_NAME=[Customers].[All Customers].[USA].[WA], MEMBER_TYPE=1, MEMBER_GUID=null, MEMBER_CAPTION=WA, CHILDREN_CARDINALITY=22, PARENT_LEVEL=1, PARENT_UNIQUE_NAME=[Customers].[All Customers].[USA], PARENT_COUNT=1, TREE_OP=null, DEPTH=2\n"), - s); - break; - } - } - - public void testDatabaseMetaDataGetSets() throws SQLException { - String s = checkResultSet( - olapDatabaseMetaData.getSets( - catalogName, null, null, null), - SETS_COLUMN_NAMES); - assertEquals(TestContext.fold("CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Warehouse, SET_NAME=[Top Sellers], SCOPE=1\n"), s); - - s = checkResultSet( - olapDatabaseMetaData.getSets( - catalogName, null, null, "non existent set"), - SETS_COLUMN_NAMES); - assertEquals("", s); - - } - - // todo: More tests required for other methods on DatabaseMetaData - - private String checkResultSet( - ResultSet resultSet, - List columnNames) throws SQLException - { - ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); - final int columnCount = resultSetMetaData.getColumnCount(); - if (columnNames != null) { - System.out.println(columnNames); - assertEquals( - columnNames.size(), - columnCount); - int k = -1; - for (String columnName : columnNames) { - ++k; - assertEquals( - columnName, - resultSetMetaData.getColumnName(k + 1)); - } - } - assertNotNull(resultSet); - int k = 0; - StringBuilder buf = new StringBuilder(); - while (resultSet.next()) { - ++k; - for (int i = 0; i < columnCount; i++) { - if (i > 0) { - buf.append(", "); - } - String s = resultSet.getString(i + 1); - buf.append(resultSetMetaData.getColumnName(i + 1)) - .append('=') - .append(s); - } - buf.append(NL); - } - assertTrue(k >= 0); - assertTrue(resultSet.isAfterLast()); - return buf.toString(); - } -} - -// End MetadataTest.java +/* +// This software is subject to the terms of the Common Public License +// Agreement, available at the following URL: +// http://www.opensource.org/licenses/cpl.html. +// Copyright (C) 2007-2007 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j; + +import junit.framework.TestCase; +import org.olap4j.metadata.*; +import org.olap4j.test.TestContext; + +import java.sql.*; +import java.util.*; + +/** + * Unit test for olap4j metadata methods. + * + * @version $Id$ + */ +public class MetadataTest extends TestCase { + private static final String NL = System.getProperty("line.separator"); + + private final TestContext.Tester tester; + private Connection connection; + private String catalogName; + private OlapConnection olapConnection; + private OlapDatabaseMetaData olapDatabaseMetaData; + private final String propertyNamePattern = null; + private final String dataSourceName = "xx"; + + private static final List CUBE_COLUMN_NAMES = Arrays.asList("CATALOG_NAME", "SCHEMA_NAME", "CUBE_NAME", "CUBE_TYPE", "CUBE_GUID", "CREATED_ON", "LAST_SCHEMA_UPDATE", "SCHEMA_UPDATED_BY", "LAST_DATA_UPDATE", "DATA_UPDATED_BY", "IS_DRILLTHROUGH_ENABLED", "IS_WRITE_ENABLED", "IS_LINKABLE", "IS_SQL_ENABLED", "DESCRIPTION"); + private static final List LITERALS_COLUMN_NAMES = Arrays.asList("LITERAL_NAME", "LITERAL_VALUE", "LITERAL_INVALID_CHARS", "LITERAL_INVALID_STARTING_CHARS", "LITERAL_MAX_LENGTH"); + private static final List SETS_COLUMN_NAMES = Arrays.asList("CATALOG_NAME", "SCHEMA_NAME", "CUBE_NAME", "SET_NAME", "SCOPE"); + private static final List PROPERTIES_COLUMN_NAMES = Arrays.asList("CATALOG_NAME", "SCHEMA_NAME", "CUBE_NAME", "DIMENSION_UNIQUE_NAME", "HIERARCHY_UNIQUE_NAME", "LEVEL_UNIQUE_NAME", "MEMBER_UNIQUE_NAME", "PROPERTY_NAME", "PROPERTY_CAPTION", "PROPERTY_TYPE", "DATA_TYPE", "PROPERTY_CONTENT_TYPE", "DESCRIPTION"); + private static final List MEMBERS_COLUMN_NAMES = Arrays.asList("CATALOG_NAME", "SCHEMA_NAME", "CUBE_NAME", "DIMENSION_UNIQUE_NAME", "HIERARCHY_UNIQUE_NAME", "LEVEL_UNIQUE_NAME", "LEVEL_NUMBER", "MEMBER_ORDINAL", "MEMBER_NAME", "MEMBER_UNIQUE_NAME", "MEMBER_TYPE", "MEMBER_GUID", "MEMBER_CAPTION", "CHILDREN_CARDINALITY", "PARENT_LEVEL", "PARENT_UNIQUE_NAME", "PARENT_COUNT", "TREE_OP", "DEPTH"); + private static final List MEASURES_COLUMN_NAMES = Arrays.asList("CATALOG_NAME", "SCHEMA_NAME", "CUBE_NAME", "MEASURE_NAME", "MEASURE_UNIQUE_NAME", "MEASURE_CAPTION", "MEASURE_GUID", "MEASURE_AGGREGATOR", "DATA_TYPE", "MEASURE_IS_VISIBLE", "LEVELS_LIST", "DESCRIPTION"); + private static final List LEVELS_COLUMN_NAMES = Arrays.asList("CATALOG_NAME", "SCHEMA_NAME", "CUBE_NAME", "DIMENSION_UNIQUE_NAME", "HIERARCHY_UNIQUE_NAME", "LEVEL_NAME", "LEVEL_UNIQUE_NAME", "LEVEL_GUID", "LEVEL_CAPTION", "LEVEL_NUMBER", "LEVEL_CARDINALITY", "LEVEL_TYPE", "CUSTOM_ROLLUP_SETTINGS", "LEVEL_UNIQUE_SETTINGS", "LEVEL_IS_VISIBLE", "DESCRIPTION"); + private static final List HIERARCHIES_COLUMN_NAMES = Arrays.asList("CATALOG_NAME", "SCHEMA_NAME", "CUBE_NAME", "DIMENSION_UNIQUE_NAME", "HIERARCHY_NAME", "HIERARCHY_UNIQUE_NAME", "HIERARCHY_GUID", "HIERARCHY_CAPTION", "DIMENSION_TYPE", "HIERARCHY_CARDINALITY", "DEFAULT_MEMBER", "ALL_MEMBER", "DESCRIPTION", "STRUCTURE", "IS_VIRTUAL", "IS_READWRITE", "DIMENSION_UNIQUE_SETTINGS", "DIMENSION_IS_VISIBLE", "HIERARCHY_ORDINAL", "DIMENSION_IS_SHARED", "PARENT_CHILD"); + private static final List FUNCTIONS_COLUMN_NAMES = Arrays.asList("FUNCTION_NAME", "DESCRIPTION", "PARAMETER_LIST", "RETURN_TYPE", "ORIGIN", "INTERFACE_NAME", "LIBRARY_NAME", "CAPTION"); + private static final List DIMENSIONS_COLUMN_NAMES = Arrays.asList("CATALOG_NAME", "SCHEMA_NAME", "CUBE_NAME", "DIMENSION_NAME", "DIMENSION_UNIQUE_NAME", "DIMENSION_GUID", "DIMENSION_CAPTION", "DIMENSION_ORDINAL", "DIMENSION_TYPE", "DIMENSION_CARDINALITY", "DEFAULT_HIERARCHY", "DESCRIPTION", "IS_VIRTUAL", "IS_READWRITE", "DIMENSION_UNIQUE_SETTINGS", "DIMENSION_MASTER_UNIQUE_NAME", "DIMENSION_IS_VISIBLE"); + private static final List DATABASE_PROPERTIES_COLUMN_NAMES = Arrays.asList("PROPERTY_NAME", "PROPERTY_DESCRIPTION", "PROPERTY_TYPE", "PROPERTY_ACCESS_TYPE", "IS_REQUIRED", "PROPERTY_VALUE"); + private static final List DATASOURCES_COLUMN_NAMES = Arrays.asList("DATA_SOURCE_NAME", "DATA_SOURCE_DESCRIPTION", "URL", "DATA_SOURCE_INFO", "PROVIDER_NAME", "PROVIDER_TYPE", "AUTHENTICATION_MODE"); + private static final List CATALOGS_COLUMN_NAMES = Arrays.asList("TABLE_CAT"); + private static final List SCHEMAS_COLUMN_NAMES = Arrays.asList("TABLE_SCHEM", "TABLE_CAT"); + private static final List ACTIONS_COLUMN_NAMES = Arrays.asList("SCHEMA_NAME", "CUBE_NAME", "ACTION_NAME", "COORDINATE", "COORDINATE_TYPE"); + + public MetadataTest() throws SQLException { + tester = TestContext.instance().getTester(); + } + + protected void setUp() throws SQLException { + connection = tester.createConnection(); + catalogName = connection.getCatalog(); + olapConnection = + tester.getWrapper().unwrap(connection, OlapConnection.class); + olapDatabaseMetaData = olapConnection.getMetaData(); + } + + protected void tearDown() throws Exception { + if (connection != null && !connection.isClosed()) { + connection.close(); + connection = null; + } + } + + // ~ Helper methods ---------- + + private void assertContains(String seek, String s) { + if (s.indexOf(seek) < 0) { + fail("expected to find '" + seek + "' in '" + s + "'"); + } + } + + private void assertNotContains(String seek, String s) { + if (s.indexOf(seek) >= 0) { + fail("expected not to find '" + seek + "' in '" + s + "'"); + } + } + + private int linecount(String s) { + int i = 0; + int count = 0; + while (i < s.length()) { + int nl = s.indexOf('\n', i); + if (nl < 0) { + break; + } + i = nl + 1; + ++count; + } + return count; + } + + // ~ Tests follow ------------- + + public void testDatabaseMetaData() throws SQLException { + assertEquals("" + catalogName + "", catalogName); + + DatabaseMetaData databaseMetaData = connection.getMetaData(); + switch (tester.getFlavor()) { + case XMLA: + // FIXME: implement getDatabaseXxxVersion in XMLA driver + break; + default: + assertTrue(databaseMetaData.getDatabaseMajorVersion() > 0); + assertTrue(databaseMetaData.getDatabaseMinorVersion() >= 0); +// assertTrue(databaseMetaData.getDatabaseProductName() != null); + assertTrue(databaseMetaData.getDatabaseProductVersion() != null); + break; + } + assertTrue(databaseMetaData.getDriverName() != null); + assertTrue(databaseMetaData.getDriverVersion() != null); + + // mondrian-specific + switch (tester.getFlavor()) { + case MONDRIAN: + assertTrue(databaseMetaData.isReadOnly()); + assertNull(databaseMetaData.getUserName()); + assertNotNull(databaseMetaData.getURL()); + break; + } + + // unwrap connection; may or may not be the same object as connection; + // check extended methods + + // also unwrap metadata from regular connection + assertTrue( + ((OlapWrapper) databaseMetaData).isWrapperFor( + OlapDatabaseMetaData.class)); + assertFalse( + ((OlapWrapper) databaseMetaData).isWrapperFor( + OlapStatement.class)); + OlapDatabaseMetaData olapDatabaseMetaData1 = + ((OlapWrapper) databaseMetaData).unwrap( + OlapDatabaseMetaData.class); + assertTrue( + olapDatabaseMetaData1.getDriverName().equals( + olapDatabaseMetaData.getDriverName())); + switch (tester.getFlavor()) { + case XMLA: + // FIXME: implement getDatabaseXxxVersion in XMLA driver + break; + default: + assertTrue( + olapDatabaseMetaData1.getDatabaseProductVersion().equals( + olapDatabaseMetaData.getDatabaseProductVersion())); + } + } + + public void testSchema() throws OlapException { + // check schema + final Schema schema1 = olapConnection.getSchema(); + assertEquals(schema1.getName(), "FoodMart"); + } + + public void testDatabaseMetaDataGetActions() throws SQLException { + String s = checkResultSet( + olapDatabaseMetaData.getActions( + catalogName, null, null, null), + ACTIONS_COLUMN_NAMES); + assertEquals("", s); // mondrian has no actions + } + + public void testDatabaseMetaDataGetDatasources() throws SQLException { + String s = checkResultSet( + olapDatabaseMetaData.getDatasources(), + DATASOURCES_COLUMN_NAMES); + switch (tester.getFlavor()) { + case MONDRIAN: + assertEquals(TestContext.fold("DATA_SOURCE_NAME=xxx," + + " DATA_SOURCE_DESCRIPTION=null," + + " URL=null," + + " DATA_SOURCE_INFO=xxx," + + " PROVIDER_NAME=null," + + " PROVIDER_TYPE=MDP," + + " AUTHENTICATION_MODE=null\n"), + s); + break; + case XMLA: + assertEquals(TestContext.fold("DATA_SOURCE_NAME=MondrianFoodMart," + + " DATA_SOURCE_DESCRIPTION=Mondrian FoodMart data source," + + " URL=http://localhost:8080/mondrian/xmla," + + " DATA_SOURCE_INFO=MondrianFoodMart," + + " PROVIDER_NAME=Mondrian," + + " PROVIDER_TYPE=MDP," + + " AUTHENTICATION_MODE=Unauthenticated\n"), + s); + break; + } + } + + public void testDatabaseMetaDataGetCatalogs() throws SQLException { + String s = checkResultSet( + olapDatabaseMetaData.getCatalogs(), + CATALOGS_COLUMN_NAMES); + assertEquals(TestContext.fold("TABLE_CAT=" + catalogName + "\n"), s); + } + + public void testDatabaseMetaDataGetSchemas() throws SQLException { + String s = checkResultSet( + olapDatabaseMetaData.getSchemas(), + SCHEMAS_COLUMN_NAMES); + assertEquals(TestContext.fold("TABLE_SCHEM=FoodMart, TABLE_CAT=" + catalogName + "\n"), s); + } + + public void testDatabaseMetaDataGetLiterals() throws SQLException { + String s = checkResultSet( + olapDatabaseMetaData.getLiterals(), + LITERALS_COLUMN_NAMES); + assertContains("LITERAL_NAME=DBLITERAL_QUOTE, LITERAL_VALUE=[, ", s); + } + + public void testDatabaseMetaDataGetDatabaseProperties() throws SQLException { + String s = checkResultSet( + olapDatabaseMetaData.getDatabaseProperties( + dataSourceName, propertyNamePattern), + DATABASE_PROPERTIES_COLUMN_NAMES); + assertContains("PROPERTY_NAME=ProviderName, ", s); + } + + public void testDatabaseMetaDataGetProperties() throws SQLException { + String s = checkResultSet( + olapDatabaseMetaData.getProperties( + catalogName, null, null, null, null, null, null, null), + PROPERTIES_COLUMN_NAMES); + assertContains("CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Warehouse and Sales, DIMENSION_UNIQUE_NAME=[Store], HIERARCHY_UNIQUE_NAME=[Store], LEVEL_UNIQUE_NAME=[Store].[Store Name], MEMBER_UNIQUE_NAME=null, PROPERTY_NAME=Frozen Sqft, PROPERTY_CAPTION=Frozen Sqft, PROPERTY_TYPE=1, DATA_TYPE=5, PROPERTY_CONTENT_TYPE=0, DESCRIPTION=Warehouse and Sales Cube - Store Hierarchy - Store Name Level - Frozen Sqft Property", s); + assertEquals(s, 70, linecount(s)); + + s = checkResultSet( + olapDatabaseMetaData.getProperties( + catalogName, "FoodMart", "Sales", + null, null, "[Store].[Store Name]", + null, null), + PROPERTIES_COLUMN_NAMES); + assertContains("CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Store], HIERARCHY_UNIQUE_NAME=[Store], LEVEL_UNIQUE_NAME=[Store].[Store Name], MEMBER_UNIQUE_NAME=null, PROPERTY_NAME=Has coffee bar, PROPERTY_CAPTION=Has coffee bar, PROPERTY_TYPE=1, DATA_TYPE=11, PROPERTY_CONTENT_TYPE=0, DESCRIPTION=Sales Cube - Store Hierarchy - Store Name Level - Has coffee bar Property", s); + assertNotContains("CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Warehouse and Sales, ", s); + assertEquals(8, linecount(s)); + } + + public void testDatabaseMetaDataGetMdxKeywords() throws SQLException { + String keywords = olapDatabaseMetaData.getMdxKeywords(); + assertNotNull(keywords); + assertContains(",From,", keywords); + } + + public void testDatabaseMetaDataGetCubes() throws SQLException { + String s = checkResultSet( + olapDatabaseMetaData.getCubes( + catalogName, + null, + null), + CUBE_COLUMN_NAMES); + assertContains("CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, ", s); + + s = checkResultSet( + olapDatabaseMetaData.getCubes( + catalogName, + null, + "Warehouse and Sales"), + CUBE_COLUMN_NAMES); + assertContains(", CUBE_NAME=Warehouse and Sales,", s); + assertNotContains(", CUBE_NAME=Warehouse,", s); + + s = checkResultSet( + olapDatabaseMetaData.getCubes( + catalogName, + null, + "Warehouse%"), + CUBE_COLUMN_NAMES); + assertTrue(s.contains(", CUBE_NAME=Warehouse and Sales")); + assertTrue(s.contains(", CUBE_NAME=Warehouse")); + } + + public void testGetCatalogs() throws SQLException { + int k = 0; + for (Catalog catalog : olapConnection.getCatalogs()) { + ++k; + assertEquals(catalog.getMetaData(), olapDatabaseMetaData); + for (Schema schema : catalog.getSchemas()) { + ++k; + assertEquals(schema.getCatalog(), catalog); + for (Cube cube : schema.getCubes()) { + ++k; + assertEquals(cube.getSchema(), schema); + } + for (Dimension dimension : schema.getSharedDimensions()) { + ++k; + } + for (Locale locale : schema.getSupportedLocales()) { + ++k; + } + } + } + assertTrue(k > 0); + } + + public void testDatabaseMetaDataGetDimensions() throws SQLException { + String s = checkResultSet( + olapDatabaseMetaData.getDimensions( + catalogName, null, null, null), + DIMENSIONS_COLUMN_NAMES); + assertContains("CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_NAME=Education Level, DIMENSION_UNIQUE_NAME=[Education Level], DIMENSION_GUID=null, DIMENSION_CAPTION=Education Level, DIMENSION_ORDINAL=9, DIMENSION_TYPE=3, DIMENSION_CARDINALITY=6, DEFAULT_HIERARCHY=[Education Level], DESCRIPTION=Sales Cube - Education Level Dimension, IS_VIRTUAL=false, IS_READWRITE=false, DIMENSION_UNIQUE_SETTINGS=0, DIMENSION_MASTER_UNIQUE_NAME=null, DIMENSION_IS_VISIBLE=true", s); + assertEquals(62, linecount(s)); + } + + public void testDatabaseMetaDataGetFunctions() throws SQLException { + String s = checkResultSet( + olapDatabaseMetaData.getOlapFunctions(null), + FUNCTIONS_COLUMN_NAMES); + assertContains("FUNCTION_NAME=Name, DESCRIPTION=Returns the name of a member., PARAMETER_LIST=Member, RETURN_TYPE=8, ORIGIN=1, INTERFACE_NAME=, LIBRARY_NAME=null, CAPTION=Name", s); + // Mondrian has 361 functions (as of 2008/1/23) + final int functionCount = linecount(s); + assertTrue(functionCount + " functions", functionCount > 360); + + // Mondrian has 7 variants of the Ascendants and Descendants functions + s = checkResultSet( + olapDatabaseMetaData.getOlapFunctions("%scendants"), + FUNCTIONS_COLUMN_NAMES); + assertEquals(s, 7, linecount(s)); + } + + public void testDatabaseMetaDataGetHierarchies() throws SQLException { + String s = checkResultSet( + olapDatabaseMetaData.getHierarchies( + catalogName, null, null, null, null), + HIERARCHIES_COLUMN_NAMES); + assertContains("CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=HR, DIMENSION_UNIQUE_NAME=[Employees], HIERARCHY_NAME=Employees, HIERARCHY_UNIQUE_NAME=[Employees], HIERARCHY_GUID=null, HIERARCHY_CAPTION=Employees, DIMENSION_TYPE=3, HIERARCHY_CARDINALITY=1156, DEFAULT_MEMBER=[Employees].[All Employees], ALL_MEMBER=[Employees].[All Employees], DESCRIPTION=HR Cube - Employees Hierarchy, STRUCTURE=0, IS_VIRTUAL=false, IS_READWRITE=false, DIMENSION_UNIQUE_SETTINGS=0, DIMENSION_IS_VISIBLE=true, HIERARCHY_ORDINAL=7, DIMENSION_IS_SHARED=true, PARENT_CHILD=true", s); + + s = checkResultSet( + olapDatabaseMetaData.getHierarchies( + catalogName, null, "Sales", null, "Store"), + HIERARCHIES_COLUMN_NAMES); + assertEquals(TestContext.fold("CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Store], HIERARCHY_NAME=Store, HIERARCHY_UNIQUE_NAME=[Store], HIERARCHY_GUID=null, HIERARCHY_CAPTION=Store, DIMENSION_TYPE=3, HIERARCHY_CARDINALITY=63, DEFAULT_MEMBER=[Store].[All Stores], ALL_MEMBER=[Store].[All Stores], DESCRIPTION=Sales Cube - Store Hierarchy, STRUCTURE=0, IS_VIRTUAL=false, IS_READWRITE=false, DIMENSION_UNIQUE_SETTINGS=0, DIMENSION_IS_VISIBLE=true, HIERARCHY_ORDINAL=1, DIMENSION_IS_SHARED=true, PARENT_CHILD=false\n"), s); + } + + public void testDatabaseMetaDataGetLevels() throws SQLException { + String s = checkResultSet( + olapDatabaseMetaData.getLevels( + catalogName, null, null, null, null, null), + LEVELS_COLUMN_NAMES); + assertContains("CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Product], HIERARCHY_UNIQUE_NAME=[Product], LEVEL_NAME=Product Category, LEVEL_UNIQUE_NAME=[Product].[Product Category], LEVEL_GUID=null, LEVEL_CAPTION=Product Category, LEVEL_NUMBER=3, LEVEL_CARDINALITY=55, LEVEL_TYPE=0, CUSTOM_ROLLUP_SETTINGS=0, LEVEL_UNIQUE_SETTINGS=0, LEVEL_IS_VISIBLE=true, DESCRIPTION=Sales Cube - Product HierarchyProduct Category Level", s); + + s = checkResultSet( + olapDatabaseMetaData.getLevels( + catalogName, null, "Sales", null, "[Store]", null), + LEVELS_COLUMN_NAMES); + assertEquals(s, 5, linecount(s)); + } + + public void testDatabaseMetaDataGetLiterals2() throws SQLException { + String s = checkResultSet( + olapDatabaseMetaData.getLiterals(), + LITERALS_COLUMN_NAMES); + assertContains("LITERAL_NAME=DBLITERAL_QUOTE, LITERAL_VALUE=[, LITERAL_INVALID_CHARS=null, LITERAL_INVALID_STARTING_CHARS=null, LITERAL_MAX_LENGTH=-1", s); + assertEquals(17, linecount(s)); + } + + public void testDatabaseMetaDataGetMeasures() throws SQLException { + String s = checkResultSet( + olapDatabaseMetaData.getMeasures( + catalogName, null, null, null, null), + MEASURES_COLUMN_NAMES); + assertContains("CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, MEASURE_NAME=Profit, MEASURE_UNIQUE_NAME=[Measures].[Profit], MEASURE_CAPTION=Profit, MEASURE_GUID=null, MEASURE_AGGREGATOR=127, DATA_TYPE=130, MEASURE_IS_VISIBLE=true, LEVELS_LIST=null, DESCRIPTION=Sales Cube - Profit Member", s); + + // wildcard match + s = checkResultSet( + olapDatabaseMetaData.getMeasures( + catalogName, null, "Sales", "%Sales", null), + MEASURES_COLUMN_NAMES); + assertEquals(s, 3, linecount(s)); + + // wildcard match + s = checkResultSet( + olapDatabaseMetaData.getMeasures( + catalogName, null, "Sales", null, "[Measures].[Unit Sales]"), + MEASURES_COLUMN_NAMES); + assertEquals(s, 1, linecount(s)); + } + + public void testDatabaseMetaDataGetMembers() throws SQLException { + String s = checkResultSet( + olapDatabaseMetaData.getMembers( + catalogName, "FoodMart", "Sales", null, "[Gender]", null, null, + null), + MEMBERS_COLUMN_NAMES); + assertEquals( + TestContext.fold("CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Gender], HIERARCHY_UNIQUE_NAME=[Gender], LEVEL_UNIQUE_NAME=[Gender].[(All)], LEVEL_NUMBER=0, MEMBER_ORDINAL=0, MEMBER_NAME=All Gender, MEMBER_UNIQUE_NAME=[Gender].[All Gender], MEMBER_TYPE=2, MEMBER_GUID=null, MEMBER_CAPTION=All Gender, CHILDREN_CARDINALITY=2, PARENT_LEVEL=0, PARENT_UNIQUE_NAME=null, PARENT_COUNT=0, TREE_OP=null, DEPTH=0\n" + + "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Gender], HIERARCHY_UNIQUE_NAME=[Gender], LEVEL_UNIQUE_NAME=[Gender].[Gender], LEVEL_NUMBER=1, MEMBER_ORDINAL=1, MEMBER_NAME=F, MEMBER_UNIQUE_NAME=[Gender].[All Gender].[F], MEMBER_TYPE=1, MEMBER_GUID=null, MEMBER_CAPTION=F, CHILDREN_CARDINALITY=0, PARENT_LEVEL=0, PARENT_UNIQUE_NAME=[Gender].[All Gender], PARENT_COUNT=1, TREE_OP=null, DEPTH=1\n" + + "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Gender], HIERARCHY_UNIQUE_NAME=[Gender], LEVEL_UNIQUE_NAME=[Gender].[Gender], LEVEL_NUMBER=1, MEMBER_ORDINAL=2, MEMBER_NAME=M, MEMBER_UNIQUE_NAME=[Gender].[All Gender].[M], MEMBER_TYPE=1, MEMBER_GUID=null, MEMBER_CAPTION=M, CHILDREN_CARDINALITY=0, PARENT_LEVEL=0, PARENT_UNIQUE_NAME=[Gender].[All Gender], PARENT_COUNT=1, TREE_OP=null, DEPTH=1\n"), + s); + + // by member unique name + s = checkResultSet( + olapDatabaseMetaData.getMembers( + catalogName, "FoodMart", "Sales", null, null, null, + "[Time].[1997].[Q2].[4]", null), + MEMBERS_COLUMN_NAMES); + assertEquals(TestContext.fold("CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Time], HIERARCHY_UNIQUE_NAME=[Time], LEVEL_UNIQUE_NAME=[Time].[Month], LEVEL_NUMBER=2, MEMBER_ORDINAL=6, MEMBER_NAME=4, MEMBER_UNIQUE_NAME=[Time].[1997].[Q2].[4], MEMBER_TYPE=1, MEMBER_GUID=null, MEMBER_CAPTION=4, CHILDREN_CARDINALITY=0, PARENT_LEVEL=1, PARENT_UNIQUE_NAME=[Time].[1997].[Q2], PARENT_COUNT=1, TREE_OP=null, DEPTH=2\n"), + s); + + // with treeop + s = checkResultSet( + olapDatabaseMetaData.getMembers( + catalogName, "FoodMart", "Sales", null, null, null, + "[Customers].[USA].[CA]", + EnumSet.of(Member.TreeOp.ANCESTORS, Member.TreeOp.SIBLINGS)), + MEMBERS_COLUMN_NAMES); + switch (tester.getFlavor()) { + case MONDRIAN: + // TODO: fix mondrian driver so that members are returned sorted + // by level depth + assertEquals( + TestContext.fold("CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Customers], HIERARCHY_UNIQUE_NAME=[Customers], LEVEL_UNIQUE_NAME=[Customers].[State Province], LEVEL_NUMBER=2, MEMBER_ORDINAL=7235, MEMBER_NAME=OR, MEMBER_UNIQUE_NAME=[Customers].[All Customers].[USA].[OR], MEMBER_TYPE=1, MEMBER_GUID=null, MEMBER_CAPTION=OR, CHILDREN_CARDINALITY=11, PARENT_LEVEL=1, PARENT_UNIQUE_NAME=[Customers].[All Customers].[USA], PARENT_COUNT=1, TREE_OP=null, DEPTH=2\n" + + "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Customers], HIERARCHY_UNIQUE_NAME=[Customers], LEVEL_UNIQUE_NAME=[Customers].[State Province], LEVEL_NUMBER=2, MEMBER_ORDINAL=8298, MEMBER_NAME=WA, MEMBER_UNIQUE_NAME=[Customers].[All Customers].[USA].[WA], MEMBER_TYPE=1, MEMBER_GUID=null, MEMBER_CAPTION=WA, CHILDREN_CARDINALITY=22, PARENT_LEVEL=1, PARENT_UNIQUE_NAME=[Customers].[All Customers].[USA], PARENT_COUNT=1, TREE_OP=null, DEPTH=2\n" + + "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Customers], HIERARCHY_UNIQUE_NAME=[Customers], LEVEL_UNIQUE_NAME=[Customers].[Country], LEVEL_NUMBER=1, MEMBER_ORDINAL=2966, MEMBER_NAME=USA, MEMBER_UNIQUE_NAME=[Customers].[All Customers].[USA], MEMBER_TYPE=1, MEMBER_GUID=null, MEMBER_CAPTION=USA, CHILDREN_CARDINALITY=3, PARENT_LEVEL=0, PARENT_UNIQUE_NAME=[Customers].[All Customers], PARENT_COUNT=1, TREE_OP=null, DEPTH=1\n" + + "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Customers], HIERARCHY_UNIQUE_NAME=[Customers], LEVEL_UNIQUE_NAME=[Customers].[(All)], LEVEL_NUMBER=0, MEMBER_ORDINAL=0, MEMBER_NAME=All Customers, MEMBER_UNIQUE_NAME=[Customers].[All Customers], MEMBER_TYPE=2, MEMBER_GUID=null, MEMBER_CAPTION=All Customers, CHILDREN_CARDINALITY=3, PARENT_LEVEL=0, PARENT_UNIQUE_NAME=null, PARENT_COUNT=0, TREE_OP=null, DEPTH=0\n"), + s); + break; + default: + assertEquals( + TestContext.fold("CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Customers], HIERARCHY_UNIQUE_NAME=[Customers], LEVEL_UNIQUE_NAME=[Customers].[(All)], LEVEL_NUMBER=0, MEMBER_ORDINAL=0, MEMBER_NAME=All Customers, MEMBER_UNIQUE_NAME=[Customers].[All Customers], MEMBER_TYPE=2, MEMBER_GUID=null, MEMBER_CAPTION=All Customers, CHILDREN_CARDINALITY=3, PARENT_LEVEL=0, PARENT_UNIQUE_NAME=null, PARENT_COUNT=0, TREE_OP=null, DEPTH=0\n" + + "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Customers], HIERARCHY_UNIQUE_NAME=[Customers], LEVEL_UNIQUE_NAME=[Customers].[Country], LEVEL_NUMBER=1, MEMBER_ORDINAL=2966, MEMBER_NAME=USA, MEMBER_UNIQUE_NAME=[Customers].[All Customers].[USA], MEMBER_TYPE=1, MEMBER_GUID=null, MEMBER_CAPTION=USA, CHILDREN_CARDINALITY=3, PARENT_LEVEL=0, PARENT_UNIQUE_NAME=[Customers].[All Customers], PARENT_COUNT=1, TREE_OP=null, DEPTH=1\n" + + "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Customers], HIERARCHY_UNIQUE_NAME=[Customers], LEVEL_UNIQUE_NAME=[Customers].[State Province], LEVEL_NUMBER=2, MEMBER_ORDINAL=7235, MEMBER_NAME=OR, MEMBER_UNIQUE_NAME=[Customers].[All Customers].[USA].[OR], MEMBER_TYPE=1, MEMBER_GUID=null, MEMBER_CAPTION=OR, CHILDREN_CARDINALITY=11, PARENT_LEVEL=1, PARENT_UNIQUE_NAME=[Customers].[All Customers].[USA], PARENT_COUNT=1, TREE_OP=null, DEPTH=2\n" + + "CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Sales, DIMENSION_UNIQUE_NAME=[Customers], HIERARCHY_UNIQUE_NAME=[Customers], LEVEL_UNIQUE_NAME=[Customers].[State Province], LEVEL_NUMBER=2, MEMBER_ORDINAL=8298, MEMBER_NAME=WA, MEMBER_UNIQUE_NAME=[Customers].[All Customers].[USA].[WA], MEMBER_TYPE=1, MEMBER_GUID=null, MEMBER_CAPTION=WA, CHILDREN_CARDINALITY=22, PARENT_LEVEL=1, PARENT_UNIQUE_NAME=[Customers].[All Customers].[USA], PARENT_COUNT=1, TREE_OP=null, DEPTH=2\n"), + s); + break; + } + } + + public void testDatabaseMetaDataGetSets() throws SQLException { + String s = checkResultSet( + olapDatabaseMetaData.getSets( + catalogName, null, null, null), + SETS_COLUMN_NAMES); + assertEquals(TestContext.fold("CATALOG_NAME=" + catalogName + ", SCHEMA_NAME=FoodMart, CUBE_NAME=Warehouse, SET_NAME=[Top Sellers], SCOPE=1\n"), s); + + s = checkResultSet( + olapDatabaseMetaData.getSets( + catalogName, null, null, "non existent set"), + SETS_COLUMN_NAMES); + assertEquals("", s); + + } + + // todo: More tests required for other methods on DatabaseMetaData + + private String checkResultSet( + ResultSet resultSet, + List columnNames) throws SQLException + { + ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); + final int columnCount = resultSetMetaData.getColumnCount(); + if (columnNames != null) { + System.out.println(columnNames); + assertEquals( + columnNames.size(), + columnCount); + int k = -1; + for (String columnName : columnNames) { + ++k; + assertEquals( + columnName, + resultSetMetaData.getColumnName(k + 1)); + } + } + assertNotNull(resultSet); + int k = 0; + StringBuilder buf = new StringBuilder(); + while (resultSet.next()) { + ++k; + for (int i = 0; i < columnCount; i++) { + if (i > 0) { + buf.append(", "); + } + String s = resultSet.getString(i + 1); + buf.append(resultSetMetaData.getColumnName(i + 1)) + .append('=') + .append(s); + } + buf.append(NL); + } + assertTrue(k >= 0); + assertTrue(resultSet.isAfterLast()); + return buf.toString(); + } +} + +// End MetadataTest.java diff --git a/testsrc/org/olap4j/MondrianTester.java b/testsrc/org/olap4j/MondrianTester.java index 6f93c55..15b1c34 100644 --- a/testsrc/org/olap4j/MondrianTester.java +++ b/testsrc/org/olap4j/MondrianTester.java @@ -1,73 +1,73 @@ -/* -// This software is subject to the terms of the Common Public License -// Agreement, available at the following URL: -// http://www.opensource.org/licenses/cpl.html. -// Copyright (C) 2007-2007 Julian Hyde -// All Rights Reserved. -// You must accept the terms of that agreement to use this software. -*/ -package org.olap4j; - -import org.olap4j.test.TestContext; - -import java.sql.*; -import java.util.Properties; - -/** - * Implementation of {@link org.olap4j.test.TestContext.Tester} which speaks to - * the mondrian olap4j driver. - * - * @author jhyde - * @version $Id$ - */ -public class MondrianTester implements TestContext.Tester { - - public Connection createConnection() throws SQLException { - try { - Class.forName(DRIVER_CLASS_NAME); - } catch (ClassNotFoundException e) { - throw new RuntimeException("oops", e); - } - return - DriverManager.getConnection( - getURL(), - new Properties()); - } - - public Connection createConnectionWithUserPassword() throws SQLException { - return DriverManager.getConnection( - getURL(), USER, PASSWORD); - } - - public String getDriverUrlPrefix() { - return DRIVER_URL_PREFIX; - } - - public String getDriverClassName() { - return DRIVER_CLASS_NAME; - } - - public String getURL() { - // This property is usually defined in build.properties. See - // examples in that file. - return TestContext.getTestProperties().getProperty( - TestContext.Property.CONNECT_URL.path); - } - - public Flavor getFlavor() { - return Flavor.MONDRIAN; - } - - public TestContext.Wrapper getWrapper() { - return TestContext.Wrapper.NONE; - } - - public static final String DRIVER_CLASS_NAME = - "mondrian.olap4j.MondrianOlap4jDriver"; - - public static final String DRIVER_URL_PREFIX = "jdbc:mondrian:"; - private static final String USER = "sa"; - private static final String PASSWORD = "sa"; -} - -// End MondrianTester.java +/* +// This software is subject to the terms of the Common Public License +// Agreement, available at the following URL: +// http://www.opensource.org/licenses/cpl.html. +// Copyright (C) 2007-2007 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j; + +import org.olap4j.test.TestContext; + +import java.sql.*; +import java.util.Properties; + +/** + * Implementation of {@link org.olap4j.test.TestContext.Tester} which speaks to + * the mondrian olap4j driver. + * + * @author jhyde + * @version $Id$ + */ +public class MondrianTester implements TestContext.Tester { + + public Connection createConnection() throws SQLException { + try { + Class.forName(DRIVER_CLASS_NAME); + } catch (ClassNotFoundException e) { + throw new RuntimeException("oops", e); + } + return + DriverManager.getConnection( + getURL(), + new Properties()); + } + + public Connection createConnectionWithUserPassword() throws SQLException { + return DriverManager.getConnection( + getURL(), USER, PASSWORD); + } + + public String getDriverUrlPrefix() { + return DRIVER_URL_PREFIX; + } + + public String getDriverClassName() { + return DRIVER_CLASS_NAME; + } + + public String getURL() { + // This property is usually defined in build.properties. See + // examples in that file. + return TestContext.getTestProperties().getProperty( + TestContext.Property.CONNECT_URL.path); + } + + public Flavor getFlavor() { + return Flavor.MONDRIAN; + } + + public TestContext.Wrapper getWrapper() { + return TestContext.Wrapper.NONE; + } + + public static final String DRIVER_CLASS_NAME = + "mondrian.olap4j.MondrianOlap4jDriver"; + + public static final String DRIVER_URL_PREFIX = "jdbc:mondrian:"; + private static final String USER = "sa"; + private static final String PASSWORD = "sa"; +} + +// End MondrianTester.java diff --git a/testsrc/org/olap4j/OlapTest.java b/testsrc/org/olap4j/OlapTest.java index 9e6671d..2db479d 100644 --- a/testsrc/org/olap4j/OlapTest.java +++ b/testsrc/org/olap4j/OlapTest.java @@ -143,7 +143,7 @@ public void testModel() { Catalog catalog = olapConnection.getCatalogs().get(catalogName); NamedList schemas = catalog.getSchemas(); for (Schema schema : schemas) { - System.out.println("schema name="+schema.getName()); + System.out.println("schema name=" + schema.getName()); } if (schemas.size() == 0) { @@ -168,7 +168,7 @@ public void testModel() { // take the "Sales" cube Cube cube = cubes.get("Sales"); - System.out.println("using cube name="+cube.getName()); + System.out.println("using cube name=" + cube.getName()); // create an XML doc to represent the Cube and print it out // This XML would be used by remote clients to enable cube navigation @@ -178,9 +178,9 @@ public void testModel() { NamedList dimensions = cube.getDimensions(); for (Dimension dimension : dimensions) { if (dimension.getDimensionType() == Dimension.Type.MEASURE) { - System.out.println("measures dimension name="+dimension.getName()); + System.out.println("measures dimension name=" + dimension.getName()); } else { - System.out.println("dimension name="+dimension.getName()); + System.out.println("dimension name=" + dimension.getName()); } listHierarchies(dimension); } @@ -673,10 +673,16 @@ public static void axisToXml(QueryAxis axis, Document doc, Element parent) { Element dimensionsNode = doc.createElement("dimensions"); root.appendChild(dimensionsNode); - switch(axis.getLocation()) { - case COLUMNS: addAttribute("location", "across", root); break; - case ROWS: addAttribute("location", "down", root); break; - case FILTER: addAttribute("location", "filter", root); break; + switch (axis.getLocation()) { + case COLUMNS: + addAttribute("location", "across", root); + break; + case ROWS: + addAttribute("location", "down", root); + break; + case FILTER: + addAttribute("location", "filter", root); + break; } List dimensions = axis.getDimensions(); @@ -721,9 +727,15 @@ public static void selectionToXml( addCDataNode("name", selection.getName(), root); addCDataNode("dimension-name", selection.getDimension().getName(), root); switch (selection.getOperator()) { - case CHILDREN: addCDataNode("operation", "children", root); break; - case SIBLINGS: addCDataNode("operation", "siblings", root); break; - case MEMBER: addCDataNode("operation", "member", root); break; + case CHILDREN: + addCDataNode("operation", "children", root); + break; + case SIBLINGS: + addCDataNode("operation", "siblings", root); + break; + case MEMBER: + addCDataNode("operation", "member", root); + break; } } catch (Throwable t) { diff --git a/testsrc/org/olap4j/XmlaCachedProxyTest.java b/testsrc/org/olap4j/XmlaCachedProxyTest.java index bae4d19..2904953 100644 --- a/testsrc/org/olap4j/XmlaCachedProxyTest.java +++ b/testsrc/org/olap4j/XmlaCachedProxyTest.java @@ -1,342 +1,319 @@ -package org.olap4j; - -import java.util.HashMap; -import java.util.Map; - -import junit.framework.TestCase; - -import org.olap4j.driver.xmla.XmlaOlap4jDriver; -import org.olap4j.driver.xmla.cache.XmlaOlap4jNamedMemoryCache; -import org.olap4j.driver.xmla.proxy.XmlaOlap4jCachedProxy; -import org.olap4j.driver.xmla.proxy.XmlaOlap4jHttpProxy; - -/** - *

        Tests both the CachedProxy implementation (HttpProxy) and the - * IXmlaOlap4jCache implementation (XmlaOlap4jNamedMemoryCache). - * - * @author Luc Boudreau - * - */ -public class XmlaCachedProxyTest extends TestCase { - - /** - *

        Tests if a simple and valid configuration can be used. - * @throws Exception If the test fails. - */ - public void testCacheConfig() throws Exception - { - XmlaOlap4jCachedProxy proxy = new XmlaOlap4jHttpProxy(); - Map driverParameters = new HashMap(); - Map cacheProperties = new HashMap(); - - driverParameters.put( - XmlaOlap4jDriver.Property.Server.name(), - "http://example.com"); - driverParameters.put( - XmlaOlap4jDriver.Property.Catalog.name(),"CatalogName"); - driverParameters.put( - XmlaOlap4jDriver.Property.Cache.name(), - "org.olap4j.driver.xmla.cache.XmlaOlap4jNamedMemoryCache"); - cacheProperties.put( - XmlaOlap4jNamedMemoryCache.Property.Name.name(), - "testCacheConfig"); - cacheProperties.put( - XmlaOlap4jNamedMemoryCache.Property.Mode.name(), - "LFU"); - cacheProperties.put( - XmlaOlap4jNamedMemoryCache.Property.Timeout.name(), - "30"); - cacheProperties.put( - XmlaOlap4jNamedMemoryCache.Property.Size.name(), - "50"); - - try { - proxy.setCache(driverParameters, cacheProperties); - } - catch (Throwable t) - { - fail(t.getMessage()); - } - } - - - - /** - *

        Makes sure that the cache mode value is validated. - * @throws Exception If the test fails. - */ - public void testCacheModeError() throws Exception { - XmlaOlap4jCachedProxy proxy = new XmlaOlap4jHttpProxy(); - Map driverParameters = new HashMap(); - Map cacheProperties = new HashMap(); - - driverParameters.put( - XmlaOlap4jDriver.Property.Server.name(), - "http://example.com"); - driverParameters.put( - XmlaOlap4jDriver.Property.Catalog.name(), - "CatalogName"); - driverParameters.put( - XmlaOlap4jDriver.Property.Cache.name(), - "org.olap4j.driver.xmla.cache.XmlaOlap4jNamedMemoryCache"); - cacheProperties.put( - XmlaOlap4jNamedMemoryCache.Property.Name.name(), - "testCacheModeError"); - cacheProperties.put( - XmlaOlap4jNamedMemoryCache.Property.Mode.name(), - "ERRONOUS VALUE MWAHAHAHAHA"); - cacheProperties.put( - XmlaOlap4jNamedMemoryCache.Property.Timeout.name(), - "30"); - cacheProperties.put( - XmlaOlap4jNamedMemoryCache.Property.Size.name(), - "50"); - - try { - proxy.setCache(driverParameters, cacheProperties); - } - catch (OlapException e) - { - return; - } - - fail("The cache mode is not validated properly"); - } - - - - /** - *

        Makes sure that the cache timeout value is validated. - * @throws Exception If the test fails. - */ - public void testCacheTimeoutError() throws Exception - { - XmlaOlap4jCachedProxy proxy = new XmlaOlap4jHttpProxy(); - Map driverParameters = new HashMap(); - Map cacheProperties = new HashMap(); - - driverParameters.put( - XmlaOlap4jDriver.Property.Server.name(), - "http://example.com"); - driverParameters.put( - XmlaOlap4jDriver.Property.Catalog.name(), - "CatalogName"); - driverParameters.put( - XmlaOlap4jDriver.Property.Cache.name(), - "org.olap4j.driver.xmla.cache.XmlaOlap4jNamedMemoryCache"); - cacheProperties.put( - XmlaOlap4jNamedMemoryCache.Property.Name.name(), - "testCacheTimeoutError"); - cacheProperties.put( - XmlaOlap4jNamedMemoryCache.Property.Mode.name(), - "LFU"); - cacheProperties.put( - XmlaOlap4jNamedMemoryCache.Property.Timeout.name(), - "EEE"); - cacheProperties.put( - XmlaOlap4jNamedMemoryCache.Property.Size.name(), - "50"); - - try { - proxy.setCache(driverParameters, cacheProperties); - } - catch (OlapException t) - { - try { - cacheProperties.put( - XmlaOlap4jNamedMemoryCache.Property.Timeout.name(), - "-30"); - proxy.setCache(driverParameters, cacheProperties); - } - catch (OlapException t2) - { - return; - } - } - - fail("The cache timeout is not validated properly"); - } - - - - /** - *

        Makes sure that the cache size value is validated. - * @throws Exception If the test fails. - */ - public void testCacheSizeError() throws Exception - { - XmlaOlap4jCachedProxy proxy = new XmlaOlap4jHttpProxy(); - Map driverParameters = new HashMap(); - Map cacheProperties = new HashMap(); - - driverParameters.put( - XmlaOlap4jDriver.Property.Server.name(), - "http://example.com"); - driverParameters.put( - XmlaOlap4jDriver.Property.Catalog.name(), - "CatalogName"); - driverParameters.put( - XmlaOlap4jDriver.Property.Cache.name(), - "org.olap4j.driver.xmla.cache.XmlaOlap4jNamedMemoryCache"); - cacheProperties.put( - XmlaOlap4jNamedMemoryCache.Property.Name.name(), - "testCacheSizeError"); - cacheProperties.put( - XmlaOlap4jNamedMemoryCache.Property.Mode.name(), - "LFU"); - cacheProperties.put( - XmlaOlap4jNamedMemoryCache.Property.Timeout.name(), - "600"); - cacheProperties.put( - XmlaOlap4jNamedMemoryCache.Property.Size.name(), - "EEE"); - - try { - proxy.setCache(driverParameters, cacheProperties); - } - catch (OlapException t) - { - try { - cacheProperties.put( - XmlaOlap4jNamedMemoryCache.Property.Size.name(), - "-30"); - proxy.setCache(driverParameters, cacheProperties); - } - catch (OlapException t2) - { - return; - } - } - - fail("The cache size is not validated properly"); - } - - - - - /** - *

        Makes sure that the cache class name value is validated. - * @throws Exception If the test fails. - */ - public void testCacheNameError() throws Exception - { - XmlaOlap4jCachedProxy proxy = new XmlaOlap4jHttpProxy(); - Map driverParameters = new HashMap(); - Map cacheProperties = new HashMap(); - - driverParameters.put( - XmlaOlap4jDriver.Property.Server.name(), - "http://example.com"); - driverParameters.put( - XmlaOlap4jDriver.Property.Catalog.name(), - "CatalogName"); - driverParameters.put( - XmlaOlap4jDriver.Property.Cache.name(), - "Class which doesn't exist"); - cacheProperties.put( - XmlaOlap4jNamedMemoryCache.Property.Name.name(), - "testCacheNameError"); - cacheProperties.put( - XmlaOlap4jNamedMemoryCache.Property.Mode.name(), - "LFU"); - cacheProperties.put( - XmlaOlap4jNamedMemoryCache.Property.Timeout.name(), - "600"); - cacheProperties.put( - XmlaOlap4jNamedMemoryCache.Property.Size.name(), - "50"); - - try { - proxy.setCache(driverParameters, cacheProperties); - } - catch (OlapException e) - { - return; - } - - fail("The cache class name is not validated properly"); - } - - - - - /** - *

        Makes sure that a cache name is properly shared in a static way and - * that the parameters are not overwritten by subsequent connection creations. - * @throws Exception If the test fails. - */ - public void testCacheSharing() throws Exception - { - XmlaOlap4jCachedProxy proxy = new XmlaOlap4jHttpProxy(); - Map driverParameters = new HashMap(); - Map cacheProperties = new HashMap(); - - driverParameters.put( - XmlaOlap4jDriver.Property.Server.name(), - "http://example.com"); - driverParameters.put( - XmlaOlap4jDriver.Property.Catalog.name(), - "CatalogName"); - driverParameters.put( - XmlaOlap4jDriver.Property.Cache.name(), - "org.olap4j.driver.xmla.cache.XmlaOlap4jNamedMemoryCache"); - cacheProperties.put( - XmlaOlap4jNamedMemoryCache.Property.Name.name(), - "testCacheSharing"); - cacheProperties.put( - XmlaOlap4jNamedMemoryCache.Property.Mode.name(), - "LFU"); - cacheProperties.put( - XmlaOlap4jNamedMemoryCache.Property.Timeout.name(), - "600"); - cacheProperties.put( - XmlaOlap4jNamedMemoryCache.Property.Size.name(), - "50"); - - try { - proxy.setCache(driverParameters, cacheProperties); - } - catch (Throwable e) - { - fail("The cache class name is not validated properly"); - } - - driverParameters.put( - XmlaOlap4jDriver.Property.Server.name(), - "http://example2.com"); - driverParameters.put( - XmlaOlap4jDriver.Property.Catalog.name(), - "CatalogName2"); - driverParameters.put( - XmlaOlap4jDriver.Property.Cache.name(), - "org.olap4j.driver.xmla.cache.XmlaOlap4jNamedMemoryCache"); - cacheProperties.put( - XmlaOlap4jNamedMemoryCache.Property.Name.name(), - "testCacheSharing"); - cacheProperties.put( - XmlaOlap4jNamedMemoryCache.Property.Mode.name(), - "Erronous value which won't trigger an exception since a shared cache should be used."); - cacheProperties.put( - XmlaOlap4jNamedMemoryCache.Property.Timeout.name(), - "Erronous value which won't trigger an exception since a shared cache should be used."); - cacheProperties.put( - XmlaOlap4jNamedMemoryCache.Property.Size.name(), - "Erronous value which won't trigger an exception since a shared cache should be used."); - - try { - // Create a new object and try with a faulty cache parameters, - // but use a name which already exists in the cache directory. - // This endures that 1 - the caches are shared in a static manner - // and that 2 - the cache is reused and it's - // parameters are not overwritten. - proxy = new XmlaOlap4jHttpProxy(); - proxy.setCache(driverParameters, cacheProperties); - } - catch (Throwable e) - { - fail("The cache is not properly shared since an error should not have been throwned."); - } - } - - -} +package org.olap4j; + +import java.util.HashMap; +import java.util.Map; + +import junit.framework.TestCase; + +import org.olap4j.driver.xmla.XmlaOlap4jDriver; +import org.olap4j.driver.xmla.cache.XmlaOlap4jNamedMemoryCache; +import org.olap4j.driver.xmla.proxy.XmlaOlap4jCachedProxy; +import org.olap4j.driver.xmla.proxy.XmlaOlap4jHttpProxy; + +/** + *

        Tests both the CachedProxy implementation (HttpProxy) and the + * IXmlaOlap4jCache implementation (XmlaOlap4jNamedMemoryCache). + * + * @author Luc Boudreau + * + */ +public class XmlaCachedProxyTest extends TestCase { + + /** + *

        Tests if a simple and valid configuration can be used. + * @throws Exception If the test fails. + */ + public void testCacheConfig() throws Exception + { + XmlaOlap4jCachedProxy proxy = new XmlaOlap4jHttpProxy(); + Map driverParameters = new HashMap(); + Map cacheProperties = new HashMap(); + + driverParameters.put( + XmlaOlap4jDriver.Property.Server.name(), + "http://example.com"); + driverParameters.put( + XmlaOlap4jDriver.Property.Catalog.name(),"CatalogName"); + driverParameters.put( + XmlaOlap4jDriver.Property.Cache.name(), + "org.olap4j.driver.xmla.cache.XmlaOlap4jNamedMemoryCache"); + cacheProperties.put( + XmlaOlap4jNamedMemoryCache.Property.Name.name(), + "testCacheConfig"); + cacheProperties.put( + XmlaOlap4jNamedMemoryCache.Property.Mode.name(), + "LFU"); + cacheProperties.put( + XmlaOlap4jNamedMemoryCache.Property.Timeout.name(), + "30"); + cacheProperties.put( + XmlaOlap4jNamedMemoryCache.Property.Size.name(), + "50"); + + proxy.setCache(driverParameters, cacheProperties); + } + + + /** + *

        Makes sure that the cache mode value is validated. + * @throws Exception If the test fails. + */ + public void testCacheModeError() throws Exception { + XmlaOlap4jCachedProxy proxy = new XmlaOlap4jHttpProxy(); + Map driverParameters = new HashMap(); + Map cacheProperties = new HashMap(); + + driverParameters.put( + XmlaOlap4jDriver.Property.Server.name(), + "http://example.com"); + driverParameters.put( + XmlaOlap4jDriver.Property.Catalog.name(), + "CatalogName"); + driverParameters.put( + XmlaOlap4jDriver.Property.Cache.name(), + "org.olap4j.driver.xmla.cache.XmlaOlap4jNamedMemoryCache"); + cacheProperties.put( + XmlaOlap4jNamedMemoryCache.Property.Name.name(), + "testCacheModeError"); + cacheProperties.put( + XmlaOlap4jNamedMemoryCache.Property.Mode.name(), + "ERRONOUS VALUE MWAHAHAHAHA"); + cacheProperties.put( + XmlaOlap4jNamedMemoryCache.Property.Timeout.name(), + "30"); + cacheProperties.put( + XmlaOlap4jNamedMemoryCache.Property.Size.name(), + "50"); + + try { + proxy.setCache(driverParameters, cacheProperties); + } catch (OlapException e) { + return; + } + + fail("The cache mode is not validated properly"); + } + + + + /** + *

        Makes sure that the cache timeout value is validated. + * @throws Exception If the test fails. + */ + public void testCacheTimeoutError() throws Exception + { + XmlaOlap4jCachedProxy proxy = new XmlaOlap4jHttpProxy(); + Map driverParameters = new HashMap(); + Map cacheProperties = new HashMap(); + + driverParameters.put( + XmlaOlap4jDriver.Property.Server.name(), + "http://example.com"); + driverParameters.put( + XmlaOlap4jDriver.Property.Catalog.name(), + "CatalogName"); + driverParameters.put( + XmlaOlap4jDriver.Property.Cache.name(), + "org.olap4j.driver.xmla.cache.XmlaOlap4jNamedMemoryCache"); + cacheProperties.put( + XmlaOlap4jNamedMemoryCache.Property.Name.name(), + "testCacheTimeoutError"); + cacheProperties.put( + XmlaOlap4jNamedMemoryCache.Property.Mode.name(), + "LFU"); + cacheProperties.put( + XmlaOlap4jNamedMemoryCache.Property.Timeout.name(), + "EEE"); + cacheProperties.put( + XmlaOlap4jNamedMemoryCache.Property.Size.name(), + "50"); + + try { + proxy.setCache(driverParameters, cacheProperties); + } catch (OlapException t) { + try { + cacheProperties.put( + XmlaOlap4jNamedMemoryCache.Property.Timeout.name(), + "-30"); + proxy.setCache(driverParameters, cacheProperties); + } catch (OlapException t2) { + return; + } + } + + fail("The cache timeout is not validated properly"); + } + + + + /** + *

        Makes sure that the cache size value is validated. + * @throws Exception If the test fails. + */ + public void testCacheSizeError() throws Exception + { + XmlaOlap4jCachedProxy proxy = new XmlaOlap4jHttpProxy(); + Map driverParameters = new HashMap(); + Map cacheProperties = new HashMap(); + + driverParameters.put( + XmlaOlap4jDriver.Property.Server.name(), + "http://example.com"); + driverParameters.put( + XmlaOlap4jDriver.Property.Catalog.name(), + "CatalogName"); + driverParameters.put( + XmlaOlap4jDriver.Property.Cache.name(), + "org.olap4j.driver.xmla.cache.XmlaOlap4jNamedMemoryCache"); + cacheProperties.put( + XmlaOlap4jNamedMemoryCache.Property.Name.name(), + "testCacheSizeError"); + cacheProperties.put( + XmlaOlap4jNamedMemoryCache.Property.Mode.name(), + "LFU"); + cacheProperties.put( + XmlaOlap4jNamedMemoryCache.Property.Timeout.name(), + "600"); + cacheProperties.put( + XmlaOlap4jNamedMemoryCache.Property.Size.name(), + "EEE"); + + try { + proxy.setCache(driverParameters, cacheProperties); + } catch (OlapException t) { + try { + cacheProperties.put( + XmlaOlap4jNamedMemoryCache.Property.Size.name(), + "-30"); + proxy.setCache(driverParameters, cacheProperties); + } catch (OlapException t2) { + return; + } + } + + fail("The cache size is not validated properly"); + } + + + /** + *

        Makes sure that the cache class name value is validated. + * @throws Exception If the test fails. + */ + public void testCacheNameError() throws Exception + { + XmlaOlap4jCachedProxy proxy = new XmlaOlap4jHttpProxy(); + Map driverParameters = new HashMap(); + Map cacheProperties = new HashMap(); + + driverParameters.put( + XmlaOlap4jDriver.Property.Server.name(), + "http://example.com"); + driverParameters.put( + XmlaOlap4jDriver.Property.Catalog.name(), + "CatalogName"); + driverParameters.put( + XmlaOlap4jDriver.Property.Cache.name(), + "Class which doesn't exist"); + cacheProperties.put( + XmlaOlap4jNamedMemoryCache.Property.Name.name(), + "testCacheNameError"); + cacheProperties.put( + XmlaOlap4jNamedMemoryCache.Property.Mode.name(), + "LFU"); + cacheProperties.put( + XmlaOlap4jNamedMemoryCache.Property.Timeout.name(), + "600"); + cacheProperties.put( + XmlaOlap4jNamedMemoryCache.Property.Size.name(), + "50"); + + try { + proxy.setCache(driverParameters, cacheProperties); + } catch (OlapException e) { + return; + } + + fail("The cache class name is not validated properly"); + } + + + + + /** + *

        Makes sure that a cache name is properly shared in a static way and + * that the parameters are not overwritten by subsequent connection creations. + * @throws Exception If the test fails. + */ + public void testCacheSharing() throws Exception + { + XmlaOlap4jCachedProxy proxy = new XmlaOlap4jHttpProxy(); + Map driverParameters = new HashMap(); + Map cacheProperties = new HashMap(); + + driverParameters.put( + XmlaOlap4jDriver.Property.Server.name(), + "http://example.com"); + driverParameters.put( + XmlaOlap4jDriver.Property.Catalog.name(), + "CatalogName"); + driverParameters.put( + XmlaOlap4jDriver.Property.Cache.name(), + "org.olap4j.driver.xmla.cache.XmlaOlap4jNamedMemoryCache"); + cacheProperties.put( + XmlaOlap4jNamedMemoryCache.Property.Name.name(), + "testCacheSharing"); + cacheProperties.put( + XmlaOlap4jNamedMemoryCache.Property.Mode.name(), + "LFU"); + cacheProperties.put( + XmlaOlap4jNamedMemoryCache.Property.Timeout.name(), + "600"); + cacheProperties.put( + XmlaOlap4jNamedMemoryCache.Property.Size.name(), + "50"); + + try { + proxy.setCache(driverParameters, cacheProperties); + } catch (Throwable e) { + fail("The cache class name is not validated properly"); + } + + driverParameters.put( + XmlaOlap4jDriver.Property.Server.name(), + "http://example2.com"); + driverParameters.put( + XmlaOlap4jDriver.Property.Catalog.name(), + "CatalogName2"); + driverParameters.put( + XmlaOlap4jDriver.Property.Cache.name(), + "org.olap4j.driver.xmla.cache.XmlaOlap4jNamedMemoryCache"); + cacheProperties.put( + XmlaOlap4jNamedMemoryCache.Property.Name.name(), + "testCacheSharing"); + cacheProperties.put( + XmlaOlap4jNamedMemoryCache.Property.Mode.name(), + "Erronous value which won't trigger an exception since a shared cache should be used."); + cacheProperties.put( + XmlaOlap4jNamedMemoryCache.Property.Timeout.name(), + "Erronous value which won't trigger an exception since a shared cache should be used."); + cacheProperties.put( + XmlaOlap4jNamedMemoryCache.Property.Size.name(), + "Erronous value which won't trigger an exception since a shared cache should be used."); + + try { + // Create a new object and try with a faulty cache parameters, + // but use a name which already exists in the cache directory. + // This endures that 1 - the caches are shared in a static manner + // and that 2 - the cache is reused and it's + // parameters are not overwritten. + proxy = new XmlaOlap4jHttpProxy(); + proxy.setCache(driverParameters, cacheProperties); + } catch (Throwable e) { + fail("The cache is not properly shared since an error should not have been thrown."); + } + } + + +} + +// End XmlaCachedProxyTest.java diff --git a/testsrc/org/olap4j/XmlaConnectionTest.java b/testsrc/org/olap4j/XmlaConnectionTest.java index 7984ea9..adb2226 100644 --- a/testsrc/org/olap4j/XmlaConnectionTest.java +++ b/testsrc/org/olap4j/XmlaConnectionTest.java @@ -12,52 +12,51 @@ import junit.framework.TestCase; public class XmlaConnectionTest extends TestCase { - - public static final String DRIVER_CLASS_NAME = - "org.olap4j.driver.xmla.XmlaOlap4jDriver"; - - static class XmlaOlap4jProxyMock implements XmlaOlap4jProxy { - - public byte[] get(URL url, String request) throws IOException { - throw new RuntimeException("Non-Trivial Call!"); - } - - public String getEncodingCharsetName() { - return "UTF-8"; - } - - public Future submit(URL url, String request) { - throw new RuntimeException("Non-Trivial Call!"); - } - - } - - /** - * this test verifies that the construction of the necessary - * xmla objects during DriverManager.getConnection() do not make - * calls that could cause deadlocks. - */ - public void testNoNonTrivalCallsOnConnect() throws Exception { - String cookie = XmlaOlap4jDriver.nextCookie(); - try { - - XmlaOlap4jDriver.PROXY_MAP.put(cookie, new XmlaOlap4jProxyMock()); - - try { + + public static final String DRIVER_CLASS_NAME = + "org.olap4j.driver.xmla.XmlaOlap4jDriver"; + + static class XmlaOlap4jProxyMock implements XmlaOlap4jProxy { + public byte[] get(URL url, String request) throws IOException { + throw new RuntimeException("Non-Trivial Call!"); + } + + public String getEncodingCharsetName() { + return "UTF-8"; + } + + public Future submit(URL url, String request) { + throw new RuntimeException("Non-Trivial Call!"); + } + } + + /** + * this test verifies that the construction of the necessary + * xmla objects during DriverManager.getConnection() do not make + * calls that could cause deadlocks. + */ + public void testNoNonTrivalCallsOnConnect() throws Exception { + String cookie = XmlaOlap4jDriver.nextCookie(); + try { + + XmlaOlap4jDriver.PROXY_MAP.put(cookie, new XmlaOlap4jProxyMock()); + + try { Class.forName(DRIVER_CLASS_NAME); - } catch (ClassNotFoundException e) { - throw new RuntimeException("oops", e); - } - Properties info = new Properties(); - info.setProperty( - XmlaOlap4jDriver.Property.Catalog.name(), "FoodMart"); - DriverManager.getConnection( - "jdbc:xmla:Server=http://foo;Catalog=FoodMart;TestProxyCookie=" + cookie, - info); - } catch (Throwable t) { - t.printStackTrace(); - fail("Non-Trival Call executed during construction of XmlaOlap4j Connection"); - } - - } + } catch (ClassNotFoundException e) { + throw new RuntimeException("oops", e); + } + Properties info = new Properties(); + info.setProperty( + XmlaOlap4jDriver.Property.Catalog.name(), "FoodMart"); + DriverManager.getConnection( + "jdbc:xmla:Server=http://foo;Catalog=FoodMart;TestProxyCookie=" + cookie, + info); + } catch (Throwable t) { + t.printStackTrace(); + fail("Non-Trival Call executed during construction of XmlaOlap4j Connection"); + } + } } + +// End XmlaConnectionTest.java diff --git a/testsrc/org/olap4j/XmlaCookieManagerTest.java b/testsrc/org/olap4j/XmlaCookieManagerTest.java index 149b175..2f6bb6e 100644 --- a/testsrc/org/olap4j/XmlaCookieManagerTest.java +++ b/testsrc/org/olap4j/XmlaCookieManagerTest.java @@ -1,117 +1,107 @@ -package org.olap4j; - -import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.URL; - -import junit.framework.TestCase; - -import org.olap4j.driver.xmla.proxy.XmlaOlap4jCookieManager; - -public class XmlaCookieManagerTest extends TestCase { - - private static final String receivedCookieKey = "Set-Cookie"; - public final static String sentCookieKey = "Cookie"; - public final static String cookieValue = "MyTestCookie=271B79EBCBAAA37C5C51B1979441E5AC"; - - - - /** - *

        This simple test makes sure that the cookie manager works as expected. It creates a - * connection stub which returns fake Set-Cookie response headers. The cookies are then - * stored in the cookie manager and a new connection stub is created. The second connection - * is then passed back to the manager and we check if the cookies were applied - * to the connection. - * - * @throws Exception - */ - public void testCookieManager() throws Exception { - URLConnectionStub conn = new URLConnectionStub(new URL("http://example.com")); - XmlaOlap4jCookieManager manager = new XmlaOlap4jCookieManager(); - - conn.connect(); - - manager.storeCookies(conn); - - conn = new URLConnectionStub(new URL("http://example.com")); - - manager.setCookies(conn); - - assertEquals(sentCookieKey, conn.getInternalCookieKey()); - assertEquals(cookieValue, conn.getInternalCookieValue()); - } - - - - - - private static class URLConnectionStub extends HttpURLConnection { - private String internalCookieKey = null; - private String internalCookieValue = null; - - protected URLConnectionStub(URL u) { - super(u); - } - - /* (non-Javadoc) - * @see java.net.HttpURLConnection#disconnect() - */ - @Override - public void disconnect() { } - - /* (non-Javadoc) - * @see java.net.HttpURLConnection#usingProxy() - */ - @Override - public boolean usingProxy() { - return false; - } - - /* (non-Javadoc) - * @see java.net.URLConnection#connect() - */ - @Override - public void connect() throws IOException { - this.connected = true; - } - - /* (non-Javadoc) - * @see java.net.HttpURLConnection#getHeaderFieldKey(int) - */ - @Override - public String getHeaderFieldKey(int n) { - if (n == 1) - return receivedCookieKey; - else - return null; - } - - /* (non-Javadoc) - * @see java.net.HttpURLConnection#getHeaderField(int) - */ - @Override - public String getHeaderField(int n) { - if (n == 1) - return cookieValue; - else - return null; - } - - @Override - public void setRequestProperty(String key, String value) { - this.internalCookieKey = key; - this.internalCookieValue = value; - } - - public String getInternalCookieKey() { - return internalCookieKey; - } - - public String getInternalCookieValue() { - return internalCookieValue; - } - - - } - -} +package org.olap4j; + +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URL; + +import junit.framework.TestCase; + +import org.olap4j.driver.xmla.proxy.XmlaOlap4jCookieManager; + +public class XmlaCookieManagerTest extends TestCase { + + private static final String receivedCookieKey = "Set-Cookie"; + public final static String sentCookieKey = "Cookie"; + public final static String cookieValue = "MyTestCookie=271B79EBCBAAA37C5C51B1979441E5AC"; + + + + /** + *

        This simple test makes sure that the cookie manager works as expected. It creates a + * connection stub which returns fake Set-Cookie response headers. The cookies are then + * stored in the cookie manager and a new connection stub is created. The second connection + * is then passed back to the manager and we check if the cookies were applied + * to the connection. + * + * @throws Exception + */ + public void testCookieManager() throws Exception { + URLConnectionStub conn = new URLConnectionStub(new URL("http://example.com")); + XmlaOlap4jCookieManager manager = new XmlaOlap4jCookieManager(); + + conn.connect(); + + manager.storeCookies(conn); + + conn = new URLConnectionStub(new URL("http://example.com")); + + manager.setCookies(conn); + + assertEquals(sentCookieKey, conn.getInternalCookieKey()); + assertEquals(cookieValue, conn.getInternalCookieValue()); + } + + + + + + private static class URLConnectionStub extends HttpURLConnection { + private String internalCookieKey = null; + private String internalCookieValue = null; + + protected URLConnectionStub(URL u) { + super(u); + } + + @Override + public void disconnect() { + } + + @Override + public boolean usingProxy() { + return false; + } + + @Override + public void connect() throws IOException { + this.connected = true; + } + + @Override + public String getHeaderFieldKey(int n) { + if (n == 1) { + return receivedCookieKey; + } else { + return null; + } + } + + @Override + public String getHeaderField(int n) { + if (n == 1) { + return cookieValue; + } else { + return null; + } + } + + @Override + public void setRequestProperty(String key, String value) { + this.internalCookieKey = key; + this.internalCookieValue = value; + } + + public String getInternalCookieKey() { + return internalCookieKey; + } + + public String getInternalCookieValue() { + return internalCookieValue; + } + + + } + +} + +// End XmlaCookieManagerTest.java diff --git a/testsrc/org/olap4j/XmlaSHAEncoderTest.java b/testsrc/org/olap4j/XmlaSHAEncoderTest.java index 4fed63c..874e5c2 100644 --- a/testsrc/org/olap4j/XmlaSHAEncoderTest.java +++ b/testsrc/org/olap4j/XmlaSHAEncoderTest.java @@ -1,46 +1,48 @@ -package org.olap4j; - -import junit.framework.TestCase; - -import org.olap4j.driver.xmla.cache.XmlaOlap4jSHAEncoder; - -/** - *

        This is a simple test that makes sure that the SHA encoder works - * as expected. - * - * @author Luc Boudreau - */ -public class XmlaSHAEncoderTest extends TestCase { - - private static final String message_1 = "This is my nifty message number 1"; - private static final String message_2 = "This is my nifty message number 2"; - private static final String message_1_encoded = "0821347e66167004f9aba546ae9e61ec5b471e59"; - private static final String message_2_encoded = "95dfe200baddc69e2f53e78feeac445a0bdbb4e7"; - - - public void testSimpleEncoding() throws Exception { - String encoded = XmlaOlap4jSHAEncoder.SHA1(message_1); - assertEquals(message_1_encoded, encoded); - } - - - public void testDoubleEncoding() throws Exception - { - String encoded = XmlaOlap4jSHAEncoder.SHA1(message_1); - assertEquals(message_1_encoded, encoded); - - String encoded2 = XmlaOlap4jSHAEncoder.SHA1(message_2); - assertEquals(message_2_encoded, encoded2); - - assertFalse(encoded.equals(encoded2)); - - String encoded3 = XmlaOlap4jSHAEncoder.SHA1(message_1); - assertEquals(message_1_encoded, encoded3); - - String encoded4 = XmlaOlap4jSHAEncoder.SHA1(message_1); - assertEquals(message_1_encoded, encoded4); - - assertEquals(encoded3, encoded4); - } - -} +package org.olap4j; + +import junit.framework.TestCase; + +import org.olap4j.driver.xmla.cache.XmlaOlap4jSHAEncoder; + +/** + *

        This is a simple test that makes sure that the SHA encoder works + * as expected. + * + * @author Luc Boudreau + */ +public class XmlaSHAEncoderTest extends TestCase { + + private static final String message_1 = "This is my nifty message number 1"; + private static final String message_2 = "This is my nifty message number 2"; + private static final String message_1_encoded = "0821347e66167004f9aba546ae9e61ec5b471e59"; + private static final String message_2_encoded = "95dfe200baddc69e2f53e78feeac445a0bdbb4e7"; + + + public void testSimpleEncoding() throws Exception { + String encoded = XmlaOlap4jSHAEncoder.SHA1(message_1); + assertEquals(message_1_encoded, encoded); + } + + + public void testDoubleEncoding() throws Exception + { + String encoded = XmlaOlap4jSHAEncoder.SHA1(message_1); + assertEquals(message_1_encoded, encoded); + + String encoded2 = XmlaOlap4jSHAEncoder.SHA1(message_2); + assertEquals(message_2_encoded, encoded2); + + assertFalse(encoded.equals(encoded2)); + + String encoded3 = XmlaOlap4jSHAEncoder.SHA1(message_1); + assertEquals(message_1_encoded, encoded3); + + String encoded4 = XmlaOlap4jSHAEncoder.SHA1(message_1); + assertEquals(message_1_encoded, encoded4); + + assertEquals(encoded3, encoded4); + } + +} + +// End XmlaSHAEncoderTest.java diff --git a/testsrc/org/olap4j/XmlaTester.java b/testsrc/org/olap4j/XmlaTester.java index 3827d77..75120a8 100644 --- a/testsrc/org/olap4j/XmlaTester.java +++ b/testsrc/org/olap4j/XmlaTester.java @@ -1,126 +1,126 @@ -/* -// This software is subject to the terms of the Common Public License -// Agreement, available at the following URL: -// http://www.opensource.org/licenses/cpl.html. -// Copyright (C) 2007-2007 Julian Hyde -// All Rights Reserved. -// You must accept the terms of that agreement to use this software. -*/ -package org.olap4j; - -import org.olap4j.driver.xmla.XmlaOlap4jDriver; -import org.olap4j.driver.xmla.proxy.XmlaOlap4jProxy; -import org.olap4j.test.TestContext; - -import java.sql.*; -import java.util.*; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; - -/** - * Implementation of {@link org.olap4j.test.TestContext.Tester} which speaks - * to the olap4j driver for XML/A. - * - * @author jhyde - * @version $Id$ - */ -public class XmlaTester implements TestContext.Tester { - final XmlaOlap4jProxy proxy; - final String cookie; - private Connection connection; - - /** - * Creates an XmlaTester - * - * @throws ClassNotFoundException on error - * @throws IllegalAccessException on error - * @throws InstantiationException on error - * @throws NoSuchMethodException on error - * @throws InvocationTargetException on error - */ - public XmlaTester() - throws ClassNotFoundException, IllegalAccessException, - InstantiationException, NoSuchMethodException, - InvocationTargetException - { - final Properties properties = TestContext.getTestProperties(); - final String catalogUrl = - properties.getProperty( - TestContext.Property.XMLA_CATALOG_URL.path); - Map catalogNameUrls = - new HashMap(); - catalogNameUrls.put("FoodMart", catalogUrl); - String urlString = - properties.getProperty(TestContext.Property.CONNECT_URL.path); - - final Class clazz = Class.forName("mondrian.olap4j.MondrianInprocProxy"); - final Constructor constructor = - clazz.getConstructor(Map.class, String.class); - this.proxy = - (XmlaOlap4jProxy) constructor.newInstance( - catalogNameUrls, urlString); - this.cookie = XmlaOlap4jDriver.nextCookie(); - XmlaOlap4jDriver.PROXY_MAP.put(cookie, proxy); - } - - public Connection createConnection() throws SQLException { - if (connection != null) { - return connection; - } - try { - Class.forName(DRIVER_CLASS_NAME); - } catch (ClassNotFoundException e) { - throw new RuntimeException("oops", e); - } - Properties info = new Properties(); - info.setProperty( - XmlaOlap4jDriver.Property.Catalog.name(), "FoodMart"); - connection = - DriverManager.getConnection( - getURL(), - info); - return connection; - } - - public Connection createConnectionWithUserPassword() throws SQLException { - try { - Class.forName(DRIVER_CLASS_NAME); - } catch (ClassNotFoundException e) { - throw new RuntimeException("oops", e); - } - Properties info = new Properties(); - info.setProperty( - XmlaOlap4jDriver.Property.Catalog.name(), "FoodMart"); - return DriverManager.getConnection( - getURL(), USER, PASSWORD); - } - - public String getDriverUrlPrefix() { - return DRIVER_URL_PREFIX; - } - - public String getDriverClassName() { - return DRIVER_CLASS_NAME; - } - - public String getURL() { - return "jdbc:xmla:Server=http://foo;Catalog=FoodMart;TestProxyCookie=" + cookie; - } - - public Flavor getFlavor() { - return Flavor.XMLA; - } - - public TestContext.Wrapper getWrapper() { - return TestContext.Wrapper.NONE; - } - - public static final String DRIVER_CLASS_NAME = - "org.olap4j.driver.xmla.XmlaOlap4jDriver"; - - public static final String DRIVER_URL_PREFIX = "jdbc:xmla:"; - private static final String USER = "user"; - private static final String PASSWORD = "password"; -} - -// End XmlaTester.java +/* +// This software is subject to the terms of the Common Public License +// Agreement, available at the following URL: +// http://www.opensource.org/licenses/cpl.html. +// Copyright (C) 2007-2007 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j; + +import org.olap4j.driver.xmla.XmlaOlap4jDriver; +import org.olap4j.driver.xmla.proxy.XmlaOlap4jProxy; +import org.olap4j.test.TestContext; + +import java.sql.*; +import java.util.*; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +/** + * Implementation of {@link org.olap4j.test.TestContext.Tester} which speaks + * to the olap4j driver for XML/A. + * + * @author jhyde + * @version $Id$ + */ +public class XmlaTester implements TestContext.Tester { + final XmlaOlap4jProxy proxy; + final String cookie; + private Connection connection; + + /** + * Creates an XmlaTester + * + * @throws ClassNotFoundException on error + * @throws IllegalAccessException on error + * @throws InstantiationException on error + * @throws NoSuchMethodException on error + * @throws InvocationTargetException on error + */ + public XmlaTester() + throws ClassNotFoundException, IllegalAccessException, + InstantiationException, NoSuchMethodException, + InvocationTargetException + { + final Properties properties = TestContext.getTestProperties(); + final String catalogUrl = + properties.getProperty( + TestContext.Property.XMLA_CATALOG_URL.path); + Map catalogNameUrls = + new HashMap(); + catalogNameUrls.put("FoodMart", catalogUrl); + String urlString = + properties.getProperty(TestContext.Property.CONNECT_URL.path); + + final Class clazz = Class.forName("mondrian.olap4j.MondrianInprocProxy"); + final Constructor constructor = + clazz.getConstructor(Map.class, String.class); + this.proxy = + (XmlaOlap4jProxy) constructor.newInstance( + catalogNameUrls, urlString); + this.cookie = XmlaOlap4jDriver.nextCookie(); + XmlaOlap4jDriver.PROXY_MAP.put(cookie, proxy); + } + + public Connection createConnection() throws SQLException { + if (connection != null) { + return connection; + } + try { + Class.forName(DRIVER_CLASS_NAME); + } catch (ClassNotFoundException e) { + throw new RuntimeException("oops", e); + } + Properties info = new Properties(); + info.setProperty( + XmlaOlap4jDriver.Property.Catalog.name(), "FoodMart"); + connection = + DriverManager.getConnection( + getURL(), + info); + return connection; + } + + public Connection createConnectionWithUserPassword() throws SQLException { + try { + Class.forName(DRIVER_CLASS_NAME); + } catch (ClassNotFoundException e) { + throw new RuntimeException("oops", e); + } + Properties info = new Properties(); + info.setProperty( + XmlaOlap4jDriver.Property.Catalog.name(), "FoodMart"); + return DriverManager.getConnection( + getURL(), USER, PASSWORD); + } + + public String getDriverUrlPrefix() { + return DRIVER_URL_PREFIX; + } + + public String getDriverClassName() { + return DRIVER_CLASS_NAME; + } + + public String getURL() { + return "jdbc:xmla:Server=http://foo;Catalog=FoodMart;TestProxyCookie=" + cookie; + } + + public Flavor getFlavor() { + return Flavor.XMLA; + } + + public TestContext.Wrapper getWrapper() { + return TestContext.Wrapper.NONE; + } + + public static final String DRIVER_CLASS_NAME = + "org.olap4j.driver.xmla.XmlaOlap4jDriver"; + + public static final String DRIVER_URL_PREFIX = "jdbc:xmla:"; + private static final String USER = "user"; + private static final String PASSWORD = "password"; +} + +// End XmlaTester.java diff --git a/testsrc/org/olap4j/impl/Olap4jUtilTest.java b/testsrc/org/olap4j/impl/Olap4jUtilTest.java index 2899ff7..a4c74ff 100644 --- a/testsrc/org/olap4j/impl/Olap4jUtilTest.java +++ b/testsrc/org/olap4j/impl/Olap4jUtilTest.java @@ -57,4 +57,4 @@ public void testWildcard() { } } -// End Olap4jOlap4jUtilTest.java +// End Olap4jUtilTest.java diff --git a/testsrc/org/olap4j/mdx/MdxTest.java b/testsrc/org/olap4j/mdx/MdxTest.java index 04daba0..48e892c 100644 --- a/testsrc/org/olap4j/mdx/MdxTest.java +++ b/testsrc/org/olap4j/mdx/MdxTest.java @@ -52,7 +52,7 @@ public void testImplode() { new IdentifierNode.Segment( null, "bar", IdentifierNode.Quoting.QUOTED)); assertEquals( - "foo.[bar]", + "foo.[bar]", IdentifierNode.unparseIdentifierList(fooBar)); List empty = Collections.emptyList(); diff --git a/testsrc/org/olap4j/test/TestContext.java b/testsrc/org/olap4j/test/TestContext.java index 7e07c41..03cb7ec 100644 --- a/testsrc/org/olap4j/test/TestContext.java +++ b/testsrc/org/olap4j/test/TestContext.java @@ -156,7 +156,7 @@ private static void printRows( */ private static void printAxis(PrintWriter pw, CellSetAxis axis) { List positions = axis.getPositions(); - for (Position position: positions) { + for (Position position : positions) { boolean firstTime = true; pw.print("{"); for (Member member : position.getMembers()) { @@ -471,7 +471,7 @@ public static synchronized Properties getTestProperties() { // ignore } } - + dir = dir.getParentFile(); } } @@ -560,7 +560,10 @@ public interface Tester { */ Wrapper getWrapper(); - enum Flavor { MONDRIAN, XMLA } + enum Flavor { + MONDRIAN, + XMLA + } } /**