summaryrefslogtreecommitdiff
path: root/src/main/org/apache/tools/ant/taskdefs/optional/metamata/MAudit.java
blob: a9b35c4fbbb1ec7ae1d35b3cf711debcc4533bb5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
/*
 * Copyright  2001-2002,2004 Apache Software Foundation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */
package org.apache.tools.ant.taskdefs.optional.metamata;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Vector;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.ExecuteStreamHandler;
import org.apache.tools.ant.taskdefs.LogStreamHandler;
import org.apache.tools.ant.types.FileSet;
import org.apache.tools.ant.types.Path;

/**
 * Invokes the Metamata Audit/ Webgain Quality Analyzer on a set of Java files.
 * <p>
 * <i>maudit</i> performs static analysis of the Java source code and byte
 * code files to find and report errors of style and potential problems related
 * to performance, maintenance and robustness. As a convenience, a stylesheet
 * is given in <tt>etc</tt> directory, so that an HTML report can be generated
 * from the XML file.
 *
 * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
 */
public class MAudit extends AbstractMetamataTask {

    /* As of Metamata 2.0, the command line of MAudit is as follows:
    Usage
        maudit <option>... <path>... [-unused <search-path>...]

    Parameters
        path               File or directory to audit.
        search-path        File or directory to search for declaration uses.

    Options
        -arguments  -A     <file>     Includes command line arguments from file.
        -classpath  -cp    <path>     Sets class path (also source path unless one
                                      explicitly set). Overrides METAPATH/CLASSPATH.
        -exit       -x                Exits after the first error.
        -fix        -f                Automatically fixes certain errors.
        -fullpath                     Prints full path for locations.
        -help       -h                Prints help and exits.
        -list       -l                Creates listing file for each audited file.
        -offsets    -off              Offset and length for locations.
        -output     -o     <file>     Prints output to file.
        -quiet      -q                Suppresses copyright and summary messages.
        -sourcepath        <path>     Sets source path. Overrides SOURCEPATH.
        -tab        -t                Prints a tab character after first argument.
        -unused     -u                Finds declarations unused in search paths.
        -verbose    -v                Prints all messages.
        -version    -V                Prints version and exits.
    */

    //---------------------- PUBLIC METHODS ------------------------------------

    /** pattern used by maudit to report the error for a file */
    /** RE does not seems to support regexp pattern with comments so i'm stripping it*/
    // (?:file:)?((?#filepath).+):((?#line)\\d+)\\s*:\\s+((?#message).*)
    static final String AUDIT_PATTERN = "(?:file:)?(.+):(\\d+)\\s*:\\s+(.*)";

    private File outFile = null;

    private Path searchPath = null;

    private Path rulesPath = null;

    private boolean fix = false;

    private boolean list = false;

    private boolean unused = false;

//  add a bunch of undocumented options for the task
    private boolean quiet = false;
    private boolean exit = false;
    private boolean offsets = false;
    private boolean verbose = false;
    private boolean fullsemanticize = false;

    /** default constructor */
    public MAudit() {
        super("com.metamata.gui.rc.MAudit");
    }

    /**
     * The XML file to which the Audit result should be written to; required
     */

    public void setTofile(File outFile) {
        this.outFile = outFile;
    }

    /**
     * Automatically fix certain errors
     * (those marked as fixable in the manual);
     * optional, default=false
     */
    public void setFix(boolean flag) {
        this.fix = flag;
    }

    /**
     * Creates listing file for each audited file; optional, default false.
     * When set, a .maudit file will be generated in the
     * same location as the source file.
     */
    public void setList(boolean flag) {
        this.list = flag;
    }

    /**
     * Finds declarations unused in search paths; optional, default false.
     * It will look for unused global declarations
     * in the source code within a use domain specified by the
     * <tt>searchpath</tt> element.
     */
    public void setUnused(boolean flag) {
        this.unused = flag;
    }

    /**
     * flag to suppress copyright and summary messages; default false.
     * internal/testing only
     * @ant.attribute ignore="true"
     */
    public void setQuiet(boolean flag) {
        this.quiet = flag;
    }

    /**
     * flag to tell the task to exit after the first error.
     * internal/testing only
     * @ant.attribute ignore="true"
     */
    public void setExit(boolean flag) {
        this.exit = flag;
    }

    /**
     * internal/testing only
     * @ant.attribute ignore="true"
     */
    public void setOffsets(boolean flag) {
        this.offsets = flag;
    }

    /**
     * flag to print all messages; optional, default false.
     * internal/testing only
     * @ant.attribute ignore="true"
     */
    public void setVerbose(boolean flag) {
        this.verbose = flag;
    }

    /**
     * internal/testing only
     * @ant.attribute ignore="true"
     */
    public void setFullsemanticize(boolean flag) {
        this.fullsemanticize = flag;
    }

    /**
     * classpath for additional audit rules
     * these must be placed before metamata.jar !!
     */
    public Path createRulespath() {
        if (rulesPath == null) {
            rulesPath = new Path(getProject());
        }
        return rulesPath;
    }

    /**
     * search path to use for unused global declarations;
     * required when <tt>unused</tt> is set.
     */
    public Path createSearchpath() {
        if (searchPath == null) {
            searchPath = new Path(getProject());
        }
        return searchPath;
    }

    /**
     * create the option vector for the command
     */
    protected Vector getOptions() {
        Vector options = new Vector(512);
        // add the source path automatically from the fileset.
        // to avoid redundancy...
        for (int i = 0; i < fileSets.size(); i++) {
            FileSet fs = (FileSet) fileSets.elementAt(i);
            Path path = createSourcepath();
            File dir = fs.getDir(getProject());
            path.setLocation(dir);
        }

        // there is a bug in Metamata 2.0 build 37. The sourcepath argument does
        // not work. So we will use the sourcepath prepended to classpath. (order
        // is important since Metamata looks at .class and .java)
        if (sourcePath != null) {
            sourcePath.append(classPath); // srcpath is prepended
            classPath = sourcePath;
            sourcePath = null; // prevent from using -sourcepath
        }

        // don't forget to modify the pattern if you change the options reporting
        if (classPath != null) {
            options.addElement("-classpath");
            options.addElement(classPath.toString());
        }
        // suppress copyright msg when running, we will let it so that this
        // will be the only output to the console if in xml mode
        if (quiet) {
            options.addElement("-quiet");
        }
        if (fullsemanticize) {
            options.addElement("-full-semanticize");
        }
        if (verbose) {
            options.addElement("-verbose");
        }
        if (offsets) {
            options.addElement("-offsets");
        }
        if (exit) {
            options.addElement("-exit");
        }
        if (fix) {
            options.addElement("-fix");
        }
        options.addElement("-fullpath");

        // generate .maudit files much more detailed than the report
        // I don't like it very much, I think it could be interesting
        // to get all .maudit files and include them in the XML.
        if (list) {
            options.addElement("-list");
        }
        if (sourcePath != null) {
            options.addElement("-sourcepath");
            options.addElement(sourcePath.toString());
        }
        addAllVector(options, includedFiles.keys());
        if (unused) {
            options.addElement("-unused");
            options.addElement(searchPath.toString());
        }
        return options;
    }

    /**
     * validate the settings
     */
    protected void checkOptions() throws BuildException {
        super.checkOptions();
        if (unused && searchPath == null) {
            throw new BuildException("'searchpath' element must be set when "
                + "looking for 'unused' declarations.");
        }
        if (!unused && searchPath != null) {
            log("'searchpath' element ignored. 'unused' attribute is disabled.",
                Project.MSG_WARN);
        }
        if (rulesPath != null) {
            cmdl.createClasspath(getProject()).addExisting(rulesPath);
        }
    }

    protected ExecuteStreamHandler createStreamHandler() throws BuildException {
        // if we didn't specify a file, then use a screen report
        if (outFile == null) {
            return new LogStreamHandler(this, Project.MSG_INFO, Project.MSG_ERR);
        }
        ExecuteStreamHandler handler = null;
        OutputStream out = null;
        try {
            out = new FileOutputStream(outFile);
            handler = new MAuditStreamHandler(this, out);
        } catch (IOException e) {
            throw new BuildException(e);
        } finally {
            if (out == null) {
                try {
                    out.close();
                } catch (IOException e) {
                }
            }
        }
        return handler;
    }

    protected void cleanUp() throws BuildException {
        super.cleanUp();
        // at this point if -list is used, we should move
        // the .maudit file since we cannot choose their location :(
        // the .maudit files match the .java files
        // we'll use includedFiles to get the .maudit files.

        /*if (out != null) {
            // close it if not closed by the handler...
        }*/
    }

}