Skip to content

Commit

Permalink
Merge 053e091 into a3ea45f
Browse files Browse the repository at this point in the history
  • Loading branch information
sjoerdtalsma committed Aug 16, 2018
2 parents a3ea45f + 053e091 commit 14a188d
Show file tree
Hide file tree
Showing 18 changed files with 739 additions and 33 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@
<version>${project.version}</version>
</docletArtifact>
<additionalOptions>
<!--<additionalOption>-verbose</additionalOption>-->
<additionalOption>-verbose</additionalOption>
<!--<additionalOption>-quiet</additionalOption>-->
<!--<aditionalOption>-umlImageDirectory images</aditionalOption>-->
</additionalOptions>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@
import nl.talsmasoftware.umldoclet.logging.Logger;
import nl.talsmasoftware.umldoclet.rendering.indent.Indentation;

import java.net.URI;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Optional;

/**
* Configuration that influences <em>how</em> UML should be rendered.
Expand Down Expand Up @@ -72,6 +74,15 @@ public interface Configuration {
*/
List<String> excludedTypeReferences();

/**
* Resolves an external link to the specified type.
*
* @param packageName The package of the type.
* @param type The type name within the package.
* @return The external link, if resolved
*/
Optional<URI> resolveExternalLinkToType(String packageName, String type);

/**
* The UML character set can be explicitly configured with the {@code "-umlEncoding"} option.
* <p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import nl.talsmasoftware.umldoclet.rendering.indent.Indentation;
import nl.talsmasoftware.umldoclet.uml.Visibility;

import java.net.URI;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
Expand Down Expand Up @@ -108,6 +109,8 @@ public class DocletConfig implements Configuration {
List<String> excludedReferences = new ArrayList<>(asList(
"java.lang.Object", "java.lang.Enum", "java.lang.annotation.Annotation"));

List<ExternalLink> externalLinks = new ArrayList<>();

private Indentation indentation = Indentation.DEFAULT;

public DocletConfig(UMLDoclet doclet) {
Expand Down Expand Up @@ -164,6 +167,14 @@ public List<String> excludedTypeReferences() {
return excludedReferences;
}

@Override
public Optional<URI> resolveExternalLinkToType(String packageName, String type) {
return externalLinks.stream()
.map(link -> link.resolveType(packageName, type))
.filter(Optional::isPresent).map(Optional::get)
.findFirst();
}

@Override
public Charset umlCharset() {
return umlencoding != null ? Charset.forName(umlencoding)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* Copyright 2016-2018 Talsma ICT
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package nl.talsmasoftware.umldoclet.javadoc;

import nl.talsmasoftware.umldoclet.configuration.Configuration;
import nl.talsmasoftware.umldoclet.logging.Message;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;

import static java.util.Collections.emptySet;
import static java.util.Collections.unmodifiableSet;
import static java.util.Objects.requireNonNull;
import static nl.talsmasoftware.umldoclet.util.FileUtils.openReaderTo;
import static nl.talsmasoftware.umldoclet.util.UriUtils.addHttpParam;
import static nl.talsmasoftware.umldoclet.util.UriUtils.addPathComponent;

final class ExternalLink {

private final Configuration config;
private final URI docUri, packageListUri;
private Set<String> packages;

ExternalLink(Configuration config, String apidoc, String packageList) {
this.config = requireNonNull(config, "Configuration is <null>.");
this.docUri = createUri(requireNonNull(apidoc, "External apidoc URI is <null>."));
requireNonNull(packageList, "Location URI for \"package-list\" is <null>.");
this.packageListUri = addPathComponent(createUri(packageList), "package-list");
}

Optional<URI> resolveType(String packagename, String typeName) {
if (packages().contains(packagename)) {
String document = packagename.replace('.', '/') + "/" + typeName + ".html";
return Optional.of(addHttpParam(makeAbsolute(addPathComponent(docUri, document)), "is-external", "true"));
}
return Optional.empty();
}

private Set<String> packages() {
if (packages == null) try {
synchronized (this) {
Set<String> pkglist = new HashSet<>();
try (BufferedReader reader = new BufferedReader(
openReaderTo(config.destinationDirectory(), packageListUri, "UTF-8"))) {
for (String line = reader.readLine(); line != null; line = reader.readLine()) {
line = line.trim();
if (!line.isEmpty()) pkglist.add(line);
}
}
packages = unmodifiableSet(pkglist);
}
} catch (IOException | RuntimeException ex) {
config.logger().warn(Message.WARNING_CANNOT_READ_PACKAGE_LIST, packageListUri, ex);
packages = emptySet();
}
return packages;
}

private URI makeAbsolute(URI uri) {
if (uri != null && !uri.isAbsolute()) {
uri = new File(config.destinationDirectory(), uri.toASCIIString()).toURI();
}
return uri;
}

private static URI createUri(String uri) {
try {
return URI.create(uri);
} catch (IllegalArgumentException iae) {
if (new File(uri).exists()) return new File(uri).toURI();
throw iae;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ private UMLOptions(DocletConfig config, Set<Doclet.Option> standardOptions) {
add(new Option("-verbose", 0, Kind.OTHER, (args) -> config.verbose = true));
add(new Option("-docencoding", 1, Kind.OTHER, (args) -> config.docencoding = args.get(0)));
add(new Option("-encoding", 1, Kind.OTHER, (args) -> config.encoding = args.get(0)));
add(new Option("-link", 1, Kind.OTHER, (args) -> config.externalLinks.add(new ExternalLink(config, args.get(0), args.get(0)))));
add(new Option("-linkoffline", 2, Kind.OTHER, (args) -> config.externalLinks.add(new ExternalLink(config, args.get(0), args.get(1)))));

// Our own options
add(new Option("-d", 1, Kind.STANDARD, (args) -> config.destDirName = args.get(0)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public enum Message {
INFO_GENERATING_FILE,
INFO_ADD_DIAGRAM_TO_FILE,
WARNING_UNRECOGNIZED_IMAGE_FORMAT,
WARNING_CANNOT_READ_PACKAGE_LIST,
ERROR_UNANTICIPATED_ERROR_GENERATING_UML,
ERROR_UNANTICIPATED_ERROR_GENERATING_DIAGRAMS,
ERROR_UNANTICIPATED_ERROR_POSTPROCESSING_HTML;
Expand Down
54 changes: 34 additions & 20 deletions src/main/java/nl/talsmasoftware/umldoclet/uml/Link.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@

import static nl.talsmasoftware.umldoclet.util.FileUtils.relativePath;

/**
* Class for rendering links in the generated UML
*
* @author Sjoerd Talsma
*/
public class Link extends UMLPart {
private static final ThreadLocal<String> LINK_FROM = new ThreadLocal<>();

Expand All @@ -33,26 +38,35 @@ private Link(UMLPart parent, URI target) {
this.target = target;
}

public static Link toType(Type type) {
public static Link forType(Type type) {
final String destinationDirectory = type.getConfiguration().destinationDirectory();
final String packageName = type.getNamespace().name;
File file = new File(type.getConfiguration().destinationDirectory());
file = new File(file, packageName.replace('.', '/'));
if (type.name.qualified.startsWith(packageName + ".")) {
file = new File(file, type.name.qualified.substring(packageName.length() + 1) + ".html");
} else {
file = new File(file, type.name.simple + ".html");
}
if (file.isFile()) {
return new Link(type, file.toURI());
}
final String nameInPackage = type.name.qualified.startsWith(packageName + ".")
? type.name.qualified.substring(packageName.length() + 1) : type.name.simple;

// Otherwise maybe provide an URL to Oracle's javadoc for JDK classes etc?
return new Link(type, null);
Optional<URI> target = relativeHtmlFile(destinationDirectory, packageName, nameInPackage)
.or(() -> type.getConfiguration().resolveExternalLinkToType(packageName, nameInPackage));

return new Link(type, target.orElse(null));
}

private static Optional<URI> relativeHtmlFile(String destinationDirectory, String packageName, String nameInPackage) {
final String directory = destinationDirectory + "/" + packageName.replace('.', '/');
return Optional.of(new File(directory, nameInPackage + ".html"))
.filter(File::isFile)
.map(File::toURI);
}

public static void linkFrom(String path) {
if (path == null) LINK_FROM.remove();
else LINK_FROM.set(path);
/**
* Sets the base path where relative links should be rendered from.
* <p>
* This setting is configured on a per-thread basis.
*
* @param basePath The base path to define relative links from.
*/
public static void linkFrom(String basePath) {
if (basePath == null) LINK_FROM.remove();
else LINK_FROM.set(basePath);
}

private Optional<Namespace> diagramPackage() {
Expand All @@ -78,15 +92,15 @@ private Optional<File> linkFromDir() {

private Optional<String> relativeTarget() {
return Optional.ofNullable(target)
.filter(uri -> "file".equals(uri.getScheme()))
.map(File::new)
.filter(uri -> "file".equals(uri.getScheme())).map(File::new)
.flatMap(targetFile -> linkFromDir().map(dir -> relativePath(dir, targetFile)));
}

@Override
public <IPW extends IndentingPrintWriter> IPW writeTo(IPW output) {
relativeTarget()
.ifPresent(link -> output.append("[[").append(link).append("]]"));
if (target != null) {
output.append("[[").append(relativeTarget().orElseGet(target::toASCIIString)).append("]]");
}
return output;
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/java/nl/talsmasoftware/umldoclet/uml/Type.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ private Type(Namespace namespace, Classification classification, TypeName name,
}

private Link link() {
if (link == null) link = Link.toType(this);
if (link == null) link = Link.forType(this);
return link;
}

Expand Down
34 changes: 33 additions & 1 deletion src/main/java/nl/talsmasoftware/umldoclet/util/FileUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@
package nl.talsmasoftware.umldoclet.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
Expand Down Expand Up @@ -78,7 +82,7 @@ public static String relativePath(File from, File to) {
* @throws IllegalStateException in case the parent directory did not yet exist and could not be created either.
*/
public static File ensureParentDir(File file) {
if (file != null && !file.getParentFile().exists() && !file.getParentFile().mkdirs()) {
if (file != null && !file.getParentFile().isDirectory() && !file.getParentFile().mkdirs()) {
throw new IllegalStateException("Can't create directory \"" + file.getParent() + "\".");
}
return file;
Expand All @@ -103,6 +107,34 @@ public static String withoutExtension(String path) {
return path;
}

/**
* Opens a reader to the specified URI.
* <p>
* If the call {@code uri.toURL().openStream()} succeeds, a reader is wrapped and returned.
* Otherwise, if the URI is absolute, an attempt is made to open it as a file. If this also fails,
* a last effort is made to open the uri relative to the specified {@code basedir} directory.
*
* @param basedir The base directory to use if the URI turns out to be a relative file link.
* @param uri The URI to read from.
* @param charsetName The character set to use for reading.
* @return The opened reader.
* @throws IOException in case the call to {@code uri.toURL().openStream()} threw an I/O Exception.
*/
public static Reader openReaderTo(String basedir, URI uri, String charsetName) throws IOException {
try {
return new InputStreamReader(uri.toURL().openStream(), charsetName);
} catch (IOException | RuntimeException ex) {
try {
File uriAsFile = uri.isAbsolute() && "file".equals(uri.getScheme()) ? new File(uri) : new File(uri.toASCIIString());
if (!uriAsFile.isFile()) uriAsFile = new File(basedir, uri.toASCIIString());
if (uriAsFile.isFile()) return new InputStreamReader(new FileInputStream(uriAsFile), charsetName);
} catch (IOException | RuntimeException secondaryEx) {
ex.addSuppressed(secondaryEx);
}
throw ex;
}
}

public static boolean hasExtension(Object file, String extension) {
if (file == null || extension == null) return false;
if (!extension.startsWith(".")) extension = '.' + extension;
Expand Down
Loading

0 comments on commit 14a188d

Please sign in to comment.