//------------------------------------------------------------------------------ // 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.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Status; import org.eclipse.emf.common.notify.AdapterFactory; import org.eclipse.emf.common.util.AbstractTreeIterator; import org.eclipse.emf.ecore.EAttribute; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.xml.type.XMLTypePackage.Literals; import org.eclipse.emf.edit.provider.ITreeItemContentProvider; import org.eclipse.epf.library.edit.IConfigurator; import org.eclipse.epf.library.edit.LibraryEditPlugin; import org.eclipse.epf.library.edit.LibraryEditResources; import org.eclipse.epf.library.edit.TngAdapterFactory; import org.eclipse.epf.library.edit.ui.IActionTypeProvider; import org.eclipse.epf.library.edit.ui.UserInteractionHelper; import org.eclipse.epf.library.edit.util.ActivityHandler; import org.eclipse.epf.library.edit.util.ExtensionManager; import org.eclipse.epf.library.edit.util.IResourceScanner; import org.eclipse.epf.library.edit.util.IRunnableWithProgress; import org.eclipse.epf.library.edit.util.ITextReferenceReplacer; import org.eclipse.epf.library.edit.util.ProcessUtil; import org.eclipse.epf.library.edit.util.ResourceFileCopyHandler; import org.eclipse.epf.library.edit.util.Suppression; import org.eclipse.epf.library.edit.util.TngUtil; import org.eclipse.epf.library.edit.validation.DependencyChecker; import org.eclipse.epf.uma.Activity; import org.eclipse.epf.uma.BreakdownElement; import org.eclipse.epf.uma.CapabilityPattern; import org.eclipse.epf.uma.DeliveryProcess; import org.eclipse.epf.uma.DescribableElement; import org.eclipse.epf.uma.Descriptor; import org.eclipse.epf.uma.MethodConfiguration; import org.eclipse.epf.uma.MethodElement; import org.eclipse.epf.uma.MethodPackage; import org.eclipse.epf.uma.MethodPlugin; import org.eclipse.epf.uma.Process; import org.eclipse.epf.uma.ProcessPackage; import org.eclipse.epf.uma.TeamProfile; import org.eclipse.epf.uma.util.UmaUtil; /** * Drop command for activity that supports extend, copy, and deep copy. * * @author Phong Nguyen Le * @since 1.0 */ public class ActivityDropCommand extends BSDropCommand { private Object viewer; private List<CapabilityPattern> oldPatterns; private List<CapabilityPattern> patterns; protected Process targetProcess; private boolean isDeliveryProcess; private int type; private Collection<Activity> appliedActivities; protected AdapterFactory adapterFactory; protected ActivityHandler activityHandler; protected boolean preExecuted; protected HashSet<?> addedObjects; protected IConfigurator activityDeepCopyConfigurator; private ResourceFileCopyHandler resourceFileCopyHandler; public ActivityDropCommand(Activity target, List activities, Object viewer, AdapterFactory adapterFactory) { super(target, activities); setLabel(LibraryEditResources.ActivityDropCommand_label); this.viewer = viewer; this.adapterFactory = adapterFactory; targetProcess = TngUtil.getOwningProcess(target); isDeliveryProcess = targetProcess instanceof DeliveryProcess; if (isDeliveryProcess) { oldPatterns = new ArrayList(((DeliveryProcess) targetProcess) .getIncludesPatterns()); } initResouceFileCopyHandler(activities); } private void initResouceFileCopyHandler(List activities) { if (activities != null && ! activities.isEmpty() && activities.get(0) instanceof BreakdownElement) { BreakdownElement dropElement0 = (BreakdownElement) activities.get(0); MethodPlugin srcPlugin = UmaUtil.getMethodPlugin(targetProcess); MethodPlugin tgtPlugin = UmaUtil.getMethodPlugin(dropElement0); boolean toCreateHandler = true; if (srcPlugin == tgtPlugin) { Process sourceProcess = TngUtil.getOwningProcess(dropElement0); boolean sIsDeliveryProcess = sourceProcess instanceof DeliveryProcess; if (isDeliveryProcess == sIsDeliveryProcess) { toCreateHandler = false; } } if (toCreateHandler) { ITextReferenceReplacer txtRefReplacer = ExtensionManager.getTextReferenceReplacer(); if (txtRefReplacer != null) { IResourceScanner resourceScanner = txtRefReplacer.getResourceScanner(); resourceScanner.init(srcPlugin, tgtPlugin); resourceFileCopyHandler = new ResourceFileCopyHandler(resourceScanner); } } } } /** * If textual descriptions in the copied elements contain references (URLs) * to other elements within the same copied process then replace these * references with references that point to the new elements in the copied * structures. */ private Collection replaceTextReferences(Map<MethodElement, MethodElement> originalToCopyMap_ ) { Collection modifiedResources = new HashSet(); ITextReferenceReplacer txtRefReplacer = ExtensionManager .getTextReferenceReplacer(); if (txtRefReplacer == null) return modifiedResources; for (Map.Entry<MethodElement, MethodElement> entry: originalToCopyMap_.entrySet()) { if (entry.getValue() instanceof BreakdownElement) { EObject element = (EObject) entry.getValue(); for (Iterator childIter = element.eAllContents(); childIter .hasNext();) { EObject child = (EObject) childIter.next(); for (Iterator attributes = child.eClass() .getEAllAttributes().iterator(); attributes .hasNext();) { EAttribute attribute = (EAttribute) attributes.next(); if (attribute.isChangeable() && !attribute.isDerived() && (attribute.isMany() || child .eIsSet(attribute)) && attribute.getEAttributeType() .getInstanceClass() == Literals.STRING .getInstanceClass()) { String text = (String) child.eGet(attribute); if (text != null) { String newtext = txtRefReplacer.replace(text, child, originalToCopyMap_); if (!newtext.equals(text)) { child.eSet(attribute, newtext); modifiedResources.add(child.eResource()); } } } } } } } originalToCopyMap_ = null; return modifiedResources; } public ActivityDropCommand(Activity target, List activities, Object viewer, AdapterFactory adapterFactory,IConfigurator deepCopyConfigurator){ this(target, activities, viewer, adapterFactory); this.activityDeepCopyConfigurator = deepCopyConfigurator; } @Override protected void prepareDropElements() { // remove any drop element that is suppress // for (Iterator<?> iter = dropElements.iterator(); iter.hasNext();) { Object element = (Object) iter.next(); Process proc = TngUtil.getOwningProcess(element); if(proc != null) { Suppression supp = Suppression.getSuppression(proc); if(supp.isSuppressed(element)) { iter.remove(); } } } super.prepareDropElements(); } public void setType(int type) { this.type = type; if(type == IActionTypeProvider.DEEP_COPY) { runAsJob = true; } } public IStatus checkCopy() { for (Object e : dropElements) { if(e instanceof Activity) { IStatus status = checkCircular((Activity) e); if(!status.isOK()) { return status; } } } return Status.OK_STATUS; } public IStatus checkExtend() { for (Iterator iter = dropElements.iterator(); iter.hasNext();) { // BreakdownElement element = (BreakdownElement) iter.next(); // // if ((ProcessUtil.hasContributorOrReplacer((Activity) element))){ // canExtend = false; // break; // } // // Process proc = TngUtil.getOwningProcess(element); // if (targetProcess.getVariabilityBasedOnElement() == proc) { // canExtend = false; // break; // } // // if (proc instanceof CapabilityPattern && proc != targetProcess) { // canExtend = true; // break; // } Activity act = (Activity) iter.next(); Process srcProc = TngUtil.getOwningProcess(act); if(srcProc instanceof DeliveryProcess && srcProc != targetProcess) { // cannot extend a different delivery process or any of its activities // return new Status(IStatus.ERROR, LibraryEditPlugin.PLUGIN_ID, 0, LibraryEditResources.cannot_copy_or_extend_delivery_process, null); } IStatus status = checkCircular(act); if(!status.isOK()) { return status; } } return Status.OK_STATUS; } private IStatus checkCircular(Activity act) { boolean result; if (DependencyChecker.newCheckAct) { result = DependencyChecker.checkCircularForMovingVariabilityElement (activity, Collections.singletonList(act), true); } else { result = DependencyChecker.checkCircularDependency(act, activity).isOK(); } if(!result) { return new Status(IStatus.ERROR, LibraryEditPlugin.PLUGIN_ID, 0, LibraryEditResources.circular_dependency_error_msg, null); } return Status.OK_STATUS; } /* * (non-Javadoc) * * @see com.ibm.library.edit.process.command.BSDropCommand#execute() */ public void execute() { IActionTypeProvider actionTypeProvider = (IActionTypeProvider) viewer; if ( viewer != null) { viewer = null; boolean canCopy = checkCopy().isOK(); boolean canExtend = checkExtend().isOK(); int[] choices = new int[1 + (canCopy ? 1 : 0) + (canExtend ? 1 : 0)]; int i = 0; if(canCopy) { choices[i++] = IActionTypeProvider.COPY; } if(canExtend) { choices[i++] = IActionTypeProvider.EXTEND; } choices[i] = IActionTypeProvider.DEEP_COPY; // delegate the execution of this command // actionTypeProvider.execute(this, choices); return; } activityHandler = new ActivityHandler(); try { if (type == IActionTypeProvider.DEEP_COPY) { doDeepCopy(); } else { super.execute(); } } finally { originalToCopyMap = activityHandler.cloneOrignaltoCopyMap(); if (originalToCopyMap != null && !originalToCopyMap.isEmpty()) { Set<Object> excludedKeySet = new HashSet<Object>(); for (Object key : originalToCopyMap.keySet()) { if (! (key instanceof MethodElement)) { excludedKeySet.add(key); } } for (Object key : excludedKeySet) { originalToCopyMap.remove(key); } } activityHandler.dispose(); } if (type == IActionTypeProvider.COPY) { replaceTextReferences(originalToCopyMap); } if(TngUtil.DEBUG) { System.out.println("ActivityDropCommand.execute(): done"); //$NON-NLS-1$ } } /** * */ protected void doDeepCopy() { if(!UserInteractionHelper.confirmDeepCopy(dropElements)) { return; } MethodConfiguration deepCopyConfig = null; try { deepCopyConfig = UserInteractionHelper.chooseDeepCopyConfiguration(targetProcess, adapterFactory); } catch(OperationCanceledException e) { getModifiedResources().clear(); return; } boolean copyExternalVariations; try { copyExternalVariations = UserInteractionHelper.copyExternalVariationsAllowed(targetProcess, adapterFactory); } catch(OperationCanceledException e) { getModifiedResources().clear(); return; } activityHandler.setCopyExternalVariations(copyExternalVariations); activityHandler.setDeepCopyConfig(deepCopyConfig); activityHandler.setTargetProcess(targetProcess); // Set a configurator to resolve and deep copy contributors and replacers activityHandler.setActivityDeepCopyConfigurator(activityDeepCopyConfigurator); IRunnableWithProgress runnable = new IRunnableWithProgress() { public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { activityHandler.setMonitor(monitor); preExecuted = preExecute(); } }; UserInteractionHelper.runWithProgress(runnable, getLabel()); if (preExecuted) { redo(); } } /* * (non-Javadoc) * * @see com.ibm.library.edit.process.command.BSDropCommand#preExecute() */ protected boolean preExecute() { if (!super.preExecute()) return false; // process the selected activities and deep-copy the valid ones // if (isDeliveryProcess) { patterns = new ArrayList<CapabilityPattern>(); } for (Iterator iter = dropElements.iterator(); iter.hasNext();) { Object element = (Object) iter.next(); if ((element instanceof Activity) // && element != target ) { Activity act = (Activity) element; // if(type == IActionTypeProvider.DEEP_COPY) { // activityHandler.deepCopy(act); // } // else { // Process proc = TngUtil.getOwningProcess(act); // if (proc instanceof CapabilityPattern && proc != targetProcess) { // if (type == IActionTypeProvider.EXTEND) { // activityHandler.extend(act); // if (patterns != null) // patterns.add(proc); // } else { // activityHandler.copy(act); // } // } else { // activityHandler.copy(act); // } // } switch(type) { case IActionTypeProvider.DEEP_COPY: activityHandler.deepCopy(element); break; case IActionTypeProvider.EXTEND: activityHandler.extend(act); if (patterns != null) { Process proc = TngUtil.getOwningProcess(act); if(proc instanceof CapabilityPattern) { patterns.add((CapabilityPattern) proc); } } break; case IActionTypeProvider.COPY: activityHandler.copy(act); break; } } } appliedActivities = new ArrayList<Activity>(activityHandler.getActivities()); return !appliedActivities.isEmpty(); } /* * (non-Javadoc) * * @see com.ibm.library.edit.process.command.BSDropCommand#doExecute() */ protected void doExecute() { Iterator<Activity> itor = appliedActivities.iterator(); ProcessPackage pkg = (ProcessPackage) activity.eContainer(); while (itor.hasNext()) { Activity act = (Activity) itor.next(); if (act.eContainer() != null && act.eContainer().eContainer() != pkg) { pkg.getChildPackages().add((MethodPackage) act.eContainer()); } if (patterns != null && !patterns.isEmpty()) { DeliveryProcess proc = (DeliveryProcess) targetProcess; for (CapabilityPattern pattern : patterns) { if (!proc.getIncludesPatterns().contains(pattern)) { proc.getIncludesPatterns().add(pattern); } } } } long time = 0; if(TngUtil.DEBUG) { time = System.currentTimeMillis(); } activity.getBreakdownElements().addAll(appliedActivities); if(TngUtil.DEBUG) { System.out.println("ActivityDropCommand.doExecute(): new activities added. " + (System.currentTimeMillis() - time)); //$NON-NLS-1$ } if(!activityHandler.getDeepCopies().isEmpty()) { if(TngUtil.DEBUG) { time = System.currentTimeMillis(); } postDeepCopy(); if(TngUtil.DEBUG) { System.out.println("ActivityDropCommand.doExecute(): postDeepCopy(). " + (System.currentTimeMillis() - time)); //$NON-NLS-1$ } } // Hack to refresh providers forcefully before calling fixDuplicateNames ITreeItemContentProvider adapter = (ITreeItemContentProvider) adapterFactory.adapt(activity, ITreeItemContentProvider.class); adapter.getChildren(activity); // fix duplicate names of newly added elements fixDuplicateNames(); getModifiedResources().add(activity.eResource()); } /** * */ private void postDeepCopy() { Runnable runnable = new Runnable() { public void run() { // add to default configuratation of the target process any missing content // if(addedObjects == null) { addedObjects = new HashSet(); } else { addedObjects.clear(); } boolean defaultConfigChanged = false; // // disable notification on change to default configuration of target process to avoid excessive UI refreshes // // // boolean oldNotify = targetProcess.getDefaultContext().eDeliver(); // targetProcess.getDefaultContext().eSetDeliver(false); // try { for (Iterator iter = activityHandler.getDeepCopies().iterator(); iter.hasNext();) { Iterator iterator = new AbstractTreeIterator(iter.next()) { /** * Comment for <code>serialVersionUID</code> */ private static final long serialVersionUID = 1L; protected Iterator getChildren(Object object) { if(object instanceof Activity) { return ((Activity)object).getBreakdownElements().iterator(); } return Collections.EMPTY_LIST.iterator(); } }; while(iterator.hasNext()) { Object e = iterator.next(); if(e instanceof Descriptor) { MethodElement me = ProcessUtil.getAssociatedElement((Descriptor) e); int size = addedObjects.size(); ProcessUtil.addToDefaultConfiguration(targetProcess, me, addedObjects); if(!defaultConfigChanged && (size != addedObjects.size())) { if (targetProcess.getDefaultContext() != null && targetProcess.getDefaultContext() .eResource() != null) { getModifiedResources().add( targetProcess.getDefaultContext() .eResource()); } defaultConfigChanged = true; } } } } // } // finally { // targetProcess.getDefaultContext().eSetDeliver(oldNotify); // } } }; UserInteractionHelper.runWithProgress(runnable, getLabel()); // synchronize the deep copies with default configuration of the target process // final SynchronizeCommand synchCmd = new SynchronizeCommand(activityHandler.getDeepCopies(), targetProcess.getDefaultContext(), null, false); try { runnable = new Runnable() { public void run() { synchCmd.initilize(); } }; UserInteractionHelper.runWithProgress(runnable, LibraryEditResources.ProcessAutoSynchronizeAction_prepare); if(synchCmd.isIntialized()) { synchCmd.execute(); } } finally { synchCmd.dispose(); } } protected Suppression getSuppression() { return Suppression.getSuppression(targetProcess); } /** * Fixes duplicate names of newly added elements */ private void fixDuplicateNames() { Suppression suppression = getSuppression(); for (Iterator iter = appliedActivities.iterator(); iter.hasNext();) { Activity act = (Activity) iter.next(); fixDuplicateNames(act, suppression); fixTeamProfileDuplicateNames(act, suppression); } } private void fixDuplicateNames(BreakdownElement e, Suppression suppression) { fixDuplicateNames(e, suppression, adapterFactory); } private static void fixDuplicateNames(BreakdownElement e, Suppression suppression, AdapterFactory adapterFactory) { String baseName = e.getName(); if (ProcessUtil.checkBreakdownElementName(adapterFactory, e, baseName, suppression) != null) { for (int i = 1; true; i++) { String name = baseName + '_' + i; if (ProcessUtil.checkBreakdownElementName(adapterFactory, e, name, suppression) == null) { e.setName(name); break; } } } baseName = ProcessUtil.getPresentationName(e); if (ProcessUtil.checkBreakdownElementPresentationName(adapterFactory, e, baseName, suppression) != null) { for (int i = 1; true; i++) { String name = baseName + '_' + i; if (ProcessUtil.checkBreakdownElementPresentationName(adapterFactory, e, name, suppression) == null) { e.setPresentationName(name); break; } } } } private void fixTeamProfileDuplicateNames(Activity act, Suppression suppression) { for (int i = act.getBreakdownElements().size() - 1; i > -1; i--) { Object element = act.getBreakdownElements().get(i); if(element instanceof TeamProfile) { fixDuplicateNames((BreakdownElement) element, suppression, TngAdapterFactory.INSTANCE.getOBS_ComposedAdapterFactory()); } else if(element instanceof Activity) { fixTeamProfileDuplicateNames((Activity) element, suppression); } } } /* * (non-Javadoc) * * @see com.ibm.library.edit.process.command.BSDropCommand#doUndo() */ protected void doUndo() { activity.getBreakdownElements().removeAll(appliedActivities); if (isDeliveryProcess) { DeliveryProcess proc = (DeliveryProcess) targetProcess; proc.getIncludesPatterns().clear(); proc.getIncludesPatterns().addAll(oldPatterns); } } public static void setName(List siblings, Activity e) { String baseName = e.getName(); if (!isNameTaken(siblings, e, baseName)) { return; } for (int i = 1; true; i++) { String name = baseName + '_' + i; if (!isNameTaken(siblings, e, name)) { e.setName(name); return; } } } public static void setDefaultPresentationName(List siblings, Activity e) { // if(e.getPresentationName() != null && // e.getPresentationName().trim().length() > 0) return; String basePresentationName = ProcessUtil.getPresentationName(e); if (!isPresentationNameTaken(siblings, e, basePresentationName)) { // e.setPresentationName(basePresentationName); return; } for (int i = 1; true; i++) { String name = basePresentationName + '_' + i; if (!isPresentationNameTaken(siblings, e, name)) { e.setPresentationName(name); return; } } } private static boolean isNameTaken(List siblings, DescribableElement e, String name) { for (int i = siblings.size() - 1; i > -1; i--) { BreakdownElement sibling = (BreakdownElement) siblings.get(i); // if(sibling != e && name.equals(sibling.getPresentationName())) { if (sibling != e && name.equals(sibling.getName())) { return true; } } return false; } private static boolean isPresentationNameTaken(List siblings, DescribableElement e, String name) { for (int i = siblings.size() - 1; i > -1; i--) { BreakdownElement sibling = (BreakdownElement) siblings.get(i); // if(sibling != e && name.equals(sibling.getPresentationName())) { if (sibling != e && name.equals(ProcessUtil.getPresentationName(sibling))) { return true; } } return false; } /* (non-Javadoc) * @see org.eclipse.emf.common.command.AbstractCommand#getAffectedObjects() */ public Collection<?> getAffectedObjects() { if(executed) { return appliedActivities; } else { return Collections.EMPTY_LIST; } } /* (non-Javadoc) * @see org.eclipse.emf.common.command.AbstractCommand#getResult() */ public Collection<?> getResult() { return getAffectedObjects(); } public ActivityHandler getActivityHandler() { return activityHandler; } public Activity getActivity(){ return activity; } public int getType(){ return type; } public void setActivityDeepCopyConfigurator( IConfigurator activityDeepCopyConfigurator) { this.activityDeepCopyConfigurator = activityDeepCopyConfigurator; } private Map originalToCopyMap; public void scanAndCopyResources() { if (resourceFileCopyHandler == null) { return; } try { resourceFileCopyHandler.execute(originalToCopyMap); } catch (Throwable e){ LibraryEditPlugin.getDefault().getLogger().logError(e); } finally { resourceFileCopyHandler.getScanner().init(null, null); originalToCopyMap = null; } } public ResourceFileCopyHandler getResourceFileCopyHandler() { return resourceFileCopyHandler; } }