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 */
9package com.vladium.emma.report;
10
11import java.util.ArrayList;
12import java.util.Iterator;
13import java.util.List;
14import java.util.Properties;
15
16import com.vladium.util.IConstants;
17import com.vladium.util.IProperties;
18import com.vladium.emma.EMMAProperties;
19import com.vladium.emma.ant.PropertyElement;
20import com.vladium.emma.ant.SuppressableTask;
21import com.vladium.emma.report.IReportEnums.DepthAttribute;
22import com.vladium.emma.report.IReportEnums.UnitsTypeAttribute;
23
24import org.apache.tools.ant.BuildException;
25import org.apache.tools.ant.Project;
26import org.apache.tools.ant.Task;
27import org.apache.tools.ant.types.Path;
28import 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 */
47public
48class ReportCfg implements IReportProperties
49{
50    // public: ................................................................
51
52
53    public static abstract class Element implements IReportEnums, IReportProperties
54    {
55        public void setUnits (final UnitsTypeAttribute units)
56        {
57            m_settings.setProperty (m_prefix.concat (UNITS_TYPE), units.getValue ());
58        }
59
60        public void setDepth (final DepthAttribute depth)
61        {
62            m_settings.setProperty (m_prefix.concat (DEPTH), depth.getValue ());
63        }
64
65        public void setColumns (final String columns)
66        {
67            m_settings.setProperty (m_prefix.concat (COLUMNS), columns);
68        }
69
70        public void setSort (final String sort)
71        {
72            m_settings.setProperty (m_prefix.concat (SORT), sort);
73        }
74
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
88        public void setOutfile (final String fileName)
89        {
90            m_settings.setProperty (m_prefix.concat (OUT_FILE), fileName);
91        }
92
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
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
110        protected abstract String getType ();
111
112
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
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    {
162        protected final String getType ()
163        {
164            return TYPE;
165        }
166
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    {
181        protected final String getType ()
182        {
183            return TYPE;
184        }
185
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    {
200        protected final String getType ()
201        {
202            return TYPE;
203        }
204
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    {
218        protected final String getType ()
219        {
220            return TYPE;
221        }
222
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
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
246    public Path getSourcepath ()
247    {
248        return m_srcpath;
249    }
250
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
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
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
307    public void setSourcepathRef (final Reference ref)
308    {
309        createSourcepath ().setRefid (ref);
310    }
311
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
323    public Element_TXT createTxt ()
324    {
325        return (Element_TXT) addCfgElement (Element_TXT.TYPE,
326                                                     new Element_TXT (m_task, m_settings));
327    }
328
329    public Element_LCOV createLcov ()
330    {
331        return (Element_LCOV) addCfgElement (Element_LCOV.TYPE,
332                                                     new Element_LCOV (m_task, m_settings));
333    }
334
335    public Element_HTML createHtml ()
336    {
337        return (Element_HTML) addCfgElement (Element_HTML.TYPE,
338                                                      new Element_HTML (m_task, m_settings));
339    }
340
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
350    public void setUnits (final UnitsTypeAttribute units)
351    {
352        m_settings.setProperty (PREFIX.concat (UNITS_TYPE), units.getValue ());
353    }
354
355    public void setDepth (final DepthAttribute depth)
356    {
357        m_settings.setProperty (PREFIX.concat (DEPTH), depth.getValue ());
358    }
359
360    public void setColumns (final String columns)
361    {
362        m_settings.setProperty (PREFIX.concat (COLUMNS), columns);
363    }
364
365    public void setSort (final String sort)
366    {
367        m_settings.setProperty (PREFIX.concat (SORT), sort);
368    }
369
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
389    public void setOutfile (final String fileName)
390    {
391        m_settings.setProperty (PREFIX.concat (OUT_FILE), fileName);
392    }
393
394    public void setEncoding (final String encoding)
395    {
396        m_settings.setProperty (PREFIX.concat (OUT_ENCODING), encoding);
397    }
398
399    // protected: .............................................................
400
401
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
424    private void setFailure (final BuildException failure)
425    {
426        if (m_settingsFailure == null) m_settingsFailure = failure; // record the first one only
427    }
428
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