package org.mulgara.doclet;
// Java 2 standard packages
import java.io.IOException;
import java.text.*;
import java.util.*;
import java.util.regex.*;
// third party packages
import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.Doc;
import com.sun.javadoc.Tag;
import com.sun.tools.doclets.ClassTree;
import com.sun.tools.doclets.DirectoryManager;
import com.sun.tools.doclets.DocletAbortException;
import com.sun.tools.doclets.standard.ClassWriter;
import com.sun.tools.doclets.standard.ConfigurationStandard;
/**
* An extended {@link ClassWriter} that adds new javadoc tags for RCS symbols.
*
* @author <a href="http://staff.pisoftware.com/raboczi">Simon Raboczi</a>
*/
public class RcsClassWriter extends ClassWriter
{
/**
* Configuration object.
*
* It's almost certain that one of the superclasses is already holding a
* copy of this, but I haven't been able to guess which one.
*/
private ConfigurationStandard configuration;
/**
* Matcher for RCS keywords.
*
* This is lazily initialized by {@link #replaceRcsKeywords}.
*/
private Matcher matcher;
/**
* Constructor.
*/
public RcsClassWriter(ConfigurationStandard configurationStandard,
String path, String filename, ClassDoc classdoc,
ClassDoc prev, ClassDoc next, ClassTree classtree,
boolean nopackage)
throws IOException
{
super(configurationStandard, path, filename, classdoc, prev, next,
classtree, nopackage);
configuration = configurationStandard;
}
/**
* Generate a class page.
*
* @param prev the previous class to generated, or null if no previous.
* @param classdoc the class to generate.
* @param next the next class to be generated, or null if no next.
*/
public static void generate(ConfigurationStandard configurationStandard,
ClassDoc classdoc, ClassDoc prev, ClassDoc next,
ClassTree classtree, boolean nopackage)
{
RcsClassWriter clsgen;
String path =
DirectoryManager.getDirectoryPath(classdoc.containingPackage());
String filename = classdoc.name() + ".html";
try {
clsgen = new RcsClassWriter(configurationStandard, path, filename,
classdoc, prev, next, classtree, nopackage);
clsgen.generateClassFile();
clsgen.close();
}
catch (IOException exc) {
configurationStandard.standardmessage.error(
"doclet.exception_encountered",
exc.toString(),
filename
);
throw new DocletAbortException();
}
}
/**
* Overrides {@link HtmlStandardWriter#generateTagInfo} to include Plugged
* In's tags.
*/
public void generateTagInfo(Doc doc)
{
Tag[] sinces = doc.tags("since");
Tag[] sees = doc.seeTags();
Tag[] authors;
Tag[] versions;
Tag[] copyrights;
Tag[] createds;
Tag[] modifieds;
Tag[] licences;
if (configuration.showauthor) {
authors = doc.tags("author");
}
else {
authors = new Tag[0];
}
if (configuration.showversion) {
versions = doc.tags("version");
}
else {
versions = new Tag[0];
}
if (configuration.nosince) {
sinces = new Tag[0];
}
copyrights = doc.tags("copyright");
createds = doc.tags("created");
licences = doc.tags("licence");
modifieds = doc.tags("modified");
if (sinces.length > 0
|| sees.length > 0
|| authors.length > 0
|| versions.length > 0
|| copyrights.length > 0
|| createds.length > 0
|| licences.length > 0
|| modifieds.length > 0
|| (doc.isClass() && ((ClassDoc)doc).isSerializable()))
{
dl();
printSinceTag(doc);
if (versions.length > 0) {
// There is going to be only one Version tag.
dt();
boldText("doclet.Version");
dd();
printInlineComment(versions[0]);
ddEnd();
}
if (authors.length > 0) {
dt();
boldText("doclet.Author");
dd();
for (int i = 0; i < authors.length; ++i) {
if (i > 0) {
print(", ");
}
printInlineComment(authors[i]);
}
ddEnd();
}
if (createds.length > 0) {
// There is going to be only one Created tag.
dt();
write("<b>Created:</b>");
dd();
printInlineComment(createds[0]);
ddEnd();
}
if (modifieds.length > 0) {
dt();
write("<b>Modified:</b>");
dd();
for (int i = 0; i < modifieds.length; ++i) {
if (i > 0) {
print(", ");
}
printInlineComment(modifieds[i]);
}
ddEnd();
}
if (copyrights.length > 0) {
dt();
write("<b>Copyright:</b>");
dd();
for (int i = 0; i < copyrights.length; ++i) {
if (i > 0) {
print(", ");
}
printInlineComment(copyrights[i]);
}
ddEnd();
}
if (licences.length > 0) {
// There is going to be only one Licence tag.
dt();
write("<b>Licence:</b>");
dd();
printInlineComment(licences[0]);
ddEnd();
}
//printSeeTags(doc); // This method vanished in 1.4 beta 3
dlEnd();
}
}
/**
* Override to include RCS keyword substitution.
*/
public void printInlineComment(Tag tag)
{
String text = tag.text();
text = replaceRcsKeywords(text);
text = replaceDocRootDir(text);
print(text);
}
/**
* Leave only the value for RCS keywords.
*
* For example, <code>$Revision: 1.1 $</code> becomes <code>1.0</code>.
*/
public String replaceRcsKeywords(String text)
{
if (matcher == null) {
matcher = Pattern.compile(
"\\$(Author|Date|Header|Id|Locker|Log|Name|RCSFile|Revision|Source|State): (.+?) \\$"
).matcher(text);
}
else {
matcher.reset(text);
}
StringBuffer buffer = new StringBuffer();
while (matcher.find()) {
String string = matcher.group(2);
// For the Date: keyword, have a shot at reformatting string
if ("Date".equals(matcher.group(1))) {
try {
DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Date date = dateFormat.parse(string);
string = date.toString();
}
catch (ParseException e) {} // if we can't parse, return unchanged
}
matcher.appendReplacement(buffer, string);
}
matcher.appendTail(buffer);
return buffer.toString();
}
}