1 /* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved. 2 * 3 * This program and the accompanying materials are made available under 4 * the terms of the Common Public License v1.0 which accompanies this distribution, 5 * and is available at http://www.eclipse.org/legal/cpl-v10.html 6 * 7 * $Id: ReportCfg.java,v 1.1.1.1.2.1 2004/07/08 10:52:11 vlad_r Exp $ 8 */ 9 package com.vladium.emma.report; 10 11 import java.util.ArrayList; 12 import java.util.Iterator; 13 import java.util.List; 14 import java.util.Properties; 15 16 import com.vladium.util.IConstants; 17 import com.vladium.util.IProperties; 18 import com.vladium.emma.EMMAProperties; 19 import com.vladium.emma.ant.PropertyElement; 20 import com.vladium.emma.ant.SuppressableTask; 21 import com.vladium.emma.report.IReportEnums.DepthAttribute; 22 import com.vladium.emma.report.IReportEnums.UnitsTypeAttribute; 23 24 import org.apache.tools.ant.BuildException; 25 import org.apache.tools.ant.Project; 26 import org.apache.tools.ant.Task; 27 import org.apache.tools.ant.types.Path; 28 import org.apache.tools.ant.types.Reference; 29 30 // ---------------------------------------------------------------------------- 31 /** 32 * ReportCfg is a container for report type {@link ReportCfg.Element}s that are 33 * in turn containers for all properties that could be set on a <report> 34 * report type configurator (<txt>, <html>, etc). The elements provide 35 * the ability for report properties to be set either via the generic <property> 36 * nested elements or dedicated attributes. Potential conflicts between the same 37 * conceptual property being set via an attribute and a nested element are resolved 38 * by making dedicated attributes higher priority.<P> 39 * 40 * Note that ReportCfg does not handle any non-report related properties. 41 * This can be done via {@link com.vladium.emma.ant.GenericCfg}. It is also the 42 * parent's responsibility to merge any inherited report properties with 43 * ReportCfg settings. 44 * 45 * @author Vlad Roubtsov, (C) 2003 46 */ 47 public 48 class ReportCfg implements IReportProperties 49 { 50 // public: ................................................................ 51 52 53 public static abstract class Element implements IReportEnums, IReportProperties 54 { setUnits(final UnitsTypeAttribute units)55 public void setUnits (final UnitsTypeAttribute units) 56 { 57 m_settings.setProperty (m_prefix.concat (UNITS_TYPE), units.getValue ()); 58 } 59 setDepth(final DepthAttribute depth)60 public void setDepth (final DepthAttribute depth) 61 { 62 m_settings.setProperty (m_prefix.concat (DEPTH), depth.getValue ()); 63 } 64 setColumns(final String columns)65 public void setColumns (final String columns) 66 { 67 m_settings.setProperty (m_prefix.concat (COLUMNS), columns); 68 } 69 setSort(final String sort)70 public void setSort (final String sort) 71 { 72 m_settings.setProperty (m_prefix.concat (SORT), sort); 73 } 74 setMetrics(final String metrics)75 public void setMetrics (final String metrics) 76 { 77 m_settings.setProperty (m_prefix.concat (METRICS), metrics); 78 } 79 80 // not supported anymore: 81 82 // public void setOutdir (final File dir) 83 // { 84 // // TODO: does ANT resolve files relative to current JVM dir or ${basedir}? 85 // m_settings.setProperty (m_prefix.concat (OUT_DIR), dir.getAbsolutePath ()); 86 // } 87 setOutfile(final String fileName)88 public void setOutfile (final String fileName) 89 { 90 m_settings.setProperty (m_prefix.concat (OUT_FILE), fileName); 91 } 92 setEncoding(final String encoding)93 public void setEncoding (final String encoding) 94 { 95 m_settings.setProperty (m_prefix.concat (OUT_ENCODING), encoding); 96 } 97 98 // generic property element [don't doc this publicly]: 99 createProperty()100 public PropertyElement createProperty () 101 { 102 // TODO: error out on conficting duplicate settings 103 104 final PropertyElement property = new PropertyElement (); 105 m_genericSettings.add (property); 106 107 return property; 108 } 109 getType()110 protected abstract String getType (); 111 112 Element(final Task task, final IProperties settings)113 Element (final Task task, final IProperties settings) 114 { 115 if (task == null) 116 throw new IllegalArgumentException ("null input: task"); 117 if (settings == null) 118 throw new IllegalArgumentException ("null input: settings"); 119 120 m_task = task; 121 m_settings = settings; 122 123 m_prefix = PREFIX.concat (getType ()).concat ("."); 124 125 m_genericSettings = new ArrayList (); 126 } 127 128 processGenericSettings()129 void processGenericSettings () 130 { 131 for (Iterator i = m_genericSettings.iterator (); i.hasNext (); ) 132 { 133 final PropertyElement property = (PropertyElement) i.next (); 134 135 final String name = property.getName (); 136 final String value = property.getValue () != null ? property.getValue () : ""; 137 138 if (name != null) 139 { 140 final String prefixedName = m_prefix.concat (name); 141 142 // generically named settings don't override report named settings: 143 144 if (! m_settings.isOverridden (prefixedName)) 145 m_settings.setProperty (prefixedName, value); 146 } 147 } 148 } 149 150 151 protected final Task m_task; // never null 152 protected final String m_prefix; // never null 153 protected final IProperties m_settings; // never null 154 protected final List /* PropertyElement */ m_genericSettings; // never null 155 156 } // end of nested class 157 158 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 159 160 public static class Element_HTML extends Element 161 { getType()162 protected final String getType () 163 { 164 return TYPE; 165 } 166 Element_HTML(final Task task, final IProperties settings)167 Element_HTML (final Task task, final IProperties settings) 168 { 169 super (task, settings); 170 } 171 172 173 static final String TYPE = "html"; 174 175 } // end of nested class 176 177 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 178 179 public static class Element_TXT extends Element 180 { getType()181 protected final String getType () 182 { 183 return TYPE; 184 } 185 Element_TXT(final Task task, final IProperties settings)186 Element_TXT (final Task task, final IProperties settings) 187 { 188 super (task, settings); 189 } 190 191 192 static final String TYPE = "txt"; 193 194 } // end of nested class 195 196 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 197 198 public static class Element_LCOV extends Element 199 { getType()200 protected final String getType () 201 { 202 return TYPE; 203 } 204 Element_LCOV(final Task task, final IProperties settings)205 Element_LCOV (final Task task, final IProperties settings) 206 { 207 super (task, settings); 208 } 209 210 static final String TYPE = "lcov"; 211 212 } // end of nested class 213 214 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 215 216 public static class Element_XML extends Element 217 { getType()218 protected final String getType () 219 { 220 return TYPE; 221 } 222 Element_XML(final Task task, final IProperties settings)223 Element_XML (final Task task, final IProperties settings) 224 { 225 super (task, settings); 226 } 227 228 229 static final String TYPE = "xml"; 230 231 } // end of nested class 232 233 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 234 235 ReportCfg(final Project project, final Task task)236 public ReportCfg (final Project project, final Task task) 237 { 238 m_project = project; 239 m_task = task; 240 241 m_reportTypes = new ArrayList (4); 242 m_cfgList = new ArrayList (4); 243 m_settings = EMMAProperties.wrap (new Properties ()); 244 } 245 getSourcepath()246 public Path getSourcepath () 247 { 248 return m_srcpath; 249 } 250 getReportTypes()251 public String [] getReportTypes () 252 { 253 final BuildException failure = getFailure (); 254 255 if (failure != null) 256 throw failure; 257 else 258 { 259 if (m_reportTypes.isEmpty ()) 260 return IConstants.EMPTY_STRING_ARRAY; 261 else 262 { 263 final String [] result = new String [m_reportTypes.size ()]; 264 m_reportTypes.toArray (result); 265 266 return result; 267 } 268 } 269 } 270 getReportSettings()271 public IProperties getReportSettings () 272 { 273 final BuildException failure = getFailure (); 274 275 if (failure != null) 276 throw failure; 277 else 278 { 279 if (! m_processed) 280 { 281 // collect all nested elements' generic settins into m_settings: 282 283 for (Iterator i = m_cfgList.iterator (); i.hasNext (); ) 284 { 285 final Element cfg = (Element) i.next (); 286 cfg.processGenericSettings (); 287 } 288 289 m_processed = true; 290 } 291 292 return m_settings; // no clone 293 } 294 } 295 296 297 // sourcepath attribute/element: 298 setSourcepath(final Path path)299 public void setSourcepath (final Path path) 300 { 301 if (m_srcpath == null) 302 m_srcpath = path; 303 else 304 m_srcpath.append (path); 305 } 306 setSourcepathRef(final Reference ref)307 public void setSourcepathRef (final Reference ref) 308 { 309 createSourcepath ().setRefid (ref); 310 } 311 createSourcepath()312 public Path createSourcepath () 313 { 314 if (m_srcpath == null) 315 m_srcpath = new Path (m_project); 316 317 return m_srcpath.createPath (); 318 } 319 320 321 // generator elements: 322 createTxt()323 public Element_TXT createTxt () 324 { 325 return (Element_TXT) addCfgElement (Element_TXT.TYPE, 326 new Element_TXT (m_task, m_settings)); 327 } 328 createLcov()329 public Element_LCOV createLcov () 330 { 331 return (Element_LCOV) addCfgElement (Element_LCOV.TYPE, 332 new Element_LCOV (m_task, m_settings)); 333 } 334 createHtml()335 public Element_HTML createHtml () 336 { 337 return (Element_HTML) addCfgElement (Element_HTML.TYPE, 338 new Element_HTML (m_task, m_settings)); 339 } 340 createXml()341 public Element_XML createXml () 342 { 343 return (Element_XML) addCfgElement (Element_XML.TYPE, 344 new Element_XML (m_task, m_settings)); 345 } 346 347 348 // report properties [defaults for all report types]: 349 setUnits(final UnitsTypeAttribute units)350 public void setUnits (final UnitsTypeAttribute units) 351 { 352 m_settings.setProperty (PREFIX.concat (UNITS_TYPE), units.getValue ()); 353 } 354 setDepth(final DepthAttribute depth)355 public void setDepth (final DepthAttribute depth) 356 { 357 m_settings.setProperty (PREFIX.concat (DEPTH), depth.getValue ()); 358 } 359 setColumns(final String columns)360 public void setColumns (final String columns) 361 { 362 m_settings.setProperty (PREFIX.concat (COLUMNS), columns); 363 } 364 setSort(final String sort)365 public void setSort (final String sort) 366 { 367 m_settings.setProperty (PREFIX.concat (SORT), sort); 368 } 369 setMetrics(final String metrics)370 public void setMetrics (final String metrics) 371 { 372 m_settings.setProperty (PREFIX.concat (METRICS), metrics); 373 } 374 375 // not supported anymore: 376 377 // public void setOutdir (final File dir) 378 // { 379 // // TODO: does ANT resolve files relative to current JVM dir or ${basedir}? 380 // m_settings.setProperty (PREFIX.concat (OUT_DIR), dir.getAbsolutePath ()); 381 // } 382 // 383 // public void setDestdir (final File dir) 384 // { 385 // // TODO: does ANT resolve files relative to current JVM dir or ${basedir}? 386 // m_settings.setProperty (PREFIX.concat (OUT_DIR), dir.getAbsolutePath ()); 387 // } 388 setOutfile(final String fileName)389 public void setOutfile (final String fileName) 390 { 391 m_settings.setProperty (PREFIX.concat (OUT_FILE), fileName); 392 } 393 setEncoding(final String encoding)394 public void setEncoding (final String encoding) 395 { 396 m_settings.setProperty (PREFIX.concat (OUT_ENCODING), encoding); 397 } 398 399 // protected: ............................................................. 400 401 addCfgElement(final String type, final Element cfg)402 protected Element addCfgElement (final String type, final Element cfg) 403 { 404 if (m_reportTypes.contains (type)) 405 { 406 setFailure ((BuildException) SuppressableTask.newBuildException (m_task.getTaskName () 407 + ": duplicate configuration for report type [" + type + "]" , 408 m_task.getLocation ()).fillInStackTrace ()); 409 } 410 else 411 { 412 m_reportTypes.add (type); 413 m_cfgList.add (cfg); 414 } 415 416 return cfg; 417 } 418 419 // package: ............................................................... 420 421 // private: ............................................................... 422 423 setFailure(final BuildException failure)424 private void setFailure (final BuildException failure) 425 { 426 if (m_settingsFailure == null) m_settingsFailure = failure; // record the first one only 427 } 428 getFailure()429 private BuildException getFailure () 430 { 431 return m_settingsFailure; 432 } 433 434 435 private final Project m_project; 436 private final Task m_task; 437 438 private final List /* report type:String */ m_reportTypes; // using a list to keep the generation order same as configuration 439 private final List /* Element */ m_cfgList; 440 private final IProperties m_settings; // never null 441 442 private Path m_srcpath; 443 444 private transient BuildException m_settingsFailure; // can be null 445 private transient boolean m_processed; 446 447 } // end of class 448 // ---------------------------------------------------------------------------- 449