/*! * 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-2017 Pentaho Corporation.. All rights reserved. */ package org.pentaho.platform.dataaccess.datasource.wizard.service.impl; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.pentaho.agilebi.modeler.geo.GeoContext; import org.pentaho.agilebi.modeler.gwt.BogoPojo; import org.pentaho.agilebi.modeler.util.MultiTableModelerSource; import org.pentaho.database.model.IDatabaseConnection; import org.pentaho.database.util.DatabaseUtil; import org.pentaho.di.core.database.Database; import org.pentaho.di.core.database.DatabaseMeta; import org.pentaho.di.core.exception.KettleDatabaseException; import org.pentaho.metadata.model.Domain; import org.pentaho.metadata.model.LogicalModel; import org.pentaho.metadata.model.concept.Concept; import org.pentaho.metadata.model.concept.security.Security; import org.pentaho.metadata.model.concept.security.SecurityOwner; import org.pentaho.platform.dataaccess.datasource.utils.DataAccessPermissionUtil; import org.pentaho.platform.dataaccess.datasource.wizard.IDatasourceSummary; import org.pentaho.platform.dataaccess.datasource.wizard.service.ConnectionServiceException; import org.pentaho.platform.dataaccess.datasource.wizard.service.DatasourceServiceException; import org.pentaho.platform.dataaccess.datasource.wizard.service.gwt.IGwtJoinSelectionService; import org.pentaho.platform.dataaccess.datasource.wizard.service.impl.utils.ConnectionServiceHelper; import org.pentaho.platform.dataaccess.datasource.wizard.service.impl.utils.LegacyDatasourceConverter; import org.pentaho.platform.dataaccess.datasource.wizard.sources.query.QueryDatasourceSummary; import org.pentaho.platform.engine.core.system.PentahoBase; import org.pentaho.platform.engine.core.system.PentahoSessionHolder; import com.thoughtworks.xstream.XStream; public class MultitableDatasourceService extends PentahoBase implements IGwtJoinSelectionService { private DatabaseMeta databaseMeta; private ConnectionServiceImpl connectionServiceImpl; private Log logger = LogFactory.getLog( MultitableDatasourceService.class ); public MultitableDatasourceService() { this.connectionServiceImpl = new ConnectionServiceImpl(); init(); } public MultitableDatasourceService( DatabaseMeta databaseMeta ) { this.databaseMeta = databaseMeta; init(); } protected void init() { } private DatabaseMeta getDatabaseMeta( IDatabaseConnection connection ) throws ConnectionServiceException { if ( this.connectionServiceImpl == null ) { return this.databaseMeta; } // DatabaseConnection objects may be de-serialized from the client and missing extra parameters and attributes. // Resolve the connection by name through ConnectionService before use. // All public methods should use getDatabaseMeta to guarantee accurate connection info. // NOTE: We want to retrieve the connection again later, so we don't want an unsanitized name here connection = connectionServiceImpl.getConnectionByName( connection.getName(), false ); connection .setPassword( ConnectionServiceHelper.getConnectionPassword( connection.getName(), connection.getPassword() ) ); DatabaseMeta dbmeta = DatabaseUtil.convertToDatabaseMeta( connection ); dbmeta.getDatabaseInterface().setQuoteAllFields( true ); //This line probably shouldn't be here. It overrides the "Quote all in Database" checkbox return dbmeta; } public List<String> retrieveSchemas( IDatabaseConnection connection ) throws DatasourceServiceException { List<String> schemas = new ArrayList<String>(); try { DatabaseMeta databaseMeta = this.getDatabaseMeta( connection ); Database database = new Database( null, databaseMeta ); database.connect(); Map<String, Collection<String>> tableMap = database.getTableMap( null ); //database.getSchemas() Set<String> schemaNames = tableMap.keySet(); schemas.addAll( schemaNames ); database.disconnect(); } catch ( KettleDatabaseException e ) { logger.error( "Error creating database object", e ); throw new DatasourceServiceException( e ); } catch ( ConnectionServiceException e ) { logger.error( "Error getting database meta", e ); throw new DatasourceServiceException( e ); } return schemas; } public List<String> getDatabaseTables( IDatabaseConnection connection, String schema ) throws DatasourceServiceException { try { DatabaseMeta databaseMeta = this.getDatabaseMeta( connection ); Database database = new Database( null, databaseMeta ); database.connect(); String[] tableNames = database.getTablenames( schema, true ); List<String> tables = new ArrayList<String>(); tables.addAll( Arrays.asList( tableNames ) ); tables.addAll( Arrays.asList( database.getViews( schema, true ) ) ); database.disconnect(); return tables; } catch ( KettleDatabaseException e ) { logger.error( "Error creating database object", e ); throw new DatasourceServiceException( e ); } catch ( ConnectionServiceException e ) { logger.error( "Error getting database meta", e ); throw new DatasourceServiceException( e ); } } public IDatasourceSummary serializeJoins( MultiTableDatasourceDTO dto, IDatabaseConnection connection ) throws DatasourceServiceException { try { ModelerService modelerService = new ModelerService(); modelerService.initKettle(); DSWDatasourceServiceImpl datasourceService = new DSWDatasourceServiceImpl(); GeoContext geoContext = datasourceService.getGeoContext(); DatabaseMeta databaseMeta = this.getDatabaseMeta( connection ); MultiTableModelerSource multiTable = new MultiTableModelerSource( databaseMeta, dto.getSchemaModel(), dto.getDatasourceName(), dto.getSelectedTables(), geoContext ); Domain domain = multiTable.generateDomain( dto.isDoOlap() ); String modelState = serializeModelState( dto ); for ( LogicalModel lm : domain.getLogicalModels() ) { lm.setProperty( "datasourceModel", modelState ); lm.setProperty( "DatasourceType", "MULTI-TABLE-DS" ); // BISERVER-6450 - add security settings to the logical model applySecurity( lm ); } modelerService.serializeModels( domain, dto.getDatasourceName(), dto.isDoOlap() ); QueryDatasourceSummary summary = new QueryDatasourceSummary(); summary.setDomain( domain ); return summary; } catch ( Exception e ) { logger.error( "Error serializing joins", e ); throw new DatasourceServiceException( e ); } } private String serializeModelState( MultiTableDatasourceDTO dto ) throws DatasourceServiceException { XStream xs = new XStream(); return xs.toXML( dto ); } public MultiTableDatasourceDTO deSerializeModelState( String dtoStr ) throws DatasourceServiceException { try { XStream xs = new XStream(); xs.registerConverter( new LegacyDatasourceConverter() ); return (MultiTableDatasourceDTO) xs.fromXML( dtoStr ); } catch ( Exception e ) { logger.error( e ); throw new DatasourceServiceException( e ); } } public List<String> getTableFields( String table, IDatabaseConnection connection ) throws DatasourceServiceException { try { DatabaseMeta databaseMeta = this.getDatabaseMeta( connection ); Database database = new Database( null, databaseMeta ); database.connect(); String query = databaseMeta.getSQLQueryFields( table ); // Setting the query limit to 1 before executing the query database.setQueryLimit( 1 ); database.getRows( query, 1 ); String[] tableFields = database.getReturnRowMeta().getFieldNames(); List<String> fields = Arrays.asList( tableFields ); database.disconnect(); return fields; } catch ( KettleDatabaseException e ) { logger.error( e ); throw new DatasourceServiceException( e ); } catch ( ConnectionServiceException e ) { logger.error( e ); throw new DatasourceServiceException( e ); } } public BogoPojo gwtWorkaround( BogoPojo pojo ) { return pojo; } @Override public Log getLogger() { // TODO Auto-generated method stub return null; } protected boolean hasDataAccessViewPermission() { return DataAccessPermissionUtil.hasViewAccess(); } protected List<String> getPermittedRoleList() { return DataAccessPermissionUtil.getPermittedViewRoleList(); } protected List<String> getPermittedUserList() { return DataAccessPermissionUtil.getPermittedViewUserList(); } protected int getDefaultAcls() { return DataAccessPermissionUtil.getDataAccessViewPermissionHandler().getDefaultAcls( PentahoSessionHolder.getSession() ); } protected boolean isSecurityEnabled() { Boolean securityEnabled = ( getPermittedRoleList() != null && getPermittedRoleList().size() > 0 ) || ( ( getPermittedUserList() != null && getPermittedUserList().size() > 0 ) ); return securityEnabled; } protected void applySecurity( LogicalModel logicalModel ) { if ( isSecurityEnabled() ) { Security security = new Security(); for ( String user : getEffectivePermittedUserList( isSecurityEnabled() ) ) { SecurityOwner owner = new SecurityOwner( SecurityOwner.OwnerType.USER, user ); security.putOwnerRights( owner, getDefaultAcls() ); } for ( String role : getPermittedRoleList() ) { SecurityOwner owner = new SecurityOwner( SecurityOwner.OwnerType.ROLE, role ); security.putOwnerRights( owner, getDefaultAcls() ); } logicalModel.setProperty( Concept.SECURITY_PROPERTY, security ); } } // Add user to list if not already present private List<String> getEffectivePermittedUserList( boolean securityEnabled ) { ArrayList<String> permittedUserList = getPermittedUserList() == null ? new ArrayList<String>() : new ArrayList<String>( getPermittedUserList() ); if ( securityEnabled ) { if ( !permittedUserList.contains( PentahoSessionHolder.getSession().getName() ) ) { permittedUserList.add( PentahoSessionHolder.getSession().getName() ); } } return permittedUserList; } }