/* * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License, version 2 as published by the Free Software * Foundation. * * You should have received a copy of the GNU General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/gpl-2.0.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 General Public License for more details. * * * Copyright 2006 - 2016 Pentaho Corporation. All rights reserved. */ package org.pentaho.platform.repository; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import org.pentaho.database.model.IDatabaseConnection; import org.pentaho.database.service.IDatabaseDialectService; import org.pentaho.di.repository.RepositoryObjectType; import org.pentaho.platform.api.engine.IPentahoSession; import org.pentaho.platform.api.repository.datasource.DatasourceMgmtServiceException; import org.pentaho.platform.api.repository.datasource.DuplicateDatasourceException; import org.pentaho.platform.api.repository.datasource.IDatasourceMgmtService; import org.pentaho.platform.api.repository.datasource.NonExistingDatasourceException; import org.pentaho.platform.api.repository2.unified.IUnifiedRepository; import org.pentaho.platform.api.repository2.unified.RepositoryFile; import org.pentaho.platform.api.repository2.unified.UnifiedRepositoryException; import org.pentaho.platform.api.repository2.unified.data.node.NodeRepositoryFileData; import org.pentaho.platform.engine.core.system.PentahoSystem; import org.pentaho.platform.repository.messages.Messages; import org.pentaho.platform.repository2.ClientRepositoryPaths; public class JcrBackedDatasourceMgmtService implements IDatasourceMgmtService { private IUnifiedRepository repository; private volatile List<Character> cachedReservedChars; // make sure threads see up-to-date value private Serializable cachedDatabaseParentFolderId; private static final String FOLDER_PDI = "pdi"; //$NON-NLS-1$ private static final String FOLDER_DATABASES = "databases"; //$NON-NLS-1$ private DatabaseHelper databaseHelper; public JcrBackedDatasourceMgmtService() { } public JcrBackedDatasourceMgmtService( IUnifiedRepository repository, IDatabaseDialectService databaseDialectService ) { super(); this.repository = repository; cachedReservedChars = repository.getReservedChars(); databaseHelper = new DatabaseHelper( databaseDialectService ); } public void init( IPentahoSession session ) { repository = PentahoSystem.get( IUnifiedRepository.class, session ); cachedReservedChars = repository.getReservedChars(); } public String createDatasource( IDatabaseConnection databaseConnection ) throws DuplicateDatasourceException, DatasourceMgmtServiceException { try { // IPasswordService passwordService = PentahoSystem.get(IPasswordService.class, // PentahoSessionHolder.getSession()); // databaseMeta.setPassword(passwordService.encrypt(databaseMeta.getPassword())); RepositoryFile file = new RepositoryFile.Builder( RepositoryFilenameUtils.escape( databaseConnection.getName() + RepositoryObjectType.DATABASE.getExtension(), cachedReservedChars ) ).title( RepositoryFile.DEFAULT_LOCALE, databaseConnection.getName() ).versioned( true ).build(); file = repository.createFile( getDatabaseParentFolderId(), file, new NodeRepositoryFileData( databaseHelper .databaseConnectionToDataNode( databaseConnection ) ), null ); if ( file != null && file.getId() != null ) { return file.getId().toString(); } else { return null; } // } catch(PasswordServiceException pse) { // throw new DatasourceMgmtServiceException(Messages.getInstance().getErrorString( // "DatasourceMgmtService.ERROR_0007_UNABLE_TO_ENCRYPT_PASSWORD"), pse ); //$NON-NLS-1$ } catch ( UnifiedRepositoryException ure ) { if ( ure.getCause().toString().contains( "ItemExistsException" ) ) { throw new DuplicateDatasourceException(); } throw new DatasourceMgmtServiceException( Messages .getInstance() .getErrorString( "DatasourceMgmtService.ERROR_0001_UNABLE_TO_CREATE_DATASOURCE", databaseConnection.getName(), ure.getLocalizedMessage() ), ure ); //$NON-NLS-1$ } } public void deleteDatasourceByName( String name ) throws NonExistingDatasourceException, DatasourceMgmtServiceException { RepositoryFile fileToDelete = null; try { fileToDelete = repository.getFile( getPath( name ) ); } catch ( UnifiedRepositoryException ure ) { throw new DatasourceMgmtServiceException( Messages .getInstance() .getErrorString( "DatasourceMgmtService.ERROR_0002_UNABLE_TO_DELETE_DATASOURCE", fileToDelete.getName(), ure.getLocalizedMessage() ), ure ); //$NON-NLS-1$ } deleteDatasource( fileToDelete ); } public void deleteDatasourceById( String id ) throws NonExistingDatasourceException, DatasourceMgmtServiceException { RepositoryFile fileToDelete = null; try { fileToDelete = repository.getFileById( id ); } catch ( UnifiedRepositoryException ure ) { throw new DatasourceMgmtServiceException( Messages .getInstance() .getErrorString( "DatasourceMgmtService.ERROR_0002_UNABLE_TO_DELETE_DATASOURCE", fileToDelete.getName(), ure.getLocalizedMessage() ), ure ); //$NON-NLS-1$ } deleteDatasource( fileToDelete ); } private void deleteDatasource( RepositoryFile file ) throws DatasourceMgmtServiceException { try { if ( file != null ) { // Permanently Deletes the File repository.deleteFile( file.getId(), true, null ); } else { throw new DatasourceMgmtServiceException( Messages.getInstance().getErrorString( "DatasourceMgmtService.ERROR_0002_UNABLE_TO_DELETE_DATASOURCE", "", "" ) ); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } } catch ( UnifiedRepositoryException ure ) { throw new DatasourceMgmtServiceException( Messages .getInstance() .getErrorString( "DatasourceMgmtService.ERROR_0002_UNABLE_TO_DELETE_DATASOURCE", file.getName(), ure.getLocalizedMessage() ), ure ); //$NON-NLS-1$ } } public IDatabaseConnection getDatasourceByName( String name ) throws DatasourceMgmtServiceException { RepositoryFile file = null; try { file = repository.getFile( getPath( name ) ); } catch ( UnifiedRepositoryException ure ) { throw new DatasourceMgmtServiceException( Messages.getInstance().getErrorString( "DatasourceMgmtService.ERROR_0004_UNABLE_TO_RETRIEVE_DATASOURCE", name, ure.getLocalizedMessage() ), ure ); //$NON-NLS-1$ } if ( file != null ) { return getDatasource( file ); } return null; } public IDatabaseConnection getDatasourceById( String id ) throws DatasourceMgmtServiceException { RepositoryFile file = null; try { file = repository.getFileById( id ); } catch ( UnifiedRepositoryException ure ) { throw new DatasourceMgmtServiceException( Messages.getInstance().getErrorString( "DatasourceMgmtService.ERROR_0004_UNABLE_TO_RETRIEVE_DATASOURCE", file.getName() ), ure ); //$NON-NLS-1$ } if ( file != null ) { return getDatasource( file ); } return null; } private IDatabaseConnection getDatasource( RepositoryFile file ) throws DatasourceMgmtServiceException { try { if ( file != null ) { NodeRepositoryFileData data = repository.getDataForRead( file.getId(), NodeRepositoryFileData.class ); IDatabaseConnection databaseConnection = databaseHelper.dataNodeToDatabaseConnection( file.getId(), file.getTitle(), data.getNode() ); // IPasswordService passwordService = PentahoSystem.get(IPasswordService.class, // PentahoSessionHolder.getSession()); // databaseMeta.setPassword(passwordService.decrypt(databaseMeta.getPassword())); return databaseConnection; } else { throw new DatasourceMgmtServiceException( Messages.getInstance().getErrorString( "DatasourceMgmtService.ERROR_0004_UNABLE_TO_RETRIEVE_DATASOURCE", "", "" ) ); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } // } catch(PasswordServiceException pse) { // throw new DatasourceMgmtServiceException(Messages.getInstance() // .getErrorString("DatasourceMgmtService.ERROR_0008_UNABLE_TO_DECRYPT_PASSWORD"), pse ); //$NON-NLS-1$ } catch ( UnifiedRepositoryException ure ) { throw new DatasourceMgmtServiceException( Messages .getInstance() .getErrorString( "DatasourceMgmtService.ERROR_0004_UNABLE_TO_RETRIEVE_DATASOURCE", file.getName(), ure.getLocalizedMessage() ), ure ); //$NON-NLS-1$ } } public List<IDatabaseConnection> getDatasources() throws DatasourceMgmtServiceException { try { List<IDatabaseConnection> datasourceList = new ArrayList<IDatabaseConnection>(); List<RepositoryFile> repositoryFiles = getRepositoryFiles(); if ( repositoryFiles != null ) { for ( RepositoryFile file : repositoryFiles ) { NodeRepositoryFileData data = repository.getDataForRead( file.getId(), NodeRepositoryFileData.class ); IDatabaseConnection databaseConnection = databaseHelper.dataNodeToDatabaseConnection( file.getId(), file.getTitle(), data.getNode() ); // IPasswordService passwordService = PentahoSystem.get(IPasswordService.class, // PentahoSessionHolder.getSession()); // databaseMeta.setPassword(passwordService.decrypt(databaseMeta.getPassword())); datasourceList.add( databaseConnection ); } } return datasourceList; // } catch(PasswordServiceException pse) { // throw new DatasourceMgmtServiceException(Messages.getInstance() // .getErrorString("DatasourceMgmtService.ERROR_0008_UNABLE_TO_DECRYPT_PASSWORD"), pse ); //$NON-NLS-1$ } catch ( UnifiedRepositoryException ure ) { throw new DatasourceMgmtServiceException( Messages.getInstance().getErrorString( "DatasourceMgmtService.ERROR_0004_UNABLE_TO_RETRIEVE_DATASOURCE", "", ure.getLocalizedMessage() ), ure ); //$NON-NLS-1$ //$NON-NLS-2$ } } public List<String> getDatasourceIds() throws DatasourceMgmtServiceException { try { List<String> datasourceList = new ArrayList<String>(); List<RepositoryFile> repositoryFiles = getRepositoryFiles(); if ( repositoryFiles != null ) { for ( RepositoryFile file : repositoryFiles ) { datasourceList.add( file.getId().toString() ); } } return datasourceList; } catch ( UnifiedRepositoryException ure ) { throw new DatasourceMgmtServiceException( Messages.getInstance().getErrorString( "DatasourceMgmtService.ERROR_0004_UNABLE_TO_RETRIEVE_DATASOURCE", "", ure.getLocalizedMessage() ), ure ); //$NON-NLS-1$ //$NON-NLS-2$ } } public String updateDatasourceById( String id, IDatabaseConnection databaseConnection ) throws NonExistingDatasourceException, DatasourceMgmtServiceException { RepositoryFile file = null; try { file = repository.getFileById( id ); } catch ( UnifiedRepositoryException ure ) { throw new DatasourceMgmtServiceException( Messages .getInstance() .getErrorString( "DatasourceMgmtService.ERROR_0003_UNABLE_TO_UPDATE_DATASOURCE", databaseConnection.getName(), ure.getLocalizedMessage() ), ure ); //$NON-NLS-1$ } return updateDatasource( file, databaseConnection ); } public String updateDatasourceByName( String name, IDatabaseConnection databaseConnection ) throws NonExistingDatasourceException, DatasourceMgmtServiceException { RepositoryFile file = null; try { if ( databaseConnection.getId() != null ) { file = repository.getFileById( databaseConnection.getId() ); } else { file = repository.getFile( getPath( name ) ); } } catch ( UnifiedRepositoryException ure ) { throw new DatasourceMgmtServiceException( Messages .getInstance() .getErrorString( "DatasourceMgmtService.ERROR_0003_UNABLE_TO_UPDATE_DATASOURCE", databaseConnection.getName(), ure.getLocalizedMessage() ), ure ); //$NON-NLS-1$ } return updateDatasource( file, databaseConnection ); } private String updateDatasource( RepositoryFile file, IDatabaseConnection databaseConnection ) throws NonExistingDatasourceException, DatasourceMgmtServiceException { try { // IPasswordService passwordService = PentahoSystem.get(IPasswordService.class, // PentahoSessionHolder.getSession()); // Store the new encrypted password in the datasource object // databaseMeta.setPassword(passwordService.encrypt(databaseMeta.getPassword())); if ( file != null ) { file = new RepositoryFile.Builder( file ).versionId( file.getVersionId() ).id( file.getId() ).title( RepositoryFile.DEFAULT_LOCALE, databaseConnection.getName() ).build(); file = repository.updateFile( file, new NodeRepositoryFileData( databaseHelper .databaseConnectionToDataNode( databaseConnection ) ), null ); renameIfNecessary( databaseConnection, file ); return file.getId().toString(); } else { throw new NonExistingDatasourceException( Messages.getInstance().getErrorString( "DatasourceMgmtService.ERROR_0006_DATASOURCE_DOES_NOT_EXIST", databaseConnection.getName() ) ); //$NON-NLS-1$ } // } catch(PasswordServiceException pse) { // throw new DatasourceMgmtServiceException(Messages.getInstance() // .getErrorString("DatasourceMgmtService.ERROR_0007_UNABLE_TO_ENCRYPT_PASSWORD"), pse ); //$NON-NLS-1$ } catch ( UnifiedRepositoryException ure ) { throw new DatasourceMgmtServiceException( Messages .getInstance() .getErrorString( "DatasourceMgmtService.ERROR_0003_UNABLE_TO_UPDATE_DATASOURCE", databaseConnection.getName(), ure.getLocalizedMessage() ), ure ); //$NON-NLS-1$ } } private String getDatabaseParentFolderPath() { return ClientRepositoryPaths.getEtcFolderPath() + RepositoryFile.SEPARATOR + FOLDER_PDI + RepositoryFile.SEPARATOR + FOLDER_DATABASES; } private Serializable getDatabaseParentFolderId() { if ( cachedDatabaseParentFolderId == null ) { try { RepositoryFile f = repository.getFile( getDatabaseParentFolderPath() ); cachedDatabaseParentFolderId = f.getId(); } catch ( UnifiedRepositoryException ure ) { return cachedDatabaseParentFolderId; } } return cachedDatabaseParentFolderId; } private List<RepositoryFile> getRepositoryFiles() { Serializable folderId = getDatabaseParentFolderId(); if ( folderId != null ) { return repository.getChildren( folderId, "*" + RepositoryObjectType.DATABASE.getExtension() ); } else { return null; } } private String getPath( final String name ) { String escapedName = RepositoryFilenameUtils.escape( name, cachedReservedChars ); return getDatabaseParentFolderPath() + RepositoryFile.SEPARATOR + escapedName + RepositoryObjectType.DATABASE.getExtension(); } private void renameIfNecessary( final IDatabaseConnection databaseConnection, final RepositoryFile file ) { if ( !isRenamed( databaseConnection, file ) ) { return; } StringBuilder buf = new StringBuilder( file.getPath().length() ); buf.append( getParentPath( file.getPath() ) ); buf.append( RepositoryFile.SEPARATOR ); buf.append( RepositoryFilenameUtils.escape( databaseConnection.getName(), cachedReservedChars ) ); buf.append( RepositoryObjectType.DATABASE.getExtension() ); repository.moveFile( file.getId(), buf.toString(), null ); } private boolean isRenamed( final IDatabaseConnection databaseConnection, final RepositoryFile file ) { String filename = databaseConnection.getName() + RepositoryObjectType.DATABASE.getExtension(); if ( !file.getName().equals( RepositoryFilenameUtils.escape( filename, cachedReservedChars ) ) ) { return true; } return false; } protected String getParentPath( final String path ) { if ( path == null ) { throw new IllegalArgumentException(); } else if ( RepositoryFile.SEPARATOR.equals( path ) ) { return null; } int lastSlashIndex = path.lastIndexOf( RepositoryFile.SEPARATOR ); if ( lastSlashIndex == 0 ) { return RepositoryFile.SEPARATOR; } else if ( lastSlashIndex > 0 ) { return path.substring( 0, lastSlashIndex ); } else { throw new IllegalArgumentException(); } } }