/******************************************************************************* * Copyright (c) 2006-2012 * Software Technology Group, Dresden University of Technology * DevBoost GmbH, Berlin, Amtsgericht Charlottenburg, HRB 140026 * * 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: * Software Technology Group - TU Dresden, Germany; * DevBoost GmbH - Berlin, Germany * - initial API and implementation ******************************************************************************/ package org.reuseware.coconut.fragment.util; import java.util.Collection; import java.util.Iterator; import org.eclipse.emf.common.notify.Adapter; import org.eclipse.emf.common.util.BasicEList; import org.eclipse.emf.common.util.ECollections; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EStructuralFeature.Setting; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.emf.ecore.util.EcoreUtil.Copier; /** * Utility class to record and retrieve tracing information for EObjects that * participate in a composition by Reuseware. */ public final class SyncEcoreUtil { private SyncEcoreUtil() { } /** * Record information about the relationship of original EObjects * and their copies in a certain context (e.g., a composition program execution). * * @param copier the <code>EcoreUtil.Copier</code> that was used for copying EObjects * @param contextObject object identifying the context in which the copies were produced * (e.g., a composition program) */ public static void syncCopy(Copier copier, EObject contextObject) { for (EObject original : copier.keySet()) { EObject copy = copier.get(original); boolean isCopy = true; while (isCopy) { isCopy = false; for (Adapter a : original.eAdapters()) { if (a instanceof CopiedFromAdapter) { original = ((CopiedFromAdapter) a).getOriginal(); isCopy = true; break; } } } //the copier might contain values which are not "real" copies if (!copy.equals(original)) { copy.eAdapters().add(new CopiedFromAdapter(original, contextObject)); } } } /** * Returns the EObject from which the given copy was created. * * @param copy the copy * @return the original */ public static EObject getOriginal(EObject copy) { if (copy == null) { return null; } for (Adapter a : copy.eAdapters()) { if (a instanceof CopiedFromAdapter) { return ((CopiedFromAdapter) a).getOriginal(); } } return null; } /** * Returns the EObject that was created as copy of the given original in * the given context. * * @param original the original * @param contextObject the context in which the copy was produced * @param copieContainers collections of EObjects containing copies as children * @return the copy */ public static EObject getCopy(EObject original, EObject contextObject, Collection<EObject> copieContainers) { if (original == null) { return null; } //maybe the original is already a copy, because we are composing a composed fragment //--> exchange "original" for the real original for (Adapter a : original.eAdapters()) { if (a instanceof CopiedFromAdapter) { original = ((CopiedFromAdapter) a).getOriginal(); break; } } for (Iterator<EObject> copyIt = EcoreUtil.getAllContents(copieContainers); copyIt.hasNext();) { EObject copy = copyIt.next(); for (Adapter a : copy.eAdapters()) { if (a instanceof CopiedFromAdapter) { CopiedFromAdapter cfa = (CopiedFromAdapter) a; if (contextObject == null || contextObject.equals(cfa.getContextObject())) { if (original.equals(cfa.getOriginal())) { return copy; } } } } } return null; } /** * Returns all EObjects that were created as copy of the given original in * independent of a context objects. * * * @param original the original * @param copieContainers collections of EObjects containing copies as children * @return the copies */ public static EList<EObject> getAllCopies(EObject original, Collection<EObject> copieContainers) { EList<EObject> resultList = new BasicEList<EObject>(); if (original == null) { return resultList; } //maybe the original is already a copy, because we are composing a composed fragment //--> exchange "original" for the real original for (Adapter a : original.eAdapters()) { if (a instanceof CopiedFromAdapter) { original = ((CopiedFromAdapter) a).getOriginal(); break; } } for (Iterator<EObject> copyIt = EcoreUtil.getAllContents(copieContainers); copyIt.hasNext();) { EObject copy = copyIt.next(); for (Adapter a : copy.eAdapters()) { if (a instanceof CopiedFromAdapter) { CopiedFromAdapter cfa = (CopiedFromAdapter) a; if (original.equals(cfa.getOriginal())) { resultList.add(copy); } } } } return resultList; } /** * Finds EObjects that were replaced by the given replacement EObject during composition. * * @param replacement the EObject that replaced others * @return the replaced EObjects */ public static EList<EObject> getReplacedValues(EObject replacement) { if (replacement == null) { return ECollections.emptyEList(); } for (Adapter a : replacement.eAdapters()) { if (a instanceof ReplacementForAdapter) { return ((ReplacementForAdapter) a).getReplacedValues(); } } return ECollections.emptyEList(); } /** * Finds the setting from which the given EObject was removed during composition. * * @param removed the EObject that was removed from some setting * @return the setting from which the EObject was removed */ public static Setting getRemovedFromSetting(EObject removed) { if (removed == null) { return null; } for (Adapter a : removed.eAdapters()) { if (a instanceof ReplacementForAdapter) { return ((ReplacementForAdapter) a).getRemovedFromSetting(); } } return null; } /** * Removes all EObjects that were replaced by other ones from the * containment hierarchy of the given containers. This method is * used to clean slot elements (which are replaced in * non-containment references only) from the contents of a * composed fragment. * * @param containers root EObjects of the containment hierarchy to be cleaned */ public static void removeReplaced(EList<EObject> containers) { EList<EObject> replacedList = new BasicEList<EObject>(); for (Iterator<EObject> it = EcoreUtil.getAllContents(containers); it.hasNext();) { EObject element = it.next(); replacedList.addAll(getReplacedValues(element)); } for (EObject replaced : replacedList) { EcoreUtil.remove(replaced); } } /** * Marks a replaced EObject as replacement of another EObject. * This method is called to record trace information. * * @param replacement the EObject that is the replacement for another EObject * @param replaced the EObject that was replaced */ public static void markAsReplacement(EObject replacement, EObject replaced) { if (replacement == null || replaced == null) { return; } ReplacementForAdapter rfa = null; for (Iterator<Adapter> adapterIt = replacement.eAdapters().iterator(); adapterIt.hasNext();) { Adapter a = adapterIt.next(); if (a instanceof ReplacementForAdapter) { rfa = (ReplacementForAdapter) a; } } if (rfa == null) { rfa = new ReplacementForAdapter(); replacement.eAdapters().add(rfa); } if (!rfa.getReplacedValues().contains(replaced)) { rfa.getReplacedValues().add(replaced); } } /** * Marks a removed EObject as removed from a certain setting. * This method is called to record trace information. * * @param removed the EObject that was removed from a setting * @param removedFromSetting the setting the EObject was removed from */ public static void markAsRemovedFrom(EObject removed, Setting removedFromSetting) { if (removed == null || removedFromSetting == null) { return; } ReplacementForAdapter rfa = null; for (Iterator<Adapter> adapterIt = removed.eAdapters().iterator(); adapterIt.hasNext();) { Adapter a = adapterIt.next(); if (a instanceof ReplacementForAdapter) { rfa = (ReplacementForAdapter) a; } } if (rfa == null) { rfa = new ReplacementForAdapter(); removed.eAdapters().add(rfa); } rfa.setRemovedFromSetting(removedFromSetting); } }