| 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("<pre>"); |
| sb.append(getAreaID(region)); |
| sb.append(" <br>"); |
| 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(" <br>"); |
| } |
| sb.append("<pre>"); |
| 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 |
| |
| |