Package com.googlecode.gwt.test.internal

Source Code of com.googlecode.gwt.test.internal.ConfigurationLoader

package com.googlecode.gwt.test.internal;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;

import javassist.CtClass;
import javassist.bytecode.annotation.Annotation;
import javassist.bytecode.annotation.ClassMemberValue;
import javassist.bytecode.annotation.StringMemberValue;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.googlecode.gwt.test.exceptions.GwtTestConfigurationException;
import com.googlecode.gwt.test.exceptions.GwtTestException;
import com.googlecode.gwt.test.exceptions.GwtTestPatchException;
import com.googlecode.gwt.test.internal.ClassesScanner.ClassVisitor;
import com.googlecode.gwt.test.patchers.PatchClass;
import com.googlecode.gwt.test.utils.JavassistUtils;

/**
* Class in charge of parsing META-INF/gwt-test-utils.properties configuration files. <strong>For
* internal use only.</strong>
*
* @author Bertrand Paquet
* @author Gael Lazzari
*
*/
public final class ConfigurationLoader {

   private static final String CONFIG_FILENAME = "META-INF/gwt-test-utils.properties";
   private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurationLoader.class);

   private final Set<String> delegates;

   private final List<String> gwtModules;
   private PatcherFactory patcherFactory;
   private final Set<String> scanPackages;
   private final List<URL> srcDirectories;

   ConfigurationLoader(URL surefireBooterJarUrl) {
      this.gwtModules = new ArrayList<String>();
      this.delegates = new HashSet<String>();
      this.scanPackages = new HashSet<String>();
      this.srcDirectories = new ArrayList<URL>();

      readFiles();
      visitPatchClasses();
      processRelatedProjectSrcDirectories(surefireBooterJarUrl);
   }

   public Set<String> getDelegates() {
      return delegates;
   }

   public List<String> getGwtModules() {
      return gwtModules;
   }

   public PatcherFactory getPatcherFactory() {
      return patcherFactory;
   }

   public Set<String> getScanPackages() {
      return scanPackages;
   }

   public URL[] getSrcUrls() {
      return srcDirectories.toArray(new URL[srcDirectories.size()]);
   }

   private void addToSrcUrls(File file) {
      try {
         srcDirectories.add(file.toURI().toURL());

      } catch (Exception e) {
         // skip : should never happen
      }
   }

   /**
    * Search recursively for java source directories related to a classpathEntry which isn't a .jar
    * file. Typically, those entries would be 'target/classes' (maven) or 'bin' folder of java
    * project which the current project depends on.
    *
    * @param classpathEntry The classpath entry to look around
    * @param distance The number of super folders in the folder hierarchy to scan
    * @param currentLevel The current level in the super fold hierarchy. Starts at index 0.
    */
   private void collectEventualSourceDirectories(File classpathEntry, int distance, int currentLevel) {

      String projectRootPath = classpathEntry.getAbsolutePath();
      for (String srcDir : SrcDirectoriesHolder.SRC_DIRECTORIES) {
         StringBuilder sb = new StringBuilder(projectRootPath).append("/").append(srcDir);
         if (!srcDir.endsWith("/")) {
            sb.append("/");
         }

         File file = new File(sb.toString());

         if (file.exists()) {
            addToSrcUrls(file);
         }
      }

      if (currentLevel < distance) {
         collectEventualSourceDirectories(classpathEntry.getParentFile(), distance, ++currentLevel);
      }
   }

   private URL[] extractSrcUrlsFromBooterJar(String surefireBooterJarPath) {

      try {
         // handles spaces encoded %20 to fix
         // https://github.com/gwt-test-utils/gwt-test-utils/issues/17
         String decodedJarPath = URLDecoder.decode(surefireBooterJarPath, "utf-8");
         JarFile surefireBooterJar = new JarFile(decodedJarPath);
         Manifest mf = surefireBooterJar.getManifest();
         Attributes a = mf.getMainAttributes();

         String[] classpathEntries = a.getValue("Class-Path").split(" ");

         URL[] urls = new URL[classpathEntries.length];

         for (int i = 0; i < classpathEntries.length; i++) {
            urls[i] = new URL(classpathEntries[i]);
         }

         return urls;
      } catch (Exception e) {
         throw new GwtTestException("Error while parsing maven-surefire-plugin booter jar: "
                  + surefireBooterJarPath, e);
      }

   }

   private void process(Properties p, URL url) {
      for (Entry<Object, Object> entry : p.entrySet()) {
         String key = ((String) entry.getKey()).trim();
         String value = ((String) entry.getValue()).trim();
         if ("gwt-module".equals(value)) {
            gwtModules.add(key);
         } else if ("scan-package".equals(value)) {
            scanPackages.add(key);
         } else if ("delegate".equals(value)) {
            delegates.add(key);
         } else if ("src-directory".equals(value)) {
            processSrcDirectory(key);
         } else {
            throw new GwtTestConfigurationException("Error in '" + url.getPath()
                     + "' : unknown value '" + value + "'");
         }
      }

   }

   private void processRelatedProjectSrcDirectories(URL surefireBooterJarUrl) {

      URL[] classpathUrls = null;

      if (surefireBooterJarUrl != null) {
         classpathUrls = extractSrcUrlsFromBooterJar(surefireBooterJarUrl.getFile());
      } else {

         ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
         if (classLoader instanceof URLClassLoader) {
            classpathUrls = ((URLClassLoader) classLoader).getURLs();
         }
      }

      if (classpathUrls == null) {
         // should never happen
         throw new GwtTestConfigurationException("Unable to collect classpath entries");
      }

      for (URL classpathUrl : classpathUrls) {
         srcDirectories.add(classpathUrl);

         if (!classpathUrl.getPath().endsWith(".jar")) {
            // we are only interested in directory files from eventual referenced java project in
            // workspace
            try {
               collectEventualSourceDirectories(new File(classpathUrl.toURI()), 2, 0);
            } catch (URISyntaxException e) {
               throw new GwtTestConfigurationException(
                        "Error while getting source folder(s) related to path "
                                 + classpathUrl.getPath(), e);
            }
         }
      }

   }

   private void processSrcDirectory(String srcDir) {
      SrcDirectoriesHolder.SRC_DIRECTORIES.add(srcDir);
   }

   private void readFiles() {
      try {
         Enumeration<URL> configFiles = Thread.currentThread().getContextClassLoader().getResources(
                  CONFIG_FILENAME);
         while (configFiles.hasMoreElements()) {
            URL url = configFiles.nextElement();
            LOGGER.debug("Load config file " + url.toString());
            Properties p = new Properties();
            InputStream inputStream = url.openStream();
            p.load(inputStream);
            inputStream.close();
            process(p, url);
            LOGGER.debug("File loaded and processed " + url.toString());
         }

         if (gwtModules.size() == 0) {
            throw new GwtTestConfigurationException(
                     "No declared module. Did you forget to add your own META-INF/gwt-test-utils.properties file with a 'gwt-module' property in the test classpath?");
         }

      } catch (IOException e) {
         throw new GwtTestConfigurationException("Error while reading '" + CONFIG_FILENAME
                  + "' files", e);
      }
   }

   private void visitPatchClasses() {
      final Map<String, Set<CtClass>> patchClassMap = new HashMap<String, Set<CtClass>>();

      ClassVisitor patchClassVisitor = new ClassVisitor() {

         public void visit(CtClass ctClass) {

            try {
               if (ctClass.hasAnnotation(PatchClass.class)) {

                  Annotation annotation = JavassistUtils.getAnnotation(ctClass, PatchClass.class);

                  String classToPatchName = PatchClass.class.getName();

                  ClassMemberValue value = (ClassMemberValue) annotation.getMemberValue("value");

                  if (value != null) {
                     classToPatchName = value.getValue();
                  }

                  if (classToPatchName.equals(PatchClass.class.getName())) {
                     StringMemberValue target = (StringMemberValue) annotation.getMemberValue("target");
                     classToPatchName = (target != null) ? target.getValue() : "";
                  }

                  if (!"".equals(classToPatchName)) {
                     addPatchClass(classToPatchName, ctClass);
                  }
               }
            } catch (ClassNotFoundException e) {
               // should never happen
               throw new GwtTestPatchException(e);
            }
         }

         private void addPatchClass(String targetName, CtClass patchClass) {
            Set<CtClass> patchClasses = patchClassMap.get(targetName);
            if (patchClasses == null) {
               patchClasses = new HashSet<CtClass>();
               patchClassMap.put(targetName, patchClasses);
            }

            patchClasses.add(patchClass);

            LOGGER.debug("Add patch for class '" + targetName + "' : '" + patchClass.getName()
                     + "'");
         }

      };

      ClassesScanner.getInstance().scanPackages(patchClassVisitor, scanPackages);

      // create all patchers
      patcherFactory = new PatcherFactory(patchClassMap);
   }

}
TOP

Related Classes of com.googlecode.gwt.test.internal.ConfigurationLoader

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.