8219958: Automatically load taglets from a jar file

Reviewed-by: jjg
This commit is contained in:
Priya Lakshmi Muthuswamy 2019-03-20 09:58:12 +05:30
parent 95b189916f
commit 1c0f35a5b4
4 changed files with 230 additions and 57 deletions

View file

@ -837,39 +837,47 @@ public abstract class BaseConfiguration {
tagletManager = tagletManager == null ?
new TagletManager(nosince, showversion, showauthor, javafx, this) :
tagletManager;
for (List<String> args : customTagStrs) {
if (args.get(0).equals("-taglet")) {
tagletManager.addCustomTag(args.get(1), getFileManager(), tagletpath);
continue;
}
List<String> tokens = tokenize(args.get(1), TagletManager.SIMPLE_TAGLET_OPT_SEPARATOR, 3);
switch (tokens.size()) {
case 1:
String tagName = args.get(1);
if (tagletManager.isKnownCustomTag(tagName)) {
//reorder a standard tag
tagletManager.addNewSimpleCustomTag(tagName, null, "");
} else {
//Create a simple tag with the heading that has the same name as the tag.
StringBuilder heading = new StringBuilder(tagName + ":");
heading.setCharAt(0, Character.toUpperCase(tagName.charAt(0)));
tagletManager.addNewSimpleCustomTag(tagName, heading.toString(), "a");
}
break;
case 2:
//Add simple taglet without heading, probably to excluding it in the output.
tagletManager.addNewSimpleCustomTag(tokens.get(0), tokens.get(1), "");
break;
case 3:
tagletManager.addNewSimpleCustomTag(tokens.get(0), tokens.get(2), tokens.get(1));
break;
default:
Messages messages = getMessages();
messages.error("doclet.Error_invalid_custom_tag_argument", args.get(1));
JavaFileManager fileManager = getFileManager();
Messages messages = getMessages();
try {
tagletManager.initTagletPath(fileManager, tagletpath);
tagletManager.loadTaglets(fileManager);
for (List<String> args : customTagStrs) {
if (args.get(0).equals("-taglet")) {
tagletManager.addCustomTag(args.get(1), fileManager);
continue;
}
List<String> tokens = tokenize(args.get(1), TagletManager.SIMPLE_TAGLET_OPT_SEPARATOR, 3);
switch (tokens.size()) {
case 1:
String tagName = args.get(1);
if (tagletManager.isKnownCustomTag(tagName)) {
//reorder a standard tag
tagletManager.addNewSimpleCustomTag(tagName, null, "");
} else {
//Create a simple tag with the heading that has the same name as the tag.
StringBuilder heading = new StringBuilder(tagName + ":");
heading.setCharAt(0, Character.toUpperCase(tagName.charAt(0)));
tagletManager.addNewSimpleCustomTag(tagName, heading.toString(), "a");
}
break;
case 2:
//Add simple taglet without heading, probably to excluding it in the output.
tagletManager.addNewSimpleCustomTag(tokens.get(0), tokens.get(1), "");
break;
case 3:
tagletManager.addNewSimpleCustomTag(tokens.get(0), tokens.get(2), tokens.get(1));
break;
default:
messages.error("doclet.Error_invalid_custom_tag_argument", args.get(1));
}
}
} catch (IOException e) {
messages.error("doclet.taglet_could_not_set_location", e.toString());
}
}

View file

@ -56,6 +56,8 @@ doclet.Notice_taglet_overriden=Note: Custom tags that override standard tags: {0
doclet.Notice_taglet_conflict_warn=Note: Custom tags that could override future standard tags: {0}. To avoid potential overrides, use at least one period character (.) in custom tag names.
doclet.Error_taglet_not_registered=Error - Exception {0} thrown while trying to register Taglet {1}...
doclet.Error_invalid_custom_tag_argument=Error - {0} is an invalid argument to the -tag option...
doclet.taglet_could_not_set_location = Could not set the taglet path: {0}
doclet.not_standard_file_manager = Cannot set taglet path; the file manager is not a StandardJavaFileManager
doclet.Author=Author:
doclet.DefaultValue=Default value:
doclet.PropertyDescription=Property description:

View file

@ -204,44 +204,77 @@ public class TagletManager {
}
/**
* Add a new {@code Taglet}. Print a message to indicate whether or not
* Initializes the location TAGLET_PATH which is used to locate the custom taglets.
* @param fileManager the filemanager to load classes and resources.
* @param tagletPath the path to the custom taglet.
* @throws IOException if an error occurs while setting the location.
*/
public void initTagletPath(JavaFileManager fileManager, String tagletPath) throws IOException {
if (fileManager instanceof StandardJavaFileManager) {
StandardJavaFileManager sfm = (StandardJavaFileManager)fileManager;
if (tagletPath != null) {
List<File> paths = new ArrayList<>();
for (String pathname : tagletPath.split(File.pathSeparator)) {
paths.add(new File(pathname));
}
sfm.setLocation(TAGLET_PATH, paths);
} else if (!sfm.hasLocation(TAGLET_PATH)) {
sfm.setLocation(TAGLET_PATH, Collections.emptyList());
}
} else if (tagletPath != null) {
messages.error("doclet.not_standard_file_manager");
}
}
/**
* Adds a new {@code Taglet}. Print a message to indicate whether or not
* the Taglet was registered properly.
* @param classname the name of the class representing the custom tag.
* @param fileManager the filemanager to load classes and resources.
* @param tagletPath the path to the class representing the custom tag.
*/
public void addCustomTag(String classname, JavaFileManager fileManager, String tagletPath) {
public void addCustomTag(String classname, JavaFileManager fileManager) {
try {
ClassLoader tagClassLoader;
if (!fileManager.hasLocation(TAGLET_PATH)) {
List<File> paths = new ArrayList<>();
if (tagletPath != null) {
for (String pathname : tagletPath.split(File.pathSeparator)) {
paths.add(new File(pathname));
}
}
if (fileManager instanceof StandardJavaFileManager) {
((StandardJavaFileManager) fileManager).setLocation(TAGLET_PATH, paths);
}
}
tagClassLoader = fileManager.getClassLoader(TAGLET_PATH);
Class<? extends jdk.javadoc.doclet.Taglet> customTagClass =
tagClassLoader.loadClass(classname).asSubclass(jdk.javadoc.doclet.Taglet.class);
jdk.javadoc.doclet.Taglet instance = customTagClass.getConstructor().newInstance();
instance.init(docEnv, doclet);
Taglet newLegacy = new UserTaglet(instance);
String tname = newLegacy.getName();
Taglet t = allTaglets.get(tname);
if (t != null) {
allTaglets.remove(tname);
}
allTaglets.put(tname, newLegacy);
messages.notice("doclet.Notice_taglet_registered", classname);
} catch (Exception exc) {
messages.error("doclet.Error_taglet_not_registered", exc.getClass().getName(), classname);
registerTaglet(instance);
} catch (ReflectiveOperationException exc) {
messages.error("doclet.Error_taglet_not_registered", exc.getClass().getName(),
classname);
}
}
/**
* Loads taglets from a taglet path using service loader.
* @param fileManager the filemanager to load the taglets.
* @throws IOException if an error occurs while getting the service loader.
*/
public void loadTaglets(JavaFileManager fileManager) throws IOException {
Iterable<? extends File> location = ((StandardJavaFileManager)fileManager).getLocation(TAGLET_PATH);
if (location != null && location.iterator().hasNext()) {
ServiceLoader<jdk.javadoc.doclet.Taglet> serviceLoader =
fileManager.getServiceLoader(TAGLET_PATH, jdk.javadoc.doclet.Taglet.class);
Iterator<jdk.javadoc.doclet.Taglet> iterator = serviceLoader.iterator();
while (iterator.hasNext()) {
jdk.javadoc.doclet.Taglet taglet = iterator.next();
registerTaglet(taglet);
}
}
}
/**
* Registers the {@code Taglet}. Prints a message if a {@code Taglet} got registered properly.
* @param instance the {@code Taglet} instance.
*/
private void registerTaglet(jdk.javadoc.doclet.Taglet instance) {
instance.init(docEnv, doclet);
Taglet newLegacy = new UserTaglet(instance);
allTaglets.put(newLegacy.getName(), newLegacy);
messages.notice("doclet.Notice_taglet_registered", instance.getClass().getName());
}
/**
* Add a new {@code SimpleTaglet}. If this tag already exists
* and the header passed as an argument is null, move tag to the back of the