/*
 * Copyright 2010 Lincoln Baxter, III
 *
 * 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 org.ocpsoft.rewrite.annotation.config;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.servlet.ServletContext;

import org.ocpsoft.common.services.ServiceLoader;
import org.ocpsoft.logging.Logger;
import org.ocpsoft.rewrite.annotation.ClassVisitorImpl;
import org.ocpsoft.rewrite.annotation.scan.ByteCodeFilter;
import org.ocpsoft.rewrite.annotation.scan.PackageFilter;
import org.ocpsoft.rewrite.annotation.scan.WebClassesFinder;
import org.ocpsoft.rewrite.annotation.scan.WebLibFinder;
import org.ocpsoft.rewrite.annotation.spi.AnnotationHandler;
import org.ocpsoft.rewrite.annotation.spi.ClassFinder;
import org.ocpsoft.rewrite.config.Configuration;
import org.ocpsoft.rewrite.servlet.config.HttpConfigurationProvider;

public class AnnotationConfigProvider extends HttpConfigurationProvider
{
   private final Logger log = Logger.getLogger(AnnotationConfigProvider.class);

   public static final String CONFIG_SCAN_LIB_DIR = "com.ocpsoft.pretty.SCAN_LIB_DIRECTORY";
   public static final String CONFIG_BASE_PACKAGES = "com.ocpsoft.pretty.BASE_PACKAGES";

   @Override
   public int priority()
   {
      return 0;
   }

   @Override
   public Configuration getConfiguration(ServletContext servletContext)
   {

      /*
       * ======================================================
       * ============[ Configuration parameters ]==============
       * ======================================================
       */

      // retrieve the optional package filter configuration parameter
      String packageFilters = servletContext.getInitParameter(CONFIG_BASE_PACKAGES);

      // does the user want to scan the WEB-INF/lib directory
      boolean scanLibDir = false;
      String jarConfig = servletContext.getInitParameter(CONFIG_SCAN_LIB_DIR);
      if ((jarConfig != null) && jarConfig.trim().equalsIgnoreCase("true")) {
         scanLibDir = true;
      }

      // users can disable annotation scanning
      if ((packageFilters != null) && packageFilters.trim().equalsIgnoreCase("none")) {
         log.debug("Annotation scanning is disabled!");
         return null;
      }

      /*
       * ======================================================
       * ============[ Prepare scanning process ]==============
       * ======================================================
       */

      // the byte code filter needs to know the annotations to look for
      Set<Class<? extends Annotation>> annotationType = new HashSet<Class<? extends Annotation>>();

      // list of annotation handlers for the ClassVisitor
      List<AnnotationHandler<Annotation>> annotationHandlers = new ArrayList<AnnotationHandler<Annotation>>();

      // load the implementations of the AnnotationHandler SPI
      @SuppressWarnings("unchecked")
      Iterator<AnnotationHandler<Annotation>> handlerIterator = ServiceLoader.load(AnnotationHandler.class).iterator();
      while (handlerIterator.hasNext()) {
         AnnotationHandler<Annotation> handler = handlerIterator.next();
         annotationHandlers.add(handler);
         annotationType.add(handler.handles());
      }

      // this class will identify the classes that should be scanned without loading them
      ByteCodeFilter byteCodeFilter = new ByteCodeFilter(annotationType);

      // users can configure the annotation scanner to scan only specific packages
      PackageFilter packageFilter = new PackageFilter(packageFilters);

      // ClassVisitor will process all classes that ByteCodeFilter considers as worth scanning them
      ClassVisitorImpl classVisitor = new ClassVisitorImpl(annotationHandlers);

      // fallback to some other classloder if there is no context class loader
      ClassLoader classloader = Thread.currentThread().getContextClassLoader();
      if (classloader == null) {
         classloader = this.getClass().getClassLoader();
      }

      /*
       * ======================================================
       * =============[ Scanning process starts ]==============
       * ======================================================
       */

      // TODO this should be pulled out into a utility allowing it to run in Java SE
      // compile a list of class finders to run
      List<ClassFinder> classFinders = new ArrayList<ClassFinder>();
      classFinders.add(new WebClassesFinder(servletContext, classloader, packageFilter, byteCodeFilter));
      if (scanLibDir) {
         classFinders.add(new WebLibFinder(servletContext, classloader, packageFilter, byteCodeFilter));
      }

      // start the scanning process
      for (ClassFinder finder : classFinders) {
         finder.findClasses(classVisitor);
      }

      // return the rules collected by the class visitor
      return classVisitor;
   }

}

@@ -1664,27 +1664,27 @@
 _LIB_DIR = %22
-com
+org
 .ocpsoft.pre
@@ -1680,22 +1680,34 @@
 ocpsoft.
-p
 re
-tty
+write.annotation
 .SCAN_LI
@@ -1774,19 +1774,19 @@
 AGES = %22
-com
+org
 .ocpsoft
@@ -1790,14 +1790,26 @@
 oft.
-p
 re
-tty
+write.annotation
 .BAS

Rename package to org.ocpsoft.*