Skip to content

Commit

Permalink
Merge branch 'IntelligentEnsembles' of https://github.com/d3scomp/JDE…
Browse files Browse the repository at this point in the history
…ECo.git into IntelligentEnsembles
  • Loading branch information
jiracekz committed Jul 23, 2015
2 parents f82ed0e + 4519cc0 commit c99a8df
Show file tree
Hide file tree
Showing 13 changed files with 269 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,17 @@ public interface EnsembleFactory {
* Returns a collection of ensemble instances that should exist in the system at the moment, given the knowledge stored in the container parameter.
* @param container - a knowledge container containing the current state of the system (i.e. knowledge from the POV of a single component).
* @return Currently existing ensemble instances.
* @throws EnsembleFormationException
*/
Collection<EnsembleInstance> createInstances(KnowledgeContainer container);
Collection<EnsembleInstance> createInstances(KnowledgeContainer container) throws EnsembleFormationException;
/**
* Gets the initial offset of the ensemble formation.
* Gets the initial scheduling offset of the ensemble formation.
* @return Ensemble formation offset.
*/
int getOffset();
int getSchedulingOffset();
/**
* Gets the period after which the ensemble formation is invoked again.
* Gets the period after which the ensemble formation is scheduled again.
* @return Ensemble formation period.
*/
int getPeriod();
int getSchedulingPeriod();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package cz.cuni.mff.d3s.deeco.ensembles;

import cz.cuni.mff.d3s.deeco.runtime.DEECoException;
/**
* Exception indicating that the ensemble formation has failed significantly. The exact reason is
* implementation specific and should be attached as cause. Used in {@link EnsembleFactory#createInstances}.
*
* @author Filip Krijt
*/
public class EnsembleFormationException extends DEECoException {

private static final long serialVersionUID = 1L;

public EnsembleFormationException(Throwable cause) {
super(cause);
}

public EnsembleFormationException(String message, Throwable cause) {
super(message, cause);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package cz.cuni.mff.d3s.deeco.knowledge.container;

import cz.cuni.mff.d3s.deeco.runtime.DEECoException;

/**
* General exception thrown by the {@link TrackingKnowledgeContainer} class.
* The exception message and the inner exception contain the details.
Expand All @@ -11,16 +13,13 @@
*
* @see TrackingKnowledgeContainer
*/
public class KnowledgeContainerException extends Exception {
public class KnowledgeContainerException extends DEECoException {

/**
*
*/
private static final long serialVersionUID = -9219992641061413076L;

public KnowledgeContainerException() {
}


public KnowledgeContainerException(String message) {
super(message);
}
Expand All @@ -31,11 +30,5 @@ public KnowledgeContainerException(Throwable cause) {

public KnowledgeContainerException(String message, Throwable cause) {
super(message, cause);
}

public KnowledgeContainerException(String message, Throwable cause,
boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ public Map<EnsembleController, Task> getEnsembleTasks() {
return ensembleTasks;
}

/**
* Gets all ensemble formation tasks associated with this instance.
* @return Associated ensemble formation tasks.
*/
public List<EnsembleFormationTask> getEnsembleFormationTasks() {
return ensembleFormationTasks;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public interface DEECoContainer {
public ComponentInstance deployComponent(Object components) throws AnnotationProcessorException;

/**
* Deploys ensembles to the DEECo rutime by parsing them and adding them to the metadata model.
* Deploys ensembles to the DEECo runtime by parsing them and adding them to the metadata model.
* As soon as they are added to the model, ensembles are dynamically deployed (relevant tasks are created and scheduled).
* To be used by plugins to deploy "system ensembles" that specify knowledge exchange between "system components" and are scheduled along with application ensembles.
*
Expand All @@ -70,6 +70,11 @@ public interface DEECoContainer {

void undeployEnsemble(String ensembleName) throws AnnotationProcessorException, DuplicateEnsembleDefinitionException;

/**
* Deploys an ensemble factory to this DEECo container, immediately registering it with the runtime and creating and scheduling the relevant tasks.
* Note that unlike the {@link #deployEnsemble} method, no information is added to the metadata model.
* @param factory {@link EnsembleFactory} implementor used for specific ensemble formation.
*/
public void deployEnsembleFactory(EnsembleFactory factory);

/**
Expand Down
2 changes: 2 additions & 0 deletions jdeeco-core/src/cz/cuni/mff/d3s/deeco/runtime/DEECoNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ public int getId() {
return nodeId;
}

@Override
public ComponentInstance deployComponent(Object component) throws AnnotationProcessorException {
return processor.processComponent(component);
}
Expand All @@ -227,6 +228,7 @@ public EnsembleDefinition deployEnsemble(Class ensemble) throws AnnotationProces
return processor.processEnsemble(ensemble);
}

@Override
public void undeployEnsemble(String ensembleName) throws AnnotationProcessorException, DuplicateEnsembleDefinitionException {
processor.removeEnsemble(ensembleName);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -321,11 +321,19 @@ public void notifyChanged(Notification notification) {
instance.eAdapters().add(ensembleControllerAdapter);
componentInstanceAdapters.put(instance, ensembleControllerAdapter);

}
}

/**
* Registers the provided factory with this runtime instance. An {@link EnsembleFormationTask} is immediately created
* for each existing component and associated with it. The factory is stored in the runtime, and an additional task
* is created whenever a new component is added.
*/
@Override
public void registerEnsembleFactory(EnsembleFactory factory) {
// TODO Guards
if (factory == null)
throw new IllegalArgumentException("Attempted to pass a null factory argument.");
if (registeredEnsembleFactories.contains(factory))
throw new IllegalStateException("Cannot register the same factory object twice");

for(ComponentInstance instance : componentRecords.keySet()) {
EnsembleFormationTask newTask = new EnsembleFormationTask(scheduler, factory, instance);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.Collection;

import cz.cuni.mff.d3s.deeco.ensembles.EnsembleFactory;
import cz.cuni.mff.d3s.deeco.ensembles.EnsembleFormationException;
import cz.cuni.mff.d3s.deeco.ensembles.EnsembleInstance;
import cz.cuni.mff.d3s.deeco.knowledge.container.KnowledgeContainer;
import cz.cuni.mff.d3s.deeco.knowledge.container.KnowledgeContainerException;
Expand All @@ -13,35 +14,48 @@
import cz.cuni.mff.d3s.deeco.model.runtime.custom.TimeTriggerExt;
import cz.cuni.mff.d3s.deeco.scheduler.Scheduler;

/**
* Represents a task responsible for periodically forming ensemble instances (i.e. implementors of {@link EnsembleInstance}) using
* the associated {@link EnsembleFactory} and performing knowledge exchange on the resultant instances. Uses {@link TrackingKnowledgeContainer}
* for providing knowledge access to the ensembles, as well as committing the changes back into the knowledge storage.
*
* @author Filip Krijt
*/
public class EnsembleFormationTask extends Task {

private EnsembleFactory factory;
private ComponentInstance componentInstance;
private TimeTrigger trigger;

/**
* Creates a new {@link EnsembleFormationTask} associated with the provided factory and component instance.
* @param scheduler
* @param factory
* @param componentInstance
*/
public EnsembleFormationTask(Scheduler scheduler, EnsembleFactory factory, ComponentInstance componentInstance) {
super(scheduler);
this.factory = factory;
this.componentInstance = componentInstance;
this.trigger = new TimeTriggerExt();
this.trigger.setOffset(factory.getOffset());
this.trigger.setPeriod(factory.getPeriod());
this.trigger.setOffset(factory.getSchedulingOffset());
this.trigger.setPeriod(factory.getSchedulingPeriod());
}

@Override
public void invoke(Trigger trigger) throws TaskInvocationException {
KnowledgeContainer container = TrackingKnowledgeContainer.createFromKnowledgeManagers(componentInstance.getKnowledgeManager(),
componentInstance.getShadowKnowledgeManagerRegistry().getShadowKnowledgeManagers());

Collection<EnsembleInstance> instances = factory.createInstances(container);

for(EnsembleInstance instance : instances) {
instance.performKnowledgeExchange();
}
public void invoke(Trigger trigger) throws TaskInvocationException {

try {
KnowledgeContainer container = TrackingKnowledgeContainer.createFromKnowledgeManagers(componentInstance.getKnowledgeManager(),
componentInstance.getShadowKnowledgeManagerRegistry().getShadowKnowledgeManagers());

Collection<EnsembleInstance> instances = factory.createInstances(container);

for(EnsembleInstance instance : instances) {
instance.performKnowledgeExchange();
}
container.commitChanges();
} catch (KnowledgeContainerException e) {
} catch (KnowledgeContainerException | EnsembleFormationException e) {
throw new TaskInvocationException(e);
}
}
Expand All @@ -59,5 +73,9 @@ protected void unregisterTriggers() {
@Override
public TimeTrigger getTimeTrigger() {
return trigger;
}
}

public EnsembleFactory getFactory() {
return factory;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package cz.cuni.mff.d3s.deeco.demo.intelligent;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.Test;
import static org.junit.Assert.*;
import cz.cuni.mff.d3s.deeco.annotations.processor.AnnotationProcessorException;
import cz.cuni.mff.d3s.deeco.ensembles.EnsembleFactory;
import cz.cuni.mff.d3s.deeco.runners.DEECoSimulation;
import cz.cuni.mff.d3s.deeco.runtime.DEECoException;
import cz.cuni.mff.d3s.deeco.runtime.DEECoNode;
import cz.cuni.mff.d3s.deeco.timer.DiscreteEventTimer;
import cz.cuni.mff.d3s.deeco.timer.SimulationTimer;

/**
* A demo of the {@link EnsembleFactory}-oriented ensemble deployment functionality. Also serves as an integration test verifying
* that ensemble formation and subsequent knowledge transfer is performed.
* @author Filip Krijt
*
*/
public class DummyEnsemblesTest {

public static void main(String[] args) throws InstantiationException, IllegalAccessException, DEECoException, AnnotationProcessorException {
new DummyEnsemblesTest().testEnsembles(false);
}

@Test
public void testEnsembles() throws InstantiationException, IllegalAccessException, DEECoException, AnnotationProcessorException {
testEnsembles(true);
}

private void testEnsembles(boolean silent) throws InstantiationException, IllegalAccessException, DEECoException, AnnotationProcessorException {

ByteArrayOutputStream baos = new ByteArrayOutputStream();
if (silent) {
SimpleEnsembleFactory.outputStream = new PrintStream(baos);
} else {
SimpleEnsembleFactory.outputStream = System.out;
}

/* create main application container */
SimulationTimer simulationTimer = new DiscreteEventTimer();
DEECoSimulation realm = new DEECoSimulation(simulationTimer);

/* create one and only deeco node (centralized deployment) */
DEECoNode deeco = realm.createNode(0);
/* deploy components and an ensemble factory */

SimpleEnsembleFactory factory = new SimpleEnsembleFactory();

List<Robot> robots = new ArrayList<Robot>(Arrays.asList(new Robot("Wall-E"), new Robot("Gizmo"), new Robot("R2")));

for(Robot r : robots) {
deeco.deployComponent(r);
}

deeco.deployEnsembleFactory(factory);

// Add another component for testing purposes once the factory is deployed
Robot omnius = new Robot("Omnius");
robots.add(omnius);
deeco.deployComponent(omnius);

// Run the simulation
realm.start(999);

if (silent) {
String out = baos.toString().trim();
// Formation should be requested for each robot as many times as the formation period fits in the simulation run time
int scheduleCount = robots.size() * ((999 - factory.getSchedulingOffset()) / factory.getSchedulingPeriod() + 1);
assertEquals(scheduleCount, factory.formationCount);

// The output should be strictly alternating between formation and exchange, with exactly scheduleCount occurences
String desiredOutput = String.join(System.lineSeparator(), Collections.nCopies(scheduleCount,
"Ensemble formation requested!" + System.lineSeparator() + "Knowledge exchange performed!"));

assertEquals(desiredOutput, out);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ public class SimpleEnsemble implements EnsembleInstance {

@Override
public void performKnowledgeExchange() {
//System.out.println("Knowledge ex!");
SimpleEnsembleFactory.outputStream.println("Knowledge exchange performed!");
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package cz.cuni.mff.d3s.deeco.demo.intelligent;

import java.io.PrintStream;
import java.util.Arrays;
import java.util.Collection;

Expand All @@ -8,20 +9,23 @@
import cz.cuni.mff.d3s.deeco.knowledge.container.KnowledgeContainer;

public class SimpleEnsembleFactory implements EnsembleFactory {

public static PrintStream outputStream = System.out;
int formationCount = 0;

@Override
public Collection<EnsembleInstance> createInstances(KnowledgeContainer container) {
//System.out.println("Formation requested!");
public Collection<EnsembleInstance> createInstances(KnowledgeContainer container) {
++formationCount;
outputStream.println("Ensemble formation requested!");
return Arrays.asList(new SimpleEnsemble());
}

@Override
public int getOffset() {
public int getSchedulingOffset() {
return 42;
}

@Override
public int getPeriod() {
return 1000;
public int getSchedulingPeriod() {
return 400;
}
}
Loading

0 comments on commit c99a8df

Please sign in to comment.