/* * 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 2005 - 2009 Pentaho Corporation. All rights reserved. * * * @created Apr 28, 2005 * @author James Dixon */ package org.pentaho.platform.plugin.action.mondrian; import mondrian.olap.*; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.pentaho.commons.connection.IPentahoConnection; import org.pentaho.platform.api.engine.IPentahoSession; import org.pentaho.platform.engine.core.system.PentahoSystem; import org.pentaho.platform.engine.services.connection.PentahoConnectionFactory; import org.pentaho.platform.engine.services.solution.ComponentBase; import org.pentaho.platform.plugin.action.messages.Messages; import org.pentaho.platform.plugin.action.mondrian.catalog.MondrianCatalogComplementInfo; import org.pentaho.platform.plugin.action.mondrian.catalog.MondrianCatalogHelper; import org.pentaho.platform.plugin.services.connections.mondrian.MDXConnection; import org.pentaho.platform.plugin.services.connections.sql.SQLConnection; import org.pentaho.platform.util.logging.Logger; import java.util.HashSet; import java.util.Properties; /** * @author James Dixon * * TODO To change the template for this generated type comment go to Window - * Preferences - Java - Code Style - Code Templates */ public class MondrianModelComponent extends ComponentBase { private static final long serialVersionUID = -718697500002076945L; @Override public Log getLogger() { return LogFactory.getLog(MondrianModelComponent.class); } @Override protected boolean validateSystemSettings() { // This component does not have any system settings to validate return true; } @Override public boolean init() { // get the settings from the system configuration file return true; } @Override public boolean validateAction() { return true; } @Override public boolean executeAction() { return true; } @Override public void done() { } public static String getInitialQuery(final Properties properties, final String cubeName, IPentahoSession session) throws Throwable { MDXConnection mdxConnection = (MDXConnection) PentahoConnectionFactory.getConnection( IPentahoConnection.MDX_DATASOURCE, properties, session, null); // mdxConnection.setProperties( properties ); Connection connection = mdxConnection.getConnection(); if (connection == null) { Logger .error( "MondrianModelComponent", Messages.getInstance().getErrorString("MondrianModel.ERROR_0001_INVALID_CONNECTION", properties.toString())); //$NON-NLS-1$ //$NON-NLS-2$ return null; } try { return MondrianModelComponent.getInitialQuery(connection, cubeName); } catch (Throwable t) { if (t instanceof MondrianException) { // pull the cause out, otherwise it never gets logged Throwable cause = ((MondrianException) t).getCause(); if (cause != null) { throw cause; } else { throw t; } } else { throw t; } } } /** * @param modelPath * @param connectionString * @param driver * @param user * @param password * @param cubeName * @return mdx string that represents the initial query * @throws Throwable * @deprecated */ @Deprecated public static String getInitialQuery(final String modelPath, final String connectionString, final String driver, final String user, final String password, final String cubeName, IPentahoSession session) throws Throwable { return MondrianModelComponent.getInitialQuery(modelPath, connectionString, driver, user, password, cubeName, null, session); } /** * @param modelPath * @param connectionString * @param driver * @param user * @param password * @param cubeName * @param roleName * @return mdx string that represents the initial query * @throws Throwable * @deprecated */ @Deprecated public static String getInitialQuery(String modelPath, final String connectionString, final String driver, final String user, final String password, final String cubeName, final String roleName, IPentahoSession session) throws Throwable { Properties properties = new Properties(); // TODO support driver manager connections if (!PentahoSystem.ignored) { if (driver != null) { properties.put("Driver", driver); //$NON-NLS-1$ } if (user != null) { properties.put("User", user); //$NON-NLS-1$ } if (password != null) { properties.put("Password", password); //$NON-NLS-1$ } } if (modelPath.indexOf("http") == 0) { //$NON-NLS-1$ properties.put("Catalog", modelPath); //$NON-NLS-1$ } else { if (modelPath.indexOf("http") == 0) { //$NON-NLS-1$ properties.put("Catalog", modelPath); //$NON-NLS-1$ } else { if (!modelPath.startsWith("solution:")) { //$NON-NLS-1$ modelPath = "solution:" + modelPath; //$NON-NLS-1$ } properties.put("Catalog", modelPath); //$NON-NLS-1$ } } properties.put("Provider", "mondrian"); //$NON-NLS-1$ //$NON-NLS-2$ properties.put("PoolNeeded", "false"); //$NON-NLS-1$//$NON-NLS-2$ properties.put("dataSource", connectionString); //$NON-NLS-1$ if (roleName != null) { properties.put("Role", roleName); //$NON-NLS-1$ } return MondrianModelComponent.getInitialQuery(properties, cubeName, session); } /** * @param modelPath * @param connectionString * @param cubeName * @return mdx string that represents the initial query * @throws Throwable * @deprecated */ @Deprecated public static String getInitialQuery(final String modelPath, final String connectionString, final String cubeName, IPentahoSession session) throws Throwable { return MondrianModelComponent.getInitialQuery(modelPath, connectionString, cubeName, null, session); } /** * @param modelPath * @param jndi * @param cubeName * @param roleName * @return mdx string that represents the initial query * @throws Throwable * @deprecated */ @Deprecated public static String getInitialQuery(String modelPath, String jndi, final String cubeName, final String roleName, IPentahoSession session) throws Throwable { Properties properties = new Properties(); if (modelPath.indexOf("http") == 0) { //$NON-NLS-1$ properties.put("Catalog", modelPath); //$NON-NLS-1$ } else { if (!modelPath.startsWith("solution:")) { //$NON-NLS-1$ modelPath = "solution:" + modelPath; //$NON-NLS-1$ } properties.put("Catalog", modelPath); //$NON-NLS-1$ } properties.put("Provider", "mondrian"); //$NON-NLS-1$ //$NON-NLS-2$ properties.put("PoolNeeded", "false"); //$NON-NLS-1$ //$NON-NLS-2$ properties.put("dataSource", jndi); //$NON-NLS-1$ if (roleName != null) { properties.put("Role", roleName); //$NON-NLS-1$ } return MondrianModelComponent.getInitialQuery(properties, cubeName, session); } public static String getInitialQuery(final Connection connection, final String cubeName) throws Throwable { String measuresMdx = null; String columnsMdx = null; String whereMdx = ""; //$NON-NLS-1$ StringBuffer rowsMdx = new StringBuffer(); // Get catalog info, if exists String catalog = connection.getCatalogName(); MondrianCatalogComplementInfo catalogComplementInfo = MondrianCatalogHelper.getInstance().getCatalogComplementInfoMap(catalog); try { Schema schema = connection.getSchema(); if (schema == null) { Logger .error( "MondrianModelComponent", Messages.getInstance().getErrorString("MondrianModel.ERROR_0002_INVALID_SCHEMA", connection.getConnectString())); //$NON-NLS-1$ //$NON-NLS-2$ return null; } Cube cubes[] = schema.getCubes(); if ((cubes == null) || (cubes.length == 0)) { Logger .error( "MondrianModelComponent", Messages.getInstance().getErrorString("MondrianModel.ERROR_0003_NO_CUBES", connection.getConnectString())); //$NON-NLS-1$ //$NON-NLS-2$ return null; } if ((cubes.length > 1) && (cubeName == null)) { Logger .error( "MondrianModelComponent", Messages.getInstance().getErrorString("MondrianModel.ERROR_0004_CUBE_NOT_SPECIFIED", connection.getConnectString())); //$NON-NLS-1$ //$NON-NLS-2$ return null; } Cube cube = null; if (cubes.length == 1) { cube = cubes[0]; } else { for (Cube element : cubes) { if (element.getName().equals(cubeName)) { cube = element; break; } } } if (cube == null) { Logger .error( "MondrianModelComponent", Messages.getInstance().getErrorString("MondrianModel.ERROR_0005_CUBE_NOT_FOUND", cubeName, connection.getConnectString())); //$NON-NLS-1$ //$NON-NLS-2$ return null; } // If we have any whereConditions block, we need to find which hierarchies they are in // and not include them in the rows HashSet<Hierarchy> whereHierarchies = new HashSet<Hierarchy>(); if (catalogComplementInfo != null && catalogComplementInfo.getWhereCondition(cube.getName()) != null && !catalogComplementInfo.getWhereCondition(cube.getName()).equals("")) { //$NON-NLS-1$ final String rawString = catalogComplementInfo.getWhereCondition(cube.getName()); // Caveat - It's possible that we have in the where condition a hierarchy that we don't have access // permissions; In this case, we'll ditch the where condition at all. Same for any error that // we find here try { // According to Julian, the better way to resolve the names is to build a query final String queryStr = "select " + rawString + " on columns, {} on rows from " + cube.getName(); //$NON-NLS-1$ //$NON-NLS-2$ final Query query = connection.parseQuery(queryStr); final Hierarchy[] hierarchies = query.getMdxHierarchiesOnAxis(AxisOrdinal.StandardAxisOrdinal.COLUMNS); boolean isWhereValid = true; for (int i = 0; i < hierarchies.length && isWhereValid; i++) { final Hierarchy hierarchy = hierarchies[i]; if (connection.getRole().canAccess(hierarchy)) { whereHierarchies.add(hierarchy); } else { isWhereValid = false; whereHierarchies.clear(); } } if (isWhereValid) { whereMdx = " WHERE " + rawString; //$NON-NLS-1$ } } catch (Exception e) { // We found an error in the where slicer, so we'll just act like it wasn't here whereHierarchies.clear(); } } Dimension dimensions[] = cube.getDimensions(); if ((dimensions == null) || (dimensions.length == 0)) { Logger .error( "MondrianModelComponent", Messages.getInstance().getErrorString("MondrianModel.ERROR_0006_NO_DIMENSIONS", cubeName, connection.getConnectString())); //$NON-NLS-1$ //$NON-NLS-2$ return null; } for (Dimension element : dimensions) { Hierarchy hierarchy = element.getHierarchy(); if (hierarchy == null) { Logger .error( "MondrianModelComponent", Messages.getInstance().getErrorString("MondrianModel.ERROR_0007_NO_HIERARCHIES", element.getName(), cubeName, connection.getConnectString())); //$NON-NLS-1$ //$NON-NLS-2$ return null; } if (!connection.getRole().canAccess(hierarchy)) { // We can't access this element continue; } if (whereHierarchies.contains(hierarchy)) { // We have it on the where condition - skip it continue; } Member member = hierarchy.getDefaultMember(); if (member == null) { Logger .error( "MondrianModelComponent", Messages.getInstance().getErrorString("MondrianModel.ERROR_0008_NO_DEFAULT_MEMBER", element.getName(), cubeName, connection.getConnectString())); //$NON-NLS-1$ //$NON-NLS-2$ return null; } if (element.isMeasures()) { // measuresMdx = "with member "+ member.getUniqueName(); // //$NON-NLS-1$ measuresMdx = ""; //$NON-NLS-1$ columnsMdx = " select NON EMPTY {" + member.getUniqueName() + "} ON columns, "; //$NON-NLS-1$ //$NON-NLS-2$ } else { if (rowsMdx.length() > 0) { rowsMdx.append(", "); //$NON-NLS-1$ } rowsMdx.append(member.getUniqueName()); } } if ((measuresMdx != null) && (columnsMdx != null) && (rowsMdx.length() > 0)) { StringBuffer result = new StringBuffer(measuresMdx.length() + columnsMdx.length() + rowsMdx.length() + 50); result.append(measuresMdx).append(columnsMdx).append("NON EMPTY {(") //$NON-NLS-1$ .append(rowsMdx).append(")} ON rows ") //$NON-NLS-1$ .append("from [" + cube.getName() + "]") //$NON-NLS-1$ //$NON-NLS-2$ .append(whereMdx); return result.toString(); } return null; } catch (Throwable t) { if (t instanceof MondrianException) { // pull the cause out, otherwise it never gets logged Throwable cause = ((MondrianException) t).getCause(); if (cause != null) { throw cause; } else { throw t; } } else { throw t; } } } protected SQLConnection getConnection(final String jndiName, final String driver, final String userId, final String password, final String connectionInfo) { SQLConnection connection = null; try { if (jndiName != null) { connection = (SQLConnection) PentahoConnectionFactory.getConnection(IPentahoConnection.SQL_DATASOURCE, jndiName, getSession(), this); } if (connection == null) { if ((driver == null) && (connectionInfo == null)) { // TODO raise an error } connection = (SQLConnection) PentahoConnectionFactory.getConnection(IPentahoConnection.SQL_DATASOURCE, driver, connectionInfo, userId, password, getSession(), this); } if (connection == null) { Logger.error( "MondrianModelComponent", Messages.getInstance().getErrorString("SQLBaseComponent.ERROR_0005_INVALID_CONNECTION")); //$NON-NLS-1$ //$NON-NLS-2$ return null; } return connection; } catch (Exception e) { Logger.error( "MondrianModelComponent", Messages.getInstance().getErrorString("SQLBaseComponent.ERROR_0006_EXECUTE_FAILED", ""), e); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } return null; } }