| /* |
| * Copyright (c) 2006, 2009 Borland Software Corporation |
| * 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: |
| * Artem Tikhomirov (Borland) |
| * Boris Blajer (Borland) - support for composite resources |
| */ |
| package org.eclipse.gmf.internal.xpand.build; |
| |
| import java.io.FileNotFoundException; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.Reader; |
| import java.net.URL; |
| import java.util.ArrayList; |
| import java.util.LinkedList; |
| import java.util.List; |
| |
| import org.eclipse.core.resources.IContainer; |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IResource; |
| 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.eclipse.core.runtime.Platform; |
| import org.eclipse.gmf.internal.xpand.inactive.StreamDecoder; |
| import org.eclipse.gmf.internal.xpand.model.XpandResource; |
| import org.eclipse.gmf.internal.xpand.util.BundleUnitResolver; |
| import org.eclipse.gmf.internal.xpand.util.ParserException; |
| import org.eclipse.gmf.internal.xpand.util.ResourceManagerImpl; |
| import org.eclipse.gmf.internal.xpand.util.StreamConverter; |
| import org.eclipse.gmf.internal.xpand.util.TypeNameUtil; |
| import org.eclipse.m2m.internal.qvt.oml.compiler.UnitResolver; |
| import org.eclipse.m2m.internal.qvt.oml.project.builder.WorkspaceUnitResolver; |
| import org.osgi.framework.Bundle; |
| |
| // FIXME package-local?, refactor Activator.getResourceManager uses |
| public class WorkspaceResourceManager extends ResourceManagerImpl { |
| |
| private static final IPath[] EMPTY_PATH = new IPath[0]; |
| |
| private final IProject contextProject; |
| private final IPath[] myConfiguredRoots; |
| |
| /** |
| * Fall-back constructor can be used for stand alone XPand resources |
| */ |
| public WorkspaceResourceManager(IProject context) { |
| this(context, EMPTY_PATH); |
| } |
| |
| public WorkspaceResourceManager(IProject context, IPath[] configuredRoots) { |
| this.contextProject = context; |
| myConfiguredRoots = configuredRoots; |
| } |
| |
| public XpandResource loadXpandResource(IFile file) throws CoreException, IOException, ParserException { |
| String fullyQualifiedName; |
| if (file == null || (fullyQualifiedName = toFullyQualifiedName(file)) == null) { |
| return null; |
| } |
| // try file directly, to get IO/Parse exceptions, if any. |
| Reader r = new StreamConverter().toContentsReader(file); |
| XpandResource[] loadXpandResources = loadXpandResources(new Reader[] { r }, fullyQualifiedName); |
| assert loadXpandResources.length == 1 && loadXpandResources[0] != null; |
| return loadXpandResources[0]; |
| } |
| |
| @Override |
| protected void handleParserException(ParserException ex) { |
| // may get here only when some referenced template/xtend file is |
| // broken. Since it's expected to get compiled anyway (either prior |
| // to compilation of its use or afterwards), error messages should get |
| // into problems view sooner or later. |
| } |
| |
| @Override |
| protected boolean shouldCache() { |
| /* |
| * WorkspanceResourceManager was refactored to cache all resources. |
| * |
| * From now this resource manager should be: |
| * |
| * 1. created |
| * |
| * 2. used during the session of compilation/code completion |
| * |
| * 3. forgotten to free corresponding memory resources. |
| */ |
| return true; |
| } |
| |
| public void forget(IFile resource) { |
| // implement when caching |
| } |
| |
| @Override |
| protected Reader[] resolveMultiple(String fqn, String ext) throws IOException { |
| IPath fp = new Path(fqn.replaceAll(TypeNameUtil.NS_DELIM, "/")).addFileExtension(ext); |
| IPath[] resolutions = getResolutions(fp); |
| ArrayList<Reader> result = new ArrayList<Reader>(resolutions.length); |
| for (IPath p : getResolutions(fp)) { |
| Reader nextReader = getReader(p); |
| if (nextReader != null) { |
| result.add(nextReader); |
| } |
| } |
| if (result.isEmpty()) { |
| throw new FileNotFoundException(fp.toString()); |
| } |
| return result.toArray(new Reader[result.size()]); |
| } |
| |
| private Reader getReader(IPath p) throws IOException { |
| if (p.isAbsolute()) { |
| assert p.segmentCount() > 1; |
| //Try workspace-relative first. |
| IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(p.segment(0)); |
| if (project.isAccessible()) { |
| return getWorkspaceFileReader(project, p.removeFirstSegments(1)); |
| } |
| //Fallback to platform location |
| Bundle platformBundle = Platform.getBundle(p.segment(0)); |
| if (platformBundle != null) { |
| URL url = platformBundle.getEntry(p.removeFirstSegments(1).toString()); |
| if (url != null) { |
| InputStream is = url.openStream(); |
| // FIXME for now, go with legacy encoding as a default |
| return new StreamDecoder(is, StreamDecoder.LEGACY_ENCODING).getReader(); |
| } |
| } |
| } else { |
| return getWorkspaceFileReader(contextProject, p); |
| } |
| return null; |
| } |
| |
| private Reader getWorkspaceFileReader(IProject project, IPath path) throws IOException { |
| IResource r = project.findMember(path); |
| if (r instanceof IFile) { |
| try { |
| return new StreamConverter().toContentsReader((IFile) r); |
| } catch (CoreException ex) { |
| IOException wrap = new IOException(ex.getStatus().getMessage()); |
| wrap.initCause(ex); |
| throw wrap; |
| } |
| } |
| return null; |
| } |
| |
| private IPath[] getResolutions(IPath p) { |
| IPath[] rv = new IPath[myConfiguredRoots.length]; |
| for (int i = 0; i < myConfiguredRoots.length; i++) { |
| rv[i] = myConfiguredRoots[i].append(p); |
| } |
| return rv; |
| } |
| private String toFullyQualifiedName(IFile file) { |
| for (IPath nextRoot : myConfiguredRoots) { |
| if (!nextRoot.isAbsolute()) { |
| if (file.getProject().equals(contextProject) && nextRoot.isPrefixOf(file.getProjectRelativePath())) { |
| return toFullyQualifiedName(file.getProjectRelativePath().removeFirstSegments(nextRoot.segmentCount())); |
| } |
| } else { |
| if (nextRoot.isPrefixOf(file.getFullPath())) { |
| return toFullyQualifiedName(file.getFullPath().removeFirstSegments(nextRoot.segmentCount())); |
| } |
| } |
| } |
| return null; |
| } |
| |
| private static String toFullyQualifiedName(IPath filePath) { |
| return filePath.removeFileExtension().toString().replace("/", TypeNameUtil.NS_DELIM); |
| } |
| |
| @Override |
| protected String resolveCFileFullPath(String fullyQualifiedName, String fileExtension) { |
| IPath fp = new Path(fullyQualifiedName.replaceAll(TypeNameUtil.NS_DELIM, "/")).addFileExtension(fileExtension); |
| IPath[] resolutions = getResolutions(fp); |
| for (IPath resolvedPath : resolutions) { |
| IFile file = resolvedPath.isAbsolute() ? ResourcesPlugin.getWorkspace().getRoot().getFile(resolvedPath) : contextProject.getFile(resolvedPath); |
| if (file.exists()) { |
| return file.getLocation().toOSString(); |
| } |
| } |
| // TODO: use file located in main Path in this case? |
| return fullyQualifiedName + "." + fileExtension; |
| } |
| |
| @Override |
| protected UnitResolver getQVTUnitResolver() { |
| List<URL> bundleRootURLs = new ArrayList<URL>(); |
| for (IPath rootPath : myConfiguredRoots) { |
| if (rootPath.isAbsolute()) { |
| if (!rootPath.hasTrailingSeparator()) { |
| rootPath = rootPath.addTrailingSeparator(); |
| } |
| Bundle platformBundle = Platform.getBundle(rootPath.segment(0)); |
| if (platformBundle != null) { |
| URL url = platformBundle.getEntry(rootPath.removeFirstSegments(1).toString()); |
| if (url != null) { |
| bundleRootURLs.add(url); |
| } |
| } |
| } |
| } |
| |
| final UnitResolver bundleDelegate = BundleUnitResolver.createResolver(bundleRootURLs, true); |
| |
| List<IContainer> resolverPaths = new LinkedList<IContainer>(); |
| for (IPath rootPath : myConfiguredRoots) { |
| if(!rootPath.isAbsolute()) { |
| rootPath = contextProject.getFullPath().append(rootPath); |
| } |
| |
| IResource member = ResourcesPlugin.getWorkspace().getRoot().findMember(rootPath); |
| if (member != null && (member instanceof IContainer)) { |
| IContainer container = (IContainer) member; |
| if (container.exists()) { |
| resolverPaths.add(container); |
| } |
| } |
| } |
| return new WorkspaceUnitResolver(resolverPaths) { |
| @Override |
| protected UnitResolver getParent() { |
| return bundleDelegate; |
| } |
| }; |
| } |
| } |