blob: 269e51ac8ae8f4a05e3afd89a9bbd2e9b0af39b4 [file] [log] [blame]
//------------------------------------------------------------------------------
// Copyright (c) 2005, 2006 IBM Corporation and others.
// 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
//
// Contributors:
// IBM Corporation - initial implementation
//------------------------------------------------------------------------------
package org.eclipse.epf.library.edit.process.command;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import org.eclipse.emf.common.CommonPlugin;
import org.eclipse.emf.common.command.BasicCommandStack;
import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.common.command.CompoundCommand;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.util.AbstractTreeIterator;
import org.eclipse.emf.common.util.WrappedException;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.edit.command.RemoveCommand;
import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.epf.library.edit.IConfigurator;
import org.eclipse.epf.library.edit.LibraryEditResources;
import org.eclipse.epf.library.edit.Providers;
import org.eclipse.epf.library.edit.TngAdapterFactory;
import org.eclipse.epf.library.edit.command.BatchCommand;
import org.eclipse.epf.library.edit.command.IResourceAwareCommand;
import org.eclipse.epf.library.edit.ui.UserInteractionHelper;
import org.eclipse.epf.library.edit.util.Messenger;
import org.eclipse.epf.library.edit.util.ProcessUtil;
import org.eclipse.epf.library.edit.util.TngUtil;
import org.eclipse.epf.uma.Activity;
import org.eclipse.epf.uma.BreakdownElement;
import org.eclipse.epf.uma.Deliverable;
import org.eclipse.epf.uma.Descriptor;
import org.eclipse.epf.uma.MethodConfiguration;
import org.eclipse.epf.uma.MethodElement;
import org.eclipse.epf.uma.Process;
import org.eclipse.epf.uma.Role;
import org.eclipse.epf.uma.RoleDescriptor;
import org.eclipse.epf.uma.Task;
import org.eclipse.epf.uma.TaskDescriptor;
import org.eclipse.epf.uma.TeamProfile;
import org.eclipse.epf.uma.VariabilityElement;
import org.eclipse.epf.uma.WorkProduct;
import org.eclipse.epf.uma.WorkProductDescriptor;
/**
* Command for one-way synchronization from method to process.
*
* @author Phong Nguyen Le - Nov 22, 2005
* @since 1.0
*/
public class SynchronizeCommand extends CompoundCommand implements
IResourceAwareCommand {
private Collection elements;
private IConfigurator configurator;
protected boolean aborted;
private ArrayList deleteList;
protected boolean preExecSuccessful;
protected List deleteCommandList;
protected boolean successful;
private MethodConfiguration config;
private Set synchFeatures;
private DeleteUnusedDescriptorsCommand deleteUnusedDescriptorsCommand;
private Collection activities;
private boolean showSuccessfulMsg = true;
private boolean intialized;
private BatchCommand batchCommand = new BatchCommand(false);
private Map<VariabilityElement, VariabilityElement> replacerToBaseMap = new HashMap<VariabilityElement, VariabilityElement>();
// private Object UIContext;
/**
* Constructs a SynchronizeCommand that use the process default
* configuration to synchronize all the synchronizable features
*
* @param elements
* a list of BreakdownElement objects
*/
public SynchronizeCommand(String label, Collection elements) {
super(label);
this.elements = elements;
}
/**
* Constructs a SynchronizeCommand that use the given configuration
* and list of synchronizable features to synchronize
*
* @param elements
* @param config the configuration
* @param synchFeatures the synchronizable features
*/
public SynchronizeCommand(Collection elements, MethodConfiguration config, Set synchFeatures, boolean showSuccessfulMsg) {
super(LibraryEditResources.AutoSynchronizeCommand_label);
this.elements = elements;
this.config = config;
this.synchFeatures = synchFeatures;
this.showSuccessfulMsg = showSuccessfulMsg;
}
public void setMethodConfiguration(MethodConfiguration config) {
this.config = config;
if(configurator != null) {
configurator.setMethodConfiguration(config);
}
}
public void setSynchronizationFeatures(Set synchFeatures) {
this.synchFeatures = synchFeatures;
}
private boolean doInitialize() {
commandList.clear();
if (elements == null || elements.isEmpty()) {
return false;
}
deleteCommandList = new ArrayList();
deleteList = new ArrayList();
activities = new ArrayList();
for (Iterator iter = elements.iterator(); iter.hasNext();) {
Object element = (Object) iter.next();
addToDeleteList(element, deleteList);
if(element instanceof Activity) {
activities.add(element);
}
}
elements.removeAll(deleteList);
for (Iterator iter = elements.iterator(); iter.hasNext();) {
Object object = iter.next();
if (object instanceof Descriptor) {
Descriptor descriptor = (Descriptor) object;
if (descriptor.getIsSynchronizedWithSource().booleanValue()
&& !deleteList.contains(descriptor)) {
if(descriptor.getSuperActivities() == null) {
// descriptor is used by TeamProfile to represent a role or used by a deliverable descriptor to
// represent a deliverable part
//
if(descriptor instanceof WorkProductDescriptor && ((WorkProductDescriptor)descriptor).getWorkProduct() instanceof Deliverable) {
append(new SynchronizeDeliverableDescriptorCommand((WorkProductDescriptor) descriptor, synchFeatures, config));
}
else {
append(new BasicSynchronizeDescriptorCommand(descriptor, synchFeatures, config));
}
}
else {
Activity act = descriptor.getSuperActivities();
if (object instanceof TaskDescriptor) {
Task task = ((TaskDescriptor) object).getTask();
if (task != null) {
if(replacerToBaseMap.containsKey(task)) {
task = (Task) replacerToBaseMap.get(task);
}
append(new WBSDropCommand(act, Collections
.singletonList(task), config, synchFeatures));
}
} else if (object instanceof RoleDescriptor) {
Role role = ((RoleDescriptor) object).getRole();
if (role != null) {
if(replacerToBaseMap.containsKey(role)) {
role = (Role) replacerToBaseMap.get(role);
}
append(new OBSDropCommand(act, Collections
.singletonList(role), config, synchFeatures, configurator));
}
} else if (object instanceof WorkProductDescriptor) {
WorkProduct wp = ((WorkProductDescriptor) object)
.getWorkProduct();
if (wp != null) {
if(replacerToBaseMap.containsKey(wp)) {
wp = (WorkProduct) replacerToBaseMap.get(wp);
}
append(new PBSDropCommand(act, Collections
.singletonList(wp), config, synchFeatures, configurator));
}
}
}
}
} else if (object instanceof Activity) {
appendCommands((Activity) object);
} else if (object instanceof TeamProfile) {
appendCommands((TeamProfile)object);
}
}
return !deleteList.isEmpty() || !commandList.isEmpty() || !activities.isEmpty();
}
public boolean initilize() {
boolean b = isPrepared;
try {
// since Eclipse 3.3, CompoundCommand.append() throws IllegalStateException if isPrepared is already set
// but this method is called after isPrepared is set in canExecute() and it makes many calls to append()
// work-around is to unset isPrepared at beginning of this method and set it back to old value at method end.
//
isPrepared = false;
return intialized = doInitialize();
}
finally {
isPrepared = b;
}
}
/**
* @return the intialized
*/
public boolean isIntialized() {
return intialized;
}
/**
* @param activity
*/
private void appendCommands(Activity activity) {
List tasks = new ArrayList();
List roles = new ArrayList();
List workProducts = new ArrayList();
List activities = new ArrayList();
for (Iterator iter = activity.getBreakdownElements().iterator(); iter
.hasNext();) {
Object element = iter.next();
if (element instanceof Descriptor) {
if (((Descriptor) element).getIsSynchronizedWithSource()
.booleanValue()
&& !deleteList.contains(element)) {
if (element instanceof TaskDescriptor) {
Task task = ((TaskDescriptor) element).getTask();
if (task != null) {
if(replacerToBaseMap.containsKey(task)) {
task = (Task) replacerToBaseMap.get(task);
}
tasks.add(task);
}
} else if (element instanceof RoleDescriptor) {
Role role = ((RoleDescriptor) element).getRole();
if (role != null) {
if(replacerToBaseMap.containsKey(role)) {
role = (Role) replacerToBaseMap.get(role);
}
roles.add(role);
}
} else if (element instanceof WorkProductDescriptor) {
WorkProduct wp = ((WorkProductDescriptor) element)
.getWorkProduct();
if (wp != null) {
if(replacerToBaseMap.containsKey(wp)) {
wp = (WorkProduct) replacerToBaseMap.get(wp);
}
workProducts.add(wp);
}
}
}
} else if (element instanceof Activity) {
activities.add(element);
} else if (element instanceof TeamProfile) {
appendCommands((TeamProfile)element);
}
}
if (!tasks.isEmpty()) {
append(new WBSDropCommand(activity, tasks, config, synchFeatures));
}
if (!roles.isEmpty()) {
append(new OBSDropCommand(activity, roles, config, synchFeatures, configurator));
}
if (!workProducts.isEmpty()) {
append(new PBSDropCommand(activity, workProducts, config,
synchFeatures, configurator));
}
for (Iterator iter = activities.iterator(); iter.hasNext();) {
appendCommands((Activity) iter.next());
}
}
private void appendCommands(TeamProfile team) {
Iterator iter = new AbstractTreeIterator(team, false) {
/**
*
*/
private static final long serialVersionUID = 1L;
protected Iterator getChildren(Object object) {
if(object instanceof TeamProfile) {
TeamProfile team = ((TeamProfile)object);
List children = new ArrayList(team.getSubTeam());
children.addAll(team.getTeamRoles());
return children.iterator();
}
else {
return Collections.EMPTY_LIST.iterator();
}
}
};
while(iter.hasNext()) {
Object obj = iter.next();
// synch only own role descriptor of team profile
//
if(obj instanceof RoleDescriptor && ((RoleDescriptor)obj).getSuperActivities() == null) {
append(new BasicSynchronizeDescriptorCommand((Descriptor) obj, synchFeatures, config));
}
}
}
/*
* (non-Javadoc)
*
* @see com.ibm.library.edit.command.IResourceAwareCommand#getModifiedResources()
*/
public Collection getModifiedResources() {
HashSet modifiedResources = new HashSet();
for (Iterator iter = commandList.iterator(); iter.hasNext();) {
Object cmd = iter.next();
if(cmd instanceof IResourceAwareCommand) {
modifiedResources.addAll(((IResourceAwareCommand)cmd).getModifiedResources());
}
}
return modifiedResources;
}
// public void setUIContext(Object UIContext) {
// this.UIContext = UIContext;
// }
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.common.command.CompoundCommand#execute()
*/
public void execute() {
// delete all descriptors whose linked element are no longer in the
// configuration
//
if (!deleteList.isEmpty()) {
Command cmd = delete(deleteList);
if (cmd != null) {
deleteCommandList.add(cmd);
}
}
batchCommand.execute();
if (!aborted) {
// IRunnableWithProgress runnable = new IRunnableWithProgress() {
//
// public void run(IProgressMonitor monitor)
// throws InvocationTargetException, InterruptedException {
// preExecSuccessful = preExecute();
// }
//
// };
//
// UserInteractionHelper.runWithProgress(runnable, false, null);
//
// if (preExecSuccessful) {
// try {
// BusyIndicator.showWhile(Display.getCurrent(), new Runnable() {
//
// public void run() {
// superRedo();
// successful = true;
// }
//
// });
// }
// catch(RuntimeException e) {
// LibraryEditPlugin.getDefault().getMsgDialog().displayError(getLabel(), e.toString());
// }
// }
Runnable runnable = new Runnable() {
public void run() {
preExecSuccessful = preExecute();
if(preExecute()) {
superRedo();
successful = true;
}
}
};
UserInteractionHelper.runInUI(runnable, getLabel());
if (successful) {
if(!activities.isEmpty()) {
if(deleteUnusedDescriptorsCommand == null) {
deleteUnusedDescriptorsCommand = new DeleteUnusedDescriptorsCommand(elements, true, deleteList) {
protected Command delete(List elements) {
return SynchronizeCommand.this.delete(elements);
}
};
deleteCommandList.add(deleteUnusedDescriptorsCommand);
}
deleteUnusedDescriptorsCommand.execute();
}
if (showSuccessfulMsg) {
if(!replacerToBaseMap.isEmpty()) {
refreshViewer();
}
Messenger.INSTANCE.showInfo(
LibraryEditResources.SynchronizeCompleteDialog_Title,
LibraryEditResources.AutoSynchronizeCommand_sucessful);
}
}
}
}
private void refreshViewer() {
if(elements.isEmpty()) return;
Process proc = TngUtil.getOwningProcess(elements.iterator().next());
if(proc != null) {
for (int i = 0; i < TngAdapterFactory.processAdapterFactories.length; i++) {
AdapterFactory adapterFactory = TngAdapterFactory.processAdapterFactories[i];
ProcessUtil.refreshViewer(adapterFactory, proc);
}
}
}
private void superRedo() {
super.redo();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.common.command.CompoundCommand#redo()
*/
public void redo() {
execute();
}
public boolean isSucessful() {
return successful;
}
protected boolean preExecute() {
for (ListIterator commands = commandList.listIterator(); commands
.hasNext();) {
Object command = commands.next();
if(command instanceof BSDropCommand && !((BSDropCommand)command).preExecute()) {
return false;
}
// be polite to other threads (no effect on some platforms)
//
Thread.yield();
}
return true;
}
/**
* Deletes the specified elements
* @param elements
* @return the executed command that deleted the given elements
*/
protected Command delete(List elements) {
EditingDomain domain = new AdapterFactoryEditingDomain(
TngAdapterFactory.INSTANCE.getProcessComposedAdapterFactory(),
new BasicCommandStack());
Command cmd = new ProcessElementDeleteCommand(RemoveCommand.create(domain,
elements), elements);
cmd.execute();
return cmd;
}
private IConfigurator getConfigurator() {
if (configurator == null) {
MethodConfiguration config = this.config;
if(config == null) {
Process proc = TngUtil.getOwningProcess((BreakdownElement) elements
.iterator().next());
config = proc.getDefaultContext();
}
configurator = Providers.getConfiguratorFactory()
.createConfigurator(config);
}
return configurator;
}
/**
* @param element
* @param deleteList
*/
private void addToDeleteList(Object element, List deleteList) {
if (element instanceof Descriptor) {
if (!getConfigurator().accept(element)) {
MethodElement linkedElement = ProcessUtil.getAssociatedElement((Descriptor) element);
if(linkedElement instanceof VariabilityElement && TngUtil.isReplacer((VariabilityElement) linkedElement)) {
// if the linked element of the descriptor is a replacer, delete the descriptor in this synchronization
// only if the base of linked element is not in the configuration
//
VariabilityElement base = ((VariabilityElement)linkedElement).getVariabilityBasedOnElement();
while(base != null && TngUtil.isContributorOrReplacer(base)) {
base = base.getVariabilityBasedOnElement();
}
if(base != null) {
if(!getConfigurator().accept(base)) {
deleteList.add(element);
}
else {
batchCommand.addFeatureValue((EObject) element,
ProcessUtil.getLinkReference((Descriptor) element), base);
replacerToBaseMap.put((VariabilityElement) linkedElement, base);
}
}
}
else {
deleteList.add(element);
}
}
} else if (element instanceof Activity) {
for (Iterator iter = ((Activity) element).getBreakdownElements()
.iterator(); iter.hasNext();) {
addToDeleteList(iter.next(), deleteList);
}
}
}
private void superUndo() {
super.undo();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.common.command.CompoundCommand#undo()
*/
public void undo() {
UserInteractionHelper.getUIHelper().runWithBusyIndicator(new Runnable() {
public void run() {
if (!deleteCommandList.isEmpty()) {
for (ListIterator commands = deleteCommandList
.listIterator(deleteCommandList.size()); commands
.hasPrevious();) {
try {
Command command = (Command) commands.previous();
command.undo();
} catch (RuntimeException exception) {
// Skip over the command that threw the exception.
//
commands.next();
try {
// Iterate forward over the undone commands to
// redo them.
//
while (commands.hasNext()) {
Command command = (Command) commands.next();
command.redo();
}
} catch (RuntimeException nestedException) {
CommonPlugin.INSTANCE
.log(new WrappedException(
CommonPlugin.INSTANCE
.getString("_UI_IgnoreException_exception"), nestedException).fillInStackTrace()); //$NON-NLS-1$
}
throw exception;
}
}
}
superUndo();
batchCommand.undo();
}
});
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.common.command.CompoundCommand#prepare()
*/
protected boolean prepare() {
return true;
}
/* (non-Javadoc)
* @see org.eclipse.emf.common.command.CompoundCommand#dispose()
*/
public void dispose() {
if(activities != null) {
activities.clear();
}
if(deleteCommandList != null) {
for (Iterator iter = deleteCommandList.iterator(); iter.hasNext();) {
Command cmd = (Command) iter.next();
cmd.dispose();
}
}
if(deleteList != null) {
deleteList.clear();
}
super.dispose();
}
}