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