callgraph/src/main/java/org/netbeans/lib/callgraph/Callgraph.java
author Tim Boudreau <tboudreau@netbeans.org>
Sat, 03 Sep 2016 02:41:36 -0400
changeset 18374 04a79821e760
parent 18373 3527a32a19f0
child 18400 c87c223efe6a
permissions -rw-r--r--
Eliminate duplicates in graph files
tboudreau@18301
     1
/* 
tboudreau@18301
     2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
tboudreau@18301
     3
 *
tboudreau@18374
     4
 * Copyright (C) 1997-2016 Oracle and/or its affiliates. All rights reserved.
tboudreau@18301
     5
 *
tboudreau@18301
     6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
tboudreau@18301
     7
 * Other names may be trademarks of their respective owners.
tboudreau@18301
     8
 *
tboudreau@18301
     9
 * The contents of this file are subject to the terms of either the GNU
tboudreau@18301
    10
 * General Public License Version 2 only ("GPL") or the Common
tboudreau@18301
    11
 * Development and Distribution License("CDDL") (collectively, the
tboudreau@18301
    12
 * "License"). You may not use this file except in compliance with the
tboudreau@18301
    13
 * License. You can obtain a copy of the License at
tboudreau@18301
    14
 * http://www.netbeans.org/cddl-gplv2.html
tboudreau@18301
    15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
tboudreau@18301
    16
 * specific language governing permissions and limitations under the
tboudreau@18301
    17
 * License.  When distributing the software, include this License Header
tboudreau@18301
    18
 * Notice in each file and include the License file at
tboudreau@18301
    19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
tboudreau@18301
    20
 * particular file as subject to the "Classpath" exception as provided
tboudreau@18301
    21
 * by Oracle in the GPL Version 2 section of the License file that
tboudreau@18301
    22
 * accompanied this code. If applicable, add the following below the
tboudreau@18301
    23
 * License Header, with the fields enclosed by brackets [] replaced by
tboudreau@18301
    24
 * your own identifying information:
tboudreau@18301
    25
 * "Portions Copyrighted [year] [name of copyright owner]"
tboudreau@18301
    26
 *
tboudreau@18301
    27
 * Contributor(s):
tboudreau@18301
    28
 *
tboudreau@18301
    29
 * The Original Software is NetBeans. The Initial Developer of the Original
tboudreau@18301
    30
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
tboudreau@18301
    31
 * Microsystems, Inc. All Rights Reserved.
tboudreau@18301
    32
 *
tboudreau@18301
    33
 * If you wish your version of this file to be governed by only the CDDL
tboudreau@18301
    34
 * or only the GPL Version 2, indicate your decision by adding
tboudreau@18301
    35
 * "[Contributor] elects to include this software in this distribution
tboudreau@18301
    36
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
tboudreau@18301
    37
 * single choice of license, a recipient has the option to distribute
tboudreau@18301
    38
 * your version of this file under either the CDDL, the GPL Version 2 or
tboudreau@18301
    39
 * to extend the choice of license to its licensees as provided above.
tboudreau@18301
    40
 * However, if you add GPL Version 2 code and therefore, elected the GPL
tboudreau@18301
    41
 * Version 2 license, then the option applies only if the new code is
tboudreau@18301
    42
 * made subject to such option by the copyright holder.
tboudreau@18301
    43
 */
tboudreau@18301
    44
package org.netbeans.lib.callgraph;
tboudreau@18301
    45
tboudreau@18301
    46
import org.netbeans.lib.callgraph.Arguments.InvalidArgumentsException;
tboudreau@18301
    47
import static org.netbeans.lib.callgraph.CallgraphControl.CMD_CLASSGRAPH;
tboudreau@18301
    48
import static org.netbeans.lib.callgraph.CallgraphControl.CMD_DISABLE_EIGHT_BIT_STRINGS;
tboudreau@18301
    49
import static org.netbeans.lib.callgraph.CallgraphControl.CMD_EXCLUDE;
tboudreau@18301
    50
import static org.netbeans.lib.callgraph.CallgraphControl.CMD_MAVEN;
tboudreau@18301
    51
import static org.netbeans.lib.callgraph.CallgraphControl.CMD_METHODGRAPH;
tboudreau@18301
    52
import static org.netbeans.lib.callgraph.CallgraphControl.CMD_NOSELF;
tboudreau@18301
    53
import static org.netbeans.lib.callgraph.CallgraphControl.CMD_OMIT_ABSTRACT;
tboudreau@18301
    54
import static org.netbeans.lib.callgraph.CallgraphControl.CMD_PACKAGEGRAPH;
tboudreau@18301
    55
import static org.netbeans.lib.callgraph.CallgraphControl.CMD_QUIET;
tboudreau@18301
    56
import static org.netbeans.lib.callgraph.CallgraphControl.CMD_REVERSE;
tboudreau@18301
    57
import static org.netbeans.lib.callgraph.CallgraphControl.CMD_SIMPLE;
tboudreau@18301
    58
import org.netbeans.lib.callgraph.io.JavaFilesIterator;
tboudreau@18301
    59
import org.netbeans.lib.callgraph.javac.JavacRunner;
tboudreau@18301
    60
import org.netbeans.lib.callgraph.javac.SourceElement;
tboudreau@18301
    61
import org.netbeans.lib.callgraph.javac.SourcesInfo;
tboudreau@18301
    62
import org.netbeans.lib.callgraph.util.MergeIterator;
tboudreau@18301
    63
import java.io.File;
tboudreau@18301
    64
import java.io.IOException;
tboudreau@18301
    65
import java.io.PrintStream;
tboudreau@18301
    66
import java.util.ArrayList;
tboudreau@18301
    67
import java.util.Collections;
tboudreau@18301
    68
import java.util.HashSet;
tboudreau@18301
    69
import java.util.Iterator;
tboudreau@18301
    70
import java.util.LinkedList;
tboudreau@18301
    71
import java.util.List;
tboudreau@18301
    72
import java.util.Set;
tboudreau@18372
    73
import java.util.concurrent.atomic.AtomicReference;
tboudreau@18372
    74
import java.util.function.Consumer;
tboudreau@18301
    75
tboudreau@18301
    76
/**
tboudreau@18301
    77
 * Scans a source folder and runs javac against any Java sources present, and
tboudreau@18301
    78
 * builds graphs of what calls what within those. The library classpath does not
tboudreau@18301
    79
 * need to be set, and the folders do not need to be package roots - we are
tboudreau@18301
    80
 * instructing javac to treat errors as non-fatal. The available sources will be
tboudreau@18301
    81
 * attributed.
tboudreau@18301
    82
 *
tboudreau@18301
    83
 * @author Tim Boudreau
tboudreau@18301
    84
 */
tboudreau@18301
    85
public final class Callgraph {
tboudreau@18301
    86
tboudreau@18301
    87
    private boolean noself;
tboudreau@18301
    88
    private boolean maven;
tboudreau@18301
    89
    private boolean quiet;
tboudreau@18301
    90
    private boolean simple;
tboudreau@18301
    91
    private final Set<String> excludes = new HashSet<>();
tboudreau@18301
    92
    private final Set<File> folders = new HashSet<>();
tboudreau@18301
    93
    private File classgraphFile;
tboudreau@18301
    94
    private File methodgraphFile;
tboudreau@18301
    95
    private File packagegraphFile;
tboudreau@18301
    96
    private Listener listener;
tboudreau@18301
    97
    private boolean omitAbstract;
tboudreau@18301
    98
    private boolean useJavaStrings;
tboudreau@18301
    99
    private boolean reverse;
tboudreau@18301
   100
tboudreau@18301
   101
    private Callgraph() {
tboudreau@18301
   102
    }
tboudreau@18301
   103
tboudreau@18301
   104
    /**
tboudreau@18301
   105
     * Configure a Callgraph to build.
tboudreau@18301
   106
     *
tboudreau@18301
   107
     * @return A call graph to configure
tboudreau@18301
   108
     */
tboudreau@18301
   109
    public static Callgraph configure() {
tboudreau@18301
   110
        return new Callgraph();
tboudreau@18301
   111
    }
tboudreau@18301
   112
tboudreau@18301
   113
    public static void main(String[] args) throws IOException {
tboudreau@18301
   114
        CallgraphControl arguments = null;
tboudreau@18301
   115
        try {
tboudreau@18301
   116
            arguments = new Arguments(args);
tboudreau@18301
   117
        } catch (InvalidArgumentsException ex) {
tboudreau@18301
   118
            // this will be a help message describing usage and the invalid
tboudreau@18301
   119
            // arguments
tboudreau@18301
   120
            System.err.println(ex.getMessage());
tboudreau@18301
   121
            System.exit(1);
tboudreau@18301
   122
        }
tboudreau@18301
   123
        assert arguments != null;
tboudreau@18301
   124
        invoke(arguments, arguments.isVerbose() ? new LoggingListener() : null);
tboudreau@18301
   125
    }
tboudreau@18301
   126
tboudreau@18301
   127
    /**
tboudreau@18301
   128
     * Run javac and produce output.
tboudreau@18301
   129
     *
tboudreau@18301
   130
     * @param arguments The parsed arguments
tboudreau@18301
   131
     * @return The list of all methods found, sorted by qname
tboudreau@18301
   132
     * @throws IOException If i/o fails
tboudreau@18301
   133
     */
tboudreau@18301
   134
    static List<SourceElement> invoke(CallgraphControl arguments, Listener listener) throws IOException {
tboudreau@18374
   135
        SourcesInfo info = new SourcesInfo(arguments.isDisableEightBitStrings(), arguments.isAggressive());
tboudreau@18301
   136
        // Build an iterable of all Java sources (without collecting them all ahead of time)
tboudreau@18301
   137
        List<Iterable<File>> iterables = new LinkedList<>();
tboudreau@18301
   138
        for (File folder : arguments) {
tboudreau@18301
   139
            iterables.add(JavaFilesIterator.iterable(folder));
tboudreau@18301
   140
        }
tboudreau@18301
   141
        // The thing that will run javac
tboudreau@18301
   142
        JavacRunner runner = new JavacRunner(info, MergeIterator.toIterable(iterables), listener);
tboudreau@18372
   143
        AtomicReference<File> lastFile = new AtomicReference<>();
tboudreau@18372
   144
        Consumer<File> monitor = lastFile::set;
tboudreau@18301
   145
        // run javac
tboudreau@18372
   146
        Set<SourceElement> allElements = runner.go(monitor, lastFile);
tboudreau@18301
   147
tboudreau@18301
   148
        List<SourceElement> all = new ArrayList<>(allElements);
tboudreau@18301
   149
        // Sort, so textual output is more human-friendly
tboudreau@18301
   150
        Collections.sort(all);
tboudreau@18301
   151
        // Now write files and print output
tboudreau@18301
   152
        if (!all.isEmpty()) {
tboudreau@18301
   153
            PrintStream outStream = createPrintStreamIfNotNull(arguments.methodGraphFile());
tboudreau@18301
   154
            PrintStream packageStream = createPrintStreamIfNotNull(arguments.packageGraphFile());
tboudreau@18301
   155
            PrintStream classStream = createPrintStreamIfNotNull(arguments.classGraphFile());
tboudreau@18301
   156
            // duplicate avoidance
tboudreau@18301
   157
            Set<CharSequence> emittedPackageLines = new HashSet<>();
tboudreau@18301
   158
            Set<CharSequence> emittedClassLines = new HashSet<>();
tboudreau@18374
   159
            List<Object> clazz = new ArrayList<>(5);
tboudreau@18374
   160
            CharSequence lastClass = null;
tboudreau@18374
   161
tboudreau@18374
   162
            List<Object> pkg = new ArrayList<>(5);
tboudreau@18374
   163
            CharSequence lastPackage = null;
tboudreau@18374
   164
            
tboudreau@18301
   165
            try {
tboudreau@18301
   166
                // Iterate every method
tboudreau@18374
   167
                outer:
tboudreau@18301
   168
                for (SourceElement sce : all) {
tboudreau@18301
   169
                    if (arguments.isExcluded(sce.qname().toString())) { // Ignore matches
tboudreau@18301
   170
                        continue;
tboudreau@18301
   171
                    }
tboudreau@18301
   172
                    List<SourceElement> outbounds = new ArrayList<>(arguments.isReverse() ? sce.getInboundReferences() : sce.getOutboundReferences());
tboudreau@18301
   173
                    Collections.sort(outbounds); // also sort connections
tboudreau@18301
   174
                    // Iterate the current method's connections
tboudreau@18374
   175
                    List<Object> mth = new ArrayList<>(5);
tboudreau@18374
   176
                    CharSequence currClazz = arguments.isShortNames() ? sce.typeName() : info.strings.concat(sce.packageName(), info.strings.DOT, sce.typeName());
tboudreau@18374
   177
                    if (!currClazz.equals(lastClass)) {
tboudreau@18374
   178
                        if (classStream != null) {
tboudreau@18374
   179
                            writeLine(clazz, info, emittedClassLines, classStream);
tboudreau@18374
   180
                        }
tboudreau@18374
   181
                        clazz.clear();
tboudreau@18374
   182
                        lastClass = currClazz;
tboudreau@18374
   183
                    }
tboudreau@18374
   184
                    if (clazz.isEmpty()) {
tboudreau@18374
   185
                        clazz.add(currClazz);
tboudreau@18374
   186
                        if (arguments.isExtendedProperties()) {
tboudreau@18374
   187
                            clazz.add(sce.isAbstract());
tboudreau@18374
   188
                        }
tboudreau@18374
   189
                    }
tboudreau@18374
   190
                    CharSequence currPkg = sce.packageName();
tboudreau@18374
   191
                    if (pkg.isEmpty()) {
tboudreau@18374
   192
                        pkg.add(currPkg);
tboudreau@18374
   193
                    }
tboudreau@18374
   194
                    if (!currPkg.equals(lastPackage)) {
tboudreau@18374
   195
                        if (packageStream != null) {
tboudreau@18374
   196
                            writeLine(pkg, info, emittedPackageLines, packageStream);
tboudreau@18374
   197
                        }
tboudreau@18374
   198
                        lastPackage = currPkg;
tboudreau@18374
   199
                        pkg.clear();
tboudreau@18374
   200
                    }
tboudreau@18301
   201
                    for (SourceElement outbound : outbounds) {
tboudreau@18301
   202
                        if (arguments.isExcluded(outbound.qname().toString())) { // Ignore matches
tboudreau@18301
   203
                            continue;
tboudreau@18301
   204
                        }
tboudreau@18301
   205
                        // If we are ignoring abstract methods, do that - has no effect on classes
tboudreau@18301
   206
                        if (arguments.isOmitAbstract() && (outbound.isAbstract() | sce.isAbstract())) {
tboudreau@18301
   207
                            continue;
tboudreau@18301
   208
                        }
tboudreau@18301
   209
                        // If the argument is set, ignore cases where it's a class' method
tboudreau@18301
   210
                        // referencing another method on that class
tboudreau@18301
   211
                        if (!arguments.isSelfReferences() && sce.typeName().equals(outbound.typeName())) {
tboudreau@18301
   212
                            continue;
tboudreau@18301
   213
                        }
tboudreau@18374
   214
                        if (outStream != null || !arguments.isQuiet()) {
tboudreau@18373
   215
                            if (arguments.isShortNames()) {
tboudreau@18373
   216
                                mth.add(outbound.shortName());
tboudreau@18373
   217
                            } else {
tboudreau@18373
   218
                                mth.add(outbound.qname());
tboudreau@18373
   219
                            }
tboudreau@18374
   220
                            if (arguments.isExtendedProperties()) {
tboudreau@18374
   221
                                mth.add(outbound.isAbstract());
tboudreau@18374
   222
                            }
tboudreau@18301
   223
                        }
tboudreau@18301
   224
                        // Build the package graph output if necessary
tboudreau@18301
   225
                        if (packageStream != null) {
tboudreau@18374
   226
                            if (!outbound.packageName().equals(currPkg) || arguments.isSelfReferences()) {
tboudreau@18374
   227
                                pkg.add(outbound.packageName());
tboudreau@18301
   228
                            }
tboudreau@18301
   229
                        }
tboudreau@18301
   230
                        // Build the class graph output if necessary
tboudreau@18301
   231
                        if (classStream != null) {
tboudreau@18301
   232
                            CharSequence type1 = sce.typeName();
tboudreau@18301
   233
                            CharSequence type2 = outbound.typeName();
tboudreau@18301
   234
                            if (!arguments.isShortNames()) {
tboudreau@18374
   235
//                                type1 = info.strings.concat(sce.packageName(), info.strings.DOT, type1);
tboudreau@18301
   236
                                type2 = info.strings.concat(outbound.packageName(), info.strings.DOT, type2);
tboudreau@18301
   237
                            }
tboudreau@18374
   238
                            if (!type1.equals(type2) && !clazz.contains(type2)) {
tboudreau@18374
   239
                                clazz.add(type2);
tboudreau@18374
   240
                                if (arguments.isExtendedProperties()) {
tboudreau@18374
   241
                                    clazz.add(outbound.isAbstract());
tboudreau@18301
   242
                                }
tboudreau@18301
   243
                            }
tboudreau@18301
   244
                        }
tboudreau@18301
   245
                    }
tboudreau@18374
   246
                    if (!arguments.isQuiet() || outStream != null) {
tboudreau@18373
   247
                        if (!mth.isEmpty()) {
tboudreau@18373
   248
                            CharSequence nm = arguments.isShortNames() ? sce.shortName() : sce.qname();
tboudreau@18374
   249
                            List<Object> l = mth;
tboudreau@18374
   250
                            if (arguments.isExtendedProperties()) {
tboudreau@18374
   251
                                mth.add(0, sce.isAbstract());
tboudreau@18374
   252
                            }
tboudreau@18373
   253
                            l.add(0, nm);
tboudreau@18373
   254
                            CharSequence line = info.strings.concatQuoted(l);
tboudreau@18373
   255
                            if (!arguments.isQuiet()) {
tboudreau@18373
   256
                                System.out.println(line);
tboudreau@18373
   257
                            }
tboudreau@18373
   258
                            if (outStream != null) {
tboudreau@18373
   259
                                outStream.println(line);
tboudreau@18373
   260
                            }
tboudreau@18373
   261
                        }
tboudreau@18373
   262
                    }
tboudreau@18301
   263
                }
tboudreau@18374
   264
                if (classStream != null && !clazz.isEmpty()) {
tboudreau@18374
   265
                    writeLine(clazz, info, emittedClassLines, classStream);
tboudreau@18374
   266
                }
tboudreau@18374
   267
                if (packageStream != null && !pkg.isEmpty()) {
tboudreau@18374
   268
                    writeLine(pkg, info, emittedPackageLines, packageStream);
tboudreau@18374
   269
                }
tboudreau@18301
   270
            } finally {
tboudreau@18301
   271
                for (PrintStream ps : new PrintStream[]{outStream, packageStream, classStream}) {
tboudreau@18301
   272
                    if (ps != null) {
tboudreau@18301
   273
                        ps.close();
tboudreau@18301
   274
                    }
tboudreau@18301
   275
                }
tboudreau@18301
   276
            }
tboudreau@18301
   277
        }
tboudreau@18301
   278
        return all;
tboudreau@18301
   279
    }
tboudreau@18374
   280
    private static void writeLine(List<Object> clazz, SourcesInfo info, Set<CharSequence> emittedClassLines, PrintStream classStream) {
tboudreau@18374
   281
        if (!clazz.isEmpty()) {
tboudreau@18374
   282
            CharSequence cs = info.strings.concatQuoted(clazz);
tboudreau@18374
   283
            if (!emittedClassLines.contains(cs)) {
tboudreau@18374
   284
                classStream.println(cs);
tboudreau@18374
   285
                emittedClassLines.add(cs);
tboudreau@18374
   286
            }
tboudreau@18374
   287
        }
tboudreau@18374
   288
    }
tboudreau@18301
   289
tboudreau@18301
   290
    private static PrintStream createPrintStreamIfNotNull(File outputFile) throws IOException {
tboudreau@18301
   291
        PrintStream outStream = null;
tboudreau@18301
   292
        if (outputFile != null) {
tboudreau@18301
   293
            if (!outputFile.exists()) {
tboudreau@18301
   294
                if (!outputFile.createNewFile()) {
tboudreau@18301
   295
                    throw new IllegalStateException("Could not create " + outputFile);
tboudreau@18301
   296
                }
tboudreau@18301
   297
            }
tboudreau@18301
   298
            outStream = new PrintStream(outputFile);
tboudreau@18301
   299
        }
tboudreau@18301
   300
        return outStream;
tboudreau@18301
   301
    }
tboudreau@18301
   302
tboudreau@18301
   303
    public List<String> toCommandLineArguments() {
tboudreau@18301
   304
        List<String> args = new ArrayList<>();
tboudreau@18301
   305
        addBoolean(CMD_NOSELF, noself, args);
tboudreau@18301
   306
        addBoolean(CMD_MAVEN, maven, args);
tboudreau@18301
   307
        addBoolean(CMD_QUIET, quiet, args);
tboudreau@18301
   308
        addBoolean(CMD_SIMPLE, simple, args);
tboudreau@18301
   309
        addBoolean(CMD_REVERSE, reverse, args);
tboudreau@18301
   310
        addBoolean(CMD_DISABLE_EIGHT_BIT_STRINGS, useJavaStrings, args);
tboudreau@18301
   311
        addBoolean(CMD_OMIT_ABSTRACT, omitAbstract, args);
tboudreau@18301
   312
        if (!excludes.isEmpty()) {
tboudreau@18301
   313
            StringBuilder concat = new StringBuilder();
tboudreau@18301
   314
            for (Iterator<String> it = excludes.iterator(); it.hasNext();) {
tboudreau@18301
   315
                String next = it.next();
tboudreau@18301
   316
                concat.append(next);
tboudreau@18301
   317
                if (it.hasNext()) {
tboudreau@18301
   318
                    concat.append(",");
tboudreau@18301
   319
                }
tboudreau@18301
   320
            }
tboudreau@18301
   321
            args.add("--" + CMD_EXCLUDE);
tboudreau@18301
   322
            args.add(concat.toString());
tboudreau@18301
   323
        }
tboudreau@18301
   324
        addFile(CMD_CLASSGRAPH, classgraphFile, args);
tboudreau@18301
   325
        addFile(CMD_METHODGRAPH, methodgraphFile, args);
tboudreau@18301
   326
        addFile(CMD_PACKAGEGRAPH, packagegraphFile, args);
tboudreau@18301
   327
        for (File fld : folders) {
tboudreau@18301
   328
            args.add(fld.getAbsolutePath());
tboudreau@18301
   329
        }
tboudreau@18301
   330
        return args;
tboudreau@18301
   331
    }
tboudreau@18301
   332
tboudreau@18372
   333
    CallgraphControl build() throws IOException {
tboudreau@18301
   334
        List<String> args = toCommandLineArguments();
tboudreau@18301
   335
        // We use regular string processing so we get the argument validation
tboudreau@18301
   336
        String[] argList = args.toArray(new String[args.size()]);
tboudreau@18301
   337
        Arguments arguments = new Arguments(false, argList);
tboudreau@18301
   338
        return arguments;
tboudreau@18301
   339
    }
tboudreau@18301
   340
tboudreau@18301
   341
    /**
tboudreau@18301
   342
     * Run this callgraph, writing output and returning the set of all methods
tboudreau@18301
   343
     * found, sorted in qname order. Call SourceElement.getInboundReferences()
tboudreau@18301
   344
     * and SourceElement.getOutboundReferences() to explore the graph.
tboudreau@18301
   345
     *
tboudreau@18301
   346
     * @return Sorted set of source elements
tboudreau@18301
   347
     * @throws IOException If i/o fails
tboudreau@18301
   348
     */
tboudreau@18301
   349
    public List<SourceElement> run() throws IOException {
tboudreau@18301
   350
        return Callgraph.invoke(build(), listener);
tboudreau@18301
   351
    }
tboudreau@18301
   352
tboudreau@18301
   353
    private void addFile(String command, File file, List<String> args) {
tboudreau@18301
   354
        if (file != null) {
tboudreau@18301
   355
            args.add("--" + command);
tboudreau@18301
   356
            args.add(file.getAbsolutePath());
tboudreau@18301
   357
        }
tboudreau@18301
   358
    }
tboudreau@18301
   359
tboudreau@18301
   360
    private void addBoolean(String command, boolean val, List<String> args) {
tboudreau@18301
   361
        if (val) {
tboudreau@18301
   362
            args.add("--" + command);
tboudreau@18301
   363
        }
tboudreau@18301
   364
    }
tboudreau@18301
   365
tboudreau@18301
   366
    public Callgraph setListener(Listener listener) {
tboudreau@18301
   367
        this.listener = listener;
tboudreau@18301
   368
        return this;
tboudreau@18301
   369
    }
tboudreau@18301
   370
tboudreau@18301
   371
    public Callgraph packageGraphOutput(File file) {
tboudreau@18301
   372
        packagegraphFile = file;
tboudreau@18301
   373
        return this;
tboudreau@18301
   374
    }
tboudreau@18301
   375
tboudreau@18301
   376
    public Callgraph methodGraphOutput(File file) {
tboudreau@18301
   377
        methodgraphFile = file;
tboudreau@18301
   378
        return this;
tboudreau@18301
   379
    }
tboudreau@18301
   380
tboudreau@18301
   381
    public Callgraph classGraphOutput(File file) {
tboudreau@18301
   382
        classgraphFile = file;
tboudreau@18301
   383
        return this;
tboudreau@18301
   384
    }
tboudreau@18301
   385
tboudreau@18301
   386
    public Callgraph addSourceParent(File folder) {
tboudreau@18301
   387
        folders.add(folder);
tboudreau@18301
   388
        return this;
tboudreau@18301
   389
    }
tboudreau@18301
   390
tboudreau@18301
   391
    public Callgraph excludePrefix(String prefix) {
tboudreau@18301
   392
        excludes.add(prefix);
tboudreau@18301
   393
        return this;
tboudreau@18301
   394
    }
tboudreau@18301
   395
tboudreau@18301
   396
    public Callgraph useSimpleClassNames() {
tboudreau@18301
   397
        simple = true;
tboudreau@18301
   398
        return this;
tboudreau@18301
   399
    }
tboudreau@18301
   400
tboudreau@18301
   401
    public Callgraph quiet() {
tboudreau@18301
   402
        quiet = true;
tboudreau@18301
   403
        return this;
tboudreau@18301
   404
    }
tboudreau@18301
   405
tboudreau@18301
   406
    public Callgraph ignoreSelfReferences() {
tboudreau@18301
   407
        noself = true;
tboudreau@18301
   408
        return this;
tboudreau@18301
   409
    }
tboudreau@18301
   410
tboudreau@18301
   411
    public Callgraph scanFoldersForMavenProjects() {
tboudreau@18301
   412
        maven = true;
tboudreau@18301
   413
        return this;
tboudreau@18301
   414
    }
tboudreau@18301
   415
tboudreau@18301
   416
    public Callgraph reverse() {
tboudreau@18301
   417
        reverse = true;
tboudreau@18301
   418
        return this;
tboudreau@18301
   419
    }
tboudreau@18301
   420
tboudreau@18301
   421
    public Callgraph useJavaStrings() {
tboudreau@18301
   422
        useJavaStrings = true;
tboudreau@18301
   423
        return this;
tboudreau@18301
   424
    }
tboudreau@18301
   425
tboudreau@18301
   426
    public Callgraph omitAbstract() {
tboudreau@18301
   427
        omitAbstract = true;
tboudreau@18301
   428
        return this;
tboudreau@18301
   429
    }
tboudreau@18301
   430
tboudreau@18301
   431
    private static final class LoggingListener implements Listener {
tboudreau@18301
   432
tboudreau@18301
   433
        @Override
tboudreau@18301
   434
        public void onStart() {
tboudreau@18301
   435
            //do nothing
tboudreau@18301
   436
        }
tboudreau@18301
   437
tboudreau@18301
   438
        @Override
tboudreau@18301
   439
        public void onFinish() {
tboudreau@18301
   440
            System.out.println("Done.");
tboudreau@18301
   441
        }
tboudreau@18301
   442
tboudreau@18301
   443
        @Override
tboudreau@18301
   444
        public void onStartActivity(String activity, int steps) {
tboudreau@18301
   445
            if (steps > 0) {
tboudreau@18301
   446
                System.out.println(activity + " (" + steps + " steps)");
tboudreau@18301
   447
            }
tboudreau@18301
   448
        }
tboudreau@18301
   449
tboudreau@18301
   450
        @Override
tboudreau@18301
   451
        public void onStep(String step) {
tboudreau@18301
   452
            System.out.println("\t" + step);
tboudreau@18301
   453
        }
tboudreau@18301
   454
    }
tboudreau@18301
   455
}