Commits

Karsten Schmidt committed d36e5b8

initial check in of TextileDoclet and Eclipse project files

  • Participants

Comments (0)

Files changed (7)

+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
+syntax: glob
+
+.DS_Store
+
+bin
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>textile-doclet</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>

File .settings/org.eclipse.jdt.core.prefs

+#Fri Dec 05 03:59:01 GMT 2008
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.5

File .settings/org.eclipse.jdt.ui.prefs

+#Sun Jun 28 19:28:27 BST 2009
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+internal.default.compliance=default
+sp_cleanup.add_default_serial_version_id=true
+sp_cleanup.add_generated_serial_version_id=false
+sp_cleanup.add_missing_annotations=true
+sp_cleanup.add_missing_deprecated_annotations=true
+sp_cleanup.add_missing_methods=false
+sp_cleanup.add_missing_nls_tags=false
+sp_cleanup.add_missing_override_annotations=false
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=false
+sp_cleanup.always_use_this_for_non_static_field_access=false
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=true
+sp_cleanup.format_source_code=true
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.make_local_variable_final=false
+sp_cleanup.make_parameters_final=false
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=true
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_trailing_whitespaces=true
+sp_cleanup.remove_trailing_whitespaces_all=true
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
+sp_cleanup.remove_unnecessary_casts=true
+sp_cleanup.remove_unnecessary_nls_tags=false
+sp_cleanup.remove_unused_imports=true
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=true
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=true
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=true
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_blocks=true
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=false
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+sp_cleanup.use_this_for_non_static_method_access=false
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true

File src/com/postspectacular/doclet/FileUtils.java

+package com.postspectacular.doclet;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.GZIPOutputStream;
+
+public class FileUtils {
+
+	static public void createDirectories(File file) {
+		try {
+			String parentName = file.getParent();
+			if (parentName != null) {
+				File parent = new File(parentName);
+				if (!parent.exists()) {
+					parent.mkdirs();
+				}
+			}
+		} catch (SecurityException se) {
+			System.err.println("No permissions to create "
+					+ file.getAbsolutePath());
+		}
+	}
+
+	static public InputStream createInputStream(File file) throws IOException {
+		if (file == null) {
+			throw new IllegalArgumentException("file can't be null");
+		}
+		InputStream stream = new FileInputStream(file);
+		if (file.getName().toLowerCase().endsWith(".gz")) {
+			stream = new GZIPInputStream(stream);
+		}
+		return stream;
+	}
+
+	static public OutputStream createOutputStream(File file) throws IOException {
+		if (file == null) {
+			throw new IllegalArgumentException("file can't be null");
+		}
+		createDirectories(file);
+		OutputStream stream = new FileOutputStream(file);
+		if (file.getName().toLowerCase().endsWith(".gz")) {
+			stream = new GZIPOutputStream(stream);
+		}
+		return stream;
+	}
+
+	public static BufferedReader createReader(File file) throws IOException {
+		return createReader(createInputStream(file));
+	}
+
+	public static BufferedReader createReader(InputStream input) {
+		return createReader(input, "UTF-8");
+	}
+
+	public static BufferedReader createReader(InputStream input, String encoding) {
+		InputStreamReader isr = null;
+		try {
+			isr = new InputStreamReader(input, encoding);
+		} catch (UnsupportedEncodingException e) {
+		}
+		return new BufferedReader(isr);
+	}
+
+	public static PrintWriter createWriter(File file) throws IOException {
+		return createWriter(createOutputStream(file));
+	}
+
+	public static PrintWriter createWriter(OutputStream out) {
+		return createWriter(out, "UTF-8");
+	}
+
+	public static PrintWriter createWriter(OutputStream out, String encoding) {
+		OutputStreamWriter w = null;
+		try {
+			w = new OutputStreamWriter(out, encoding);
+		} catch (UnsupportedEncodingException e) {
+		}
+		return new PrintWriter(w);
+	}
+
+	static public byte[] loadBytes(InputStream stream) throws IOException {
+		BufferedInputStream input = new BufferedInputStream(stream);
+		ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+		int c;
+		while ((c = input.read()) != -1) {
+			buffer.write(c);
+		}
+		return buffer.toByteArray();
+	}
+
+	public static String loadText(BufferedReader r) throws IOException {
+		StringBuilder result = new StringBuilder();
+		String line;
+		while ((line = r.readLine()) != null) {
+			result.append(line).append("\n");
+		}
+		return result.toString();
+	}
+
+	public static String loadText(InputStream input) throws IOException {
+		return loadText(input, "UTF-8");
+	}
+
+	public static String loadText(InputStream input, String encoding)
+			throws IOException {
+		byte[] raw = loadBytes(input);
+		return new String(raw, encoding);
+	}
+
+	static public void saveText(OutputStream output, String string) {
+		saveText(createWriter(output), string);
+	}
+
+	static public void saveText(PrintWriter writer, String string) {
+		writer.println(string);
+		writer.flush();
+		writer.close();
+	}
+}

File src/com/postspectacular/doclet/TextileDoclet.java

+package com.postspectacular.doclet;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import com.sun.javadoc.ClassDoc;
+import com.sun.javadoc.Doclet;
+import com.sun.javadoc.ExecutableMemberDoc;
+import com.sun.javadoc.MethodDoc;
+import com.sun.javadoc.PackageDoc;
+import com.sun.javadoc.ParamTag;
+import com.sun.javadoc.Parameter;
+import com.sun.javadoc.RootDoc;
+import com.sun.javadoc.SeeTag;
+import com.sun.javadoc.Tag;
+import com.sun.javadoc.Type;
+
+/**
+ * This custom doclet generates Javadocs in Textile markup. Textile is supported
+ * by popular wiki engines (e.g. Confluence) and as well is suitable for later
+ * translation into a number of other formats (e.g. Docbook, XHTML etc.). All
+ * generated files are stored as flat hierarchy in the specified target
+ * directory and are named as their corresponding qualified java types.
+ * 
+ * @author Karsten Schmidt
+ */
+public class TextileDoclet extends Doclet {
+
+	private static final String JAVA_API_URL = "http://download.oracle.com/javase/6/docs/api/";
+
+	private static String getOption(RootDoc root, String option) {
+		for (String[] o : root.options()) {
+			if (o[0].equals(option)) {
+				return o[1];
+			}
+		}
+		return null;
+	}
+
+	public static int optionLength(String option) {
+		if (option.equals("-d")) {
+			return 2;
+		}
+		if (option.equals("-module")) {
+			return 2;
+		}
+		return 0;
+	}
+
+	public static boolean start(RootDoc root) {
+		String targetDir = getOption(root, "-d");
+		String moduleName = getOption(root, "-module");
+		TextileDoclet doclet = new TextileDoclet(root);
+		doclet.setTargetDir(targetDir);
+		doclet.setModuleName(moduleName);
+		doclet.buildPackagePage();
+		doclet.buildClassPages();
+		return true;
+	}
+
+	private final RootDoc root;
+
+	private String targetDir;
+
+	private String moduleName;
+
+	public TextileDoclet(RootDoc root) {
+		this.root = root;
+	}
+
+	private void buildClassPages() {
+		for (ClassDoc cd : root.classes()) {
+			StringBuffer buf = new StringBuffer();
+			buf.append("h1. ").append(cd.qualifiedName()).append("\n\n");
+			buf.append(parseComment(cd.inlineTags())).append("\n\n");
+			buf.append("h2. Constructors\n\n");
+			buf.append(parseMembers(cd.constructors())).append("\n\n");
+			buf.append("h2. Methods\n\n");
+			buf.append(parseMembers(cd.methods())).append("\n\n");
+			writeFile(cd.qualifiedName() + ".textile", buf.toString());
+		}
+	}
+
+	private void buildPackageClassesPage(PackageDoc pdoc) {
+		StringBuffer buf = new StringBuffer();
+		buf.append("h1. ").append(pdoc.name()).append("\n\n");
+		String comment = parseComment(pdoc.inlineTags());
+		if (comment.length() > 0) {
+			buf.append(comment).append("\n\n");
+		}
+		buf.append("h2. Package overview\n\n");
+		List<ClassDoc> classes = Arrays.asList(pdoc.allClasses(true));
+		Collections.sort(classes, new Comparator<ClassDoc>() {
+			public int compare(ClassDoc a, ClassDoc b) {
+				return a.name().compareTo(b.name());
+			}
+		});
+		for (ClassDoc cd : classes) {
+			buf.append("* [").append(cd.name()).append('|')
+					.append(cd.qualifiedName()).append("]\n");
+		}
+		writeFile(pdoc.name() + ".textile", buf.toString());
+	}
+
+	private void buildPackagePage() {
+		StringBuffer buf = new StringBuffer();
+		buf.append("h1. ").append(moduleName).append("\n\n");
+		// TODO add module description from ???
+		buf.append("h2. List of packages in this module\n\n");
+		for (PackageDoc p : root.specifiedPackages()) {
+			if (p.allClasses().length > 0) {
+				buf.append("h3. [").append(p.name()).append("]\n\n");
+				String comment = parseComment(p.inlineTags());
+				if (comment.length() > 0) {
+					buf.append(comment).append("\n\n");
+				}
+				buildPackageClassesPage(p);
+			}
+		}
+		writeFile(moduleName + ".textile", buf.toString());
+	}
+
+	private String buildTypeLink(Type type) {
+		if (type.isPrimitive()) {
+			return type.simpleTypeName();
+		} else {
+			if (type.qualifiedTypeName().startsWith("java")) {
+				return "[" + type.simpleTypeName() + "|" + JAVA_API_URL
+						+ type.qualifiedTypeName().replaceAll("\\.", "/")
+						+ ".html]";
+			} else {
+				return "[" + type.simpleTypeName() + "|"
+						+ type.qualifiedTypeName() + "]";
+			}
+		}
+	}
+
+	private String parseComment(Tag[] tags) {
+		StringBuffer buf = new StringBuffer();
+		for (Tag t : tags) {
+			String type = t.name();
+			if (type.equalsIgnoreCase("text")) {
+				buf.append(t.text());
+			} else if (type.equalsIgnoreCase("@link")) {
+				SeeTag st = (SeeTag) t;
+				buf.append('[');
+				if (st.label() != null && st.label().length() > 0) {
+					buf.append(st.label()).append('|');
+				}
+				buf.append(st.referencedClassName());
+				if (st.referencedMemberName() != null) {
+					buf.append('#').append(st.referencedMemberName());
+				}
+				buf.append("]");
+			}
+			// TODO support other tags like @see, etc.
+		}
+		String comment = buf.toString().replaceAll("\n", "");
+		comment = comment.replaceAll("\\<.*?\\>", "");
+		return comment;
+	}
+
+	private String parseMembers(ExecutableMemberDoc[] mems) {
+		StringBuffer buf = new StringBuffer();
+		for (ExecutableMemberDoc m : mems) {
+			ParamTag[] params = m.paramTags();
+			if (m instanceof MethodDoc) {
+				MethodDoc md = (MethodDoc) m;
+				buf.append("{anchor:").append(md.name())
+						.append(md.flatSignature()).append("}\n");
+			}
+			buf.append("h3. " + m.qualifiedName());
+			buf.append('(');
+			for (int i = 0, nump = m.parameters().length; i < nump; i++) {
+				Parameter p = m.parameters()[i];
+				buf.append(buildTypeLink(p.type())).append(" ")
+						.append(p.name());
+				if (i < nump - 1) {
+					buf.append(", ");
+				}
+			}
+			buf.append(")\n\n");
+			String comment = parseComment(m.inlineTags());
+			if (comment.length() > 0) {
+				buf.append(comment).append("\n\n");
+			}
+			for (ParamTag p : params) {
+				buf.append(
+						"* *" + p.parameterName() + "*: "
+								+ p.parameterComment()).append("\n");
+			}
+			if (m instanceof MethodDoc) {
+				MethodDoc md = (MethodDoc) m;
+				buf.append("\n*Returns:* ")
+						.append(md.returnType().qualifiedTypeName())
+						.append("\n");
+			}
+			buf.append("\n");
+		}
+		return buf.toString();
+	}
+
+	public void setModuleName(String moduleName) {
+		this.moduleName = moduleName;
+	}
+
+	public void setTargetDir(String targetDir) {
+		this.targetDir = targetDir;
+	}
+
+	private void writeFile(String fileName, String buf) {
+		try {
+			File path = new File(targetDir + "/" + fileName);
+			System.out.println("writing: " + path.getAbsolutePath());
+			PrintWriter writer = FileUtils.createWriter(path);
+			FileUtils.saveText(writer, buf);
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+	}
+}