/******************************************************************************* * Copyright (c) 2007 IBM 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: * Robert Fuhrer (rfuhrer@watson.ibm.com) - initial API and implementation *******************************************************************************/ package org.eclipse.imp.model; import java.util.HashMap; import java.util.Map; import org.eclipse.core.resources.IContainer; 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.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.imp.core.ErrorHandler; import org.eclipse.imp.language.Language; import org.eclipse.imp.language.LanguageRegistry; import org.eclipse.imp.model.IPathEntry.PathEntryType; import org.eclipse.imp.model.internal.CompilationUnitRef; import org.eclipse.imp.model.internal.PathEntry; import org.eclipse.imp.model.internal.SourceFolder; import org.eclipse.imp.model.internal.SourceProject; import org.eclipse.imp.model.internal.WorkspaceModel; import org.eclipse.jface.text.IDocument; import org.eclipse.ui.editors.text.TextFileDocumentProvider; /** * A factory for implementations of the various common model interfaces, e.g., ISourceProject, * ICompilationUnit, and so on. * @author rfuhrer */ public class ModelFactory { public class ModelException extends Exception { private static final long serialVersionUID= -1051581958821533299L; public ModelException() { super(); } public ModelException(String message) { super(message); } public ModelException(String message, Throwable cause) { super(message, cause); } public ModelException(Throwable cause) { super(cause); } } public static final String NO_SUCH_ELEMENT= "No such element: "; public static final String ELEMENT_ALREADY_EXISTS= "Element already exists: "; private static ModelFactory sInstance= new ModelFactory(); public static ModelFactory getInstance() { return sInstance; } /** * Implementations of this interface, once registered, can augment the model entities * created by the factory before they are returned to the client.<br> * This provides a mechanism for language-specific customization of core model entity * properties. E.g, the project's search path can be augmented based on a global * language-specific preference setting. */ // TODO Implementations of this interface should probably be provided via an extension point public interface IFactoryExtender { /** * This method gets called for the extender corresponding to each language nature * configured on the given project. */ void extend(ISourceProject project); /** * This method gets called only for the extender of the "host language" contained * within the given compilation unit (i.e. for the language to which the associated * content type maps). */ void extend(ICompilationUnit unit); } private ModelFactory() {} private IWorkspaceModel fModelRoot= new WorkspaceModel(ResourcesPlugin.getWorkspace().getRoot()); private Map<IProject, ISourceProject> fProjectMap= new HashMap<IProject, ISourceProject>(); private Map<Language, IFactoryExtender> fExtenderMap= new HashMap<Language, IFactoryExtender>(); public void installExtender(IFactoryExtender extender, Language language) { fExtenderMap.put(language, extender); } public static IWorkspaceModel getModelRoot() { return getInstance().fModelRoot; } // public static IWorkspaceModel open(IWorkspaceRoot wsRoot) throws ModelException { // return getInstance().doOpen(wsRoot); // } // // private IWorkspaceModel doOpen(IWorkspaceRoot wsRoot) throws ModelException { // if (!wsRoot.exists()) // throw new ModelException(NO_SUCH_ELEMENT); // // return new WorkspaceModel(wsRoot); // } public static ISourceProject open(IProject project) throws ModelException { return getInstance().doOpen(project); } private ISourceProject doOpen(IProject project) throws ModelException { if (!project.exists()) throw new ModelException(NO_SUCH_ELEMENT); ISourceProject sp= fProjectMap.get(project); if (sp == null) { fProjectMap.put(project, sp= new SourceProject(project)); // Find each language nature configured on the underlying project, find the // corresponding factory extender, and invoke it before returning the project. try { String[] natures= project.getDescription().getNatureIds(); for(int i= 0; i < natures.length; i++) { String natureID= natures[i]; Language lang= LanguageRegistry.findLanguageByNature(natureID); if (lang != null) { IFactoryExtender ext= fExtenderMap.get(lang); if (ext != null) { ext.extend(sp); } } } } catch (CoreException e) { ErrorHandler.reportError(e.getMessage()); } } return sp; } // TODO needs a progress monitor public static ISourceProject create(IProject project) throws ModelException { return getInstance().doCreate(project); } // TODO needs a progress monitor private ISourceProject doCreate(IProject project) throws ModelException { throw new ModelException(ELEMENT_ALREADY_EXISTS); } public static ISourceEntity open(IContainer container) throws ModelException { return getInstance().doOpen(container); } public static ISourceEntity open(IResource resource) throws ModelException { if (resource instanceof IContainer) { return getInstance().doOpen((IContainer) resource); } else if (resource instanceof IFile) { ISourceProject srcProject= getInstance().doOpen(resource.getProject()); return getInstance().doOpen((IFile) resource, srcProject); } return null; } private ISourceEntity doOpen(IContainer container) throws ModelException { if (container instanceof IProject) { return doOpen((IProject) container); } else if (container instanceof IFolder) { return doOpen((IFolder) container); } else if (container instanceof IWorkspaceRoot) { return fModelRoot; // doOpen((IWorkspaceRoot) container); } throw new ModelException("Inappropriate argument type " + container.getClass() + " to ModelFactory.doOpen(IContainer)."); } // TODO needs a progress monitor public static ISourceEntity create(IContainer container) throws ModelException { return getInstance().doCreate(container); } // TODO needs a progress monitor private ISourceEntity doCreate(IContainer container) throws ModelException { if (container instanceof IProject) { return doCreate((IProject) container); } else if (container instanceof IFolder) { return doOpen((IFolder) container); } else if (container instanceof IWorkspaceRoot) { return fModelRoot; // doOpen((IWorkspaceRoot) container); } throw new ModelException("Inappropriate argument type " + container.getClass() + " to ModelFactory.doOpen(IContainer)."); } public static ISourceFolder open(IFolder folder) throws ModelException { return getInstance().doOpen(folder); } private ISourceFolder doOpen(IFolder folder) throws ModelException { if (!folder.exists()) { throw new ModelException(NO_SUCH_ELEMENT); } ISourceProject sp= doOpen(folder.getProject()); SourceFolder sf= new SourceFolder(sp, folder.getProjectRelativePath()); return sf; } /** * Creates a source folder. Must not already exist. Containing project * must already exist. */ // TODO needs a progress monitor public static ISourceFolder create(IFolder folder) throws ModelException { return getInstance().doCreate(folder); } // TODO needs a progress monitor private ISourceFolder doCreate(IFolder folder) throws ModelException { ISourceProject sp= doOpen(folder.getProject()); if (!folder.exists()) { try { folder.create(true, false, null); } catch (CoreException e) { throw new ModelException("Unable to create underlying folder for source folder " + folder.getLocation().toPortableString(), e); } } SourceFolder sf= new SourceFolder(sp, folder.getProjectRelativePath()); return sf; } public static ICompilationUnit open(IPath path, ISourceProject srcProject) { return getInstance().doOpen(path, srcProject); } private ICompilationUnit doOpen(IPath path, ISourceProject srcProject) { ICompilationUnit unit; IPath resolvedPath; if (path.isAbsolute()) unit= new CompilationUnitRef(resolvedPath= path, null); else { resolvedPath= srcProject.resolvePath(path); if (resolvedPath == null) return null; unit= new CompilationUnitRef(resolvedPath, srcProject); } // Determine the language of this compilation unit, find the corresponding // factory extender, and invoke it before returning the compilation unit. Language lang= LanguageRegistry.findLanguage(resolvedPath, null); IFactoryExtender ext= fExtenderMap.get(lang); if (ext != null) ext.extend(unit); return unit; } public static ICompilationUnit open(IFile file, ISourceProject srcProject) { return getInstance().doOpen(file, srcProject); } private ICompilationUnit doOpen(IFile file, ISourceProject srcProject) { if (!file.exists()) return null; ICompilationUnit unit= new CompilationUnitRef(file.getFullPath(), srcProject); // Determine the language of this compilation unit, find the corresponding // factory extender, and invoke it before returning the compilation unit. TextFileDocumentProvider tfdp= new TextFileDocumentProvider(); // TODO perhaps this should be in a field? or another type of doc provider? IDocument doc= tfdp.getDocument(file); Language lang= LanguageRegistry.findLanguage(file.getLocation(), doc); IFactoryExtender ext= fExtenderMap.get(lang); if (ext != null) ext.extend(unit); return unit; } /** * * @param projRelPath * @param srcProject * @return never returns null */ // TODO needs a progress monitor public static ICompilationUnit create(IPath projRelPath, ISourceProject srcProject) throws ModelException { return getInstance().doCreate(projRelPath, srcProject); } // TODO needs a progress monitor private ICompilationUnit doCreate(IPath projRelPath, ISourceProject srcProject) throws ModelException { throw new ModelException(ELEMENT_ALREADY_EXISTS); } /** * @param file * @param srcProject * @return the new ICompilationUnit corresponding to the given file */ // TODO needs a progress monitor public static ICompilationUnit create(IFile file, ISourceProject srcProject) throws ModelException { return getInstance().doCreate(file, srcProject); } // TODO needs a progress monitor private ICompilationUnit doCreate(IFile file, ISourceProject srcProject) throws ModelException { return doCreate(file.getProjectRelativePath(), srcProject); } // TODO needs a progress monitor public static IPathEntry createPathEntry(PathEntryType type, IPath path) { return new PathEntry(type, path); } }