Skip to content

Commit

Permalink
Implement links from diagrams to javadoc HTML
Browse files Browse the repository at this point in the history
This fixes #69
  • Loading branch information
sjoerdtalsma committed Jun 22, 2018
1 parent 272b469 commit bed7e76
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,16 @@ String process(String line) {
}

private String getImageTag() {
String style = " style=\"max-width:60%;float:right;\"";
if (relativePath.endsWith(".svg")) {
// Render SVG images as objects to make their links work
return "<object type=\"image/svg+xml\" data=\"" + relativePath + "\" " + style + "></object>";
}

String name = relativePath.substring(relativePath.lastIndexOf('/') + 1);
int dotIdx = name.lastIndexOf('.');
if (dotIdx > 0) name = name.substring(0, dotIdx);
return "<img src=\"" + relativePath + "\" alt=\"" + name + " UML Diagram\" style=\"max-width:60%;float:right;\"/>";
return "<img src=\"" + relativePath + "\" alt=\"" + name + " UML Diagram\"" + style + "/>";
}

private String clearSummaryDiv(String line) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ String process(String line) {
}

private String getImageTag() {
if (relativePath.endsWith(".svg")) {
// Render SVG images as objects to make their links work
return "<object type=\"image/svg+xml\" data=\"" + relativePath + "\" " + CENTER_STYLE + "></object>";
}
return "<img src=\"" + relativePath + "\" alt=\"Package summary UML Diagram\"" + CENTER_STYLE + "/>";
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,43 +26,62 @@
import java.io.OutputStream;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.regex.Pattern;

import static java.util.Objects.requireNonNull;

/**
* @author Sjoerd Talsma
*/
public class PlantumlImage {
private static final Pattern LINK_PATTERN = Pattern.compile("\\[\\[\\S+]]");

private final String name;
private final File file;
private final FileFormat fileFormat;
private final Supplier<OutputStream> outputStreamSupplier;

protected PlantumlImage(String name, FileFormat fileFormat, Supplier<OutputStream> outputStreamSupplier) {
this.name = requireNonNull(name, "Image name is <null>.");
protected PlantumlImage(File file, FileFormat fileFormat, Supplier<OutputStream> outputStreamSupplier) {
this.file = requireNonNull(file, "Image file is <null>.");
this.fileFormat = requireNonNull(fileFormat, "File format is <null>.");
this.outputStreamSupplier = requireNonNull(outputStreamSupplier, "Output stream supplier is <null>.");
}

public static Optional<PlantumlImage> fromFile(File file) {
return fileFormatOf(file).map(format -> new PlantumlImage(file.getPath(), format, () -> createFileOutputStream(file)));
return fileFormatOf(file).map(format -> new PlantumlImage(file, format, () -> createFileOutputStream(file)));
}

public String getName() {
return name;
return file.getPath();
}

final void renderPlantuml(SourceStringReader plantumlSource) throws IOException {
requireNonNull(plantumlSource, "PlantUML source is <null>.");
final void renderPlantuml(String uml) throws IOException {
requireNonNull(uml, "PlantUML diagram is <null>.");
try (OutputStream imageOutput = new BufferedOutputStream(outputStreamSupplier.get())) {
plantumlSource.outputImage(imageOutput, new FileFormatOption(fileFormat));
new SourceStringReader(filterBrokenLinks(uml)).outputImage(imageOutput, new FileFormatOption(fileFormat));
}
}

private String filterBrokenLinks(String uml) {
return LINK_PATTERN.matcher(uml).replaceAll(result -> {
String link = uml.substring(result.start() + 2, result.end() - 2);
return fixLink(link).map(lnk -> "[[" + lnk + "]]").orElse("");
});
}

private Optional<String> fixLink(String link) {
// For now only keep links that work relative from where the diagram ends up
File f = new File(file.getParent(), link);
if (f.exists()) {
return Optional.of(link);
}
// TODO: Fix images relative to possible umlImagedir
// TODO: Fix possible JDK documentation links?
return Optional.empty();
}

@Override
public String toString() {
final int sep = name.lastIndexOf(File.separatorChar);
return sep >= 0 ? name.substring(sep + 1) : name;
return file.getName();
}

private static Optional<FileFormat> fileFormatOf(File file) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
*/
package nl.talsmasoftware.umldoclet.rendering.plantuml;

import net.sourceforge.plantuml.SourceStringReader;
import nl.talsmasoftware.umldoclet.configuration.Configuration;
import nl.talsmasoftware.umldoclet.logging.Logger;
import nl.talsmasoftware.umldoclet.rendering.writers.StringBufferingWriter;
Expand Down Expand Up @@ -82,10 +81,10 @@ public static PlantumlImageWriter create(Configuration config, File plantumlFile
public void close() throws IOException {
super.close();
if (!images.isEmpty()) {
SourceStringReader sourceStringReader = new SourceStringReader(getBuffer().toString());
final String uml = getBuffer().toString();
for (PlantumlImage image : images) {
config.logger().info(INFO_GENERATING_FILE, image.getName());
image.renderPlantuml(sourceStringReader);
image.renderPlantuml(uml);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
*/
public class PackageDiagram extends UMLDiagram {

private final String packageName;
final String packageName;
private File pumlFile = null;

public PackageDiagram(Configuration config, String packageName) {
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/nl/talsmasoftware/umldoclet/uml/Type.java
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,21 @@ public <IPW extends IndentingPrintWriter> IPW writeTo(IPW output, Namespace name
output.append(classfication.toUml()).whitespace();
writeNameTo(output, namespace).whitespace();
if (isDeprecated) output.append("<<deprecated>>").whitespace();
writeLinkTo(output).whitespace();
writeChildrenTo(output).newline();
return output;
}

private <IPW extends IndentingPrintWriter> IPW writeLinkTo(IPW output) {
final String prefix = getNamespace().name + '.';
if (name.qualified.startsWith(prefix)) {
output.append("[[");
output.append(name.qualified.substring(prefix.length()));
output.append(".html]]");
}
return output;
}

@Override
public <IPW extends IndentingPrintWriter> IPW writeChildrenTo(IPW output) {
if (!children.isEmpty()) super.writeChildrenTo(output.append('{').newline()).append('}');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

import nl.talsmasoftware.umldoclet.UMLDoclet;
import nl.talsmasoftware.umldoclet.util.Testing;
import org.junit.Ignore;
import org.junit.Test;

import java.io.File;
Expand All @@ -30,11 +29,13 @@
/**
* @author Sjoerd Talsma
*/
@Ignore // Links are not built yet
public class Issue69LinksTest {
static final File testoutput = new File("target/test-69");
static final String packageAsPath = Issue69LinksTest.class.getPackageName().replace('.', '/');

public static class InnerClass {
}

@Test
public void testLink_sameDirectory() {
File outputdir = new File(testoutput, "same-dir");
Expand All @@ -47,24 +48,10 @@ public void testLink_sameDirectory() {
);

String uml = Testing.read(packageUml);
// Check link to test class
assertThat(uml, stringContainsInOrder(asList("Issue69LinksTest", "[[Issue69LinksTest.html]]")));
}

@Test
public void testLink_otherDirectory() {
File outputdir = new File(testoutput, "other-dir");
File packageUml = new File(outputdir, packageAsPath + "/package.puml");

ToolProvider.findFirst("javadoc").get().run(
System.out, System.err,
"-d", outputdir.getPath(),
"-umlImageDirectory", "images",
"-doclet", UMLDoclet.class.getName(),
"src/test/java/" + packageAsPath + '/' + getClass().getSimpleName() + ".java"
);

String uml = Testing.read(packageUml);
assertThat(uml, stringContainsInOrder(asList("Issue69LinksTest", "[[../nl/talsmasoftware/umldoclet/issues/Issue69LinksTest.html]]")));
// Check link to inner class
assertThat(uml, stringContainsInOrder(asList("InnerClass", "[[Issue69LinksTest.InnerClass.html]]")));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
package nl.talsmasoftware.umldoclet.rendering.plantuml;

import net.sourceforge.plantuml.FileFormat;
import net.sourceforge.plantuml.SourceStringReader;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
Expand All @@ -41,7 +40,7 @@
* @author Sjoerd Talsma
*/
public class PlantumlImageTest {
private static SourceStringReader plantumlSource = new SourceStringReader("@startuml\nversion\n@enduml");
private static String uml = "@startuml\nversion\n@enduml";

private File tempdir;

Expand All @@ -65,13 +64,13 @@ public void testConstructor_nameNull() {

@Test(expected = NullPointerException.class)
public void testConstructor_fileFormatNull() {
new PlantumlImage("diagram.png", null, ByteArrayOutputStream::new) {
new PlantumlImage(new File("diagram.png"), null, ByteArrayOutputStream::new) {
};
}

@Test(expected = NullPointerException.class)
public void testConstructor_outputStreamSupplierNull() {
new PlantumlImage("diagram.png", FileFormat.PNG, null) {
new PlantumlImage(new File("diagram.png"), FileFormat.PNG, null) {
};
}

Expand Down Expand Up @@ -111,7 +110,7 @@ public void testRender_cannotCreateFile() throws IOException {
File pngDir = new File(tempdir, "directory.png");
assertThat(pngDir.mkdir(), is(true));
try {
PlantumlImage.fromFile(pngDir).get().renderPlantuml(plantumlSource);
PlantumlImage.fromFile(pngDir).get().renderPlantuml(uml);
fail("Runtime exception expected");
} catch (RuntimeException expected) {
assertThat(expected, hasToString(stringContainsInOrder(asList("Could not create writer", "directory.png"))));
Expand All @@ -123,7 +122,7 @@ public void testRender_cannotCreateFile() throws IOException {
@Test
public void testRenderImage() throws IOException {
File png = new File(tempdir, "diagram.png");
PlantumlImage.fromFile(png).get().renderPlantuml(plantumlSource);
PlantumlImage.fromFile(png).get().renderPlantuml(uml);
assertThat(png.isFile(), is(true));
assertThat(png.length(), is(greaterThan(0L)));
}
Expand Down

0 comments on commit bed7e76

Please sign in to comment.