All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.codefx.maven.plugin.jdeps.parse.ViolationParser Maven / Gradle / Ivy

The newest version!
package org.codefx.maven.plugin.jdeps.parse;

import java.util.Objects;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.codefx.maven.plugin.jdeps.dependency.InternalType;
import org.codefx.maven.plugin.jdeps.dependency.Type;
import org.codefx.maven.plugin.jdeps.dependency.Violation;
import org.codefx.maven.plugin.jdeps.dependency.Violation.ViolationBuilder;

/**
 * Parses violation blocks from the JDeps output line by line and hands created {@link Violation}s to a {@link Consumer}
 * which can further process it.
 */
public class ViolationParser {

	/**
	 * Pattern to match the reported type line, e.g.
	 *
	 * 
	 * 	   org.codefx.lab.App (...)
	 * 
*/ private static final Pattern REPORTED_TYPE_PATTERN = Pattern.compile("" + "\\s+" // leading spaces + "([a-zA_Z_][\\.\\w]*)" // qualified class name (simplified), e.g. "sun.misc.Unsafe" + "\\s+" // spaces to separate class name + ".*"); private final InternalTypeLineParser internalTypeLineParser; private final Consumer violationConsumer; private LineParserState lineParser; /** * Creates a new parser. * * @param violationConsumer * the {@link Consumer} to which parsed {@link Violation}s are handed over */ public ViolationParser(Consumer violationConsumer) { this(new InternalTypeLineParser(), violationConsumer); } /** * Creates a new parser. * * @param internalTypeLineParser * used to parse individual internal dependencies * @param violationConsumer * the {@link Consumer} to which parsed {@link Violation}s are handed over */ public ViolationParser(InternalTypeLineParser internalTypeLineParser, Consumer violationConsumer) { Objects.requireNonNull(internalTypeLineParser, "The argument 'internalTypeLineParser' must not be null."); Objects.requireNonNull(violationConsumer, "The argument 'violationConsumer' must not be null."); this.internalTypeLineParser = internalTypeLineParser; this.violationConsumer = violationConsumer; this.lineParser = new NoBlock(); } // #begin PARSE SUPPORT /** * Parses the specified line. *

* As soon as a new {@link Violation} is created it is handed to the {@link Consumer} specified during construction. * * @param line * the line to parse */ public void parseLine(String line) { Objects.requireNonNull(line, "The argument 'line' must not be null."); lineParser = lineParser.parseLine(line); } /** * Informs the parser that parsing is done (for now). *

* If a violation is currently being created, calling this method will build it. */ public void finish() { lineParser = lineParser.parseLine(""); } private LineParserState determineWhetherNewBlockStarted(String line) { Optional asFirstBlockLine = parseAsFirstBlockLine(line); if (asFirstBlockLine.isPresent()) return new BlockBegan(asFirstBlockLine.get()); else return new NoBlock(); } private static Optional parseAsFirstBlockLine(String line) { Matcher firstLineMatcher = REPORTED_TYPE_PATTERN.matcher(line); boolean isFirstLine = firstLineMatcher.matches(); if (isFirstLine) return Optional.of(firstLineMatcher.group(1)); else return Optional.empty(); } // #end PARSE SUPPORT // #begin PARSE STATE MACHINE private interface LineParserState { LineParserState parseLine(String line); } /** * There is currently no violations block. *

* The next line may start a new block if it is a {@link #REPORTED_TYPE_PATTERN REPORTED_TYPE}. */ private class NoBlock implements LineParserState { @Override public LineParserState parseLine(String line) { return determineWhetherNewBlockStarted(line); } } /** * A block began and a violation is being build. *

* The block can either be continued with an internal dependency or may end. If it ends: *

    *
  • the violation which is currently being build is finished and handed to the {@link #violationConsumer} *
  • a new block might start with the next line ~> transition to new {@link BlockBegan} *
  • some other lines might occur ~> transition to {@link NoBlock} *
*/ private class BlockBegan implements LineParserState { private final ViolationBuilder violationBuilder; public BlockBegan(String fullyQualifiedClassName) { assert fullyQualifiedClassName != null : "The argument 'fullyQualifiedClassName' must not be null."; Type type = Type.of(fullyQualifiedClassName); violationBuilder = Violation.forType(type); } @Override public LineParserState parseLine(String line) { assert line != null : "The argument 'line' must not be null."; boolean lineCouldBeProcessed = processLine(line); return computeNextState(line, lineCouldBeProcessed); } private boolean processLine(String line) { Optional parsedInternalType = internalTypeLineParser.parseLine(line); parsedInternalType.ifPresent(violationBuilder::addDependency); return parsedInternalType.isPresent(); } private LineParserState computeNextState(String line, boolean lineCouldBeProcessed) { if (lineCouldBeProcessed) return this; else { finishViolation(); return determineWhetherNewBlockStarted(line); } } private void finishViolation() { Violation violation = violationBuilder.build(); violationConsumer.accept(violation); } } // #end PARSE STATE MACHINE }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy