package edu.uiuc.cs.fsl.propertydocs.taglets;
import com.sun.javadoc.Tag;
import com.sun.tools.doclets.Taglet;
import edu.uiuc.cs.fsl.propertydocs.util.DefaultMap;
import edu.uiuc.cs.fsl.propertydocs.util.GenerateUrls;
import edu.uiuc.cs.fsl.propertydocs.util.PositionWrapper;
import java.io.File;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* This Taglet handles to opening of Description text comments
*
* @author Patrick Meredith
*
*/
public class DescriptionOpenTaglet implements Taglet {
private static final String NAME = "description.open";
private static final String dir = System.getProperty( "outputpath" );
private File stats = new File(dir + File.separator + "__properties" + File.separator + "description.stats");
private final String GLOBAL = "<global>";
private Set<PositionWrapper> seenDocs = new HashSet<PositionWrapper>();
private Map<String, Integer> statsDB = new DefaultMap<String, Integer>(0);
// private int chars = 0; //number of description chars
// private int words = 0; //number of description words
// private int lines = 0; //number of description lines
public String getName() { return NAME; }
/** can be used in a field comment*/
public boolean inField() { return true; }
/**can be used in a constructor comment*/
public boolean inConstructor() { return true; }
/**can be used in a method comment*/
public boolean inMethod() { return true; }
/**can be used in overview comment*/
public boolean inOverview() { return true; }
/**can be used in package comment*/
public boolean inPackage() { return true; }
/**can be used in type comment (classes or interfaces)*/
public boolean inType() { return true; }
/**this IS an inline tag*/
public boolean isInlineTag() { return true; }
/**
* Register this Taglet.
* @param tagletMap the map to register this tag to.
*/
@SuppressWarnings("unchecked")
public static void register(Map tagletMap) {
DescriptionOpenTaglet tag = new DescriptionOpenTaglet();
Taglet t = (Taglet) tagletMap.get(tag.getName());
if (t != null) {
tagletMap.remove(tag.getName());
}
tagletMap.put(tag.getName(), tag);
}
/**
* Given the <code>Tag</code> representation of this custom
* tag, return its string representation.
*
* Here we have to do some annoying garbage because you there is no
* way short of file io to share info between Taglets. Instead
* I am going to parse all the inline tags if the whole document
* and collect statistics on <b>all</b> the description sections in the
* document.
*
* Statistics will only be collected if we have not already seen an
* description.open tag for this document. We keep track of the document
* by hashing its SourcePosition. The PositionWrapper makes these
* hashable.
*
* @param tag he <code>Tag</code> representation of this custom tag.
*/
public String toString(Tag tag) {
PositionWrapper p = new PositionWrapper(tag.holder().position());
if(!(seenDocs.contains(p))){
seenDocs.add(p);
handleTags(tag);
}
// This part is always executed, but for description we simply return the
// empty String. For other tags we will output fancy html/javascript
return "<DIV CLASS=\"TableHeadingColor\" NAME=\"description\""
+" ONMOUSEOVER=\"balloon.showTooltip(event,'This is description text.')\""
+" STYLE=\"display:inline\">";
}
private void handleTags(Tag t){
Tag[] tags = t.holder().inlineTags();
boolean inDescription = false;
//not sure if trim() is necessary. I doubt it is, but speed isn't
//an issue here
String packageName = GenerateUrls.getPackageDoc(t).toString().trim();
// int c = 0; //character count
int w = 0; //word count
// int l = 0; //line count
for(Tag tag : tags){
if(tag.name().equals("@description.open")){
inDescription = true;
}
else if(tag.name().equals("@description.close")){
inDescription = false;
}
else if(tag.name().equals("Text") && inDescription){
String text = tag.text().trim();
if(text.length() == 0) continue;
w += text.split("\\s+").length;
}
else if(
(tag.name().equals("@property.close")
|| tag.name().equals("@property.open")
|| tag.name().equals("@inheritDoc")) && inDescription){
System.err.println("ERROR: " + tag.name() + " inside description environment in comment near "
+ tag.holder().position() + " is not allowed");
System.exit(1);
}
}
if(inDescription) {
System.err.println("ERROR: @description.open tag in comment near "
+ tags[0].holder().position() + " was not closed");
System.exit(1);
}
Integer globalWords = statsDB.get(GLOBAL);
Integer packageWords = statsDB.get(packageName);
statsDB.put(GLOBAL, globalWords + w);
statsDB.put(packageName, packageWords + w);
//System.out.println("!!!!!!!!" + statsDB);
try {
FileOutputStream fos = new FileOutputStream(stats);
ObjectOutputStream ps = new ObjectOutputStream(fos);
ps.writeObject(statsDB);
ps.close();
} catch (java.io.IOException e){
throw new RuntimeException(e);
}
}
/**
* This method should not be called since arrays of inline tags do not
* exist. Method {@link #toString(Tag)} should be used to convert this
* inline tag to a string.
* @param tags the array of <code>Tag</code>s representing of this custom tag.
*/
public String toString(Tag[] tags) {
return null;
}
}