org.pentaho.platform.dataaccess.datasource.api.DataSourceWizardService.java Source code

Java tutorial

Introduction

Here is the source code for org.pentaho.platform.dataaccess.datasource.api.DataSourceWizardService.java

Source

/*!
 * 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 (c) 2002-2015 Pentaho Corporation..  All rights reserved.
 */

package org.pentaho.platform.dataaccess.datasource.api;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.pentaho.agilebi.modeler.ModelerPerspective;
import org.pentaho.agilebi.modeler.ModelerWorkspace;
import org.pentaho.agilebi.modeler.gwt.GwtModelerWorkspaceHelper;
import org.pentaho.agilebi.modeler.services.IModelerService;
import org.pentaho.agilebi.modeler.util.ModelerWorkspaceHelper;
import org.pentaho.metadata.model.Domain;
import org.pentaho.metadata.model.LogicalModel;
import org.pentaho.metadata.util.MondrianModelExporter;
import org.pentaho.metadata.util.XmiParser;
import org.pentaho.platform.api.engine.IPentahoSession;
import org.pentaho.platform.api.engine.PentahoAccessControlException;
import org.pentaho.platform.api.repository.datasource.IDatasourceMgmtService;
import org.pentaho.platform.api.repository2.unified.IPlatformImportBundle;
import org.pentaho.platform.api.repository2.unified.IUnifiedRepository;
import org.pentaho.platform.api.repository2.unified.RepositoryFileAcl;
import org.pentaho.platform.dataaccess.datasource.api.DataSourceWizardService.DswPublishValidationException.Type;
import org.pentaho.platform.dataaccess.datasource.beans.LogicalModelSummary;
import org.pentaho.platform.dataaccess.datasource.utils.DataAccessPermissionUtil;
import org.pentaho.platform.dataaccess.datasource.wizard.service.DatasourceServiceException;
import org.pentaho.platform.dataaccess.datasource.wizard.service.gwt.IDSWDatasourceService;
import org.pentaho.platform.dataaccess.datasource.wizard.service.impl.DSWDatasourceServiceImpl;
import org.pentaho.platform.dataaccess.datasource.wizard.service.impl.ModelerService;
import org.pentaho.platform.engine.core.system.PentahoSessionHolder;
import org.pentaho.platform.engine.core.system.PentahoSystem;
import org.pentaho.platform.engine.services.metadata.MetadataPublisher;
import org.pentaho.platform.plugin.action.mondrian.MondrianCachePublisher;
import org.pentaho.platform.plugin.action.mondrian.catalog.IAclAwareMondrianCatalogService;
import org.pentaho.platform.plugin.action.mondrian.catalog.MondrianCatalogServiceException;
import org.pentaho.platform.plugin.services.importer.IPlatformImporter;
import org.pentaho.platform.plugin.services.importer.RepositoryFileImportBundle;
import org.pentaho.platform.plugin.services.importexport.legacy.MondrianCatalogRepositoryHelper;
import org.pentaho.platform.plugin.services.metadata.IAclAwarePentahoMetadataDomainRepositoryImporter;
import org.pentaho.platform.plugin.services.metadata.IPentahoMetadataDomainRepositoryExporter;
import org.pentaho.platform.repository2.unified.webservices.RepositoryFileAclDto;
import org.pentaho.platform.dataaccess.datasource.wizard.service.ConnectionServiceException;

public class DataSourceWizardService extends DatasourceService {

    protected IDSWDatasourceService dswService;
    protected IModelerService modelerService;
    protected IDatasourceMgmtService datasourceMgmtSvc;

    protected IAclAwarePentahoMetadataDomainRepositoryImporter aclAwarePentahoMetadataDomainRepositoryImporter;
    protected IAclAwareMondrianCatalogService aclAwareMondrianCatalogService;

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

    private static final String MONDRIAN_CATALOG_REF = "MondrianCatalogRef"; //$NON-NLS-1$
    private static final String METADATA_PUBLISHER = MetadataPublisher.class.getName();
    private static final String MONDRIAN_PUBLISHER = MondrianCachePublisher.class.getName();
    private static final String ENCODING = "UTF-8";
    private static final String MONDRIAN_CONNECTION_PARAM = "parameters";
    private static final String MONDRIAN_SCHEMA_NAME = "schema.xml";
    private static final String MONDRIAN_MIME = "application/vnd.pentaho.mondrian+xml";
    private static final String METADATA_MIME = "text/xmi+xml";
    private static final String METADATA_EXT = ".xmi";
    private static final String IMPORT_DOMAIN_ID = "domain-id";

    public DataSourceWizardService() {
        dswService = getDswDatasourceService();
        modelerService = new ModelerService();
        datasourceMgmtSvc = PentahoSystem.get(IDatasourceMgmtService.class, PentahoSessionHolder.getSession());
        if (metadataDomainRepository instanceof IAclAwarePentahoMetadataDomainRepositoryImporter) {
            aclAwarePentahoMetadataDomainRepositoryImporter = (IAclAwarePentahoMetadataDomainRepositoryImporter) metadataDomainRepository;
        }
        if (mondrianCatalogService instanceof IAclAwareMondrianCatalogService) {
            aclAwareMondrianCatalogService = (IAclAwareMondrianCatalogService) mondrianCatalogService;
        }
    }

    protected IDSWDatasourceService getDswDatasourceService() {
        return new DSWDatasourceServiceImpl();
    }

    public Map<String, InputStream> doGetDSWFilesAsDownload(String dswId) throws PentahoAccessControlException {
        if (!canManageACL()) {
            throw new PentahoAccessControlException();
        }
        // First get the metadata files;
        Map<String, InputStream> fileData = getMetadataFiles(dswId);

        // Then get the corresponding mondrian files
        Domain domain = metadataDomainRepository.getDomain(dswId);
        ModelerWorkspace model = createModelerWorkspace();
        model.setDomain(domain);
        LogicalModel logicalModel = model.getLogicalModel(ModelerPerspective.ANALYSIS);
        if (logicalModel == null) {
            logicalModel = model.getLogicalModel(ModelerPerspective.REPORTING);
        }
        if (logicalModel.getProperty(MONDRIAN_CATALOG_REF) != null) {
            MondrianCatalogRepositoryHelper helper = createMondrianCatalogRepositoryHelper();
            String catalogRef = (String) logicalModel.getProperty(MONDRIAN_CATALOG_REF);
            fileData.putAll(helper.getModrianSchemaFiles(catalogRef));
            parseMondrianSchemaNameWrapper(dswId, fileData);
        }

        return fileData;
    }

    public void removeDSW(String dswId) throws PentahoAccessControlException {
        try {
            ensureDataAccessPermissionCheck();
        } catch (ConnectionServiceException e) {
            throw new PentahoAccessControlException();
        }
        Domain domain = metadataDomainRepository.getDomain(dswId);
        ModelerWorkspace model = createModelerWorkspace();
        model.setDomain(domain);
        LogicalModel logicalModel = model.getLogicalModel(ModelerPerspective.ANALYSIS);
        if (logicalModel == null) {
            logicalModel = model.getLogicalModel(ModelerPerspective.REPORTING);
        }
        if (logicalModel.getProperty(MONDRIAN_CATALOG_REF) != null) {
            String catalogRef = (String) logicalModel.getProperty(MONDRIAN_CATALOG_REF);
            try {
                mondrianCatalogService.removeCatalog(catalogRef, getSession());
            } catch (MondrianCatalogServiceException e) {
                logger.warn("Failed to remove mondrian catalog", e);
            }
        }
        try {
            dswService.deleteLogicalModel(domain.getId(), logicalModel.getId());
        } catch (DatasourceServiceException ex) {
            logger.warn("Failed to remove logical model", ex);
        }
        metadataDomainRepository.removeDomain(dswId);
    }

    public List<String> getDSWDatasourceIds() {
        List<String> datasourceList = new ArrayList<String>();
        try {
            nextModel: for (LogicalModelSummary summary : dswService.getLogicalModels(null)) {
                Domain domain = modelerService.loadDomain(summary.getDomainId());
                List<LogicalModel> logicalModelList = domain.getLogicalModels();
                if (logicalModelList != null && logicalModelList.size() >= 1) {
                    for (LogicalModel logicalModel : logicalModelList) {
                        Object property = logicalModel.getProperty("AGILE_BI_GENERATED_SCHEMA"); //$NON-NLS-1$
                        if (property != null) {
                            datasourceList.add(summary.getDomainId());
                            continue nextModel;
                        }
                    }
                }
            }
        } catch (Throwable e) {
            return null;
        }
        return datasourceList;
    }

    public String publishDsw(String domainId, InputStream metadataFile, boolean overwrite, boolean checkConnection,
            RepositoryFileAclDto acl) throws PentahoAccessControlException, IllegalArgumentException,
            DswPublishValidationException, Exception {
        if (!hasManageAccessCheck()) {
            throw new PentahoAccessControlException();
        }
        if (!endsWith(domainId, METADATA_EXT)) {
            // if doesn't end in case-sensitive '.xmi' there will be trouble later on
            final String errorMsg = "domainId must end in " + METADATA_EXT;
            throw new IllegalArgumentException(errorMsg);
        }
        if (metadataFile == null) {
            throw new IllegalArgumentException("metadataFile is null");
        }
        if (!overwrite) {
            final List<String> overwritten = getOverwrittenDomains(domainId);
            if (!overwritten.isEmpty()) {
                final String domainIds = StringUtils.join(overwritten, ",");
                throw new DswPublishValidationException(DswPublishValidationException.Type.OVERWRITE_CONFLICT,
                        domainIds);
            }
        }

        XmiParser xmiParser = createXmiParser();
        Domain domain = null;
        try {
            domain = xmiParser.parseXmi(metadataFile);
        } catch (Exception e) {
            throw new DswPublishValidationException(DswPublishValidationException.Type.INVALID_XMI, e.getMessage());
        }
        domain.setId(domainId);
        if (checkConnection) {
            final String connectionId = getMondrianDatasourceWrapper(domain);
            if (datasourceMgmtSvc.getDatasourceByName(connectionId) == null) {
                final String msg = "connection not found: '" + connectionId + "'";
                throw new DswPublishValidationException(Type.MISSING_CONNECTION, msg);
            }
        }
        // build bundles
        InputStream metadataIn = toInputStreamWrapper(domain, xmiParser);
        IPlatformImportBundle metadataBundle = createMetadataDswBundle(domain, metadataIn, overwrite, acl);
        IPlatformImportBundle mondrianBundle = createMondrianDswBundle(domain, acl);
        // do import
        IPlatformImporter importer = getIPlatformImporter();
        importer.importFile(metadataBundle);
        logger.debug("imported metadata xmi");
        importer.importFile(mondrianBundle);
        logger.debug("imported mondrian schema");
        // trigger refreshes
        IPentahoSession session = getSession();
        PentahoSystem.publish(session, METADATA_PUBLISHER);
        PentahoSystem.publish(session, MONDRIAN_PUBLISHER);
        logger.info("publishDsw: Published DSW with domainId='" + domainId + "'.");
        return domainId;
    }

    /**
     * Retrieve ACL of the DSW. Actually it is ACL of it's Metadata.
     *
     * @param dswId dsw id
     * @return ACL
     * @throws PentahoAccessControlException
     */
    public RepositoryFileAclDto getDSWAcl(String dswId)
            throws PentahoAccessControlException, FileNotFoundException {
        checkDSWExists(dswId);

        if (aclAwarePentahoMetadataDomainRepositoryImporter != null) {
            final RepositoryFileAcl acl = aclAwarePentahoMetadataDomainRepositoryImporter.getAclFor(dswId);
            return acl == null ? null : repositoryFileAclAdapter.marshal(acl);
        }
        return null;
    }

    /**
     * Set ACL to both Mondrian Catalog and Metadata Schema
     *
     * @param dswId dsw id
     * @param aclDto ACL
     * @throws PentahoAccessControlException
     * @throws FileNotFoundException
     */
    public void setDSWAcl(String dswId, RepositoryFileAclDto aclDto)
            throws PentahoAccessControlException, FileNotFoundException {
        checkDSWExists(dswId);

        if (!endsWith(dswId, METADATA_EXT)) {
            // if doesn't end in case-sensitive '.xmi' there will be trouble later on
            final String errorMsg = "domainId must end in " + METADATA_EXT;
            throw new IllegalArgumentException(errorMsg);
        }

        final RepositoryFileAcl acl = aclDto == null ? null : repositoryFileAclAdapter.unmarshal(aclDto);
        if (aclAwareMondrianCatalogService != null) {
            aclAwareMondrianCatalogService.setAclFor(dswId.substring(0, dswId.lastIndexOf(METADATA_EXT)), acl);
        }
        if (aclAwarePentahoMetadataDomainRepositoryImporter != null) {
            aclAwarePentahoMetadataDomainRepositoryImporter.setAclFor(dswId, acl);
        }
        flushDataSources();
    }

    private void checkDSWExists(String dswId) throws PentahoAccessControlException, FileNotFoundException {
        try {
            doGetDSWFilesAsDownload(dswId);
        } catch (NullPointerException e) {
            throw new FileNotFoundException(dswId + " doesn't exist");
        }
    }

    public static class DswPublishValidationException extends Exception {
        public enum Type {
            OVERWRITE_CONFLICT, MISSING_CONNECTION, INVALID_XMI
        }

        private static final long serialVersionUID = 1L;
        private Type type;

        public DswPublishValidationException(Type type, String msg) {
            super(msg);
        }

        public Type getType() {
            return type;
        }
    }

    protected List<String> getOverwrittenDomains(String dswId) {
        List<String> domainIds = new ArrayList<String>(2);
        if (metadataDomainRepository.getDomainIds().contains(dswId)) {
            domainIds.add("dsw/" + dswId);
        }
        final String catalogName = toAnalysisDomainId(dswId);
        if (mondrianCatalogService.getCatalog(catalogName, PentahoSessionHolder.getSession()) != null) {
            domainIds.add("mondrian/" + catalogName);
        }
        return domainIds;
    }

    private String toAnalysisDomainId(String dswId) {
        return dswId.substring(0, dswId.lastIndexOf('.'));
    }

    protected IPlatformImportBundle createMetadataDswBundle(Domain domain, InputStream metadataIn,
            boolean overwrite, RepositoryFileAclDto acl) {
        final RepositoryFileImportBundle.Builder builder = new RepositoryFileImportBundle.Builder()
                .input(metadataIn).charSet(ENCODING).hidden(false).overwriteFile(overwrite).mime(METADATA_MIME)
                .withParam(IMPORT_DOMAIN_ID, domain.getId()).preserveDsw(true);
        if (acl != null) {
            builder.acl(repositoryFileAclAdapter.unmarshal(acl)).applyAclSettings(true);
        }
        return builder.build();
    }

    /**
     * Generate a mondrian schema from the model and create the appropriate import bundle
     * @param domain domain with olap model
     * @return import bundle
     * @throws DatasourceServiceException 
     * @throws Exception If schema generation fails
     */
    protected IPlatformImportBundle createMondrianDswBundle(Domain domain, RepositoryFileAclDto acl)
            throws DatasourceServiceException, DswPublishValidationException, IOException {
        final String analysisDomainId = toAnalysisDomainId(domain.getId());
        final String dataSource = ModelerService.getMondrianDatasource(domain);
        // get olap logical model
        final String locale = Locale.getDefault().toString();
        ModelerWorkspace workspace = new ModelerWorkspace(new ModelerWorkspaceHelper(locale),
                dswService.getGeoContext());
        workspace.setModelName(analysisDomainId);
        workspace.setDomain(domain);
        LogicalModel olapModel = workspace.getLogicalModel(ModelerPerspective.ANALYSIS);
        if (olapModel == null) {
            throw new IllegalArgumentException("No analysis model in xmi.");
        }
        // reference schema in xmi
        olapModel.setProperty(MONDRIAN_CATALOG_REF, analysisDomainId);
        // generate schema
        MondrianModelExporter exporter = new MondrianModelExporter(olapModel, locale);
        String mondrianSchema = null;
        try {
            mondrianSchema = exporter.createMondrianModelXML();
        } catch (Exception e) {
            throw new DswPublishValidationException(Type.INVALID_XMI, e.getMessage());
        }
        // create bundle
        final RepositoryFileImportBundle.Builder builder = new RepositoryFileImportBundle.Builder()
                .input(IOUtils.toInputStream(mondrianSchema, ENCODING)).name(MONDRIAN_SCHEMA_NAME).charSet(ENCODING)
                .overwriteFile(true).mime(MONDRIAN_MIME).withParam(IMPORT_DOMAIN_ID, analysisDomainId)
                .withParam(MONDRIAN_CONNECTION_PARAM, "DataSource=" + dataSource);
        if (acl != null) {
            builder.acl(repositoryFileAclAdapter.unmarshal(acl)).applyAclSettings(true);
        }
        return builder.build();
    }

    protected boolean canAdministerCheck() {
        return super.canAdminister();
    }

    protected void ensureDataAccessPermissionCheck() throws ConnectionServiceException {
        super.ensureDataAccessPermission();
    }

    protected boolean hasManageAccessCheck() {
        return DataAccessPermissionUtil.hasManageAccess();
    }

    protected boolean endsWith(String str, String suffix) {
        return StringUtils.endsWith(str, suffix);
    }

    protected XmiParser createXmiParser() {
        return new XmiParser();
    }

    protected void parseMondrianSchemaNameWrapper(String dswId, Map<String, InputStream> fileData) {
        super.parseMondrianSchemaName(dswId, fileData);
    }

    protected String getMondrianDatasourceWrapper(Domain domain) {
        return ModelerService.getMondrianDatasource(domain);
    }

    protected InputStream toInputStreamWrapper(Domain domain, XmiParser xmiParser) throws IOException {
        return IOUtils.toInputStream(xmiParser.generateXmi(domain), ENCODING);
    }

    protected String parseMondrianSchemaNameWrapper(String dswId) {
        return super.fixEncodedSlashParam(dswId);
    }

    protected Map<String, InputStream> getMetadataFiles(String dswId) {
        return ((IPentahoMetadataDomainRepositoryExporter) metadataDomainRepository).getDomainFilesData(dswId);
    }

    protected ModelerWorkspace createModelerWorkspace() {
        return new ModelerWorkspace(new GwtModelerWorkspaceHelper());
    }

    protected MondrianCatalogRepositoryHelper createMondrianCatalogRepositoryHelper() {
        return new MondrianCatalogRepositoryHelper(PentahoSystem.get(IUnifiedRepository.class));
    }

    protected IPentahoSession getSession() {
        return PentahoSessionHolder.getSession();
    }

    protected IPlatformImporter getIPlatformImporter() {
        return PentahoSystem.get(IPlatformImporter.class);
    }

}