/******************************************************************************* * Copyright (c) 2005 Business Objects Software Limited and others. * All rights reserved. * This file is 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: * Business Objects Software Limited - initial API and implementation *******************************************************************************/ /* * EclipseProgramResourcePathRepository.java * Creation date: Dec 13, 2005. * By: Edward Lam */ package org.openquark.cal.eclipse.core; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.Set; 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.IStorage; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.IWorkspaceRunnable; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IPackageFragment; import org.eclipse.jdt.internal.core.JarEntryFile; import org.openquark.cal.compiler.ModuleName; import org.openquark.cal.eclipse.core.builder.ICALResourceContainer; import org.openquark.cal.eclipse.core.util.Util; import org.openquark.cal.machine.AsynchronousFileWriter; import org.openquark.cal.machine.ProgramResourceLocator; import org.openquark.cal.machine.ProgramResourceRepository; import org.openquark.cal.runtime.MachineType; /* * For now, this is just the same as a BasicProgramResourcePathRepository. * This will have to change if there is the possibility that runtime files are included precompiled. * * One problem with a potential change would be that Eclipse really assumes that the files in the plugin are static. * For performance reasons, Eclipse's classloader caches class-finding info between calls to findClass(). * This means that any changes to the files in the nullary workspace might cause classloader * finding of files to return incorrect results. * Trace through org.eclipse.osgi.framework.internal.core.BundleLoader.findClass() for details. */ /** * A repository of program resources in the eclipse environment. * * This class grabs resources out of the lecc_runtime directory * * @author Edward Lam */ public class EclipseProgramResourcePathRepository implements ProgramResourceRepository { /* * TODOEL: we might want the program resource output to go into a user-specified folder, * just as .java files can be specified as having .class file output to a bin/ folder. */ /** * @return a provider for a program resource finder associated with the workspace. */ public static ProgramResourceRepository.Provider getResourceRepositoryProvider() { return new ProgramResourceRepository.Provider() { public ProgramResourceRepository getRepository(MachineType machineType) { return new EclipseProgramResourcePathRepository(); } }; } /** * Constructor for a EclipseProgramResourcePathRepository. * Private -- obtain via the repository provider. */ private EclipseProgramResourcePathRepository() { } /** * @return the workspace. */ private static IWorkspace getWorkspace() { return ResourcesPlugin.getWorkspace(); } /** * {@inheritDoc} */ public InputStream getContents(ProgramResourceLocator.File fileLocator) throws IOException { IStorage inputFile = getProgramResource(fileLocator); if (inputFile == null) { return null; } try { return inputFile.getContents(); } catch (CoreException e) { throw (IOException)(new IOException()).initCause(e); } } /** * {@inheritDoc} * Only sets the contents if this is a file, not a Jar entry */ public void setContents(ProgramResourceLocator.File fileLocator, InputStream source) throws IOException { IStorage output = getProgramResource(fileLocator); if (output instanceof IFile) { // Handle null source. if (source == null) { source = new ByteArrayInputStream(new byte[0]); } IFile outputFile = (IFile) output; try { if (outputFile.exists()) { // source, force, keepHistory, progressMonitor outputFile.setContents(source, true, false, null); } else { // walk up the parent folders and ensure they all exist IFolder folder = (IFolder) outputFile.getParent(); EclipseFileResourceHelper.ensureFolderExists(folder); // source, force, monitor outputFile.create(source, true, null); } } catch (CoreException e) { throw (IOException)(new IOException()).initCause(e); } } else { Util.log(new Exception(), "Attempt to write to an unwritable resource: " + output, IStatus.WARNING); } } /** * {@inheritDoc} * If the specified folder is in a jar file, then this request is ignored */ public void ensureFolderExists(ProgramResourceLocator.Folder folderLocator) throws IOException { IFolder folder = getIFolder(folderLocator); if (folder != null) { EclipseFileResourceHelper.ensureFolderExists(folder); } else { Util.log(new Exception(), "Attempt to create a folder in a jar file: " + folderLocator, IStatus.WARNING); } } /** * {@inheritDoc} */ public void delete(ProgramResourceLocator resourceLocator) throws IOException { IResource resourceToDelete = getIResource(resourceLocator); if (resourceToDelete != null) { try { // force, progressMonitor resourceToDelete.delete(true, null); } catch (CoreException e) { // Couldn't delete for some reason. Util.log(new IOException().initCause(e), "Couldn't delete " + resourceLocator); } } } /** * may return null if resourceLocator points to somewhere in a jar * @param resourceLocator * @return the corresponding IResource if any */ private IResource getIResource(ProgramResourceLocator resourceLocator) { if (resourceLocator instanceof ProgramResourceLocator.File) { IStorage storage = getProgramResource((ProgramResourceLocator.File) resourceLocator); if (storage instanceof IFile) { return (IFile) storage; } else { return null; } } else { return getIFolder((ProgramResourceLocator.Folder) resourceLocator); } } /** * {@inheritDoc} */ public void delete(final ProgramResourceLocator[] resourceLocators) throws IOException { try { // Batch together in a workspace runnable so that only one update is sent. getWorkspace().run(new IWorkspaceRunnable() { public void run(IProgressMonitor monitor) throws CoreException { for (final ProgramResourceLocator resourceLocator : resourceLocators) { IResource resource = getIResource(resourceLocator); if (resource != null) { resource.delete(true, null); } } } }, null); } catch (CoreException e) { // The operation failed for some reason. throw (IOException)(new IOException()).initCause(e); } } /** * {@inheritDoc} */ public boolean exists(ProgramResourceLocator resourceLocator) { if (resourceLocator instanceof ProgramResourceLocator.File) { ProgramResourceLocator.File fileLocator = (ProgramResourceLocator.File) resourceLocator; IStorage storage = getProgramResource(fileLocator); if (storage == null) { return false; } else { return storage instanceof JarEntryFile || ((IFile) storage).exists(); } } else { ProgramResourceLocator.Folder folderLocator = (ProgramResourceLocator.Folder) resourceLocator; IFolder folder = getIFolder(folderLocator); return folder != null && folder.exists(); } } /** * {@inheritDoc} */ public long lastModified(ProgramResourceLocator resourceLocator) { IResource resource = getIResource(resourceLocator); if (resource != null) { return resource.getLocalTimeStamp(); } else { // ADE warning...slow! ICALResourceContainer inputContainer = CALModelManager.getCALModelManager(). getInputSourceFileContainer(resourceLocator.getModuleName()); return inputContainer.getTimeStamp(); } } /** * {@inheritDoc} */ public ProgramResourceLocator[] getMembers(ProgramResourceLocator.Folder folder) { IResource[] resources; try { // TODOEL: There are three functions named members(). Is this the right one? resources = getIFolder(folder).members(); } catch (CoreException e) { // Doesn't exist, or project isn't open. return null; } // The locators to return. ProgramResourceLocator[] folderFileLocators = new ProgramResourceLocator[resources.length]; // Iterate over the resource members. for (int i = 0; i < resources.length; i++) { IResource ithResource = resources[i]; String nthFileName = ithResource.getName(); int resourceType = ithResource.getType(); if (resourceType == IResource.FOLDER) { folderFileLocators[i] = folder.extendFolder(nthFileName); } else if (resourceType == IResource.FILE) { folderFileLocators[i] = folder.extendFile(nthFileName); } else { throw new IllegalStateException(); } } return folderFileLocators; } /** * {@inheritDoc} */ public File getFile(ProgramResourceLocator resourceLocator) { IResource resource = getIResource(resourceLocator); if (resource != null) { return new File(resource.getLocation().toOSString()); } else { return null; } } /** * This will return null for resourceLocators in car-jars * @param resourceLocator the locator for a folder resource. * @return the folder resource indicated by the locator. */ private IFolder getIFolder(ProgramResourceLocator.Folder resourceLocator) { ICALResourceContainer inputFolder = CALModelManager.getCALModelManager().getInputSourceFileContainer(resourceLocator.getModuleName()); if (inputFolder != null) { IPackageFragment frag = inputFolder.getProgramFolder(resourceLocator, false); IResource resource = frag.getResource(); if (resource instanceof IFolder) { return (IFolder)resource; } } return null; } /** * @param resourceLocator the locator for a resource. * @return the resource indicated by the locator. * Null if the resource does not exist. */ private IStorage getProgramResource(ProgramResourceLocator.File resourceLocator) { // Get the path to the module base folder, relative to the workspace root. ICALResourceContainer inputFolder = CALModelManager.getCALModelManager(). getInputSourceFileContainer(resourceLocator.getModuleName()); if (inputFolder == null) { // TODOEL should we default to some folder? // We probably should not be asking for a resource from a module for which we don't have source. return null; } return inputFolder.getProgramResource(resourceLocator, false); } /** * {@inheritDoc} */ public boolean isEmpty() { // Iterate over the projects in the workspace. IProject[] projects = getWorkspace().getRoot().getProjects(); for (final IProject project : projects) { // only look at CAL projects IJavaProject javaProject = Util.getCalProject(project); if (javaProject != null) { // Iterate over the input folders in the project. ICALResourceContainer[] inputFolders = CALModelManager.getCALModelManager().getInputFolders(javaProject); for (final ICALResourceContainer inputFolder : inputFolders) { if (!inputFolder.getCALSources().isEmpty()) { return false; } } } } // No projects have an input folder parent with a non-empty base resource folder. return true; } /** * {@inheritDoc} */ public long getSize(ProgramResourceLocator.File fileLocator) { /* * IFile doesn't provide a direct way to find the length of a file. * So first convert to a File, and get the length of that. * This only works if there is a corresponding java.io.File, so it doesn't work when a file is derived or not real in some other sense. * * IFile.length() returns 0L when there is no corresponding java.io.File -- this is ok. */ File file = getFile(fileLocator); if (file != null) { return file.length(); } else { return 0; } } /** * {@inheritDoc} */ public ModuleName[] getModules() { Set<ModuleName> moduleNames = CALModelManager.getCALModelManager().getModuleNames(); return moduleNames.toArray(new ModuleName[moduleNames.size()]); } /** * {@inheritDoc} */ public String getLocationString() { // Return the path to the root of the workspace. This is probably the best we can do.. return getWorkspace().getRoot().getFullPath().toOSString(); } /** * {@inheritDoc} */ public String getDebugInfo(org.openquark.cal.machine.ProgramResourceLocator.File fileLocator) { IStorage inputFile = getProgramResource(fileLocator); if (inputFile == null) { return null; } else { return "from Eclipse file: " + inputFile.getName(); } } /** * {@inheritDoc} */ public AsynchronousFileWriter getAsynchronousFileWriter() { return new EclipseAsynchronousFileWriter(this); } }