Package com.clarkparsia.empire.util.apt

Source Code of com.clarkparsia.empire.util.apt.EmpireAnnotationProcessorFactory$Collector

/*
* Copyright (c) 2009-2010 Clark & Parsia, LLC. <http://www.clarkparsia.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.clarkparsia.empire.util.apt;

import com.sun.mirror.apt.AnnotationProcessorFactory;
import com.sun.mirror.apt.AnnotationProcessor;
import com.sun.mirror.apt.AnnotationProcessorEnvironment;
import com.sun.mirror.apt.AnnotationProcessors;
import com.sun.mirror.apt.RoundCompleteListener;
import com.sun.mirror.apt.RoundCompleteEvent;

import com.sun.mirror.declaration.AnnotationTypeDeclaration;
import com.sun.mirror.declaration.Declaration;
import com.sun.mirror.declaration.ClassDeclaration;

import com.sun.mirror.util.SimpleDeclarationVisitor;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.Arrays;
import java.util.Collections;
import java.util.Properties;
import java.util.HashMap;
import java.util.Map;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import com.clarkparsia.empire.annotation.RdfsClass;
import com.complexible.common.collect.Iterables2;
import com.google.common.base.Joiner;
import com.google.common.base.Predicate;

import javax.persistence.NamedQuery;
import javax.persistence.NamedQueries;
import javax.persistence.NamedNativeQueries;
import javax.persistence.NamedNativeQuery;

/**
* <p>Implementation of an APT-based annotation processor to pull out Annotation information
* relevant to Empire, such as the classes using the {@link RdfsClass} or {@link NamedQuery} annotations. This
* information is written in Java Properties format to a file called "empire.config" in the same directory APT
* is executed from.  This file can then be put into the current dir of the application using Empire</p>
*
* @author  Michael Grove
* @since   0.1
* @version 0.7
* @see <a href="http://java.sun.com/j2se/1.5.0/docs/guide/apt/GettingStarted.html">Sun APT Docs</a>
*/
public final class EmpireAnnotationProcessorFactory implements AnnotationProcessorFactory {

  /**
   * A map of annotation class names to the fully qualified class names of classes which have the specific annotation.
   */
  private Map<String, Collection<String>> mAnnotationClassMap;

  /**
   * Create a new EmpireAnnotationProcessorFactory
   */
  public EmpireAnnotationProcessorFactory() {
    mAnnotationClassMap = new HashMap<String, Collection<String>>();
  }

  /**
   * @inheritDoc
   */
  public Collection<String> supportedOptions() {
    return Collections.emptyList();
  }

  /**
   * @inheritDoc
   */
  public Collection<String> supportedAnnotationTypes() {
    return Arrays.asList(RdfsClass.class.getName(),
               NamedQuery.class.getName(),
               NamedQueries.class.getName(),
               NamedNativeQuery.class.getName(),
               NamedNativeQueries.class.getName());
  }

  /**
   * @inheritDoc
   */
  public AnnotationProcessor getProcessorFor(final Set<AnnotationTypeDeclaration> theDeclarations,
                         final AnnotationProcessorEnvironment theEnvironment) {
    AnnotationProcessor aProcessor;

    if (theDeclarations.isEmpty()) {
      aProcessor = AnnotationProcessors.NO_OP;
    }
    else {
      aProcessor = new SimpleAnnotationProcessor(theEnvironment);
    }

    return aProcessor;
  }

  /**
   * An AnnotationProcessor which will collect all the classes with the given set of annotations and write them
   * into a Properties file when the processing is done.
   */
  private class SimpleAnnotationProcessor implements AnnotationProcessor {

    private AnnotationProcessorEnvironment mEnv;

    private SimpleAnnotationProcessor(final AnnotationProcessorEnvironment theEnv) {
      mEnv = theEnv;

      mEnv.addListener(new RoundCompleteListener() {
        public void roundComplete(final RoundCompleteEvent theEvent) {

          Properties aProps = new Properties();

          for (String aClass : mAnnotationClassMap.keySet()) {
            aProps.setProperty(aClass, Joiner.on(",").join(mAnnotationClassMap.get(aClass)));
          }

          // TODO: configure where this file is written (and what it's named) based on an APT option
          OutputStream aStream = null;
          try {
            aStream = new FileOutputStream(new File("empire.apt.config"));
            aProps.store(aStream, "Empire Config generated by APT");
          }
          catch (IOException e) {
            System.err.println("There was a failure generating Empire config using APT");

            e.printStackTrace();
          }
          finally {
            if (aStream != null) {
              try {
                aStream.flush();
                aStream.close();
              }
              catch (IOException e) {
                // oh well.
              }
            }
          }
        }
      });
    }

    /**
     * @inheritDoc
     */
    public void process() {

      for (String aClass : supportedAnnotationTypes()) {
        Collection<String> aCollection = new HashSet<String>();

        // I think APT can do this in multiple passes, so if we've already collected some information, lets
        // reuse it.
        if (mAnnotationClassMap.containsKey(aClass)) {
          aCollection = mAnnotationClassMap.get(aClass);
        }

        Iterables2.each(mEnv.getDeclarationsAnnotatedWith((AnnotationTypeDeclaration) mEnv.getTypeDeclaration(aClass)),
                new Collector(aCollection));

        mAnnotationClassMap.put(aClass, aCollection);
      }
    }
  }

  /**
   * Executable for applying a Visitor to a Declaration in order to collect the class declaration information
   */
  private class Collector implements Predicate<Declaration> {

    /**
     * The visitor that will be applied
     */
    private CollectorVisitor mVisitor;

    /**
     * Create a new Collector
     * @param theCollection the collector the visitor will append it's information to.
     */
    private Collector(final Collection<String> theCollection) {
      mVisitor = new CollectorVisitor(theCollection);
    }

    /**
     * @inheritDoc
     */
    public boolean apply(Declaration theDeclaration) {
      theDeclaration.accept(mVisitor);
      return true;
    }
  }

  /**
   * APT Visitor implementation that will inspect the class declarations with the given annotation and collect
   * the list of classes with the annotation.
   */
  private static class CollectorVisitor extends SimpleDeclarationVisitor {

    /**
     * The list of class names with the annotation
     */
    private Collection<String> mCollection;

    /**
     * Create a new CollectorVisitor
     * @param theCollection the collection to add to
     */
    private CollectorVisitor(final Collection<String> theCollection) {
      mCollection = theCollection;
    }

    /**
     * @inheritDoc
     */
    public void visitClassDeclaration(ClassDeclaration theDeclaration) {
      mCollection.add(theDeclaration.getQualifiedName());
    }
  }
}
TOP

Related Classes of com.clarkparsia.empire.util.apt.EmpireAnnotationProcessorFactory$Collector

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.