Package com.google.gwt.dev.cfg

Source Code of com.google.gwt.dev.cfg.ModuleDef

/*
* Copyright 2006 Google Inc.
*
* 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.google.gwt.dev.cfg;

import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.CompilationUnitProvider;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.dev.jdt.CacheManager;
import com.google.gwt.dev.jdt.TypeOracleBuilder;
import com.google.gwt.dev.jdt.URLCompilationUnitProvider;
import com.google.gwt.dev.util.Empty;
import com.google.gwt.dev.util.FileOracle;
import com.google.gwt.dev.util.FileOracleFactory;
import com.google.gwt.dev.util.Util;
import com.google.gwt.dev.util.FileOracleFactory.FileFilter;

import org.apache.tools.ant.types.ZipScanner;

import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

/**
* Represents a module specification. In principle, this could be built without
* XML for unit tests.
*/
public class ModuleDef {

  private static final FileFilter JAVA_ACCEPTOR = new FileFilter() {
    public boolean accept(String name) {
      return name.endsWith(".java");
    }
  };

  private static final Comparator REV_NAME_CMP = new Comparator() {
    public int compare(Object o1, Object o2) {
      Map.Entry entry1 = (Entry) o1;
      Map.Entry entry2 = (Entry) o2;
      String key1 = (String) entry1.getKey();
      String key2 = (String) entry2.getKey();
      // intentionally reversed
      return key2.compareTo(key1);
    }
  };

  public static boolean isValidModuleName(String moduleName) {
    String[] parts = moduleName.split("\\.");
    for (int i = 0; i < parts.length; i++) {
      String part = parts[i];
      if (!Util.isValidJavaIdent(part)) {
        return false;
      }
    }
    return true;
  }

  private final ArrayList allCups = new ArrayList();

  private final Set alreadySeenFiles = new HashSet();

  private final CacheManager cacheManager = new CacheManager(".gwt-cache",
      new TypeOracle());

  private CompilationUnitProvider[] cups = new CompilationUnitProvider[0];

  private final List entryPointTypeNames = new ArrayList();

  private final Set gwtXmlFiles = new HashSet();

  private FileOracle lazyPublicOracle;

  private FileOracle lazySourceOracle;

  private TypeOracle lazyTypeOracle;

  private final long moduleDefCreationTime = System.currentTimeMillis();

  private final String name;

  private final Properties properties = new Properties();

  private final FileOracleFactory publicPathEntries = new FileOracleFactory();

  private final Rules rules = new Rules();

  private final Scripts scripts = new Scripts();

  private final Map servletClassNamesByPath = new HashMap();

  private final FileOracleFactory sourcePathEntries = new FileOracleFactory();

  private final Styles styles = new Styles();

  public ModuleDef(String name) {
    this.name = name;
  }

  public synchronized void addEntryPointTypeName(String typeName) {
    entryPointTypeNames.add(typeName);
  }

  public void addGwtXmlFile(File xmlFile) {
    gwtXmlFiles.add(xmlFile);
  }

  public synchronized void addPublicPackage(String publicPackage,
      String[] includeList, String[] excludeList, boolean defaultExcludes,
      boolean caseSensitive) {

    if (lazyPublicOracle != null) {
      throw new IllegalStateException("Already normalized");
    }

    /*
     * Hijack Ant's ZipScanner to handle inclusions/exclusions exactly as Ant
     * does. We're only using its pattern-matching capabilities; the code path
     * I'm using never tries to hit the filesystem in Ant 1.6.5.
     */
    final ZipScanner scanner = new ZipScanner();
    if (includeList.length > 0) {
      scanner.setIncludes(includeList);
    }
    if (excludeList.length > 0) {
      scanner.setExcludes(excludeList);
    }
    if (defaultExcludes) {
      scanner.addDefaultExcludes();
    }
    scanner.setCaseSensitive(caseSensitive);
    scanner.init();

    // index from this package down
    publicPathEntries.addRootPackage(publicPackage, new FileFilter() {
      public boolean accept(String name) {
        return scanner.match(name);
      }
    });
  }

  public synchronized void addSourcePackage(String sourcePackage) {
    if (lazySourceOracle != null) {
      throw new IllegalStateException("Already normalized");
    }

    // index from from the base package
    sourcePathEntries.addPackage(sourcePackage, JAVA_ACCEPTOR);
  }

  public synchronized void addSuperSourcePackage(String superSourcePackage) {
    if (lazySourceOracle != null) {
      throw new IllegalStateException("Already normalized");
    }

    // index from this package down
    sourcePathEntries.addRootPackage(superSourcePackage, JAVA_ACCEPTOR);
  }

  public void clearEntryPoints() {
    entryPointTypeNames.clear();
  }

  public synchronized URL findPublicFile(String partialPath) {
    return lazyPublicOracle.find(partialPath);
  }

  public synchronized String findServletForPath(String actual) {
    // Walk in backwards sorted order to find the longest path match first.
    //
    Set entrySet = servletClassNamesByPath.entrySet();
    Map.Entry[] entries = (Entry[]) Util.toArray(Map.Entry.class, entrySet);
    Arrays.sort(entries, REV_NAME_CMP);
    for (int i = 0, n = entries.length; i < n; ++i) {
      String mapping = (String) entries[i].getKey();
      /*
       * Ensure that URLs that match the servlet mapping, including those that
       * have additional path_info, get routed to the correct servlet.
       *
       * See "Inside Servlets", Second Edition, pg. 208
       */
      if (actual.equals(mapping) || actual.startsWith(mapping + "/")) {
        return (String) entries[i].getValue();
      }
    }
    return null;
  }

  public String[] getAllPublicFiles() {
    return lazyPublicOracle.getAllFiles();
  }

  public CacheManager getCacheManager() {
    return cacheManager;
  }

  public synchronized CompilationUnitProvider[] getCompilationUnits() {
    return cups;
  }

  public synchronized String[] getEntryPointTypeNames() {
    final int n = entryPointTypeNames.size();
    return (String[]) entryPointTypeNames.toArray(new String[n]);
  }

  public synchronized String getFunctionName() {
    return name.replace('.', '_');
  }

  public synchronized String getName() {
    return name;
  }

  /**
   * The properties that have been defined.
   */
  public synchronized Properties getProperties() {
    return properties;
  }

  /**
   * Gets a reference to the internal rules for this module def.
   */
  public synchronized Rules getRules() {
    return rules;
  }

  /**
   * Gets a reference to the internal scripts list for this module def.
   */
  public Scripts getScripts() {
    return scripts;
  }

  public synchronized String[] getServletPaths() {
    return (String[]) servletClassNamesByPath.keySet().toArray(Empty.STRINGS);
  }

  /**
   * Gets a reference to the internal styles list for this module def.
   */
  public Styles getStyles() {
    return styles;
  }

  public synchronized TypeOracle getTypeOracle(TreeLogger logger)
      throws UnableToCompleteException {
    if (lazyTypeOracle == null) {

      // Refresh the type oracle.
      //
      try {
        String msg = "Analyzing source in module '" + name + "'";
        TreeLogger branch = logger.branch(TreeLogger.TRACE, msg, null);
        long before = System.currentTimeMillis();
        TypeOracleBuilder builder = new TypeOracleBuilder(getCacheManager());
        CompilationUnitProvider[] currentCups = getCompilationUnits();
        Arrays.sort(currentCups, CompilationUnitProvider.LOCATION_COMPARATOR);

        TreeLogger subBranch = null;
        if (branch.isLoggable(TreeLogger.DEBUG)) {
          subBranch = branch.branch(TreeLogger.DEBUG,
              "Adding compilation units...", null);
        }

        for (int i = 0; i < currentCups.length; i++) {
          CompilationUnitProvider cup = currentCups[i];
          if (subBranch != null) {
            subBranch.log(TreeLogger.DEBUG, cup.getLocation(), null);
          }
          builder.addCompilationUnit(currentCups[i]);
        }
        lazyTypeOracle = builder.build(branch);
        long after = System.currentTimeMillis();
        branch.log(TreeLogger.TRACE, "Finished in " + (after - before) + " ms",
            null);
      } catch (UnableToCompleteException e) {
        logger.log(TreeLogger.ERROR, "Failed to complete analysis", null);
        throw new UnableToCompleteException();
      }

      // Sanity check the seed types and don't even start it they're missing.
      //
      boolean seedTypesMissing = false;
      if (lazyTypeOracle.findType("java.lang.Object") == null) {
        Util.logMissingTypeErrorWithHints(logger, "java.lang.Object");
        seedTypesMissing = true;
      } else {
        TreeLogger branch = logger.branch(TreeLogger.TRACE,
            "Finding entry point classes", null);
        String[] typeNames = getEntryPointTypeNames();
        for (int i = 0; i < typeNames.length; i++) {
          String typeName = typeNames[i];
          if (lazyTypeOracle.findType(typeName) == null) {
            Util.logMissingTypeErrorWithHints(branch, typeName);
            seedTypesMissing = true;
          }
        }
      }

      if (seedTypesMissing) {
        throw new UnableToCompleteException();
      }
    }

    return lazyTypeOracle;
  }

  public boolean isGwtXmlFileStale() {
    for (Iterator iter = gwtXmlFiles.iterator(); iter.hasNext();) {
      File xmlFile = (File) iter.next();
      if ((!xmlFile.exists())
          || (xmlFile.lastModified() > moduleDefCreationTime)) {
        return true;
      }
    }
    return false;
  }

  /**
   * For convenience in hosted mode, servlets can be automatically loaded and
   * delegated to via {@link com.google.gwt.dev.shell.GWTShellServlet}. If a
   * servlet is already mapped to the specified path, it is replaced.
   *
   * @param path the url path at which the servlet resides
   * @param servletClassName the name of the servlet to publish
   */
  public synchronized void mapServlet(String path, String servletClassName) {
    servletClassNamesByPath.put(path, servletClassName);
  }

  public synchronized void refresh(TreeLogger logger)
      throws UnableToCompleteException {

    cacheManager.invalidateVolatileFiles();
    lazyTypeOracle = null;
    normalize(logger);
    getTypeOracle(logger);
    Util.invokeInaccessableMethod(TypeOracle.class, "incrementReloadCount",
        new Class[] {}, lazyTypeOracle, new Object[] {});
  }

  /**
   * The final method to call when everything is setup. Before calling this
   * method, several of the getter methods may not be called. After calling this
   * method, the add methods may not be called.
   *
   * @param logger Logs the activity.
   */
  synchronized void normalize(TreeLogger logger) {
    // Normalize property providers.
    //
    for (Iterator iter = getProperties().iterator(); iter.hasNext();) {
      Property prop = (Property) iter.next();
      if (prop.getActiveValue() == null) {
        // If there are more than one possible values, then create a provider.
        // Otherwise, pretend the one value is an active value.
        //
        String[] knownValues = prop.getKnownValues();
        assert (knownValues.length > 0);
        if (knownValues.length > 1) {
          if (prop.getProvider() == null) {
            // Create a default provider.
            //
            prop.setProvider(new DefaultPropertyProvider(this, prop));
          }
        } else {
          prop.setActiveValue(knownValues[0]);
        }
      }
    }

    // Create the source path.
    //
    TreeLogger branch = Messages.SOURCE_PATH_LOCATIONS.branch(logger, null);
    lazySourceOracle = sourcePathEntries.create(branch);

    if (lazySourceOracle.isEmpty()) {
      branch.log(TreeLogger.WARN,
          "No source path entries; expect subsequent failures", null);
    } else {
      // Create the CUPs
      String[] allFiles = lazySourceOracle.getAllFiles();
      Set files = new HashSet();
      files.addAll(Arrays.asList(allFiles));
      files.removeAll(alreadySeenFiles);
      for (Iterator iter = files.iterator(); iter.hasNext();) {
        String fileName = (String) iter.next();
        int pos = fileName.lastIndexOf('/');
        String packageName;
        if (pos >= 0) {
          packageName = fileName.substring(0, pos);
          packageName = packageName.replace('/', '.');
        } else {
          packageName = "";
        }
        URL url = lazySourceOracle.find(fileName);
        allCups.add(new URLCompilationUnitProvider(url, packageName));
      }
      alreadySeenFiles.addAll(files);
      this.cups = (CompilationUnitProvider[]) allCups.toArray(this.cups);
    }

    // Create the public path.
    //
    branch = Messages.PUBLIC_PATH_LOCATIONS.branch(logger, null);
    lazyPublicOracle = publicPathEntries.create(branch);
  }

}
TOP

Related Classes of com.google.gwt.dev.cfg.ModuleDef

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.