it.biztech.btable.olap.OlapUtils.java Source code

Java tutorial

Introduction

Here is the source code for it.biztech.btable.olap.OlapUtils.java

Source

/*
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
 * If a copy of the MPL was not distributed with this file, You can obtain one at
 * http://mozilla.org/MPL/2.0/.
 *
 * Covered Software is provided under this License on an as is basis,
 * without warranty of any kind, either expressed, implied, or statutory,
 * including, without limitation, warranties that the Covered Software is
 * free of defects, merchantable, fit for a particular purpose or non-infringing.
 * The entire risk as to the quality and performance of the Covered Software is with You.
 * Should any Covered Software prove defective in any respect, You (not any Contributor)
 * assume the cost of any necessary servicing, repair, or correction.
 * This disclaimer of warranty constitutes an essential part of this License.
 * No use of any Covered Software is authorized under this License except under this disclaimer.
 */

package it.biztech.btable.olap;

import java.util.HashMap;
import java.util.List;
import javax.sql.DataSource;

import mondrian.olap.Connection;
import mondrian.olap.Dimension;
import mondrian.olap.DriverManager;
import mondrian.olap.Hierarchy;
import mondrian.olap.Level;
import mondrian.olap.MondrianDef.CalculatedMember;
import mondrian.olap.MondrianDef.Cube;
import mondrian.olap.MondrianDef.Measure;
import mondrian.olap.MondrianDef.Schema;
import mondrian.olap.Query;
import mondrian.olap.Role;
import mondrian.olap.Util;
import mondrian.rolap.RolapConnectionProperties;
import mondrian.rolap.RolapMember;
import mondrian.rolap.RolapMemberBase;
import mondrian.rolap.RolapResult;
import mondrian.rolap.RolapSchema;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.json.JSONException;

import org.pentaho.platform.api.data.IDBDatasourceService;
import org.pentaho.platform.api.engine.ICacheManager;
import org.pentaho.platform.api.engine.IConnectionUserRoleMapper;
import org.pentaho.platform.api.engine.IPentahoSession;
import org.pentaho.platform.api.engine.PentahoAccessControlException;
import org.pentaho.platform.engine.core.system.PentahoSessionHolder;
import org.pentaho.platform.engine.core.system.PentahoSystem;
import org.pentaho.platform.plugin.action.mondrian.catalog.IMondrianCatalogService;
import org.pentaho.platform.plugin.action.mondrian.catalog.MondrianCatalog;
import org.pentaho.platform.plugin.action.mondrian.catalog.MondrianCatalogHelper;
import org.pentaho.platform.plugin.action.mondrian.catalog.MondrianCube;
import org.pentaho.platform.plugin.services.connections.mondrian.MDXConnection;
import org.pentaho.platform.util.messages.LocaleHelper;

@SuppressWarnings("deprecation")
public class OlapUtils {

    private static Log logger = LogFactory.getLog(OlapUtils.class);

    private IPentahoSession userSession;
    private ICacheManager cacheManager;
    boolean cachingAvailable;
    private static final String MONDRIAN_CATALOGS = "CDFDD_DATASOURCES_REPOSITORY_DOCUMENT";
    private final IMondrianCatalogService mondrianCatalogService = MondrianCatalogHelper.getInstance();
    Connection nativeConnection = null;

    public OlapUtils() {
        this.userSession = PentahoSessionHolder.getSession();
        cacheManager = PentahoSystem.getCacheManager(userSession);
        cachingAvailable = cacheManager != null && cacheManager.cacheEnabled();
    }

    public JSONObject getOlapCubes() throws JSONException {
        logger.debug("Returning Olap cubes");

        JSONObject result = new JSONObject();
        JSONArray catalogsArray = new JSONArray();

        List<MondrianCatalog> catalogList = getMondrianCatalogs();
        for (MondrianCatalog catalog : catalogList) {

            Connection connection = getMdxConnection(catalog.getDefinition(), catalog.getJndi());
            if (connection == null) {
                logger.error("Failed to get valid connection");
                return null;
            }
            Role role = connection.getRole();

            JSONArray cubesArray = new JSONArray();

            List<MondrianCube> cubeList = catalog.getSchema().getCubes();
            for (MondrianCube cube : cubeList) {

                String query = "select {Measures.Children} ON Rows, {} ON Columns from [" + cube.getId() + "]";
                Query mdxQuery = null;
                try {
                    mdxQuery = connection.parseQuery(query);
                } catch (Exception e) {
                }

                if (mdxQuery != null) {
                    mondrian.olap.Cube olapCube = mdxQuery.getCube();
                    if (role.canAccess(olapCube)) {
                        JSONObject cubeJson = new JSONObject();
                        cubeJson.put("id", cube.getId());
                        cubeJson.put("name", cube.getName());
                        cubeJson.put("caption", olapCube.getCaption());
                        cubeJson.put("description", olapCube.getDescription());
                        cubesArray.add(cubeJson);
                    }
                }

            }

            JSONObject catalogJson = new JSONObject();
            catalogJson.put("name", catalog.getName());
            catalogJson.put("schema", catalog.getDefinition());
            catalogJson.put("jndi", catalog.getJndi());
            //catalogJson.put("cubes", JSONArray.fromObject(catalog.getSchema().getCubes()));
            catalogJson.put("cubes", cubesArray);
            catalogsArray.add(catalogJson);

        }

        logger.debug("Cubes found: " + catalogsArray.toString(2));

        result.put("catalogs", catalogsArray);

        return result;
    }

    public JSONObject getCubeStructure(String catalog, String cube, String jndi) throws JSONException {
        logger.debug("Returning Olap structure for cube " + cube);

        JSONObject result = new JSONObject();

        Connection connection = jndi != null ? getMdxConnection(catalog, jndi) : getMdxConnection(catalog);

        if (connection == null) {
            logger.error("Failed to get valid connection");
            return null;
        }

        JSONArray dimensionsArray = getDimensions(connection, cube);
        System.out.println(dimensionsArray.toString(2));
        result.put("dimensions", dimensionsArray);

        JSONArray measuresArray = getMeasures(connection, cube);
        System.out.println(measuresArray.toString(2));
        result.put("measures", measuresArray);

        return result;
    }

    private JSONArray getDimensions(Connection connection, String cube) throws JSONException {
        String query = "select {} ON Rows, {} ON Columns from [" + cube + "]";
        Query mdxQuery = connection.parseQuery(query);

        Role role = connection.getRole();

        JSONArray dimensionsArray = new JSONArray();
        Dimension[] dimensions = mdxQuery.getCube().getDimensions();

        for (Dimension dimension : dimensions) {
            if (dimension.isMeasures() || !role.canAccess(dimension)) {
                continue;
            }

            JSONObject jsonDimension = new JSONObject();
            jsonDimension.put("name", dimension.getName());
            jsonDimension.put("caption",
                    dimension.getCaption().isEmpty() ? dimension.getName() : dimension.getCaption());
            jsonDimension.put("description", dimension.getDescription());
            jsonDimension.put("type", dimension.getDimensionType().name());

            // Hierarchies
            JSONArray hierarchiesArray = new JSONArray();
            Hierarchy[] hierarchies = dimension.getHierarchies();

            for (Hierarchy hierarchy : hierarchies) {
                if (role.canAccess(hierarchy)) {
                    JSONObject jsonHierarchy = new JSONObject();
                    jsonHierarchy.put("type", "hierarchy");
                    jsonHierarchy.put("name", hierarchy.getName());
                    jsonHierarchy.put("caption",
                            hierarchy.getCaption().isEmpty() ? hierarchy.getName() : hierarchy.getCaption());
                    jsonHierarchy.put("description", hierarchy.getDescription());
                    jsonHierarchy.put("qualifiedName",
                            hierarchy.getQualifiedName().substring(11, hierarchy.getQualifiedName().length() - 1));
                    jsonHierarchy.put("defaultMember", hierarchy.getAllMember().getName());
                    jsonHierarchy.put("defaultMemberCaption",
                            hierarchy.getAllMember().getCaption().isEmpty() ? hierarchy.getAllMember().getName()
                                    : hierarchy.getAllMember().getCaption());
                    jsonHierarchy.put("defaultMemberQualifiedName", hierarchy.getAllMember().getQualifiedName()
                            .substring(8, hierarchy.getAllMember().getQualifiedName().length() - 1));

                    // Levels
                    JSONArray levelsArray = new JSONArray();
                    Level[] levels = hierarchy.getLevels();

                    for (Level level : levels) {
                        JSONObject jsonLevel = new JSONObject();
                        if (!level.isAll()) {
                            jsonLevel.put("type", "level");
                            jsonLevel.put("depth", level.getDepth());
                            jsonLevel.put("name", level.getName());
                            jsonLevel.put("caption",
                                    level.getCaption().isEmpty() ? level.getName() : level.getCaption());
                            jsonLevel.put("description", level.getDescription());
                            jsonLevel.put("qualifiedName",
                                    level.getQualifiedName().substring(7, level.getQualifiedName().length() - 1));

                            levelsArray.add(jsonLevel);
                        }
                    }

                    jsonHierarchy.put("levels", levelsArray);
                    hierarchiesArray.add(jsonHierarchy);
                }
            }

            jsonDimension.put("hierarchies", hierarchiesArray);
            dimensionsArray.add(jsonDimension);
        }

        return dimensionsArray;
    }

    private JSONArray getMeasures(Connection connection, String cube) throws JSONException {
        String query = "select {Measures.Children} ON Rows, {} ON Columns from [" + cube + "]";
        Query mdxQuery = connection.parseQuery(query);

        Role role = connection.getRole();

        RolapResult result = (RolapResult) connection.execute(mdxQuery);
        List<RolapMember> rolapMembers = result.getCube().getMeasuresMembers();

        HashMap<String, JSONObject> defs = new HashMap<String, JSONObject>();

        RolapSchema rolapSchema = result.getCube().getSchema();
        Schema schemaDef = rolapSchema.getXMLSchema();

        Cube[] mdCubes = schemaDef.cubes;
        for (Cube mdCube : mdCubes) {
            if (mdCube.name.equals(cube)) {

                Measure[] mdMeasures = mdCube.measures;
                for (Measure mdMeasure : mdMeasures) {
                    JSONObject jsonMdMeasure = new JSONObject();
                    jsonMdMeasure.put("datatype", mdMeasure.datatype);
                    jsonMdMeasure.put("formatString", mdMeasure.formatString);

                    defs.put(mdMeasure.name, jsonMdMeasure);
                }

                CalculatedMember[] mdCalculatedMembers = mdCube.calculatedMembers;
                for (CalculatedMember mdCalculatedMember : mdCalculatedMembers) {
                    JSONObject jsonMdCalculatedMember = new JSONObject();
                    jsonMdCalculatedMember.put("formatString", mdCalculatedMember.getFormatString());
                    jsonMdCalculatedMember.put("formula", mdCalculatedMember.getFormula());

                    defs.put(mdCalculatedMember.name, jsonMdCalculatedMember);
                }

            }
        }

        JSONArray measuresArray = new JSONArray();

        for (RolapMember measure : rolapMembers) {
            if (role.canAccess(measure) && measure.isVisible()) {
                String name = ((RolapMemberBase) measure).getName();
                JSONObject jsonMeasure = new JSONObject();
                jsonMeasure.put("type", "measure");
                jsonMeasure.put("name", name);
                jsonMeasure.put("caption", ((RolapMemberBase) measure).getCaption().isEmpty() ? name
                        : ((RolapMemberBase) measure).getCaption());
                jsonMeasure.put("description", ((RolapMemberBase) measure).getDescription());
                jsonMeasure.put("qualifiedName",
                        measure.getQualifiedName().substring(8, measure.getQualifiedName().length() - 1));
                jsonMeasure.put("memberType", measure.getMemberType().toString());
                jsonMeasure.put("formatString",
                        defs.containsKey(name) ? defs.get(name).get("formatString") : "#,###");

                measuresArray.add(jsonMeasure);
            }
        }

        return measuresArray;
    }

    private Connection getMdxConnection(String catalog) {
        if (catalog != null && catalog.startsWith("/")) {
            catalog = StringUtils.substring(catalog, 1);
        }

        MondrianCatalog selectedCatalog = mondrianCatalogService.getCatalog(catalog, userSession);
        if (selectedCatalog == null) {
            logger.error("Received catalog '" + catalog + "' doesn't appear to be valid");
            return null;
        }
        selectedCatalog.getDataSourceInfo();
        logger.info("Found catalog " + selectedCatalog.toString());

        return getMdxConnection(selectedCatalog.getDefinition(), selectedCatalog.getJndi());
    }

    private Connection getMdxConnection(String catalog, String jndi) {
        String connectStr = "Provider=mondrian; DataSource=" + jndi + "; Catalog=" + catalog
                + "; DynamicSchemaProcessor=mondrian.i18n.LocalizingDynamicSchemaProcessor; Locale="
                + LocaleHelper.getLocale().toString() + "; Role='" + getRoles(catalog) + "'";

        return getMdxConnectionFromConnectionString(connectStr);
    }

    private Connection getMdxConnectionFromConnectionString(String connectStr) {
        Util.PropertyList properties = Util.parseConnectString(connectStr);
        try {
            String dataSourceName = properties.get(RolapConnectionProperties.DataSource.name());

            if (dataSourceName != null) {
                IDBDatasourceService datasourceService = PentahoSystem.getObjectFactory()
                        .get(IDBDatasourceService.class, null);
                DataSource dataSourceImpl = datasourceService.getDataSource(dataSourceName);
                if (dataSourceImpl != null) {
                    properties.remove(RolapConnectionProperties.DataSource.name());
                    nativeConnection = DriverManager.getConnection(properties, null, dataSourceImpl);
                } else {
                    nativeConnection = DriverManager.getConnection(properties, null);
                }
            } else {
                nativeConnection = DriverManager.getConnection(properties, null);
            }

            if (nativeConnection == null) {
                logger.error("Invalid connection: " + connectStr);
            }
        } catch (Throwable t) {
            logger.error("Invalid connection: " + connectStr + " - " + t.toString());
        }

        return nativeConnection;
    }

    private List<MondrianCatalog> getMondrianCatalogs() {
        List<MondrianCatalog> catalogs = null;

        if (cachingAvailable && (catalogs = (List<MondrianCatalog>) cacheManager.getFromSessionCache(userSession,
                MONDRIAN_CATALOGS)) != null) {
            logger.debug("Datasource document found in cache");
            return catalogs;
        } else {
            catalogs = mondrianCatalogService.listCatalogs(userSession, true);
            cacheManager.putInSessionCache(userSession, MONDRIAN_CATALOGS, catalogs);
        }

        return catalogs;
    }

    public String getRoles(String catalog) {
        if (PentahoSystem.getObjectFactory().objectDefined(MDXConnection.MDX_CONNECTION_MAPPER_KEY)) {
            final IConnectionUserRoleMapper mondrianUserRoleMapper = PentahoSystem
                    .get(IConnectionUserRoleMapper.class, MDXConnection.MDX_CONNECTION_MAPPER_KEY, null);
            try {
                final String[] validMondrianRolesForUser = mondrianUserRoleMapper.mapConnectionRoles(
                        PentahoSessionHolder.getSession(), catalog.replaceAll("mondrian:/", ""));

                if ((validMondrianRolesForUser != null) && (validMondrianRolesForUser.length > 0)) {
                    final StringBuffer buff = new StringBuffer();
                    for (int i = 0; i < validMondrianRolesForUser.length; i++) {
                        final String aRole = validMondrianRolesForUser[i];
                        // According to http://mondrian.pentaho.org/documentation/configuration.php
                        // double-comma escapes a comma
                        if (i > 0) {
                            buff.append(",");
                        }
                        buff.append(aRole.replaceAll(",", ",,"));
                    }
                    logger.debug("Assembled role: " + buff.toString() + " for catalog: " + catalog);
                    return buff.toString();
                }

            } catch (PentahoAccessControlException e) {
                logger.error("User has no rights to the catalog: " + catalog);
            }
        }

        return "";
    }

}