ListDiffPrinter.java
/*
* Copyright (c) 2001-2025, 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.diff;
import com.jeantessier.text.PrinterBuffer;
import org.apache.oro.text.perl.Perl5Util;
import java.util.Collection;
import java.util.Collections;
import java.util.TreeSet;
public class ListDiffPrinter {
public static final boolean DEFAULT_COMPRESS = false;
public static final String DEFAULT_ENCODING = "utf-8";
public static final String DEFAULT_DTD_PREFIX = "https://jeantessier.github.io/dependency-finder/dtd";
public static final String DEFAULT_INDENT_TEXT = PrinterBuffer.DEFAULT_INDENT_TEXT;
private static final Perl5Util perl = new Perl5Util();
private final boolean compress;
private final PrinterBuffer buffer;
private String name = "";
private String oldVersion = "";
private String newVersion = "";
private final Collection<String> removed = new TreeSet<>();
private final Collection<String> added = new TreeSet<>();
public ListDiffPrinter() {
this(DEFAULT_COMPRESS, DEFAULT_INDENT_TEXT, DEFAULT_ENCODING, DEFAULT_DTD_PREFIX);
}
public ListDiffPrinter(boolean compress) {
this(compress, DEFAULT_INDENT_TEXT, DEFAULT_ENCODING, DEFAULT_DTD_PREFIX);
}
public ListDiffPrinter(boolean compress, String indentText, String encoding, String dtdPrefix) {
this.buffer = new PrinterBuffer(indentText);
this.compress = compress;
appendHeader(encoding, dtdPrefix);
}
private void appendHeader(String encoding, String dtdPrefix) {
append("<?xml version=\"1.0\" encoding=\"").append(encoding).append("\" ?>").eol();
eol();
append("<!DOCTYPE list-diff SYSTEM \"").append(dtdPrefix).append("/list-diff.dtd\">").eol();
eol();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getOldVersion() {
return oldVersion;
}
public void setOldVersion(String oldVersion) {
this.oldVersion = oldVersion;
}
public String getNewVersion() {
return newVersion;
}
public void setNewVersion(String newVersion) {
this.newVersion = newVersion;
}
public Collection<String> getRemoved() {
return Collections.unmodifiableCollection(removed);
}
public void remove(String line) {
this.removed.add(line);
}
public Collection<String> getAdded() {
return Collections.unmodifiableCollection(added);
}
public void add(String line) {
this.added.add(line);
}
protected ListDiffPrinter append(boolean b) {
buffer.append(b);
return this;
}
protected ListDiffPrinter append(char c) {
buffer.append(c);
return this;
}
protected ListDiffPrinter append(char[] str, int offset, int len) {
buffer.append(str, offset, len);
return this;
}
protected ListDiffPrinter append(char[] str) {
buffer.append(str);
return this;
}
protected ListDiffPrinter append(double d) {
buffer.append(d);
return this;
}
protected ListDiffPrinter append(float f) {
buffer.append(f);
return this;
}
protected ListDiffPrinter append(int i) {
buffer.append(i);
return this;
}
protected ListDiffPrinter append(long l) {
buffer.append(l);
return this;
}
protected ListDiffPrinter append(Object obj) {
buffer.append(obj);
return this;
}
protected ListDiffPrinter append(String str) {
buffer.append(str);
return this;
}
protected ListDiffPrinter indent() {
buffer.indent();
return this;
}
protected ListDiffPrinter eol() {
buffer.eol();
return this;
}
protected void raiseIndent() {
buffer.raiseIndent();
}
protected void lowerIndent() {
buffer.lowerIndent();
}
public String toString() {
indent().append("<list-diff>").eol();
raiseIndent();
indent().append("<name>").append(getName()).append("</name>").eol();
indent().append("<old>").append(getOldVersion()).append("</old>").eol();
indent().append("<new>").append(getNewVersion()).append("</new>").eol();
indent().append("<removed>").eol();
raiseIndent();
printLines(compress ? compress(getRemoved()) : getRemoved());
lowerIndent();
indent().append("</removed>").eol();
indent().append("<added>").eol();
raiseIndent();
printLines(compress ? compress(getAdded()) : getAdded());
lowerIndent();
indent().append("</added>").eol();
lowerIndent();
indent().append("</list-diff>").eol();
return buffer.toString();
}
private void printLines(Collection<String> lines) {
lines.forEach(line -> {
int pos = line.lastIndexOf(" [");
if (pos != -1) {
indent().append("<line>").append(line.substring(0, pos)).append("</line>").eol();
} else {
indent().append("<line>").append(line).append("</line>").eol();
}
});
}
private Collection<String> compress(Collection<String> lines) {
Collection<String> result = new TreeSet<>();
lines.forEach(line -> {
boolean add = true;
if (line.endsWith(" [C]")) {
String packageName = extractPackageName(line);
add = !lines.contains(packageName + " [P]");
} else if (line.endsWith(" [F]")) {
String className = extractClassName(line);
String packageName = extractPackageName(className);
add = !lines.contains(packageName + " [P]") && !lines.contains(className + " [C]");
}
if (add) {
result.add(line);
}
});
return result;
}
private String extractPackageName(String className) {
String result = "";
int pos = className.lastIndexOf('.');
if (pos != -1) {
result = className.substring(0, pos);
}
return result;
}
private String extractClassName(String featureName) {
String result = "";
synchronized (perl) {
if (perl.match("/^(.*)\\.[^\\.]*\\(.*\\)(: \\S.*)?/", featureName)) {
result = perl.group(1);
} else if (perl.match("/^(.*)\\.[\\^.]*/", featureName)) {
result = perl.group(1);
}
}
return result;
}
}