- /*
- * Copyright (c) 2001-2024, Jean Tessier
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * * Neither the name of Jean Tessier nor the names of his contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- package com.jeantessier.dependencyfinder.cli;
- import com.jeantessier.classreader.AggregatingClassfileLoader;
- import com.jeantessier.classreader.ClassfileLoader;
- import com.jeantessier.classreader.LoadListenerVisitorAdapter;
- import com.jeantessier.classreader.TransientClassfileLoader;
- import com.jeantessier.commandline.CommandLineException;
- import com.jeantessier.metrics.*;
- import org.apache.logging.log4j.*;
- import java.io.*;
- import java.lang.reflect.*;
- import java.nio.file.*;
- import java.util.*;
- public class OOMetrics extends DirectoryExplorerCommand {
- public static final String DEFAULT_PROJECT_NAME = "Project";
- public static final String DEFAULT_SORT = "name";
- protected void populateCommandLineSwitches() {
- super.populateCommandLineSwitches();
- populateCommandLineSwitchesForXMLOutput(XMLPrinter.DEFAULT_ENCODING, XMLPrinter.DEFAULT_DTD_PREFIX, XMLPrinter.DEFAULT_INDENT_TEXT);
- getCommandLine().addSingleValueSwitch("project-name", DEFAULT_PROJECT_NAME);
- getCommandLine().addSingleValueSwitch("default-configuration", true);
- getCommandLine().addSingleValueSwitch("configuration");
- getCommandLine().addToggleSwitch("csv");
- getCommandLine().addToggleSwitch("json");
- getCommandLine().addToggleSwitch("text");
- getCommandLine().addToggleSwitch("txt");
- getCommandLine().addToggleSwitch("xml");
- getCommandLine().addToggleSwitch("yaml");
- getCommandLine().addToggleSwitch("yml");
- getCommandLine().addToggleSwitch("validate");
- getCommandLine().addToggleSwitch("project");
- getCommandLine().addToggleSwitch("groups");
- getCommandLine().addToggleSwitch("classes");
- getCommandLine().addToggleSwitch("methods");
- getCommandLine().addMultipleValuesSwitch("scope-includes-list");
- getCommandLine().addMultipleValuesSwitch("scope-excludes-list");
- getCommandLine().addMultipleValuesSwitch("filter-includes-list");
- getCommandLine().addMultipleValuesSwitch("filter-excludes-list");
- getCommandLine().addToggleSwitch("show-all-metrics");
- getCommandLine().addToggleSwitch("show-empty-metrics");
- getCommandLine().addToggleSwitch("show-hidden-measurements");
- getCommandLine().addSingleValueSwitch("sort", DEFAULT_SORT);
- getCommandLine().addToggleSwitch("expand");
- getCommandLine().addToggleSwitch("reverse");
- getCommandLine().addToggleSwitch("enable-cross-class-measurements");
- }
- protected Collection<CommandLineException> parseCommandLine(String[] args) {
- Collection<CommandLineException> exceptions = super.parseCommandLine(args);
- if (!getCommandLine().isPresent("project") && !getCommandLine().isPresent("groups") && !getCommandLine().isPresent("classes") && !getCommandLine().isPresent("methods")) {
- getCommandLine().getSwitch("project").setValue(true);
- getCommandLine().getSwitch("groups").setValue(true);
- getCommandLine().getSwitch("classes").setValue(true);
- getCommandLine().getSwitch("methods").setValue(true);
- }
- int modeSwitch = 0;
- if (getCommandLine().getToggleSwitch("csv")) {
- modeSwitch++;
- }
- if (getCommandLine().getToggleSwitch("txt")) {
- modeSwitch++;
- }
- if (getCommandLine().getToggleSwitch("text")) {
- modeSwitch++;
- }
- if (getCommandLine().getToggleSwitch("xml")) {
- modeSwitch++;
- }
- if (getCommandLine().getToggleSwitch("json")) {
- modeSwitch++;
- }
- if (getCommandLine().getToggleSwitch("yaml")) {
- modeSwitch++;
- }
- if (getCommandLine().getToggleSwitch("yml")) {
- modeSwitch++;
- }
- if (modeSwitch != 1) {
- exceptions.add(new CommandLineException("Must have one and only one of -csv, -json, -text, -txt, -xml, -yml, or -yaml"));
- }
- return exceptions;
- }
- protected void doProcessing() throws Exception {
- LogManager.getLogger(OOMetrics.class).debug("Reading configuration ...");
- getVerboseListener().print("Reading configuration ...");
- String projectName = getCommandLine().getSingleSwitch("project-name");
- MetricsFactory factory;
- if (getCommandLine().isPresent("configuration")) {
- factory = new MetricsFactory(projectName, new MetricsConfigurationLoader(getCommandLine().getToggleSwitch("validate")).load(getCommandLine().getSingleSwitch("configuration")));
- } else {
- factory = new MetricsFactory(projectName, new MetricsConfigurationLoader(getCommandLine().getToggleSwitch("validate")).load(getCommandLine().getSingleSwitch("default-configuration")));
- }
- MetricsGatherer gatherer = new MetricsGatherer(factory);
- if (getCommandLine().isPresent("scope-includes-list") || getCommandLine().isPresent("scope-excludes-list")) {
- gatherer.setScopeIncludes(createCollection(getCommandLine().getMultipleSwitch("scope-includes-list"), getCommandLine().getMultipleSwitch("scope-excludes-list")));
- }
- if (getCommandLine().isPresent("filter-includes-list") || getCommandLine().isPresent("filter-excludes-list")) {
- gatherer.setFilterIncludes(createCollection(getCommandLine().getMultipleSwitch("filter-includes-list"), getCommandLine().getMultipleSwitch("filter-excludes-list")));
- }
- gatherer.addMetricsListener(getVerboseListener());
- if (getCommandLine().isPresent("enable-cross-class-measurements")) {
- LogManager.getLogger(OOMetrics.class).debug("Reading in all classes ...");
- getVerboseListener().print("Reading in all classes ...");
- ClassfileLoader loader = new AggregatingClassfileLoader();
- loader.addLoadListener(getVerboseListener());
- loader.load(getCommandLine().getParameters());
- LogManager.getLogger(OOMetrics.class).debug("Computing metrics ...");
- getVerboseListener().print("Computing metrics ...");
- gatherer.visitClassfiles(loader.getAllClassfiles());
- } else {
- ClassfileLoader loader = new TransientClassfileLoader();
- loader.addLoadListener(getVerboseListener());
- loader.addLoadListener(new LoadListenerVisitorAdapter(gatherer));
- LogManager.getLogger(OOMetrics.class).debug("Reading classes and computing metrics as we go ...");
- getVerboseListener().print("Reading classes and computing metrics as we go ...");
- loader.load(getCommandLine().getParameters());
- }
- if (getCommandLine().isPresent("show-all-metrics")) {
- gatherer.getMetricsFactory().getAllClassMetrics().forEach(metrics -> gatherer.getMetricsFactory().includeClassMetrics(metrics));
- gatherer.getMetricsFactory().getAllMethodMetrics().forEach(metrics -> gatherer.getMetricsFactory().includeMethodMetrics(metrics));
- }
- LogManager.getLogger(OOMetrics.class).debug("Printing results ...");
- getVerboseListener().print("Printing results ...");
- if (getCommandLine().isPresent("csv")) {
- printCSVFiles(gatherer.getMetricsFactory());
- } else if (getCommandLine().isPresent("json")) {
- printJSONFile(gatherer.getMetricsFactory());
- } else if (getCommandLine().isPresent("text") || getCommandLine().isPresent("txt")) {
- printTextFile(gatherer.getMetricsFactory());
- } else if (getCommandLine().isPresent("xml")) {
- printXMLFile(gatherer.getMetricsFactory());
- } else if (getCommandLine().isPresent("yaml") || getCommandLine().isPresent("yml")) {
- printYAMLFile(gatherer.getMetricsFactory());
- }
- LogManager.getLogger(OOMetrics.class).debug("Done.");
- }
- private static Collection<String> createCollection(Collection<String> includes, Collection<String> excludes) throws IOException {
- Collection<String> result = new HashSet<>();
- for (String include : includes) {
- result.addAll(Files.readAllLines(Paths.get(include)));
- }
- for (String exclude : excludes) {
- result.removeAll(Files.readAllLines(Paths.get(exclude)));
- }
- return result;
- }
- private void printCSVFiles(MetricsFactory factory) throws IOException {
- printCSVFile("project", "Project", factory.getConfiguration().getProjectMeasurements(), factory.getProjectMetrics());
- printCSVFile("groups", "Groups", factory.getConfiguration().getGroupMeasurements(), factory.getGroupMetrics());
- printCSVFile("classes", "Classes", factory.getConfiguration().getClassMeasurements(), factory.getClassMetrics());
- printCSVFile("methods", "Methods", factory.getConfiguration().getMethodMeasurements(), factory.getMethodMetrics());
- }
- private void printCSVFile(String name, String label, List<MeasurementDescriptor> descriptors, Collection<Metrics> metrics) throws IOException {
- if (getCommandLine().getToggleSwitch(name)) {
- if (getCommandLine().isPresent("out")) {
- setOut(new PrintWriter(new FileWriter(getCommandLine().getSingleSwitch("out") + "_" + name + ".csv")));
- } else {
- getOut().print(label);
- getOut().println(":");
- }
- printMetrics(descriptors, metrics, CSVPrinter.class);
- if (getCommandLine().isPresent("out")) {
- getOut().close();
- }
- }
- }
- private void printJSONFile(MetricsFactory factory) throws IOException {
- printMetrics(factory.getProjectMetrics(), new JSONPrinter(getOut(), factory.getConfiguration()));
- getOut().close();
- }
- private void printTextFile(MetricsFactory factory) throws IOException {
- printTextFile("project", "Project metrics", factory.getConfiguration().getProjectMeasurements(), factory.getProjectMetrics());
- printTextFile("groups", "Group metrics", factory.getConfiguration().getGroupMeasurements(), factory.getGroupMetrics());
- printTextFile("classes", "Class metrics", factory.getConfiguration().getClassMeasurements(), factory.getClassMetrics());
- printTextFile("methods", "Method metrics", factory.getConfiguration().getMethodMeasurements(), factory.getMethodMetrics());
- getOut().close();
- }
- private void printTextFile(String name, String label, List<MeasurementDescriptor> descriptors, Collection<Metrics> metrics) throws IOException {
- if (getCommandLine().getToggleSwitch(name)) {
- getOut().println(label);
- getOut().println(label.replaceAll(".", "-"));
- printMetrics(descriptors, metrics, TextPrinter.class);
- getOut().println();
- }
- }
- private void printXMLFile(MetricsFactory factory) throws IOException {
- printMetrics(factory.getProjectMetrics(), new XMLPrinter(getOut(), factory.getConfiguration(), getCommandLine().getSingleSwitch("encoding"), getCommandLine().getSingleSwitch("dtd-prefix")));
- getOut().close();
- }
- private void printYAMLFile(MetricsFactory factory) throws IOException {
- printMetrics(factory.getProjectMetrics(), new YAMLPrinter(getOut(), factory.getConfiguration()));
- getOut().close();
- }
- private void printMetrics(List<MeasurementDescriptor> descriptors, Collection<Metrics> metrics, Class<? extends Printer> clazz) throws IOException {
- try {
- printMetrics(metrics, clazz.getConstructor(PrintWriter.class, List.class).newInstance(getOut(), descriptors));
- } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException ex) {
- throw new RuntimeException(ex);
- }
- }
- private void printMetrics(Collection<Metrics> metrics, Printer printer) {
- printer.setExpandCollectionMeasurements(getCommandLine().getToggleSwitch("expand"));
- printer.setShowEmptyMetrics(getCommandLine().isPresent("show-empty-metrics"));
- printer.setShowHiddenMeasurements(getCommandLine().isPresent("show-hidden-measurements"));
- if (getCommandLine().isPresent("indent-text")) {
- printer.setIndentText(getCommandLine().getSingleSwitch("indent-text"));
- }
- var comparator = new MetricsComparator(getCommandLine().getSingleSwitch("sort"));
- if (getCommandLine().getToggleSwitch("reverse")) {
- comparator.reverse();
- }
- printer.setComparator(comparator);
- printer.visitMetrics(metrics);
- }
- public static void main(String[] args) throws Exception {
- new OOMetrics().run(args);
- }
- }