/*
* 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!
}
}
}
}
}
}