/* * JBoss, Home of Professional Open Source. * * See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing. * * See the AUTHORS.txt file distributed with this work for a full listing of individual contributors. */ package org.teiid.designer.core.container; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Set; import org.eclipse.emf.common.command.Command; import org.eclipse.emf.common.command.CompoundCommand; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.edit.command.AddCommand; import org.eclipse.emf.edit.command.CommandParameter; import org.eclipse.emf.edit.command.CopyCommand; import org.eclipse.emf.edit.domain.EditingDomain; import org.teiid.core.designer.ModelerCoreException; import org.teiid.designer.core.FindRelatedObjectsToBeCopied; import org.teiid.designer.core.ModelerCore; import org.teiid.designer.core.util.ModelVisitorProcessor; import org.teiid.designer.metamodels.core.Annotation; import org.teiid.designer.metamodels.transformation.MappingClassSet; import org.teiid.designer.metamodels.transformation.TransformationMappingRoot; /** * CloneCommand * * @since 8.0 */ public class CloneCommand extends CompoundCommand { /** * This creates a command that clones the given collection of objects. */ public static Command create(EditingDomain domain, final EObject objectToBeCloned) { if (domain == null) { CloneCommand command = new CloneCommand(domain, objectToBeCloned); return command; } Command command = domain.createCommand(CloneCommand.class, new CommandParameter(null, null, objectToBeCloned)); return command; } /** * This creates a command that clones the given collection of objects. */ public static Command create(EditingDomain domain, final Collection objectsToBeCloned) { if (domain == null) { CloneCommand command = new CloneCommand(domain, objectsToBeCloned); return command; } Command command = domain.createCommand(CloneCommand.class, new CommandParameter(null, null, objectsToBeCloned)); return command; } private final EditingDomain domain; private final Collection objectsToBeCloned; private final CopyCommand.Helper helper; private final Collection results; /** * Construct an instance of CloneCommand. * @param domain the editing domain; may not be null * @param objectToBeCloned the object that is to be cloned one time */ public CloneCommand( final EditingDomain domain, final EObject objectToBeCloned ) { this(domain,Collections.singletonList(objectToBeCloned)); } /** * Construct an instance of CloneCommand. * @param domain the editing domain; may not be null * @param objectsToBeCloned the list of objects that are to be cloned one time */ public CloneCommand( final EditingDomain domain, final Collection objectsToBeCloned ) { super(); this.domain = domain; this.objectsToBeCloned = objectsToBeCloned; this.helper = new CopyCommand.Helper(); this.results = new HashSet(); } public CopyCommand.Helper getHelper() { return this.helper; } /** * Construct the commands in this compound command. * @see org.eclipse.emf.common.command.CompoundCommand#prepare() */ @Override protected boolean prepare() { // Ensure there are objects to be cloned ... if ( this.objectsToBeCloned == null || this.objectsToBeCloned.isEmpty() ) { return false; } return true; } /** * @see org.eclipse.emf.common.command.CompoundCommand#execute() */ @Override public void execute() { this.commandList.clear(); addCommandsToClone(this.objectsToBeCloned,true); if ( this.domain instanceof ContainerEditingDomain ) { // ------------------------------------------------------ // Now, see if there are additional things to be done ... // ------------------------------------------------------ // Iterate through the original objects, and find any additional objects that should be copied ... final FindRelatedObjectsToBeCopied visitor = new FindRelatedObjectsToBeCopied(); final ModelVisitorProcessor processor = new ModelVisitorProcessor(visitor); try { processor.walk(this.objectsToBeCloned,ModelVisitorProcessor.DEPTH_INFINITE); } catch (ModelerCoreException e) { ModelerCore.Util.log(e); } // See if there are any additional objects to be copied ... final Collection additionalObjs = visitor.getAdditionalObjects(); if ( additionalObjs.size() != 0 ) { addCommandsToClone(additionalObjs,false); } } } /** * @see org.eclipse.emf.common.command.CompoundCommand#getResult() */ @Override public Collection getResult() { return this.results; } protected void addCommandsToClone(final Collection objectsToClone, final boolean addToResults ) { // Walk through the objects to be cloned, and construct the appropriate command(s) ... if (! objectsToClone.isEmpty() ) { // Find all of the annotations and transformations ... final Set annotations = new HashSet(); final Set transformations = new HashSet(); final Set mappingClassSets = new HashSet(); final List remaining = new LinkedList(); for (final Iterator it = objectsToClone.iterator(); it.hasNext();) { final Object additionalObj = it.next(); if ( additionalObj instanceof Annotation ) { annotations.add(additionalObj); } else if ( additionalObj instanceof TransformationMappingRoot ) { transformations.add(additionalObj); } else if ( additionalObj instanceof MappingClassSet ) { mappingClassSets.add(additionalObj); } else { remaining.add(additionalObj); } } // Create the copy command for all of the annotations ... if ( annotations.size() != 0 ) { cloneAndAdd(annotations, addToResults); } // Create the copy command for all of the mapping class sets ... if ( mappingClassSets.size() != 0 ) { cloneAndAdd(mappingClassSets, addToResults); } // Create the copy command for all of the transformations ... if ( transformations.size() != 0 ) { cloneAndAdd(transformations, addToResults); } // Create the copy command for the remaining objects if ( remaining.size() != 0 ) { cloneAndAdd(remaining, addToResults); } } } protected void cloneAndAdd(final Collection objectsToClone, final boolean addToResults) { for (final Iterator it = objectsToClone.iterator(); it.hasNext();) { final Object obj = it.next(); if ( obj instanceof EObject ) { final EObject eObject = (EObject)obj; // Copy this object (use a helper) ... final Command copyCommand = domain.createCommand(CopyCommand.class, new CommandParameter(eObject, null, helper)); final boolean copied = this.appendAndExecute(copyCommand); if ( copied ) { final Collection copiedObjects = copyCommand.getResult(); if ( addToResults ) { this.results.addAll(copiedObjects); } // See where the original object lived final EObject parent = eObject.eContainer(); if ( parent != null ) { // And then add the new copy under the parent using the same feature as the original ... final EReference reference = eObject.eContainmentFeature(); if(reference != null && reference.isMany() ){ final List values = (List) parent.eGet(reference); if(values instanceof EList){ final int index = values.indexOf(eObject) + 1; final Command addCommand = AddCommand.create(this.domain,parent,reference,copiedObjects,index); this.appendAndExecute(addCommand); } } } else { // There is no parent, so it might be a root-level object ... final Resource resource = eObject.eResource(); if ( resource != null ) { // Simply add the object to the end of the resource ... // (This relies upon the editing domain to handle adding root objects!) final List roots = resource.getContents(); final int index = roots.indexOf(eObject)+1; final Command addCommand = AddCommand.create(this.domain,resource,null,copiedObjects,index); this.appendAndExecute(addCommand); } // else, not in a resource, so don't know what to do with it! } } } } } }