package org.mulgara.doclet;
// Java 2 standard packages
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
// Third party packages
import com.sun.javadoc.Tag; // Doclet API
import com.sun.tools.doclets.Taglet; // Taglet API
/**
* Custom taglets for the Mulgara project which reformat RCS tags placed into
* javadoc tags by the revision control system.
*
* These tags are valid in all scopes (constructors, fields, methods, overviews
* and packages) but not as inline tags.
*
* Although the interface can't enforce this, it is necessary to implement a
* <code>public static void register(Map<String, Taglet>)</code> method on each
* concrete taglet class extended from this one. The {#register} method is
* provided to simplify this.
*
* @created 2006-08-25
* @author <a href="http://staff.pisoftware.com/raboczi">Simon Raboczi</a>
* @version $Revision$
* @modified $Date$
* @maintenanceAuthor $Author$
* @copyright ©2006 <a href="http://www.mulgara.org/">Mulgara Project</a>
* @licence <a href="http://opensource.org/licenses/osl-3.0.php">Open Software License v3.0</a>
*/
public abstract class RCSTaglet implements Taglet
{
/**
* Matcher for RCS keywords.
*
* This is lazily initialized by {@link #replaceRcsKeywords}.
*/
private Matcher matcher;
/**
* @return the heading to be written into the documentation for human readers
*/
public abstract String getHeading();
//
// Methods implementing the Taglet interface
//
public abstract String getName();
/**
* @inheritDoc
*
* @return <code>true</code>
*/
public boolean inConstructor()
{
return true;
}
/**
* @inheritDoc
*
* @return <code>true</code>
*/
public boolean inField()
{
return true;
}
/**
* @inheritDoc
*
* @return <code>true</code>
*/
public boolean inMethod()
{
return false;
}
/**
* @inheritDoc
*
* @return <code>true</code>
*/
public boolean inOverview()
{
return false;
}
/**
* @inheritDoc
*
* @return <code>true</code>
*/
public boolean inPackage()
{
return false;
}
/**
* @inheritDoc
*
* @return <code>true</code>
*/
public boolean inType()
{
return true;
}
/**
* @inheritDoc
*
* @return <code>false</code>
*/
public boolean isInlineTag()
{
return false;
}
public String toString(Tag tag)
{
return "<DT><B>"
+ getHeading()
+ "</B></DT><DD>"
+ replaceRcsKeywords(tag.text())
+ "</DD>";
}
public String toString(Tag[] tags)
{
StringBuffer buffer = new StringBuffer("<DT><B>");
buffer.append(getHeading())
.append("</B></DT><DD>");
for (int i = 0; i < tags.length; i++) {
buffer.append(replaceRcsKeywords(tags[i].text()));
if (i + 1 < tags.length) {
buffer.append(", ");
}
}
buffer.append("</DD>");
return buffer.toString();
}
protected static void register(Taglet taglet, Map<String, Taglet> tagletMap)
{
assert taglet != null;
assert tagletMap != null;
if (tagletMap.containsKey(taglet.getName())) {
tagletMap.remove(taglet.getName());
}
assert !tagletMap.containsKey(taglet.getName());
tagletMap.put(taglet.getName(), taglet);
assert tagletMap.containsKey(taglet.getName());
}
//
// Internal methods
//
/**
* Leave only the value for RCS keywords.
*
* For example, <code>*Revision: 1.1 *</code> becomes <code>1.1</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.replaceAll("\\\\", "\\\\\\\\").replaceAll("\\$", "\\\\\\$"));
}
matcher.appendTail(buffer);
return buffer.toString();
}
}