Java tutorial
/*! * 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); } }