From 54d0a4563b3c79a5a0a78a5a9d44b6b66043f164 Mon Sep 17 00:00:00 2001
From: Nikolaus Huber <nikolaus.huber@uni-wuerzburg.de>
Date: Mon, 16 Sep 2013 14:28:41 +0000
Subject: [PATCH] git-svn-id:
 https://se1.informatik.uni-wuerzburg.de/usvn/svn/code/code/DMM/trunk@13067
 9e42b895-fcda-4063-8a3b-11be15eb1bbd

---
 .../.classpath                                |   7 +
 .../.project                                  |  28 ++
 .../.settings/org.eclipse.jdt.core.prefs      |   7 +
 .../.settings/org.eclipse.pde.core.prefs      |   4 +
 .../META-INF/MANIFEST.MF                      |  32 ++
 .../build.properties                          |   4 +
 .../model/adaptation/Activator.java           |  30 ++
 .../model/adaptation/IActionHandler.java      |  22 ++
 .../adaptation/dmm/DmmModelActionHandler.java | 320 ++++++++++++++++++
 .../dmm/util/DmmModelActionHelper.java        | 282 +++++++++++++++
 .../adaptation/dmm/util/DmmModelChanger.java  | 304 +++++++++++++++++
 .../adaptation/dmm/util/ObjectivesHelper.java |  65 ++++
 .../dmm/util/OclEvaluationHelper.java         |  89 +++++
 .../exceptions/InvalidAdaptationPlan.java     |  14 +
 .../OperationNotPerformedException.java       |  14 +
 15 files changed, 1222 insertions(+)
 create mode 100644 edu.kit.ipd.descartes.adaptation.model.adaptation/.classpath
 create mode 100644 edu.kit.ipd.descartes.adaptation.model.adaptation/.project
 create mode 100644 edu.kit.ipd.descartes.adaptation.model.adaptation/.settings/org.eclipse.jdt.core.prefs
 create mode 100644 edu.kit.ipd.descartes.adaptation.model.adaptation/.settings/org.eclipse.pde.core.prefs
 create mode 100644 edu.kit.ipd.descartes.adaptation.model.adaptation/META-INF/MANIFEST.MF
 create mode 100644 edu.kit.ipd.descartes.adaptation.model.adaptation/build.properties
 create mode 100644 edu.kit.ipd.descartes.adaptation.model.adaptation/src/edu/kit/ipd/descartes/adaptation/model/adaptation/Activator.java
 create mode 100644 edu.kit.ipd.descartes.adaptation.model.adaptation/src/edu/kit/ipd/descartes/adaptation/model/adaptation/IActionHandler.java
 create mode 100644 edu.kit.ipd.descartes.adaptation.model.adaptation/src/edu/kit/ipd/descartes/adaptation/model/adaptation/dmm/DmmModelActionHandler.java
 create mode 100644 edu.kit.ipd.descartes.adaptation.model.adaptation/src/edu/kit/ipd/descartes/adaptation/model/adaptation/dmm/util/DmmModelActionHelper.java
 create mode 100644 edu.kit.ipd.descartes.adaptation.model.adaptation/src/edu/kit/ipd/descartes/adaptation/model/adaptation/dmm/util/DmmModelChanger.java
 create mode 100644 edu.kit.ipd.descartes.adaptation.model.adaptation/src/edu/kit/ipd/descartes/adaptation/model/adaptation/dmm/util/ObjectivesHelper.java
 create mode 100644 edu.kit.ipd.descartes.adaptation.model.adaptation/src/edu/kit/ipd/descartes/adaptation/model/adaptation/dmm/util/OclEvaluationHelper.java
 create mode 100644 edu.kit.ipd.descartes.adaptation.model.adaptation/src/edu/kit/ipd/descartes/adaptation/model/adaptation/exceptions/InvalidAdaptationPlan.java
 create mode 100644 edu.kit.ipd.descartes.adaptation.model.adaptation/src/edu/kit/ipd/descartes/adaptation/model/adaptation/exceptions/OperationNotPerformedException.java

diff --git a/edu.kit.ipd.descartes.adaptation.model.adaptation/.classpath b/edu.kit.ipd.descartes.adaptation.model.adaptation/.classpath
new file mode 100644
index 00000000..ad32c83a
--- /dev/null
+++ b/edu.kit.ipd.descartes.adaptation.model.adaptation/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/edu.kit.ipd.descartes.adaptation.model.adaptation/.project b/edu.kit.ipd.descartes.adaptation.model.adaptation/.project
new file mode 100644
index 00000000..da16a401
--- /dev/null
+++ b/edu.kit.ipd.descartes.adaptation.model.adaptation/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>edu.kit.ipd.descartes.adaptation.model.adaptation</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/edu.kit.ipd.descartes.adaptation.model.adaptation/.settings/org.eclipse.jdt.core.prefs b/edu.kit.ipd.descartes.adaptation.model.adaptation/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000..c537b630
--- /dev/null
+++ b/edu.kit.ipd.descartes.adaptation.model.adaptation/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,7 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/edu.kit.ipd.descartes.adaptation.model.adaptation/.settings/org.eclipse.pde.core.prefs b/edu.kit.ipd.descartes.adaptation.model.adaptation/.settings/org.eclipse.pde.core.prefs
new file mode 100644
index 00000000..e8ff8be0
--- /dev/null
+++ b/edu.kit.ipd.descartes.adaptation.model.adaptation/.settings/org.eclipse.pde.core.prefs
@@ -0,0 +1,4 @@
+eclipse.preferences.version=1
+pluginProject.equinox=false
+pluginProject.extensions=false
+resolve.requirebundle=false
diff --git a/edu.kit.ipd.descartes.adaptation.model.adaptation/META-INF/MANIFEST.MF b/edu.kit.ipd.descartes.adaptation.model.adaptation/META-INF/MANIFEST.MF
new file mode 100644
index 00000000..44adc257
--- /dev/null
+++ b/edu.kit.ipd.descartes.adaptation.model.adaptation/META-INF/MANIFEST.MF
@@ -0,0 +1,32 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: ModelAdaptor
+Bundle-SymbolicName: edu.kit.ipd.descartes.adaptation.model.adaptation
+Bundle-Version: 1.0.0.qualifier
+Bundle-Activator: edu.kit.ipd.descartes.adaptation.model.adaptation.Activator
+Bundle-Vendor: Descartes Research Group
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Import-Package: 
+ edu.kit.ipd.descartes.adaptation.model.repository,
+ edu.kit.ipd.descartes.adaptation.model.repository.dmm,
+ edu.kit.ipd.descartes.core,
+ edu.kit.ipd.descartes.identifier,
+ edu.kit.ipd.descartes.mm.adaptation,
+ edu.kit.ipd.descartes.mm.adaptationpoints,
+ edu.kit.ipd.descartes.mm.containerrepository,
+ edu.kit.ipd.descartes.mm.resourceconfiguration,
+ edu.kit.ipd.descartes.mm.resourcelandscape,
+ edu.kit.ipd.descartes.mm.runtimeenvironmentclasses,
+ edu.kit.ipd.descartes.perfdatarepo,
+ org.apache.log4j;version="1.2.15",
+ org.eclipse.emf.common,
+ org.eclipse.emf.common.util,
+ org.eclipse.emf.ecore,
+ org.eclipse.emf.ecore.util,
+ org.eclipse.ocl.ecore,
+ org.osgi.framework;version="1.3.0"
+Export-Package: edu.kit.ipd.descartes.adaptation.model.adaptation,
+ edu.kit.ipd.descartes.adaptation.model.adaptation.dmm,
+ edu.kit.ipd.descartes.adaptation.model.adaptation.dmm.util,
+ edu.kit.ipd.descartes.adaptation.model.adaptation.exceptions
+Require-Bundle: org.eclipse.ocl;bundle-version="3.2.1"
diff --git a/edu.kit.ipd.descartes.adaptation.model.adaptation/build.properties b/edu.kit.ipd.descartes.adaptation.model.adaptation/build.properties
new file mode 100644
index 00000000..34d2e4d2
--- /dev/null
+++ b/edu.kit.ipd.descartes.adaptation.model.adaptation/build.properties
@@ -0,0 +1,4 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .
diff --git a/edu.kit.ipd.descartes.adaptation.model.adaptation/src/edu/kit/ipd/descartes/adaptation/model/adaptation/Activator.java b/edu.kit.ipd.descartes.adaptation.model.adaptation/src/edu/kit/ipd/descartes/adaptation/model/adaptation/Activator.java
new file mode 100644
index 00000000..17fec1ce
--- /dev/null
+++ b/edu.kit.ipd.descartes.adaptation.model.adaptation/src/edu/kit/ipd/descartes/adaptation/model/adaptation/Activator.java
@@ -0,0 +1,30 @@
+package edu.kit.ipd.descartes.adaptation.model.adaptation;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+public class Activator implements BundleActivator {
+
+	private static BundleContext context;
+
+	static BundleContext getContext() {
+		return context;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
+	 */
+	public void start(BundleContext bundleContext) throws Exception {
+		Activator.context = bundleContext;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
+	 */
+	public void stop(BundleContext bundleContext) throws Exception {
+		Activator.context = null;
+	}
+
+}
diff --git a/edu.kit.ipd.descartes.adaptation.model.adaptation/src/edu/kit/ipd/descartes/adaptation/model/adaptation/IActionHandler.java b/edu.kit.ipd.descartes.adaptation.model.adaptation/src/edu/kit/ipd/descartes/adaptation/model/adaptation/IActionHandler.java
new file mode 100644
index 00000000..419c44b7
--- /dev/null
+++ b/edu.kit.ipd.descartes.adaptation.model.adaptation/src/edu/kit/ipd/descartes/adaptation/model/adaptation/IActionHandler.java
@@ -0,0 +1,22 @@
+/**
+ * 
+ */
+package edu.kit.ipd.descartes.adaptation.model.adaptation;
+
+import edu.kit.ipd.descartes.adaptation.model.adaptation.exceptions.OperationNotPerformedException;
+import edu.kit.ipd.descartes.mm.adaptation.AdaptationActionOperation;
+import edu.kit.ipd.descartes.mm.adaptationpoints.AdaptationPoint;
+
+/**
+ * @author nhuber
+ * 
+ * 
+ *
+ */
+public interface IActionHandler {
+
+	public void execute(AdaptationPoint point, AdaptationActionOperation adaptationOperation) throws OperationNotPerformedException;
+	
+	public void persistActions();
+	
+}
diff --git a/edu.kit.ipd.descartes.adaptation.model.adaptation/src/edu/kit/ipd/descartes/adaptation/model/adaptation/dmm/DmmModelActionHandler.java b/edu.kit.ipd.descartes.adaptation.model.adaptation/src/edu/kit/ipd/descartes/adaptation/model/adaptation/dmm/DmmModelActionHandler.java
new file mode 100644
index 00000000..5388b733
--- /dev/null
+++ b/edu.kit.ipd.descartes.adaptation.model.adaptation/src/edu/kit/ipd/descartes/adaptation/model/adaptation/dmm/DmmModelActionHandler.java
@@ -0,0 +1,320 @@
+package edu.kit.ipd.descartes.adaptation.model.adaptation.dmm;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Random;
+
+import org.apache.log4j.Logger;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+
+import edu.kit.ipd.descartes.adaptation.model.adaptation.IActionHandler;
+import edu.kit.ipd.descartes.adaptation.model.adaptation.dmm.util.DmmModelActionHelper;
+import edu.kit.ipd.descartes.adaptation.model.adaptation.dmm.util.DmmModelChanger;
+import edu.kit.ipd.descartes.adaptation.model.adaptation.dmm.util.OclEvaluationHelper;
+import edu.kit.ipd.descartes.adaptation.model.adaptation.exceptions.OperationNotPerformedException;
+import edu.kit.ipd.descartes.adaptation.model.repository.dmm.AdaptationProcessModelLoader;
+import edu.kit.ipd.descartes.core.AdaptableEntity;
+import edu.kit.ipd.descartes.core.Entity;
+import edu.kit.ipd.descartes.mm.adaptation.AdaptationActionOperation;
+import edu.kit.ipd.descartes.mm.adaptation.AdaptationScope;
+import edu.kit.ipd.descartes.mm.adaptationpoints.AdaptationPoint;
+import edu.kit.ipd.descartes.mm.adaptationpoints.ModelEntityConfigurationRange;
+import edu.kit.ipd.descartes.mm.adaptationpoints.ModelVariableConfigurationRange;
+import edu.kit.ipd.descartes.mm.adaptationpoints.PropertyRange;
+import edu.kit.ipd.descartes.mm.adaptationpoints.SetOfConfigurations;
+import edu.kit.ipd.descartes.mm.adaptationpoints.VariationType;
+import edu.kit.ipd.descartes.mm.containerrepository.ContainerTemplate;
+import edu.kit.ipd.descartes.mm.containerrepository.ContainerrepositoryPackage;
+import edu.kit.ipd.descartes.mm.resourcelandscape.Container;
+import edu.kit.ipd.descartes.mm.resourcelandscape.ResourcelandscapePackage;
+import edu.kit.ipd.descartes.mm.resourcelandscape.RuntimeEnvironment;
+
+public class DmmModelActionHandler implements IActionHandler {
+    static Logger logger = Logger.getLogger(DmmModelActionHandler.class);
+
+    public DmmModelActionHandler() {
+        logger.info("DMM models loaded.");
+    }
+
+    private void saveModels() {
+        try {
+            AdaptationProcessModelLoader.saveAll();
+        } catch (IOException e) {
+            logger.error("Error while saving models", e);
+        }
+    }
+
+    @Override
+    public void execute(AdaptationPoint point, AdaptationActionOperation operation)
+            throws OperationNotPerformedException {
+
+        logger.debug("Executing adaptation action <<" + operation.getAdaptationOperationDirection().getLiteral() + ", "
+                + operation.getAdaptationOperationScope().getLiteral() + ">> on adaptation point <<" + point.getName()
+                + ">>.");
+
+        if (point instanceof ModelEntityConfigurationRange) {
+            logger.debug("Type of Adaptation: EntityConfigurationRange");
+            execEntityConfigRangeAdaptation(point, operation);
+        } else if (point instanceof ModelVariableConfigurationRange) {
+            logger.debug("Type of Adaptation Point: VariableConfigurationRange");
+            execVariableConfigRangeAdaptation(point, operation);
+        } else {
+            logger.error("No matching type found for given adaptation point " + point.toString());
+            throw new OperationNotPerformedException(
+                    "No maching adaptation point execution found for adaptation point " + point);
+        }
+    }
+
+    public void execVariableConfigRangeAdaptation(AdaptationPoint point, AdaptationActionOperation operation)
+            throws OperationNotPerformedException {
+        ModelVariableConfigurationRange configRange = (ModelVariableConfigurationRange) point;
+
+        AdaptableEntity adaptedEntity = configRange.getAdaptableEntity();
+        EObject actuallyConfiguredInstance = DmmModelActionHelper.findParentConfiguredInstance(adaptedEntity);
+        switch (actuallyConfiguredInstance.eClass().getClassifierID()) {
+        case ResourcelandscapePackage.RUNTIME_ENVIRONMENT:
+            DmmModelChanger.scaleModelVariable(configRange, operation.getAdaptationOperationDirection());
+            break;
+        case ContainerrepositoryPackage.CONTAINER_TEMPLATE:
+            DmmModelChanger.scaleContainerTemplate((ContainerTemplate) actuallyConfiguredInstance, configRange,
+                    operation);
+            break;
+        case ResourcelandscapePackage.CONTAINER:
+            /*
+             * This code should not be reached because RUNTIME_ENVIRONMENTS are also containers.
+             * Only AbstractHardwareInfrastructures are Containers but not RuntimeEnvironments, but
+             * they cannot be changed because they're hardware
+             */
+            logger.error("You cannot specify an adaptation point for " + actuallyConfiguredInstance.eClass());
+            break;
+        default:
+            logger.error("No adaptation action implemented for type " + actuallyConfiguredInstance.eClass());
+            break;
+        }
+    }
+
+    public void execEntityConfigRangeAdaptation(AdaptationPoint point, AdaptationActionOperation operation)
+            throws OperationNotPerformedException {
+
+        ModelEntityConfigurationRange configRange = (ModelEntityConfigurationRange) point;
+        Entity adaptableEntity = configRange.getAdaptableEntity();
+        VariationType range = configRange.getVariationPossibility();
+
+        switch (operation.getAdaptationOperationDirection()) {
+        case INCREASE:
+            scaleOutModelEntity(adaptableEntity, range);
+            break;
+        case DECREASE:
+            scaleInModelEntity(adaptableEntity, range);
+            break;
+        case MIGRATE:
+            logger.debug("Executing MIGRATE operation");
+            migrate(adaptableEntity, range, operation.getAdaptationOperationScope());
+            break;
+        default:
+            throw new OperationNotPerformedException("Operation " + operation + " on adaptation point "
+                    + point.getName() + " not supported");
+        }
+    }
+
+    private void scaleInModelEntity(Entity adaptableEntity, VariationType range) throws OperationNotPerformedException {
+        logger.debug("Executing DECREASE operation");
+        Entity scaledEntity = scaleIn(adaptableEntity);
+        if (scaledEntity == null)
+            throw new OperationNotPerformedException("Could not scale " + adaptableEntity.getName()
+                    + ". Minimum has been reached!");
+    }
+
+    private void scaleOutModelEntity(Entity adaptableEntity, VariationType range) throws OperationNotPerformedException {
+        logger.debug("Executing INCREASE operation");
+        RuntimeEnvironment scaledRE = scaleOut(adaptableEntity);
+        if (!invariantsAreValid(adaptableEntity, (PropertyRange) range)) { // spawn new
+                                                                           // runtimeEnvironment on
+                                                                           // different machine
+            List<Container> possibleTargets = DmmModelActionHelper.queryContainersWithSimilarTemplate(scaledRE
+                    .getContainedIn());
+            for (Container nextContainer : possibleTargets) {
+                scaledRE.setContainedIn(nextContainer);
+                if (invariantsAreValid(scaledRE, (PropertyRange) range)) {
+                    logger.debug("Scaling entity " + scaledRE.getName() + " on altenative container "
+                            + nextContainer.getName() + " (ID: " + nextContainer.getId() + ")");
+                    return;
+                }
+            }
+            // in case a violation occured and no alternative container was found
+            EcoreUtil.delete(scaledRE, true);
+            throw new OperationNotPerformedException("Could not scale " + adaptableEntity.getName()
+                    + ". Maxiumum has been reached!");
+        }
+    }
+
+    private boolean invariantsAreValid(Entity adaptableEntity, PropertyRange range) {
+        boolean invariant = OclEvaluationHelper.evaluateOclConstraint(adaptableEntity, range.getMinValueConstraint()
+                .getOclString(), adaptableEntity.eClass());
+
+        if (!invariant)
+            logger.debug("Invariant " + range.getMinValueConstraint().getOclString() + " violated");
+
+        invariant &= OclEvaluationHelper.evaluateOclConstraint(adaptableEntity, range.getMaxValueConstraint()
+                .getOclString(), adaptableEntity.eClass());
+
+        if (!invariant)
+            logger.debug("Invariant " + range.getMaxValueConstraint().getOclString() + " violated");
+
+        return invariant;
+    }
+
+    private void migrate(Entity adaptableEntity, VariationType targets, AdaptationScope adaptationScope) throws OperationNotPerformedException {
+        switch (adaptableEntity.eClass().getClassifierID()) {
+        case ResourcelandscapePackage.RUNTIME_ENVIRONMENT:
+            logger.debug("Starting migration of a runtime environment referring to container template "
+                    + adaptableEntity.getName() + " (ID: " + adaptableEntity.getId() + ")");
+            /*
+             * 1. Copy RE 2. Attach copy to a target specified in the Adaptation Point 3. Delete
+             * origin
+             */
+
+            if (!(targets instanceof SetOfConfigurations))
+                throw new IllegalArgumentException(
+                        "Migration could not be performed because no target specification found!");
+            EList<Entity> migrationTargets = ((SetOfConfigurations) targets).getVariants();
+
+            RuntimeEnvironment migratedEntity = (RuntimeEnvironment) adaptableEntity;
+            Container source = migratedEntity.getContainedIn();
+            // TODO Here you could implement something more sophisticated
+            // e.g., choose the container with the lowest util.
+            Entity target = randomTarget(migrationTargets, source);
+            
+            if (!(target instanceof Container))
+                throw new IllegalArgumentException(
+                        "Migration could not be performed because target is not a container!");
+            Container targetContainer = (Container) target;
+            
+            if (migrationTargets.size() == 1 && EcoreUtil.equals(source, target))
+                throw new OperationNotPerformedException("Migration operation not executed because source and destination are identical.");
+
+            targetContainer.getContains().add(migratedEntity);
+            source.getContains().remove(migratedEntity);
+            break;
+        case ContainerrepositoryPackage.CONTAINER_TEMPLATE:
+//            logger.debug("Starting migration of a container referring to container template "
+//                    + adaptableEntity.getName() + " (ID: " + adaptableEntity.getId() + ")");
+            ContainerTemplate containerTemplate = (ContainerTemplate) adaptableEntity;
+            Container migratedContainer = DmmModelActionHelper.findSuitableContainer(containerTemplate, adaptationScope, targets);
+            if (migratedContainer == null)
+                throw new OperationNotPerformedException("Could not execute migration operation because no suitable migration candidate found");
+            migrate(migratedContainer, targets, adaptationScope);
+            break;
+        default:
+            throw new IllegalArgumentException("No implemented migrate operation for " + adaptableEntity);
+        }
+
+    }
+
+    private Entity randomTarget(EList<Entity> destinations, Entity source) {
+        if (destinations.size() == 1)
+            return destinations.get(0);
+        
+        Entity destination = destinations.get(0);
+        Random randomGenerator = new Random();
+        while (EcoreUtil.equals(destination, source)) {
+            int destNumber = randomGenerator.nextInt(destinations.size());
+            destination = destinations.get(destNumber);
+        }
+
+        return destination;
+    }
+
+    private Entity scaleIn(Entity adaptableEntity) {
+        Entity result = null;
+        switch (adaptableEntity.eClass().getClassifierID()) {
+        case ResourcelandscapePackage.RUNTIME_ENVIRONMENT:
+            result = DmmModelChanger.scaleInRuntimeEnvironmentInstance((RuntimeEnvironment) adaptableEntity);
+            break;
+        case ContainerrepositoryPackage.CONTAINER_TEMPLATE:
+            // TODO: move to DmmModelChanger
+            result = scaleInContainerTemplate((ContainerTemplate) adaptableEntity);
+            break;
+        default:
+            throw new IllegalArgumentException("No implemented scale in operation for " + adaptableEntity);
+        }
+        return result;
+    }
+
+    private RuntimeEnvironment scaleOut(Entity adaptableEntity) {
+        RuntimeEnvironment re = null;
+        switch (adaptableEntity.eClass().getClassifierID()) {
+        case ResourcelandscapePackage.RUNTIME_ENVIRONMENT:
+            re = DmmModelChanger.createNewRuntimeEnvironmentInstance((RuntimeEnvironment) adaptableEntity);
+            break;
+        case ContainerrepositoryPackage.CONTAINER_TEMPLATE:
+            re = scaleOutContainerTemplate((ContainerTemplate) adaptableEntity);
+            break;
+        default:
+            throw new IllegalArgumentException("No implemented scale out operation for " + adaptableEntity);
+        }
+        return re;
+    }
+
+    private Entity scaleInContainerTemplate(ContainerTemplate template) {
+        Container referringContainer = template.getReferringContainers().get(0);
+        RuntimeEnvironment removedRe = null;
+        if (referringContainer != null && referringContainer instanceof RuntimeEnvironment) {
+            removedRe = DmmModelChanger.scaleInRuntimeEnvironmentInstance((RuntimeEnvironment) referringContainer);
+        } else {
+            logger.error("Cannot scale " + referringContainer);
+        }
+
+        if (removedRe != null)
+            template.getReferringContainers().remove(removedRe);
+
+        return removedRe;
+    }
+
+    /**
+     * Creates a new RuntimeEnvironment. If you want to scale an attribute of the ContainerTemplate,
+     * ModelVariableConfigurationRange must be used. However, here we are scaling a
+     * ModelEntityConfigurationRange.
+     */
+    // this is just a helper function
+    private RuntimeEnvironment scaleOutContainerTemplate(ContainerTemplate template) {
+        if (template.getReferringContainers().size() == 0) {
+            logger.debug("No referring containers found for template " + template.getName()
+                    + ", creating new instance from template.");
+            return DmmModelChanger.createNewRuntimeEnvironmentInstanceFromTemplate(template);
+        } else {
+            Container referringContainer = template.getReferringContainers().get(0);
+
+            if (referringContainer != null && referringContainer instanceof RuntimeEnvironment) {
+                return DmmModelChanger.createNewRuntimeEnvironmentInstance((RuntimeEnvironment) referringContainer);
+            } else {
+                logger.error("Cannot scale " + referringContainer);
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public void persistActions() {
+        saveModels();
+    }
+
+    // private boolean checkInvariants(EObject adaptableEntity, PropertyRange range) {
+    // OclEvaluationHelper evalHelper = new OclEvaluationHelper();
+    // boolean invariant = evalHelper.evaluate(adaptableEntity,
+    // range.getMinValueConstraint().getOclString());
+    //
+    // if (!invariant)
+    // logger.error("Invariant " + range.getMinValueConstraint().getOclString() + " violated");
+    //
+    // invariant &= evalHelper.evaluate(adaptableEntity,
+    // range.getMaxValueConstraint().getOclString());
+    //
+    // if (!invariant)
+    // logger.error("Invariant " + range.getMaxValueConstraint().getOclString() + " violated");
+    //
+    // return invariant;
+    // }
+}
diff --git a/edu.kit.ipd.descartes.adaptation.model.adaptation/src/edu/kit/ipd/descartes/adaptation/model/adaptation/dmm/util/DmmModelActionHelper.java b/edu.kit.ipd.descartes.adaptation.model.adaptation/src/edu/kit/ipd/descartes/adaptation/model/adaptation/dmm/util/DmmModelActionHelper.java
new file mode 100644
index 00000000..843ca788
--- /dev/null
+++ b/edu.kit.ipd.descartes.adaptation.model.adaptation/src/edu/kit/ipd/descartes/adaptation/model/adaptation/dmm/util/DmmModelActionHelper.java
@@ -0,0 +1,282 @@
+package edu.kit.ipd.descartes.adaptation.model.adaptation.dmm.util;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Random;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+
+import edu.kit.ipd.descartes.core.AdaptableEntity;
+import edu.kit.ipd.descartes.core.Entity;
+import edu.kit.ipd.descartes.core.NamedElement;
+import edu.kit.ipd.descartes.mm.adaptation.AdaptationScope;
+import edu.kit.ipd.descartes.mm.adaptationpoints.SetOfConfigurations;
+import edu.kit.ipd.descartes.mm.adaptationpoints.VariationType;
+import edu.kit.ipd.descartes.mm.containerrepository.ContainerTemplate;
+import edu.kit.ipd.descartes.mm.resourceconfiguration.ConfigurationSpecification;
+import edu.kit.ipd.descartes.mm.resourceconfiguration.ResourceconfigurationPackage;
+import edu.kit.ipd.descartes.mm.resourcelandscape.Container;
+import edu.kit.ipd.descartes.mm.resourcelandscape.ResourcelandscapePackage;
+import edu.kit.ipd.descartes.mm.resourcelandscape.RuntimeEnvironment;
+
+public class DmmModelActionHelper {
+
+    /**
+     * 
+     * @param aEntity
+     * @return the {@link EObject} of the model instance that contains {@code aEntity}
+     */
+    public static EObject findParentConfiguredInstance(AdaptableEntity aEntity) {
+
+        ConfigurationSpecification c = null;
+
+        if (aEntity.eClass().getClassifierID() == ResourceconfigurationPackage.NUMBER_OF_PARALLEL_PROCESSING_UNITS)
+            c = (ConfigurationSpecification) aEntity.eContainer().eContainer();
+        else if (aEntity.eClass().getClassifierID() == ResourceconfigurationPackage.PASSIVE_RESOURCE_CAPACITY)
+            c = (ConfigurationSpecification) aEntity.eContainer();
+        else
+            return null;
+
+        return c.eContainer();
+    }
+
+    /**
+     * Query for a {@link Container} with similar specs
+     * 
+     * @param candidates
+     * @param comparatorContainer
+     * @return
+     */
+    public static List<Container> filterContainersWithSimilarSpecs(List<Container> candidates,
+            Container comparatorContainer) {
+
+        List<Container> resultList = new ArrayList<Container>();
+
+        for (Container c : candidates) {
+
+            /*
+             * Make sure we find a RuntimeEnvironment with 1. a DIFFERENT ID 2. similar properties
+             * and 3. name must contain COPY_MARK to make sure we remove only a copy
+             */
+            if (c.getId() != comparatorContainer.getId() && c.getName().contains(DmmModelChanger.COPY_MARK)
+                    && EcoreUtil.equals(comparatorContainer.getConfigSpec(), c.getConfigSpec())
+                    && EcoreUtil.equals(comparatorContainer.getTemplate(), c.getTemplate())) {
+                resultList.add(c);
+            }
+        }
+        return resultList;
+    }
+
+    /**
+     * Query for a {@link RuntimeEnvironment} that has been copied (contains
+     * {@link DmmModelChanger.COPY_MARK}) and refers to the same ContainerTemplate.
+     * 
+     * @param candidates
+     * @param comparatorRE
+     * @return
+     */
+    public static RuntimeEnvironment filterCopiedRuntimeEnvironment(List<RuntimeEnvironment> candidates,
+            RuntimeEnvironment comparatorRE) {
+
+        for (RuntimeEnvironment re : candidates) {
+
+            if (re.getId() != comparatorRE.getId() && re.getName().contains(DmmModelChanger.COPY_MARK)
+            // && EcoreUtil.equals(comparatorRE.getConfigSpec(), re.getConfigSpec())
+            // && EcoreUtil.equals(comparatorRE.getContainedIn(), re.getContainedIn())
+                    && EcoreUtil.equals(comparatorRE.getTemplate(), re.getTemplate())) {
+                return re;
+            }
+        }
+        return null;
+    }
+
+    public static RuntimeEnvironment filterRuntimeEnvironment(List<RuntimeEnvironment> candidates,
+            RuntimeEnvironment comparatorRE) {
+
+        // Filter RE with copy mark first
+        RuntimeEnvironment reWithCopyMark = filterCopiedRuntimeEnvironment(candidates, comparatorRE);
+        if (reWithCopyMark != null) {
+            return reWithCopyMark;
+        } else {
+            // If there is no copy mark, filter an RE with different ID
+            for (RuntimeEnvironment re : candidates) {
+
+                if (re.getId() != comparatorRE.getId()
+                // && EcoreUtil.equals(comparatorRE.getConfigSpec(), re.getConfigSpec())
+                // && EcoreUtil.equals(comparatorRE.getContainedIn(), re.getContainedIn())
+                        && EcoreUtil.equals(comparatorRE.getTemplate(), re.getTemplate())) {
+                    return re;
+                }
+            }
+        }
+        // If no matches have been found, return the comparator element
+        return comparatorRE;
+    }
+
+    public static NamedElement findEntityWithName(NamedElement element, String name) {
+
+        if (element.getName().equals(name))
+            return element;
+        else {
+            NamedElement result = null;
+            for (Iterator<EObject> iterator = element.eContents().iterator(); iterator.hasNext();) {
+                NamedElement nextElement = (NamedElement) iterator.next();
+                result = findEntityWithName(nextElement, name);
+                if (result != null)
+                    return result;
+            }
+            return result;
+        }
+    }
+
+    /**
+     * Queries for all Container instances that have a similar configuration specification as
+     * Container <code>c</code>. Similar configuration specification meas that ContainerTemplate and
+     * ConfigurationSpecification are equal.
+     * 
+     * @param c
+     * @return A list of Container instances
+     */
+    public static List<Container> queryContainersWithSimilarSpecs(Container c) {
+        List<Container> result = queryContainersWithSimilarTemplate(c);
+        return filterContainersWithSimilarSpecs(result, c);
+    }
+
+    /**
+     * Queries for a RuntimeEnvironment whose ContainerTemplate is similar to the given
+     * RuntimeEnvironment <code>re</code> and whose capacity is below <code>maxValue</code>.
+     * 
+     * @param re
+     * @param maxValue
+     * @return
+     */
+    public static RuntimeEnvironment queryUnfilledRuntimeEnvironment(RuntimeEnvironment re, double maxValue) {
+        // TODO SEAMS specific helper function! Generalize!
+        String queryExpression = "RuntimeEnvironment.allInstances()->select( re | re.template = self.template )->select(re | re.configSpec.oclAsType(resourceconfiguration::ActiveResourceSpecification).processingResourceSpecifications->forAll(nrOfParProcUnits.number < "
+                + maxValue + "))";
+        List<EObject> resultList = new ArrayList<EObject>(OclEvaluationHelper.query(re, queryExpression, re.eClass()));
+
+        if (resultList.size() > 0)
+            return (RuntimeEnvironment) resultList.get(0);
+        else
+            return null;
+    }
+
+    public static RuntimeEnvironment queryNotEmptyRuntimeEnvironment(RuntimeEnvironment re, double minValue) {
+        // TODO SEAMS specific helper function! Generalize!
+        String queryExpression = "RuntimeEnvironment.allInstances()->select( re | re.template = self.template and not re.configSpec->isEmpty() )->select(re | re.configSpec.oclAsType(resourceconfiguration::ActiveResourceSpecification).processingResourceSpecifications->forAll(nrOfParProcUnits.number > "
+                + minValue + "))";
+        List<EObject> resultList = new ArrayList<EObject>(OclEvaluationHelper.query(re, queryExpression, re.eClass()));
+
+        if (resultList.size() > 0)
+            return (RuntimeEnvironment) resultList.get(0);
+        else
+            return null;
+    }
+
+    /**
+     * Queries for all Container instances referring to the same ContainerTemplate as the given
+     * container.
+     * 
+     * @param container
+     *            The container to look for
+     * @return All Container Instances referring to the same ContainerTemplate
+     */
+    public static List<Container> queryContainersWithSimilarTemplate(Container container) {
+//        String queryExpression = "RuntimeEnvironment.allInstances()->select( re | re.template = self.template and re.id <> self.id)";
+        String queryExpression = "RuntimeEnvironment.allInstances()->select( re | re.template = self.template)";
+        List<EObject> tempList = new ArrayList<EObject>(OclEvaluationHelper.query(container, queryExpression,
+                container.eClass()));
+        List<Container> resultList = new ArrayList<Container>(tempList.size());
+        for (Iterator<EObject> iterator = tempList.iterator(); iterator.hasNext();) {
+            Container temp = (Container) iterator.next();
+            resultList.add(temp);
+        }
+        return resultList;
+    }
+
+    /**
+     * Filter the given {@code containerList} for RuntimeEnvironments and cast them to
+     * {@link RuntimeEnvironment}
+     * 
+     * @param containerList
+     * @return a list of RuntimeEnvironments
+     */
+    public static List<RuntimeEnvironment> filterAndConvertRuntimeEnvironment(List<Container> containerList) {
+        List<RuntimeEnvironment> result = new ArrayList<RuntimeEnvironment>();
+
+        for (Container container : containerList) {
+            if (container.eClass().getClassifierID() == ResourcelandscapePackage.RUNTIME_ENVIRONMENT)
+                result.add((RuntimeEnvironment) container);
+        }
+
+        return result;
+    }
+
+    /**
+     * Find a container that refers to the given {@link ContainerTemplate} and that suits the given
+     * {@link AdaptationScope}. This is the new target.
+     * 
+     * @param containerTemplate
+     * @param adaptationScope
+     * @param targets
+     * @return
+     */
+    public static Container findSuitableContainer(ContainerTemplate containerTemplate, AdaptationScope adaptationScope,
+            VariationType targets) {
+        // Get all containers referring to the template
+        List<Container> containers = containerTemplate.getReferringContainers();
+        List<Entity> variants = ((SetOfConfigurations) targets).getVariants();
+
+        // Prepare the list of migration targets
+        List<Container> migrationTargets = new ArrayList<Container>();
+        for (Entity entity : variants) {
+            migrationTargets.add((Container) entity);
+        }
+
+        for (Container container : containers) {
+
+            // Remove container from migration targets
+            List<Container> migrationTargetCandidates = excludeSelfContainmentFromTargetList(container,
+                    migrationTargets);
+
+            // If there are migration targets left
+            if (migrationTargetCandidates.size() > 0) {
+                switch (adaptationScope) {
+                case RANDOM:
+                    Random generator = new Random();
+                    int next = generator.nextInt(containers.size());
+                    return containers.get(next);
+                default:
+                    return null;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns a list of {@code targets} excluding the target the container {@code self} is already
+     * contained in.
+     * 
+     * @param self
+     * @param targets
+     * @return
+     */
+    public static List<Container> excludeSelfContainmentFromTargetList(Container self, List<Container> targets) {
+        if (self == null || targets == null)
+            return null;
+
+        List<Container> resultList = new ArrayList<Container>();
+
+        for (Container target : targets) {
+            if (!EcoreUtil.equals(target, self.eContainer()))
+                resultList.add(target);
+        }
+
+        return resultList;
+    }
+
+}
diff --git a/edu.kit.ipd.descartes.adaptation.model.adaptation/src/edu/kit/ipd/descartes/adaptation/model/adaptation/dmm/util/DmmModelChanger.java b/edu.kit.ipd.descartes.adaptation.model.adaptation/src/edu/kit/ipd/descartes/adaptation/model/adaptation/dmm/util/DmmModelChanger.java
new file mode 100644
index 00000000..e02f4adf
--- /dev/null
+++ b/edu.kit.ipd.descartes.adaptation.model.adaptation/src/edu/kit/ipd/descartes/adaptation/model/adaptation/dmm/util/DmmModelChanger.java
@@ -0,0 +1,304 @@
+package edu.kit.ipd.descartes.adaptation.model.adaptation.dmm.util;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Random;
+
+import org.apache.log4j.Logger;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+
+import edu.kit.ipd.descartes.adaptation.model.adaptation.exceptions.OperationNotPerformedException;
+import edu.kit.ipd.descartes.core.AdaptableEntity;
+import edu.kit.ipd.descartes.core.Entity;
+import edu.kit.ipd.descartes.core.NamedElement;
+import edu.kit.ipd.descartes.mm.adaptation.AdaptationActionOperation;
+import edu.kit.ipd.descartes.mm.adaptation.AdaptationDirection;
+import edu.kit.ipd.descartes.mm.adaptation.AdaptationScope;
+import edu.kit.ipd.descartes.mm.adaptationpoints.ModelVariableConfigurationRange;
+import edu.kit.ipd.descartes.mm.containerrepository.ContainerTemplate;
+import edu.kit.ipd.descartes.mm.resourceconfiguration.ConfigurationSpecification;
+import edu.kit.ipd.descartes.mm.resourceconfiguration.NumberOfParallelProcessingUnits;
+import edu.kit.ipd.descartes.mm.resourceconfiguration.ResourceconfigurationPackage;
+import edu.kit.ipd.descartes.mm.resourcelandscape.Container;
+import edu.kit.ipd.descartes.mm.resourcelandscape.ResourcelandscapeFactory;
+import edu.kit.ipd.descartes.mm.resourcelandscape.RuntimeEnvironment;
+import edu.kit.ipd.descartes.mm.runtimeenvironmentclasses.RuntimeEnvironmentClasses;
+
+public class DmmModelChanger {
+    
+    private static final int FIRST = 0;
+
+    /**
+     * Denotes a Container as a copy of another by
+     * adding this mark to its name.
+     */
+    public static final String COPY_MARK = "-Copy";
+
+    static Logger logger = Logger.getLogger(DmmModelChanger.class);
+
+    /**
+     * Scales the actual number of a given model variable
+     * 
+     * @param adaptedEntity
+     * @param operation
+     */
+    public static void scaleModelVariable(ModelVariableConfigurationRange range, AdaptationDirection direction)
+            throws OperationNotPerformedException {
+        
+        switch (range.getAdaptableEntity().eClass().getClassifierID()) {
+        case ResourceconfigurationPackage.NUMBER_OF_PARALLEL_PROCESSING_UNITS:
+            adaptNumberOfCores(range.getAdaptableEntity(), range, direction);
+            break;
+        default:
+            logger.error("SCALING THIS TYPE OF MODEL VARIABLE HAS NOT BEEN IMPLEMENTED YET!");
+            break;
+        }
+    }
+
+    private static void adaptNumberOfCores(AdaptableEntity adaptedEntity, ModelVariableConfigurationRange range,
+            AdaptationDirection direction) throws OperationNotPerformedException {
+        NumberOfParallelProcessingUnits adaptableModelEntity = (NumberOfParallelProcessingUnits) adaptedEntity;
+        Entity containingEntity = (Entity) adaptableModelEntity.getProcessingResourceSpec().getParentResourceSpecification().eContainer();
+                
+        Integer currentValue = adaptableModelEntity.getNumber();
+        Integer maxValue = (int) Math.floor(range.getMaxValue());
+        Integer minValue = (int) Math.ceil(range.getMinValue());
+        
+        if (direction == AdaptationDirection.INCREASE) {
+            // if current value less than max value
+            if (currentValue < maxValue) {
+                adaptableModelEntity.setNumber(currentValue + 1);
+                logger.info("Number of " + containingEntity.getName() + " (ID: " + containingEntity.getId() + ")" + " increased to "
+                        + (currentValue + 1) + ".");
+            } else
+                throw new OperationNotPerformedException("Adaptation operation " + direction.getLiteral()
+                        + " for adaptation point " + adaptedEntity.getName()
+                        + " could not be executed because the maximum has been reached");
+        } else if (direction == AdaptationDirection.DECREASE) {
+            // if current value greater than min value
+            if (currentValue > minValue) {
+                adaptableModelEntity.setNumber(currentValue - 1);
+                logger.info("Number of " + containingEntity.getName() + " (ID: " + containingEntity.getId() + ")" + " decreased to "
+                        + (currentValue - 1) + ".");
+            } else
+                throw new OperationNotPerformedException("Adaptation operation " + direction.getLiteral()
+                        + " for adaptation point " + adaptedEntity.getName()
+                        + " could not be executed because the minimum has been reached");
+        } else
+            logger.error("Adaptation direction " + direction.getLiteral() + " not defined for "
+                    + adaptedEntity.eClass());
+    }
+
+    /**
+     * Removes the given {@link RuntimeEnvironment} instance
+     * 
+     * @param runtimeEnvironment
+     *            the {@link RuntimeEnvironment} to remove
+     * @return
+     */
+    public static RuntimeEnvironment scaleInRuntimeEnvironmentInstance(RuntimeEnvironment runtimeEnvironment) {
+        List<Container> similarContainers = DmmModelActionHelper.queryContainersWithSimilarTemplate(runtimeEnvironment);
+        List<RuntimeEnvironment> containedEntities = DmmModelActionHelper.filterAndConvertRuntimeEnvironment(similarContainers);
+        RuntimeEnvironment similarEntity = DmmModelActionHelper.filterRuntimeEnvironment(containedEntities, runtimeEnvironment);
+        if (similarEntity != null) {
+            runtimeEnvironment.getTemplate().getReferringContainers().remove(similarEntity);
+            similarEntity.getContainedIn().getContains().remove(similarEntity);
+            logger.info("RuntimeEnvironment " + similarEntity.getName() + " (ID: " + similarEntity.getId() + ") removed.");
+        } else
+            logger.error("Could not remove a runtime environment instance because no similar entity has been found.");
+
+        return (RuntimeEnvironment) similarEntity;
+    }
+
+    /**
+     * Creates a new {@link RuntimeEnvironment} instance
+     * 
+     * @param runtimeEnvironment
+     *            the {@link RuntimeEnvironment} to copy
+     * @return
+     */
+    public static RuntimeEnvironment createNewRuntimeEnvironmentInstance(RuntimeEnvironment runtimeEnvironment) {
+        RuntimeEnvironment newRuntimeEnvironment = EcoreUtil.copy(runtimeEnvironment);
+        newRuntimeEnvironment.setId(EcoreUtil.generateUUID());
+        newRuntimeEnvironment.setName(newRuntimeEnvironment.getName() + COPY_MARK);
+        newRuntimeEnvironment.setTemplate(runtimeEnvironment.getTemplate());
+        runtimeEnvironment.getTemplate().getReferringContainers().add(newRuntimeEnvironment);
+        
+        if (runtimeEnvironment.getConfigSpec().size() > 0) {
+            newRuntimeEnvironment.getConfigSpec().clear();
+            newRuntimeEnvironment.getConfigSpec().addAll(EcoreUtil.copyAll(runtimeEnvironment.getTemplate().getTemplateConfig()));
+        }
+       
+        runtimeEnvironment.getContainedIn().getContains().add(newRuntimeEnvironment);
+        logger.debug("New RuntimeEnvironment " + newRuntimeEnvironment.getName() + " (ID: " +
+                newRuntimeEnvironment.getId() + ") to " +
+                newRuntimeEnvironment.getContainedIn().getName() + " (ID: " + newRuntimeEnvironment.getContainedIn().getId() + ") added." );
+        return newRuntimeEnvironment;
+    }
+
+    /**
+     * Scales either the model variable if AdaptationScope is set to ALL
+     * or scales a ModelEntity referring to <code>actuallyConfiguredInstance</code>
+     * according to the specified <code>operation</code>.
+     * 
+     * @param actuallyConfiguredInstance
+     * @param range
+     * @param operation
+     * @throws OperationNotPerformedException
+     */
+    public static void scaleContainerTemplate(ContainerTemplate actuallyConfiguredInstance, ModelVariableConfigurationRange range, AdaptationActionOperation operation) throws OperationNotPerformedException {
+
+        Container container = null;
+        
+        AdaptationScope scope = operation.getAdaptationOperationScope();
+        AdaptationDirection direction = operation.getAdaptationOperationDirection();
+        
+        if (operation.getAdaptationOperationScope() == AdaptationScope.ALL) {
+            switch (direction) {
+            case INCREASE : // falls SCALE_UP/DOWN -> Šndere Template
+                scaleModelVariable(range, direction);
+                break;
+            case DECREASE : // falls SCALE_UP/DOWN -> Šndere Template
+                scaleModelVariable(range, direction);
+                break;
+            default :
+                logger.error(scope.getLiteral() + ", " + direction.getLiteral() + " not defined for " + range.getAdaptableEntity().eClass());
+                break;
+            }
+        }
+        
+        else {
+            switch (scope) {
+            case RANDOM:
+                // pick a random instance referring to this template and
+                // change its configuration
+                container = pickRandomReferringContainer(actuallyConfiguredInstance);
+                break;
+            case LEAST_UTILIZED_FIRST:
+                logger.error("NOT IMPLEMENTED YET"); 
+                break;
+            case MOST_UTILIZED_FIRST:
+                logger.error("NOT IMPLEMENTED YET");
+                break;
+            default:
+                logger.error("No adaptation operation defined for " + scope.getLiteral() + ", "
+                        + direction.getLiteral());
+                break;
+            }
+            if (container != null)
+                try {
+                    scaleResourceProvidedByContainer(container, range, direction);
+                } catch (OperationNotPerformedException e) {
+                    logger.error(container.getName() + " could not be adapted. Trying alternative containers.");
+                    scaleResourcesOfAlternativeContainer(range, container, direction);
+                }
+
+            else
+                throw new OperationNotPerformedException("No adaptable container found.");
+        }
+    }
+
+    private static void scaleResourcesOfAlternativeContainer(ModelVariableConfigurationRange range, Container container,
+            AdaptationDirection direction) throws OperationNotPerformedException {
+        Container targetContainer = null;
+        switch (direction) {
+        case INCREASE:
+            targetContainer = DmmModelActionHelper.queryUnfilledRuntimeEnvironment((RuntimeEnvironment) container, range.getMaxValue());
+            break;
+        case DECREASE:
+            targetContainer = DmmModelActionHelper.queryNotEmptyRuntimeEnvironment((RuntimeEnvironment) container, range.getMinValue());
+            break;
+        default:
+            logger.error("No corresponding AdaptationDirection found for :" + range + ".");
+            break;
+        }
+        if (targetContainer == null) {
+            logger.error("No alternative container for adaptation found!");
+            throw new OperationNotPerformedException("No alternative container found. Scale operation not performed!");
+        } else {
+            scaleResourceProvidedByContainer(targetContainer, range, direction);
+        }
+    }
+
+    
+    /**Scales the resource (capacity) provided by the container, e.g., 
+     * the number of virtual cores of a VM.
+     * 
+     * @param container The container to be scaled
+     * @param range The min and max capacity
+     * @param direction Specifies if up- or down-scaling
+     * @throws OperationNotPerformedException
+     */
+    public static void scaleResourceProvidedByContainer(Container container, ModelVariableConfigurationRange range,
+            AdaptationDirection direction) throws OperationNotPerformedException {
+
+        boolean copyWasCreated = false;
+        
+        if (container.getConfigSpec().isEmpty()) // Better check if configSpecs are identical
+        {
+            copyTemplateSpecToConfigSpec(container);
+            copyWasCreated = true;
+        }
+
+        NamedElement changedElement = getRespectiveAdaptableConfigSpecElement(container, range);
+
+        if (changedElement != null && changedElement instanceof AdaptableEntity) {
+            AdaptableEntity adaptableEntity = (AdaptableEntity) changedElement;
+            try {
+                adaptNumberOfCores(adaptableEntity, range, direction);
+            // in case operation was not executed, e.g. because min was reached
+            } catch (OperationNotPerformedException e) {
+                //undo copy of config spec
+                if (copyWasCreated)
+                    container.getConfigSpec().clear();
+                throw e;
+            }
+        }
+        
+        // If template and configSpec are identical, remove config spec
+        if (EcoreUtil.equals(container.getConfigSpec(), container.getTemplate().getTemplateConfig()))
+            container.getConfigSpec().clear();
+
+    }
+
+    private static NamedElement getRespectiveAdaptableConfigSpecElement(Container container,
+            ModelVariableConfigurationRange range) {
+        NamedElement changedElement = null;
+
+        for (Iterator<ConfigurationSpecification> iterator = container.getConfigSpec().iterator(); iterator.hasNext();) {
+            ConfigurationSpecification configurationSpecification = (ConfigurationSpecification) iterator.next();
+            changedElement = DmmModelActionHelper.findEntityWithName(configurationSpecification, range
+                    .getAdaptableEntity().getName());
+            if (!changedElement.equals(null))
+                break;
+        }
+        return changedElement;
+    }
+
+    private static void copyTemplateSpecToConfigSpec(Container container) {
+        Collection<ConfigurationSpecification> copiedList = EcoreUtil.copyAll(container.getTemplate()
+                .getTemplateConfig());
+        container.getConfigSpec().addAll(copiedList);
+    }
+
+    private static Container pickRandomReferringContainer(ContainerTemplate template) {
+        Random randomGenerator = new Random();
+        EList<Container> containers = template.getReferringContainers();
+        int index = randomGenerator.nextInt(containers.size());
+        return containers.get(index);
+    }
+
+    public static RuntimeEnvironment createNewRuntimeEnvironmentInstanceFromTemplate(ContainerTemplate template) {
+        RuntimeEnvironment newRe = ResourcelandscapeFactory.eINSTANCE.createRuntimeEnvironment();
+        newRe.setId(EcoreUtil.generateUUID());
+        newRe.setName("RuntimeEnvironmentInstanceOfTemplate_" + template.getName());
+        newRe.setTemplate(template);
+        newRe.setOfClass(RuntimeEnvironmentClasses.MIDDLEWARE);
+        newRe.setContainedIn(template.getRunningOn().get(FIRST));
+        
+        template.getReferringContainers().add(newRe);        
+        return newRe;
+    }
+}
diff --git a/edu.kit.ipd.descartes.adaptation.model.adaptation/src/edu/kit/ipd/descartes/adaptation/model/adaptation/dmm/util/ObjectivesHelper.java b/edu.kit.ipd.descartes.adaptation.model.adaptation/src/edu/kit/ipd/descartes/adaptation/model/adaptation/dmm/util/ObjectivesHelper.java
new file mode 100644
index 00000000..f1e81cdc
--- /dev/null
+++ b/edu.kit.ipd.descartes.adaptation.model.adaptation/src/edu/kit/ipd/descartes/adaptation/model/adaptation/dmm/util/ObjectivesHelper.java
@@ -0,0 +1,65 @@
+package edu.kit.ipd.descartes.adaptation.model.adaptation.dmm.util;
+
+import java.util.List;
+
+import org.eclipse.emf.common.util.EList;
+
+import edu.kit.ipd.descartes.mm.adaptation.Event;
+import edu.kit.ipd.descartes.mm.adaptation.RelationalOperator;
+import edu.kit.ipd.descartes.mm.adaptation.Specification;
+import edu.kit.ipd.descartes.perfdatarepo.MetricType;
+import edu.kit.ipd.descartes.perfdatarepo.MetricValue;
+import edu.kit.ipd.descartes.perfdatarepo.Result;
+
+public class ObjectivesHelper {
+
+    public static boolean compare(double left, double right, RelationalOperator operator) {
+        switch (operator) {
+        case EQUAL:
+            return left == right;
+        case NOT_EQUAL:
+            return left != right;
+        case LESS:
+            return left < right;
+        case LESS_EQUAL:
+            return left <= right;
+        case GREATER:
+            return left > right;
+        case GREATER_EQUAL:
+            return left >= right;
+        default:
+            return false;
+        }
+    }
+
+    public static boolean isObjectiveFulfilled(Event event, Result result) {
+        List<Specification> specs = event.getTriggers().getObjective().getSpecifications();
+        for (Specification specification : specs) {
+            MetricType m = specification.getMetricType();
+//          TODO: Connect QueryEngine:  Double actualValue = QueryEngineAdapter.getValueForMetricType(m);
+            Double actualValue = getValueForMetricType(m, result);
+            Double threshold = specification.getValue();
+            if (!ObjectivesHelper.compare(actualValue, threshold, specification.getRelationalOperator()))
+                return false;
+
+        }
+        return true;
+    }
+    
+    private static double getValueForMetricType(MetricType metricType, Result result) {
+        EList<MetricValue> metricValues = result.getMetricValues();
+
+        for (MetricValue metricValue : metricValues) {
+            if (sameMetricType(metricValue, metricType))
+                return metricValue.getValue();
+        }
+        return Double.NaN;
+    }
+
+    private static boolean sameMetricType(MetricValue metricValue, MetricType metricType) {
+//      return metricValue.getMetricType().equals(metricType);
+      return (metricValue.getMetricType().getName().equals(metricType.getName())); 
+//              && metricValue.getMetricType().getId().equals(metricType.getId()));
+  }
+    
+}
diff --git a/edu.kit.ipd.descartes.adaptation.model.adaptation/src/edu/kit/ipd/descartes/adaptation/model/adaptation/dmm/util/OclEvaluationHelper.java b/edu.kit.ipd.descartes.adaptation.model.adaptation/src/edu/kit/ipd/descartes/adaptation/model/adaptation/dmm/util/OclEvaluationHelper.java
new file mode 100644
index 00000000..a2707f29
--- /dev/null
+++ b/edu.kit.ipd.descartes.adaptation.model.adaptation/src/edu/kit/ipd/descartes/adaptation/model/adaptation/dmm/util/OclEvaluationHelper.java
@@ -0,0 +1,89 @@
+package edu.kit.ipd.descartes.adaptation.model.adaptation.dmm.util;
+
+import java.util.Set;
+
+import org.apache.log4j.Logger;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.ocl.OCL;
+import org.eclipse.ocl.ParserException;
+import org.eclipse.ocl.Query;
+import org.eclipse.ocl.ecore.Constraint;
+import org.eclipse.ocl.ecore.EcoreEnvironmentFactory;
+import org.eclipse.ocl.expressions.OCLExpression;
+import org.eclipse.ocl.helper.OCLHelper;
+
+/**
+ * @author nhuber
+ *
+ */
+public class OclEvaluationHelper {
+	
+	private static Logger logger = Logger.getLogger(OclEvaluationHelper.class);
+
+	/**
+	 * @param checkedObject the checked object
+	 * @param constraint the constraint to evaluate on the object
+	 * @param context the {@link EClass} of the given object
+	 * @return
+	 *     {@code true} if check was successful
+	 */
+	public static boolean evaluateOclConstraint(EObject checkedObject, String constraint, EClass context) {
+		Constraint invariant = null;
+		OCL<?, EClassifier, ?, ?, ?, ?, ?, ?, ?, Constraint, EClass, EObject> ocl;
+		ocl = OCL.newInstance(EcoreEnvironmentFactory.INSTANCE);
+		OCLHelper<EClassifier, ?, ?, Constraint> helper = ocl.createOCLHelper();
+		
+		helper.setContext(context);
+		
+		try {
+			invariant = helper.createInvariant(constraint);
+		} catch (ParserException e) {
+			logger.error("Error parsing OCL string '" + constraint + "'", e);
+			return false;
+		}
+		
+		Query<EClassifier, EClass, EObject> eval = ocl.createQuery(invariant);
+		return eval.check(checkedObject);		
+	}
+
+	
+	
+	/**
+	 * Executes the query on a given object.
+	 * 
+	 * @param obj the model instance the query is executed on
+	 * @param queryExpression the OCL query
+	 * @param context the eClass of the model instance
+	 * @return
+	 */
+	public static Set<EObject> query(EObject obj, String queryExpression, EClassifier context) {
+	    OCL<?, EClassifier, ?, ?, ?, ?, ?, ?, ?, Constraint, EClass, EObject> ocl;
+	    ocl = OCL.newInstance(EcoreEnvironmentFactory.INSTANCE);
+	    OCLHelper<EClassifier, ?, ?, Constraint> helper = ocl.createOCLHelper();
+
+	    helper.setContext(context);
+	    
+	    OCLExpression<EClassifier> query;
+        try {
+            query = helper.createQuery(queryExpression);
+        } catch (ParserException e) {
+            logger.error("Error parsing OCL query '" + queryExpression + "'", e);
+            return null;
+        }
+
+	    // create a Query to evaluate our query expression
+	    Query<EClassifier, EClass, EObject> queryEval = ocl.createQuery(query);
+
+	    Object result = queryEval.evaluate(obj);
+
+        if (result.toString().contains("invalid"))
+            return null;
+                
+        @SuppressWarnings("unchecked")  
+        Set<EObject> resultList = (Set<EObject>) result;
+
+        return resultList;
+	}
+}
diff --git a/edu.kit.ipd.descartes.adaptation.model.adaptation/src/edu/kit/ipd/descartes/adaptation/model/adaptation/exceptions/InvalidAdaptationPlan.java b/edu.kit.ipd.descartes.adaptation.model.adaptation/src/edu/kit/ipd/descartes/adaptation/model/adaptation/exceptions/InvalidAdaptationPlan.java
new file mode 100644
index 00000000..9cbe01a5
--- /dev/null
+++ b/edu.kit.ipd.descartes.adaptation.model.adaptation/src/edu/kit/ipd/descartes/adaptation/model/adaptation/exceptions/InvalidAdaptationPlan.java
@@ -0,0 +1,14 @@
+package edu.kit.ipd.descartes.adaptation.model.adaptation.exceptions;
+
+public class InvalidAdaptationPlan extends Exception {
+    
+    public InvalidAdaptationPlan(String message) {
+        super(message);
+    }
+
+    /**
+     * 
+     */
+    private static final long serialVersionUID = 963013704332157870L;
+
+}
diff --git a/edu.kit.ipd.descartes.adaptation.model.adaptation/src/edu/kit/ipd/descartes/adaptation/model/adaptation/exceptions/OperationNotPerformedException.java b/edu.kit.ipd.descartes.adaptation.model.adaptation/src/edu/kit/ipd/descartes/adaptation/model/adaptation/exceptions/OperationNotPerformedException.java
new file mode 100644
index 00000000..734025f5
--- /dev/null
+++ b/edu.kit.ipd.descartes.adaptation.model.adaptation/src/edu/kit/ipd/descartes/adaptation/model/adaptation/exceptions/OperationNotPerformedException.java
@@ -0,0 +1,14 @@
+package edu.kit.ipd.descartes.adaptation.model.adaptation.exceptions;
+
+public class OperationNotPerformedException extends Exception {
+
+	public OperationNotPerformedException(String message) {
+		super(message);
+	}
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 7144698514945329908L;
+
+}
-- 
GitLab