/* *******************************************************************
* Copyright (c) 1999-2001 Xerox Corporation,
* 2002 Palo Alto Research Center, Incorporated (PARC).
* All rights reserved.
* This program and the accompanying materials are made available
* under the terms of the Eclipse Public License v1.0
* which accompanies this distribution and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Xerox/PARC initial implementation
* Mik Kersten port to AspectJ 1.1+ code base
* ******************************************************************/
package org.aspectj.tools.ajdoc;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import org.aspectj.asm.AsmManager;
import org.aspectj.asm.IProgramElement;
import org.aspectj.util.FileUtil;
/**
* @author Mik Kersten
*/
class StubFileGenerator {
static Hashtable declIDTable = null;
static void doFiles(AsmManager model, Hashtable table, File[] inputFiles, File[] signatureFiles) throws DocException {
declIDTable = table;
for (int i = 0; i < inputFiles.length; i++) {
processFile(model, inputFiles[i], signatureFiles[i]);
}
}
static void processFile(AsmManager model, File inputFile, File signatureFile) throws DocException {
try {
// Special Case for package-info.java just copy file directly.
if(signatureFile.getName().equals("package-info.java")) {
FileUtil.copyFile(inputFile, signatureFile);
return;
}
String path = StructureUtil.translateAjPathName(signatureFile.getCanonicalPath());
PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(path)));
String packageName = StructureUtil.getPackageDeclarationFromFile(model, inputFile);
if (packageName != null && packageName != "") {
writer.println("package " + packageName + ";");
}
IProgramElement fileNode = model.getHierarchy().findElementForSourceFile(inputFile.getAbsolutePath());
for (Iterator it = fileNode.getChildren().iterator(); it.hasNext();) {
IProgramElement node = (IProgramElement) it.next();
if (node.getKind().isPackageDeclaration()) {
// skip
} else if (node.getKind().equals(IProgramElement.Kind.IMPORT_REFERENCE)) {
processImportDeclaration(node, writer);
} else {
try {
processTypeDeclaration(node, writer);
} catch (DocException d) {
throw new DocException("File name invalid: " + inputFile.toString());
}
}
}
// if we got an error we don't want the contents of the file
writer.close();
} catch (IOException e) {
System.err.println(e.getMessage());
e.printStackTrace();
}
}
private static void processImportDeclaration(IProgramElement node, PrintWriter writer) throws IOException {
List imports = node.getChildren();
for (Iterator i = imports.iterator(); i.hasNext();) {
IProgramElement importNode = (IProgramElement) i.next();
writer.println(importNode.getSourceSignature());
}
}
private static void processTypeDeclaration(IProgramElement classNode, PrintWriter writer) throws DocException {
String formalComment = addDeclID(classNode, classNode.getFormalComment());
writer.println(formalComment);
String signature = genSourceSignature(classNode);// StructureUtil.genSignature(classNode);
if (signature == null) {
throw new DocException("The java file is invalid");
}
// System.err.println("######" + signature + ", " + classNode.getName());
if (!StructureUtil.isAnonymous(classNode) && !classNode.getName().equals("<undefined>")) {
writer.println(signature + " { ");
processMembers(classNode.getChildren(), writer, classNode.getKind().equals(IProgramElement.Kind.INTERFACE));
writer.println();
writer.println("}");
}
}
private static void processMembers(List/* IProgramElement */members, PrintWriter writer, boolean declaringTypeIsInterface)
throws DocException {
for (Iterator it = members.iterator(); it.hasNext();) {
IProgramElement member = (IProgramElement) it.next();
if (member.getKind().isType()) {
if (!member.getParent().getKind().equals(IProgramElement.Kind.METHOD) && !StructureUtil.isAnonymous(member)) {// don't
// print
// anonymous
// types
// System.err.println(">>>>>>>>>>>>>" + member.getName() + "<<<<" + member.getParent());
processTypeDeclaration(member, writer);
}
} else {
String formalComment = addDeclID(member, member.getFormalComment());
;
writer.println(formalComment);
String signature = "";
if (!member.getKind().equals(IProgramElement.Kind.POINTCUT)
&& !member.getKind().equals(IProgramElement.Kind.ADVICE)) {
signature = member.getSourceSignature();// StructureUtil.genSignature(member);
if (member.getKind().equals(IProgramElement.Kind.ENUM_VALUE)) {
int index = members.indexOf(member);
if ((index + 1 < members.size())
&& ((IProgramElement) members.get(index + 1)).getKind().equals(IProgramElement.Kind.ENUM_VALUE)) {
// if the next member is also an ENUM_VALUE:
signature = signature + ",";
} else {
signature = signature + ";";
}
}
}
if (member.getKind().isDeclare()) {
// System.err.println("> Skipping declare (ajdoc limitation): " + member.toLabelString());
} else if (signature != null && signature != "" && !member.getKind().isInterTypeMember()
&& !member.getKind().equals(IProgramElement.Kind.INITIALIZER) && !StructureUtil.isAnonymous(member)) {
writer.print(signature);
} else {
// System.err.println(">> skipping: " + member.getKind());
}
if (member.getKind().equals(IProgramElement.Kind.METHOD)
|| member.getKind().equals(IProgramElement.Kind.CONSTRUCTOR)) {
if (member.getParent().getKind().equals(IProgramElement.Kind.INTERFACE) || signature.indexOf("abstract ") != -1) {
writer.println(";");
} else {
writer.println(" { }");
}
} else if (member.getKind().equals(IProgramElement.Kind.FIELD)) {
// writer.println(";");
}
}
}
}
/**
* Translates "aspect" to "class", as long as its not ".aspect"
*/
private static String genSourceSignature(IProgramElement classNode) {
String signature = classNode.getSourceSignature();
if (signature != null) {
int index = signature.indexOf("aspect");
if (index == 0 || (index != -1 && signature.charAt(index - 1) != '.')) {
signature = signature.substring(0, index) + "class " + signature.substring(index + 6, signature.length());
}
}
return signature;
}
static int nextDeclID = 0;
static String addDeclID(IProgramElement decl, String formalComment) {
String declID = "" + ++nextDeclID;
declIDTable.put(declID, decl);
return addToFormal(formalComment, Config.DECL_ID_STRING + declID + Config.DECL_ID_TERMINATOR);
}
/**
* We want to go: just before the first period just before the first @ just before the end of the comment
*
* Adds a place holder for the period ('#') if one will need to be replaced.
*/
static String addToFormal(String formalComment, String string) {
if (string == null || string.equals("")) {
return formalComment;
}
// boolean appendPeriod = true;
if ((formalComment == null) || formalComment.equals("")) {
// formalComment = "/**\n * . \n */\n";
formalComment = "/**\n * \n */\n";
// appendPeriod = false;
}
formalComment = formalComment.trim();
int atsignPos = formalComment.indexOf('@');
int endPos = formalComment.indexOf("*/");
int periodPos = formalComment.indexOf("/**");
int position = 0;
String periodPlaceHolder = "";
if (periodPos != -1) {
position = periodPos + 3;// length of "/**"
} else if (atsignPos != -1) {
string = string + "\n * ";
position = atsignPos;
} else if (endPos != -1) {
string = "* " + string + "\n";
position = endPos;
} else {
// !!! perhaps this error should not be silent
throw new Error("Failed to append to formal comment for comment: " + formalComment);
}
return formalComment.substring(0, position) + periodPlaceHolder + string + formalComment.substring(position);
}
}