XmlDocConsumer.java :  » Database-ORM » sqlc » biz » hammurapi » codegen » Java Open Source

Java Open Source » Database ORM » sqlc 
sqlc » biz » hammurapi » codegen » XmlDocConsumer.java
/*
 * sqlc 1
 * SQL Compiler 
 * Copyright (C) 2003  Hammurapi Group
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * URL: http://www.hammurapi.biz/products/sqlc/index.html
 * e-Mail: support@hammurapi.biz
 */
package biz.hammurapi.codegen;

import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;

import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.generic.ClassGen;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import biz.hammurapi.codegen.JavaLexer;
import biz.hammurapi.codegen.JavaRecognizer;
import biz.hammurapi.codegen.JavaTokenTypes;

import antlr.RecognitionException;
import antlr.TokenStreamException;
import antlr.collections.AST;
import biz.hammurapi.xml.dom.DOMUtils;


/**
 * Stores generated class files in a specified directory and creates HTML documenation. 
 * @author Pavel Vlasov
 * @version $Revision: 1.4 $
 */
public class XmlDocConsumer implements DocumentingConsumer {
  private File classDir;
  private File docDir;
  private Document indexDocument;
  private Element indexRoot;
  
  final Map documentMap=new HashMap();    
  
  /**
   * Construcotor
   * @param classDir Output directory for generated classes. Mandatory.
   * @param docDir Output directory for HTML documentation. Optional (can be null).
   * @param indexName Name of index file.
   * @throws GenerationException
   */
  public XmlDocConsumer(File classDir, File docDir, String indexName) throws GenerationException {
    if (classDir==null) {
      throw new GenerationException("Class directory is null");
    }
    if (!classDir.isDirectory()) {
      throw new GenerationException(classDir.getAbsolutePath()+" is not a directory");
    }
    if (docDir!=null && !docDir.isDirectory()) {
      throw new GenerationException(docDir.getAbsolutePath()+" is not a directory");
    }
    this.classDir=classDir;
    this.docDir=docDir;
    this.indexName=indexName;
    
    if (docDir!=null) {
      indexDocument=newDocument();
      indexRoot=indexDocument.createElement("classes");
      indexDocument.appendChild(indexRoot);
    }
  }
  
  /**
   * @throws GenerationException
   */
  private Document newDocument() {
    try {
      return DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
    } catch (ParserConfigurationException e) {
      throw new DocumentingException("Cannot create index document: "+e, e);
    } catch (FactoryConfigurationError e) {
      throw new DocumentingException("Cannot create index document: "+e, e);
    }
  }

  private GenerationListener listener;
  private String indexName;  

  /**
   * Writes file to disk and also adds it to documentation
   * @param javaClass Class to save and document
   * @throws GenerationException If generated file could not be saved
   */
  public void consume(JavaClass javaClass) throws GenerationException {
    try {
      javaClass.dump(new File(classDir, javaClass.getClassName().replace('.', File.separatorChar)+".class"));
    } catch (IOException e) {
      throw new GenerationException("Cannot save generated file: "+e, e);
    }      
  }

  private void saveDocument(String className) {
    Node classRoot = (Node) documentMap.get(className);
    if (classRoot!=null) {
      try {
        Iterator it=documentMap.keySet().iterator();
        while (it.hasNext()) {
          Element ref=classRoot.getOwnerDocument().createElement("ref");
          classRoot.appendChild(ref);
          ref.appendChild(ref.getOwnerDocument().createTextNode((String) it.next()));
        }
        File file = new File(docDir, className.replace('.', File.separatorChar)+".xml");
        file.getParentFile().mkdirs();
        DOMUtils.serialize(classRoot.getOwnerDocument(), file);
        indexRoot.appendChild(indexDocument.importNode(classRoot, true));                  
      } catch (IOException e) {
        throw new DocumentingException("Cannot save documentation for class "+className+": "+e, e);        
      } catch (TransformerException e) {
        throw new DocumentingException("Cannot save documentation for class "+className+": "+e, e);        
      }
    }
  }

  /**
   * @return Generation listener which documents methods and classes
   */
  public GenerationListener getListener() {
    if (listener==null && docDir!=null) {
       listener = new GenerationListener() {

        public void onClass(ClassGen classGen, String description) {
          String className=classGen.getClassName();
          int idx=className.lastIndexOf('.');
          String pkg = className.substring(0, idx);
          
          Document classDocument=newDocument();
          Element classRoot=classDocument.createElement("class");
          classRoot.setAttribute("fcn", className);
          classDocument.appendChild(classRoot);
          if (idx==-1) {
            classRoot.setAttribute("name", className);            
          } else {
            classRoot.setAttribute("package", pkg);
            StringBuffer sb=new StringBuffer("..");
            for (int i=pkg.indexOf('.'); i!=-1; i=pkg.indexOf(".", i+1)) {
              sb.append("/..");
            }
            classRoot.setAttribute("upPath", sb.toString());
            classRoot.setAttribute("name", className.substring(idx+1));
          }
          if (description!=null) {
            classRoot.setAttribute("description", description);
          }
          
          if (classGen.isInterface()) {
            classRoot.setAttribute("interface", "yes");
          }
          
          String superclass = classGen.getSuperclassName();
          if (superclass!=null) {
            addSuper(classRoot, "extends", superclass);            
          }
          
          String[] interfaces = classGen.getInterfaceNames();
          for (int i=0; i<interfaces.length; i++) {
            addSuper(classRoot, "implements", interfaces[i]);
          }
          
          documentMap.put(className, classRoot);
        }

        private void addSuper(Element classRoot, String elementName, String className) {                    
          Element classElement=classRoot.getOwnerDocument().createElement(elementName);
          classRoot.appendChild(classElement);
          classElement.setAttribute("fcn", className);
          int idx=className.lastIndexOf('.');
          String pkg = className.substring(0, idx);
          if (idx==-1) {
            classElement.setAttribute("name", className);            
          } else {
            classElement.setAttribute("package", pkg);
            classElement.setAttribute("name", className.substring(idx+1));
          }
        }

        public void onMethod(String className, String signature, String description, Properties attributes) {
          //signature="public static java.lang.Object[] getObject(int a, java.lang.Object, BigDecimal[][] b) throws abc, java.lang.Pizdec";
          Element classElement=selectClass(className);
          Document ownerDocument = classElement.getOwnerDocument();
          Element methodElement=ownerDocument.createElement("method");
          classElement.appendChild(methodElement);
          methodElement.setAttribute("signature", signature);
          if (description!=null) {
            methodElement.setAttribute("description", description);
          }
          
          try {
            JavaLexer lexer=new JavaLexer(new StringReader(signature));
            JavaRecognizer parser=new JavaRecognizer(lexer);
            //System.out.println("Parsing: "+signature);
            parser.signature();
            AST ast=parser.getAST();
            //AstUtil.dumpAll(ast, parser.getTokenNames());
            if (ast.getType()==JavaTokenTypes.MODIFIERS) {
              for (AST modifier=ast.getFirstChild(); modifier!=null; modifier=modifier.getNextSibling()) {
                Element me=ownerDocument.createElement("modifier");
                me.appendChild(ownerDocument.createTextNode(modifier.getText()));
                methodElement.appendChild(me);
              }
              ast=ast.getNextSibling();
            }
            
            Element rte=ownerDocument.createElement("return");
            methodElement.appendChild(rte);
            type(ast, rte);
            ast=ast.getNextSibling();
            methodElement.setAttribute("name", ast.getText());
            ast=ast.getNextSibling();            
            for (AST parameter=ast.getFirstChild(); parameter!=null; parameter=parameter.getNextSibling()) {
              Element pe=ownerDocument.createElement("parameter");
              methodElement.appendChild(pe);
              Element pte=ownerDocument.createElement("type");
              pe.appendChild(pte);
              type(parameter.getFirstChild().getFirstChild(), pte);
              AST nameNode = parameter.getFirstChild().getNextSibling();
              if (nameNode!=null) {
                pe.setAttribute("name", nameNode.getText());
              }
            }
            ast=ast.getNextSibling();
            if (ast!=null) {
              for (AST tc=ast.getFirstChild(); tc!=null; tc=tc.getNextSibling()) {
                Element te=ownerDocument.createElement("throws");
                type(tc, te);
                methodElement.appendChild(te);
              }              
            }            
          } catch (TokenStreamException e) {
            System.err.println("WARN: Signature could not be parsed: "+signature+" ("+e+")");
          } catch (RecognitionException e) {
            System.err.println("WARN: Signature could not be parsed: "+signature+" ("+e+")");
          }
          
          if (attributes!=null) {
            Iterator it=attributes.keySet().iterator();
            while (it.hasNext()) {
              Element attributeElement=ownerDocument.createElement("attribute");
              methodElement.appendChild(attributeElement);
              String key=(String) it.next();
              attributeElement.setAttribute("name", key);
              attributeElement.appendChild(ownerDocument.createTextNode(attributes.getProperty(key)));
            }
          }
        }

        public void onField(String className, String declaration, String description, Properties attributes) {
          Element classElement=selectClass(className);
          Document ownerDocument = classElement.getOwnerDocument();
          Element fieldElement=ownerDocument.createElement("field");
          classElement.appendChild(fieldElement);
          fieldElement.setAttribute("declaration", declaration);
          if (description!=null) {
            fieldElement.setAttribute("description", description);
          }
          
          try {
            for (AST ast=ClassGeneratorBase.field(declaration); ast!=null; ast=ast.getNextSibling()) {
              if (ast.getType()==JavaTokenTypes.VARIABLE_DEF) {
                for (AST node=ast.getFirstChild(); node!=null; node=node.getNextSibling()) {
                  switch (node.getType()) {
                    case JavaTokenTypes.MODIFIERS:
                      for (AST child=node.getFirstChild(); child!=null; child=child.getNextSibling()) {
                        Element me=ownerDocument.createElement("modifier");
                        me.appendChild(ownerDocument.createTextNode(child.getText()));
                        fieldElement.appendChild(me);
                      }
                      break;
                    case JavaTokenTypes.IDENT:
                      fieldElement.setAttribute("name", node.getText());
                      break;
                    case JavaTokenTypes.TYPE:
                      fieldElement.setAttribute("type", ClassGeneratorBase.toString(node.getFirstChild()));
                      break;
                    default:
                      System.err.println("WARN: Bad field declaration '"+declaration+"', unexpected node: "+node);
                      return;
                  }
                }              
              } else {
                System.err.println("WARN: Invalid node type "+ast.getType()+" in declaration '"+declaration+"'");
              }
            }
            
            if (attributes!=null) {
              Iterator it=attributes.keySet().iterator();
              while (it.hasNext()) {
                Element attributeElement=ownerDocument.createElement("attribute");
                fieldElement.appendChild(attributeElement);
                String key=(String) it.next();
                attributeElement.setAttribute("name", key);
                attributeElement.appendChild(ownerDocument.createTextNode(attributes.getProperty(key)));
              }
            }          
          } catch (GenerationException e) {
            System.err.println("WARN: Invalid field declaration: '"+declaration+"', exception: "+e);
          } catch (DOMException e) {
            System.err.println("WARN: Invalid field declaration: '"+declaration+"', exception: "+e);
          }                    
        }
        
        private void type(AST ast, Element rte) {
          while (ast.getType()==JavaTokenTypes.ARRAY_DECLARATOR) {
            rte.setAttribute("dimensions", rte.getAttribute("dimensions")+"[]");
            ast=ast.getFirstChild();
          }
          
          if (ast.getType()==JavaTokenTypes.DOT) {
            String pkg = toString(ast.getFirstChild());
            rte.setAttribute("package", pkg);
            String name = ast.getFirstChild().getNextSibling().getText();
            rte.setAttribute("name", name);
            rte.setAttribute("fcn", pkg+"."+name);
          } else {
            rte.setAttribute("name", ast.getText());
            rte.setAttribute("fcn", ast.getText());
          }
        }
        
        private String toString(AST node) {
          if (node.getType()==JavaTokenTypes.DOT) {
            return toString(node.getFirstChild()) + "." + toString(node.getFirstChild().getNextSibling());
          }
          
          return node.getText();
        }

        private Element selectClass(String className) {              
          return (Element) documentMap.get(className);
        }      
       };      
    }
    return listener;
  }
  
  /**
   * Closes all files. 
   *
   */
  public void close() {
    Iterator it=documentMap.keySet().iterator();
    while (it.hasNext()) {
      saveDocument((String) it.next());
    }

    if (indexDocument!=null) {
      try {
        DOMUtils.serialize(indexDocument, new File(docDir, indexName));
      } catch (IOException e) {
        throw new DocumentingException("Cannot close index.html: "+e, e);        
      } catch (TransformerException e) {
        throw new DocumentingException("Cannot close index.html: "+e, e);        
      }
    }
  }

}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.