/*! * Copyright 2010 - 2016 Pentaho Corporation. All rights reserved. * * 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; import java.util.Enumeration; import java.util.ResourceBundle; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.MessageBox; import org.pentaho.di.core.exception.KettleException; import org.pentaho.di.i18n.BaseMessages; import org.pentaho.di.repository.Repository; import org.pentaho.di.repository.pur.PurRepository; import org.pentaho.di.ui.repository.pur.PurRepositoryDialog; import org.pentaho.di.ui.repository.pur.controller.SpoonLockController; import org.pentaho.di.ui.repository.pur.controller.SpoonMenuLockController; import org.pentaho.di.ui.repository.pur.repositoryexplorer.UIEEObjectRegistery; import org.pentaho.di.ui.repository.pur.repositoryexplorer.abs.AbsSecurityManagerUISupport; import org.pentaho.di.ui.repository.pur.repositoryexplorer.abs.AbsSecurityProviderUISupport; import org.pentaho.di.ui.repository.pur.repositoryexplorer.abs.controller.SpoonMenuABSController; import org.pentaho.di.ui.repository.pur.repositoryexplorer.abs.model.UIAbsRepositoryRole; import org.pentaho.di.ui.repository.pur.repositoryexplorer.model.UIEEDatabaseConnection; import org.pentaho.di.ui.repository.pur.repositoryexplorer.model.UIEEJob; import org.pentaho.di.ui.repository.pur.repositoryexplorer.model.UIEERepositoryDirectory; import org.pentaho.di.ui.repository.pur.repositoryexplorer.model.UIEERepositoryUser; import org.pentaho.di.ui.repository.pur.repositoryexplorer.model.UIEETransformation; import org.pentaho.di.ui.repository.pur.repositoryexplorer.uisupport.AclUISupport; import org.pentaho.di.ui.repository.pur.repositoryexplorer.uisupport.ConnectionAclUISupport; import org.pentaho.di.ui.repository.pur.repositoryexplorer.uisupport.ManageRolesUISupport; import org.pentaho.di.ui.repository.pur.repositoryexplorer.uisupport.RepositoryLockUISupport; import org.pentaho.di.ui.repository.pur.repositoryexplorer.uisupport.RevisionsUISupport; import org.pentaho.di.ui.repository.pur.repositoryexplorer.uisupport.TrashUISupport; import org.pentaho.di.ui.repository.pur.services.IAbsSecurityManager; import org.pentaho.di.ui.repository.pur.services.IAbsSecurityProvider; import org.pentaho.di.ui.repository.pur.services.IAclService; import org.pentaho.di.ui.repository.pur.services.IConnectionAclService; import org.pentaho.di.ui.repository.pur.services.ILockService; import org.pentaho.di.ui.repository.pur.services.IRevisionService; import org.pentaho.di.ui.repository.pur.services.IRoleSupportSecurityManager; import org.pentaho.di.ui.repository.pur.services.ITrashService; import org.pentaho.di.ui.repository.repositoryexplorer.UISupportRegistery; import org.pentaho.di.ui.repository.repositoryexplorer.model.UIObjectRegistry; import org.pentaho.di.ui.spoon.ChangedWarningDialog; import org.pentaho.di.ui.spoon.Spoon; import org.pentaho.di.ui.spoon.SpoonLifecycleListener; import org.pentaho.di.ui.spoon.SpoonPerspective; import org.pentaho.di.ui.spoon.SpoonPerspectiveManager; import org.pentaho.di.ui.spoon.SpoonPlugin; import org.pentaho.di.ui.spoon.SpoonPluginCategories; import org.pentaho.di.ui.spoon.SpoonPluginInterface; import org.pentaho.di.ui.spoon.delegates.SpoonDelegateRegistry; import org.pentaho.di.ui.spoon.delegates.SpoonEEJobDelegate; import org.pentaho.di.ui.spoon.delegates.SpoonEETransformationDelegate; import org.pentaho.ui.xul.XulDomContainer; import org.pentaho.ui.xul.XulException; import org.pentaho.ui.xul.components.XulMenuitem; import org.pentaho.ui.xul.components.XulMessageBox; import org.pentaho.ui.xul.components.XulToolbarbutton; import org.pentaho.ui.xul.containers.XulMenu; import org.pentaho.ui.xul.dom.Document; @SpoonPlugin( id = "EESpoonPlugin", image = "" ) @SpoonPluginCategories( { "spoon", "trans-graph", "job-graph", "repository-explorer" } ) public class EESpoonPlugin implements SpoonPluginInterface, SpoonLifecycleListener, java.io.Serializable { private static final long serialVersionUID = -5672306503357631444L; /* EESOURCE: UPDATE SERIALVERUID */ protected static Class<?> PKG = EESpoonPlugin.class; protected XulDomContainer spoonXulContainer = null; protected ResourceBundle messages = new ResourceBundle() { @Override public Enumeration<String> getKeys() { return null; } @Override protected Object handleGetObject( String key ) { return BaseMessages.getString( PKG, key ); } }; public EESpoonPlugin() { } public SpoonLifecycleListener getLifecycleListener() { return this; } public SpoonPerspective getPerspective() { return null; } public void onEvent( SpoonLifeCycleEvent evt ) { try { switch ( evt ) { case MENUS_REFRESHED: break; case REPOSITORY_CHANGED: doOnSecurityUpdate(); break; case REPOSITORY_CONNECTED: final Spoon spoon = Spoon.getInstance(); if ( spoon != null ) { // Check permissions to see so we can decide how to close tabs that should not be open // For example if user connects and does not have create content perms, then we should force // closing of the tabs. spoon.getShell().getDisplay().asyncExec( new Runnable() { public void run() { try { warnClosingOfOpenTabsBasedOnPerms( spoon ); } catch ( KettleException ex ) { // Ok we are just checking perms } } } ); } doOnSecurityUpdate(); break; case REPOSITORY_DISCONNECTED: doOnSecurityCleanup(); break; case STARTUP: doOnStartup(); break; case SHUTDOWN: doOnShutdown(); break; default: break; } } catch ( KettleException e ) { try { getMainSpoonContainer(); XulMessageBox messageBox = (XulMessageBox) spoonXulContainer.getDocumentRoot().createElement( "messagebox" ); //$NON-NLS-1$ messageBox.setTitle( BaseMessages.getString( PKG, "Dialog.Success" ) ); //$NON-NLS-1$ messageBox.setAcceptLabel( BaseMessages.getString( PKG, "Dialog.Ok" ) ); //$NON-NLS-1$ messageBox .setMessage( BaseMessages.getString( PKG, "AbsController.RoleActionPermission.Success" ) ); //$NON-NLS-1$ messageBox.open(); } catch ( Exception ex ) { e.printStackTrace(); } } } private void doOnStartup() { registerUISuppportForRepositoryExplorer(); } private void doOnShutdown() { } /** * Override UI elements to reflect the users capabilities as described by their permission levels */ private void doOnSecurityUpdate() throws KettleException { getMainSpoonContainer(); Repository repository = Spoon.getInstance().getRepository(); // Repository User if ( repository != null && repository.hasService( IRoleSupportSecurityManager.class ) ) { UIObjectRegistry.getInstance().registerUIRepositoryUserClass( UIEERepositoryUser.class ); } else { UIObjectRegistry.getInstance().registerUIRepositoryUserClass( UIObjectRegistry.DEFAULT_UIREPOSITORYUSER_CLASS ); } // Repository Directory if ( repository != null && repository.hasService( IAclService.class ) ) { UIObjectRegistry.getInstance().registerUIRepositoryDirectoryClass( UIEERepositoryDirectory.class ); UIObjectRegistry.getInstance().registerUIDatabaseConnectionClass( UIEEDatabaseConnection.class ); } else { UIObjectRegistry.getInstance().registerUIRepositoryDirectoryClass( UIObjectRegistry.DEFAULT_UIDIR_CLASS ); } // Repository Role if ( repository != null && repository.hasService( IAbsSecurityProvider.class ) ) { UIEEObjectRegistery.getInstance().registerUIRepositoryRoleClass( UIAbsRepositoryRole.class ); IAbsSecurityProvider securityProvider = (IAbsSecurityProvider) repository.getService( IAbsSecurityProvider.class ); enablePermission( securityProvider ); } // Job & Transformation = if ( repository.hasService( ILockService.class ) ) { UIObjectRegistry.getInstance().registerUIJobClass( UIEEJob.class ); UIObjectRegistry.getInstance().registerUITransformationClass( UIEETransformation.class ); SpoonDelegateRegistry.getInstance().registerSpoonJobDelegateClass( SpoonEEJobDelegate.class ); SpoonDelegateRegistry.getInstance().registerSpoonTransDelegateClass( SpoonEETransformationDelegate.class ); } else { UIObjectRegistry.getInstance().registerUIJobClass( UIObjectRegistry.DEFAULT_UIJOB_CLASS ); UIObjectRegistry.getInstance().registerUITransformationClass( UIObjectRegistry.DEFAULT_UITRANS_CLASS ); SpoonDelegateRegistry.getInstance().registerSpoonJobDelegateClass( SpoonDelegateRegistry.DEFAULT_SPOONJOBDELEGATE_CLASS ); SpoonDelegateRegistry.getInstance().registerSpoonTransDelegateClass( SpoonDelegateRegistry.DEFAULT_SPOONTRANSDELEGATE_CLASS ); } } /** * Called when repository is disconnected. */ private void doOnSecurityCleanup() { updateSchedulePerspective( false ); updateMenuState( true, true ); } private void enablePermission( IAbsSecurityProvider securityProvider ) throws KettleException { boolean createPermitted = securityProvider.isAllowed( IAbsSecurityProvider.CREATE_CONTENT_ACTION ); boolean executePermitted = securityProvider.isAllowed( IAbsSecurityProvider.EXECUTE_CONTENT_ACTION ); boolean adminPermitted = securityProvider.isAllowed( IAbsSecurityProvider.ADMINISTER_SECURITY_ACTION ); boolean schedulePermitted = securityProvider.isAllowed( IAbsSecurityProvider.SCHEDULE_CONTENT_ACTION ); enablePermission( createPermitted, executePermitted, adminPermitted, schedulePermitted ); } private void enablePermission( boolean createPermitted, boolean executePermitted, boolean adminPermitted, boolean schedulePermitted ) { updateMenuState( createPermitted, executePermitted ); updateSchedulePerspective( schedulePermitted ); updateChangedWarningDialog( createPermitted ); } private void registerUISuppportForRepositoryExplorer() { UISupportRegistery.getInstance().registerUISupport( IRevisionService.class, RevisionsUISupport.class ); UISupportRegistery.getInstance().registerUISupport( IAclService.class, AclUISupport.class ); UISupportRegistery.getInstance().registerUISupport( IConnectionAclService.class, ConnectionAclUISupport.class ); UISupportRegistery.getInstance().registerUISupport( IRoleSupportSecurityManager.class, ManageRolesUISupport.class ); UISupportRegistery.getInstance().registerUISupport( IAbsSecurityManager.class, AbsSecurityManagerUISupport.class ); UISupportRegistery.getInstance().registerUISupport( IAbsSecurityProvider.class, AbsSecurityProviderUISupport.class ); UISupportRegistery.getInstance().registerUISupport( ITrashService.class, TrashUISupport.class ); UISupportRegistery.getInstance().registerUISupport( ILockService.class, RepositoryLockUISupport.class ); } public void applyToContainer( String category, XulDomContainer container ) throws XulException { container.registerClassLoader( getClass().getClassLoader() ); if ( category.equals( "spoon" ) ) { //$NON-NLS-1$ // register the two controllers, note that the lock controller must come // after the abs controller so the biz logic between the two hold. // Register the ABS Menu controller Spoon.getInstance().addSpoonMenuController( new SpoonMenuABSController() ); // Register the SpoonMenuLockController to modify the main Spoon Menu structure Spoon.getInstance().addSpoonMenuController( new SpoonMenuLockController() ); } else if ( category.equals( "trans-graph" ) || category.equals( "job-graph" ) ) { //$NON-NLS-1$ //$NON-NLS-2$ if ( ( Spoon.getInstance() != null ) && ( Spoon.getInstance().getRepository() != null ) && ( Spoon.getInstance().getRepository() instanceof PurRepository ) ) { container.getDocumentRoot().addOverlay( "org/pentaho/di/ui/repository/pur/xul/spoon-lock-overlay.xul" ); //$NON-NLS-1$ container.addEventHandler( new SpoonLockController() ); } try { Repository repository = Spoon.getInstance().getRepository(); if ( repository != null ) { IAbsSecurityProvider securityProvider = (IAbsSecurityProvider) repository.getService( IAbsSecurityProvider.class ); if ( securityProvider != null ) { enablePermission( securityProvider ); } } } catch ( KettleException e ) { e.printStackTrace(); } } else if ( category.equals( "repository-explorer" ) ) { //$NON-NLS-1$ try { Repository repository = Spoon.getInstance().getRepository(); IAbsSecurityProvider securityProvider = null; if ( repository != null ) { securityProvider = (IAbsSecurityProvider) repository.getService( IAbsSecurityProvider.class ); } if ( securityProvider != null ) { boolean createPermitted = securityProvider.isAllowed( IAbsSecurityProvider.CREATE_CONTENT_ACTION ); boolean executePermitted = securityProvider.isAllowed( IAbsSecurityProvider.EXECUTE_CONTENT_ACTION ); // Disable export if user can not create or execute content (prevents execution outside of this repo) container.getDocumentRoot().getElementById( "folder-context-export" ).setDisabled( !createPermitted || !executePermitted ); } } catch ( KettleException e ) { e.printStackTrace(); } } } /** * Change the menu-item states based on Execute and Create permissions. * @param createPermitted * - if true, we enable menu-items requiring creation permissions * @param executePermitted * - if true, we enable menu-items requiring execute permissions */ void updateMenuState( boolean createPermitted, boolean executePermitted ) { Document doc = getDocumentRoot(); if ( doc != null ) { // Main spoon menu ( (XulMenuitem) doc.getElementById( "process-run" ) ).setDisabled( !executePermitted ); //$NON-NLS-1$ XulToolbarbutton transRunButton = ( (XulToolbarbutton) doc.getElementById( "trans-run" ) ); //$NON-NLS-1$ if ( transRunButton != null ) { transRunButton.setDisabled( !executePermitted ); } ( (XulMenuitem) doc.getElementById( "trans-preview" ) ).setDisabled( !executePermitted ); //$NON-NLS-1$ ( (XulMenuitem) doc.getElementById( "trans-debug" ) ).setDisabled( !executePermitted ); //$NON-NLS-1$ ( (XulMenuitem) doc.getElementById( "trans-replay" ) ).setDisabled( !executePermitted ); //$NON-NLS-1$ ( (XulMenuitem) doc.getElementById( "trans-verify" ) ).setDisabled( !executePermitted ); //$NON-NLS-1$ ( (XulMenuitem) doc.getElementById( "trans-impact" ) ).setDisabled( !executePermitted ); //$NON-NLS-1$ ( (XulMenuitem) doc.getElementById( "trans-get-sql" ) ).setDisabled( !executePermitted ); //$NON-NLS-1$ // Disable Show Last menu under the Action menu. ( (XulMenu) doc.getElementById( "trans-last" ) ).setDisabled( !executePermitted ); //$NON-NLS-1$ // Schedule is a plugin if ( doc.getElementById( "trans-schedule" ) != null ) { ( (XulMenuitem) doc.getElementById( "trans-schedule" ) ).setDisabled( !executePermitted ); //$NON-NLS-1$ } // Main spoon toolbar ( (XulToolbarbutton) doc.getElementById( "toolbar-file-new" ) ).setDisabled( !createPermitted ); //$NON-NLS-1$ ( (XulToolbarbutton) doc.getElementById( "toolbar-file-save" ) ).setDisabled( !createPermitted ); //$NON-NLS-1$ ( (XulToolbarbutton) doc.getElementById( "toolbar-file-save-as" ) ).setDisabled( !createPermitted ); //$NON-NLS-1$ // Popup menus ( (XulMenuitem) doc.getElementById( "trans-class-new" ) ).setDisabled( !createPermitted ); //$NON-NLS-1$ ( (XulMenuitem) doc.getElementById( "job-class-new" ) ).setDisabled( !createPermitted ); //$NON-NLS-1$ // Main spoon menu ( (XulMenu) doc.getElementById( "file-new" ) ).setDisabled( !createPermitted ); //$NON-NLS-1$ ( (XulMenuitem) doc.getElementById( "file-save" ) ).setDisabled( !createPermitted ); //$NON-NLS-1$ ( (XulMenuitem) doc.getElementById( "file-save-as" ) ).setDisabled( !createPermitted ); //$NON-NLS-1$ ( (XulMenuitem) doc.getElementById( "file-close" ) ).setDisabled( !createPermitted ); //$NON-NLS-1$ boolean exportAllowed = createPermitted && executePermitted; ( (XulMenu) doc.getElementById( "file-export" ) ).setDisabled( !exportAllowed ); //$NON-NLS-1$ ( (XulMenuitem) doc.getElementById( "repository-export-all" ) ).setDisabled( !exportAllowed ); //$NON-NLS-1$ ( (XulMenuitem) doc.getElementById( "file-save-as-vfs" ) ).setDisabled( !exportAllowed ); //$NON-NLS-1$ ( (XulMenuitem) doc.getElementById( "edit-cut-steps" ) ).setDisabled( !exportAllowed ); //$NON-NLS-1$ ( (XulMenuitem) doc.getElementById( "edit-copy-steps" ) ).setDisabled( !exportAllowed ); //$NON-NLS-1$ ( (XulMenuitem) doc.getElementById( "edit.copy-file" ) ).setDisabled( !exportAllowed ); //$NON-NLS-1$ ( (XulMenuitem) doc.getElementById( "edit-paste-steps" ) ).setDisabled( !exportAllowed ); //$NON-NLS-1$ XulMenuitem transCopyContextMenu = ( (XulMenuitem) doc.getElementById( "trans-graph-entry-copy" ) ); //$NON-NLS-1$ if ( transCopyContextMenu != null ) { transCopyContextMenu.setDisabled( !exportAllowed ); } } } void updateSchedulePerspective( boolean schedulePermitted ) { final String schedulePerspectiveId = "schedulerPerspective"; final SpoonPerspectiveManager perspectiveManager = getPerspectiveManager(); if ( schedulePermitted ) { perspectiveManager.showPerspective( schedulePerspectiveId ); } else { perspectiveManager.hidePerspective( schedulePerspectiveId ); } } public static void updateChangedWarningDialog( boolean overrideDefaultDialogBehavior ) { if ( !overrideDefaultDialogBehavior ) { // Update the ChangedWarningDialog - Disable the yes button ChangedWarningDialog.setInstance( new ChangedWarningDialog() { public int show() { return show( null ); } public int show( String fileName ) { XulMessageBox msgBox = null; try { msgBox = runXulChangedWarningDialog( fileName ); if ( fileName != null ) { msgBox.setMessage( BaseMessages.getString( PKG, "Spoon.Dialog.PromptToSave.Fail.Message.WithParam", fileName ) ); //$NON-NLS-1$ } else { msgBox.setMessage( BaseMessages.getString( PKG, "Spoon.Dialog.PromptToSave.Fail.Message" ) ); //$NON-NLS-1$ } msgBox.setButtons( new Integer[] { SWT.YES | SWT.NO } ); } catch ( Exception e ) { e.printStackTrace(); throw new RuntimeException( e ); } int retVal = msgBox.open(); // Map from this question to make sense in the original context // (Yes = save, No = no-save , Cancel = do not disconnect) if ( retVal == SWT.YES ) { return SWT.NO; } else { return SWT.CANCEL; } } } ); } else { ChangedWarningDialog.setInstance( new ChangedWarningDialog() ); } } private void warnClosingOfOpenTabsBasedOnPerms( Spoon spoon ) throws KettleException { Class<PurRepositoryDialog> PKG = PurRepositoryDialog.class; // Check to see if there are any open jobs/trans Repository repository = spoon.getRepository(); if ( spoon.getActiveMeta() == null ) { return; } String warningTitle = BaseMessages.getString( PKG, "PurRepository.Dialog.WarnToCloseAllForce.Connect.Title" ); String warningText = BaseMessages.getString( PKG, "PurRepository.Dialog.WarnToCloseAllOptionAdditional.Connect.Message" ); String additionalWarningText = ""; int buttons = SWT.OK; IAbsSecurityProvider absSecurityProvider = (IAbsSecurityProvider) repository.getService( IAbsSecurityProvider.class ); if ( absSecurityProvider != null ) { boolean createPerms = false; boolean executePerms = false; boolean readPerms = false; try { createPerms = absSecurityProvider.isAllowed( IAbsSecurityProvider.CREATE_CONTENT_ACTION ); executePerms = absSecurityProvider.isAllowed( IAbsSecurityProvider.EXECUTE_CONTENT_ACTION ); readPerms = absSecurityProvider.isAllowed( IAbsSecurityProvider.READ_CONTENT_ACTION ); } catch ( KettleException e ) { // No nothing - we are just checking perms } // Check to see if display of warning dialog has been disabled if ( readPerms && createPerms && executePerms ) { warningTitle = BaseMessages.getString( PKG, "PurRepository.Dialog.WarnToCloseAllOption.Connect.Title" ); warningText = BaseMessages.getString( PKG, "PurRepository.Dialog.WarnToCloseAllOption.Connect.Message" ); buttons = SWT.YES | SWT.NO | SWT.ICON_INFORMATION; } else { warningText = BaseMessages.getString( PKG, "PurRepository.Dialog.WarnToCloseAllForce.Connect.Message" ); if ( createPerms ) { additionalWarningText = BaseMessages.getString( PKG, "PurRepository.Dialog.WarnToCloseAllForceAdditional.Connect.Message" ); buttons = SWT.YES | SWT.NO | SWT.ICON_WARNING; } else { additionalWarningText = BaseMessages.getString( PKG, "PurRepository.Dialog.WarnToCloseAllOptionAdditional.Connect.Message" ); buttons = SWT.OK | SWT.ICON_WARNING; } } } MessageBox mb = new MessageBox( spoon.getShell(), buttons ); mb.setMessage( additionalWarningText.length() != 0 ? warningText + "\n\n" + additionalWarningText : warningText ); mb.setText( warningTitle ); final int isCloseAllFiles = mb.open(); // If user has create content perms, then they can leave the tabs open. // Otherwise, we force close the tabs if ( ( isCloseAllFiles == SWT.YES ) || ( isCloseAllFiles == SWT.OK ) ) { spoon.closeAllFiles(); } } private Document getDocumentRoot() { getMainSpoonContainer(); if ( spoonXulContainer != null ) { return spoonXulContainer.getDocumentRoot(); } else { return null; } } private void getMainSpoonContainer() { if ( Spoon.getInstance() != null ) { // Make sure spoon has been initialized first if ( spoonXulContainer == null && Spoon.getInstance().getMainSpoonContainer() != null ) { spoonXulContainer = Spoon.getInstance().getMainSpoonContainer(); } } } /** * For testing */ SpoonPerspectiveManager getPerspectiveManager() { return SpoonPerspectiveManager.getInstance(); } }