| // CSVLogWriter |
| package org.eclipse.stem.util.loggers.views; |
| |
| /******************************************************************************* |
| * Copyright (c) 2007,2008 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.BufferedWriter; |
| import java.io.File; |
| import java.io.FileWriter; |
| import java.io.IOException; |
| import java.text.SimpleDateFormat; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Locale; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| |
| import org.eclipse.emf.ecore.EClass; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EStructuralFeature; |
| import org.eclipse.emf.edit.provider.ComposedAdapterFactory; |
| import org.eclipse.emf.edit.provider.IItemPropertyDescriptor; |
| import org.eclipse.emf.edit.provider.IItemPropertySource; |
| import org.eclipse.stem.adapters.time.TimeProvider; |
| import org.eclipse.stem.core.common.CommonPackage; |
| import org.eclipse.stem.core.graph.DynamicLabel; |
| import org.eclipse.stem.core.graph.IntegrationLabel; |
| import org.eclipse.stem.core.graph.IntegrationLabelValue; |
| 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.IntegrationDecorator; |
| import org.eclipse.stem.core.model.STEMTime; |
| import org.eclipse.stem.definitions.adapters.population.PopulationEnumerator; |
| import org.eclipse.stem.definitions.adapters.population.PopulationEnumeratorAdapter; |
| import org.eclipse.stem.definitions.adapters.population.PopulationEnumeratorAdapterFactory; |
| 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.diseasemodels.standard.DiseaseModel; |
| import org.eclipse.stem.diseasemodels.standard.DiseaseModelLabel; |
| import org.eclipse.stem.jobs.simulation.ISimulation; |
| import org.eclipse.stem.populationmodels.standard.DemographicPopulationModel; |
| import org.eclipse.stem.populationmodels.standard.PopulationGroup; |
| import org.eclipse.stem.populationmodels.standard.PopulationModel; |
| import org.eclipse.stem.populationmodels.standard.PopulationModelLabel; |
| import org.eclipse.stem.util.loggers.Activator; |
| import org.eclipse.stem.util.loggers.preferences.PreferenceConstants; |
| |
| /** |
| * A log writer writing CSV files containing data for a single state of the simulation. |
| * Columns contain location IDs as well as simulation time and iteration id. |
| */ |
| |
| public class NewCSVLogWriter extends LogWriter { |
| |
| // The buffer size (per log file) to use. |
| private final static int BUFSZ = 1024*1024; // 1 MB |
| |
| |
| |
| private static final String CSV_EXT = ".csv"; |
| |
| private static final String AIR_TRANSPORT_URI_DUPLICATE_FEATURE="node/transport/pipe"; |
| |
| /** |
| * |
| */ |
| private String directoryName; |
| |
| /** |
| * |
| */ |
| private String logDataObjectName; |
| |
| //private final static String DUBLIN_CORE_CLASS = "DublinCore"; |
| |
| private static SimpleDateFormat dateFormat = new SimpleDateFormat("EEE d MMM yy", Locale.getDefault()); |
| |
| /** |
| * CSV Header Label for time column |
| */ |
| public static final String TIME_LABEL = "time"; |
| |
| /** |
| * CSV Header Label for iteration column |
| */ |
| public static final String ITERATION_LABEL = "iteration"; |
| |
| /** |
| * Name of all run parameter files (one per scenario folder) |
| */ |
| public static final String RUN_PARAMETER_FILE_NAME = "runparameters.csv"; |
| |
| |
| private int icount = 0; |
| |
| /** |
| * FileWriters are stored here, organized by state (e.g. S, E, I, R) and geographic level |
| */ |
| |
| private final Map<StateLevelMap, BufferedWriter> fileWriters; |
| |
| private boolean logIntegers; |
| |
| /** |
| * |
| * @param dirName |
| * @param simulation |
| * @param dm |
| * @param logParameters |
| */ |
| public NewCSVLogWriter(final String dirName, final ISimulation simulation, IntegrationDecorator dm, boolean logParameters) { |
| logIntegers = Activator.getDefault().getPreferenceStore().getBoolean(PreferenceConstants.LOG_INTEGER_PREFERENCE); |
| fileWriters = new HashMap<StateLevelMap, BufferedWriter>(); |
| this.directoryName = dirName; |
| |
| needsHeader = true; |
| done = false; |
| icount = 0; |
| |
| // append the disease name or population type |
| if(dm instanceof DiseaseModel) { |
| logDataObjectName = ((DiseaseModel)dm).getDiseaseName().trim(); |
| } |
| else if (dm instanceof PopulationModel) { |
| logDataObjectName = ((PopulationModel)dm).getName().trim(); |
| } |
| |
| if (logDataObjectName == null) { |
| Activator.logError("Failed to find a disease or population model. Cannot create CSV Logger", null); |
| return; |
| } |
| |
| this.directoryName += logDataObjectName + sep; |
| |
| // remove illegal strings |
| directoryName= directoryName.replaceAll("\"", ""); |
| |
| final File dir = new File(this.directoryName); |
| |
| if ((!dir.exists()) || (!dir.isDirectory())) { |
| // create it. |
| boolean success = dir.mkdirs(); |
| if (!success) { |
| Activator.logError( |
| "Failed to Create Driectory" + directoryName, |
| new IOException("Failed to Create Driectory" |
| + directoryName)); |
| } |
| |
| } |
| |
| if(logParameters) { |
| logRunParameters(dm); |
| } |
| |
| |
| } // NewCSVLogWriter |
| |
| |
| /** |
| * Must implement this method to log data in run thread |
| * |
| * @param rvp |
| * |
| */ |
| @Override |
| public void logHeader(final RelativeValueProviderAdapter rvp) { |
| /* |
| * TODO do we need a header? |
| */ |
| }// log header |
| |
| /** |
| * logHeader New method |
| * |
| * @param sim Simulation to log |
| * @param dm Disease Model |
| * @param nodeLevels Level information for each node in the simulation |
| * @param timeProvider Time provider |
| */ |
| |
| @Override |
| public void logHeader(ISimulation sim, IntegrationDecorator dm, Map<Node, Integer>nodeLevels, TimeProvider timeProvider) { |
| |
| |
| int headerItemCount = 0; |
| |
| String dirs = this.directoryName; |
| File dir = new File(dirs); |
| if(!dir.exists()) { |
| boolean success = dir.mkdirs(); |
| if(!success) { |
| Activator.logError( |
| "Failed to Create Driectory" + directoryName, |
| new IOException("Failed to Create Driectory" |
| + directoryName)); |
| } |
| } |
| // Find min/max level |
| int minLevel = Integer.MAX_VALUE; |
| int maxLevel = -1; |
| for(int level:nodeLevels.values()) { |
| if(level < minLevel)minLevel = level; |
| if(level > maxLevel)maxLevel = level; |
| } |
| try { |
| |
| // Get the first node in the canonical graph and look at the labels. |
| // We will generate one log file for each label |
| // Find the first node that has some labels and use those as representative labels |
| // for every node |
| |
| IntegrationLabel label = null; |
| Iterator<DynamicLabel> it = ((Decorator)dm).getLabelsToUpdate().iterator(); |
| while(it.hasNext()) { |
| DynamicLabel l = it.next(); |
| if(l instanceof IntegrationLabel) { |
| label = (IntegrationLabel)l; |
| break; |
| } |
| |
| } |
| if(label == null) { |
| // We couldn't find any labels. PANIC! |
| Activator.logError("Cannot log, no label found for decorator!", new Exception()); |
| return; |
| } |
| |
| final RelativeValueProviderAdapter rvp = (RelativeValueProviderAdapter) RelativeValueProviderAdapterFactory.INSTANCE |
| .adapt(label, RelativeValueProvider.class); |
| List<IItemPropertyDescriptor>properties = rvp.getProperties(); |
| if(properties == null) |
| Activator.logError("Cannot retrieve properties for "+label, null); |
| |
| ArrayList<String>populationIdentifiers = getPopulationIdentifiers(dm); |
| |
| for(IItemPropertyDescriptor property:properties) { |
| for(int level = minLevel;level <=maxLevel;++level) { |
| |
| for(String pid:populationIdentifiers) { |
| |
| boolean fileHasData = false; |
| StateLevelMap slm = new StateLevelMap(pid, property.getDisplayName(property), level); |
| File pdir = new File(dirs+pid+sep); |
| if(!pdir.exists()) { |
| if (!pdir.mkdir()) { |
| throw new IOException("Error creating log store directories: "+ pdir.getAbsolutePath()); |
| } |
| } |
| String file = dirs+pid+sep+property.getDisplayName(property)+"_"+level+CSV_EXT; |
| BufferedWriter fw = new BufferedWriter(new FileWriter(file), BUFSZ); // 10 MB |
| |
| |
| Iterator<Node> nodeIterator = this.getNodeIterator(level, nodeLevels); |
| // Iterate over nodes for a given resolution |
| fw.write(ITERATION_LABEL); |
| fw.write(","); |
| fw.write(TIME_LABEL); |
| |
| int nodeCount = 0; |
| |
| while(nodeIterator.hasNext()) { |
| Node node = nodeIterator.next(); |
| NodeLabel mLabel = getMatchingLabel(dm, node, pid); |
| if(mLabel == null) continue; |
| String nodeURI = node.getURI().toString(); |
| if(nodeURI.indexOf(AIR_TRANSPORT_URI_DUPLICATE_FEATURE)>=0) continue; |
| fileHasData = true; |
| String id = this.filterLocationId(node.getURI().toString()); |
| fw.write(","); |
| fw.write(id); |
| headerItemCount++; |
| nodeCount++; |
| } |
| |
| fw.write("\n"); |
| if(fileHasData) { |
| // register the writer |
| fileWriters.put(slm, fw); |
| } else { |
| // don't ever write empty files |
| fw.flush(); |
| fw.close(); |
| File toDelete = new File(file); |
| toDelete.delete(); |
| fw=null; |
| } |
| } |
| } |
| }// all properties |
| |
| needsHeader = false; |
| } catch(IOException ioe) { |
| Activator.logError("Error writing log header ", ioe); |
| } |
| |
| } |
| |
| /** |
| * Returns true if the node has a label that is updated by the decorator. |
| * |
| * @param dm |
| * @param n |
| * @param popId |
| * @return The label of the correct type matching the population identifier, or null if not found |
| */ |
| private NodeLabel getMatchingLabel(IntegrationDecorator dm, Node n, String popId) { |
| for(NodeLabel label:n.getLabels()) |
| if(dm instanceof DiseaseModel && label instanceof DiseaseModelLabel && ((DiseaseModelLabel)label).getDecorator().equals(dm) && ((DiseaseModelLabel)label).getPopulationModelLabel().getPopulationIdentifier().equals(popId)) return label; |
| else if (dm instanceof PopulationModel && label instanceof PopulationModelLabel && ((PopulationModelLabel)label).getDecorator().equals(dm) && ((PopulationModelLabel)label).getPopulationIdentifier().equals(popId)) return label; |
| return null; |
| } |
| |
| /** |
| * Return all the population identifiers the decorator manages |
| * |
| * @param id |
| * @return ArrayList<String> The population identifiers |
| */ |
| |
| private ArrayList<String> getPopulationIdentifiers(IntegrationDecorator id) { |
| |
| ArrayList<String>result = new ArrayList<String>(); |
| |
| if(id instanceof DiseaseModel) { |
| PopulationEnumeratorAdapter en = (PopulationEnumeratorAdapter)PopulationEnumeratorAdapterFactory.INSTANCE.adapt(id, PopulationEnumerator.class); |
| if(en != null) { |
| en.setTarget(id); |
| String [] pops = en.getPopulationIdentifiers(); |
| for(int i=0;i<pops.length;++i) |
| result.add(pops[i]); |
| } else result.add(((DiseaseModel)id).getPopulationIdentifier()); |
| |
| } else if (id instanceof PopulationModel) { |
| |
| if(id instanceof DemographicPopulationModel) { |
| // We need to create separate log directories for each population group |
| DemographicPopulationModel dpm = (DemographicPopulationModel)id; |
| for(PopulationGroup g:dpm.getPopulationGroups()) |
| result.add(g.getIdentifier()); |
| } else result.add(((PopulationModel)id).getPopulationIdentifier()); |
| } |
| return result; |
| } |
| |
| |
| /** |
| * Creates a log file for run parameters. Only one of these is created per |
| * diseaseFolder |
| * |
| * @param dm Disease Model |
| */ |
| |
| public void logRunParameters(IntegrationDecorator dm) { |
| if (dm == null) { // check |
| return; |
| } |
| |
| try { |
| final FileWriter fwp = new FileWriter(directoryName |
| + RUN_PARAMETER_FILE_NAME); |
| |
| |
| final ComposedAdapterFactory itemProviderFactory = new ComposedAdapterFactory( |
| ComposedAdapterFactory.Descriptor.Registry.INSTANCE); |
| |
| final IItemPropertySource propertySource = (IItemPropertySource) itemProviderFactory |
| .adapt(dm, IItemPropertySource.class); |
| |
| final List<IItemPropertyDescriptor> properties = propertySource |
| .getPropertyDescriptors(dm); |
| |
| StringBuilder header = new StringBuilder(); |
| StringBuilder values = new StringBuilder(); |
| |
| for (int i=0;i<properties.size();++i) { |
| IItemPropertyDescriptor descriptor = properties.get(i); |
| final EStructuralFeature feature = (EStructuralFeature) descriptor |
| .getFeature(null); |
| |
| EClass containingClass = feature.getEContainingClass(); |
| if(containingClass.equals(CommonPackage.eINSTANCE.getDublinCore())) continue; |
| |
| Object value = ((EObject)dm).eGet(feature); |
| header.append(feature.getName()); |
| header.append(","); |
| value = value.toString().replace(',', ' '); |
| value = value.toString().replace('\n', ' '); |
| values.append(value.toString().replace(',', ' ')); |
| values.append(","); |
| } |
| header.setLength(header.length()-1); // drop last , |
| values.setLength(values.length()-1); // drop last , |
| fwp.write(header.toString()); |
| fwp.write("\n"); |
| fwp.write(values.toString()); |
| fwp.flush(); |
| fwp.close(); |
| } catch (final IOException e) { |
| // debugging for now |
| Activator.logError("Error creating file writer for RUNPARAMETER ", e ); |
| |
| } |
| |
| }// logRunParameters |
| |
| /** |
| * Must implement this method to log data in run thread |
| * Need to implement TimeProviderAdapterFactory.INSTANCE.adapt().....only Graph will work right now....later in CORE |
| * @param rvp |
| * @param timeProvider |
| */ |
| @Override |
| public void logData(final RelativeValueProviderAdapter rvp, final TimeProvider timeProvider) { |
| // Not used |
| }// log data |
| |
| // We need to do some caching here to speed up execution |
| Map<Node, Integer> currentNodeLevels = null; |
| List<Integer>currentResolutionList = null; |
| Map<Integer, List<Node>>currentSortedNodeListMap = null; |
| |
| /** |
| * Log data from from a simulation after cycle |
| * |
| * @param sim Simulation |
| * @param dm DiseaseModel |
| * @param nodeLevels Node levels |
| * @param timeProvider |
| * @param beforeStart |
| */ |
| |
| @SuppressWarnings("boxing") |
| @Override |
| public void logData(ISimulation sim, IntegrationDecorator dm, Map<Node, Integer>nodeLevels, TimeProvider timeProvider, boolean beforeStart) { |
| // STEMTime ti = sim.getScenario().getSequencer().getCurrentTime(); |
| // Calendar c = Calendar.getInstance(); |
| // c.setTime(ti.getTime()); |
| // int year = c.get(Calendar.YEAR); |
| // if(year < 2036) return; |
| |
| |
| int dataColumnCount = 0; |
| |
| |
| int totalLabels = 0; |
| int labelsWritten = 0; |
| |
| int totalPropertyCount = 0; |
| // Increment iteration count |
| this.icount++; |
| |
| ArrayList<String>decoratorPopulations = this.getPopulationIdentifiers(dm); |
| |
| try { |
| // Iterate over the map resolutions |
| Iterator<Integer> resolution_it = this.getResolutionIterator(nodeLevels); |
| while(resolution_it.hasNext()) { |
| int resolution = resolution_it.next(); |
| |
| Iterator<Node> nodeIterator = this.getNodeIterator(resolution, nodeLevels); |
| |
| boolean firstNode = true; |
| // Iterate over nodes for a given resolution |
| |
| int nodeCount = 0; |
| |
| while(nodeIterator.hasNext()) { |
| Node n = nodeIterator.next(); |
| nodeCount++; |
| |
| for(String popId:decoratorPopulations) { |
| NodeLabel mLabel = getMatchingLabel(dm, n, popId); |
| if(mLabel == null) continue; |
| |
| if(!(mLabel instanceof IntegrationLabel)) continue; // Check |
| |
| IntegrationLabel dmLabel = (IntegrationLabel)mLabel; |
| |
| totalLabels++; |
| |
| labelsWritten++; |
| |
| IntegrationLabelValue dmlv = null; |
| |
| final RelativeValueProviderAdapter rvp = (RelativeValueProviderAdapter) RelativeValueProviderAdapterFactory.INSTANCE |
| .adapt(mLabel, RelativeValueProvider.class); |
| List<IItemPropertyDescriptor>properties = rvp.getProperties(); |
| |
| dmlv = (IntegrationLabelValue)dmLabel.getCurrentValue(); |
| |
| totalPropertyCount += properties.size(); |
| |
| StringBuilder sb = new StringBuilder(); |
| |
| for(IItemPropertyDescriptor itemDescriptor:properties) { |
| sb.setLength(0); |
| StateLevelMap slm = new StateLevelMap(popId, itemDescriptor.getDisplayName(itemDescriptor), resolution); |
| BufferedWriter fw = fileWriters.get(slm); |
| if(fw == null) { |
| Activator.logError("Error, no file writer found for "+slm, null); |
| continue; |
| } |
| // Before writing the values for the first location, |
| // add iteration, time columns |
| |
| if(firstNode) { |
| sb.append(this.icount); |
| sb.append(","); |
| STEMTime time = timeProvider.getTime(); |
| if(time == null) { |
| time = sim.getScenario().getSequencer().getStartTime(); |
| } |
| if(!beforeStart) |
| // Add increment |
| time = time.addIncrement(sim.getScenario().getSequencer().getTimeDelta()); |
| |
| String timeString; |
| timeString = dateFormat.format(time.getTime()); |
| |
| sb.append(timeString); |
| } |
| |
| EStructuralFeature feature = (EStructuralFeature) itemDescriptor |
| .getFeature(null); |
| |
| double value = ((Double) ((EObject)dmlv).eGet(feature)) |
| .doubleValue(); |
| |
| sb.append(","); |
| if(logIntegers) |
| sb.append(Math.rint(value)); |
| else sb.append(value); |
| |
| dataColumnCount++; |
| |
| fw.write(sb.toString()); |
| } // For each property in label |
| } // For each node label |
| |
| firstNode = false; |
| } // For each node |
| |
| } // For each node resolution |
| |
| // We need to add the end-of-line characters to each log file |
| resolution_it = this.getResolutionIterator(nodeLevels); |
| while(resolution_it.hasNext()) { |
| int resolution = resolution_it.next(); |
| |
| Iterator<Node> nodeIterator = this.getNodeIterator(resolution, nodeLevels); |
| |
| while(nodeIterator.hasNext()) { |
| Node n = nodeIterator.next(); |
| boolean wroteEOL = false; |
| for(String popId:decoratorPopulations) { |
| NodeLabel mLabel = getMatchingLabel(dm, n, popId); |
| if(mLabel == null) continue; |
| if(!(mLabel instanceof IntegrationLabel)) continue; // Check |
| final RelativeValueProviderAdapter rvp = (RelativeValueProviderAdapter) RelativeValueProviderAdapterFactory.INSTANCE |
| .adapt(mLabel, RelativeValueProvider.class); |
| List<IItemPropertyDescriptor>properties = rvp.getProperties(); |
| for(IItemPropertyDescriptor itemDescriptor:properties) { |
| StateLevelMap slm = new StateLevelMap(popId, itemDescriptor.getDisplayName(itemDescriptor), resolution); |
| BufferedWriter fw = fileWriters.get(slm); |
| fw.write("\n"); |
| } |
| wroteEOL = true; |
| } |
| if(wroteEOL) |
| break; // We only need a sample of a node to find the file writers |
| } |
| } |
| needsHeader = false; |
| } catch(IOException ioe) { |
| Activator.logError("Error writing log header ", ioe); |
| } |
| |
| // Safe to set the current node levels here |
| currentNodeLevels = nodeLevels; |
| } |
| |
| /* |
| * private Graph getGraph(final Node node) { return (Graph) |
| * node.eContainer().eContainer(); } // getGraph |
| */ |
| |
| /** |
| * Flush and Close the file |
| */ |
| @Override |
| public void flushLoggerData() { |
| Collection<BufferedWriter> writers = fileWriters.values(); |
| for(BufferedWriter writer:writers) { |
| try { |
| writer.flush(); |
| } catch(IOException ioe) { |
| Activator.logError("Cannot flush log file", ioe); |
| } |
| } |
| |
| } // flush All Data |
| |
| /** |
| * Flush and Close the file |
| */ |
| @Override |
| public void closeLoggerData() { |
| Collection<BufferedWriter> writers = fileWriters.values(); |
| for(BufferedWriter writer:writers) { |
| try { |
| writer.close(); |
| } catch(IOException ioe) { |
| Activator.logError("Cannot close log file", ioe); |
| } |
| } |
| } // closeLoggerData |
| |
| /** |
| * |
| * @param nodeLevels |
| * @return |
| */ |
| @SuppressWarnings("boxing") |
| private Iterator<Integer> getResolutionIterator(Map<Node, Integer>nodeLevels) { |
| if(nodeLevels == currentNodeLevels) |
| return currentResolutionList.iterator(); |
| ArrayList<Integer> list = new ArrayList(); |
| Collection<Integer>vals = nodeLevels.values(); |
| for(int level:vals) { |
| if(!list.contains(level)) list.add(level); |
| } |
| currentResolutionList = list; |
| return list.iterator(); |
| } |
| |
| // Return all nodes at the same level |
| // Sort by the name alphabetically for convenience |
| |
| @SuppressWarnings("boxing") |
| private Iterator<Node> getNodeIterator(int level, Map<Node, Integer>nodeLevels) { |
| if(nodeLevels == currentNodeLevels) |
| return currentSortedNodeListMap.get(level).iterator(); |
| |
| ArrayList<Node> list = new ArrayList<Node>(); |
| //Set<Node>ns = nodeLevels.keySet(); |
| //for(Node n:ns) { |
| for (Entry<Node,Integer> entry : nodeLevels.entrySet()) { |
| if(entry.getValue() == level) { |
| |
| boolean write = false; |
| for (NodeLabel s:entry.getKey().getLabels()) { |
| if(s instanceof IntegrationLabel) { |
| |
| write = true; |
| break; |
| } |
| } |
| if (!write) { |
| continue; |
| } |
| |
| // Skip air transport nodes |
| if(entry.getKey().getURI().toString().indexOf(AIR_TRANSPORT_URI_DUPLICATE_FEATURE) == -1) |
| list.add(entry.getKey()); |
| } |
| } |
| Collections.sort(list, new Comparator<Node>() { |
| |
| public int compare(Node n1, Node n2) { |
| String s1 = n1.getURI().toString(); |
| String s2 = n2.getURI().toString(); |
| return s1.compareTo(s2); |
| } |
| |
| }); |
| if(currentSortedNodeListMap == null) |
| currentSortedNodeListMap = new HashMap<Integer, List<Node>>(); |
| currentSortedNodeListMap.put(level, list); |
| return list.iterator(); |
| } |
| |
| /** |
| * filters the location id prefix from the beginning of |
| * a nodes ID for generation of a file name |
| * @param unfiltered |
| * @return the filtered file name using location id. |
| */ |
| private String filterLocationId(String unfiltered) { |
| int last = unfiltered.indexOf(LOCATIONID_PREFIX); |
| if (last >=0) { |
| last += LOCATIONID_PREFIX.length(); |
| return unfiltered.substring(last, unfiltered.length()); |
| } |
| return unfiltered; |
| } |
| |
| /** |
| * Used as key in map with FileWriters. FileWriters are key'd by |
| * the label (i.e. disease state) and by |
| */ |
| private static class StateLevelMap { |
| private final String popId; |
| private final String state; |
| private final int level; |
| |
| public StateLevelMap(String popId,String state, int level) { |
| this.popId = popId; |
| this.state = state; |
| this.level = level; |
| } |
| |
| public String getPopulationId() {return this.popId;} |
| public int getLevel() {return this.level;} |
| public String getState() {return this.state;} |
| |
| @Override |
| public int hashCode() { |
| return state.hashCode()+popId.hashCode() + level; // ugh |
| } |
| |
| @Override |
| public boolean equals(Object o) { |
| if(!(o instanceof StateLevelMap)) return false; |
| StateLevelMap slm = (StateLevelMap)o; |
| return (slm.getState().equals(this.state) && slm.getPopulationId().equals(this.popId) && slm.getLevel() == level); |
| } |
| |
| @Override |
| public String toString() { |
| return this.popId+" - "+this.state+"_"+this.level; |
| } |
| } |
| |
| |
| /** |
| * get the output folder name |
| * @return the log directory name |
| */ |
| public String getDirectoryName() { |
| return directoryName; |
| } |
| |
| |
| /** |
| * name of the data object being logged. |
| * e.g. The Disease Name |
| * @return the logged object name |
| */ |
| |
| public String getLogDataObjectName() { |
| return logDataObjectName; |
| } |
| } |