/**
  * Indicates if a class is recompilable. Recompilable means, that the classloader will try to
  * locate a groovy source file for this class and then compile it again, adding the resulting
  * class as entry to the cache. Giving null as class is like a recompilation, so the method should
  * always return true here. Only classes that are implementing GroovyObject are compilable and
  * only if the timestamp in the class is lower than Long.MAX_VALUE.
  *
  * <p>NOTE: First the parent loaders will be asked and only if they don't return a class the
  * recompilation will happen. Recompilation also only happen if the source file is newer.
  *
  * @param cls the class to be tested. If null the method should return true
  * @return true if the class should be compiled again
  * @see #isSourceNewer(URL, Class)
  */
 protected boolean isRecompilable(Class cls) {
   if (cls == null) return true;
   if (cls.getClassLoader() == this) return false;
   if (recompile == null && !config.getRecompileGroovySource()) return false;
   if (recompile != null && !recompile) return false;
   if (!GroovyObject.class.isAssignableFrom(cls)) return false;
   long timestamp = getTimeStamp(cls);
   if (timestamp == Long.MAX_VALUE) return false;
   return true;
 }
  private Class doParseClass(GroovyCodeSource codeSource) {
    validate(codeSource);
    Class answer; // Was neither already loaded nor compiling, so compile and add to cache.
    CompilationUnit unit = createCompilationUnit(config, codeSource.getCodeSource());
    if (recompile != null && recompile || recompile == null && config.getRecompileGroovySource()) {
      unit.addFirstPhaseOperation(
          TimestampAdder.INSTANCE, CompilePhase.CLASS_GENERATION.getPhaseNumber());
    }
    SourceUnit su = null;
    File file = codeSource.getFile();
    if (file != null) {
      su = unit.addSource(file);
    } else {
      URL url = codeSource.getURL();
      if (url != null) {
        su = unit.addSource(url);
      } else {
        su = unit.addSource(codeSource.getName(), codeSource.getScriptText());
      }
    }

    ClassCollector collector = createCollector(unit, su);
    unit.setClassgenCallback(collector);
    int goalPhase = Phases.CLASS_GENERATION;
    if (config != null && config.getTargetDirectory() != null) goalPhase = Phases.OUTPUT;
    unit.compile(goalPhase);

    answer = collector.generatedClass;
    String mainClass = su.getAST().getMainClassName();
    for (Object o : collector.getLoadedClasses()) {
      Class clazz = (Class) o;
      String clazzName = clazz.getName();
      definePackage(clazzName);
      setClassCacheEntry(clazz);
      if (clazzName.equals(mainClass)) answer = clazz;
    }
    return answer;
  }
 /**
  * Copy constructor. Use this if you have a mostly correct configuration for your compilation but
  * you want to make a some changes programmatically. An important reason to prefer this approach
  * is that your code will most likely be forward compatible with future changes to this
  * configuration API.<br>
  * An example of this copy constructor at work:<br>
  *
  * <pre>
  *    // In all likelihood there is already a configuration in your code's context
  *    // for you to copy, but for the sake of this example we'll use the global default.
  *    CompilerConfiguration myConfiguration = new CompilerConfiguration(CompilerConfiguration.DEFAULT);
  *    myConfiguration.setDebug(true);
  * </pre>
  *
  * @param configuration The configuration to copy.
  */
 public CompilerConfiguration(CompilerConfiguration configuration) {
   setWarningLevel(configuration.getWarningLevel());
   setOutput(configuration.getOutput());
   setTargetDirectory(configuration.getTargetDirectory());
   setClasspathList(new LinkedList(configuration.getClasspath()));
   setVerbose(configuration.getVerbose());
   setDebug(configuration.getDebug());
   setTolerance(configuration.getTolerance());
   setScriptBaseClass(configuration.getScriptBaseClass());
   setRecompileGroovySource(configuration.getRecompileGroovySource());
   setMinimumRecompilationInterval(configuration.getMinimumRecompilationInterval());
   setTargetBytecode(configuration.getTargetBytecode());
   setDefaultScriptExtension(configuration.getDefaultScriptExtension());
   setSourceEncoding(configuration.getSourceEncoding());
   setOutput(configuration.getOutput());
   setTargetDirectory(configuration.getTargetDirectory());
   Map jointCompilationOptions = configuration.getJointCompilationOptions();
   if (jointCompilationOptions != null) {
     jointCompilationOptions = new HashMap(jointCompilationOptions);
   }
   setJointCompilationOptions(jointCompilationOptions);
   setPluginFactory(configuration.getPluginFactory());
 }