/*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* Copyright 2014 Pentaho Corporation. All rights reserved.
*
*/
package org.pentaho.platform.plugin.action.olap;
import mondrian.olap.Util;
import mondrian.xmla.XmlaHandler;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.olap4j.Cell;
import org.olap4j.CellSet;
import org.olap4j.OlapConnection;
import org.olap4j.OlapException;
import org.olap4j.OlapStatement;
import org.olap4j.metadata.Cube;
import org.olap4j.metadata.Hierarchy;
import org.olap4j.metadata.Level;
import org.olap4j.metadata.Member;
import org.olap4j.metadata.MetadataElement;
import org.olap4j.metadata.Property;
import org.olap4j.metadata.Schema;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* Access to XmlaExtra inside OSGI where M4 is running is tricky. This class will delegate to the correct classes
* using the reflection api. Note that only the methods used inside extensions or Analyzer are implemented. More can
* be implemented as necessary.
*/
@SuppressWarnings( "unchecked" )
public class PlatformXmlaExtra implements XmlaHandler.XmlaExtra {
private static final String MONDRIAN_XMLA_EXTRA_NAME = "mondrian.xmla.XmlaHandler$XmlaExtra";
private static final String MONDRIAN_ROLAP_CONNECTION_NAME = "mondrian.rolap.RolapConnection";
private static final Log logger = LogFactory.getLog( PlatformXmlaExtra.class );
private Class<?> clazz;
private Object xmlaExtra;
public static XmlaHandler.XmlaExtra unwrapXmlaExtra( final OlapConnection olap4jConn )
throws SQLException {
try {
if ( inCurrentClassLoader( olap4jConn ) ) {
return olap4jConn.unwrap( XmlaHandler.XmlaExtra.class );
} else if ( isMondrianConnection( olap4jConn ) ) {
PlatformXmlaExtra platformXmlaExtra = new PlatformXmlaExtra( olap4jConn );
if ( platformXmlaExtra.isValid() ) {
return platformXmlaExtra;
}
}
} catch ( ClassNotFoundException e ) {
logger.warn( "Problem unwrapping XmlaExtra", e );
}
return null;
}
private boolean isValid() {
return clazz != null && xmlaExtra != null;
}
private static boolean isMondrianConnection( final OlapConnection olap4jConn )
throws SQLException, ClassNotFoundException {
return olap4jConn.isWrapperFor(
olap4jConn.getClass().getClassLoader().loadClass( MONDRIAN_ROLAP_CONNECTION_NAME ) );
}
private static boolean inCurrentClassLoader( final OlapConnection olap4jConn ) throws ClassNotFoundException {
return olap4jConn.getClass().getClassLoader().loadClass( MONDRIAN_XMLA_EXTRA_NAME )
.equals( XmlaHandler.XmlaExtra.class );
}
private PlatformXmlaExtra( final OlapConnection olap4jConn ) {
try {
this.clazz = olap4jConn.getClass().getClassLoader().loadClass( MONDRIAN_XMLA_EXTRA_NAME );
this.xmlaExtra = olap4jConn.unwrap( clazz );
} catch ( Exception e ) {
logger.warn( "Unable to retrieve XmlaExtra", e );
}
}
public Object invoke( String methodName, Class<?> paramType, Object param, Object defaultValue ) {
try {
return clazz.getMethod( methodName, paramType ).invoke( xmlaExtra, param );
} catch ( Exception e ) {
//really hope we never get here given all the checks during object construction
logger.warn( "Using default value for " + methodName, e );
}
return defaultValue;
}
@Override
public ResultSet executeDrillthrough( final OlapStatement olapStatement, final String s, final boolean b,
final String s2, final int[] ints )
throws SQLException {
throw new UnsupportedOperationException( );
}
@Override public void setPreferList( final OlapConnection olapConnection ) {
throw new UnsupportedOperationException( );
}
@Override public Date getSchemaLoadDate( final Schema schema ) {
throw new UnsupportedOperationException( );
}
@Override public int getLevelCardinality( final Level level ) throws OlapException {
throw new UnsupportedOperationException( );
}
@Override
public void getSchemaFunctionList( final List<FunctionDefinition> functionDefinitions, final Schema schema,
final Util.Functor1<Boolean, String> booleanStringFunctor1 ) {
throw new UnsupportedOperationException( );
}
@Override public int getHierarchyCardinality( final Hierarchy hierarchy ) throws OlapException {
throw new UnsupportedOperationException( );
}
@Override public int getHierarchyStructure( final Hierarchy hierarchy ) {
throw new UnsupportedOperationException( );
}
@Override public boolean isHierarchyParentChild( final Hierarchy hierarchy ) {
return (Boolean) invoke( "isHierarchyParentChild", Hierarchy.class, hierarchy, false );
}
@Override public int getMeasureAggregator( final Member member ) {
throw new UnsupportedOperationException();
}
@Override public void checkMemberOrdinal( final Member member ) throws OlapException {
throw new UnsupportedOperationException( );
}
@Override public boolean shouldReturnCellProperty( final CellSet cellSet, final Property property, final boolean b ) {
throw new UnsupportedOperationException( );
}
@Override public List<String> getSchemaRoleNames( final Schema schema ) {
throw new UnsupportedOperationException( );
}
@Override public String getSchemaId( final Schema schema ) {
return (String) invoke( "getSchemaId", Schema.class, schema, "" );
}
@Override public String getCubeType( final Cube cube ) {
throw new UnsupportedOperationException( );
}
@Override public boolean isLevelUnique( final Level level ) {
throw new UnsupportedOperationException( );
}
@Override public List<Property> getLevelProperties( final Level level ) {
return (List<Property>) invoke( "getLevelProperties", Level.class, level, Collections.emptyList() );
}
@Override public boolean isPropertyInternal( final Property property ) {
throw new UnsupportedOperationException( );
}
@Override public List<Map<String, Object>> getDataSources( final OlapConnection olapConnection )
throws OlapException {
throw new UnsupportedOperationException( );
}
@Override public Map<String, Object> getAnnotationMap( final MetadataElement metadataElement ) throws SQLException {
return (Map<String, Object>) invoke(
"getAnnotationMap", MetadataElement.class, metadataElement, Collections.emptyMap() );
}
@Override public boolean canDrillThrough( final Cell cell ) {
return (Boolean) invoke( "canDrillThrough", Cell.class, cell, false );
}
@Override public int getDrillThroughCount( final Cell cell ) {
return (Integer) invoke( "getDrillThroughCount", Cell.class, cell, 0 );
}
@Override public void flushSchemaCache( final OlapConnection olapConnection ) throws OlapException {
invoke( "flushSchemaCache", OlapConnection.class, olapConnection, null );
}
@Override public Object getMemberKey( final Member member ) throws OlapException {
return invoke( "getMemberKey", Member.class, member, null );
}
@Override public Object getOrderKey( final Member member ) throws OlapException {
return invoke( "getOrderKey", Member.class, member, null );
}
}