package com.sap.furcas.ide.editor.deepcopy; /** * A strategy combining several deep copy, drag&drop and copy&paste related * algorithms. This class is intended to be subclassed to add metamodel * specific behavior. * <p> * To automatically use your subclass instead of this generic implementation, * adapt EObject and GenericRefObjectNode for your metamodel to * {@link IModelTransferExtender} and {@link IModelTransferTarget}. * </p> * * The generic implementation will copy model compositions and * dependent linked composition as well as the decorating root TextBlocks. * * Dependent refers to the fact that an association with fixed upper * multiplicity on a full-copied association end also requires a full copy of * the other end. If the other side would not be copied and only referenced, a * link would need to be establish between the referenced and the copied * element. This could violate the multiplicity constraints as there is already * a link between the referenced and the original element. * <p> * <b>Attention:</b> This copy policy can lead to intrusive model changes in the source * model due to link establishment. * </p> * @author D049157 * */ public class GenericModelCopyStrategy /* extends DefaultModelTransferTarget implements DeepCopyPolicyHandler, IModelTransferExtender<EObject> */ { // // /** // * Returns the copy policy as defined by this class // */ // @Override // public DeepCopyPolicyHandler getDeepCopyPolicyHandler() { // return this; // } // // @Override // public DeepCopyPolicy getDeepCopyingPolicy(EObject sourceElement, DeepCopyPolicy defaultPolicy, DeepCopyMap copyMap) { // ResourceSet co = sourceElement.get___Connection(); // // // ask subclass // DeepCopyPolicy customPolicy = getMetaModelSpecificMapping(sourceElement, copyMap); // if (customPolicy != null) { // return customPolicy; // } // // // Always copy composite elements as proposed // if (defaultPolicy.getDeepCopyPolicyOption() == DeepCopyPolicyOption.FULL_COPY) { // return defaultPolicy; // } // // // for all association ends // for (EReference elemAssocEnd : getAssociationEnds(co, sourceElement)) { // // // if there is a reference // EReference sourceAssoc = getRefAssociationForEnd(co, elemAssocEnd); // if (sourceAssoc != null) { // // // for all linked elements // Collection<EObject> elements = getElementsForRefAssociation(co, sourceAssoc, elemAssocEnd, sourceElement); // for (EObject associatedElement : elements) { // // // if element has already been visited // if (copyMap.containsKey(associatedElement)) { // DeepCopyMappingEntry entry = copyMap.get(associatedElement); // DeepCopyPolicyOption associatedElementPolicy = entry.getModifiedPolicy().getDeepCopyPolicyOption(); // // // prevent constraint errors due to fixed upper mulitiplicity // if (associatedElementPolicy == DeepCopyPolicyOption.FULL_COPY // && !(elemAssocEnd.getEOpposite().getUpperBound() == MULTIPLICITY_BOUND_INFINITE)) { // // // storage MIGHT indicate how to resolve the error situation // if (co.getJmiHelper().isEndStored(elemAssocEnd.otherEnd())) { // // System.out.println("COPY due to MULT-STORAGE: + sourceElement.getClass().getName() + " as " + elemAssocEnd.getName() + " via FULL_COPY of " + associatedElement.getClass().getName()); // return new DeepCopyPolicy(DeepCopyPolicyOption.FULL_COPY, null); // } else { // // System.out.println("STOP due to MULTIPLICITY: " + sourceElement.getClass().getName() + " as " + elemAssocEnd.getName() + " via FULL_COPY of " + associatedElement.getClass().getName()); // return new DeepCopyPolicy(DeepCopyPolicyOption.STOP, null); // } // } // } // } // } else { // System.err.println("No RefAssoc for " + sourceElement.getClass().getName() + " on " + elemAssocEnd.getName()); // } // } // return defaultPolicy; // } // // /** // * Template method for metamodel specific behavior. Called by // * {@link GenericModelCopyStrategy#getDeepCopyingPolicy(EObject, DeepCopyPolicy, DeepCopyMap)} // * // * @param sourceElement // * @param copyMap // * @return // */ // protected DeepCopyPolicy getMetaModelSpecificMapping(EObject sourceElement, DeepCopyMap copyMap) { // return null; // } // // /** // * Template method for metamodel specific behavior. Used to prepare a copy // * before it is hooked into the composite parent structure of the target element. // * // * This class is not called during a deep copy operation but only afterwards. // * It can be used to e.g rename a ModelElement to avoid name clashes. // * // * @param identifier, unique identifier that can be used within the target environment // * to create unique names // * @param target // * @param copy // * @return false if the given copy should NOT be linked // */ // public Boolean prepareLinkingToCompositeParent(String identifier, EObject target, EObject copy) { // return true; // } // // /** // * <p> // * A hook for custom logic in the paste step of a copy/paste operation or on // * drop. Typically this includes inserting the transferred objects to a // * composition hierarchy and a partition. // * </p> // * <p> // * The default implementation tries to add the given objects to the given // * target as composite children, if this one is a {@link EObject}. If // * multiple matching {@link Association associations} are available, the // * user is asked to choose one. // * </p> // * <b>Mind:</b> By default this method does not make use of // * {@link #prepareLinkingToCompositeParent(String, EObject, EObject)} // */ // @Override // public Collection<Resource> handleTransfer(Object target, EObject[] objectsToTransfer, IModelTransferLog log) // throws OperationCanceledException { // return super.handleTransfer(target, objectsToTransfer, log); // } // // /** // * Called by copy&paste and drag&drop code and is required to include // * TextBlocks of underlying model elements of copied tree nodes. // * <p> // * Extends the original set of objects to transfer. Called for each object // * of the set that has a matching type. If e.g. an extender is registered // * for Mof classes, it will be called once for each class in the set. // * Duplicate results are merged. The <code>originalObjects</code> set, // * however, stays the same. // * </p> // * @param toExtend // * the object for which additional objects can be returned // * @param originalObjects // * the original objects, usually a selection in the workbench // * // * @return additional objects to be included in the transfer set // */ // @Override // public EObject[] getAdditionalObjects(EObject toExtend, EObject[] originalObjects) { // if (toExtend instanceof EObject) { // EObject refObj = toExtend; // ResourceSet con = refObj.get___Connection(); // TextblocksPackage tbPackage = con.getPackage(TextblocksPackage.PACKAGE_DESCRIPTOR); // Collection<DocumentNode> nodes = tbPackage.getDocumentNodeReferencesCorrespondingModelElement() // .getDocumentNode(refObj); // // Collection<EObject> rootNodes = new ArrayList<EObject>(); // for (DocumentNode node : nodes) { // // Only include root TextBlocks // if (node.refImmediateComposite() == null) { // rootNodes.add(node); // } // } // return rootNodes.toArray(new EObject[rootNodes.size()]); // } // return new EObject[] {}; // } }