Package org.eclipse.php.internal.debug.core.pathmapper

Source Code of org.eclipse.php.internal.debug.core.pathmapper.DebugSearchEngine$PHPFilenameFilter

/*******************************************************************************
* Copyright (c) 2009 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     IBM Corporation - initial API and implementation
*     Zend Technologies
*******************************************************************************/
package org.eclipse.php.internal.debug.core.pathmapper;

import java.io.File;
import java.io.FileFilter;
import java.util.*;
import java.util.regex.Pattern;

import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.content.IContentType;
import org.eclipse.core.runtime.content.IContentTypeManager.ContentTypeChangeEvent;
import org.eclipse.core.runtime.content.IContentTypeManager.IContentTypeChangeListener;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.model.IDebugTarget;
import org.eclipse.dltk.core.*;
import org.eclipse.dltk.core.environment.EnvironmentManager;
import org.eclipse.dltk.core.environment.EnvironmentPathUtils;
import org.eclipse.dltk.core.environment.IEnvironment;
import org.eclipse.php.internal.core.PHPCorePlugin;
import org.eclipse.php.internal.core.documentModel.provisional.contenttype.ContentTypeIdForPHP;
import org.eclipse.php.internal.core.includepath.IncludePath;
import org.eclipse.php.internal.core.util.*;
import org.eclipse.php.internal.core.util.PHPSearchEngine.ExternalFileResult;
import org.eclipse.php.internal.core.util.PHPSearchEngine.IncludedFileResult;
import org.eclipse.php.internal.core.util.PHPSearchEngine.ResourceResult;
import org.eclipse.php.internal.core.util.PHPSearchEngine.Result;
import org.eclipse.php.internal.debug.core.IPHPDebugConstants;
import org.eclipse.php.internal.debug.core.PHPDebugPlugin;
import org.eclipse.php.internal.debug.core.pathmapper.PathEntry.Type;
import org.eclipse.php.internal.debug.core.zend.model.PHPDebugTarget;
import org.eclipse.ui.*;
import org.eclipse.ui.ide.FileStoreEditorInput;

public class DebugSearchEngine {

  private static PHPFilenameFilter PHP_FILTER = new PHPFilenameFilter();
  private static IPathEntryFilter[] filters;

  /**
   * Searches for all local resources that match provided remote file, and
   * returns it in best match order. This method skips internal PHP search
   * mechanism, going straight to the path mapper, so it's good only for
   * resolving absolute paths.
   *
   * @param remoteFile
   *            Path of the file on server. This argument must not be
   *            <code>null</code>.
   * @param debugTarget
   *            Current debug target
   * @return path entry or <code>null</code> in case it could not be found
   */
  public static PathEntry find(String remoteFile, IDebugTarget debugTarget) {
    return find(remoteFile, debugTarget, null, null);
  }

  /**
   * Searches for all local resources that match provided remote file, and
   * returns it in best match order.
   *
   * @param remoteFile
   *            Path of the file on server. This argument must not be
   *            <code>null</code>.
   * @param debugTarget
   *            Current debug target
   * @param currentWorkingDir
   *            Current working directory of PHP process
   * @param currentScriptDir
   *            Directory of current PHP file
   * @return path entry or <code>null</code> in case it could not be found
   */
  public static PathEntry find(String remoteFile, IDebugTarget debugTarget,
      String currentWorkingDir, String currentScriptDir) {
    if (remoteFile == null) {
      throw new NullPointerException();
    }

    PathEntry pathEntry = null;
    ILaunchConfiguration launchConfiguration = debugTarget.getLaunch()
        .getLaunchConfiguration();

    IProject project = null;
    if (currentScriptDir != null) {
      IResource resource = ResourcesPlugin.getWorkspace().getRoot()
          .findMember(currentScriptDir);
      if (resource != null) {
        project = resource.getProject();
      }
    }
    if (project == null && debugTarget instanceof PHPDebugTarget) {
      project = ((PHPDebugTarget) debugTarget).getProject();
    }
    if (project == null) {
      String projectName;
      try {
        projectName = launchConfiguration.getAttribute(
            IPHPDebugConstants.PHP_Project, (String) null);
        if (projectName != null) {
          project = ResourcesPlugin.getWorkspace().getRoot()
              .getProject(projectName);
        }
      } catch (CoreException e) {
        PHPDebugPlugin.log(e);
      }
    }

    // If the given path is not absolute - use internal PHP search
    // mechanism:
    if (!VirtualPath.isAbsolute(remoteFile)) {
      if (project != null && currentWorkingDir != null
          && currentScriptDir != null) {
        // This is not a full path, search using PHP Search Engine:
        Result<?, ?> result = PHPSearchEngine.find(remoteFile,
            currentWorkingDir, currentScriptDir, project);
        if (result instanceof ExternalFileResult) {
          ExternalFileResult extFileResult = (ExternalFileResult) result;
          return new PathEntry(extFileResult.getFile()
              .getAbsolutePath(), Type.EXTERNAL,
              extFileResult.getContainer());
        }
        if (result instanceof IncludedFileResult) {
          IncludedFileResult incFileResult = (IncludedFileResult) result;
          IBuildpathEntry container = incFileResult.getContainer();
          Type type = (container.getEntryKind() == IBuildpathEntry.BPE_VARIABLE) ? Type.INCLUDE_VAR
              : Type.INCLUDE_FOLDER;
          return new PathEntry(incFileResult.getFile()
              .getAbsolutePath(), type, container);
        }
        if (result != null) {
          // workspace file
          ResourceResult resResult = (ResourceResult) result;
          IResource resource = resResult.getFile();
          return new PathEntry(resource.getFullPath().toString(),
              Type.WORKSPACE, resource.getParent());
        }
      }
      return null;
    }

    PathMapper pathMapper = PathMapperRegistry
        .getByLaunchConfiguration(launchConfiguration);
    if (pathMapper != null) {
      pathEntry = find(pathMapper, remoteFile, project, debugTarget);
    }
    return pathEntry;
  }

  /**
   * Searches for all local resources that match provided remote file, and
   * returns it in best match order.
   *
   * @param pathMapper
   *            Path mapper to look at
   * @param remoteFile
   *            Path of the file on server. This argument must not be
   *            <code>null</code>.
   * @param debugTarget
   *            Current debug target
   * @return path entry or <code>null</code> in case it could not be found
   */
  public static PathEntry find(final PathMapper pathMapper,
      final String remoteFile, final IProject currentProject,
      final IDebugTarget debugTarget) {

    final PathEntry[] localFile = new PathEntry[1];

    Job findJob = new Job(Messages.DebugSearchEngine_0) {
      protected IStatus run(IProgressMonitor monitor) {
        // First, look into the path mapper:
        localFile[0] = pathMapper.getLocalFile(remoteFile);
        if (localFile[0] != null) {
          if (localFile[0].getType() == Type.SERVER) {
            localFile[0] = null;
          }
          return Status.OK_STATUS;
        }

        // if it is server mapping
        localFile[0] = pathMapper.getServerFile(remoteFile);
        if (localFile[0] != null) {
          localFile[0] = null;
          return Status.OK_STATUS;
        }

        VirtualPath abstractPath = new VirtualPath(remoteFile);

        // Check whether we have an exact mapping for the remote path
        // If so - we shouldn't proceed with search (we should have this
        // file right in the mapped folder)
        VirtualPath testPath = abstractPath.clone();
        testPath.removeLastSegment();
        if (pathMapper.getLocalPathMapping(testPath) != null) {
          return Status.OK_STATUS;
        }

        LinkedList<PathEntry> results = new LinkedList<PathEntry>();

        IncludePath[] includePaths;
        IBuildpathEntry[] buildPaths = null;

        // Search in the whole workspace:
        Set<IncludePath> s = new LinkedHashSet<IncludePath>();
        Set<IBuildpathEntry> b = new LinkedHashSet<IBuildpathEntry>();
        IProject[] projects = null;
        if (currentProject != null && currentProject.isOpen()) {
          projects = new IProject[] { currentProject };
        } else {
          projects = ResourcesPlugin.getWorkspace().getRoot()
              .getProjects();
        }
        for (IProject project : projects) {
          if (project.isOpen() && project.isAccessible()) {
            // get include paths of all projects
            PHPSearchEngine.buildIncludePath(project, s);

            // get build paths of all projects
            IScriptProject scriptProject = DLTKCore.create(project);
            if (scriptProject != null && scriptProject.isOpen()) {
              try {
                IBuildpathEntry[] rawBuildpath = scriptProject
                    .getRawBuildpath();
                for (IBuildpathEntry pathEntry : rawBuildpath) {
                  b.add(pathEntry);
                }
              } catch (ModelException e) {
                PHPDebugPlugin.log(e);
              }

            }
          }
        }
        includePaths = s.toArray(new IncludePath[s.size()]);
        buildPaths = b.toArray(new IBuildpathEntry[b.size()]);

        // Try to find this file in the Workspace:
        try {
          IPath path = Path.fromOSString(remoteFile);
          IFile file = ResourcesPlugin.getWorkspace().getRoot()
              .getFileForLocation(path);
          if (file != null && file.exists()) {
            for (IncludePath includePath : includePaths) {
              if (includePath.getEntry() instanceof IContainer) {
                IContainer container = (IContainer) includePath
                    .getEntry();
                if (container.getFullPath().isPrefixOf(
                    file.getFullPath())) {
                  localFile[0] = new PathEntry(file
                      .getFullPath().toString(),
                      Type.WORKSPACE, file.getParent());
                  pathMapper.addEntry(remoteFile,
                      localFile[0]);
                  PathMapperRegistry.storeToPreferences();
                  return Status.OK_STATUS;
                }
              }
            }
          }
        } catch (Exception e) {
          // no need to catch - this may be due to IPath creation
          // failure
        }

        // Try to find this file in the Include Path:
        File file = new File(remoteFile);
        if (file.exists()) {
          try {
            IScriptProject scriptProject = DLTKCore
                .create(currentProject);
            if (currentProject != null && scriptProject != null) {
              IBuildpathEntry[] rawBuildpath = scriptProject
                  .getRawBuildpath();

              IEnvironment environment = EnvironmentManager
                  .getEnvironment(currentProject);
              IPath remoteFilePath = EnvironmentPathUtils
                  .getFullPath(environment, new Path(
                      remoteFile));
              for (IBuildpathEntry entry : rawBuildpath) {
                IPath entryPath = entry.getPath();
                if (entry.getEntryKind() == IBuildpathEntry.BPE_VARIABLE) {
                  entryPath = DLTKCore
                      .getResolvedVariablePath(entryPath);
                }
                if (entryPath != null
                    && (entryPath.isPrefixOf(Path
                        .fromOSString(remoteFile)) || entryPath
                        .isPrefixOf(remoteFilePath))) {
                  Type type = (entry.getEntryKind() == IBuildpathEntry.BPE_VARIABLE) ? Type.INCLUDE_VAR
                      : Type.INCLUDE_FOLDER;
                  localFile[0] = new PathEntry(
                      file.getAbsolutePath(), type, entry);
                  // pathMapper.addEntry(remoteFile,
                  // localFile[0]);
                  // PathMapperRegistry.storeToPreferences();
                  return Status.OK_STATUS;
                }
              }
            }

          } catch (Exception e) {
            PHPDebugPlugin.log(e);
          }
          for (IncludePath includePath : includePaths) {
            if (includePath.getEntry() instanceof IBuildpathEntry) {
              IBuildpathEntry entry = (IBuildpathEntry) includePath
                  .getEntry();
              IPath entryPath = entry.getPath();
              if (entry.getEntryKind() == IBuildpathEntry.BPE_VARIABLE) {
                entryPath = DLTKCore
                    .getResolvedVariablePath(entryPath);
              }
              if (entryPath != null
                  && entryPath.isPrefixOf(Path
                      .fromOSString(remoteFile))) {
                Type type = (entry.getEntryKind() == IBuildpathEntry.BPE_VARIABLE) ? Type.INCLUDE_VAR
                    : Type.INCLUDE_FOLDER;
                localFile[0] = new PathEntry(
                    file.getAbsolutePath(), type, entry);
                pathMapper.addEntry(remoteFile, localFile[0]);
                PathMapperRegistry.storeToPreferences();
                return Status.OK_STATUS;
              }
            }
          }
        }

        // try to find in build paths
        if (buildPaths != null) {
          for (IBuildpathEntry entry : buildPaths) {

            IPath entryPath = entry.getPath();
            if (entry.getEntryKind() == IBuildpathEntry.BPE_LIBRARY) {
              // We don't support lookup in archive
              File entryDir = entryPath.toFile();
              find(entryDir, abstractPath, entry, results);
            } else if (entry.getEntryKind() == IBuildpathEntry.BPE_PROJECT
                || entry.getEntryKind() == IBuildpathEntry.BPE_SOURCE) {
              IResource res = ResourcesPlugin.getWorkspace()
                  .getRoot()
                  .findMember(entry.getPath().lastSegment());
              if (res instanceof IProject) {
                IProject project = (IProject) res;
                if (project.isOpen() && project.isAccessible()) {
                  try {
                    find(project, abstractPath, results);
                  } catch (InterruptedException e) {
                    PHPDebugPlugin.log(e);
                  }
                }
              }
            } else if (entry.getEntryKind() == IBuildpathEntry.BPE_VARIABLE) {
              entryPath = DLTKCore
                  .getResolvedVariablePath(entryPath);
              if (entryPath != null) {
                File entryDir = entryPath.toFile();
                find(entryDir, abstractPath, entry, results);
              }
            } else if (entry.getEntryKind() == IBuildpathEntry.BPE_CONTAINER) {

              try {
                if (projects.length == 0) {
                  continue;
                }
                final IProject currentProject = projects[0];
                final IScriptProject scriptProject = DLTKCore
                    .create(currentProject);

                IBuildpathContainer container = DLTKCore
                    .getBuildpathContainer(entry.getPath(),
                        scriptProject);
                if (container != null) {
                  IBuildpathEntry[] buildpathEntries = container
                      .getBuildpathEntries();
                  entryPath = EnvironmentPathUtils
                      .getLocalPath(buildpathEntries[0]
                          .getPath());
                  if (entryPath != null) {
                    find(entryPath.toFile(), abstractPath,
                        entry, results);
                  }

                }
              } catch (ModelException e) {
                PHPCorePlugin.log(e);
              }

            }
          }
        }

        // Iterate over all include path, and search for a requested
        // file
        for (IncludePath includePath : includePaths) {
          if (includePath.getEntry() instanceof IContainer) {
            try {
              find((IContainer) includePath.getEntry(),
                  abstractPath, results);
            } catch (InterruptedException e) {
              PHPDebugPlugin.log(e);
            }
          }
        }

        boolean foundInWorkspace = results.size() > 0;

        // search in opened editors
        searchOpenedEditors(results, abstractPath);

        if (!foundInWorkspace
            && results.size() == 1
            && abstractPath.equals(results.getFirst()
                .getAbstractPath())) {
          localFile[0] = results.getFirst();
        } else if (results.size() > 0) {
          Collections.sort(results, new BestMatchPathComparator(
              abstractPath));
          localFile[0] = filterItems(abstractPath,
              results.toArray(new PathEntry[results.size()]),
              debugTarget);
          if (localFile[0] != null) {
            if (localFile[0].getType() == Type.SERVER) {
              pathMapper.addServerEntry(remoteFile, localFile[0]);
              PathMapperRegistry.storeToPreferences();
              localFile[0] = null;
            } else {
              pathMapper.addEntry(remoteFile, localFile[0]);
              PathMapperRegistry.storeToPreferences();
            }
          }
        }
        return Status.OK_STATUS;
      }
    };

    findJob.schedule();
    try {
      findJob.join();
    } catch (InterruptedException e) {
    }

    return localFile[0];
  }

  private static void searchOpenedEditors(LinkedList<PathEntry> results,
      VirtualPath remotePath) {
    // Collect open editor references:
    List<IEditorReference> editors = new ArrayList<IEditorReference>(0);
    IWorkbench workbench = PlatformUI.getWorkbench();
    IWorkbenchWindow[] windows = workbench.getWorkbenchWindows();
    for (IWorkbenchWindow element : windows) {
      IWorkbenchPage[] pages = element.getPages();
      for (IWorkbenchPage element2 : pages) {
        IEditorReference[] references = element2.getEditorReferences();
        editors.addAll(Arrays.asList(references));
      }
    }

    // Collect external files opened in editors:
    for (IEditorReference editor : editors) {
      IEditorInput editorInput = null;
      try {
        editorInput = editor.getEditorInput();
      } catch (PartInitException e) {
        continue;
      }
      if (editorInput instanceof FileStoreEditorInput) {
        File file = new File(((IURIEditorInput) editorInput).getURI());
        if (file.exists()
            && file.getName().equalsIgnoreCase(
                remotePath.getLastSegment())) {
          results.add(new PathEntry(file.getAbsolutePath(),
              PathEntry.Type.EXTERNAL, file.getParentFile()));
        }
      }
    }
  }

  private static PathEntry filterItems(VirtualPath remotePath,
      PathEntry[] entries, IDebugTarget debugTarget) {

    IPathEntryFilter[] filters = initializePathEntryFilters();
    for (int i = 0; i < filters.length; ++i) {
      entries = filters[i].filter(entries, remotePath, debugTarget);
    }
    return entries.length > 0 ? entries[0] : null;
  }

  private static synchronized IPathEntryFilter[] initializePathEntryFilters() {
    if (filters == null) {
      Map<String, IPathEntryFilter> filtersMap = new HashMap<String, IPathEntryFilter>();
      IExtensionRegistry registry = Platform.getExtensionRegistry();
      IConfigurationElement[] elements = registry
          .getConfigurationElementsFor(PHPDebugPlugin.getID(),
              "pathEntryFilters"); //$NON-NLS-1$
      for (IConfigurationElement element : elements) {
        if ("filter".equals(element.getName())) { //$NON-NLS-1$
          String id = element.getAttribute("id"); //$NON-NLS-1$
          if (!filtersMap.containsKey(id)) {
            String overridesIds = element
                .getAttribute("overridesId"); //$NON-NLS-1$
            if (overridesIds != null) {
              StringTokenizer st = new StringTokenizer(
                  overridesIds, ", "); //$NON-NLS-1$
              while (st.hasMoreTokens()) {
                filtersMap.put(st.nextToken(), null);
              }
            }
            try {
              filtersMap.put(id, (IPathEntryFilter) element
                  .createExecutableExtension("class")); //$NON-NLS-1$
            } catch (CoreException e) {
              PHPDebugPlugin.log(e);
            }
          }
        }
      }
      Collection<IPathEntryFilter> l = filtersMap.values();
      while (l.remove(null))
        ; // remove null elements
      filters = l.toArray(new IPathEntryFilter[filtersMap.size()]);
    }
    return filters;
  }

  /**
   * Searches for the path in the given IO file
   *
   * @param file
   *            File to start search from
   * @param path
   *            Abstract path of the remote file
   * @param container
   *            Include path entry container
   * @param results
   *            List of results to return
   * @throws InterruptedException
   */
  private static void find(final File file, final VirtualPath path,
      final IBuildpathEntry container, final List<PathEntry> results) {
    if (!file.isDirectory() && file.getName().equals(path.getLastSegment())) {
      Type type = (container.getEntryKind() == IBuildpathEntry.BPE_VARIABLE) ? Type.INCLUDE_VAR
          : Type.INCLUDE_FOLDER;
      PathEntry pathEntry = new PathEntry(file.getAbsolutePath(), type,
          container);
      results.add(pathEntry);
      return;
    } else {
      File[] files = file.listFiles(PHP_FILTER);
      if (files != null) {
        for (int i = 0; i < files.length; ++i) {
          find(files[i], path, container, results);
        }
      }
    }
  }

  /**
   * Searches for the path in the given resource
   *
   * @param resource
   *            Resource to start the search from
   * @param path
   *            Abstract path of the remote file
   * @param results
   *            List of results to return
   * @throws InterruptedException
   */
  private static void find(final IResource resource, final VirtualPath path,
      final List<PathEntry> results) throws InterruptedException {
    if (resource == null || !resource.exists() || !resource.isAccessible()) {
      return;
    }
    WorkspaceJob findJob = new WorkspaceJob("") { //$NON-NLS-1$
      public IStatus runInWorkspace(IProgressMonitor monitor)
          throws CoreException {
        resource.accept(new IResourceVisitor() {
          public boolean visit(IResource resource)
              throws CoreException {
            if (!resource.isAccessible()) {
              return false;
            }
            if (resource instanceof IFile
                && resource.getName().equals(
                    path.getLastSegment())) {
              PathEntry pathEntry = new PathEntry(resource
                  .getFullPath().toString(), Type.WORKSPACE,
                  resource.getParent());
              results.add(pathEntry);
            }
            return true;
          }
        });
        return Status.OK_STATUS;
      }
    };
    findJob.schedule();
    findJob.join();
  }

  private static class PHPFilenameFilter implements FileFilter,
      IContentTypeChangeListener {
    private Pattern phpFilePattern;

    public PHPFilenameFilter() {
      buildPHPFilePattern();
      Platform.getContentTypeManager().addContentTypeChangeListener(this);
    }

    private void buildPHPFilePattern() {
      IContentType type = Platform.getContentTypeManager()
          .getContentType(ContentTypeIdForPHP.ContentTypeID_PHP);
      String[] phpExtensions = type
          .getFileSpecs(IContentType.FILE_EXTENSION_SPEC);
      StringBuilder buf = new StringBuilder();
      buf.append(".*\\.("); //$NON-NLS-1$
      for (int i = 0; i < phpExtensions.length; ++i) {
        if (i > 0) {
          buf.append("|"); //$NON-NLS-1$
        }
        buf.append(phpExtensions[i]);
      }
      buf.append(')');
      phpFilePattern = Pattern.compile(buf.toString(),
          Pattern.CASE_INSENSITIVE);
    }

    public void contentTypeChanged(ContentTypeChangeEvent event) {
      buildPHPFilePattern();
    }

    public boolean accept(File pathname) {
      if (pathname.isDirectory()
          || phpFilePattern.matcher(pathname.getName()).matches()) {
        return true;
      }
      return false;
    }
  }

}
TOP

Related Classes of org.eclipse.php.internal.debug.core.pathmapper.DebugSearchEngine$PHPFilenameFilter

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.