blob: 7a39959af59af7d4b06f3873588d0e42411ee383 [file] [log] [blame]
package org.eclipse.emf.edapt.declaration.replacement;
import java.util.List;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.edapt.declaration.EdaptConstraint;
import org.eclipse.emf.edapt.declaration.EdaptOperation;
import org.eclipse.emf.edapt.declaration.EdaptParameter;
import org.eclipse.emf.edapt.declaration.OperationImplementation;
import org.eclipse.emf.edapt.internal.common.MetamodelFactory;
import org.eclipse.emf.edapt.spi.migration.Instance;
import org.eclipse.emf.edapt.spi.migration.Metamodel;
import org.eclipse.emf.edapt.spi.migration.Model;
/**
* {@description}
*
* @author herrmama
* @author $Author$
* @version $Rev$
* @levd.rating YELLOW Hash: EFEF0E6FC56A2B1350A5596C8D6C8060
*/
@EdaptOperation(identifier = "introduceReferenceClass", label = "Association to Class", description = "In the metamodel, a reference is replaced by a reference class. More specifically, the reference class is now contained by the source class. In the model, links conforming to the reference are replaced by instances of the reference class.")
public class IntroduceReferenceClass extends OperationImplementation {
/** {@description} */
@EdaptParameter(main = true, description = "The reference to be replaced by a reference class")
public EReference reference;
/** {@description} */
@EdaptParameter(description = "The name of the reference class")
public String className;
/** {@description} */
@EdaptParameter(description = "The name of the opposite reference to the source class", optional = true)
public String sourceReferenceName;
/** {@description} */
@EdaptParameter(description = "The name of the opposite reference to the target class", optional = true)
public String targetReferenceName;
/** {@description} */
@EdaptConstraint(description = "Reference has to have an opposite")
public boolean checkReferenceOpposite() {
return reference.getEOpposite() != null;
}
/** {@description} */
@EdaptConstraint(description = "Opposite reference is not allowed to be containment")
public boolean checkOppositeNotContainment() {
return reference.getEOpposite() == null
|| !reference.getEOpposite().isContainment();
}
/** {@description} */
@EdaptConstraint(description = "Reference is not allowed to be containment")
public boolean checkReferenceNotContainment() {
return !reference.isContainment();
}
/** {@inheritDoc} */
@Override
public void execute(Metamodel metamodel, Model model) {
// variables
final EReference opposite = reference.getEOpposite();
// metamodel adaptation
final EClass sourceClass = reference.getEContainingClass();
final EClass targetClass = reference.getEReferenceType();
final EPackage contextPackage = sourceClass.getEPackage();
final EClass referenceClass = MetamodelFactory.newEClass(contextPackage,
className);
metamodel.setEOpposite(reference, null);
reference.setEType(referenceClass);
opposite.setEType(referenceClass);
reference.setContainment(true);
// model migration
for (final Instance target : model.getAllInstances(targetClass)) {
target.unset(opposite);
}
for (final Instance source : model.getAllInstances(sourceClass)) {
if (reference.isMany()) {
for (final Instance target : source.<List<Instance>> unset(reference)) {
final Instance referenceInstance = model
.newInstance(referenceClass);
source.add(reference, referenceInstance);
put(target, opposite, referenceInstance);
}
} else {
final Instance target = source.unset(reference);
if (target != null) {
final Instance referenceInstance = model
.newInstance(referenceClass);
source.set(reference, referenceInstance);
put(target, opposite, referenceInstance);
}
}
}
// metamodel adaptation
if (sourceReferenceName != null) {
final EReference sourceReference = MetamodelFactory.newEReference(
referenceClass, sourceReferenceName, sourceClass, 1, 1,
false);
metamodel.setEOpposite(reference, sourceReference);
}
if (targetReferenceName != null) {
final EReference targetReference = MetamodelFactory.newEReference(
referenceClass, targetReferenceName, targetClass, 1, 1,
false);
metamodel.setEOpposite(opposite, targetReference);
}
}
/** Put a value into a reference depending on the multiplicity. */
private void put(Instance target, EReference opposite,
Instance referenceInstance) {
if (opposite.isMany()) {
target.add(opposite, referenceInstance);
} else {
target.set(opposite, referenceInstance);
}
}
}