Package org.openiaml.docs.generation

Source Code of org.openiaml.docs.generation.LoadSemanticsFromTests$OperationalSemanticsJavadocVisitor

/**
*
*/
package org.openiaml.docs.generation;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.Javadoc;
import org.eclipse.jdt.core.dom.MemberRef;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.MethodRef;
import org.eclipse.jdt.core.dom.QualifiedName;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.TagElement;
import org.eclipse.jdt.core.dom.TextElement;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.openiaml.docs.generation.semantics.ITagHandler;
import org.openiaml.docs.generation.semantics.SemanticFinder;
import org.openiaml.docs.generation.semantics.SemanticHandlerException;
import org.openiaml.docs.modeldoc.JavaClass;
import org.openiaml.docs.modeldoc.JavaElement;
import org.openiaml.docs.modeldoc.JavaMethod;
import org.openiaml.docs.modeldoc.JavadocClassReference;
import org.openiaml.docs.modeldoc.JavadocFragment;
import org.openiaml.docs.modeldoc.JavadocMethodReference;
import org.openiaml.docs.modeldoc.JavadocTagElement;
import org.openiaml.docs.modeldoc.JavadocTextElement;
import org.openiaml.docs.modeldoc.ModelDocumentation;
import org.openiaml.docs.modeldoc.ModeldocFactory;
import org.openiaml.docs.modeldoc.Reference;

/**
* @author jmwright
*
*/
public class LoadSemanticsFromTests extends DocumentationHelper implements ILoader {
 
  private File folder;
 
  private String plugin;
 
  private String packageBase;

  private DocumentationGenerator generator;
 
  public List<ITagHandler> getSemanticTagHandlers() {
    return generator.getSemanticTagHandlers();
  }
 
  /**
   * @param folder
   * @param plugin
   * @param packageBase
   * @param semanticTagHandlers
   */
  public LoadSemanticsFromTests(File folder, String plugin,
      String packageBase, DocumentationGenerator generator) {
    super();
    this.folder = folder;
    this.plugin = plugin;
    this.packageBase = packageBase;
    this. generator = generator;
  }

  /**
   * Load test case semantics.
   *
   * @param factory
   * @param root
   * @throws IOException
   */
  public void load(final ModeldocFactory factory,
      final ModelDocumentation root) throws DocumentationGenerationException {

    try {
      loadTestCaseSemantics(factory,
          root,
          folder /* folder */,
          plugin /* plugin */,
          packageBase /* starting package */);
    } catch (IOException e) {
      throw new DocumentationGenerationException(e);
    }
  }
 
  /**
   * Load test case semantics in the given directory recursively.
   *
   * @param factory
   * @param root
   * @throws IOException
   */
  protected void loadTestCaseSemantics(final ModeldocFactory factory,
      final ModelDocumentation root, File folder, String plugin, String pkg) throws IOException {
   
    if (!folder.exists())
      throw new RuntimeException(folder + " does not exist");
   
    // for every java in this folder,
    String[] files = folder.list();
    for (String file : files) {
      File inFile = new File(folder.getAbsolutePath() + File.separator + file);
      if (inFile.isDirectory()) {
        // recurse over directories
        loadTestCaseSemantics(factory, root, inFile, plugin, pkg + "." + file);
      } else if (file.endsWith(".java")) {
        // iterate over this file
        String name = file.substring(0, file.lastIndexOf(".java")); // remove extension
       
        System.out.println("Parsing '" + inFile + "'...");
       
        ASTParser parser = ASTParser.newParser(AST.JLS3);
        parser.setKind(ASTParser.K_COMPILATION_UNIT);
        char[] input = readFile(inFile);
        parser.setSource(input);
        parser.setResolveBindings(true);
        CompilationUnit cu = (CompilationUnit) parser.createAST(null);
       
        // create a new JavaClass
        JavaClass cls = factory.createJavaClass();
        cls.setPlugin(plugin);
        cls.setPackage(pkg);
        cls.setName(name);
        cls.setParent(root);
       
        cu.accept(new OperationalSemanticsJavadocVisitor(factory, root, cls, input));
      }
    }
   
  }

  /**
   * An AST visitor to iterate over Java ASTs (loaded by Eclipse)
   * and locate Javadoc comments for operational semantics.
   *
   * @author jmwright
   *
   */
  private class OperationalSemanticsJavadocVisitor extends ASTVisitor {
   
    private ModeldocFactory factory;
    private ModelDocumentation root;
    private JavaClass cls;
    private char[] input;
   
    /**
     * @param factory
     * @param root
     */
    public OperationalSemanticsJavadocVisitor(ModeldocFactory factory,
        ModelDocumentation root, JavaClass cls, char[] input) {
      super();
      this.factory = factory;
      this.root = root;
      this.cls = cls;
      this.input = input;
    }

    private List<JavadocFragment> handleTagFragment(
        List<?> fragments,
        JavaElement javaReference) throws SemanticHandlerException {
      List<JavadocFragment> result = new ArrayList<JavadocFragment>();
      for (Object o : fragments) {
        if (o instanceof TagElement) {
          TagElement tag = (TagElement) o;
          JavadocTagElement e = factory.createJavadocTagElement();
          e.setName(tag.getTagName());
         
          // recurse to create parents           
          e.getFragments().addAll(handleTagFragment(tag.fragments(), javaReference));
         
          // link up any references to model elements
          handleModelReferences(e, javaReference);
         
          result.add(e);
        } else if (o instanceof TextElement) {
          TextElement text = (TextElement) o;
          JavadocTextElement e = factory.createJavadocTextElement();
          e.setValue(text.getText());
          result.add(e);
        } else if (o instanceof MethodRef) {
          MethodRef ref = (MethodRef) o;
          JavaMethod method = getMethodFor(ref);
          if (method != null) {
            JavadocMethodReference e = factory.createJavadocMethodReference();
            e.setReference(method);
            result.add(e);
          }
        } else if (o instanceof SimpleName) {
          // assume it is a class name
          JavaClass cls = getJavaClassFor((SimpleName) o);
          if (cls != null) {
            JavadocClassReference e = factory.createJavadocClassReference();
            e.setReference(cls);
            result.add(e);
          }
        } else if (o instanceof QualifiedName) {
          // assume it is a class name (with package)
          JavaClass cls = getJavaClassFor((QualifiedName) o);
          if (cls != null) {
            JavadocClassReference e = factory.createJavadocClassReference();
            e.setReference(cls);
            result.add(e);
          }
        } else if (o instanceof MemberRef) {
          // ignore
        } else {
          throw new RuntimeException("Unknown element type '" + o.getClass() + "': '" + o + "'");
        }
      }
      return result;
   

    /**
     * Iterate over all semantic handlers in {@link LoadSemanticsFromTests#getSemanticTagHandlers()}
     * and identify potential semantic tags.
     *
     * @param e
     * @param reference
     * @throws SemanticHandlerException
     */
    protected void handleModelReferences(JavadocTagElement e, Reference reference) throws SemanticHandlerException {
      SemanticFinder finder = new SemanticFinder();
      for (ITagHandler sem : getSemanticTagHandlers()) {
        finder.findSemanticReferences(LoadSemanticsFromTests.this, root, e, reference, sem);
      }
    }

    /**
     * Find an existing JavaClass for the given name.
     * Does not create a new one.
     *
     * @param o
     * @return the class found, or null
     */
    private JavaClass getJavaClassFor(SimpleName o) {
      for (Reference r : root.getReferences()) {
        if (r instanceof JavaClass) {
          JavaClass cls = (JavaClass) r;
          if (cls.getName().equals(o.getFullyQualifiedName())) {
            // found it
            return cls;
          }
        }
      }
     
      return null;
    }

    /**
     * Find an existing JavaClass for the given name.
     * Does not create a new one.
     * Since it is a qualified name, we are also looking for packages.
     *
     * @param o
     * @return the class found, or null
     */
    private JavaClass getJavaClassFor(QualifiedName o) {
      for (Reference r : root.getReferences()) {
        if (r instanceof JavaClass) {
          JavaClass cls = (JavaClass) r;
          String qn = cls.getPackage() + "." + cls.getName();
          if (qn.equals(o.getFullyQualifiedName())) {
            // found it
            return cls;
          }
        }
      }
     
      return null;
    }
   
    /**
     * Wrap a single TagElement and get a single JavadocTagElement back.
     *
     * @param fragment
     * @return
     * @throws SemanticHandlerException
     */
    private JavadocTagElement handleTagFragment(
        TagElement fragment, JavaElement javaReference) throws SemanticHandlerException {
      List<Object> input = new ArrayList<Object>();
      input.add(fragment);
      List<JavadocFragment> result = handleTagFragment(input, javaReference);

      JavadocTagElement je = (JavadocTagElement) result.get(0);
     
      return je;
    }

    @Override
    public boolean visit(Javadoc node) {
      try {
        if (node.getParent() instanceof TypeDeclaration) {
          TypeDeclaration parent = (TypeDeclaration) node.getParent();
       
          if (parentMatches(parent, cls)) {         
            for (Object o : node.tags()) {
              TagElement tag = (TagElement) o;
              JavadocTagElement docs = handleTagFragment(tag, cls);
              cls.getJavadocs().add(docs);
            }
          }
        } else if (node.getParent() instanceof MethodDeclaration) {
          // a method
          MethodDeclaration parent = (MethodDeclaration) node.getParent();
         
          JavaMethod method = getMethodFor(parent, cls);
          if (method != null) {
            for (Object o : node.tags()) {
              TagElement tag = (TagElement) o;
              JavadocTagElement docs = handleTagFragment(tag, method);
              method.getJavadocs().add(docs);
            }
          }
         
        }
      } catch (SemanticHandlerException e) {
        throw new RuntimeException("Could not process node '" + node + "': " + e.getMessage(), e);
      }

      return super.visit(node);
    }

    /**
     * Get the JavaMethod for the given parent in the given class.
     * Create it if necessary and possible.
     * Return null if no such method can be created.
     *
     * @param ref
     * @return
     */
    private JavaMethod getMethodFor(MethodRef ref) {
      return getMethodFor(ref, cls);
    }
   
    /**
     * Get the JavaMethod for the given parent in the given class.
     * Create it if necessary and possible.
     * Return null if no such method can be created.
     *
     * @param ref
     * @return
     */
    private JavaMethod getMethodFor(MethodRef ref, JavaClass cls) {
      if (ref.getQualifier() != null) {
        if (!ref.getQualifier().equals(cls.getName()))
          return null// a different class: can never match
      }
      for (JavaMethod m : cls.getMethods()) {
        if (m.getName().equals(ref.getName().getFullyQualifiedName())) {
          // found it
          return m;
        }
      }
     
      // need to create a new one
      JavaMethod method = factory.createJavaMethod();
      method.setName( ref.getName().getFullyQualifiedName() );
      // cannot update the line count; we let {@link #getMethodFor(MethodDeclaration, JavaClass)} do this.
      // method.setLine( getLineFor(ref.getStartPosition()) );
      method.setJavaClass(cls);
      return method;   
    }
   
    /**
     * Get the JavaMethod for the given parent in the given
     * class. Create it if necessary. Return null if no such method
     * can be created.
     *
     * @param parent
     * @param cls
     * @return
     */
    private JavaMethod getMethodFor(MethodDeclaration parent,
        JavaClass cls) {
      // any existing methods?
      for (JavaMethod m : cls.getMethods()) {
        String methodName = parent.getName().getFullyQualifiedName();
        if (m.getName().equals(methodName)) {
          // update the line
          m.setLine( getLineFor(parent.getStartPosition()) );
          return m;
        }
      }
     
      // we need to make a new one
      JavaMethod method = factory.createJavaMethod();
      method.setName( parent.getName().getFullyQualifiedName() );
      method.setLine( getLineFor(parent.getStartPosition()) );
      method.setJavaClass(cls);
      return method;       
    }
   
    /**
     * Get the line number for a given position.
     *
     * @param pos
     * @return
     */
    private int getLineFor(int pos) {
      int r = 0;
      for (int i = 0; i <= pos; i++) {
        if (input[i] == '\n')
          r++;
      }
      return r;
    }

    private boolean parentMatches(TypeDeclaration parent, JavaClass cls) {
      if (parent.getParent() instanceof CompilationUnit) {
        // root element in a class
        CompilationUnit cu = (CompilationUnit) parent.getParent();
        String cuPackage = cu.getPackage().getName().getFullyQualifiedName();
        String clsPackage = cls.getPackage();
        String cuName = parent.getName().getFullyQualifiedName();
        String clsName = cls.getName();
        if (cuPackage.equals(clsPackage) && cuName.equals(clsName)) {
          // matches!
          return true;
        }
      }
      return false;
    }
   
  }
 
}
TOP

Related Classes of org.openiaml.docs.generation.LoadSemanticsFromTests$OperationalSemanticsJavadocVisitor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.