/* * Created on Jan 29, 2005 * */ package org.rubypeople.rdt.internal.core; import java.io.File; import java.util.ArrayList; import java.util.HashSet; import java.util.Map; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Path; import org.rubypeople.rdt.core.IOpenable; import org.rubypeople.rdt.core.IRubyElement; import org.rubypeople.rdt.core.IRubyModel; import org.rubypeople.rdt.core.IRubyProject; import org.rubypeople.rdt.core.RubyModelException; import org.rubypeople.rdt.core.WorkingCopyOwner; import org.rubypeople.rdt.internal.core.util.MementoTokenizer; import org.rubypeople.rdt.internal.core.util.Messages; /** * @author Chris * */ public class RubyModel extends Openable implements IRubyModel { /** * A set of java.io.Files used as a cache of external jars that * are known to be existing. * Note this cache is kept for the whole session. */ public static HashSet<File> existingExternalFiles = new HashSet<File>(); /** * A set of external files ({@link #existingExternalFiles}) which have * been confirmed as file (ie. which returns true to {@link java.io.File#isFile()}. * Note this cache is kept for the whole session. */ public static HashSet existingExternalConfirmedFolders = new HashSet(); protected RubyModel() { super(null); } /** * Flushes the cache of external files known to be existing. */ public static void flushExternalFileCache() { existingExternalFiles = new HashSet<File>(); existingExternalConfirmedFolders = new HashSet(); } /** * Returns a new element info for this element. */ protected Object createElementInfo() { return new RubyModelInfo(); } public boolean equals(Object o) { if (!(o instanceof RubyModel)) return false; return super.equals(o); } /** * @see IRubyModel */ public Object[] getNonRubyResources() throws RubyModelException { return ((RubyModelInfo) getElementInfo()).getNonRubyResources(); } /** * Finds the given project in the list of the java model's children. Returns * null if not found. */ public IRubyProject findRubyProject(IProject project) { try { IRubyProject[] projects = this.getRubyProjects(); for (int i = 0, length = projects.length; i < length; i++) { IRubyProject rubyProject = projects[i]; if (project.equals(rubyProject.getProject())) { return rubyProject; } } } catch (RubyModelException e) { // ruby model doesn't exist: cannot find any project } return null; } /* * (non-Javadoc) * * @see org.rubypeople.rdt.core.IRubyElement#getElementType() */ public int getElementType() { return IRubyElement.RUBY_MODEL; } /* * @see IRubyElement */ public IPath getPath() { return Path.ROOT; } /* * (non-Javadoc) * * @see org.rubypeople.rdt.core.IRubyElement#getResource() */ public IResource getResource() { return ResourcesPlugin.getWorkspace().getRoot(); } /** * @see IOpenable */ public IResource getUnderlyingResource() { return null; } /** * Returns the workbench associated with this object. */ public IWorkspace getWorkspace() { return ResourcesPlugin.getWorkspace(); } /** * @see IRubyModel */ public IRubyProject[] getRubyProjects() throws RubyModelException { ArrayList list = getChildrenOfType(RUBY_PROJECT); IRubyProject[] array = new IRubyProject[list.size()]; list.toArray(array); return array; } protected boolean buildStructure(OpenableElementInfo info, IProgressMonitor pm, Map newElements, IResource underlyingResource) { // determine my children IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); for (int i = 0, max = projects.length; i < max; i++) { IProject project = projects[i]; if (RubyProject.hasRubyNature(project)) { info.addChild(getRubyProject(project)); } } newElements.put(this, info); return true; } /** * Returns the active Ruby project associated with the specified resource, * or <code>null</code> if no Ruby project yet exists for the resource. * * @exception IllegalArgumentException * if the given resource is not one of an IProject, IFolder, * or IFile. */ public IRubyProject getRubyProject(IResource resource) { switch (resource.getType()) { case IResource.FOLDER: return new RubyProject(((IFolder) resource).getProject(), this); case IResource.FILE: return new RubyProject(((IFile) resource).getProject(), this); case IResource.PROJECT: return new RubyProject((IProject) resource, this); default: throw new IllegalArgumentException(Messages.bind(Messages.element_invalidResourceForProject)); } } /** * @see IRubyModel */ public IRubyProject getRubyProject(String projectName) { return new RubyProject(ResourcesPlugin.getWorkspace().getRoot().getProject(projectName), this); } /** * Helper method - returns the targeted item (IResource if internal or java.io.File if external), * or null if unbound * Internal items must be referred to using container relative paths. */ public static Object getTarget(IPath path, boolean checkResourceExistence) { Object target = getWorkspaceTarget(path); // Implicitly checks resource existence if (target != null) return target; return getExternalTarget(path, checkResourceExistence); } public static IResource getWorkspaceTarget(IPath path) { if (path == null || path.getDevice() != null) return null; IWorkspace workspace = ResourcesPlugin.getWorkspace(); if (workspace == null) return null; return workspace.getRoot().findMember(path); } public static Object getExternalTarget(IPath path, boolean checkResourceExistence) { if (path == null) return null; File externalFile = new File(path.toOSString()); Object linkedFolder = getFolder(externalFile); if (linkedFolder != null) { if (checkResourceExistence) { // check if external folder is present if (!externalFile.exists()) { return null; } } return linkedFolder; } if (!checkResourceExistence) { return externalFile; } else if (existingExternalFilesContains(externalFile)) { return externalFile; } else { if (RubyModelManager.ZIP_ACCESS_VERBOSE) { System.out.println("(" + Thread.currentThread() + ") [RubyModel.getTarget(...)] Checking existence of " + path.toString()); //$NON-NLS-1$ //$NON-NLS-2$ } if (externalFile.isFile()) { // isFile() checks for existence (it returns false if a directory) // cache external file existingExternalFilesAdd(externalFile); return externalFile; } } return null; } private synchronized static void existingExternalFilesAdd(File externalFile) { existingExternalFiles.add(externalFile); } private synchronized static boolean existingExternalFilesContains(File externalFile) { return existingExternalFiles.contains(externalFile); } /** * Helper method - returns whether an object is a file (ie. which returns true to {@link java.io.File#isFile()}. */ public static boolean isFolder(Object target) { return getFolder(target) != null; } /** * Helper method - returns the file item (ie. which returns true to {@link java.io.File#isFile()}, * or null if unbound */ public static synchronized File getFolder(Object target) { if (existingExternalConfirmedFolders.contains(target)) return (File) target; if (target instanceof File) { File f = (File) target; if (f.isDirectory()) { existingExternalConfirmedFolders.add(f); return f; } } return null; } /* * @see RubyElement */ public IRubyElement getHandleFromMemento(String token, MementoTokenizer memento, WorkingCopyOwner owner) { switch (token.charAt(0)) { case JEM_RUBYPROJECT: if (!memento.hasMoreTokens()) return this; String projectName = memento.nextToken(); RubyElement project = (RubyElement)getRubyProject(projectName); return project.getHandleFromMemento(memento, owner); } return null; } /** * @see RubyElement#getHandleMemento(StringBuffer) */ protected void getHandleMemento(StringBuffer buff) { buff.append(getElementName()); } /** * Returns the <code>char</code> that marks the start of this handles * contribution to a memento. */ protected char getHandleMementoDelimiter(){ Assert.isTrue(false, "Should not be called"); //$NON-NLS-1$ return 0; } /* * @see IRubyModel */ public boolean contains(IResource resource) { switch (resource.getType()) { case IResource.ROOT: case IResource.PROJECT: return true; } // file or folder IRubyProject[] projects; try { projects = this.getRubyProjects(); } catch (RubyModelException e) { return false; } for (int i = 0, length = projects.length; i < length; i++) { RubyProject project = (RubyProject)projects[i]; if (!project.contains(resource)) { return false; } } return true; } /** * @see IRubyModel#refreshExternalArchives(IRubyElement[], IProgressMonitor) */ public void refreshExternalArchives(IRubyElement[] elementsScope, IProgressMonitor monitor) throws RubyModelException { if (elementsScope == null){ elementsScope = new IRubyElement[] { this }; } RubyModelManager.getRubyModelManager().getDeltaProcessor().checkExternalArchiveChanges(elementsScope, monitor); } }