package org.rubypeople.rdt.internal.core.search; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.rubypeople.rdt.core.IRubyProject; import org.rubypeople.rdt.core.IRubyScript; import org.rubypeople.rdt.core.ISourceFolder; import org.rubypeople.rdt.core.ISourceFolderRoot; import org.rubypeople.rdt.core.RubyCore; import org.rubypeople.rdt.internal.core.Openable; import org.rubypeople.rdt.internal.core.RubyModel; import org.rubypeople.rdt.internal.core.RubyModelManager; import org.rubypeople.rdt.internal.core.SourceFolderRoot; import org.rubypeople.rdt.internal.core.util.CharOperation; import org.rubypeople.rdt.internal.core.util.HashtableOfArrayToObject; import org.rubypeople.rdt.internal.core.util.Util; public class HandleFactory { /** * Cache package fragment root information to optimize speed performance. */ private String lastSrcFolderRootPath; private ISourceFolderRoot lastSrcFolderRoot; /** * Cache package handles to optimize memory. */ private HashtableOfArrayToObject folderHandles; private RubyModel rubyModel; public HandleFactory() { this.rubyModel = RubyModelManager.getRubyModelManager().getRubyModel(); } /** * Returns the source folder root that contains the given resource path. */ private ISourceFolderRoot getSourceFolderRoot(String pathString) { IPath path = new Path(pathString); IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); for (int i = 0, max = projects.length; i < max; i++) { try { IProject project = projects[i]; if (!project.isAccessible() || !project.hasNature(RubyCore.NATURE_ID)) continue; IRubyProject rubyProject = this.rubyModel.getRubyProject(project); ISourceFolderRoot[] roots = rubyProject.getSourceFolderRoots(); for (int j = 0, rootCount = roots.length; j < rootCount; j++) { SourceFolderRoot root = (SourceFolderRoot) roots[j]; if (root.getPath().isPrefixOf(path) && !Util.isExcluded(path, root.fullInclusionPatternChars(), root.fullExclusionPatternChars(), false)) { return root; } } } catch (CoreException e) { // CoreException from hasNature - should not happen since we // check that the project is accessible // RubyModelException from getPackageFragmentRoots - a problem // occured while accessing project: nothing we can do, ignore } } return null; } /** * Creates an Openable handle from the given resource path. The resource * path can be a path to a file in the workbench. */ public Openable createOpenable(String resourcePath) { // path to a file in a directory // Optimization: cache source folder root handle and package handles int rootPathLength = -1; if (this.lastSrcFolderRootPath == null || !(resourcePath.startsWith(this.lastSrcFolderRootPath) && (rootPathLength = this.lastSrcFolderRootPath.length()) > 0 && resourcePath.charAt(rootPathLength) == '/')) { ISourceFolderRoot root = this.getSourceFolderRoot(resourcePath); if (root == null) return null; // match is outside loadpath this.lastSrcFolderRoot = root; this.lastSrcFolderRootPath = this.lastSrcFolderRoot.getPath().toString(); this.folderHandles = new HashtableOfArrayToObject(5); } // create handle resourcePath = resourcePath.substring(this.lastSrcFolderRootPath.length() + 1); String[] simpleNames = new Path(resourcePath).segments(); String[] pkgName; int length = simpleNames.length - 1; if (length > 0) { pkgName = new String[length]; System.arraycopy(simpleNames, 0, pkgName, 0, length); } else { pkgName = CharOperation.NO_STRINGS; } ISourceFolder pkgFragment = (ISourceFolder) this.folderHandles.get(pkgName); if (pkgFragment == null) { pkgFragment = ((SourceFolderRoot) this.lastSrcFolderRoot).getSourceFolder(pkgName); this.folderHandles.put(pkgName, pkgFragment); } String simpleName = simpleNames[length]; if (org.rubypeople.rdt.internal.core.util.Util.isRubyOrERBLikeFileName(simpleName)) { IRubyScript unit = pkgFragment.getRubyScript(simpleName); return (Openable) unit; } return null; } }