Package flex2.compiler

Source Code of flex2.compiler.SourcePathBase$ClasspathOverlap

/*
*
*  Licensed to the Apache Software Foundation (ASF) under one or more
*  contributor license agreements.  See the NOTICE file distributed with
*  this work for additional information regarding copyright ownership.
*  The ASF licenses this file to You 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 flex2.compiler;

import flex2.compiler.common.SinglePathResolver;
import flex2.compiler.io.FileUtil;
import flex2.compiler.io.LocalFile;
import flex2.compiler.io.VirtualFile;
import flex2.compiler.util.CompilerMessage;
import java.io.File;
import java.util.*;

/**
* A list of paths specified by the -source-path option, where
* dependencies, following the single public definition rule, can be
* resolved.
*
* @author Clement Wong
*/
public class SourcePath extends SourcePathBase
    implements SinglePathResolver
{
    protected final List<File> directories;
    //private ApplicationCache applicationCache;

  public SourcePath(VirtualFile[] classPath, VirtualFile appPath, String[] mimeTypes, boolean allowSourcePathOverlap)
  {
    this(mimeTypes, allowSourcePathOverlap);

    addApplicationParentToSourcePath(appPath, classPath, this.directories);
    addPathElements(classPath, this.directories, allowSourcePathOverlap, warnings);
  }
 
  public SourcePath(String[] mimeTypes, boolean allowSourcePathOverlap)
  {
    super(mimeTypes, allowSourcePathOverlap);
    directories = new LinkedList<File>();
  }

  public void addPathElements(VirtualFile[] classPath)
  {
    addPathElements(classPath, directories, allowSourcePathOverlap, warnings);
 

  /*
  private Source newSource(File file, File pathRoot, String namespaceURI, String localPart)
  {
        Source source = new Source(new LocalFile(file), new LocalFile(pathRoot),
                                   namespaceURI.replace('.', '/'), localPart, this, false, false);

        if (applicationCache != null)
        {
            String className = CompilerAPI.constructClassName(namespaceURI, localPart);
            Source cachedSource = applicationCache.getSource(className);

            if ((cachedSource != null) && !cachedSource.isUpdated())
            {
                CompilationUnit cachedCompilationUnit = cachedSource.getCompilationUnit();

                if (cachedSource.getPathRoot().equals(source.getPathRoot()) &&
                    (cachedCompilationUnit != null) && cachedCompilationUnit.hasTypeInfo)
                {
                    CompilationUnit compilationUnit =
                        source.newCompilationUnit(cachedCompilationUnit.getSyntaxTree(),
                                                  new CompilerContext());

                    Source.copyCompilationUnit(cachedCompilationUnit, compilationUnit, true);
                    source.setFileTime(cachedSource.getFileTime());
                    cachedSource.reused();

                    // We somehow need to validate that other reused
                    // sources, which depend on this source, reference
                    // the same slots.  Or maybe it's good enough just
                    // to validate that the slots referenced by this
                    // source are the same as the slots referenced by
                    // the dependencies.  Something to ponder.
                }
            }
        }

        return source;
  }
 
  // see if the Source object continues to be the first choice given a QName.
  boolean checkPreference(Source s)
  {
    assert s.getOwner() == this;
   
    String relativePath = constructRelativePath(s), pathRoot = s.getPathRoot().getName();
    if (relativePath == null)
    {
      // not possible, but don't disrupt the flow...
      return true;
    }
   
    boolean thisPath = false;
   
    for (int i = 0, size = directories.size(); i < size; i++)
    {
      File d = directories.get(i), f = null;
      if (pathRoot.equals(FileUtil.getCanonicalPath(d)))
      {
        thisPath = true;
      }
     
      try
      {
        f = findFile(d, relativePath, mimeTypes);
      }
      catch (CompilerException ex)
      {
        removeSource(s);
        return false;
      }

      if (f != null && !thisPath)
      {
        removeSource(s);
        return false;
      }
    }
   
    return true;
  }
 
  protected Source findFile(String className, String namespaceURI, String localPart) throws CompilerException
  {
    String p = className.replace(':', '.').replace('.', File.separatorChar);
    Source s = null;

    for (int i = 0, size = directories.size(); i < size; i++)
    {
      File f, d = directories.get(i);

      if ((f = findFile(d, p, mimeTypes)) != null)
      {
        sources.put(className, s = newSource(f, d, namespaceURI, localPart));
        return s;
      }
    }
   
    return null;
  }
 
  public boolean hasPackage(String packageName)
  {
    for (int i = 0, size = directories.size(); i < size; i++)
    {
      File d = directories.get(i);
      if (hasDirectory(d, packageName))
      {
        return true;
      }
    }

    return false;
  }

  public boolean hasDefinition(QName qName)
  {
    String className = CompilerAPI.constructClassName(qName.getNamespace(), qName.getLocalPart());

    if (misses.contains(className))
    {
      return false;
    }

    if (hits.contains(className))
    {
      return true;
    }

    String p = className.replace(':', '.').replace('.', File.separatorChar);

    for (int i = 0, size = directories.size(); i < size; i++)
    {
      File f, d = directories.get(i);

      try
      {
        if ((f = findFile(d, p, mimeTypes)) != null)
        {
          hits.add(className);
          return true;
        }
      }
      catch (CompilerException ex)
      {
      }
    }

    misses.add(className);
    return false;
  }

  private boolean hasDirectory(File dir, String packageName)
  {
    if (packageName.length() == 0)
    {
      return true;
    }

    String relativePath = packageName.replace('.', File.separatorChar);
    String fullPath = dir.getPath() + File.separator + relativePath;

    if (dirs.get(fullPath) == NO_DIR)
    {
      return false;
    }

    boolean result = new File(dir, relativePath).isDirectory();
    dirs.put(fullPath, result ? fullPath : NO_DIR);

    return result;
  }
 
  public List<File> getPaths()
  {
    return directories;
  }
    */
    /**
     * Resolves paths with a leading slash and relative to a Source
     * Path directory.
     */
    public VirtualFile resolve(String path)
    {
        if (path.charAt(0) == '/')
        {
            String relativePath = path.substring(1);

            for (File directory : directories)
            {
                File file = FileUtil.openFile(directory, relativePath);

                if ((file != null) && file.exists())
                {
                    return new LocalFile(file);
                }
            }
        }

        return null;
    }

    /*
    public void setApplicationCache(ApplicationCache applicationCache)
    {
        this.applicationCache = applicationCache;
    }
     */
}

/**
* @author Clement Wong
*/
abstract class SourcePathBase
{
  protected final static String NO_DIR = "";

  static void addApplicationParentToSourcePath(VirtualFile appPath, VirtualFile[] classPath, List<File> directories)
  {
    if (appPath != null)
    {
      File f = FileUtil.openFile(appPath.getParent());
      // if (f != null && f.isDirectory())
      if (f != null && f.isDirectory() && (FileUtil.isSubdirectoryOf(appPath.getParent(), classPath) == -1))
      {
        directories.add(f);
      }
    }
  }

  static void addPathElements(VirtualFile[] classPath, List<File> directories, boolean allowSourcePathOverlap, List<ClasspathOverlap> warnings)
  {
    boolean badPaths = false;

    for (int i = 0, length = (classPath == null) ? 0 : classPath.length; i < length; i++)
    {
      String path = classPath[i].getName();
      File f = FileUtil.openFile(path);
      if (f != null && f.isDirectory())
      {
        if (!allowSourcePathOverlap && !badPaths)
        {
          int index = FileUtil.isSubdirectoryOf(f, directories);
          if (index != -1)
          {
            String dirPath = directories.get(index).getAbsolutePath();
            if (checkValidPackageName(path, dirPath))
            {
              // C: don't want to use ThreadLocalToolkit here...

                          // preilly: don't use logError below, because we don't stop
                          // compiling and if the error count is non-zero downstream mayhem
                          // occurs.  For example, no SWC's get loaded, which makes it
                          // alittle tough to compile.

              warnings.add(new ClasspathOverlap(path, dirPath));
              badPaths = true;
            }
          }
        }
        directories.add(f);
      }
    }   
  }
 
  private static boolean checkValidPackageName(String path1, String path2)
  {
    if (path1.equals(path2)) return true;
    String packagePath = path1.length() > path2.length() ? path1.substring(path2.length()) : path2.substring(path1.length());

    for (StringTokenizer t = new StringTokenizer(packagePath, File.separator); t.hasMoreTokens(); )
    {
      String s = t.nextToken();
      if (!flex2.compiler.mxml.lang.TextParser.isValidIdentifier(s))
      {
        return false;
      }
    }
   
    return true;
  }

  public SourcePathBase(String[] mimeTypes, boolean allowSourcePathOverlap)
  {
    this.mimeTypes = mimeTypes;
    this.allowSourcePathOverlap = allowSourcePathOverlap;
    sources = new HashMap<String, Source>();

    hits = new HashSet<String>();
    misses = new HashSet<String>(1024);
    dirs = new HashMap<String, String>();
    warnings = new ArrayList<ClasspathOverlap>(5);
  }

  protected final String[] mimeTypes;
  protected final Map<String, Source> sources;
  protected boolean allowSourcePathOverlap;

  protected final Set<String> hits, misses;
  protected final HashMap<String, String> dirs;
  protected final List<ClasspathOverlap> warnings;

    /*
  public Source findSource(String namespaceURI, String localPart) throws CompilerException
  {
    assert localPart.indexOf('.') == -1 && localPart.indexOf('/') == -1 && localPart.indexOf(':') == -1
                : "findSource(" + namespaceURI + "," + localPart + ") has bad localPart";

    // classname format is a.b:c
    String className = CompilerAPI.constructClassName(namespaceURI, localPart);
   
    return findSource(className, namespaceURI, localPart);
  }
 
  protected Source findSource(String className, String namespaceURI, String localPart) throws CompilerException
  {
    if (misses.contains(className))
    {
      return null;
    }

    Source s = sources.get(className);

    if (s == null)
    {
      if ((s = findFile(className, namespaceURI, localPart)) != null)
      {
        return s;
      }
    }

    CompilationUnit u = (s != null) ? s.getCompilationUnit() : null;

    if (s != null && !s.exists())
    {
      sources.remove(className);
      s = null;
    }

    if (adjustDefinitionName(namespaceURI, localPart, s, u))
    {
      u = null;
      s = null;
    }

    if (s != null && ((u != null && !u.isDone()) || s.isUpdated()))
    {
      // s.removeCompilationUnit();
    }
    else if (s != null && u != null)
    {
      s = s.copy();
      assert s != null;
    }

    if (s == null)
    {
      misses.add(className);
    }

    return s;
  }

  protected boolean adjustDefinitionName(String namespaceURI, String localPart, Source s, CompilationUnit u)
  {
    // If the compilation unit does exist and the top level definition name doesn't match
    // the specified class name, we don't count it as a match.
    if (s != null && u != null && u.topLevelDefinitions.size() == 1)
    {
      if (!u.topLevelDefinitions.contains(namespaceURI, localPart))
      {
        String realName = (u.topLevelDefinitions.first()).toString();
        sources.put(realName, s);
        misses.remove(realName);
        return true;
      }
    }
   
    return false;
  }
 
  abstract boolean checkPreference(Source s);

  protected abstract Source findFile(String className, String namespaceURI, String localPart) throws CompilerException;

  protected File findFile(File directory, String relativePath, String[] mimeTypes) throws CompilerException
  {
    File found = null;

    for (int k = 0, length = mimeTypes.length; k < length; k++)
    {
      File f = findFile(directory, relativePath, mimeTypes[k]);

      if (f != null && found == null)
      {
        found = f;
        // break;
      }
      else if (f != null)
      {
        throw new MoreThanOneComponentOfTheSameName(found.getAbsolutePath(), f.getAbsolutePath());
      }
    }

    return found;
  }

  protected File findFile(File directory, String relativePath, String mimeType)
  {
    String fullPath = directory.getPath() + File.separator + relativePath;
    int lastSlash = fullPath.lastIndexOf(File.separator);
    String dir = null;
    if (lastSlash != -1)
    {
      dir = fullPath.substring(0, lastSlash);
      if (dirs.get(dir) == NO_DIR)
      {
        return null;
      }
    }

    String path = relativePath + MimeMappings.getExtension(mimeType);
    File f = FileUtil.openFile(directory, path);

    if ((f != null) && f.isFile() && FileUtil.getCanonicalPath(f).endsWith(path))
    {
      return f;
    }
    else if (f != null && dir != null && !dirs.containsKey(dir))
    {
      File p = f.getParentFile();
      dirs.put(dir, p != null && p.isDirectory() ? dir : NO_DIR);
    }

    return null;
  }

  String[] checkClassNameFileName(Source s)
  {
    String defName = null, pathName = null;
   
    if (s.getOwner() == this)
    {
      QName def = s.getCompilationUnit().topLevelDefinitions.last();
     
      defName = def.getLocalPart();
      pathName = s.getShortName();
     
      if (defName.equals(pathName))
      {
        return null;
      }
    }
   
    return new String[] { pathName, defName };
  }

  String[] checkPackageNameDirectoryName(Source s)
  {
    String defPackage = null, pathPackage = null;
   
    if (s.getOwner() == this)
    {
      QName def = s.getCompilationUnit().topLevelDefinitions.last();
     
      defPackage = NameFormatter.normalizePackageName(def.getNamespace());   
      pathPackage = NameFormatter.toDot(s.getRelativePath(), '/');
     
      if (defPackage.equals(pathPackage))
      {
        return null;
      }
    }
   
    return new String[] { pathPackage, defPackage };
  }

  protected String constructRelativePath(Source s)
  {
    // + 1 removes the leading /
    String relativePath = s.getName().substring(s.getPathRoot().getName().length() + 1);
    for (int k = 0, length = mimeTypes.length; k < length; k++)
    {
      String ext = MimeMappings.getExtension(mimeTypes[k]);
      if (relativePath.endsWith(ext))
      {
        relativePath = relativePath.substring(0, relativePath.length() - ext.length());
        return relativePath;
      }
    }
   
    assert false;
    return null;
  }
 
  // used by CompilerAPI.validateCompilationUnits()... not efficient, but we rarely call it...
  public void removeSource(Source s)
  {
    for (Iterator i = sources.entrySet().iterator(); i.hasNext(); )
    {
      Map.Entry e = (Map.Entry) i.next();
      if (e.getValue() == s)
      {
        i.remove();
        return;
      }
    }

        assert false : "couldn't find " + s;
  }

  public void clearCache()
  {
    hits.clear();
    misses.clear();
    dirs.clear();
  }

  String[] getMimeTypes()
  {
    return mimeTypes;
  }

  public Map<String, Source> sources()
  {
    return sources;
  }

    public String toString()
    {
        StringBuilder buffer = new StringBuilder("SourcePath: \n");
    Iterator<Source> iterator = sources.values().iterator();

        while (iterator.hasNext())
    {
            Source source = iterator.next();
            buffer.append("\tsource = " + source + ", cu = " + source.getCompilationUnit() + "\n");
    }

        return buffer.toString();
    }
 
  public void displayWarnings()
  {
    for (int i = 0, size = warnings.size(); i < size; i++)
    {
      ThreadLocalToolkit.log(warnings.get(i));
    }
  }
    */

  // error messages

  public static class ClasspathOverlap extends CompilerMessage.CompilerWarning
  {
    private static final long serialVersionUID = -6314431057641028497L;

        public ClasspathOverlap(String path, String directory)
    {
      super();
      this.cpath = path;
      this.directory = directory;
    }

    public final String cpath, directory;
  }

  public static class MoreThanOneComponentOfTheSameName extends CompilerMessage.CompilerInfo
  {
    private static final long serialVersionUID = 5943423934006966281L;

        public MoreThanOneComponentOfTheSameName(String file1, String file2)
    {
      super();
      this.file1 = file1;
      this.file2 = file2;
    }

    public final String file1, file2;
  }
}
TOP

Related Classes of flex2.compiler.SourcePathBase$ClasspathOverlap

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.