/* * JBoss, Home of Professional Open Source. * * See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing. * * See the AUTHORS.txt file distributed with this work for a full listing of individual contributors. */ package org.teiid.designer.core.workspace; import java.io.File; import java.io.IOException; import java.util.ArrayList; import org.eclipse.core.resources.ICommand; 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.IProjectDescription; import org.eclipse.core.resources.IProjectNature; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.teiid.core.designer.util.CoreArgCheck; import org.teiid.designer.core.ModelerCore; import org.teiid.designer.extension.ExtensionConstants; /** * ModelProjectImpl * * @since 8.0 */ public class ModelProjectImpl extends OpenableImpl implements IProjectNature, ModelProject { /** * Whether the underlying file system is case sensitive. */ protected static final boolean IS_CASE_SENSITIVE = !new File("Temp").equals(new File("temp")); //$NON-NLS-1$ //$NON-NLS-2$ /** * Name of file containing custom project preferences */ public static final String PREF_FILENAME = ".mprefs"; //$NON-NLS-1$ /** * The platform project this <code>ModelProject</code> is based on * * @since 4.0 */ protected IProject fProject; /** * The platform project this <code>ModelProject</code> is based on * * @since 4.0 */ protected IPath path; /** * Constructor needed for {@link IProject#getNature(java.lang.String)} and {@link IProject#addNature()}. * * @see #setProject * @since 4.0 */ public ModelProjectImpl() { super(MODEL_PROJECT, null, null); } /** * Construct an instance of ModelProjectImpl. * * @since 4.0 */ public ModelProjectImpl( final IProject project, final ModelWorkspaceItem parent ) { super(MODEL_PROJECT, parent, project.getName()); fProject = project; } /** * Returns a canonicalized path from the given external path. Note that the return path contains the same number of segments * and it contains a device only if the given path contained one. * * @see java.io.File for the definition of a canonicalized path */ public static IPath canonicalizedPath( IPath externalPath ) { if (externalPath == null) { return null; } if (IS_CASE_SENSITIVE) { return externalPath; } // if not external path, return original path IWorkspace workspace = ModelerCore.getWorkspace(); if (workspace == null) { return externalPath; // protection during shutdown (30487) } if (workspace.getRoot().findMember(externalPath) != null) { return externalPath; } IPath canonicalPath = null; try { canonicalPath = new Path(new File(externalPath.toOSString()).getCanonicalPath()); } catch (IOException e) { // default to original path return externalPath; } IPath result; int canonicalLength = canonicalPath.segmentCount(); if (canonicalLength == 0) { // the java.io.File canonicalization failed return externalPath; } else if (externalPath.isAbsolute()) { result = canonicalPath; } else { // if path is relative, remove the first segments that were added by the java.io.File canonicalization // e.g. 'lib/classes.zip' was converted to 'd:/myfolder/lib/classes.zip' int externalLength = externalPath.segmentCount(); if (canonicalLength >= externalLength) { result = canonicalPath.removeFirstSegments(canonicalLength - externalLength); } else { return externalPath; } } // keep device only if it was specified (this is because File.getCanonicalPath() converts '/lib/classed.zip' to // 'd:/lib/classes/zip') if (externalPath.getDevice() == null) { result = result.setDevice(null); } return result; } /** * @since 4.0 */ private void addToBuildSpec( final String builderId ) throws CoreException { final IProject project = getProject(); final IProjectDescription desc = project.getDescription(); ICommand cmd = getBuilderCommand(desc, builderId); if (cmd == null) { // Add a new build spec as the first build spec cmd = desc.newCommand(); cmd.setBuilderName(builderId); final ICommand[] cmds = desc.getBuildSpec(); final ICommand[] newCmds = new ICommand[cmds.length + 1]; System.arraycopy(cmds, 0, newCmds, 1, cmds.length); newCmds[0] = cmd; desc.setBuildSpec(newCmds); project.setDescription(desc, null); } } /** * @see org.eclipse.core.resources.IProjectNature#configure() * @since 4.0 */ @Override public void configure() throws CoreException { // builders get executed in reverse order addToBuildSpec(ModelerCore.BUILDER_ID); addToBuildSpec(ExtensionConstants.MED_BUILDER_ID); addToBuildSpec(ModelerCore.VDB_BUILDER_ID); } /** * Does nothing. * * @see org.eclipse.core.resources.IProjectNature#deconfigure() * @since 4.0 */ @Override public void deconfigure() throws CoreException { removeFromBuildSpec(ModelerCore.BUILDER_ID); removeFromBuildSpec(ExtensionConstants.MED_BUILDER_ID); removeFromBuildSpec(ModelerCore.VDB_BUILDER_ID); } /** * @see org.teiid.designer.core.workspace.Openable * @since 4.0 */ @Override protected boolean generateInfos( final OpenableModelWorkspaceItemInfo info, final IProgressMonitor pm, final IResource underlyingResource ) throws ModelWorkspaceException { boolean validInfo = false; try { if (getProject().isOpen()) { // put the info now, because computing the roots requires it ModelWorkspaceManager.getModelWorkspaceManager().putInfo(this, info); // compute the pkg fragment roots updatePackageFragmentRoots(); // only valid if reaches here validInfo = true; } } finally { if (!validInfo) { ModelWorkspaceManager.getModelWorkspaceManager().removeInfo(this); } } return validInfo; } /** * @since 4.0 */ private ICommand getBuilderCommand( final IProjectDescription description, final String builderId ) { final ICommand[] cmds = description.getBuildSpec(); for (int ndx = cmds.length; --ndx >= 0;) { final ICommand cmd = cmds[ndx]; if (cmd.getBuilderName().equals(builderId)) { return cmd; } } return null; } /** * @see org.teiid.designer.core.workspace.ModelProject#getNonModelingResources() * @since 4.0 */ @Override public Object[] getNonModelingResources() throws ModelWorkspaceException { return ((ModelProjectInfo)getItemInfo()).getNonModelResources(this); } /** * @see org.teiid.designer.core.workspace.ModelWorkspaceItem#getPath() * @since 4.0 */ @Override public IPath getPath() { if (this.path == null) { return this.getProject().getFullPath(); } return this.path; } /** * @see org.teiid.designer.core.workspace.ModelWorkspaceItem#getPath() * @since 4.0 */ public void setPath( IPath path ) { this.path = path; } /** * @see org.teiid.designer.core.workspace.ModelProject#getProject() * @since 4.0 */ @Override public IProject getProject() { return fProject; } /** * @see org.teiid.designer.core.workspace.ModelWorkspaceItem#getResource() * @since 4.0 */ @Override public IResource getResource() { return this.getProject(); } /** * Removes the given builder from the build spec for the given project. * * @since 4.0 */ private void removeFromBuildSpec( final String builderId ) throws CoreException { final IProject project = getProject(); final IProjectDescription desc = project.getDescription(); final ICommand[] cmds = desc.getBuildSpec(); for (int ndx = cmds.length; --ndx >= 0;) { final ICommand cmd = cmds[ndx]; if (cmd.getBuilderName().equals(builderId)) { final ICommand[] newCmds = new ICommand[cmds.length - 1]; System.arraycopy(cmds, 0, newCmds, 0, ndx); System.arraycopy(cmds, ndx + 1, newCmds, ndx, cmds.length - ndx - 1); desc.setBuildSpec(newCmds); project.setDescription(desc, null); return; } } } /** * @see org.eclipse.core.resources.IProjectNature#setProject(org.eclipse.core.resources.IProject) * @since 4.0 */ @Override public void setProject( final IProject project ) { this.fProject = project; } /** * Convenience method that returns the specific type of info for a ModelProject. */ protected ModelProjectInfo getModelProjectInfo() throws ModelWorkspaceException { return (ModelProjectInfo)getItemInfo(); } /** * Reset the collection of package fragment roots (local ones) - only if opened. Need to check *all* package fragment roots in * order to reset NameLookup * * @since 4.0 */ public void updatePackageFragmentRoots() throws ModelWorkspaceException { if (this.isOpen()) { boolean failed = false; try { ModelProjectInfo info = getModelProjectInfo(); info.setNonModelResources(null); info.setChildren(computeModelResources()); } catch (ModelWorkspaceException e) { failed = true; throw e; } catch (RuntimeException e) { failed = true; throw e; } finally { if (failed) { try { close(); // could not do better } catch (ModelWorkspaceException ex) { } } } } } @Override public ModelWorkspaceItem findModelWorkspaceItem( IResource resource ) throws ModelWorkspaceException { CoreArgCheck.isNotNull(resource); return ModelWorkspaceManager.getModelWorkspaceManager().findModelWorkspaceItem(resource); } /** * Used by the {@link #computeModelResources(IContainer, ArrayList)} method. * * @param resource * @return */ protected ModelResource createModelResource( final IFile resource ) { ModelWorkspaceItem parent = findParent(resource); if (!ModelUtil.isVdbArchiveFile(resource)) { return new ModelResourceImpl(parent, resource.getName(), false); } return new ModelResourceImpl(parent, resource.getName()); } /** * Used by the {@link #computeModelResources(IContainer, ArrayList)} method. * * @param resource * @return */ protected ModelFolder createModelFolder( final IFolder folder ) { ModelWorkspaceItem parent = findParent(folder); return new ModelFolderImpl(folder, parent); } /** * @param resource * @return */ private ModelWorkspaceItem findParent( IResource resource ) { final IContainer iParent = resource.getParent(); if (iParent instanceof IProject) { return this; } return this.getModelWorkspace().getParent(resource); } public ModelWorkspaceItem[] computeModelResources() { final ArrayList accumulatedModelResources = new ArrayList(); computeModelResources(this.getProject(), accumulatedModelResources); final ModelWorkspaceItem[] results = new ModelWorkspaceItem[accumulatedModelResources.size()]; accumulatedModelResources.toArray(results); return results; } public void computeModelResources( final IContainer container, final ArrayList accumulatedModelResources ) { try { // Iterate through the container's immediate children and add them final IResource[] children = container.members(); for (int i = 0; i < children.length; ++i) { final IResource child = children[i]; if (IResource.FILE == child.getType()) { // If the resource is a model file, then add it to the accumulated list if (ModelUtil.isModelFile(child)) { final ModelResource mdlResource = ModelProjectImpl.this.createModelResource((IFile)child); accumulatedModelResources.add(mdlResource); // If the IFile extension does not match the set of well-known model file extensions with // a case-sensitive check but does match when the check is case-insensitive then error (defect 17709) } else if (!ModelFileUtil.isModelFileExtension(child.getFileExtension(), true) && ModelFileUtil.isModelFileExtension(child.getFileExtension(), false)) { final String actualFileName = child.getName(); final String actualExtension = child.getFileExtension(); final int endIndex = actualFileName.length() - actualExtension.length(); final String expectedFileName = actualFileName.substring(0, endIndex) + actualExtension.toLowerCase(); final Object[] params = new Object[] {actualFileName, expectedFileName}; final String msg = ModelerCore.Util.getString("ModelerCore.file_extension_not_correct_case_please_rename_file", params); //$NON-NLS-1$ ModelerCore.Util.log(IStatus.ERROR, msg); } } else if (IResource.FOLDER == child.getType()) { final ModelFolder mdlFolder = ModelProjectImpl.this.createModelFolder((IFolder)child); accumulatedModelResources.add(mdlFolder); } } } catch (CoreException e) { ModelerCore.Util.log(IStatus.ERROR, e, ModelerCore.Util.getString("ModelProjectImpl.Error_while_computing_ModelResource_instances_for_ModelProject", this)); //$NON-NLS-1$ } } /* (non-Javadoc) * @see org.teiid.designer.core.workspace.OpenableImpl#createItemInfo() */ @Override protected OpenableModelWorkspaceItemInfo createItemInfo() { return new ModelProjectInfo(); } }