/*! * Copyright 2010 - 2015 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.pur.controller; import java.util.Enumeration; import java.util.List; import java.util.ResourceBundle; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Shell; import org.pentaho.di.core.EngineMetaInterface; import org.pentaho.di.core.exception.KettleException; import org.pentaho.di.core.gui.SpoonFactory; import org.pentaho.di.i18n.BaseMessages; import org.pentaho.di.job.JobMeta; import org.pentaho.di.repository.Repository; import org.pentaho.di.repository.pur.PurRepository; import org.pentaho.di.repository.pur.UnifiedRepositoryLockService; import org.pentaho.di.repository.pur.model.RepositoryLock; import org.pentaho.di.trans.TransMeta; import org.pentaho.di.ui.core.dialog.ErrorDialog; import org.pentaho.di.ui.core.gui.GUIResource; import org.pentaho.di.ui.repository.pur.PurRepositoryDialog; import org.pentaho.di.ui.repository.pur.services.IAbsSecurityProvider; import org.pentaho.di.ui.repository.pur.services.ILockService; import org.pentaho.di.ui.spoon.Spoon; import org.pentaho.di.ui.spoon.job.JobGraph; import org.pentaho.di.ui.spoon.trans.TransGraph; import org.pentaho.ui.xul.XulComponent; import org.pentaho.ui.xul.XulDomContainer; import org.pentaho.ui.xul.XulException; import org.pentaho.ui.xul.binding.Binding.Type; import org.pentaho.ui.xul.binding.BindingConvertor; import org.pentaho.ui.xul.binding.BindingFactory; import org.pentaho.ui.xul.binding.DefaultBindingFactory; import org.pentaho.ui.xul.components.XulMenuitem; import org.pentaho.ui.xul.components.XulMessageBox; import org.pentaho.ui.xul.components.XulPromptBox; import org.pentaho.ui.xul.impl.AbstractXulEventHandler; import org.pentaho.ui.xul.swt.custom.DialogConstant; import org.pentaho.ui.xul.util.XulDialogCallback; public class SpoonLockController extends AbstractXulEventHandler implements java.io.Serializable { private static final long serialVersionUID = -8466323408581425803L; /* EESOURCE: UPDATE SERIALVERUID */ private static final Class<?> PKG = PurRepositoryDialog.class; private ILockService service; private EngineMetaInterface workingMeta = null; private BindingFactory bindingFactory = null; private boolean tabBound = false; private boolean isCreateAllowed = false; private boolean isLockingAllowed = false; private Shell shell; private static Log log = LogFactory.getLog( SpoonLockController.class ); protected ResourceBundle messages = new ResourceBundle() { @Override public Enumeration<String> getKeys() { return null; } @Override protected Object handleGetObject( String key ) { return BaseMessages.getString( PKG, key ); } }; public String getName() { return "spoonLockController"; //$NON-NLS-1$ } public void lockContent() throws Exception { try { if ( workingMeta != null && workingMeta.getObjectId() != null && supportsLocking( Spoon.getInstance().getRepository() ) ) { // Bind the tab icon if it is not already bound (cannot be done in init because TransGraph must exist to create // the tab) // Look in the SpoonTransformationDelegate for details on the TabItem creation if ( !tabBound ) { bindingFactory .createBinding( this, "activeMetaUnlocked", Spoon.getInstance().delegates.tabs.findTabMapEntry( workingMeta ).getTabItem(), "image", new BindingConvertor<Boolean, Image>() { //$NON-NLS-1$ //$NON-NLS-2$ @Override public Image sourceToTarget( Boolean activeMetaUnlocked ) { if ( activeMetaUnlocked ) { if ( workingMeta instanceof TransMeta ) { return GUIResource.getInstance().getImageTransGraph(); } else if ( workingMeta instanceof JobMeta ) { return GUIResource.getInstance().getImageJobGraph(); } } else { return GUIResource.getInstance().getImageLocked(); } return null; } @Override public Boolean targetToSource( Image arg0 ) { return false; } } ); tabBound = true; } // Decide whether to lock or unlock the object if ( fetchRepositoryLock( workingMeta ) == null ) { // Lock the object (it currently is NOT locked) XulPromptBox lockNotePrompt = promptLockMessage( document, messages, null ); lockNotePrompt.addDialogCallback( new XulDialogCallback<String>() { public void onClose( XulComponent component, Status status, String value ) { if ( !status.equals( Status.CANCEL ) ) { try { if ( workingMeta instanceof TransMeta ) { getService( Spoon.getInstance().getRepository() ).lockTransformation( workingMeta.getObjectId(), value ); } else if ( workingMeta instanceof JobMeta ) { getService( Spoon.getInstance().getRepository() ).lockJob( workingMeta.getObjectId(), value ); } // Execute binding. Notify listeners that the object is now locked firePropertyChange( "activeMetaUnlocked", true, false ); //$NON-NLS-1$ //$NON-NLS-2$ // this keeps the menu item and the state in sync // could a binding be used instead? XulDomContainer container = getXulDomContainer(); XulMenuitem lockMenuItem = (XulMenuitem) container.getDocumentRoot().getElementById( "lock-context-lock" ); //$NON-NLS-1$ lockMenuItem.setSelected( true ); } catch ( Exception e ) { // convert to runtime exception so it bubbles up through the UI throw new RuntimeException( e ); } } else { // this keeps the menu item and the state in sync // could a binding be used instead? XulDomContainer container = getXulDomContainer(); XulMenuitem lockMenuItem = (XulMenuitem) container.getDocumentRoot().getElementById( "lock-context-lock" ); //$NON-NLS-1$ lockMenuItem.setSelected( false ); } } public void onError( XulComponent component, Throwable err ) { throw new RuntimeException( err ); } } ); lockNotePrompt.open(); } else { // Unlock the object (it currently IS locked) if ( workingMeta instanceof TransMeta ) { getService( Spoon.getInstance().getRepository() ).unlockTransformation( workingMeta.getObjectId() ); } else if ( workingMeta instanceof JobMeta ) { getService( Spoon.getInstance().getRepository() ).unlockJob( workingMeta.getObjectId() ); } // Execute binding. Notify listeners that the object is now unlocked firePropertyChange( "activeMetaUnlocked", false, true ); //$NON-NLS-1$ //$NON-NLS-2$ } } else if ( workingMeta != null && workingMeta.getObjectId() == null && supportsLocking( Spoon.getInstance().getRepository() ) ) { XulDomContainer container = getXulDomContainer(); XulMenuitem lockMenuItem = (XulMenuitem) container.getDocumentRoot().getElementById( "lock-context-lock" ); //$NON-NLS-1$ lockMenuItem.setSelected( false ); XulMessageBox msgBox = (XulMessageBox) document.createElement( "messagebox" ); //$NON-NLS-1$ msgBox.setTitle( BaseMessages.getString( PKG, "Dialog.Error" ) ); //$NON-NLS-1$ msgBox.setMessage( BaseMessages.getString( PKG, "LockController.SaveBeforeLock" ) );//$NON-NLS-1$ msgBox.setModalParent( shell ); msgBox.open(); } else { XulDomContainer container = getXulDomContainer(); XulMenuitem lockMenuItem = (XulMenuitem) container.getDocumentRoot().getElementById( "lock-context-lock" ); //$NON-NLS-1$ lockMenuItem.setSelected( false ); XulMessageBox msgBox = (XulMessageBox) document.createElement( "messagebox" ); //$NON-NLS-1$ msgBox.setTitle( BaseMessages.getString( PKG, "Dialog.Error" ) ); //$NON-NLS-1$ msgBox.setMessage( BaseMessages.getString( PKG, "LockController.NoLockingSupport" ) );//$NON-NLS-1$ msgBox.setModalParent( shell ); msgBox.open(); } } catch ( Throwable th ) { log.error( BaseMessages.getString( PKG, "LockController.NoLockingSupport" ), th );//$NON-NLS-1$ new ErrorDialog( ( (Spoon) SpoonFactory.getInstance() ).getShell(), BaseMessages.getString( PKG, "Dialog.Error" ), BaseMessages.getString( PKG, "LockController.NoLockingSupport" ), th ); //$NON-NLS-1$ //$NON-NLS-2$ } } public void viewLockNote() throws Exception { if ( workingMeta != null && supportsLocking( Spoon.getInstance().getRepository() ) ) { try { RepositoryLock repoLock = fetchRepositoryLock( workingMeta ); if ( repoLock != null ) { XulMessageBox msgBox = (XulMessageBox) document.createElement( "messagebox" ); //$NON-NLS-1$ msgBox.setTitle( BaseMessages.getString( PKG, "PurRepository.LockNote.Title" ) ); //$NON-NLS-1$ msgBox.setMessage( repoLock.getMessage() ); msgBox.setModalParent( shell ); msgBox.open(); } } catch ( Throwable th ) { log.error( BaseMessages.getString( PKG, "LockController.NoLockingSupport" ), th );//$NON-NLS-1$ new ErrorDialog( ( (Spoon) SpoonFactory.getInstance() ).getShell(), BaseMessages .getString( PKG, "Dialog.Error" ), BaseMessages.getString( PKG, "LockController.NoLockingSupport" ), th ); //$NON-NLS-1$ //$NON-NLS-2$ } } else { XulMessageBox msgBox = (XulMessageBox) document.createElement( "messagebox" ); //$NON-NLS-1$ msgBox.setTitle( BaseMessages.getString( PKG, "Dialog.Error" ) ); //$NON-NLS-1$ msgBox.setMessage( BaseMessages.getString( PKG, "LockController.NoLockingSupport" ) );//$NON-NLS-1$ msgBox.setModalParent( shell ); msgBox.open(); } } @Override public void setXulDomContainer( XulDomContainer xulDomContainer ) { super.setXulDomContainer( xulDomContainer ); init(); } public boolean isActiveMetaUnlocked() { try { if ( fetchRepositoryLock( workingMeta ) != null ) { return false; } else { return true; } } catch ( KettleException e ) { throw new RuntimeException( e ); } } protected void init() { try { if ( ( Spoon.getInstance().getRepository() != null ) && ( Spoon.getInstance().getRepository().hasService( IAbsSecurityProvider.class ) ) ) { IAbsSecurityProvider securityService = (IAbsSecurityProvider) Spoon.getInstance().getRepository().getService( IAbsSecurityProvider.class ); setCreateAllowed( allowedActionsContains( securityService, IAbsSecurityProvider.CREATE_CONTENT_ACTION ) ); } shell = ( ( (Spoon) SpoonFactory.getInstance() ).getShell() ); XulDomContainer container = getXulDomContainer(); bindingFactory = new DefaultBindingFactory(); bindingFactory.setDocument( container.getDocumentRoot() ); bindingFactory.setBindingType( Type.ONE_WAY ); bindingFactory.createBinding( this, "activeMetaUnlocked", "lock-context-locknotes", "disabled" ); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ bindingFactory.createBinding( this, "lockingNotAllowed", "lock-context-lock", "disabled" ); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ // Get trans* object to gain access to the *Meta object to determine if we are initially locked or not // Try transformation if ( container.getEventHandlers().containsKey( "transgraph" ) ) { //$NON-NLS-1$ workingMeta = ( (TransGraph) container.getEventHandler( "transgraph" ) ).getMeta(); //$NON-NLS-1$ } else if ( container.getEventHandlers().containsKey( "jobgraph" ) ) { //$NON-NLS-1$ workingMeta = ( (JobGraph) container.getEventHandler( "jobgraph" ) ).getMeta(); //$NON-NLS-1$ } RepositoryLock repoLock = fetchRepositoryLock( workingMeta ); if ( repoLock != null ) { XulMenuitem lockMenuItem = (XulMenuitem) container.getDocumentRoot().getElementById( "lock-context-lock" ); //$NON-NLS-1$ lockMenuItem.setSelected( true ); // Permit locking/unlocking if the user owns the lock if ( Spoon.getInstance().getRepository() instanceof PurRepository ) { setLockingAllowed( new UnifiedRepositoryLockService( ( (PurRepository) Spoon.getInstance().getRepository() ) .getPur() ).canUnlockFileById( workingMeta.getObjectId() ) ); } else { setLockingAllowed( repoLock.getLogin().equalsIgnoreCase( Spoon.getInstance().getRepository().getUserInfo().getLogin() ) ); } } else { setLockingAllowed( true ); } firePropertyChange( "activeMetaUnlocked", null, repoLock == null ); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } catch ( Exception e ) { log.error( BaseMessages.getString( PKG, "LockController.NoLockingSupport" ), e );//$NON-NLS-1$ new ErrorDialog( ( (Spoon) SpoonFactory.getInstance() ).getShell(), BaseMessages.getString( PKG, "Dialog.Error" ), e.getMessage(), e ); //$NON-NLS-1$ } } public boolean isCreateAllowed() { return isCreateAllowed; } public void setCreateAllowed( boolean isCreateAllowed ) { this.isCreateAllowed = isCreateAllowed; this.firePropertyChange( "createAllowed", null, isCreateAllowed ); //$NON-NLS-1$ } public boolean isLockingAllowed() { return isLockingAllowed; } public boolean isLockingNotAllowed() { return !isLockingAllowed; } public void setLockingAllowed( boolean isLockingAllowed ) { this.isLockingAllowed = isLockingAllowed; this.firePropertyChange( "lockingNotAllowed", null, !isLockingAllowed ); //$NON-NLS-1$ } private boolean allowedActionsContains( IAbsSecurityProvider service, String action ) throws KettleException { List<String> allowedActions = service.getAllowedActions( IAbsSecurityProvider.NAMESPACE ); for ( String actionName : allowedActions ) { if ( action != null && action.equals( actionName ) ) { return true; } } return false; } protected RepositoryLock fetchRepositoryLock( EngineMetaInterface meta ) throws KettleException { RepositoryLock result = null; if ( meta != null ) { if ( meta.getObjectId() != null ) { if ( meta instanceof TransMeta ) { result = getService( Spoon.getInstance().getRepository() ).getTransformationLock( meta.getObjectId() ); } else if ( meta instanceof JobMeta ) { result = getService( Spoon.getInstance().getRepository() ).getJobLock( meta.getObjectId() ); } } } return result; } private XulPromptBox promptLockMessage( org.pentaho.ui.xul.dom.Document document, ResourceBundle messages, String defaultMessage ) throws XulException { XulPromptBox prompt = (XulPromptBox) document.createElement( "promptbox" ); //$NON-NLS-1$ prompt.setModalParent( shell ); prompt.setTitle( BaseMessages.getString( PKG, "RepositoryExplorer.LockMessage.Title" ) );//$NON-NLS-1$ prompt.setButtons( new DialogConstant[] { DialogConstant.OK, DialogConstant.CANCEL } ); prompt.setMessage( BaseMessages.getString( PKG, "RepositoryExplorer.LockMessage.Label" ) );//$NON-NLS-1$ prompt.setValue( defaultMessage == null ? BaseMessages.getString( PKG, "RepositoryExplorer.DefaultLockMessage" ) : defaultMessage ); //$NON-NLS-1$ return prompt; } private ILockService getService( Repository repository ) throws KettleException { if ( service == null ) { if ( repository != null && repository.hasService( ILockService.class ) ) { return (ILockService) repository.getService( ILockService.class ); } else { throw new IllegalStateException(); } } else { return service; } } private boolean supportsLocking( Repository repository ) throws KettleException { return repository.hasService( ILockService.class ); } }