/****************************************************************************** * Copyright (c) 2008 g-Eclipse consortium * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Initial development of the original code was made for * project g-Eclipse founded by European Union * project number: FP6-IST-034327 http://www.geclipse.eu/ * * Contributor(s): * Mariusz Wojtysiak - initial API and implementation * David Johnson (UoR) - added support for deleting JSDLs linked to * workflows *****************************************************************************/ package eu.geclipse.ui.internal.actions; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.eclipse.core.filesystem.IFileStore; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.window.IShellProvider; import org.eclipse.jface.window.Window; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.ISharedImages; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.actions.DeleteResourceAction; import org.eclipse.ui.actions.SelectionListenerAction; import eu.geclipse.core.filesystem.GEclipseFileSystem; import eu.geclipse.core.model.GridModel; import eu.geclipse.core.model.IGridConnectionElement; import eu.geclipse.core.model.IGridContainer; import eu.geclipse.core.model.IGridElement; import eu.geclipse.core.model.IGridJob; import eu.geclipse.core.model.IGridJobDescription; import eu.geclipse.core.reporting.IProblem; import eu.geclipse.core.reporting.ISolution; import eu.geclipse.core.reporting.ProblemException; import eu.geclipse.ui.dialogs.ProblemDialog; import eu.geclipse.ui.internal.Activator; import eu.geclipse.workflow.IGridWorkflowDescription; import eu.geclipse.workflow.IGridWorkflowJobDescription; /** * */ public class DeleteGridElementAction extends SelectionListenerAction { Shell shell; private DeleteResourceAction eclipseAction; protected DeleteGridElementAction( final Shell shell ) { super( Messages.getString("DeleteGridElementAction.actionNameDelete") ); //$NON-NLS-1$ this.shell = shell; this.eclipseAction = new DeleteResourceAction( new IShellProvider() { public Shell getShell() { return shell; } } ); ISharedImages sharedImages = PlatformUI.getWorkbench().getSharedImages(); ImageDescriptor deleteImage = sharedImages.getImageDescriptor( ISharedImages.IMG_TOOL_DELETE ); setImageDescriptor( deleteImage ); } /* * (non-Javadoc) * * @see org.eclipse.jface.action.Action#run() */ @Override public void run() { List<IGridJob> selectedJobs = new ArrayList<IGridJob>( getSelectedResources().size() ); List<IGridJobDescription> selectedWorkflowJobDescriptions = new ArrayList<IGridJobDescription>( getSelectedResources().size() ); List<IResource> selectedResources = new ArrayList<IResource>( getSelectedResources().size() ); dispatchSelectedElements( selectedJobs, selectedWorkflowJobDescriptions, selectedResources ); deactivateConnections( selectedResources.toArray( new IResource[ selectedResources.size() ] ) ); if( !selectedJobs.isEmpty() ) { deleteJobs( selectedJobs ); } if( !selectedResources.isEmpty() ) { deleteOtherResources( selectedResources ); } if (!selectedWorkflowJobDescriptions.isEmpty()) { deleteWorkflowJobDescriptions( selectedWorkflowJobDescriptions ); } } @Override protected boolean updateSelection( final IStructuredSelection selection ) { return ! getSelectedResources().isEmpty(); } private void deactivateConnections( final IResource[] resources ) { if ( resources != null ) { for ( IResource resource : resources ) { IGridElement element = GridModel.getRoot().findElement( resource ); if ( element instanceof IGridConnectionElement ) { try { IGridConnectionElement connection = ( IGridConnectionElement ) element; IFileStore fileStore = connection.getConnectionFileStore(); // Deactivate the connection before deleting it in order to avoid // info or child fetching GEclipseFileSystem.setFileStoreActive( fileStore, false, false, false ); // Refresh the resource tree in order to remove all cached child // resources that would also cause info fetching resource.refreshLocal( IResource.DEPTH_INFINITE, null ); } catch( CoreException cExc ) { Activator.logException( cExc ); } } if ( resource instanceof IContainer ) { try { IResource[] members = ( ( IContainer ) resource ).members(); deactivateConnections( members ); } catch ( CoreException cExc ) { Activator.logException( cExc ); } } } } } private void dispatchSelectedElements( final List<IGridJob> selectedJobs, final List<IGridJobDescription> selectedWorkflowJobDescriptions, final List<IResource> otherSelectedResources ) { for( Object obj : getSelectedResources() ) { if( obj instanceof IResource ) { IResource resource = (IResource)obj; IGridElement element = GridModel.getRoot().findElement( resource ); if( element instanceof IGridJob ) { selectedJobs.add( (IGridJob)element ); } else if (element instanceof IGridJobDescription ) { // find out if the parent resource is a workflow IGridContainer parent = element.getParent(); if (parent instanceof IGridWorkflowDescription) { boolean inWorkflow = false; List<IGridWorkflowJobDescription> childrenJobs = ( ( IGridWorkflowDescription )parent ).getChildrenJobs(); for (Iterator<IGridWorkflowJobDescription> i = childrenJobs.iterator(); i.hasNext();) { IGridWorkflowJobDescription child = i.next(); String childUri = child.getDescriptionPath().toString(); String fullPath = element.getResource().getLocation().toString(); if ( childUri.equals( fullPath ) ) { inWorkflow = true; } } if (inWorkflow) { selectedWorkflowJobDescriptions.add( ( IGridJobDescription )element ); } else { otherSelectedResources.add( resource ); } } else { otherSelectedResources.add( resource ); } } else { otherSelectedResources.add( resource ); } } } } private void deleteOtherResources( final List<IResource> selectedResources ) { this.eclipseAction.selectionChanged( new StructuredSelection( selectedResources ) ); this.eclipseAction.run(); } /* * At the moment it only works if workflow is not dirty (i.e. workflow must be saved for * it to behave correctly). There is not yet any Problem reporting or Progress monitoring. */ private void deleteWorkflowJobDescriptions( final List<IGridJobDescription> selectedJobDescriptions ) { MessageDialog dialog = null; String dialogMessage = ""; //$NON-NLS-1$ if (selectedJobDescriptions.size()==1) { IGridJobDescription selectedJobDesc = selectedJobDescriptions.get( 0 ); String jsdl = selectedJobDesc.getResource().getName(); dialogMessage = String.format( Messages.getString( "DeleteGridElementAction.confirmJobDescDeleteOne" ), jsdl); //$NON-NLS-1$ } else { String jsdlList = ""; //$NON-NLS-1$ for (Iterator<IGridJobDescription> i = selectedJobDescriptions.iterator(); i.hasNext();) { jsdlList = jsdlList + " " + i.next().getResource().getName(); //$NON-NLS-1$ } dialogMessage = String.format(Messages.getString( "DeleteGridElementAction.confirmJobDescDeleteMany" ), jsdlList); //$NON-NLS-1$ } dialog = new MessageDialog(DeleteGridElementAction.this.shell, Messages.getString("DeleteGridElementAction.confirmationTitle"), //$NON-NLS-1$ null, dialogMessage, MessageDialog.WARNING, new String[] { IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL }, 0 ); if ( dialog.open() == Window.OK ) { try { for (Iterator<IGridJobDescription> i1 = selectedJobDescriptions.iterator(); i1.hasNext();) { IResource r = i1.next().getResource(); r.delete( true, new NullProgressMonitor() ); // TODO add a proper progress monitor to use } } catch( CoreException e ) { // TODO Auto-generated catch block, add proper problem reporting e.printStackTrace(); } } } private enum ConfirmChoice { /** * */ deleteFromGrid, /** * */ deleteOnlyFromWorkspace, /** * */ cancel } private void deleteJobs( final List<IGridJob> selectedJobs ) { ConfirmChoice choice = confirmDeleteJobs( selectedJobs ); if( choice != ConfirmChoice.cancel ) { DeleteJobsJob job = new DeleteJobsJob( selectedJobs, choice ); job.setUser( true ); job.schedule(); } } private ConfirmChoice confirmDeleteJobs( final List<IGridJob> selectedJobs ) { ConfirmChoice choice = ConfirmChoice.cancel; String question = null, warning = null; if( selectedJobs.size() == 1 ) { IGridJob job = selectedJobs.iterator().next(); question = String.format( Messages.getString("DeleteGridElementAction.confirmationOne"), job.getJobName() ); //$NON-NLS-1$ if( job.getJobStatus().canChange() ) { warning = String.format( Messages.getString("DeleteGridElementAction.warningOne"), job.getJobName() ); //$NON-NLS-1$ } } else { question = String.format( Messages.getString("DeleteGridElementAction.confirmationMany"), Integer.valueOf( selectedJobs.size() ) ); //$NON-NLS-1$ for( IGridJob job : selectedJobs ) { if( job.getJobStatus().canChange() ) { warning = Messages.getString("DeleteGridElementAction.warningMany"); //$NON-NLS-1$ break; } } } String msg = question; if( warning != null ) { msg += "\n\n" + warning; //$NON-NLS-1$ } ConfirmDeleteJobsDialog dialog = new ConfirmDeleteJobsDialog( msg, warning == null ? MessageDialog.QUESTION : MessageDialog.WARNING ); if( dialog.open() == 0 ) { if( dialog.isDeleteFromGrid() ) { choice = ConfirmChoice.deleteFromGrid; } else { choice = ConfirmChoice.deleteOnlyFromWorkspace; } } return choice; } private class ConfirmDeleteJobsDialog extends MessageDialog { private Button deleteFromGridCheckbox; private boolean deleteFromGrid; ConfirmDeleteJobsDialog( final String dialogMessage, final int dialogImageType ) { super( DeleteGridElementAction.this.shell, Messages.getString("DeleteGridElementAction.confirmationTitle"), //$NON-NLS-1$ null, dialogMessage, dialogImageType, new String[] { IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL }, 0 ); } /* (non-Javadoc) * @see org.eclipse.jface.dialogs.MessageDialog#createCustomArea(org.eclipse.swt.widgets.Composite) */ @Override protected Control createCustomArea( final Composite parent ) { this.deleteFromGridCheckbox = new Button( parent, SWT.CHECK ); this.deleteFromGridCheckbox.setText( Messages.getString("DeleteGridElementAction.alsoDeleteFromGrid") ); //$NON-NLS-1$ this.deleteFromGridCheckbox.setSelection( true ); return super.createCustomArea( parent ); } /* (non-Javadoc) * @see org.eclipse.jface.dialogs.Dialog#close() */ @Override public boolean close() { this.deleteFromGrid = this.deleteFromGridCheckbox.getSelection(); return super.close(); } boolean isDeleteFromGrid() { return this.deleteFromGrid; } } private class DeleteJobsJob extends Job { boolean forceDeleteLocal = false; private List<IGridJob> selectedJobs; private ConfirmChoice userChoice; /** * @param selectedJobs * @param userChoice */ public DeleteJobsJob( final List<IGridJob> selectedJobs, final ConfirmChoice userChoice ) { super( Messages.getString("DeleteGridElementAction.deleteJobName") ); //$NON-NLS-1$ this.selectedJobs = selectedJobs; this.userChoice = userChoice; } @Override protected IStatus run( final IProgressMonitor monitor ) { IStatus status = Status.OK_STATUS; SubMonitor submonitor = SubMonitor.convert( monitor ); submonitor.setWorkRemaining( this.selectedJobs.size() ); try { Iterator<IGridJob> iterator = this.selectedJobs.iterator(); IGridJob job = null; while( iterator.hasNext() ) { try { testCancel( submonitor ); job = iterator.next(); deleteJob( submonitor.newChild( 1 ), job ); iterator.remove(); // if succesful deleted, then don't delete it again during eventually next try } catch( ProblemException exception ) { addSolutionOnlyLocalDel( exception ); ProblemDialog.openProblem( DeleteGridElementAction.this.shell, Messages.getString("DeleteGridElementAction.deleteProblemTitle"), //$NON-NLS-1$ String.format( Messages.getString("DeleteGridElementAction.problemDescription"), //$NON-NLS-1$ job != null ? job.getJobName() : "unknown" ), //$NON-NLS-1$ exception ); break; } } } finally { submonitor.done(); } return status; } private void deleteJob( final SubMonitor monitor, final IGridJob job ) throws ProblemException { monitor.setTaskName( String.format( Messages.getString("DeleteGridElementAction.taskNameDeleting"), job.getJobName() ) ); //$NON-NLS-1$ monitor.setWorkRemaining( this.userChoice == ConfirmChoice.deleteFromGrid ? 3 : 2 ); stopJobStatusUpdater( job, monitor.newChild( 1 ) ); if( this.userChoice == ConfirmChoice.deleteFromGrid ) { try { job.deleteJob( monitor.newChild( 1 ) ); } catch( ProblemException exception ) { if( this.forceDeleteLocal ) { Activator.logException( exception ); } else { throw exception; } } } try { testCancel( monitor ); job.getResource().delete( true, monitor.newChild( 1 ) ); } catch( CoreException exception ) { throw new ProblemException( "eu.geclipse.problem.deleteGridElementAction.cannotDeleteResource", //$NON-NLS-1$ exception, Activator.PLUGIN_ID ); } } private void stopJobStatusUpdater( final IGridJob job, final SubMonitor monitor ) { monitor.subTask( Messages.getString("DeleteGridElementAction.taskStoppingUpdater") ); //$NON-NLS-1$ GridModel.getJobManager().removeJobStatusUpdater( job, true, monitor ); } private void testCancel( final IProgressMonitor monitor ) { if( monitor.isCanceled() ) { throw new OperationCanceledException(); } } void addSolutionOnlyLocalDel( final ProblemException exception ) { if( this.userChoice == ConfirmChoice.deleteFromGrid && !this.forceDeleteLocal ) { IProblem problem = exception.getProblem(); problem.addSolution( new ISolution() { public String getDescription() { return Messages.getString("DeleteGridElementAction.forceDeleteLocal"); //$NON-NLS-1$ } public String getID() { return null; } public boolean isActive() { return true; } public void solve() throws InvocationTargetException { DeleteJobsJob.this.forceDeleteLocal = true; DeleteJobsJob.this.schedule(); }} ); } } } }