blob: 579833fac2e8054536afbeec99bf5bfff99c995c [file] [log] [blame]
package org.eclipse.stem.ui.ge;
/*******************************************************************************
* Copyright (c) 2006 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
import java.io.File;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.runtime.Preferences;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.edit.provider.ItemPropertyDescriptor;
import org.eclipse.stem.core.common.DublinCore;
import org.eclipse.stem.core.graph.Graph;
import org.eclipse.stem.core.graph.Node;
import org.eclipse.stem.core.graph.NodeLabel;
import org.eclipse.stem.core.model.Decorator;
import org.eclipse.stem.core.model.Model;
import org.eclipse.stem.core.scenario.Scenario;
import org.eclipse.stem.core.sequencer.Sequencer;
import org.eclipse.stem.data.geography.GeographicNames;
import org.eclipse.stem.definitions.adapters.relativevalue.RelativeValueProvider;
import org.eclipse.stem.definitions.adapters.relativevalue.RelativeValueProviderAdapter;
import org.eclipse.stem.definitions.adapters.relativevalue.RelativeValueProviderAdapterFactory;
import org.eclipse.stem.definitions.adapters.spatial.geo.LatLong;
import org.eclipse.stem.definitions.adapters.spatial.geo.LatLong.Segment;
import org.eclipse.stem.definitions.adapters.spatial.geo.LatLongProvider;
import org.eclipse.stem.definitions.adapters.spatial.geo.LatLongProviderAdapter;
import org.eclipse.stem.definitions.adapters.spatial.geo.LatLongProviderAdapterFactory;
import org.eclipse.stem.definitions.adapters.spatial.geo.PlatformLatLongDataProvider;
import org.eclipse.stem.definitions.nodes.impl.RegionImpl;
import org.eclipse.stem.jobs.preferences.PreferenceConstants;
import org.eclipse.stem.jobs.simulation.ISimulation;
import org.eclipse.stem.jobs.simulation.ISimulationListener;
import org.eclipse.stem.jobs.simulation.ISimulationManagerListener;
import org.eclipse.stem.jobs.simulation.SimulationEvent;
import org.eclipse.stem.jobs.simulation.SimulationManager;
import org.eclipse.stem.jobs.simulation.SimulationManagerEvent;
import org.eclipse.stem.jobs.simulation.SimulationState;
import org.eclipse.stem.ui.ge.kml.KmlDisplaySelection;
import org.eclipse.stem.ui.ge.kml.StemKml;
import org.eclipse.stem.ui.ge.views.GEPreferencePage;
import org.eclipse.stem.ui.ge.views.GEView;
import org.eclipse.stem.ui.views.geographic.map.GeographicSelectionElements;
/**
* This is the STEM half of the interface between
* STEM and GoogleEarth.
*
* It listens for Simulations to be added or deleted and maintains a
* list of simulations. When a simulation becomes active it then
* listens for Simulation events.
* <p>
* When a simulation cycle completes, we are notified and
* it will take the STEM data and call StemKml to convert
* it to KML and either log it to a set of files for later display
* or send it directly to GoogleEarth.
* <p>
* The overall process flow is the following:
* <pre>
* <b>simulationsChanged:</b> Notified when a new Simulation is added
* or removed. If added then setActive() is called to add it to
* the list of Simulations being handled.
*
* <b>simulationChanged:</b> Notified when a cycle ends. It calls
* the processCycle method.
*
* <b>processCycle</b>Main process when a processing cycle ends.
*
* <b>buildMap()</b> called on 1st cycle to build a map of
* GEData instances that contains the geographic description
* of each county/areaid
*
* It then uses the PreferencePage option to decide how to
* comunicate with GoogleEarth.
*
* <b>storeSEIR()</b> This updates the GEData instances with the
* relative disease statistics.
*
* <b>generateKML()</b> This sends all the information to the
* GEJob instance where a KML file for this cydle is written.
*
* </pre>
*
*/
public class GEInterface
implements ISimulationListener, ISimulationManagerListener{
/**
* template for the KML filename written on the
* Nth cycle for type T
*/
private static final String controlTemplate = "control_&N_&T.kml";
/**
* List of active simulations keyed by Name
*
* The list is updated by SimulationManager events
* that add or remove simulations.
*/
private Map<String,GESimEntry> activeSimulations = null;
/**
* map of geographic data keyed by area id
*/
private Map<String, GEData> stemMap = null;
/**
* GEView handles all the gui ui for us
*/
private GEView geView = null;
/**
* This will contain the simulation id when that simulation
* is sending its KML to GoogleEarth. When it is filled
* in any subsequent requests to log and view will only do logging.
* It is cleared when the simulation is removed.
*/
private String activeView = null;
/**
* when set to a node name then the displayMap method
* will only display that node.
*/
private String displayNode = null;
/**
* Cycle being processed.
*/
//private int cycle = 0;
/**
* This map is used to collect nodes that have been
* displayed by previous requests so that this can
* be an accumulative display.
*/
private Map<String,GEData> stemMapNode = null;
/**
* default Aspect to be displayed for simulations.
* Set by GEView context menu to override
* the defaultAspect specified in Aspect.properties
*/
private Aspect defaultAspect = null;
/**
* place to store an error message so the caller can get it.
*/
private String errorMessage = null;
/**
* when user requests a manual display of map
* set this true
*/
private boolean manualRequest = false;
/**
* Reference to the display module that
* displays the info based on a selection by
* the mapview view
*/
private final KmlDisplaySelection displaySelection =
new KmlDisplaySelection();
/**
* remember if we have isssued a displayArea cmd
* so we can clean it up.
*/
private boolean didDisplayArea = false;
/**
*
* Constructor.
*
* - setup to listen for SimulationManager events
* - check if existing simulations.
* @param geView GUI class that is invoking us.
*/
public GEInterface(GEView geView) {
GELog.debug(this,"constructor: ");
this.geView = geView;
Aspect.setup();
activeSimulations = new HashMap<String,GESimEntry>(1);
}
/**
* called by GEView to do any initialization
* after we have setup the GUI environment
*
* It will startup the servlet web server if possible
*
* @return true if initialization is successful
*
*/
public boolean init() {
boolean ok = true;
boolean okKML = true;
SimulationManager simulationManager = SimulationManager.getManager();
simulationManager.addSimulationManagerListener(this);
List<ISimulation>list = simulationManager.getActiveSimulations();
boolean autolog = GEPreferencePage.isAutoLogging();
for (ISimulation sim: list) {
String name = getSimulationId(sim);
GELog.debug(this,"simulationAdded: "+name+" "+sim);
setActive(sim,autolog);
}
// check for valid web server
String url = StemKml.initWebServer();
GELog.debug(this,"Web server URL: "+url);
if (url == null ) {
setErrorMessage("Unable to access WebServer");
ok = false;
} else {
okKML = StemKml.verifyGE();
// handle undefined KML
if (! okKML) {
setErrorMessage("GoogleEarth KML files are not defined");
}
}
if (!ok || !okKML) {
// check if preferences will work with no web
// server or no KNL file definition
ok = checkPreferences(url,okKML);
if (!ok) {
GELog.debug(getErrorMessage());
}
}
return ok;
}
/**
* verify (and change) the preferences based on the
* environment.
*
* If a webserver is not available or if googleearth
* has not been installed then it will limit the
* communication methods to not use a webserve or
* not try to launch the kml file.
*
* @param url URL for web server or null
* @param okGE false if googleEarth not installed
* @return false if not OK and changes had to be made
*/
private boolean checkPreferences(String url,boolean okGE) {
boolean result = false;
int method = GEPreferencePage.getMethod();
int newMethod = -1;
switch (method) {
case GEPreferencePage.M_LOG_ONLY:
// this method alway works
result = true;
break;
case GEPreferencePage.M_LOG_SERVLET:
// this method will not work if no server
result = false;
if ( url == null && okGE) {
newMethod = GEPreferencePage.M_AUTO_LAUNCH;
errorMessage = "No WebServer: Changed to directly launch KML";
} else {
newMethod = GEPreferencePage.M_LOG_ONLY;
errorMessage = "KML is not recognized, Changed to only Log files";
}
break;
case GEPreferencePage.M_ASYNC_SERVLET:
// this method will not work if no server
if ( url == null && okGE) {
newMethod = GEPreferencePage.M_AUTO_LAUNCH;
errorMessage = "No WebServer: Changed to directly launch KML";
} else {
newMethod = GEPreferencePage.M_LOG_ONLY;
errorMessage = "KML is not recognized, Changed to only Log files";
}
break;
case GEPreferencePage.M_AUTO_LAUNCH:
// this method will not work if KML is unknown
if (! okGE) {
newMethod = GEPreferencePage.M_LOG_ONLY;
errorMessage = "KML is not recognized, Changed to only Log files";
}
break;
case GEPreferencePage.M_MANUAL_DISPLAY:
// this method is always OK
break;
default:
}
if (newMethod != -1) {
GEPreferencePage.setMethod(newMethod);
result = false; // tell about change
}
return result;
}
/**
* We get here because we are listening for SimulationsChanged
* events from the Simulation Manager and one occured.
* We will check for a Simulation being removed and if so check if
* it is one of our active simulation and if so remove it.
* If a simulation is being added, it will be added to the list of
* active simulations.
*
*/
public void simulationsChanged(SimulationManagerEvent event) {
GELog.debug(this.getClass(), "simulationsChanged: ");
// GELog.memory();
if (event.getSimulationsRemoved().length > 0) {
for (ISimulation sim : event.getSimulationsRemoved()) {
String id = getSimulationId(sim);
GELog.debug(this.getClass(), "simulationRemoved: " + id + " "
+ sim);
GESimEntry existing = activeSimulations.get(id);
if (existing != null) {
boolean active = isActiveView(sim);
setActive(sim, false);
activeSimulations.remove(id);
if (active) {
stopGE();
}
GELog.debug(this, "Active simulation removed: " + id);
}
}
} else if (event.getSimulationsAdded().length > 0) {
boolean autolog = GEPreferencePage.isAutoLogging();
for (ISimulation sim : event.getSimulationsAdded()) {
String name = getSimulationId(sim);
GELog.debug(this, "simulationAdded: " + name + " " + sim);
GESimEntry existing = activeSimulations.get(name);
if (existing == null) {
boolean ok = setActive(sim, autolog);
if (!ok) {
if (!autolog) {
geView.showMessage(errorMessage);
}
}
}
}
}
} // simulationsChanged
/**
* Called by GEView.dispose()
*
*
*/
public void dispose() {
SimulationManager simulationManager = SimulationManager.getManager();
List<ISimulation> list =simulationManager.getActiveSimulations();
for (ISimulation sim:list) {
sim.removeSimulationListener(this);
}
simulationManager.removeListener(this);
if (activeView != null) {
// GE is talking to us
stopGE();
// wait a bit before we continue
// because this will kill the webserver
// that GoogleEarth is talking to.
try {
Thread.sleep(5000);
} catch (Exception e) {
// ignore
}
}
}
/**
* Listener for events that happen in a specific Simulation.
*
* <code>
* This gets called for the following event states
* SimulationState: RUNNING
* COMPLETED_CYCLE
* PAUSED
* We are interested in Completed_Cycle
*
* @param event
* the event that records what happened to the manager.
*/
public void simulationChanged(SimulationEvent event) {
try {
ISimulation simulation = event.getSimulation();
SimulationState state = event.getSimulationState();
String id = getSimulationId(simulation);
GESimEntry existing = activeSimulations.get(id);
Sequencer seq = simulation.getScenario().getSequencer();
if (state == SimulationState.COMPLETED_CYCLE) {
if (existing == null ) {
GELog.debug(this,"Simulation "+id+" not active for GE.");
return;
}
//existing.cycle++;
int cycle = seq.getCycle();
GELog.debug(this,id+" State="+state+" cycle="+cycle);
processCycle(simulation,state);
geView.refresh();
} else {
GELog.debug(this,id+" State="+state);
}
} catch (Exception e) {
GELog.error("simulationChanged: Failure ", e);
}
}
/**
* Handle the simulation event that just occured
* This is where the real processing starts.
* If we haven't already, we build a map of the
* geographical information.
* Then determine if we want to do anything on this cycle and
* determine how we want to comunicate with GE.
* Next we run thru the scenario nodes and pick up
* the current disease state for each node.
* Finally all of the information is sent to a
* background method that builds the KML file that is
* sent to GoogleEarth.
*
* @param simulation that event is for
* @param state Current state being processed
*
*/
private void processCycle(ISimulation simulation, SimulationState state ) {
String kmlfn = null;
boolean doit = false;
int nth = GEPreferencePage.getWhichCycle();
String id = getSimulationId(simulation);
GESimEntry existing = activeSimulations.get(id);
if (existing == null) {
GELog.debug(this,"Simulation "+id+" not active for GE.");
return;
}
int method = existing.getMethod();
String entryFolder = existing.getLogFolder();
Scenario scenario = simulation.getScenario();
Sequencer seq = scenario.getSequencer();
// get cycle from simulation
int cycle = seq.getCycle();
if (GELog.memoryCheck(0.8) ) {
GELog.debug(this,"Process for cycle "+
cycle+" skipped. Memory low");
return;
}
//if we haven't yet, then build geo map
if ((stemMap = existing.getStemMap()) == null ) {
if (! GELog.memoryCheck(0.8) ) {
stemMap = buildMap(simulation);
}
if (stemMap == null) {
GELog.debug(this.getClass(),"Unable to build stemMap");
return;
}
doit = true;
existing.setStemMap(stemMap);
}
StemKml stemKml = existing.getStemKml();
if (stemKml == null) {
stemKml = new StemKml();
existing.setStemKml(stemKml);
stemKml.init();
}
// if ManualDisplay and no user request
if (method == GEPreferencePage.M_MANUAL_DISPLAY &&
! manualRequest ) {
return;
}
if (cycle == 0 || nth == 1 ) {
doit = true;
} else if (nth > 1 && cycle%nth == 0 ) {
doit = true;
}
// Get aspect that we want view of
Aspect aspect = getAspectToDisplay(simulation);
if (manualRequest)
doit = true;
// decide how we want to process it
if (doit) {
try {
boolean launch = false;
boolean rename = false;
switch (method) {
case GEPreferencePage.M_LOG_ONLY:
// log the file but no launch or netlink
if (entryFolder != null) {
kmlfn = StemKml.getControlFN(entryFolder,
controlTemplate,aspect, cycle);
} else {
doit = false;
}
break;
case GEPreferencePage.M_LOG_SERVLET:
// log file and launch a netlink to display
if ( manualRequest ) {
doit = true;
if (activeView == null) {
launch = true;
kmlfn = StemKml.getControlFile();
} else {
kmlfn = StemKml.getControlFN(entryFolder,
controlTemplate,aspect, cycle);
}
} else if (! id.equals(activeView)) {
doit = false;
GELog.debug(this,"Unable to display id "+id);
} else if (entryFolder != null) {
kmlfn = StemKml.getControlFN(entryFolder,
controlTemplate,aspect, cycle);
} else {
doit = false;
GELog.debug(this,"Unable to display. Invalid folder");
}
break;
case GEPreferencePage.M_ASYNC_SERVLET:
if ( manualRequest ) {
if (activeView != null) {
doit = false;
GELog.debug(this,"Unable to do manual display");
} else {
launch = true;
kmlfn = StemKml.getControlFile();
}
} else {
if (! id.equals(activeView)) {
doit = false;
GELog.debug(this,"Not an active Simulation id: "+id+" activeView: "+
activeView);
} else {
kmlfn = StemKml.getControlFile();
rename = true;
}
}
break;
case GEPreferencePage.M_AUTO_LAUNCH:
// build control.kml and launch it
launch = true;
kmlfn = StemKml.getControlFile();
if ( ! manualRequest && (! id.equals(activeView)) ) {
doit = false;
GELog.debug(this,"Invalid. id: "+id+
" activeView: "+activeView);
}
break;
case GEPreferencePage.M_MANUAL_DISPLAY:
if (manualRequest) {
GELog.debug(this,"Do manual display");
launch = true;
kmlfn = StemKml.getControlFile();
doit = true;
} else {
doit = false;
}
break;
default:
}
manualRequest = false;
if (doit) {
// store the current SEIR data into GEData
storeAspects(simulation, stemMap);
// generate the KML file
GELog.debug(this.getClass(),"GenerateKML for id: "+
id + " aspect "+aspect.toString());
generateKML(kmlfn, stemKml,stemMap, aspect, cycle,launch,rename);
}
} catch (Exception e) {
GELog.error("processCycle(): Failure creating KML ",e);
activeSimulations.remove(id);
}
}
//GELog.debug(this.getClass(),"Done. cycle="+cycle);
}
/**
* called by GEView to display the current map for
* a specific admin area.
*
* @param adminFile File that contains desired data
* @param search String that is matched against area id
* @param clear If true then clear the existing map
* @return true if able to display map or false if could not.
*/
public boolean displayArea( String adminFile,String search, boolean clear) {
displayNode = search;
didDisplayArea = true;
errorMessage = null;
boolean result = true;
try {
if (clear)
stemMapNode = null;
GELog.debug(this,"displayMap() "+adminFile+" search: "+search);
if (adminFile == null) {
errorMessage = "AdminFile argument is null";
GELog.debug(this,errorMessage);
return false;
}
String fn = StemKml.getDisplayAreaFile();
StemKml stemKml = new StemKml();
stemKml.init();
// this will create GEData instances with LatLong data
// The LatLong comes from file rather than simulation
Map<String,GEData> stemMap = buildMap(adminFile,search);
if (stemMap.size() == 0) {
errorMessage = "Search argument "+search+
" did not match any admin area name.";
return false;
}
if (stemMapNode == null) {
stemMapNode = stemMap;
} else {
stemMapNode.putAll(stemMap);
}
// Get aspect that we want view of
Aspect aspect = Aspect.getAspect("S");
// generate the KML file
boolean rename = false;
int cycle = 0;
boolean launch = true;
generateKML(fn,stemKml,stemMapNode, aspect,
cycle,launch,rename);
} catch (RuntimeException e) {
result = false;
GELog.error("DisplayArea failure", e);
}
displayNode = null;
return result;
}
/**
* called by GEView to display the specified area
* when a Selection event is received from mapview
*
* @param region The Identifiable describing the admin area that
* was selected.
* @param gse reference to the data about the selection
*
* @return true if able to display map or false if could not.
*/
public boolean displaySelection( RegionImpl region,GeographicSelectionElements gse) {
didDisplayArea = true;
errorMessage = null;
boolean result = true;
try {
String fn = StemKml.getDisplayAreaFile();
StemKml stemKml = new StemKml();
stemKml.init();
Map<String,GEData> stemMap = buildSelectionMap(region,gse);
if (stemMap == null || stemMap.size() == 0) {
return false;
}
if (stemMapNode == null) {
stemMapNode = stemMap;
} else {
//stemMapNode.putAll(stemMap);
stemMapNode = stemMap; // clear???
}
// Aspect not used
Aspect aspect = null;
// generate the KML file
displaySelection.generatePolygons(fn, stemMapNode,aspect);
// launch the file for GoogleEarth
StemKml.launch(fn);
GELog.debug(this,"GoogleEarth Map submitted");
} catch (RuntimeException e) {
result = false;
GELog.error("DisplayArea failure", e);
}
displayNode = null;
return result;
}
/**
* called by GEView to display the current map
* This version sets a switch to cause
* a display on the next cycle if simulation or
* now if paused.
*
*
* @param simulation The currently selected Simulation
* @return true if able to display map or false if could not.
*/
public boolean displayMap(ISimulation simulation) {
boolean result = true;
SimulationState state = simulation.getSimulationState();
GELog.debug(this,"DisplayMap request");
manualRequest = true;
if (state != SimulationState.RUNNING) {
// process it if not running.
processCycle(simulation,simulation.getSimulationState());
}
// if it was running it will do it at end of cycle
return result;
}
/**
* called by GEView to display the KML files on GE
* via the Servlet API
*
* @param folder
* @return true if able to display map or false if could not.
*/
public boolean runGE(String folder) {
boolean result = true;
GELog.debug(this,"GoogleEarth run request");
if (activeView == null) {
activeView = "runGE";
StemKml.setWaitForKML(false);
StemKml.launchNetworkLink(folder, null);
} else {
errorMessage = "GoogleEarth is busy";
GELog.debug(this,errorMessage);
result = false;
}
return result;
}
/**
* called by GEView to start the GoogleEarth
* application if not already started
*
*
*
* @return true if able to display map or false if could not.
*/
public boolean startGE() {
boolean result = true;
GELog.debug(this,"GoogleEarth Start request");
StemKml.launchGE();
return result;
}
/**
* called by GEView when the GoogleEarth
* application is being restarted.
*
*
*
* @return true if able to reset or false if could not.
*/
public boolean restartGE() {
boolean result = true;
GELog.debug(this,"GoogleEarth Restart request");
StemKml.launchGE();
int method = 0;
// TODO
// reestablish the communication environment.
// If a networklink was active, reestablish it.
if (activeView != null) {
GESimEntry existing = activeSimulations.get(activeView);
if (existing != null) {
method = existing.getMethod();
ISimulation sim = existing.getSimulation();
if (sim.getSimulationState() == SimulationState.RUNNING){
errorMessage =
"Simulation should be paused while restarting GoogleEarth";
return false;
}
String folder = existing.getLogFolder();
if (method == GEPreferencePage.M_ASYNC_SERVLET ||
method == GEPreferencePage.M_LOG_SERVLET) {
StemKml.launchNetworkLink(folder, null);
}
}
}
return result;
}
/**
* called by GEView to stop the current
* display the KML files on GE
* via the Servlet API
*
*
* @return true
*/
public boolean stopGE() {
boolean result = true;
GELog.debug(this,"GoogleEarth Stop request");
//StemKml.launchGE();
if (didDisplayArea) {
StemKml.clearDisplayArea();
}
activeView = null;
// for some reason it appears that sometimes
// it takes to writing of an empty control file
// to stop the current NetworkLink so do it again
StemKml.launchGE();
return result;
}
/**
* Schedule the background job that will build the .kml file
* that will be sent to GoogleEarth
*
* @param fn Fully qualified Filename where we write the kml
* @param stemKml Object containing info about where and
* how to generate the KML.
* @param stemMap Map of Polygons with SEIR data and PopDensity
*
* @param aspect SEIR Type to be displayed
* @param cycle current cycle number
* @param launch true if file should be sent to GoogleEarth
* @param rename true if file should be written then renamed
* @return reference to the file containing the KML
*/
private StemKml generateKML(String fn,StemKml stemKml, Map<String,GEData> stemMap,
Aspect aspect,long cycle,boolean launch,boolean rename) {
try {
GEJob job = new GEJob("Generate KML");
job.generateKML(fn,stemKml, stemMap, aspect, cycle,launch,rename);
} catch (Exception e) {
e.printStackTrace();
}
return stemKml;
}
/**
* obtain the current aspect values and store them in the
* GEData instance
*
* @param sim
* @param stemMap
*/
private void storeAspects(ISimulation sim,Map<String,GEData> stemMap) {
Scenario scenario = sim.getScenario();
// We get the decorators from the scenario ...
Graph g = scenario.getCanonicalGraph();
Decorator[] decorators = g.getDecorators().toArray(new Decorator[g.getDecorators().size()]);
int err1ctr = 0; // no latlong data
int err2ctr = 0; // no aspect data
for (Decorator decorator : decorators) {
Object[] labels = decorator.getLabelsToUpdate().toArray();
for (Object element: labels){
if ( element instanceof NodeLabel) {
NodeLabel nodeLabel = (NodeLabel)element;
Node node = nodeLabel.getNode();
String key = node.getDublinCore().getTitle();
GEData data = stemMap.get(key);
if (data == null) { // filtered previously
continue;
}
boolean keep = filter(node,key,data);
if (!keep)
continue;
//if (nodeLabel instanceof SEIRLabelImpl) {
// TODO we need a way to get PopDensity
//SEIRLabelImpl label = (SEIRLabelImpl)nodeLabel;
//DiseaseModelState state = (DiseaseModelState)label.getDiseaseModelState();
// popDensity =50*Math.random(); //state.getPopulationDensity();
// data.setPopDensity(popDensity);
//}
RelativeValueProviderAdapter rvp = (RelativeValueProviderAdapter) RelativeValueProviderAdapterFactory.INSTANCE
.adapt(element, RelativeValueProvider.class);
rvp.setTarget((Notifier)element);
// Does the label have relative values?
if (rvp != null) {
Map<String,Double> map = data.getValueMap();
for (Iterator propertyIter =
rvp.getProperties().iterator(); propertyIter.hasNext();) {
ItemPropertyDescriptor property =
(ItemPropertyDescriptor) propertyIter.next();
String p = property.getDisplayName(property);
double v = rvp.getRelativeValue(property);
// TODO debug insert of Infectious value
// if (key.startsWith("M") && p.equals("I")) {
// v = Math.random();
// }
// if we are keeping track of this aspect
if (Aspect.exists(p)) {
map.put(p,v);
}
} // for each property
// remove debug code
// To debug this then make the infectious value random
// if (key.startsWith("Middlesex") && key.contains("MA")) {
// GELog.debug(this,key+" Aspects: "+data.getValuesAsString());
// //GELog.debug(this,"BBox:"+data.getBBox());
// }
// if (key.contains("G220010") ) {
// GELog.debug(this,key+" Aspects: "+data.getValuesAsString());
// //GELog.debug(this,"BBox:"+data.getBBox());
// }
} else {
//if (err2ctr == 0)
//GELog.debug(this,"Node: "+key+" has no aspect data");
err2ctr++;
}
}
} // for
}
if (err1ctr > 0)
GELog.debug(this,"Nodes with no LatLong data. count="+err1ctr);
if (err2ctr > 0)
GELog.debug(this,"Nodes with no aspect values. count="+err2ctr);
}
/**
* Build a StemMap instance for the specified Simulation
*
* The StemMap is a HashMap containing GEData objects
* keyed by areaid. The location object contains the
* geographic borders for the areaid.
*
* @param simulation that will be shown
* @return Map Key is node, element is GEData instance
*
*/
private Map<String,GEData> buildMap(ISimulation simulation) {
try {
stemMap = new HashMap<String,GEData>();
Scenario scenario = simulation.getScenario();
//String title = scenario.produceTitle();
//DublinCore dc = scenario.getDublinCore();
//GELog.debug(this,"buildMap(): title="+title);
//GELog.debug(this,"buildMap(): DublinCore="+dc);
// We get the graph...
final Graph canonicalGraph = scenario.getCanonicalGraph();
//GELog.debug(this,"buildMap(): canonicalGraph="+canonicalGraph);
if (canonicalGraph == null) {
GELog.debug(this,"buildMap(): canonicalGraph is null");
return null;
}
// ...and can now iterate through the nodes. Note that the method
// "getNodes" returns a map indexed by the URI of each of the nodes,
// thus we need to get the values of the map to have an actual list to
// iterator over.
int errctr = 0;
for (final Iterator nodeIter = canonicalGraph.getNodes().values()
.iterator(); nodeIter.hasNext();) {
final Node node = (Node) nodeIter.next();
String nodeTitle = node.getDublinCore().getTitle();
//GELog.debug(this, node+" : "+ nodeTitle);
boolean keep = filter(node,nodeTitle,null);
if (! keep)
continue;
// The node may or may not have lat/long data associated with
// it, if it doesn't the LatLong that's returned will be empty.
final LatLong latLongData = getLatLong(node);
if (latLongData != null && latLongData.size() > 0) {
GEData data = new GEData(nodeTitle,latLongData);
stemMap.put(nodeTitle,data);
} else {
// if (errctr <= 2) {
// GELog.debug(this,"buildMap(): No spacial data\n"+
// "Name="+nodeTitle+" Node="+node);
// }
errctr++;
}
} // for each node
if (errctr > 0)
GELog.debug(this,"Total buildmap errors = "+errctr);
} catch (Throwable e) {
GELog.error("Failure building area map", e);
stemMap = null;
}
return stemMap;
}
/**
* Filter out nodes that we are not interested in
* Note: The important filtering is done in the
* filter method in StemKml. This just affects gathering of
* aspect data .
*
* @param node
* @param nodeTitle
* @paran data GEData instance for the node
* @return true if we should keep the node, false to ignore it
*/
boolean filter(Node node,String nodeTitle, GEData data) {
// if (GEPreferencePage.isTest()) {
// if (nodeTitle.indexOf(" US-")< 0 ) {
// return false;
// }
// }
// // ignore alaska
// if (nodeTitle.indexOf(" US-AK")> 0 ) {
// return false;
// }
//// ignore hawaii
// if (nodeTitle.indexOf(" US-HI")> 0 ) {
// return false;
//
// filter out AdminArea 0 because they "may" be container entries
int adminarea = getAreaType(node);
if (adminarea <= 0) {
GELog.debug(this,"Skip AdminArea 0: "+node);
return false;
}
// debug stuff
if (displayNode != null) {
displayNode = displayNode.toLowerCase();
if (nodeTitle.toLowerCase().contains(displayNode) ) {
GELog.debug(this,"Display: "+nodeTitle);
return true;
} else {
//GELog.debug(this,"Do not Display: "+nodeTitle);
return false;
}
}
return true;
}
/**
* Get the id of the area from the DublinCore instance
* @param region Node representing an AdminArea
* @return 3 Char ISO id of Country
*/
private String getAreaID(Node region) {
final DublinCore dc = region.getDublinCore();
final String dcIdentifier = dc.getIdentifier();
final String isoKey = dcIdentifier.substring(dcIdentifier
.lastIndexOf("/")+1);
return isoKey;
}
/**
* Get the name of the area from the DublinCore instance
* @param region Node representing an AdminArea
* @return Name of the AdminArea
*/
private String getAreaName(Node region) {
final DublinCore dc = region.getDublinCore();
final String dcIdentifier = dc.getIdentifier();
final String isoKey = dcIdentifier.substring(dcIdentifier
.lastIndexOf("/")+1);
// Did we get it?
if (isoKey != null && !"".equals(isoKey)) {
// Yes
final String geographicName =
GeographicNames.getName(isoKey);
return geographicName;
// final StringBuilder sb= new StringBuilder(geographicName);
// sb.append(" (");
// sb.append(isoKey);
// sb.append(")");
// return sb.toString();
} else {
return dc.getTitle();
}
}
/**
* Get the type of the Admin area from the DublinCore instance
* @param region
* @return 0 1 or 2 (-1 if problem)
*/
private int getAreaType(Node node) {
int areatype = -1;
final DublinCore dc = node.getDublinCore();
final String spatial = dc.getSpatial();
if (spatial != null) {
String mapid = spatial.substring(spatial.lastIndexOf("/") + 1);
// Did we get it?
if (mapid != null && !"".equals(mapid)) {
// XXX_0_MAP.xml#XXX
mapid = mapid.substring(0, mapid.indexOf("#"));
mapid = mapid.substring(4, 5);
areatype = Integer.parseInt(mapid);
}
}
return areatype;
}
/**
* Build a StemMap instance for a specified Spatial location
* based on a Selection event from MapView
*
* The StemMap is a HashMap containing GEData objects
* keyed by areaid. The location object contains the
* geographic borders for the areaid.
*
* @param region The Identifiable describing the admin area that
* was selected.
* @param gse Instace of GeographicSelectionElements that was
* passed from MapView when mouseup occurred.
*
* @return Map Key is node, element is GEData instance
*
*/
private Map<String, GEData> buildSelectionMap(RegionImpl region,
GeographicSelectionElements gse) {
try {
DublinCore dc = region.getDublinCore();
String spatial = dc.getSpatial();
String uriString = spatial.replace("stemspatial:","");
stemMap = new HashMap<String, GEData>();
PlatformLatLongDataProvider provider = new PlatformLatLongDataProvider();
URI uriNode = URI.createURI(uriString);
LatLong latLong = provider.getLatLong(uriNode);
// get id of the area
String id = getAreaID(region);
String name = getAreaName(region);
GEData data = new GEData(id,name, latLong); // Use S just to get it to work
data.setValue(Aspect.getAspect("S"), 01.0);
String description = formatDescription(region,gse);
data.setDescription(description);
double longitude = gse.getLongitude();
double latitude = gse.getLatitude();
GELog.debug(longitude+":"+latitude);
//double[] center = data.getBBoxCenter();
//GELog.debug(center[0]+":"+center[1]);
// set the thumbtack on the point clicked by user
data.setPoint(longitude, latitude);
stemMap.put(id, data);
} catch (Throwable e) {
GELog.error("Failure building area map", e);
stemMap = null;
errorMessage = "Exception while building Map";
}
return stemMap;
}
/**
* Build a StemMap instance for the specified Simulation
*
* The StemMap is a HashMap containing GEData objects
* keyed by areaid. The location object contains the
* geographic borders for the areaid.
*
* @param adminFile file name to use in search
* @param search string to look for
* @return Map Key is node, element is GEData instance
*
*/
private Map<String, GEData> buildMap(String adminFile, String search) {
String baseURI =
"platform:/plugin/org.eclipse.stem.geography/" +
"resources/data/geo/country/";
try {
String uriString = baseURI+adminFile;
stemMap = new HashMap<String, GEData>();
PlatformLatLongDataProvider provider = new PlatformLatLongDataProvider();
final URI uri = URI.createURI(uriString);
final Collection<String> ids = provider.getIds(uri);
if (ids.size() == 0) {
errorMessage = "Invalid Country code specified";
return stemMap;
}
String match = search.toLowerCase();
for (String id : ids) {
if (id.toLowerCase().contains(match)) {
URI uriNode = URI.createURI(uriString + "#" + id);
LatLong latLong = provider.getLatLong(uriNode);
if (latLong != null && latLong.size() > 0) {
GEData data = new GEData(id, latLong);
// Use S just to get it to work
data.setValue(Aspect.getAspect("S"), 1.0);
stemMap.put(id, data);
} else {
GELog.debug(this, "No spacial data" + " Name=" + id);
}
}
} // for each id
if (ids.size() == 0) {
errorMessage = "No Matching internal Administration area found";
}
} catch (Throwable e) {
GELog.error("Failure building area map", e);
stemMap = null;
errorMessage = "Exception while building Map";
}
return stemMap;
}
/**
* Create a formated display to use for description
* <pre>
* S: 25.3%
* I: 10.2%
* ..
* R: 0.0%
* </pre>
* @return formatted description
*/
private String formatDescription(RegionImpl region,
GeographicSelectionElements gse) {
StringBuffer sb = new StringBuffer(128);
Map<String,Double> relValues = getRelValues(region);
Set<String> aspects = relValues.keySet();
sb.append("&lt;pre&gt;");
sb.append(getAreaID(region));
sb.append(" &lt;br&gt;");
for(String aspect:aspects) {
Double relValue = relValues.get(aspect)*100;
// format as " S: 15.1%"
String result= String.format("%8s: %5.1f%%",aspect,relValue);
sb.append(result);
// add the html formatting
sb.append(" &lt;br&gt;");
}
sb.append("&lt;pre&gt;");
return sb.toString();
}
/**
* Get relative values from the Graph.
* We are given the RegionImpl for the Admin Area.
* We will get the lable from it that contains
* relative values and put then in a Map with
* the value name as the key.
*
* @param region
* @return Map containing <name:Value>
*/
private Map<String,Double> getRelValues(RegionImpl region) {
Map<String,Double> map = new HashMap<String, Double>();
List<NodeLabel> nodes = region.getLabels();
for(NodeLabel node:nodes) {
RelativeValueProvider rvp =
(RelativeValueProvider) RelativeValueProviderAdapterFactory.INSTANCE
.adapt(node, RelativeValueProvider.class);
// Does the label have relative values?
if (rvp != null) {
for (Iterator propertyIter =
rvp.getProperties().iterator(); propertyIter.hasNext();) {
ItemPropertyDescriptor property =
(ItemPropertyDescriptor) propertyIter.next();
String name = property.getDisplayName(property);
Double value = rvp.getRelativeValue(property);
map.put(name, value);
} // for
}
} // for
return map;
}
/**
* Get geographical border of the node. We'd like to have access to lat/long
* data of the node if there is any, to do that we use a factory to create
* an adapter that knows about the inner details of nodes (it really knows
* about all Identifiables) and implements the LatLongProvider interface.
*
* @param node
* @return border of the node espressed as an array of long/latitude points.
*/
LatLong getLatLong(final Node node) {
// The node may or may not have lat/long data associated with
// it, if it doesn't the list that's returned will be empty.
try {
final LatLongProviderAdapter latLongProvider =
(LatLongProviderAdapter) LatLongProviderAdapterFactory.INSTANCE
.adapt(node, LatLongProvider.class);
latLongProvider.setTarget(node);
return latLongProvider.getLatLong();
} catch (RuntimeException e) {
GELog.debug(this,e.getMessage());
return null;
}
}
/**
* Check if the specified simulation is actively
* being listened to. A simulation is active if
* it is listed in the map of active simulations
* and can therefore be manually displayed.
*
* @param sim
* @return <code>true</code> if active, <code>false</code> in not active or non existent
*/
public boolean isActive(ISimulation sim) {
String name = getSimulationId(sim);
GESimEntry existing = activeSimulations.get(name);
return (existing == null) ? false : existing.active;
}
/**
* Check if the specified simulation is the simulation
* being viewed by GoogleEarth
*
* @param sim
* @return true if activeView
*/
public boolean isActiveView(ISimulation sim) {
String name = getSimulationId(sim);
return name.equals(activeView);
}
/**
* Set the logging for the specified simulation.
* This creates the GESimEntry which is used to collect
* information about the ISimulation instance to used
* to build KML files.
*
* @param sim Simulation instance being activated
* (or deactivated)
* @param active set true to write file,
* set false to bypass write
* @return true if ok, false in failed with
* errorMessage
*/
public boolean setActive(ISimulation sim, boolean active) {
String name = getSimulationId(sim);
GESimEntry existing = activeSimulations.get(name);
GELog.debug(this.getClass(),"setActive: "+name+" "+active);
if (existing != null) {
// if already known about
if (existing.active == active) {
// no change in state do nothing
return true;
} else {
existing.active = active;
if (!existing.active) {
// do anything if deactivated????
if (name.equals(activeView))
activeView = null;
}
}
} else {
// new entry
existing = new GESimEntry(name,sim);
existing.active = active;
activeSimulations.put(name, existing);
existing.setAspectToDisplay(GEPreferencePage.getAspect());
//Handl this based on communication method
if (active) {
String entryFolder = existing.getLogFolder();
int method = GEPreferencePage.getMethod();
switch (method) {
case GEPreferencePage.M_LOG_ONLY:
// log the file but no launch or netlink
if (geView != null) {
entryFolder = GEPreferencePage.getFolder();
entryFolder = geView.verifyFolder(entryFolder);
existing.setLogFolder(entryFolder);
existing.setMethod(method);
}
sim.addSimulationListener(this);
break;
case GEPreferencePage.M_LOG_SERVLET:
// log file and launch a netlink to display
if (geView != null) {
entryFolder = GEPreferencePage.getFolder();
entryFolder = geView.verifyFolder(entryFolder);
existing.setLogFolder(entryFolder);
}
if (entryFolder != null) {
if (activeView == null) {
StemKml.setWaitForKML(true);
StemKml.launchNetworkLink(entryFolder,null);
activeView = name;
sim.addSimulationListener(this);
existing.setMethod(method);
} else {
errorMessage ="Simulation "+
activeView+
" already active on GoogleEarth.";
GELog.debug(this,errorMessage);
existing.active = false;
return false;
}
}
break;
case GEPreferencePage.M_ASYNC_SERVLET:
// write control.kml and
// launch netlink to display control.kml
// every n seconds
String kmlfn = StemKml.getControlFile();
File f = new File(kmlfn);
String parent = f.getParent()+File.separator;
kmlfn = f.getName();
kmlfn = parent+ kmlfn.replace(".","_Current.");
if (activeView == null) {
StemKml.setWaitForKML(true);
StemKml.launchNetworkLink(entryFolder,kmlfn);
activeView = name;
sim.addSimulationListener(this);
existing.setMethod(method);
} else {
errorMessage ="Simulation "+
activeView+
" already active on GoogleEarth.";
GELog.debug(this,errorMessage);
existing.active = false;
return false;
}
break;
case GEPreferencePage.M_AUTO_LAUNCH:
if (activeView == null ) {
activeView = name;
sim.addSimulationListener(this);
existing.setMethod(method);
} else {
errorMessage ="Simulation "+
activeView+
" already active on GoogleEarth.";
GELog.debug(this,errorMessage);
existing.active = false;
sim.addSimulationListener(this);
return false;
}
break;
case GEPreferencePage.M_MANUAL_DISPLAY:
sim.addSimulationListener(this);
existing.setMethod(method);
break;
default:
}// switch
}
}
return true;
}
/**
* Set the SEIR value that wwe want displayed.
*
* @param sim Simulation instance
* @param aspect the sEIRValue to set
*/
public void setAspectToDisplay(ISimulation sim, Aspect aspect) {
if (sim == null) {
setDefaultAspect(aspect);
} else {
String name = getSimulationId(sim);
GESimEntry existing = activeSimulations.get(name);
if (existing != null) {
// if already known about
existing.setAspectToDisplay(aspect);
} else {
setDefaultAspect(aspect);
}
}
}
/**
* Get the SEIR value to be displayed from user.
*
* @param sim
* Simulation instance
* @return the sEIRValue to display
*/
public Aspect getAspectToDisplay(ISimulation sim) {
String name = getSimulationId(sim);
GESimEntry existing = activeSimulations.get(name);
Aspect value = null;
if (existing != null) {
// if already known about
value = existing.getAspectToDisplay();
} else {
value = getDefaultAspect();
}
return value;
}
/**
* display status.
*
* This will display on the console a lot of
* information about the environment.
* Currently it displays the status on the console.
* At some point the important status may be
* placed into a dialog box and displayed.
*The main purpose of this is to have a way to
*display interesting stuff.
* It can be used as a problem reporting aid
* since one can take the output and use it in the
* problem description. So it is important that information
* that is needed in diagnosing problems with the
* STEM-GE interface be displayed here.
*
*
*
*/
public void displayStatus() {
boolean saveDebug = GELog.DEBUG;
GELog.DEBUG = true;
// display Preferences
GELog.debug(this,GEPreferencePage.display());
final Preferences preferences =
org.eclipse.stem.jobs.Activator.getDefault()
.getPluginPreferences();
boolean simulationSleep = preferences
.getBoolean(PreferenceConstants.SIMULATION_SLEEP_BOOLEAN);
// display an important delay value. GE needs it
int simulationSleepSeconds = preferences
.getInt(PreferenceConstants.SIMULATION_SLEEP_MILLISECONDS_INTEGER) * 1000;
GELog.debug(this,"SIMULATION_SLEEP: "
+simulationSleep);
GELog.debug(this,"SIMULATION_SLEEP_SECONDS: "
+simulationSleepSeconds);
GELog.debug(this,"activeView: "+activeView);
if (activeSimulations.size() == 0) {
GELog.debug(this,"No active Simulations");
} else {
GELog.debug(this,"Active Simulations: "+activeSimulations.size());
for (Map.Entry entry : activeSimulations.entrySet()) {
GESimEntry geSim = (GESimEntry)entry.getValue();
String name = (String)entry.getKey();
ISimulation sim = geSim.getSimulation();
try {
GELog.debug(this," Simulation: "+
" "+geSim.toString());
GELog.debug(this," State: "+sim.getSimulationState());
GESimEntry existing = activeSimulations.get(name);
GELog.debug(this," GESimEntry: "+existing);
Scenario scenario = sim.getScenario();
GELog.debug(this," Scenario: "+scenario);
DublinCore dc = scenario.getDublinCore();
GELog.debug(this," Scenario DublinCore: "+dc);
Sequencer sequencer = scenario.getSequencer();
GELog.debug(this," Sequencer: "+sequencer);
Model model = scenario.getModel();
GELog.debug(this," Model: "+model);
//GELog.debug(this," LongLat: "+displayLatLong(sim));
//GELog.debug(this," Aspect: "+displayAspect(sim));
} catch (Throwable t) {
GELog.error("Display Status failure", t);
}
}
}
GELog.DEBUG = saveDebug;
}
/**
* display the LatLong data.
* This is mostly for debug usage.
*
*
* @param simulation that will be shown
* @return display string of latlong data
*
*/
@SuppressWarnings("unused")
private String displayLatLong(ISimulation simulation) {
final StringBuilder sb = new StringBuilder();
int counter = 0;
try {
sb.append("LatLong data: ");
Scenario scenario = simulation.getScenario();
// We get the graph...
final Graph canonicalGraph = scenario.getCanonicalGraph();
GELog.debug(this,"displayLatLong(): canonicalGraph="+canonicalGraph);
if (canonicalGraph == null) {
GELog.debug(this,"displayLatLong(): canonicalGraph is null");
return null;
}
// ...and can now iterate through the nodes. Note that the method
// "getNodes" returns a map indexed by the URI of each of the nodes,
// thus we need to get the values of the map to have an actual list to
// iterator over.
for (final Iterator nodeIter = canonicalGraph.getNodes().values()
.iterator(); nodeIter.hasNext();) {
counter++;
if (counter>100) {
sb.append("\n Limit of 100 reached");
break;
}
final Node node = (Node) nodeIter.next();
String nodeTitle = node.getDublinCore().getTitle();
sb.append("\n"+"Node: "+nodeTitle);
final LatLongProviderAdapter latLongProvider = (LatLongProviderAdapter) LatLongProviderAdapterFactory.INSTANCE
.adapt(node, LatLongProvider.class);
latLongProvider.setTarget(node);
// The node may or may not have lat/long data associated with
// it, if it doesn't the list that's returned will be empty.
final LatLong latLongData = latLongProvider.getLatLong();
if (latLongData != null && latLongData.size() > 0) {
//GELog.debug(this,"displayLatLong(): Node="+nodeTitle);
// Now we just go through each segment and create a string.
for (Segment segment : latLongData.getSegments()) {
String data = createStringOfLatLongData(segment);
sb.append("LatLong: "+data);
} // for
} else {
GELog.debug(this,"buildMap()(): No spacial data for Node="+nodeTitle);
}
} // for each node
} catch (Throwable e) {
GELog.error("Failure building area map", e);
}
return sb.toString();
}
/**
* display the Aspect data.
* This is mostly for debug
*
* @param simulation that will be shown
* @return Display string containing info about SEIR valued
*
*/
@SuppressWarnings("unused")
private String displayAspect(ISimulation simulation) {
final StringBuilder sb = new StringBuilder();
try {
int counter = 0;
Scenario scenario = simulation.getScenario();
// We get the decorators from the scenario ...
Graph g = scenario.getCanonicalGraph();
Decorator[] decorators = g.getDecorators().toArray(new Decorator[g.getDecorators().size()]);
for (Decorator decorator : decorators) {
GELog.debug(this,"decorator: "+decorator.toString());
Object[] labels = decorator.getLabelsToUpdate().toArray();
for (Object element: labels){
counter++;
if (counter>100) {
sb.append("\n Limit of 100 reached");
break;
}
if ( element instanceof NodeLabel) {
NodeLabel nodeLabel = (NodeLabel)element;
Node node = nodeLabel.getNode();
String title = node.getDublinCore().getTitle();
sb.append("\nNode: "+title+" ");
RelativeValueProviderAdapter rvp = (RelativeValueProviderAdapter) RelativeValueProviderAdapterFactory.INSTANCE
.adapt(element, RelativeValueProvider.class);
rvp.setTarget((Notifier)element);
// Does the label have relative values?
if (rvp != null) {
for (Iterator propertyIter = rvp.getProperties().iterator(); propertyIter
.hasNext();) {
ItemPropertyDescriptor property = (ItemPropertyDescriptor) propertyIter
.next();
sb.append(property.getDisplayName(property));
sb.append(": ");
sb.append(String.format("%.2f", rvp.getRelativeValue(property)));
if (propertyIter.hasNext()) {
sb.append(", ");
}
} // for each property
} // if
}
} // for
}
} catch (Throwable e) {
GELog.error("Failure getting SEIR data", e);
}
return sb.toString();
}
/**
* Get the ID to use for getting the GESimEntry instance
* @param simulation
* @return "SIM[sequenceNumber"]"
*/
public static String getSimulationId(ISimulation simulation) {
if (simulation != null)
return "SIM["+
Integer.toString(simulation.getSequenceNumber())+
"]";
else
return null;
}
/**
* Display the latlong data from a LatLong segment
* A segment is a line or polygon.
*
* @param segment
* @return a string of the lat/long points
*/
private static String createStringOfLatLongData(final Segment segment) {
final StringBuilder sb = new StringBuilder();
final int size = segment.size();
for (int i = 0; i < size; i++) {
sb.append("(");
sb.append(segment.latitude(i));
sb.append(", ");
sb.append(segment.longitude(i));
sb.append(")");
} // for each lat/long pair
return sb.toString();
} // createStringOfLatLongData
/**
* @return the defaultAspect
*/
public Aspect getDefaultAspect() {
if (defaultAspect == null)
defaultAspect = Aspect.getDefault();
return defaultAspect;
}
/**
* @param defaultAspect the defaultAspect to set
*/
public void setDefaultAspect(Aspect defaultAspect) {
this.defaultAspect = defaultAspect;
}
/**
* Set an error message to display
* @param msg
*
*/
public void setErrorMessage(String msg) {
errorMessage = msg;
}
/**
* @return the errorMessage
*/
public String getErrorMessage() {
if (errorMessage == null)
return "";
else
return errorMessage;
}
/**
* @param sim Simulation that is being processed.
* @return the cycle
*/
public int getCycle(ISimulation sim) {
Scenario scenario = sim.getScenario();
Sequencer seq = scenario.getSequencer();
int cycle = seq.getCycle();
return cycle;
}
} // class GEInterface