/*
Copyright 2009 Lunatech Research
This file is part of jax-doclets.
jax-doclets is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
jax-doclets is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with jax-doclets. If not, see <http://www.gnu.org/licenses/>.
*/
package com.lunatech.doclets.jax;
import java.io.*;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.lunatech.doclets.jax.jaxb.model.JAXBClass;
import com.lunatech.doclets.jax.jaxrs.model.Resource;
import com.lunatech.doclets.jax.jaxrs.model.ResourceMethod;
import com.lunatech.doclets.jax.jpa.model.JPAClass;
import com.lunatech.doclets.jax.writers.DocletWriter;
import com.sun.javadoc.AnnotationDesc;
import com.sun.javadoc.AnnotationDesc.ElementValuePair;
import com.sun.javadoc.AnnotationTypeDoc;
import com.sun.javadoc.AnnotationValue;
import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.Doc;
import com.sun.javadoc.MethodDoc;
import com.sun.javadoc.PackageDoc;
import com.sun.javadoc.ParamTag;
import com.sun.javadoc.Parameter;
import com.sun.javadoc.ParameterizedType;
import com.sun.javadoc.ProgramElementDoc;
import com.sun.javadoc.Tag;
import com.sun.javadoc.Type;
import com.sun.tools.doclets.formats.html.HtmlDocletWriter;
import com.sun.tools.doclets.internal.toolkit.Configuration;
import com.sun.tools.doclets.internal.toolkit.taglets.DeprecatedTaglet;
import com.sun.tools.doclets.internal.toolkit.taglets.ParamTaglet;
import com.sun.tools.doclets.internal.toolkit.taglets.Taglet;
import com.sun.tools.doclets.internal.toolkit.taglets.TagletManager;
import com.sun.tools.doclets.internal.toolkit.taglets.TagletOutput;
import com.sun.tools.doclets.internal.toolkit.taglets.TagletWriter;
import com.sun.tools.doclets.internal.toolkit.util.DirectoryManager;
public class Utils {
public static boolean isEmptyOrNull(String str) {
return str == null || str.length() == 0;
}
public static String getParamDoc(final MethodDoc declaringMethod, final String name) {
for (final ParamTag paramTag : declaringMethod.paramTags()) {
if (paramTag.parameterName().equals(name)) {
return paramTag.parameterComment();
}
}
return "";
}
public static Object getAnnotationValue(final AnnotationDesc annotation) {
return getAnnotationValue(annotation, "value");
}
public static Object getAnnotationValue(AnnotationDesc annotation, String name) {
for (final ElementValuePair elementValuePair : annotation.elementValues()) {
if (elementValuePair.element().name().equals(name)) {
return elementValuePair.value().value();
}
}
return null;
}
public static String[] getAnnotationValues(final AnnotationDesc annotation) {
final Object value = getAnnotationValue(annotation);
if (value instanceof String) {
return new String[] { (String) value };
}
if (value instanceof AnnotationValue[]) {
final AnnotationValue[] values = (AnnotationValue[]) value;
final String[] ret = new String[values.length];
for (int i = 0; i < ret.length; i++) {
ret[i] = (String) values[i].value();
}
return ret;
}
throw new IllegalArgumentException("value is not string or string[]: " + value);
}
public static boolean hasAnnotation(final ProgramElementDoc programElementDoc, final Class<?>... soughtAnnotations) {
return findAnnotation(programElementDoc, soughtAnnotations) != null;
}
public static MethodDoc findAnnotatedMethod(final ClassDoc declaringClass, final MethodDoc method, final Class<?>... soughtAnnotations) {
if(isExcluded(method)) {
return null;
}
final AnnotationDesc onMethod = findAnnotation(method, soughtAnnotations);
if (onMethod != null) {
return method;
}
// try on the declaring class
for (final MethodDoc declaringMethod : declaringClass.methods(false)) {
if (overrides(method, declaringMethod)) {
if (hasAnnotation(declaringMethod, soughtAnnotations)) {
return declaringMethod;
}
return null;
}
}
return null;
}
/**
* JavaDoc's MethodDoc.overrides(MethodDoc) is just broken as it doesn't do
* interfaces properly
*/
private static boolean overrides(MethodDoc overridingMethod, MethodDoc overriddenMethod) {
return overridingMethod.name().equals(overriddenMethod.name()) && overridingMethod.signature().equals(overriddenMethod.signature());
}
public static AnnotationDesc findMethodAnnotation(final ClassDoc declaringClass, final MethodDoc method,
final Class<?>... soughtAnnotations) {
final AnnotationDesc onMethod = findAnnotation(method, soughtAnnotations);
if (onMethod != null) {
return onMethod;
}
// try on the declaring class
for (final MethodDoc declaringMethod : declaringClass.methods(false)) {
if (overrides(method, declaringMethod)) {
return findAnnotation(declaringMethod, soughtAnnotations);
}
}
return null;
}
public static AnnotationDesc findParameterAnnotation(final MethodDoc declaringMethod, final Parameter parameter, int parameterIndex,
final Class<?>... soughtAnnotations) {
final AnnotationDesc onParameter = findAnnotation(parameter, soughtAnnotations);
if (onParameter != null) {
return onParameter;
}
// try on the declaring method
Parameter overriddenParameter = declaringMethod.parameters()[parameterIndex];
return findAnnotation(overriddenParameter, soughtAnnotations);
}
public static List<AnnotationDesc> findAnnotations(final ProgramElementDoc programElementDoc, final Class<?>... soughtAnnotations) {
return findAnnotations(programElementDoc.annotations(), soughtAnnotations);
}
public static AnnotationDesc findAnnotation(final ProgramElementDoc programElementDoc, final Class<?>... soughtAnnotations) {
return findAnnotation(programElementDoc.annotations(), soughtAnnotations);
}
public static AnnotationDesc findAnnotation(final Parameter parameter, final Class<?>... soughtAnnotations) {
return findAnnotation(parameter.annotations(), soughtAnnotations);
}
public static AnnotationDesc findAnnotation(final PackageDoc pack, final Class<?>... soughtAnnotations) {
return findAnnotation(pack.annotations(), soughtAnnotations);
}
public static AnnotationDesc findAnnotation(final AnnotationDesc[] annotations, final Class<?>... soughtAnnotations) {
for (final AnnotationDesc annotation : annotations) {
final AnnotationTypeDoc annotationType = annotation.annotationType();
for (final Class<?> soughtAnnotation : soughtAnnotations) {
if (annotationType.qualifiedTypeName().equals(soughtAnnotation.getName())) {
return annotation;
}
}
}
return null;
}
public static AnnotationDesc findAnnotation(final AnnotationDesc[] annotations, final String... soughtAnnotations) {
for (final AnnotationDesc annotation : annotations) {
final AnnotationTypeDoc annotationType = annotation.annotationType();
for (final String soughtAnnotation : soughtAnnotations) {
if (annotationType.qualifiedTypeName().equals(soughtAnnotation)) {
return annotation;
}
}
}
return null;
}
public static List<AnnotationDesc> findAnnotations(final AnnotationDesc[] annotations, final Class<?>... soughtAnnotations) {
List<AnnotationDesc> ret = new LinkedList<AnnotationDesc>();
for (final AnnotationDesc annotation : annotations) {
final AnnotationTypeDoc annotationType = annotation.annotationType();
for (final Class<?> soughtAnnotation : soughtAnnotations) {
if (annotationType.qualifiedTypeName().equals(soughtAnnotation.getName())) {
ret.add(annotation);
}
}
}
return ret;
}
public static ClassDoc findAnnotatedInterface(final ClassDoc klass, final Class<?>... soughtAnnotations) {
// find it in the interfaces
final Type[] interfaceTypes = klass.interfaceTypes();
for (final Type interfaceType : interfaceTypes) {
final ClassDoc interfaceClassDoc = interfaceType.asClassDoc();
if (interfaceClassDoc != null && !isExcluded(interfaceClassDoc)) {
if (hasAnnotation(interfaceClassDoc, soughtAnnotations)) {
return interfaceClassDoc;
}
final ClassDoc foundClassDoc = findAnnotatedInterface(interfaceClassDoc, soughtAnnotations);
if (foundClassDoc != null) {
return foundClassDoc;
}
}
}
return null;
}
public static ClassDoc findAnnotatedClass(final ClassDoc klass, final Class<?>... soughtAnnotations) {
if (!klass.isClass() || isExcluded(klass))
return null;
if (hasAnnotation(klass, soughtAnnotations)) {
return klass;
}
// find it in the interfaces
final ClassDoc foundClassDoc = findAnnotatedInterface(klass, soughtAnnotations);
if (foundClassDoc != null) {
return foundClassDoc;
}
final Type superclass = klass.superclassType();
if (superclass != null && superclass.asClassDoc() != null) {
return findAnnotatedClass(superclass.asClassDoc(), soughtAnnotations);
}
return null;
}
public static Type findSuperType(final Type type, String typeName) {
ClassDoc doc = type.asClassDoc();
if (doc == null)
return null;
if (doc.qualifiedTypeName().equals(typeName))
return type;
if (doc.isInterface())
return findSuperTypeFromInterface(doc, typeName);
if (doc.isClass() && !doc.isEnum() && !doc.isError() && !doc.isException())
return findSuperTypeFromClass(doc, typeName);
return null;
}
public static Type findSuperTypeFromInterface(final ClassDoc klass, String typeName) {
// find it in the interfaces
final Type[] interfaceTypes = klass.interfaceTypes();
for (final Type interfaceType : interfaceTypes) {
final ClassDoc interfaceClassDoc = interfaceType.asClassDoc();
if (interfaceClassDoc != null) {
if (interfaceClassDoc.qualifiedTypeName().equals(typeName))
return interfaceClassDoc;
final Type foundType = findSuperTypeFromInterface(interfaceClassDoc, typeName);
if (foundType != null) {
return foundType;
}
}
}
return null;
}
public static Type findSuperTypeFromClass(final ClassDoc klass, String typeName) {
if (klass.qualifiedTypeName().equals(typeName))
return klass;
// find it in the interfaces
final Type foundType = findSuperTypeFromInterface(klass, typeName);
if (foundType != null) {
return foundType;
}
final Type superclass = klass.superclassType();
if (superclass != null && superclass.asClassDoc() != null) {
return findSuperTypeFromClass(superclass.asClassDoc(), typeName);
}
return null;
}
public static String appendURLFragments(String... fragments) {
StringBuilder strbuf = new StringBuilder();
for (String fragment : fragments) {
// skip empty fragments
if (fragment == null || fragment.length() == 0)
continue;
if (!strbuf.toString().endsWith("/") && !fragment.startsWith("/")) {
strbuf.append("/");
}
if (strbuf.toString().endsWith("/") && fragment.startsWith("/")) {
fragment = fragment.substring(1);
}
strbuf.append(fragment);
}
return strbuf.toString();
}
public static String getFirstURLFragment(String path) {
if (path.startsWith("/"))
path = path.substring(1);
if (path.length() == 0)
return null;
String[] fragments = path.split("/+");
if (fragments.length == 0)
return null;
return fragments[0];
}
public static String slashify(String url) {
if (url == null)
return "";
if (!url.endsWith("/"))
return url + "/";
return url;
}
public static String unEndSlashify(String url) {
if (url == null)
return "";
if (url.endsWith("/"))
return url.substring(0, url.length() - 1);
return url;
}
public static String unStartSlashify(String url) {
if (url == null)
return "";
if (!url.startsWith("/"))
return url;
if (url.length() == 1) {
return "";
}
return url.substring(1);
}
public static String classToPath(JAXBClass jaxbClass) {
return DirectoryManager.getPath(jaxbClass.getPackageName());
}
public static String classToPath(JPAClass jpaClass) {
return DirectoryManager.getPath(jpaClass.getPackageName());
}
public static String classToPath(ClassDoc cDoc) {
return DirectoryManager.getPath(cDoc.containingPackage().name());
}
public static String urlToPath(Resource resource) {
String name = resource.getAbsolutePath();
if (name.startsWith("/"))
name = name.substring(1);
return name;
}
public static String urlToSystemPath(Resource resource) {
String name = resource.getAbsolutePath();
if (name.startsWith("/"))
name = name.substring(1);
return name.replace('/', File.separatorChar);
}
public static String urlToClass(ClassDoc from, ClassDoc to) {
return classToRoot(from) + classToPath(to) + "/" + to.name() + ".html";
}
public static String urlToClass(JAXBClass from, JAXBClass to) {
return classToRoot(from) + classToPath(to) + "/" + to.getShortClassName() + ".html";
}
public static String urlToClass(JPAClass from, JPAClass to) {
return classToRoot(from) + classToPath(to) + "/" + to.getShortClassName() + ".html";
}
public static String urlToType(ClassDoc klass) {
return DirectoryManager.getPathToClass(klass);
}
public static String classToRoot(JAXBClass klass) {
return DirectoryManager.getRelativePath(klass.getPackageName());
}
public static String classToRoot(ClassDoc cDoc) {
return DirectoryManager.getRelativePath(cDoc.containingPackage());
}
public static String classToRoot(JPAClass klass) {
return DirectoryManager.getRelativePath(klass.getPackageName());
}
public static String urlToRoot(Resource resource) {
String from = resource.getAbsolutePath();
if (from.startsWith("/"))
from = from.substring(1);
return urlToRoot(from);
}
public static String urlToRoot(String from) {
if (from == null || from.length() == 0) {
return "";
}
StringBuilder pathstr = new StringBuilder();
for (int i = 0; i < from.length(); i++) {
char ch = from.charAt(i);
if (ch == '/') {
pathstr.append("../");
}
}
pathstr.append("../");
return pathstr.toString();
}
public static void createDirectory(String path) {
if (path == null || path.length() == 0) {
return;
}
File dir = new File(path);
if (!dir.exists() && !dir.mkdirs()) {
throw new RuntimeException("Could not create path: " + path);
}
}
public static void genTagOuput(TagletManager tagletManager, Doc doc, Taglet[] taglets, TagletWriter writer, TagletOutput output,
Set<String> tagletsToPrint) {
tagletManager.checkTags(doc, doc.tags(), false);
tagletManager.checkTags(doc, doc.inlineTags(), true);
TagletOutput currentOutput = null;
for (int i = 0; i < taglets.length; i++) {
if (!tagletsToPrint.contains(taglets[i].getName()))
continue;
if (doc instanceof ClassDoc && taglets[i] instanceof ParamTaglet) {
// The type parameters are documented in a special section away
// from the tag info, so skip here.
continue;
}
if (taglets[i] instanceof DeprecatedTaglet) {
// Deprecated information is documented "inline", not in tag
// info
// section.
continue;
}
try {
currentOutput = taglets[i].getTagletOutput(doc, writer);
} catch (IllegalArgumentException e) {
// The taglet does not take a member as an argument. Let's try
// a single tag.
Tag[] tags = doc.tags(taglets[i].getName());
if (tags.length > 0) {
currentOutput = taglets[i].getTagletOutput(tags[0], writer);
}
}
if (currentOutput != null) {
tagletManager.seenCustomTag(taglets[i].getName());
output.appendOutput(currentOutput);
}
}
}
public static void copyResources(JAXConfiguration configuration) {
InputStream defaultCSS = Utils.class.getResourceAsStream("/doclet.css");
if (defaultCSS == null)
throw new RuntimeException("Failed to find doclet CSS (incorrect jax-doclets packaging?)");
if (!isEmptyOrNull(configuration.parentConfiguration.stylesheetfile)) {
try {
InputStream stream = new FileInputStream(configuration.parentConfiguration.stylesheetfile);
copyResource(stream, new File(configuration.parentConfiguration.destDirName, "doclet.css"));
// also put the original stylesheet in case it's needed
copyResource(defaultCSS, new File(configuration.parentConfiguration.destDirName, "default-doclet.css"));
} catch (Exception x) {
throw new RuntimeException("Failed to read user stylesheet " + configuration.parentConfiguration.stylesheetfile, x);
}
} else
copyResource(defaultCSS, new File(configuration.parentConfiguration.destDirName, "doclet.css"));
}
public static void copyJPAResources(JAXConfiguration configuration) {
copyResource(configuration, "graph.js");
copyResource(configuration, "jit.js");
}
private static void copyResource(JAXConfiguration configuration, String name) {
InputStream graphHTML = Utils.class.getResourceAsStream("/" + name);
if (graphHTML == null)
throw new RuntimeException("Failed to find " + name + " (incorrect jax-doclets packaging?)");
copyResource(graphHTML, new File(configuration.parentConfiguration.destDirName, name));
}
private static void copyResource(InputStream stream, File output) {
try {
OutputStream os = new FileOutputStream(output);
byte[] buffer = new byte[1024];
int read;
while ((read = stream.read(buffer)) >= 0) {
os.write(buffer, 0, read);
}
os.flush();
os.close();
stream.close();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static String readResource(File input) {
try {
Reader stream = new FileReader(input);
StringBuilder output = new StringBuilder();
char[] buffer = new char[1024];
int read;
while ((read = stream.read(buffer)) >= 0) {
output.append(buffer, 0, read);
}
stream.close();
return output.toString();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Returns either Produces.class or ProduceMime.class (old version)
*
* @return
*/
public static Class<?> getProducesClass() {
try {
return Class.forName("javax.ws.rs.Produces");
} catch (ClassNotFoundException e) {
try {
return Class.forName("javax.ws.rs.ProduceMime");
} catch (ClassNotFoundException e1) {
throw new RuntimeException(e1);
}
}
}
/**
* Returns either Consumes.class or ConsumeMime.class (old version)
*
* @return
*/
public static Class<?> getConsumesClass() {
try {
return Class.forName("javax.ws.rs.Consumes");
} catch (ClassNotFoundException e) {
try {
return Class.forName("javax.ws.rs.ConsumeMime");
} catch (ClassNotFoundException e1) {
throw new RuntimeException(e1);
}
}
}
public static String getExternalLink(Configuration configuration, Type type, HtmlDocletWriter writer) {
return getExternalLink(configuration, type.asClassDoc().containingPackage().name(), type.typeName(), writer);
}
public static String getExternalLink(Configuration configuration, String className, HtmlDocletWriter writer) {
int lastSep = className.lastIndexOf('.');
if (lastSep == -1)
return getExternalLink(configuration, "", className, writer);
String link;
// since classes can be internal, look up backwards with an ever shrinking
// package name
do {
link = getExternalLink(configuration, className.substring(0, lastSep), className.substring(lastSep + 1), writer);
if (link != null)
return link;
lastSep = className.lastIndexOf('.', lastSep - 1);
} while (lastSep > -1);
return null;
}
private static String getExternalLink(Configuration configuration, String packageName, String className, HtmlDocletWriter writer) {
return configuration.extern.getExternalLink(packageName, writer.relativePath, className + ".html");
}
public static String getLinkTypeName(String url) {
int lastSep = url.lastIndexOf('/');
if (lastSep != -1 && url.endsWith(".html"))
return url.substring(lastSep + 1, url.length() - 5);
throw new IllegalArgumentException("Invalid type link: " + url);
}
public static Tag getTag(Doc doc, String tagName) {
Tag[] tags = doc.tags("@" + tagName);
if (tags != null && tags.length > 0) {
return tags[0];
}
return null;
}
public static Tag[] getTags(Doc doc, String tagName) {
Tag[] tags = doc.tags("@" + tagName);
if (tags != null && tags.length > 0) {
return tags;
}
return null;
}
public static String getOption(String options[][], String optionName) {
for (String option[] : options) {
String name = option[0];
if (!optionName.equals(name)) {
continue;
}
String value = option.length > 1 ? option[1] : null;
return value;
}
return null;
}
public static List<String> getOptions(String options[][], String optionName) {
List<String> result = new ArrayList<String>();
for (String option[] : options) {
String name = option[0];
if (!optionName.equals(name)) {
continue;
}
String value = option.length > 1 ? option[1] : null;
result.add(value);
}
return result;
}
/**
* @return true if optionName exists in one of the options.
*/
public static boolean hasOption(String options[][], String optionName) {
for (String option[] : options) {
String name = option[0];
if (!optionName.equals(name)) {
continue;
}
return true;
}
return false;
}
public static boolean isCollection(Type type) {
Type collectionType = Utils.findSuperType(type, "java.util.Collection");
// FIXME: this is dodgy at best
return collectionType != null;
}
public static boolean isArray(Type type) {
String dimension = type.dimension();
return dimension != null && dimension.length() > 0;
}
public static Type getCollectionType(Type type, JAXDoclet<?> doclet) {
Type collectionType = Utils.findSuperType(type, "java.util.Collection");
// FIXME: this is dodgy at best
if (collectionType != null) {
ParameterizedType parameterizedType = type.asParameterizedType();
Type[] types = parameterizedType == null ? null : parameterizedType.typeArguments();
if (types != null && types.length == 1)
return types[0];
return doclet.forName("java.lang.Object");
}
return type;
}
@SuppressWarnings("deprecation")
public static Type resolveType(String typeName, ClassDoc klass, JAXDoclet<?> doclet) {
log("resolving " + typeName + " in " + klass.qualifiedTypeName());
// first look in inner classes
for (ClassDoc innerClass : klass.innerClasses(false)) {
if (innerClass.simpleTypeName().equals(typeName))
return innerClass;
}
// then the class itself
if (klass.typeName().equals(typeName))
return klass;
try {
// then go through the named imports
for (ClassDoc importedClass : klass.importedClasses()) {
if (importedClass.typeName().equals(typeName))
return importedClass;
}
// then the package imports
for (PackageDoc importedPackage : klass.importedPackages()) {
for (ClassDoc importedClass : importedPackage.allClasses(false)) {
if (importedClass.typeName().equals(typeName))
return importedClass;
}
}
} catch (NullPointerException e) {
}
// now try FQDN
Type type = doclet.forName(typeName);
if (type != null)
return type;
log("resolving failed for " + typeName + " in " + klass.qualifiedTypeName());
return null;
}
public static JaxType parseType(String typeName, ClassDoc containingClass, JAXDoclet<?> doclet) throws InvalidJaxTypeException {
typeName = typeName.trim();
char[] chars = typeName.toCharArray();
Stack<JaxType> types = new Stack<JaxType>();
JaxType currentType = new JaxType();
types.push(currentType);
StringBuffer currentTypeName = new StringBuffer();
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
log("Looking at char " + c);
if (c == '<') {
log("Start params for " + currentTypeName);
// we're done for the type name
setupType(currentType, currentTypeName, containingClass, doclet);
// add a parameter to the current type
JaxType parameterType = new JaxType();
currentType.parameters.add(parameterType);
currentType = parameterType;
// prepare for the parameter type
types.push(currentType);
} else if (c == '>') {
// we're done for the parameter type
if (currentTypeName.length() > 0)
setupType(currentType, currentTypeName, containingClass, doclet);
// reset and pop
types.pop();
currentType = types.peek();
log("End params for " + currentType.typeName);
// we should have at least the top type
if (types.size() < 1)
throw new InvalidJaxTypeException();
} else if (c == ',') {
// we're done for the parameter type, unless it was already done by
// closing its parameter list
if (currentTypeName.length() > 0) {
setupType(currentType, currentTypeName, containingClass, doclet);
// reset, pop
types.pop();
currentType = types.peek();
}
log("Next params for " + currentType.typeName);
// we should have at least the top type
if (types.size() < 1)
throw new InvalidJaxTypeException();
// add a parameter to the current type
JaxType parameterType = new JaxType();
currentType.parameters.add(parameterType);
currentType = parameterType;
// prepare for the parameter type
types.push(currentType);
} else if (c == '[' || c == ']') {
log("Dimension for " + currentType.typeName);
// done for the class name unless it was already done by
// closing its parameter list
if (currentTypeName.length() > 0) {
setupType(currentType, currentTypeName, containingClass, doclet);
}
// FIXME: check dimension correctness
currentType.dimension += c;
} else {
log("Name char: " + currentTypeName);
// if the currentType already has a name, barf
if (currentType.typeName != null)
throw new InvalidJaxTypeException();
currentTypeName.append(c);
}
}
// perhaps we didn't have any parameters or dimension
if (currentTypeName.length() > 0) {
log("End of type without param or dimension for " + currentTypeName);
setupType(currentType, currentTypeName, containingClass, doclet);
}
// we should have the original type to return
if (types.size() != 1)
throw new InvalidJaxTypeException();
return currentType;
}
public static String removeFragmentRegexes(String fragment, Map<String, String> regexFragments) {
Pattern regexPattern = Pattern.compile("\\{(\\w[\\w\\.-]*)\\s*:");
Matcher regexMatcher = regexPattern.matcher(fragment);
int start = 0;
char[] fragmentArray = fragment.toCharArray();
StringBuffer strbuf = new StringBuffer();
while (regexMatcher.find(start)) {
strbuf.append(fragment.substring(start, regexMatcher.start()));
String name = regexMatcher.group(1);
strbuf.append("{").append(name);
// now move on until after the last "}"
int openBraces = 1;
start = regexMatcher.end();
while (start < fragmentArray.length) {
char c = fragmentArray[start++];
if (c == '{')
openBraces++;
else if (c == '}') {
openBraces--;
if (openBraces == 0)
break;
}
}
if (openBraces > 0)
throw new RuntimeException("Invalid Path fragment: " + fragment);
String regex = fragment.substring(regexMatcher.end(), start - 1);
if (regexFragments != null)
regexFragments.put(name, regex);
strbuf.append("}");
}
// add all that remains
strbuf.append(fragment.substring(start, fragmentArray.length));
return strbuf.toString();
}
@SuppressWarnings("serial")
public static class InvalidJaxTypeException extends Exception {}
private static void setupType(JaxType currentType, StringBuffer currentTypeName, ClassDoc containingClass, JAXDoclet<?> doclet)
throws InvalidJaxTypeException {
if (currentTypeName.length() == 0) {
throw new InvalidJaxTypeException();
}
currentType.typeName = currentTypeName.toString();
currentType.type = resolveType(currentType.typeName, containingClass, doclet);
currentTypeName.setLength(0);
}
public static class JaxType {
String typeName;
Type type;
List<JaxType> parameters = new LinkedList<JaxType>();
String dimension = "";
public String getDimension() {
return dimension;
}
public String getTypeName() {
return typeName;
}
public Type getType() {
return type;
}
public List<JaxType> getParameters() {
return parameters;
}
public boolean hasParameters() {
return !parameters.isEmpty();
}
}
private static String addContextPath(JAXConfiguration config, String resource) {
// FIXME: move this to JAXRSConfiguration
String jaxrscontext = getOption(config.parentConfiguration.root.options(), "-jaxrscontext");
if (jaxrscontext == null) {
return appendURLFragments("/", resource);
} else {
return appendURLFragments(jaxrscontext, resource);
}
}
public static String getDisplayURL(DocletWriter writer, Resource resource, ResourceMethod method) {
return addContextPath(writer.getConfiguration(), method.getURL(resource));
}
public static String getAbsolutePath(DocletWriter writer, Resource resource) {
return addContextPath(writer.getConfiguration(), resource.getAbsolutePath());
}
public static String getAbsolutePath(JAXConfiguration config, Resource resource) {
return addContextPath(config, resource.getAbsolutePath());
}
public static void log(String mesg) {
// System.err.println(mesg);
}
private static boolean isExcluded(Doc doc) {
return doc.tags("exclude").length != 0;
}
}