MATSIM
ConfigWriterHandlerImplV2.java
Go to the documentation of this file.
1 /* *********************************************************************** *
2  * project: org.matsim.*
3  * NonFlatConfigWriter.java
4  * *
5  * *********************************************************************** *
6  * *
7  * copyright : (C) 2013 by the members listed in the COPYING, *
8  * LICENSE and WARRANTY file. *
9  * email : info at matsim dot org *
10  * *
11  * *********************************************************************** *
12  * *
13  * This program is free software; you can redistribute it and/or modify *
14  * it under the terms of the GNU General Public License as published by *
15  * the Free Software Foundation; either version 2 of the License, or *
16  * (at your option) any later version. *
17  * See also COPYING, LICENSE and WARRANTY file *
18  * *
19  * *********************************************************************** */
20 package org.matsim.core.config;
21 
22 import org.apache.logging.log4j.LogManager;
31 
32 import java.io.BufferedWriter;
33 import java.io.IOException;
34 import java.io.UncheckedIOException;
35 import java.util.ArrayList;
36 import java.util.Collection;
37 import java.util.HashSet;
38 import java.util.Map;
39 import java.util.Map.Entry;
40 import java.util.Set;
41 
42 import static org.matsim.core.config.ConfigV2XmlNames.CONFIG;
43 import static org.matsim.core.config.ConfigV2XmlNames.MODULE;
44 import static org.matsim.core.config.ConfigV2XmlNames.NAME;
45 import static org.matsim.core.config.ConfigV2XmlNames.PARAMETER;
46 import static org.matsim.core.config.ConfigV2XmlNames.PARAMETER_SET;
47 import static org.matsim.core.config.ConfigV2XmlNames.TYPE;
48 
52 class ConfigWriterHandlerImplV2 extends ConfigWriterHandler {
53  // yy I introduced "verbosity" to also write a reduced config. In the end, this became so complicated
54  // that it would probably have been better to just separate the config writers for the two execution
55  // paths. If someone feels like doing that, please go ahead. kai, jun'18
56 
57  private String newline = "\n";
58 
64  private final Verbosity verbosity;
65 
66  private final Set<String> commentsAlreadyWritten = new HashSet<>() ;
67 
68  ConfigWriterHandlerImplV2( Verbosity verbosity ) {
69  this.verbosity = verbosity ;
70  }
71 
72  private void writeModule(
73  final BufferedWriter writer,
74  final String indent,
75  final String moduleTag,
76  final String moduleNameAtt,
77  final String moduleName,
78  final ConfigGroup module,
79  final ConfigGroup comparisonModule ) {
80  Map<String, String> params = module.getParams();
81  Map<String, String> comments = module.getComments();
82 
83  try {
84 
85  // first write the regular config entries (key,value pairs)
86  boolean headerHasBeenWritten = writeRegularEntries(writer, indent, moduleTag, moduleNameAtt, moduleName, comparisonModule, params, comments);
87 
88  // can't say what this is for:
89  if ( moduleName.equals("thisAintNoFlat") ) {
90  LogManager.getLogger(this.getClass()).warn("here") ;
91  }
92 
93  // then process the parameter sets (which will recursively call the current method again):
94  headerHasBeenWritten = processParameterSets(writer, indent, moduleTag, moduleNameAtt, moduleName, module, comparisonModule, headerHasBeenWritten);
95 
96  if ( headerHasBeenWritten ) {
97  writer.write(indent);
98  writer.write("\t</" + moduleTag + ">");
99  writer.write(this.newline);
100  }
101 
102  } catch (IOException e) {
103  throw new UncheckedIOException(e);
104  }
105  }
106 
107  private Boolean processParameterSets(BufferedWriter writer, String indent, String moduleTag, String moduleNameAtt, String moduleName,
108  ConfigGroup module, ConfigGroup comparisonModule, Boolean headerHasBeenWritten) throws IOException {
109  for ( Entry<String, ? extends Collection<? extends ConfigGroup>> entry : module.getParameterSets().entrySet() ) {
110  Collection<? extends ConfigGroup> comparisonSets = new ArrayList<>() ;
111  if ( comparisonModule != null ) {
112  comparisonSets = comparisonModule.getParameterSets(entry.getKey());
113  }
114  for ( ConfigGroup pSet : entry.getValue() ) {
115  ConfigGroup comparisonPSet = null ;
116  for ( ConfigGroup cg : comparisonSets ) {
117  if ( sameType( pSet, cg ) ) {
118  comparisonPSet = cg ;
119  break ;
120  }
121  }
122 // if ( comparisonPSet==null && !comparisonSets.isEmpty() ) {
123 // // (e.g. activity type, or mode defined in config which is not in default)
124 // comparisonPSet = comparisonSets.iterator().next() ; // just an arbitrary one
125 // }
126  if ( verbosity== Verbosity.minimal && comparisonPSet==null ) {
127  if ( pSet instanceof ScoringParameterSet) {
128  comparisonPSet = ((ScoringConfigGroup) comparisonModule).getOrCreateScoringParameters(((ScoringParameterSet) pSet).getSubpopulation());
129  } else if ( pSet instanceof ModeParams ) {
130  comparisonPSet = ((ScoringParameterSet) comparisonModule).getOrCreateModeParams(((ModeParams) pSet).getMode());
131  } else if ( pSet instanceof ActivityParams ) {
132  comparisonPSet = ((ScoringParameterSet) comparisonModule).getOrCreateActivityParams(((ActivityParams) pSet).getActivityType());
133  } else if ( pSet instanceof RoutingConfigGroup.TeleportedModeParams ) {
134  comparisonPSet = ((RoutingConfigGroup) comparisonModule).getOrCreateModeRoutingParams(((RoutingConfigGroup.TeleportedModeParams) pSet).getMode() ) ;
135  } else {
136  try {
137  comparisonPSet = pSet.getClass().newInstance();
138  } catch (InstantiationException | IllegalAccessException e) {
139 // e.printStackTrace();
140  // this happens when pSet is not a parameter set, but the config group itself, _and_ it is a non-typed config group.
141  // Then we don't have a default constructor. Which is why we then try a plain config group. kai, jun'18
142  comparisonPSet = new ConfigGroup(pSet.getName()) ;
143  }
144  }
145  }
146 // LogManager.getLogger(this.getClass()).warn( "comparisonPSet=" + comparisonPSet ) ;
147  // TODO: write comments only for the first parameter set of a given type?
148  // I think that that is done now. kai, jun'18
149  if ( !headerHasBeenWritten ) {
150  headerHasBeenWritten = true ;
151  writeHeader(writer, indent, moduleTag, moduleNameAtt, moduleName, newline);
152  }
153  writeModule(writer, indent+"\t", PARAMETER_SET, TYPE, entry.getKey(), pSet, comparisonPSet );
154  }
155  }
156  return headerHasBeenWritten;
157  }
158 
159  private Boolean writeRegularEntries(BufferedWriter writer, String indent, String moduleTag, String moduleNameAtt,
160  String moduleName, ConfigGroup comparisonModule, Map<String, String> params,
161  Map<String, String> comments) throws IOException {
162  boolean headerHasBeenWritten = false ;
163  for (Entry<String, String> entry : params.entrySet()) {
164 
165  final String actual = entry.getValue();
166  if ( verbosity== Verbosity.minimal ) {
167  if ( comparisonModule!=null ) {
168  String defaultValue = comparisonModule.getParams().get( entry.getKey() ) ;
169  // exclude some cases manually for the time being (setting the default value to null means that
170  // the actual entry will be written to file):
171  switch( entry.getKey() ) {
172  case ActivityParams.TYPICAL_DURATION:
173  defaultValue = null ;
174  break ;
175  case ModeParams.MODE:
176 // case ModeRoutingParams.MODE: // same string value!
177  defaultValue = null ;
178  break ;
179  case ActivityParams.ACTIVITY_TYPE:
180  defaultValue = null ;
181  break ;
182  }
183  if (actual.equals(defaultValue)) {
184  continue;
185  }
186 // if ( actual==null && defaultValue.equals("null") ) {
187 // continue ;
188 // }
189  }
190  }
191 
192  if ( !headerHasBeenWritten ) {
193  headerHasBeenWritten = true ;
194  writeHeader(writer, indent, moduleTag, moduleNameAtt, moduleName, newline);
195  }
196 
197  String key = entry.getKey() + "." + moduleName ;
198  if (comments.get( entry.getKey() ) != null && !commentsAlreadyWritten.contains( key )) {
199  commentsAlreadyWritten.add( key ) ;
200 
201 // writer.write( this.newline );
202  writer.write( indent );
203  writer.write( "\t\t<!-- " + comments.get(entry.getKey()) + " -->");
204  writer.write( this.newline );
205 // lastHadComment = true;
206 // } else {
207 // if (lastHadComment) {
208 // writer.write( this.newline );
209 // }
210 // lastHadComment = false;
211  }
212  writer.write( indent );
213  writer.write("\t\t<"+PARAMETER+" name=\"" + entry.getKey() + "\" value=\"" + actual + "\" />");
214  writer.write( this.newline );
215  }
216  return headerHasBeenWritten;
217  }
218 
219  private static void writeHeader(BufferedWriter writer, String indent, String moduleTag, String moduleNameAtt, String moduleName, String newline) throws IOException {
220  // writer.write( this.newline );
221  writer.write( indent );
222  writer.write("\t<"+moduleTag);
223  writer.write(" "+moduleNameAtt+"=\"" + moduleName + "\" >");
224  writer.write( newline );
225  }
226 
227  private static boolean sameType(ConfigGroup pSet, ConfigGroup cg) {
228  if ( ! ( pSet.getName().equals( cg.getName() ) ) ) {
229  return false;
230  }
231  if ( pSet instanceof RoutingConfigGroup.TeleportedModeParams ) {
232  // (these are the "teleportedRouteParameters" in config.xml)
233  if ( ((RoutingConfigGroup.TeleportedModeParams)pSet).getMode().equals( ((RoutingConfigGroup.TeleportedModeParams)cg).getMode() ) ) {
234  return true ;
235  }
236  }
237  if ( pSet instanceof ScoringParameterSet ) {
238  return true ;
239  }
240  if ( pSet instanceof ModeParams ) {
241  if ( ((ModeParams)pSet).getMode().equals( ((ModeParams)cg).getMode() ) ) {
242  return true ;
243  }
244  }
245  if ( pSet instanceof ActivityParams ) {
246  if ( ((ActivityParams)pSet).getActivityType().equals( ((ActivityParams)cg).getActivityType() ) ) {
247  return true ;
248  }
249  }
250  if ( pSet instanceof StrategySettings ) {
251  return true ;
252  // yy this will not work since there is no corresponding default entry! kai, may'18
253  }
254  return false ;
255  }
256 
257  @Override
258  void startConfig(
259  final Config config,
260  final BufferedWriter out) {
261  try {
262  out.write("<"+CONFIG+">");
263  out.write( this.newline );
264  } catch (IOException e) {
265  throw new UncheckedIOException(e);
266  }
267 
268  }
269 
270  @Override
271  void endConfig(
272  final BufferedWriter out) {
273  try {
274  out.write( this.newline );
275  out.write("</"+CONFIG+">");
276  out.write( this.newline );
277  } catch (IOException e) {
278  throw new UncheckedIOException(e);
279  }
280  }
281 
282  @Override
283  void writeModule(
284  final ConfigGroup module,
285  final BufferedWriter out) {
286  if ( ! (module instanceof ChangeLegModeConfigGroup) ) {
287  // yyyy special case to provide error message; may be removed eventually. kai, may'16
288 
289 
290  ConfigGroup comparisonConfig = null ;
291  if ( verbosity==Verbosity.minimal) {
292  comparisonConfig = ConfigUtils.createConfig().getModules().get(module.getName());
293  // preference to generate this here multiple times to avoid having it as a field. kai, may'18
294  }
295 
296  writeModule(
297  out,
298  "",
299  MODULE,
300  NAME,
301  module.getName(),
302  module,
303  comparisonConfig
304  );
305  }
306  }
307 
308  @Override
309  void writeSeparator(final BufferedWriter out) {
310 // try {
312 // out.write("<!-- ====================================================================== -->");
313 // out.write( this.newline );
314 //
315 // } catch (IOException e) {
316 // throw new UncheckedIOException(e);
317 // }
318 
319  // this looks ugly in the reduced config, thus disabling them for the time being. kai, jun'18
320  }
321 
322 
323  @Override
324  String setNewline(final String newline) {
325  String former = this.newline;
326  this.newline = newline;
327  return former;
328  }
329 
330 }
331