/*! ******************************************************************************
*
* Pentaho Data Integration
*
* Copyright (C) 2002-2017 by Pentaho : http://www.pentaho.com
*
*******************************************************************************
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
package org.pentaho.di.ui.repository.repositoryexplorer.controllers;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.pentaho.di.core.Const;
import org.pentaho.di.core.database.DatabaseMeta;
import org.pentaho.di.core.exception.KettleException;
import org.pentaho.di.i18n.BaseMessages;
import org.pentaho.di.repository.ObjectId;
import org.pentaho.di.repository.Repository;
import org.pentaho.di.repository.RepositoryElementMetaInterface;
import org.pentaho.di.repository.RepositoryObjectType;
import org.pentaho.di.ui.core.database.dialog.DatabaseDialog;
import org.pentaho.di.ui.core.dialog.ErrorDialog;
import org.pentaho.di.ui.repository.repositoryexplorer.ContextChangeVetoer;
import org.pentaho.di.ui.repository.repositoryexplorer.ContextChangeVetoer.TYPE;
import org.pentaho.di.ui.repository.repositoryexplorer.ContextChangeVetoerCollection;
import org.pentaho.di.ui.repository.repositoryexplorer.ControllerInitializationException;
import org.pentaho.di.ui.repository.repositoryexplorer.IUISupportController;
import org.pentaho.di.ui.repository.repositoryexplorer.RepositoryExplorer;
import org.pentaho.di.ui.repository.repositoryexplorer.model.UIDatabaseConnection;
import org.pentaho.di.ui.repository.repositoryexplorer.model.UIDatabaseConnections;
import org.pentaho.di.ui.repository.repositoryexplorer.model.UIObjectCreationException;
import org.pentaho.di.ui.repository.repositoryexplorer.model.UIObjectRegistry;
import org.pentaho.ui.xul.XulException;
import org.pentaho.ui.xul.binding.Binding;
import org.pentaho.ui.xul.binding.BindingFactory;
import org.pentaho.ui.xul.binding.DefaultBindingFactory;
import org.pentaho.ui.xul.components.XulButton;
import org.pentaho.ui.xul.containers.XulTree;
import org.pentaho.ui.xul.swt.tags.SwtDialog;
public class ConnectionsController extends LazilyInitializedController implements IUISupportController {
private static Class<?> PKG = RepositoryExplorer.class; // for i18n purposes, needed by Translator2!!
private XulTree connectionsTable = null;
protected BindingFactory bf = null;
private boolean isRepReadOnly = true;
private Binding bindButtonNew = null;
private Binding bindButtonEdit = null;
private Binding bindButtonRemove = null;
private Shell shell = null;
private UIDatabaseConnections dbConnectionList = new UIDatabaseConnections();
private DatabaseDialog databaseDialog;
private MainController mainController;
protected ContextChangeVetoerCollection contextChangeVetoers;
protected List<UIDatabaseConnection> selectedConnections;
protected List<UIDatabaseConnection> repositoryConnections;
public ConnectionsController() {
}
@Override
public String getName() {
return "connectionsController";
}
@Override
public void init( Repository repository ) throws ControllerInitializationException {
this.repository = repository;
}
// package-local visibility for testing purposes
DatabaseDialog getDatabaseDialog() {
if ( databaseDialog != null ) {
return databaseDialog;
}
databaseDialog = new DatabaseDialog( shell );
return databaseDialog;
}
private void createBindings() {
refreshConnectionList();
connectionsTable = (XulTree) document.getElementById( "connections-table" );
// Bind the connection table to a list of connections
bf.setBindingType( Binding.Type.ONE_WAY );
//CHECKSTYLE:LineLength:OFF
try {
bf.createBinding( dbConnectionList, "children", connectionsTable, "elements" ).fireSourceChanged();
( bindButtonNew = bf.createBinding( this, "repReadOnly", "connections-new", "disabled" ) ).fireSourceChanged();
( bindButtonEdit = bf.createBinding( this, "repReadOnly", "connections-edit", "disabled" ) ).fireSourceChanged();
( bindButtonRemove = bf.createBinding( this, "repReadOnly", "connections-remove", "disabled" ) ).fireSourceChanged();
if ( repository != null ) {
bf.createBinding( connectionsTable, "selectedItems", this, "selectedConnections" );
}
} catch ( Exception ex ) {
if ( mainController == null || !mainController.handleLostRepository( ex ) ) {
// convert to runtime exception so it bubbles up through the UI
throw new RuntimeException( ex );
}
}
}
@Override
protected boolean doLazyInit() {
try {
mainController = (MainController) this.getXulDomContainer().getEventHandler( "mainController" );
} catch ( XulException e ) {
return false;
}
try {
setRepReadOnly( this.repository.getRepositoryMeta().getRepositoryCapabilities().isReadOnly() );
// Load the SWT Shell from the explorer dialog
shell = ( (SwtDialog) document.getElementById( "repository-explorer-dialog" ) ).getShell();
bf = new DefaultBindingFactory();
bf.setDocument( this.getXulDomContainer().getDocumentRoot() );
if ( bf != null ) {
createBindings();
}
enableButtons( true, false, false );
return true;
} catch ( Exception e ) {
if ( mainController == null || !mainController.handleLostRepository( e ) ) {
return false;
}
}
return false;
}
public Repository getRepository() {
return repository;
}
public void setRepReadOnly( boolean isRepReadOnly ) {
try {
if ( this.isRepReadOnly != isRepReadOnly ) {
this.isRepReadOnly = isRepReadOnly;
if ( initialized ) {
bindButtonNew.fireSourceChanged();
bindButtonEdit.fireSourceChanged();
bindButtonRemove.fireSourceChanged();
}
}
} catch ( Exception e ) {
if ( mainController == null || !mainController.handleLostRepository( e ) ) {
// convert to runtime exception so it bubbles up through the UI
throw new RuntimeException( e );
}
}
}
public boolean isRepReadOnly() {
return isRepReadOnly;
}
// package-local visibility for testing purposes
void refreshConnectionList() {
final List<UIDatabaseConnection> tmpList = new ArrayList<UIDatabaseConnection>();
Runnable r = new Runnable() {
@Override
public void run() {
try {
ObjectId[] dbIdList = repository.getDatabaseIDs( false );
for ( ObjectId dbId : dbIdList ) {
DatabaseMeta dbMeta = repository.loadDatabaseMeta( dbId, null );
RepositoryElementMetaInterface repoMeta =
repository.getObjectInformation( dbId, RepositoryObjectType.DATABASE );
UIDatabaseConnection conn = null;
try {
conn = UIObjectRegistry.getInstance().constructUIDatabaseConnection( dbMeta, repository );
} catch ( UIObjectCreationException uoe ) {
conn = new UIDatabaseConnection( dbMeta, repository );
}
if ( conn != null ) {
conn.setRepositoryElementMetaInterface( repoMeta );
tmpList.add( conn );
}
}
} catch ( KettleException e ) {
if ( mainController == null || !mainController.handleLostRepository( e ) ) {
// convert to runtime exception so it bubbles up through the UI
throw new RuntimeException( e );
}
}
}
};
doWithBusyIndicator( r );
dbConnectionList.setChildren( tmpList );
}
public void createConnection() {
try {
DatabaseMeta databaseMeta = new DatabaseMeta();
databaseMeta.initializeVariablesFrom( null );
getDatabaseDialog().setDatabaseMeta( databaseMeta );
String dbName = getDatabaseDialog().open();
if ( dbName != null ) {
dbName = dbName.trim();
if ( !dbName.isEmpty() ) {
// See if this user connection exists...
ObjectId idDatabase = repository.getDatabaseID( dbName );
if ( idDatabase == null ) {
repository.insertLogEntry( BaseMessages.getString(
PKG, "ConnectionsController.Message.CreatingDatabase", getDatabaseDialog()
.getDatabaseMeta().getName() ) );
repository.save( getDatabaseDialog().getDatabaseMeta(), Const.VERSION_COMMENT_INITIAL_VERSION, null );
reloadLoadedJobsAndTransformations();
} else {
showAlreadyExistsMessage();
}
}
}
// We should be able to tell the difference between a cancel and an empty database name
//
// else {
// MessageBox mb = new MessageBox(shell, SWT.ICON_ERROR | SWT.OK);
// mb.setMessage(BaseMessages.getString(PKG, "RepositoryExplorerDialog.Connection.Edit.MissingName.Message"));
// mb.setText(BaseMessages.getString(PKG, "RepositoryExplorerDialog.Connection.Edit.MissingName.Title"));
// mb.open();
// }
} catch ( KettleException e ) {
if ( mainController == null || !mainController.handleLostRepository( e ) ) {
new ErrorDialog( shell,
BaseMessages.getString( PKG, "RepositoryExplorerDialog.Connection.Create.UnexpectedError.Title" ),
BaseMessages.getString( PKG, "RepositoryExplorerDialog.Connection.Create.UnexpectedError.Message" ), e );
}
} finally {
refreshConnectionList();
}
}
private boolean reloadLoadedJobsAndTransformations() {
if ( mainController != null && mainController.getSharedObjectSyncUtil() != null ) {
mainController.getSharedObjectSyncUtil().reloadJobRepositoryObjects( false );
mainController.getSharedObjectSyncUtil().reloadTransformationRepositoryObjects( false );
return true;
}
return false;
}
// package-local visibility for testing purposes
void showAlreadyExistsMessage() {
MessageBox mb = new MessageBox( shell, SWT.ICON_ERROR | SWT.OK );
mb.setMessage( BaseMessages.getString(
PKG, "RepositoryExplorerDialog.Connection.Create.AlreadyExists.Message" ) );
mb.setText( BaseMessages.getString(
PKG, "RepositoryExplorerDialog.Connection.Create.AlreadyExists.Title" ) );
mb.open();
}
/**
* Fire all current {@link ContextChangeVetoer}. Every one who has added their self as a vetoer has a change to vote
* on what should happen.
*/
List<TYPE> pollContextChangeVetoResults() {
if ( contextChangeVetoers != null ) {
return contextChangeVetoers.fireContextChange();
} else {
List<TYPE> returnValue = new ArrayList<TYPE>();
returnValue.add( TYPE.NO_OP );
return returnValue;
}
}
public void addContextChangeVetoer( ContextChangeVetoer listener ) {
if ( contextChangeVetoers == null ) {
contextChangeVetoers = new ContextChangeVetoerCollection();
}
contextChangeVetoers.add( listener );
}
public void removeContextChangeVetoer( ContextChangeVetoer listener ) {
if ( contextChangeVetoers != null ) {
contextChangeVetoers.remove( listener );
}
}
private boolean contains( TYPE type, List<TYPE> typeList ) {
for ( TYPE t : typeList ) {
if ( t.equals( type ) ) {
return true;
}
}
return false;
}
boolean compareConnections( List<UIDatabaseConnection> ro1, List<UIDatabaseConnection> ro2 ) {
if ( ro1 != null && ro2 != null ) {
if ( ro1.size() != ro2.size() ) {
return false;
}
for ( int i = 0; i < ro1.size(); i++ ) {
if ( ro1.get( i ) != null && ro2.get( i ) != null ) {
if ( !ro1.get( i ).getName().equals( ro2.get( i ).getName() ) ) {
return false;
}
}
}
} else {
return false;
}
return true;
}
public void editConnection() {
try {
Collection<UIDatabaseConnection> connections = connectionsTable.getSelectedItems();
if ( connections != null && !connections.isEmpty() ) {
// Grab the first item in the list & send it to the database dialog
DatabaseMeta databaseMeta = ( (UIDatabaseConnection) connections.toArray()[0] ).getDatabaseMeta();
// Make sure this connection already exists and store its id for updating
ObjectId idDatabase = repository.getDatabaseID( databaseMeta.getName() );
if ( idDatabase == null ) {
MessageBox mb = new MessageBox( shell, SWT.ICON_ERROR | SWT.OK );
mb.setMessage( BaseMessages.getString(
PKG, "RepositoryExplorerDialog.Connection.Edit.DoesNotExists.Message" ) );
mb.setText( BaseMessages.getString(
PKG, "RepositoryExplorerDialog.Connection.Edit.DoesNotExists.Title" ) );
mb.open();
} else {
getDatabaseDialog().setDatabaseMeta( databaseMeta );
String dbName = getDatabaseDialog().open();
if ( dbName != null ) {
dbName = dbName.trim();
if ( !dbName.isEmpty() ) {
ObjectId idRenamed = repository.getDatabaseID( dbName );
if ( idRenamed == null || idRenamed.equals( idDatabase ) ) {
// renaming to non-existing name or updating the current
repository.insertLogEntry( BaseMessages.getString(
PKG, "ConnectionsController.Message.UpdatingDatabase", databaseMeta.getName() ) );
repository.save( databaseMeta, Const.VERSION_COMMENT_EDIT_VERSION, null );
} else {
// trying to rename to an existing name - show error dialog
showAlreadyExistsMessage();
}
}
}
// We should be able to tell the difference between a cancel and an empty database name
//
// else {
// MessageBox mb = new MessageBox(shell, SWT.ICON_ERROR | SWT.OK);
// mb.setMessage(BaseMessages.getString(PKG, "RepositoryExplorerDialog.Connection.Edit.MissingName.Message"));
// mb.setText(BaseMessages.getString(PKG, "RepositoryExplorerDialog.Connection.Edit.MissingName.Title"));
// mb.open();
// }
}
} else {
MessageBox mb = new MessageBox( shell, SWT.ICON_ERROR | SWT.OK );
mb.setMessage( BaseMessages.getString(
PKG, "RepositoryExplorerDialog.Connection.Edit.NoItemSelected.Message" ) );
mb
.setText( BaseMessages
.getString( PKG, "RepositoryExplorerDialog.Connection.Edit.NoItemSelected.Title" ) );
mb.open();
}
} catch ( KettleException e ) {
if ( mainController == null || !mainController.handleLostRepository( e ) ) {
new ErrorDialog( shell,
BaseMessages.getString( PKG, "RepositoryExplorerDialog.Connection.Create.UnexpectedError.Title" ),
BaseMessages.getString( PKG, "RepositoryExplorerDialog.Connection.Edit.UnexpectedError.Message" ), e );
}
} finally {
refreshConnectionList();
}
}
public void removeConnection() {
try {
Collection<UIDatabaseConnection> connections = connectionsTable.getSelectedItems();
if ( connections != null && !connections.isEmpty() ) {
for ( Object obj : connections ) {
if ( obj != null && obj instanceof UIDatabaseConnection ) {
UIDatabaseConnection connection = (UIDatabaseConnection) obj;
DatabaseMeta databaseMeta = connection.getDatabaseMeta();
// Make sure this connection already exists and store its id for updating
ObjectId idDatabase = repository.getDatabaseID( databaseMeta.getName() );
if ( idDatabase == null ) {
MessageBox mb = new MessageBox( shell, SWT.ICON_ERROR | SWT.OK );
mb
.setMessage( BaseMessages.getString(
PKG, "RepositoryExplorerDialog.Connection.Delete.DoesNotExists.Message", databaseMeta
.getName() ) );
mb.setText( BaseMessages.getString( PKG, "RepositoryExplorerDialog.Connection.Delete.Title" ) );
mb.open();
} else {
repository.deleteDatabaseMeta( databaseMeta.getName() );
reloadLoadedJobsAndTransformations();
}
}
}
} else {
MessageBox mb = new MessageBox( shell, SWT.ICON_ERROR | SWT.OK );
mb.setMessage( BaseMessages.getString(
PKG, "RepositoryExplorerDialog.Connection.Edit.NoItemSelected.Message" ) );
mb.setText( BaseMessages.getString( PKG, "RepositoryExplorerDialog.Connection.Delete.Title" ) );
mb.open();
}
} catch ( KettleException e ) {
if ( mainController == null || !mainController.handleLostRepository( e ) ) {
new ErrorDialog( shell,
BaseMessages.getString( PKG, "RepositoryExplorerDialog.Connection.Create.UnexpectedError.Title" ),
BaseMessages.getString( PKG, "RepositoryExplorerDialog.Connection.Remove.UnexpectedError.Message" ), e );
}
} finally {
refreshConnectionList();
}
}
public void setSelectedConnections( List<UIDatabaseConnection> connections ) {
// SELECTION LOGIC
if ( !compareConnections( connections, this.selectedConnections ) ) {
List<TYPE> pollResults = pollContextChangeVetoResults();
if ( !contains( TYPE.CANCEL, pollResults ) ) {
this.selectedConnections = connections;
setRepositoryConnections( connections );
} else {
connectionsTable.setSelectedItems( this.selectedConnections );
return;
}
}
// ENABLE BUTTONS LOGIC
boolean enableEdit = false;
boolean enableRemove = false;
if ( connections != null && connections.size() > 0 ) {
enableRemove = true;
if ( connections.size() == 1 ) {
enableEdit = true;
}
}
// Convenience - Leave 'new' enabled, modify 'edit' and 'remove'
enableButtons( true, enableEdit, enableRemove );
}
public List<UIDatabaseConnection> getRepositoryConnections() {
return repositoryConnections;
}
public void setRepositoryConnections( List<UIDatabaseConnection> connections ) {
this.repositoryConnections = connections;
firePropertyChange( "repositoryConnections", null, connections );
}
public void enableButtons( boolean enableNew, boolean enableEdit, boolean enableRemove ) {
XulButton bNew = (XulButton) document.getElementById( "connections-new" );
XulButton bEdit = (XulButton) document.getElementById( "connections-edit" );
XulButton bRemove = (XulButton) document.getElementById( "connections-remove" );
bNew.setDisabled( !enableNew );
bEdit.setDisabled( !enableEdit );
bRemove.setDisabled( !enableRemove );
}
public void tabClicked() {
lazyInit();
}
}