DependencyReporter.java

  1. /*
  2.  *  Copyright (c) 2001-2024, Jean Tessier
  3.  *  All rights reserved.
  4.  *  
  5.  *  Redistribution and use in source and binary forms, with or without
  6.  *  modification, are permitted provided that the following conditions
  7.  *  are met:
  8.  *  
  9.  *      * Redistributions of source code must retain the above copyright
  10.  *        notice, this list of conditions and the following disclaimer.
  11.  *  
  12.  *      * Redistributions in binary form must reproduce the above copyright
  13.  *        notice, this list of conditions and the following disclaimer in the
  14.  *        documentation and/or other materials provided with the distribution.
  15.  *  
  16.  *      * Neither the name of Jean Tessier nor the names of his contributors
  17.  *        may be used to endorse or promote products derived from this software
  18.  *        without specific prior written permission.
  19.  *  
  20.  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21.  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22.  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23.  *  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR
  24.  *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  25.  *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  26.  *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  27.  *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  28.  *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  29.  *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  30.  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31.  */

  32. package com.jeantessier.dependencyfinder.cli;

  33. import java.util.*;
  34. import java.io.*;

  35. import javax.xml.parsers.*;

  36. import org.xml.sax.*;

  37. import com.jeantessier.commandline.*;
  38. import com.jeantessier.dependency.*;
  39. import com.jeantessier.dependency.Printer;
  40. import com.jeantessier.dependency.TextPrinter;
  41. import com.jeantessier.dependency.Visitor;

  42. public class DependencyReporter extends DependencyGraphCommand {
  43.     protected void populateCommandLineSwitches() {
  44.         super.populateCommandLineSwitches();
  45.         populateCommandLineSwitchesForXMLOutput(XMLPrinter.DEFAULT_ENCODING, XMLPrinter.DEFAULT_DTD_PREFIX, XMLPrinter.DEFAULT_INDENT_TEXT);

  46.         populateCommandLineSwitchesForScoping();
  47.         populateCommandLineSwitchesForFiltering();

  48.         getCommandLine().addAliasSwitch("p2p", "package-scope", "package-filter");
  49.         getCommandLine().addAliasSwitch("c2p", "class-scope", "package-filter");
  50.         getCommandLine().addAliasSwitch("c2c", "class-scope", "class-filter");
  51.         getCommandLine().addAliasSwitch("f2f", "feature-scope", "feature-filter");
  52.         getCommandLine().addAliasSwitch("includes", "scope-includes", "filter-includes");
  53.         getCommandLine().addAliasSwitch("excludes", "scope-excludes", "filter-excludes");

  54.         getCommandLine().addToggleSwitch("show-inbounds");
  55.         getCommandLine().addToggleSwitch("show-outbounds");
  56.         getCommandLine().addToggleSwitch("show-empty-nodes");

  57.         getCommandLine().addToggleSwitch("html");
  58.         getCommandLine().addToggleSwitch("json");
  59.         getCommandLine().addToggleSwitch("text");
  60.         getCommandLine().addToggleSwitch("txt");
  61.         getCommandLine().addToggleSwitch("xml");
  62.         getCommandLine().addToggleSwitch("yaml");
  63.         getCommandLine().addToggleSwitch("yml");

  64.         getCommandLine().addToggleSwitch("minimize");
  65.         getCommandLine().addToggleSwitch("maximize");
  66.         getCommandLine().addToggleSwitch("copy-only");
  67.         getCommandLine().addToggleSwitch("include-filter-nodes");

  68.         getCommandLine().addSingleValueSwitch("url-format", HTMLPrinter.DEFAULT_URL_FORMAT);
  69.     }

  70.     protected Collection<CommandLineException> parseCommandLine(String[] args) {
  71.         Collection<CommandLineException> exceptions = super.parseCommandLine(args);

  72.         exceptions.addAll(validateCommandLineForScoping());
  73.         exceptions.addAll(validateCommandLineForFiltering());

  74.         if (getCommandLine().getToggleSwitch("maximize") && getCommandLine().getToggleSwitch("minimize")) {
  75.             exceptions.add(new CommandLineException("Only one of -maximize or -minimize is allowed"));
  76.         }

  77.         int modeSwitch = 0;

  78.         if (getCommandLine().getToggleSwitch("html")) {
  79.             modeSwitch++;
  80.         }
  81.         if (getCommandLine().getToggleSwitch("json")) {
  82.             modeSwitch++;
  83.         }
  84.         if (getCommandLine().getToggleSwitch("text")) {
  85.             modeSwitch++;
  86.         }
  87.         if (getCommandLine().getToggleSwitch("txt")) {
  88.             modeSwitch++;
  89.         }
  90.         if (getCommandLine().getToggleSwitch("xml")) {
  91.             modeSwitch++;
  92.         }
  93.         if (getCommandLine().getToggleSwitch("yaml")) {
  94.             modeSwitch++;
  95.         }
  96.         if (getCommandLine().getToggleSwitch("yml")) {
  97.             modeSwitch++;
  98.         }
  99.         if (modeSwitch > 1) {
  100.             exceptions.add(new CommandLineException("Must have at most one of -html, -json, -text, -txt, -xml, -yml, or -yaml"));
  101.         }

  102.         return exceptions;
  103.     }

  104.     protected void doProcessing() throws Exception {
  105.         SelectionCriteria scopeCriteria = getScopeCriteria();
  106.         SelectionCriteria filterCriteria = getFilterCriteria();

  107.         GraphCopier copier;
  108.         if (getCommandLine().getToggleSwitch("copy-only") || getCommandLine().getToggleSwitch("maximize")) {
  109.             copier = new GraphCopier(new SelectiveTraversalStrategy(scopeCriteria, filterCriteria));
  110.         } else {
  111.             copier = new GraphSummarizer(scopeCriteria, filterCriteria);
  112.         }
  113.         copyGraph(copier);

  114.         getVerboseListener().print("Printing the graph ...");

  115.         Printer printer;
  116.         if (getCommandLine().isPresent("html")) {
  117.             printer = new HTMLPrinter(getOut(), getCommandLine().getSingleSwitch("url-format"));
  118.         } else if (getCommandLine().isPresent("json")) {
  119.             printer = new JSONPrinter(getOut());
  120.         } else if (getCommandLine().isPresent("xml")) {
  121.             printer = new XMLPrinter(getOut(), getCommandLine().getSingleSwitch("encoding"), getCommandLine().getSingleSwitch("dtd-prefix"));
  122.         } else if (getCommandLine().isPresent("yaml") || getCommandLine().isPresent("yml")) {
  123.             printer = new YAMLPrinter(getOut());
  124.         } else {
  125.             printer = new TextPrinter(getOut());
  126.         }

  127.         if (getCommandLine().isPresent("indent-text")) {
  128.             printer.setIndentText(getCommandLine().getSingleSwitch("indent-text"));
  129.         }

  130.         if (getCommandLine().isPresent("show-inbounds") || getCommandLine().isPresent("show-outbounds") || getCommandLine().isPresent("show-empty-nodes")) {
  131.             printer.setShowInbounds(getCommandLine().isPresent("show-inbounds"));
  132.             printer.setShowOutbounds(getCommandLine().isPresent("show-outbounds"));
  133.             printer.setShowEmptyNodes(getCommandLine().isPresent("show-empty-nodes"));
  134.         }

  135.         var packages = copier.getScopeFactory().getPackages().values();

  136.         if (getCommandLine().isPresent("include-filter-nodes")) {
  137.             var nodeFactory = new NodeFactory();
  138.             new GraphCopier(nodeFactory).traverseNodes(packages);
  139.             packages = nodeFactory.getPackages().values();
  140.         }

  141.         printer.traverseNodes(packages);
  142.     }

  143.     private void copyGraph(Visitor copier) throws IOException, SAXException, ParserConfigurationException {
  144.         if (getCommandLine().getParameters().isEmpty()) {
  145.             copyGraphFromSystemIn(copier);
  146.         } else {
  147.             copyGraphFromFiles(copier);
  148.         }
  149.     }

  150.     private void copyGraphFromSystemIn(Visitor copier) throws IOException, ParserConfigurationException, SAXException {
  151.         copyGraph(copier, loadGraphFromSystemIn());
  152.     }

  153.     private void copyGraphFromFiles(Visitor copier) throws IOException, SAXException, ParserConfigurationException {
  154.         for (String filename : getCommandLine().getParameters()) {
  155.             if (filename.endsWith(".xml")) {
  156.                 copyGraph(copier, loadGraphFromFile(filename));
  157.             } else {
  158.                 getVerboseListener().print("Skipping \"" + filename + "\".");
  159.             }

  160.         }
  161.     }

  162.     private void copyGraph(Visitor copier, Collection<PackageNode> packages) {
  163.         if (getCommandLine().getToggleSwitch("maximize")) {
  164.             new LinkMaximizer().traverseNodes(packages);
  165.         } else if (getCommandLine().getToggleSwitch("minimize")) {
  166.             new LinkMinimizer().traverseNodes(packages);
  167.         }

  168.         copier.traverseNodes(packages);
  169.     }

  170.     private Collection<PackageNode> loadGraphFromSystemIn() throws IOException, SAXException, ParserConfigurationException {
  171.         Collection<PackageNode> packages;

  172.         getVerboseListener().print("Reading from standard input");

  173.         NodeLoader loader = new NodeLoader(getCommandLine().getToggleSwitch("validate"));
  174.         loader.addDependencyListener(getVerboseListener());
  175.         packages = loader.load(System.in).getPackages().values();

  176.         getVerboseListener().print("Read from standard input.");

  177.         return packages;
  178.     }

  179.     private Collection<PackageNode> loadGraphFromFile(String filename) throws IOException, SAXException, ParserConfigurationException {
  180.         Collection<PackageNode> packages;

  181.         getVerboseListener().print("Reading " + filename);

  182.         NodeLoader loader = new NodeLoader(getCommandLine().getToggleSwitch("validate"));
  183.         loader.addDependencyListener(getVerboseListener());
  184.         packages = loader.load(filename).getPackages().values();

  185.         getVerboseListener().print("Read \"" + filename + "\".");

  186.         return packages;
  187.     }

  188.     public static void main(String[] args) throws Exception {
  189.         new DependencyReporter().run(args);
  190.     }
  191. }