/* * 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 2008 - 2009 Pentaho Corporation. All rights reserved. * * * Created May 7, 2009 * @author rmansoor */ package org.pentaho.platform.dataaccess.datasource.wizard.service.impl; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.net.URI; import java.net.URL; import java.sql.Connection; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.Properties; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.pentaho.commons.connection.IPentahoResultSet; import org.pentaho.commons.connection.marshal.MarshallableResultSet; import org.pentaho.commons.connection.marshal.MarshallableRow; import org.pentaho.metadata.model.Domain; import org.pentaho.metadata.model.InlineEtlPhysicalModel; import org.pentaho.metadata.model.LogicalModel; import org.pentaho.metadata.model.SqlPhysicalModel; import org.pentaho.metadata.repository.DomainAlreadyExistsException; import org.pentaho.metadata.repository.DomainIdNullException; import org.pentaho.metadata.repository.DomainStorageException; import org.pentaho.metadata.repository.IMetadataDomainRepository; import org.pentaho.metadata.repository.InMemoryMetadataDomainRepository; import org.pentaho.metadata.util.InlineEtlModelGenerator; import org.pentaho.metadata.util.SQLModelGenerator; import org.pentaho.metadata.util.SQLModelGeneratorException; import org.pentaho.platform.api.engine.PentahoSystemException; import org.pentaho.platform.dataaccess.datasource.beans.BogoPojo; import org.pentaho.platform.dataaccess.datasource.beans.BusinessData; import org.pentaho.platform.dataaccess.datasource.beans.LogicalModelSummary; import org.pentaho.platform.dataaccess.datasource.beans.SerializedResultSet; import org.pentaho.platform.dataaccess.datasource.wizard.service.DatasourceServiceException; import org.pentaho.platform.dataaccess.datasource.wizard.service.QueryValidationException; import org.pentaho.platform.dataaccess.datasource.wizard.service.gwt.IDatasourceService; import org.pentaho.platform.dataaccess.datasource.wizard.service.impl.utils.DatasourceInMemoryServiceHelper; import org.pentaho.platform.dataaccess.datasource.wizard.service.impl.utils.DatasourceServiceHelper; import org.pentaho.platform.dataaccess.datasource.wizard.service.messages.Messages; import org.pentaho.platform.engine.core.system.PentahoSessionHolder; import org.pentaho.platform.plugin.services.connections.sql.SQLConnection; import org.pentaho.platform.util.messages.LocaleHelper; /* * TODO mlowery This class professes to be a datasource service yet it takes as inputs both IDatasource instances and * lower-level BusinessData instances. (BusinessData instances are stored in IDatasources.) They are not currently being * kept in sync. I propose that the service only deals with IDatasources from a caller perspective. */ public class InMemoryDatasourceServiceImpl implements IDatasourceService { public static final IMetadataDomainRepository METADATA_DOMAIN_REPO = new InMemoryMetadataDomainRepository(); private static final Log logger = LogFactory.getLog(InMemoryDatasourceServiceImpl.class); public static final String DEFAULT_UPLOAD_FILEPATH_FILE_NAME = "debug_upload_filepath.properties"; //$NON-NLS-1$ public static final String UPLOAD_FILE_PATH = "upload.file.path"; //$NON-NLS-1$ private static final String BEFORE_QUERY = " SELECT * FROM ("; private static final String AFTER_QUERY = ")"; private IMetadataDomainRepository metadataDomainRepository; public InMemoryDatasourceServiceImpl() { // this needs to share the same one as MQL editor... metadataDomainRepository = METADATA_DOMAIN_REPO; } public boolean deleteLogicalModel(String domainId, String modelName) throws DatasourceServiceException { try { metadataDomainRepository.removeModel(domainId, modelName); } catch (DomainStorageException dse) { logger.error(Messages.getInstance().getErrorString("InMemoryDatasourceServiceImpl.ERROR_0017_UNABLE_TO_STORE_DOMAIN", domainId), dse); throw new DatasourceServiceException(Messages.getInstance().getErrorString( "InMemoryDatasourceServiceImpl.ERROR_0016_UNABLE_TO_STORE_DOMAIN", domainId), dse); //$NON-NLS-1$ } catch (DomainIdNullException dne) { logger.error(Messages.getInstance().getErrorString("DatasourceServiceDelegate.ERROR_0019_DOMAIN_IS_NULL"), dne); throw new DatasourceServiceException(Messages.getInstance() .getErrorString("InMemoryDatasourceServiceImpl.ERROR_0019_DOMAIN_IS_NULL"), dne); //$NON-NLS-1$ } return true; } protected List<String> getPermittedRoleList() { DebugDataAccessViewPermissionHandler dataAccessViewPermHandler = new DebugDataAccessViewPermissionHandler(); return dataAccessViewPermHandler.getPermittedRoleList(PentahoSessionHolder.getSession()); } protected List<String> getPermittedUserList() { DebugDataAccessViewPermissionHandler dataAccessViewPermHandler = new DebugDataAccessViewPermissionHandler(); return dataAccessViewPermHandler.getPermittedUserList(PentahoSessionHolder.getSession()); } protected int getDefaultAcls() { DebugDataAccessViewPermissionHandler dataAccessViewPermHandler = new DebugDataAccessViewPermissionHandler(); return dataAccessViewPermHandler.getDefaultAcls(PentahoSessionHolder.getSession()); } private IPentahoResultSet executeQuery(String connectionName, String query, String previewLimit) throws QueryValidationException { SQLConnection sqlConnection = null; int limit = (previewLimit != null && previewLimit.length() > 0) ? Integer.parseInt(previewLimit) : -1; try { sqlConnection = DatasourceInMemoryServiceHelper.getConnection(connectionName); sqlConnection.setMaxRows(limit); sqlConnection.setReadOnly(true); return sqlConnection.executeQuery(BEFORE_QUERY + query + AFTER_QUERY); } catch (Exception e) { logger.error(Messages.getInstance().getErrorString( "InMemoryDatasourceServiceImpl.ERROR_0009_QUERY_VALIDATION_FAILED", e.getLocalizedMessage()), e);//$NON-NLS-1$ throw new QueryValidationException(e.getLocalizedMessage(), e); //$NON-NLS-1$ } finally { if (sqlConnection != null) { sqlConnection.close(); } } } public SerializedResultSet doPreview(String connectionName, String query, String previewLimit) throws DatasourceServiceException { SerializedResultSet returnResultSet; try { executeQuery(connectionName, query, previewLimit); returnResultSet = DatasourceInMemoryServiceHelper.getSerializeableResultSet(connectionName, query, Integer.parseInt(previewLimit), null); } catch (QueryValidationException e) { logger.error(Messages.getInstance().getErrorString( "InMemoryDatasourceServiceImpl.ERROR_0009_QUERY_VALIDATION_FAILED", e.getLocalizedMessage()), e);//$NON-NLS-1$ throw new DatasourceServiceException(Messages.getInstance().getErrorString( "InMemoryDatasourceServiceImpl.ERROR_0009_QUERY_VALIDATION_FAILED", e.getLocalizedMessage()), e); //$NON-NLS-1$ } return returnResultSet; } public boolean testDataSourceConnection(String connectionName) throws DatasourceServiceException { Connection conn = null; try { conn = DatasourceInMemoryServiceHelper.getDataSourceConnection(connectionName); } catch (DatasourceServiceException dme) { logger.error(Messages.getInstance().getErrorString("InMemoryDatasourceServiceImpl.ERROR_0026_UNABLE_TO_TEST_CONNECTION", connectionName), dme); throw new DatasourceServiceException(Messages.getInstance().getErrorString( "InMemoryDatasourceServiceImpl.ERROR_0026_UNABLE_TO_TEST_CONNECTION", connectionName), dme); //$NON-NLS-1$ } finally { try { if (conn != null) { conn.close(); } } catch (SQLException e) { logger.error(Messages.getInstance().getErrorString("InMemoryDatasourceServiceImpl.ERROR_0026_UNABLE_TO_TEST_CONNECTION", connectionName), e); throw new DatasourceServiceException(Messages.getInstance().getErrorString( "InMemoryDatasourceServiceImpl.ERROR_0026_UNABLE_TO_TEST_CONNECTION", connectionName), e); //$NON-NLS-1$ } } return true; } /** * This method gets the business data which are the business columns, columns types and sample preview data * * @param modelName, connection, query, previewLimit * @return BusinessData * @throws DatasourceServiceException */ public BusinessData generateLogicalModel(String modelName, String connectionName, String query, String previewLimit) throws DatasourceServiceException { try { executeQuery(connectionName, query, previewLimit); Boolean securityEnabled = (getPermittedRoleList() != null && getPermittedRoleList().size() > 0) || (getPermittedUserList() != null && getPermittedUserList().size() > 0); SerializedResultSet resultSet = DatasourceInMemoryServiceHelper.getSerializeableResultSet(connectionName, query, Integer.parseInt(previewLimit), null); SQLModelGenerator sqlModelGenerator = new SQLModelGenerator(modelName, connectionName, resultSet.getColumnTypes(), resultSet.getColumns(),query, securityEnabled, getPermittedRoleList(), getPermittedUserList(), getDefaultAcls(), "joe"); Domain domain = sqlModelGenerator.generate(); return new BusinessData(domain, resultSet.getData()); } catch (SQLModelGeneratorException smge) { logger.error(Messages.getInstance().getErrorString("InMemoryDatasourceServiceImpl.ERROR_0016_UNABLE_TO_GENERATE_MODEL", smge.getLocalizedMessage()), smge); throw new DatasourceServiceException(Messages.getInstance() .getErrorString("InMemoryDatasourceServiceImpl.ERROR_0015_UNABLE_TO_GENERATE_MODEL"), smge); //$NON-NLS-1$ } catch (QueryValidationException e) { logger.error(Messages.getInstance().getErrorString( "InMemoryDatasourceServiceImpl.ERROR_0009_QUERY_VALIDATION_FAILED", e.getLocalizedMessage()), e);//$NON-NLS-1$ throw new DatasourceServiceException(Messages.getInstance().getErrorString( "InMemoryDatasourceServiceImpl.ERROR_0009_QUERY_VALIDATION_FAILED", e.getLocalizedMessage()), e); //$NON-NLS-1$ } } public IMetadataDomainRepository getMetadataDomainRepository() { return metadataDomainRepository; } public void setMetadataDomainRepository(IMetadataDomainRepository metadataDomainRepository) { this.metadataDomainRepository = metadataDomainRepository; } public BusinessData generateInlineEtlLogicalModel(String modelName, String relativeFilePath, boolean headersPresent, String delimiter, String enclosure) throws DatasourceServiceException { try { Boolean securityEnabled = (getPermittedRoleList() != null && getPermittedRoleList().size() > 0) || (getPermittedUserList() != null && getPermittedUserList().size() > 0); InlineEtlModelGenerator inlineEtlModelGenerator = new InlineEtlModelGenerator(modelName, getUploadFilePath() + File.separatorChar, relativeFilePath, headersPresent, delimiter, enclosure, securityEnabled, getPermittedRoleList(), getPermittedUserList(), getDefaultAcls(), "joe"); Domain domain = inlineEtlModelGenerator.generate(); Properties properties = new Properties(); String path = null; FileInputStream fis = null; try { URL url = ClassLoader.getSystemResource(DEFAULT_UPLOAD_FILEPATH_FILE_NAME); URI uri = url.toURI(); File file = new File(uri); fis = new FileInputStream(file); properties.load(fis); path = (String) properties.get(UPLOAD_FILE_PATH); } catch (IOException e) { logger.error(Messages.getInstance().getErrorString("InMemoryDatasourceServiceImpl.ERROR_0016_UNABLE_TO_GENERATE_MODEL", e .getLocalizedMessage()), e); throw new DatasourceServiceException(Messages.getInstance().getErrorString( "InMemoryDatasourceServiceImpl.ERROR_0015_UNABLE_TO_GENERATE_MODEL", e.getLocalizedMessage()), e); //$NON-NLS-1$ } finally { fis.close(); } List<List<String>> data = DatasourceInMemoryServiceHelper.getCsvDataSample(path + File.separatorChar + relativeFilePath, headersPresent, delimiter, enclosure, 5); return new BusinessData(domain, data); } catch (Exception e) { logger.error(Messages.getInstance().getErrorString("InMemoryDatasourceServiceImpl.ERROR_0016_UNABLE_TO_GENERATE_MODEL", e .getLocalizedMessage()), e); throw new DatasourceServiceException(Messages.getInstance().getErrorString( "InMemoryDatasourceServiceImpl.ERROR_0015_UNABLE_TO_GENERATE_MODEL", e.getLocalizedMessage()), e); //$NON-NLS-1$ } } public BusinessData loadBusinessData(String domainId, String modelId) throws DatasourceServiceException { Domain domain = getMetadataDomainRepository().getDomain(domainId); List<List<String>> data = null; if (domain.getPhysicalModels().get(0) instanceof InlineEtlPhysicalModel) { InlineEtlPhysicalModel model = (InlineEtlPhysicalModel) domain.getPhysicalModels().get(0); data = DatasourceInMemoryServiceHelper.getCsvDataSample(model.getFileLocation(), model.getHeaderPresent(), model .getDelimiter(), model.getEnclosure(), 5); } else { SqlPhysicalModel model = (SqlPhysicalModel) domain.getPhysicalModels().get(0); String query = model.getPhysicalTables().get(0).getTargetTable(); SerializedResultSet resultSet = DatasourceInMemoryServiceHelper.getSerializeableResultSet(model.getDatasource().getDatabaseName(), query, 5,null); data = resultSet.getData(); } return new BusinessData(domain, data); } public boolean saveLogicalModel(Domain domain, boolean overwrite) throws DatasourceServiceException { String domainName = domain.getId(); try { getMetadataDomainRepository().storeDomain(domain, overwrite); return true; } catch (DomainStorageException dse) { logger.error(Messages.getInstance().getErrorString("InMemoryDatasourceServiceImpl.ERROR_0017_UNABLE_TO_STORE_DOMAIN", domainName), dse); throw new DatasourceServiceException(Messages.getInstance().getErrorString( "InMemoryDatasourceServiceImpl.ERROR_0016_UNABLE_TO_STORE_DOMAIN", domainName), dse); //$NON-NLS-1$ } catch (DomainAlreadyExistsException dae) { logger.error(Messages.getInstance().getErrorString("InMemoryDatasourceServiceImpl.ERROR_0018_DOMAIN_ALREADY_EXIST", domainName), dae); throw new DatasourceServiceException(Messages.getInstance().getErrorString( "InMemoryDatasourceServiceImpl.ERROR_0018_DOMAIN_ALREADY_EXIST", domainName), dae); //$NON-NLS-1$ } catch (DomainIdNullException dne) { logger.error(Messages.getInstance().getErrorString("InMemoryDatasourceServiceImpl.ERROR_0019_DOMAIN_IS_NULL"), dne); throw new DatasourceServiceException(Messages.getInstance() .getErrorString("InMemoryDatasourceServiceImpl.ERROR_0019_DOMAIN_IS_NULL"), dne); //$NON-NLS-1$ } } private String getUploadFilePath() throws DatasourceServiceException { try { URL url = ClassLoader.getSystemResource(DEFAULT_UPLOAD_FILEPATH_FILE_NAME); URI uri = url.toURI(); File file = new File(uri); FileInputStream fis = new FileInputStream(file); try { Properties properties = new Properties(); properties.load(fis); return (String) properties.get(UPLOAD_FILE_PATH); } finally { fis.close(); } } catch (Exception e) { throw new DatasourceServiceException(e); } } public boolean hasPermission() { return true; } public List<LogicalModelSummary> getLogicalModels() throws DatasourceServiceException { List<LogicalModelSummary> logicalModelSummaries = new ArrayList<LogicalModelSummary>(); for (String domainId : getMetadataDomainRepository().getDomainIds()) { Domain domain = getMetadataDomainRepository().getDomain(domainId); String locale = LocaleHelper.getLocale().toString(); String locales[] = new String[domain.getLocales().size()]; for (int i = 0; i < domain.getLocales().size(); i++) { locales[i] = domain.getLocales().get(i).getCode(); } locale = LocaleHelper.getClosestLocale(locale, locales); for (LogicalModel model : domain.getLogicalModels()) { logicalModelSummaries.add(new LogicalModelSummary(domainId, model.getId(), model.getName().getString(locale))); } } return logicalModelSummaries; } public BogoPojo gwtWorkaround(BogoPojo pojo) { return pojo; } }