/******************************************************************************* * Copyright © 2000, 2013 IBM Corporation and others. * 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: * IBM Corporation - initial API and implementation * *******************************************************************************/ package org.eclipse.edt.ide.core.internal.model; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.StringReader; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; 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.IMarker; 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.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Preferences; import org.eclipse.edt.ide.core.EDTCoreIDEPlugin; import org.eclipse.edt.ide.core.EDTCorePreferenceConstants; import org.eclipse.edt.ide.core.internal.model.util.EGLProjectFileUtilityLocator; import org.eclipse.edt.ide.core.internal.model.util.IEGLProjectFileUtility; import org.eclipse.edt.ide.core.internal.model.util.ObjectVector; import org.eclipse.edt.ide.core.model.EGLConventions; import org.eclipse.edt.ide.core.model.EGLCore; import org.eclipse.edt.ide.core.model.EGLModelException; import org.eclipse.edt.ide.core.model.IEGLElement; import org.eclipse.edt.ide.core.model.IEGLModelMarker; import org.eclipse.edt.ide.core.model.IEGLModelStatus; import org.eclipse.edt.ide.core.model.IEGLModelStatusConstants; import org.eclipse.edt.ide.core.model.IEGLPathContainer; import org.eclipse.edt.ide.core.model.IEGLPathEntry; import org.eclipse.edt.ide.core.model.IEGLProject; import org.eclipse.edt.ide.core.model.IPackageFragment; import org.eclipse.edt.ide.core.model.IPackageFragmentRoot; import org.eclipse.edt.ide.core.model.IPart; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.SAXException; //import com.ibm.etools.egl.internal.EGLIncompleteBuildPathSetting; //import com.ibm.etools.egl.internal.EGLVAGCompatibilitySetting; /** * @author twilson created Jul 25, 2003 */ public class EGLProject extends Openable implements IEGLProject, IProjectNature { /** * 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$ /** * An empty array of strings indicating that a project doesn't have any * prerequesite projects. */ protected static final String[] NO_PREREQUISITES = new String[0]; /** * The platform project this <code>IEGLProject</code> is based on */ protected IProject fProject; /** * Name of file containing project EGLPath */ public static final String EGLPATH_FILENAME = ".eglPath"; //$NON-NLS-1$ /** * Name of file containing custom project preferences */ public static final String PREF_FILENAME = ".eprefs"; //$NON-NLS-1$ public static final String BUILD_STATE_FILE_EXTENSION = "bs"; //$NON-NLS-1$ /** * Value of the project's raw EGLPath if the .EGLPath file contains invalid * entries. */ public static final IEGLPathEntry[] INVALID_EGLPATH = new IEGLPathEntry[0]; private static final String CUSTOM_DEFAULT_OPTION_VALUE = "#\r\n\r#custom-non-empty-default-value#\r\n\r#"; //$NON-NLS-1$ /** * Adds a builder to the build spec for the given project. * bInsert2First - means insert the builder at the beginning */ protected void addToBuildSpec(String builderID, boolean bInsert2First) throws CoreException { IProjectDescription description = getProject().getDescription(); ICommand eglCommand = getCommand(description, builderID); if (eglCommand == null) { // Add a EGL command to the build spec ICommand command = description.newCommand(); command.setBuilderName(builderID); setEGLCommand(description, command, builderID, bInsert2First); } } /** * 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 = ResourcesPlugin.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; } /** * Configure the project with Java nature. */ public void configure() throws CoreException { // register EGL builders. add them to the top of the build order, with the gen builder second addToBuildSpec(EDTCoreIDEPlugin.GENERATION_BUILDER_ID, true); addToBuildSpec(EDTCoreIDEPlugin.BUILDER_ID, true); } /** * Removes the Java nature from the project. */ public void deconfigure() throws CoreException { // deregister EGL builder removeFromBuildSpec(EGLCore.BUILDER_ID); } /** * Constructor needed for <code>IProject.getNature()</code> and <code>IProject.addNature()</code>. * * @see #setProject */ public EGLProject() { super(EGL_PROJECT, null, null); } /** * @param type * @param parent * @param name */ public EGLProject(IProject project, IEGLElement parent) { super(EGL_PROJECT, parent, project.getName()); fProject = project; } /** * Internal computation of an expanded eglpath. It will eliminate * duplicates, and produce copies of exported eglpath entries to avoid * possible side-effects ever after. */ private void computeExpandedEGLPath( EGLProject initialProject, boolean ignoreUnresolvedVariable, boolean generateMarkerOnError, HashSet visitedProjects, ObjectVector accumulatedEntries) throws EGLModelException { if (visitedProjects.contains(this)) { return; // break cycles if any } visitedProjects.add(this); if (generateMarkerOnError && !this.equals(initialProject)) { generateMarkerOnError = false; } IEGLPathEntry[] immediateEGLPath = getResolvedEGLPath(ignoreUnresolvedVariable, generateMarkerOnError); IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); for (int i = 0, length = immediateEGLPath.length; i < length; i++) { IEGLPathEntry entry = immediateEGLPath[i]; boolean isInitialProject = this.equals(initialProject); //exported eglar of referencing project should not be added if (isInitialProject || (entry.getEntryKind() != EGLPathEntry.CPE_LIBRARY && entry.isExported())) { accumulatedEntries.add(entry); // recurse in project to get all its indirect exports (only // consider exported entries from there on) if (entry.getEntryKind() == EGLPathEntry.CPE_PROJECT) { IResource member = workspaceRoot.findMember(entry.getPath()); if (member != null && member.getType() == IResource.PROJECT) { // double check if bound to project (23977) IProject projRsc = (IProject) member; if (EGLProject.hasEGLNature(projRsc)) { EGLProject project = (EGLProject) EGLCore.create(projRsc); project.computeExpandedEGLPath( initialProject, ignoreUnresolvedVariable, generateMarkerOnError, visitedProjects, accumulatedEntries); } } } } } } /** * Returns (local/all) the package fragment roots identified by the given * project's eglpath. Note: this follows project eglpath references to find * required project contributions, eliminating duplicates silently. Only * works with resolved entries */ public IPackageFragmentRoot[] computePackageFragmentRoots(IEGLPathEntry[] resolvedEGLPath, boolean retrieveExportedRoots) throws EGLModelException { ObjectVector accumulatedRoots = new ObjectVector(); computePackageFragmentRoots(resolvedEGLPath, accumulatedRoots, new HashSet(5), // rootIDs true, // inside original project true, // check existency retrieveExportedRoots); IPackageFragmentRoot[] rootArray = new IPackageFragmentRoot[accumulatedRoots.size()]; accumulatedRoots.copyInto(rootArray); return rootArray; } /** * Computes the package fragment roots identified by the given entry. Only * works with resolved entry */ public IPackageFragmentRoot[] computePackageFragmentRoots(IEGLPathEntry resolvedEntry) { try { return computePackageFragmentRoots(new IEGLPathEntry[] { resolvedEntry }, false // don't // retrieve // exported // roots ); } catch (EGLModelException e) { return new IPackageFragmentRoot[] { }; } } /** * Returns the package fragment roots identified by the given entry. In * case it refers to a project, it will follow its eglpath so as to find * exported roots as well. Only works with resolved entry */ public void computePackageFragmentRoots( IEGLPathEntry resolvedEntry, ObjectVector accumulatedRoots, HashSet rootIDs, boolean insideOriginalProject, boolean checkExistency, boolean retrieveExportedRoots) throws EGLModelException { String rootID = ((EGLPathEntry) resolvedEntry).rootID(); if (rootIDs.contains(rootID)) return; IPath projectPath = getProject().getFullPath(); IPath entryPath = resolvedEntry.getPath(); IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); switch (resolvedEntry.getEntryKind()) { // source folder case IEGLPathEntry.CPE_SOURCE : if (projectPath.isPrefixOf(entryPath)) { if (checkExistency) { Object target = EGLModel.getTarget(workspaceRoot, entryPath, checkExistency); if (target == null) return; if (target instanceof IFolder || target instanceof IProject) { accumulatedRoots.add(getPackageFragmentRoot((IResource) target)); rootIDs.add(rootID); } } else { IPackageFragmentRoot root = getFolderPackageFragmentRoot(entryPath); if (root != null) { accumulatedRoots.add(root); rootIDs.add(rootID); } } } break; case IEGLPathEntry.CPE_LIBRARY : //TODO if (referringEntry != null && !resolvedEntry.isExported()) // return; Object target = EGLModel.getTarget(workspaceRoot, entryPath, checkExistency); if (target == null) return; IPackageFragmentRoot root = null; if (target instanceof IResource){ // internal target root = getPackageFragmentRoot((IResource) target); if(root instanceof EglarPackageFragmentRoot) { ((EglarPackageFragmentRoot)root).setBinaryProject(resolvedEntry.isBinaryProject()); } } else if (target instanceof File) { // external target if (EGLModel.isFile(target)) { root = new EglarPackageFragmentRoot(entryPath, this); ((EglarPackageFragmentRoot)root).setBinaryProject(resolvedEntry.isBinaryProject()); } else if (((File) target).isDirectory()) { // TODO IPackageFragmentRoot root = new ExternalPackageFragmentRoot(entryPath, this); } } if (root != null) { accumulatedRoots.add(root); rootIDs.add(rootID); } break; // recurse into required project case IEGLPathEntry.CPE_PROJECT : if (!retrieveExportedRoots) return; if (!insideOriginalProject && !resolvedEntry.isExported()) return; IResource member = workspaceRoot.findMember(entryPath); if (member != null && member.getType() == IResource.PROJECT) { // double check if bound to project (23977) IProject requiredProjectRsc = (IProject) member; if (EGLProject.hasEGLNature(requiredProjectRsc)) { // special builder binary output rootIDs.add(rootID); EGLProject requiredProject = (EGLProject) EGLCore.create(requiredProjectRsc); requiredProject.computePackageFragmentRoots( requiredProject.getResolvedEGLPath(true), accumulatedRoots, rootIDs, false, checkExistency, retrieveExportedRoots); } break; } } } /** * Returns (local/all) the package fragment roots identified by the given * project's eglpath. Note: this follows project eglpath references to find * required project contributions, eliminating duplicates silently. Only * works with resolved entries */ public void computePackageFragmentRoots( IEGLPathEntry[] resolvedEGLPath, ObjectVector accumulatedRoots, HashSet rootIDs, boolean insideOriginalProject, boolean checkExistency, boolean retrieveExportedRoots) throws EGLModelException { if (insideOriginalProject) { rootIDs.add(rootID()); } for (int i = 0, length = resolvedEGLPath.length; i < length; i++) { computePackageFragmentRoots( resolvedEGLPath[i], accumulatedRoots, rootIDs, insideOriginalProject, checkExistency, retrieveExportedRoots); } } /** * Record a new marker denoting a eglpath problem */ IMarker createEGLPathProblemMarker(IEGLModelStatus status) { IMarker marker = null; int severity; String[] arguments = new String[0]; boolean isCycleProblem = false, isEGLPathFileFormatProblem = false; switch (status.getCode()) { case IEGLModelStatusConstants.EGLPATH_CYCLE : isCycleProblem = true; severity = IMarker.SEVERITY_ERROR; break; case IEGLModelStatusConstants.INVALID_EGLPATH_FILE_FORMAT : isEGLPathFileFormatProblem = true; severity = IMarker.SEVERITY_ERROR; break; default : IPath path = status.getPath(); if (path != null){ arguments = new String[] { path.toString()}; } //TODO EDT Support incomplete build path setting // switch(EGLIncompleteBuildPathSetting.getIncompleteBuildPathSetting()){ // case EGLIncompleteBuildPathSetting._INCOMPLETE_BUILD_PATH_ERROR: // severity = IMarker.SEVERITY_ERROR; // break; // case EGLIncompleteBuildPathSetting._INCOMPLETE_BUILD_PATH_WARNING: // severity = IMarker.SEVERITY_WARNING; // break; // default: severity = IMarker.SEVERITY_ERROR; // break; // } /* * TODO handle configurable options later if * (EGLCore.ERROR.equals(getOption(EGLCore.CORE_INCOMPLETE_EGLPATH, * true))) { severity = IMarker.SEVERITY_ERROR; } else { * severity = IMarker.SEVERITY_WARNING; } */ break; } try { marker = getProject().createMarker(IEGLModelMarker.BUILDPATH_PROBLEM_MARKER); marker .setAttributes( new String[] { IMarker.MESSAGE, IMarker.SEVERITY, IMarker.LOCATION, IEGLModelMarker.CYCLE_DETECTED, IEGLModelMarker.EGLPATH_FILE_FORMAT, IEGLModelMarker.ID, IEGLModelMarker.ARGUMENTS, }, new Object[] { status.getMessage(), new Integer(severity), EGLModelResources.eglpathBuildPath, //$NON-NLS-1$ isCycleProblem ? "true" : "false", //$NON-NLS-1$ //$NON-NLS-2$ isEGLPathFileFormatProblem ? "true" : "false", //$NON-NLS-1$ //$NON-NLS-2$ new Integer(status.getCode()), Util.getProblemArgumentsForMarker(arguments), }); } catch (CoreException e) { } return marker; } /** * Record a new marker denoting a eglpath problem */ IMarker createEGLBDProblemMarker(IEGLModelStatus status) { return null; } /** * Returns a new element info for this element. */ protected OpenableElementInfo createElementInfo() { return new EGLProjectElementInfo(); } /* * Returns whether the given resource is accessible through the children or * the non-EGL resources of this project. Returns true if the resource is * not in the project. Assumes that the resource is a folder or a file. */ public boolean contains(IResource resource) { IEGLPathEntry[] eglpath; IPath output; try { eglpath = getResolvedEGLPath(true); output = getOutputLocation(); } catch (EGLModelException e) { return false; } IPath fullPath = resource.getFullPath(); IPath innerMostOutput = output.isPrefixOf(fullPath) ? output : null; IEGLPathEntry innerMostEntry = null; for (int j = 0, cpLength = eglpath.length; j < cpLength; j++) { IEGLPathEntry entry = eglpath[j]; IPath entryPath = entry.getPath(); if ((innerMostEntry == null || innerMostEntry.getPath().isPrefixOf(entryPath)) && entryPath.isPrefixOf(fullPath)) { innerMostEntry = entry; } IPath entryOutput = eglpath[j].getOutputLocation(); if (entryOutput != null && entryOutput.isPrefixOf(fullPath)) { innerMostOutput = entryOutput; } } if (innerMostEntry != null) { // special case prj==src and nested output location if (innerMostOutput != null && innerMostOutput.segmentCount() > 1 // output isn't project && innerMostEntry.getPath().segmentCount() == 1) { // 1 segment must be project name return false; } if (resource instanceof IFolder) { // folders are always included in src/lib entries return true; } } if (innerMostOutput != null) { return false; } return true; } /** * Returns true if given name exists in receiver's namespace * * @param packageName * @return */ public boolean containsPackage(String packageName) { try { return getNameLookup().findPackageFragments(packageName, false) != null; } catch (EGLModelException e) { return false; } } /** * Returns true if this handle represents the same EGL project as the given * handle. Two handles represent the same project if they are identical or * if they represent a project with the same underlying resource and * occurrence counts. * * @see EGLElement#equals */ public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof EGLProject)) return false; EGLProject other = (EGLProject) o; return getProject().equals(other.getProject()) && fOccurrenceCount == other.fOccurrenceCount; } public boolean exists() { if (!hasEGLNature(fProject)) return false; return super.exists(); } /* * Returns the cycle marker associated with this project or null if none. */ public IMarker getCycleMarker() { try { IProject project = getProject(); if (project.exists()) { IMarker[] markers = project.findMarkers(IEGLModelMarker.BUILDPATH_PROBLEM_MARKER, false, IResource.DEPTH_ZERO); for (int i = 0, length = markers.length; i < length; i++) { IMarker marker = markers[i]; String cycleAttr = (String) marker.getAttribute(IEGLModelMarker.CYCLE_DETECTED); if (cycleAttr != null && cycleAttr.equals("true")) { //$NON-NLS-1$ return marker; } } } } catch (CoreException e) { } return null; } /** * Reads and decode an XML classpath string */ protected IEGLPathEntry[] decodeEGLPath(String xmlPath, boolean createMarker, boolean logProblems) { ArrayList paths = new ArrayList(); IEGLPathEntry defaultOutput = null; try { if (xmlPath == null) return null; StringReader reader = new StringReader(xmlPath); Element cpElement; try { DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder(); cpElement = parser.parse(new InputSource(reader)).getDocumentElement(); } catch (SAXException e) { throw new IOException(EGLModelResources.fileBadFormat); } catch (ParserConfigurationException e) { throw new IOException(EGLModelResources.fileBadFormat); } finally { reader.close(); } if (!cpElement.getNodeName().equalsIgnoreCase("eglpath")) { //$NON-NLS-1$ throw new IOException(EGLModelResources.fileBadFormat); } NodeList list = cpElement.getElementsByTagName("eglpathentry"); //$NON-NLS-1$ int length = list.getLength(); for (int i = 0; i < length; ++i) { Node node = list.item(i); if (node.getNodeType() == Node.ELEMENT_NODE) { IEGLPathEntry entry = EGLPathEntry.elementDecode((Element) node, getProject().getFullPath(), getElementName()); if (entry != null) { if (entry.getContentKind() == EGLPathEntry.K_OUTPUT) { defaultOutput = entry; // separate output } else { paths.add(entry); } } } } } catch (IOException e) { // bad format if (createMarker && this.getProject().isAccessible()) { this.createEGLPathProblemMarker(new EGLModelStatus(IEGLModelStatusConstants.INVALID_EGLPATH_FILE_FORMAT, EGLModelResources.bind(EGLModelResources.eglpathXmlFormatError, this.getElementName(), e.getMessage()))); } if (logProblems) { Util.log(e, "Exception while retrieving " + this.getPath() //$NON-NLS-1$ +"/.eglpath, will mark eglpath as invalid"); //$NON-NLS-1$ } return INVALID_EGLPATH; } catch (Exception e) { // failed creating CP entries from file if (createMarker && this.getProject().isAccessible()) { this.createEGLPathProblemMarker(new EGLModelStatus(IEGLModelStatusConstants.INVALID_EGLPATH_FILE_FORMAT, EGLModelResources.bind(EGLModelResources.eglpathIllegalEntryInEGLpathFile, this.getElementName(), e.getMessage()))); } if (logProblems) { Util.log(e, "Exception while retrieving " + this.getPath() //$NON-NLS-1$ +"/.eglpath, will mark eglpath as invalid"); //$NON-NLS-1$ } return INVALID_EGLPATH; } int pathSize = paths.size(); if (pathSize > 0 || defaultOutput != null) { IEGLPathEntry[] entries = new IEGLPathEntry[pathSize + (defaultOutput == null ? 0 : 1)]; paths.toArray(entries); if (defaultOutput != null) entries[pathSize] = defaultOutput; // ensure output is last item return entries; } else { return null; } } /** * Returns a default egl path. This is the root of the project */ protected IEGLPathEntry[] defaultEGLPath() throws EGLModelException { return new IEGLPathEntry[] { EGLCore.newSourceEntry(getProject().getFullPath())}; } /** * Returns a default output location. This is the project bin folder */ protected IPath defaultOutputLocation() throws EGLModelException { return getProject().getFullPath().append( EDTCoreIDEPlugin.getPlugin().getPreferenceStore().getString( EDTCorePreferenceConstants.EGL_OUTPUT_FOLDER )); } /** * Returns the XML String encoding of the class path. */ protected String encodeEGLPath(IEGLPathEntry[] eglpath, IPath outputLocation, boolean indent) throws EGLModelException { try { ByteArrayOutputStream s = new ByteArrayOutputStream(); OutputStreamWriter writer = new OutputStreamWriter(s, "UTF-8"); //$NON-NLS-1$ XMLWriter xmlWriter = new XMLWriter(writer); xmlWriter.startTag("eglpath", indent); //$NON-NLS-1$ for (int i = 0; i < eglpath.length; ++i) { ((EGLPathEntry)eglpath[i]).elementEncode(xmlWriter, getProject().getFullPath(), indent, true); } if (outputLocation != null) { outputLocation = outputLocation.removeFirstSegments(1); outputLocation = outputLocation.makeRelative(); HashMap parameters = new HashMap(); parameters.put("kind", EGLPathEntry.kindToString(EGLPathEntry.K_OUTPUT));//$NON-NLS-1$ parameters.put("path", String.valueOf(outputLocation));//$NON-NLS-1$ xmlWriter.printTag("eglpathentry", parameters, indent, true, true);//$NON-NLS-1$ } xmlWriter.endTag("eglpath", indent);//$NON-NLS-1$ writer.flush(); writer.close(); return s.toString("UTF8");//$NON-NLS-1$ } catch (IOException e) { throw new EGLModelException(e, IEGLModelStatusConstants.IO_EXCEPTION); } } /** * Remove all markers denoting eglpath problems */ protected void flushEGLPathProblemMarkers(boolean flushCycleMarkers, boolean flushEGLPathFormatMarkers) { try { IProject project = getProject(); if (project.exists()) { IMarker[] markers = project.findMarkers(IEGLModelMarker.BUILDPATH_PROBLEM_MARKER, false, IResource.DEPTH_ZERO); for (int i = 0, length = markers.length; i < length; i++) { IMarker marker = markers[i]; if (flushCycleMarkers && flushEGLPathFormatMarkers) { marker.delete(); } else { String cycleAttr = (String) marker.getAttribute(IEGLModelMarker.CYCLE_DETECTED); String eglpathFileFormatAttr = (String) marker.getAttribute(IEGLModelMarker.EGLPATH_FILE_FORMAT); if ((flushCycleMarkers == (cycleAttr != null && cycleAttr.equals("true"))) //$NON-NLS-1$ && (flushEGLPathFormatMarkers == (eglpathFileFormatAttr != null && eglpathFileFormatAttr.equals("true")))) { //$NON-NLS-1$ marker.delete(); } } } } } catch (CoreException e) { } } /** * @see Openable */ protected boolean generateInfos(OpenableElementInfo info, IProgressMonitor pm, Map newElements, IResource underlyingResource) throws EGLModelException { boolean validInfo = false; try { if (getProject().isOpen()) { // put the info now, because computing the roots requires it EGLModelManager.getEGLModelManager().putInfo(this, info); // compute the pkg fragment roots updatePackageFragmentRoots(); // remember the timestamps of external libraries the first time // they are looked up IEGLPathEntry[] resolvedEGLPath = getResolvedEGLPath(true /* * ignore * unresolved * variable */ ); for (int i = 0, length = resolvedEGLPath.length; i < length; i++) { IEGLPathEntry entry = resolvedEGLPath[i]; if (entry.getEntryKind() == IEGLPathEntry.CPE_LIBRARY) { IPath path = entry.getPath(); Object target = EGLModel.getTarget(ResourcesPlugin.getWorkspace().getRoot(), path, true); if (target instanceof java.io.File) { Map externalTimeStamps = EGLModelManager.getEGLModelManager().deltaProcessor.externalTimeStamps; if (externalTimeStamps.get(path) == null) { long timestamp = DeltaProcessor.getTimeStamp((java.io.File) target); externalTimeStamps.put(path, new Long(timestamp)); } } } } // only valid if reaches here validInfo = true; } } finally { if (!validInfo) EGLModelManager.getEGLModelManager().removeInfo(this); } return validInfo; } /** * @see IEGLProject */ public IEGLElement findElement(IPath path) throws EGLModelException { if (path == null || path.isAbsolute()) { throw new EGLModelException(new EGLModelStatus(IEGLModelStatusConstants.INVALID_PATH, path)); } try { String extension = path.getFileExtension(); if (extension == null) { String packageName = path.toString().replace(IPath.SEPARATOR, '.'); IPackageFragment[] pkgFragments = getNameLookup().findPackageFragments(packageName, false); if (pkgFragments == null) { return null; } else { // try to return one that is a child of this project for (int i = 0, length = pkgFragments.length; i < length; i++) { IPackageFragment pkgFragment = pkgFragments[i]; if (this.equals(pkgFragment.getParent().getParent())) { return pkgFragment; } } // default to the first one return pkgFragments[0]; } } else if (extension.equalsIgnoreCase("egl") //$NON-NLS-1$ || extension.equalsIgnoreCase("eglbld")) { //$NON-NLS-1$ IPath packagePath = path.removeLastSegments(1); String packageName = packagePath.toString().replace(IPath.SEPARATOR, '.'); String typeName = path.lastSegment(); typeName = typeName.substring(0, typeName.length() - extension.length() - 1); String qualifiedName = null; if (packageName.length() > 0) { qualifiedName = packageName + "." + typeName; //$NON-NLS-1$ } else { qualifiedName = typeName; } IPart part = getNameLookup().findPart(qualifiedName, false, NameLookup.ACCEPT_PARTS); if (part != null) { return part.getParent(); } else { return null; } } else { // unsupported extension return null; } } catch (EGLModelException e) { if (e.getStatus().getCode() == IEGLModelStatusConstants.ELEMENT_DOES_NOT_EXIST) { return null; } else { throw e; } } } /** * @see IEGLProject */ public IPackageFragment findPackageFragment(IPath path) throws EGLModelException { return findPackageFragment0(EGLProject.canonicalizedPath(path)); } /** * non path canonicalizing version */ public IPackageFragment findPackageFragment0(IPath path) throws EGLModelException { return getNameLookup().findPackageFragment(path); } /** * @see IEGLProject */ public IPackageFragmentRoot findPackageFragmentRoot(IPath path) throws EGLModelException { return findPackageFragmentRoot0(EGLProject.canonicalizedPath(path)); } /** * no path canonicalization */ public IPackageFragmentRoot findPackageFragmentRoot0(IPath path) throws EGLModelException { IPackageFragmentRoot[] allRoots = this.getAllPackageFragmentRoots(); if (!path.isAbsolute()) { throw new IllegalArgumentException(EGLModelResources.pathMustBeAbsolute); } for (int i = 0; i < allRoots.length; i++) { IPackageFragmentRoot eglpathRoot = allRoots[i]; if (eglpathRoot.getPath().equals(path)) { return eglpathRoot; } } return null; } /** * @see IEGLProject */ public IPackageFragmentRoot[] findPackageFragmentRoots(IEGLPathEntry entry) { try { IEGLPathEntry[] eglpath = this.getRawEGLPath(); for (int i = 0, length = eglpath.length; i < length; i++) { if (eglpath[i].equals(entry)) { // entry may need to be resolved return computePackageFragmentRoots(getResolvedEGLPath( new IEGLPathEntry[] { entry }, null, true, false, null /* no reverse map */ ), false); // don't retrieve exported roots } } } catch (EGLModelException e) { } return new IPackageFragmentRoot[] { }; } /** * @see IEGLProject#findPart(String) */ public IPart findPart(String fullyQualifiedName) throws EGLModelException { IPart type = this.getNameLookup().findPart(fullyQualifiedName, false, NameLookup.ACCEPT_PARTS); if (type == null) { // try to find enclosing type int lastDot = fullyQualifiedName.lastIndexOf('.'); if (lastDot == -1) return null; type = this.findPart(fullyQualifiedName.substring(0, lastDot)); if (type != null) { type = type.getPart(fullyQualifiedName.substring(lastDot + 1)); if (!type.exists()) { return null; } } } return type; } /** * @see IEGLProject#findPart(String, String) */ public IPart findPart(String packageName, String typeQualifiedName) throws EGLModelException { return this.getNameLookup().findPart(typeQualifiedName, packageName, false, NameLookup.ACCEPT_PARTS); } /** * Returns the eglpath entry that refers to the given path or <code>null</code> * if there is no reference to the path. */ public IEGLPathEntry getEGLPathEntryFor(IPath path) throws EGLModelException { IEGLPathEntry[] entries = getExpandedEGLPath(true); for (int i = 0; i < entries.length; i++) { if (entries[i].getPath().equals(path)) { return entries[i]; } } return null; } /** * Find the specific EGL command amongst the build spec of a given * description */ private ICommand getCommand(IProjectDescription description, String builderID) throws CoreException { ICommand[] commands = description.getBuildSpec(); for (int i = 0; i < commands.length; ++i) { if (commands[i].getBuilderName().equals(builderID)) { return commands[i]; } } return null; } /** * Convenience method that returns the specific type of info for a EGL * project. */ protected EGLProjectElementInfo getEGLProjectElementInfo() throws EGLModelException { return (EGLProjectElementInfo) getElementInfo(); } /** * This is a helper method returning the expanded eglpath for the project, * as a list of eglpath entries, where all eglpath variable entries have * been resolved and substituted with their final target entries. All * project exports have been appended to project entries. */ public IEGLPathEntry[] getExpandedEGLPath(boolean ignoreUnresolvedVariable) throws EGLModelException { return getExpandedEGLPath(ignoreUnresolvedVariable, false); } /** * Internal variant which can create marker on project for invalid entries, * it will also perform eglpath expansion in presence of project * prerequisites exporting their entries. */ public IEGLPathEntry[] getExpandedEGLPath(boolean ignoreUnresolvedVariable, boolean generateMarkerOnError) throws EGLModelException { ObjectVector accumulatedEntries = new ObjectVector(); this.computeExpandedEGLPath(this, ignoreUnresolvedVariable, generateMarkerOnError, new HashSet(5), accumulatedEntries); IEGLPathEntry[] expandedPath = new IEGLPathEntry[accumulatedEntries.size()]; accumulatedEntries.copyInto(expandedPath); return expandedPath; } /** * Returns the <code>char</code> that marks the start of this handles * contribution to a memento. */ protected char getHandleMementoDelimiter() { return EGLM_EGLPROJECT; } /** * @see IEGLProject */ public NameLookup getNameLookup() throws EGLModelException { EGLProjectElementInfo info = getEGLProjectElementInfo(); // lock on the project info to avoid race condition synchronized (info) { NameLookup nameLookup; if ((nameLookup = info.getNameLookup()) == null) { info.setNameLookup(nameLookup = new NameLookup(this)); } return nameLookup; } } /** * @see IEGLProject */ public IPackageFragmentRoot[] getAllPackageFragmentRoots() throws EGLModelException { return computePackageFragmentRoots(getResolvedEGLPath(true), true); } /** * Returns an array of non-java resources contained in the receiver. */ public Object[] getNonEGLResources() throws EGLModelException { return ((EGLProjectElementInfo) getElementInfo()).getNonEGLResources(this); } /* * (non-EGLdoc) * * @see com.ibm.etools.egl.internal.model.core.IEGLProject#getOption(java.lang.String, * boolean) */ public String getOption(String optionName, boolean inheritEGLCoreOptions) { // EGLTODO Fix when we have a builder preference page. // if (EGLModelManager.OptionNames.contains(optionName)){ // // Preferences preferences = getPreferences(); // if (preferences == null || preferences.isDefault(optionName)) { // return inheritEGLCoreOptions ? EGLCore.getOption(optionName) : null; // } // return preferences.getString(optionName).trim(); // } if (EGLCore.CORE_ENCODING.equals(optionName)) { return EGLCore.getOption(optionName); } return null; } /* * (non-EGLdoc) * * @see com.ibm.etools.egl.internal.model.core.IEGLProject#getOptions(boolean) */ public Map getOptions(boolean inheritEGLCoreOptions) { // TODO Auto-generated method stub return null; } /** * @see IEGLProject */ public IPath getOutputLocation() throws EGLModelException { return getOutputLocation(true); } public IPath getOutputLocation(Boolean returnDefaultIfNull) throws EGLModelException { EGLModelManager.PerProjectInfo perProjectInfo = EGLModelManager.getEGLModelManager().getPerProjectInfoCheckExistence(fProject); IPath outputLocation = perProjectInfo.outputLocation; if (outputLocation != null) return outputLocation; // force to read eglpath - will position output location as well this.getRawEGLPath(); outputLocation = perProjectInfo.outputLocation; if (outputLocation == null && returnDefaultIfNull) { return defaultOutputLocation(); } return outputLocation; } /** * @return A handle to the package fragment root identified by the given * path. This method is handle-only and the element may or may not * exist. Returns <code>null</code> if unable to generate a * handle from the path (for example, an absolute path that has * less than 1 segment. The path may be relative or absolute. */ public IPackageFragmentRoot getPackageFragmentRoot(IPath path) { if (!path.isAbsolute()) { path = getPath().append(path); } int segmentCount = path.segmentCount(); switch (segmentCount) { case 0 : return null; case 1 : // default root return getPackageFragmentRoot(getProject()); default : // a path ending with .jar/.zip is still ambiguous and could // still resolve to a source/lib folder // thus will try to guess based on existing resource if (Util.isArchiveFileName(path.lastSegment())) { IResource resource = getProject().getWorkspace().getRoot().findMember(path); if (resource != null && resource.getType() == IResource.FOLDER) { return getPackageFragmentRoot(resource); } return getPackageFragmentRoot0(path); } else if(Util.isEGLARFileName(path.lastSegment())) { //handle .eglar case IResource resource = getProject().getWorkspace().getRoot().findMember(path); if (resource != null && resource.getType() == IResource.FILE) { return getPackageFragmentRoot(resource); } return getPackageFragmentRoot0(path); } else { return getPackageFragmentRoot(getProject().getWorkspace().getRoot().getFolder(path)); } } } /** * The path is known to match a source/library folder entry. */ public IPackageFragmentRoot getFolderPackageFragmentRoot(IPath path) { if (path.segmentCount() == 1) { // default project root return getPackageFragmentRoot(getProject()); } // if ( path.toOSString().endsWith(FileInEglar.EGLAR_EXTENSION) ) { // return new EglarPackageFragmentRoot(path, this); // } else { return getPackageFragmentRoot(getProject().getWorkspace().getRoot().getFolder(path)); // } } /** * @see IEGLProject */ public IPackageFragmentRoot getPackageFragmentRoot(IResource resource) { switch (resource.getType()) { case IResource.FILE : if (Util.isEGLFileName(resource.getName())) { return new PackageFragmentRoot(resource, this, resource.getName()); } else if(Util.isEGLARFileName(resource.getName())) { return new EglarPackageFragmentRoot(resource, this, resource.getName()); }else { return null; } case IResource.FOLDER : return new PackageFragmentRoot(resource, this, resource.getName()); case IResource.PROJECT : return new PackageFragmentRoot(resource, this, ""); //$NON-NLS-1$ default : return null; } } /** * @see IEGLProject */ public IPackageFragmentRoot getPackageFragmentRoot(String jarPath) { return getPackageFragmentRoot0(EGLProject.canonicalizedPath(new Path(jarPath))); } /** * no path canonicalization */ public IPackageFragmentRoot getPackageFragmentRoot0(IPath eglPath) { if(Util.isEGLARFileName(eglPath.lastSegment())) { return new EglarPackageFragmentRoot(eglPath,this); } return new PackageFragmentRoot(null, this, "jarPackageFragment"); //$NON-NLS-1$ } /** * @see IEGLProject */ public IPackageFragmentRoot[] getPackageFragmentRoots() throws EGLModelException { //TODO The returned value does not include eglar entry... Object[] children; int length; IPackageFragmentRoot[] roots; System.arraycopy(children = getChildren(), 0, roots = new IPackageFragmentRoot[length = children.length], 0, length); return roots; } /** * Returns the package fragment root prefixed by the given path, or an * empty collection if there are no such elements in the model. */ protected IPackageFragmentRoot[] getPackageFragmentRoots(IPath path) throws EGLModelException { IPackageFragmentRoot[] roots = getAllPackageFragmentRoots(); ArrayList matches = new ArrayList(); for (int i = 0; i < roots.length; ++i) { if (path.isPrefixOf(roots[i].getPath())) { matches.add(roots[i]); } } IPackageFragmentRoot[] copy = new IPackageFragmentRoot[matches.size()]; matches.toArray(copy); return copy; } /** * @see IEGLProject */ public IPackageFragment[] getPackageFragments() throws EGLModelException { IPackageFragmentRoot[] roots = getPackageFragmentRoots(); return getPackageFragmentsInRoots(roots); } /** * Returns all the package fragments found in the specified package * fragment roots. */ public IPackageFragment[] getPackageFragmentsInRoots(IPackageFragmentRoot[] roots) { ArrayList frags = new ArrayList(); for (int i = 0; i < roots.length; i++) { IPackageFragmentRoot root = roots[i]; try { IEGLElement[] rootFragments = root.getChildren(); for (int j = 0; j < rootFragments.length; j++) { frags.add(rootFragments[j]); } } catch (EGLModelException e) { // do nothing } } IPackageFragment[] fragments = new IPackageFragment[frags.size()]; frags.toArray(fragments); return fragments; } /* * @see IEGLElement */ public IPath getPath() { return this.getProject().getFullPath(); } /** * @see IEGLProject */ public IProject getProject() { return fProject; } /** * Returns the project custom preference pool. Project preferences may * include custom encoding. */ public Preferences getPreferences() { IProject project = getProject(); if (!EGLProject.hasEGLNature(project)) return null; EGLModelManager.PerProjectInfo perProjectInfo = EGLModelManager.getEGLModelManager().getPerProjectInfo(project, true); Preferences preferences = perProjectInfo.preferences; if (preferences != null) return preferences; preferences = loadPreferences(); if (preferences == null) preferences = new Preferences(); perProjectInfo.preferences = preferences; return preferences; } /* * (non-EGLdoc) * * @see com.ibm.etools.egl.internal.model.core.IEGLProject#getRawEGLPath() */ public IEGLPathEntry[] getRawEGLPath() throws EGLModelException { EGLModelManager.PerProjectInfo perProjectInfo = EGLModelManager.getEGLModelManager().getPerProjectInfoCheckExistence(fProject); IEGLPathEntry[] eglpath = perProjectInfo.eglpath; if (eglpath != null) return eglpath; eglpath = this.readEGLPathFile(false /* don't create markers */ , true /* log problems */ ); // extract out the output location IPath outputLocation = null; if (eglpath != null && eglpath.length > 0) { IEGLPathEntry entry = eglpath[eglpath.length - 1]; if (entry.getContentKind() == EGLPathEntry.K_OUTPUT) { outputLocation = entry.getPath(); IEGLPathEntry[] copy = new IEGLPathEntry[eglpath.length - 1]; System.arraycopy(eglpath, 0, copy, 0, copy.length); eglpath = copy; } } if (eglpath == null) { return defaultEGLPath(); } perProjectInfo.eglpath = eglpath; perProjectInfo.outputLocation = outputLocation; return eglpath; } /** * @see IEGLProject */ public IEGLPathEntry[] getResolvedEGLPath(boolean ignoreUnresolvedEntry) throws EGLModelException { return this.getResolvedEGLPath(ignoreUnresolvedEntry, false); // generateMarkerOnError } /** * Internal variant which can create marker on project for invalid entries * and caches the resolved eglpath on perProjectInfo */ public IEGLPathEntry[] getResolvedEGLPath(boolean ignoreUnresolvedEntry, boolean generateMarkerOnError) throws EGLModelException { EGLModelManager manager = EGLModelManager.getEGLModelManager(); EGLModelManager.PerProjectInfo perProjectInfo = manager.getPerProjectInfoCheckExistence(fProject); // reuse cache if not needing to refresh markers or checking bound // variables if (ignoreUnresolvedEntry && !generateMarkerOnError && perProjectInfo != null) { // resolved path is cached on its info IEGLPathEntry[] infoPath = perProjectInfo.lastResolvedEGLPath; if (infoPath != null) return infoPath; } Map reverseMap = perProjectInfo == null ? null : new HashMap(5); IEGLPathEntry[] resolvedPath = getResolvedEGLPath( getRawEGLPath(), generateMarkerOnError ? getOutputLocation() : null, ignoreUnresolvedEntry, generateMarkerOnError, reverseMap); if (perProjectInfo != null) { if (perProjectInfo.eglpath == null // .eglpath file could not be // read && generateMarkerOnError && EGLProject.hasEGLNature(fProject)) { this.createEGLPathProblemMarker(new EGLModelStatus(IEGLModelStatusConstants.INVALID_EGLPATH_FILE_FORMAT, EGLModelResources.bind(EGLModelResources.eglpathCannotReadEGLpathFile, this.getElementName()))); } perProjectInfo.lastResolvedEGLPath = resolvedPath; perProjectInfo.resolvedPathToRawEntries = reverseMap; } return resolvedPath; } /** * Internal variant which can process any arbitrary eglpath */ public IEGLPathEntry[] getResolvedEGLPath(IEGLPathEntry[] eglpathEntries, IPath projectOutputLocation, // only set if needing full eglpath validation (and markers) boolean ignoreUnresolvedEntry, // if unresolved entries are met, should it trigger initializations boolean generateMarkerOnError, Map reverseMap) // can be null if not // interested in reverse // mapping throws EGLModelException { IEGLModelStatus status; if (generateMarkerOnError) { flushEGLPathProblemMarkers(false, false); } int length = eglpathEntries.length; ArrayList resolvedEntries = new ArrayList(); for (int i = 0; i < length; i++) { IEGLPathEntry rawEntry = eglpathEntries[i]; IPath resolvedPath; status = null; /* validation if needed */ if (generateMarkerOnError || !ignoreUnresolvedEntry) { status = EGLConventions.validateEGLPathEntry(this, rawEntry, false); if (generateMarkerOnError && !status.isOK()) createEGLPathProblemMarker(status); } switch (rawEntry.getEntryKind()) { case IEGLPathEntry.CPE_VARIABLE : IEGLPathEntry resolvedEntry = EGLCore.getResolvedEGLPathEntry(rawEntry); if (resolvedEntry == null) { if (!ignoreUnresolvedEntry) throw new EGLModelException(status); } else { if (reverseMap != null && reverseMap.get(resolvedPath = resolvedEntry.getPath()) == null) reverseMap.put(resolvedPath, rawEntry); resolvedEntries.add(resolvedEntry); } break; case IEGLPathEntry.CPE_CONTAINER : IEGLPathContainer container = EGLCore.getEGLPathContainer(rawEntry.getPath(), this); if (container == null) { if (!ignoreUnresolvedEntry) throw new EGLModelException(status); break; } IEGLPathEntry[] containerEntries = container.getEGLPathEntries(); if (containerEntries == null) break; // container was bound for (int j = 0, containerLength = containerEntries.length; j < containerLength; j++) { IEGLPathEntry cEntry = containerEntries[j]; if (generateMarkerOnError) { IEGLModelStatus containerStatus = EGLConventions.validateEGLPathEntry(this, cEntry, false); if (!containerStatus.isOK()) createEGLPathProblemMarker(containerStatus); } // if container is exported, then its nested entries // must in turn be exported (21749) if (rawEntry.isExported()) { cEntry = new EGLPathEntry( cEntry.getContentKind(), cEntry.getEntryKind(), cEntry.getPath(), cEntry.getExclusionPatterns()); // duplicate container entry for tagging it as // exported } if (reverseMap != null && reverseMap.get(resolvedPath = cEntry.getPath()) == null) reverseMap.put(resolvedPath, rawEntry); resolvedEntries.add(cEntry); } break; case IEGLPathEntry.CPE_LIBRARY: // resolve ".." in library path resolvedEntry = ((EGLPathEntry) rawEntry).resolvedDotDot(); if (resolvedEntry == null) { if (!ignoreUnresolvedEntry) throw new EGLModelException(status); } else { if (reverseMap != null && reverseMap.get(resolvedPath = resolvedEntry.getPath()) == null) reverseMap.put(resolvedPath, rawEntry); resolvedEntries.add(resolvedEntry); } // if (resolveChainedLibraries && result.rawReverseMap.get(resolvedEntry.getPath()) == null) { // // resolve Class-Path: in manifest // EGLPathEntry[] extraEntries = ((EGLPathEntry) resolvedEntry).resolvedChainedLibraries(); // for (int k = 0, length2 = extraEntries.length; k < length2; k++) { // if (!rawLibrariesPath.contains(extraEntries[k].getPath())) { // addToResult(rawEntry, extraEntries[k], result, resolvedEntries, externalFoldersManager, referencedEntriesMap, true); // } // } // } // addToResult(rawEntry, resolvedEntry, result, resolvedEntries, externalFoldersManager, referencedEntriesMap, false); break; default: if (reverseMap != null && reverseMap.get(resolvedPath = rawEntry.getPath()) == null) reverseMap.put(resolvedPath, rawEntry); resolvedEntries.add(rawEntry); } } IEGLPathEntry[] resolvedPath = new IEGLPathEntry[resolvedEntries.size()]; resolvedEntries.toArray(resolvedPath); if (generateMarkerOnError && projectOutputLocation != null) { status = EGLConventions.validateEGLPath(this, resolvedPath, projectOutputLocation); if (!status.isOK()) createEGLPathProblemMarker(status); } return resolvedPath; } /* * @see IEGLElement */ public IResource getResource() { return this.getProject(); } /** * Retrieve a shared property on a project. If the property is not defined, * answers null. Note that it is orthogonal to IResource persistent * properties, and client code has to decide which form of storage to use * appropriately. Shared properties produce real resource files which can * be shared through a VCM onto a server. Persistent properties are not * shareable. * * @see EGLProject#setSharedProperty(String, String) */ public String getSharedProperty(String key) throws CoreException { String property = null; IFile rscFile = getProject().getFile(key); if (rscFile.exists()) { try { property = new String(Util.getResourceContentsAsByteArray(rscFile), "UTF-8"); } catch (UnsupportedEncodingException e) { } }else { File file = rscFile.getLocation().toFile(); if (file != null && file.exists()) { byte[] bytes; try { BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(file)); try{ bytes = org.eclipse.edt.ide.core.internal.model.util.Util.getInputStreamAsByteArray(inputStream, (int)file.length()); }finally{ inputStream.close(); } } catch (IOException e) { return null; } try { property = new String(bytes, "UTF-8"); // .eglpath always encoded with UTF-8 } catch (UnsupportedEncodingException e) { Util.log(e, "Could not read .eglpath with UTF-8 encoding"); //$NON-NLS-1$ // fallback to default property = new String(bytes); } } } return property; } /* * (non-EGLdoc) * * @see com.ibm.etools.egl.internal.model.core.IEGLProject#hasBuildState() */ public boolean hasBuildState() { // TODO Check build state return false; } /** * @see IEGLProject */ public boolean hasEGLPathCycle(IEGLPathEntry[] preferredEGLPath) { HashSet cycleParticipants = new HashSet(); updateCycleParticipants( preferredEGLPath, new ArrayList(2), cycleParticipants, ResourcesPlugin.getWorkspace().getRoot(), new HashSet(2)); return !cycleParticipants.isEmpty(); } public boolean hasCycleMarker() { return this.getCycleMarker() != null; } public int hashCode() { return fProject.hashCode(); } /** * Answers true if the project potentially contains any source. A project * which has no source is immutable. */ public boolean hasSource() { // look if any source folder on the classpath // no need for resolved path given source folder cannot be abstracted IEGLPathEntry[] entries; try { entries = this.getRawEGLPath(); } catch (EGLModelException e) { return true; // unsure } for (int i = 0, max = entries.length; i < max; i++) { if (entries[i].getEntryKind() == IEGLPathEntry.CPE_SOURCE) { return true; } } return false; } /** * Returns true if the given project is accessible and it has a egl nature, * otherwise false. */ public static boolean hasEGLNature(IProject project) { try { return project.hasNature(EGLCore.NATURE_ID); } catch (CoreException e) { // project does not exist or is not open } return false; } /** * Returns true if the given project is accessible and it has a rui nature, * otherwise false. */ public static boolean hasRUINature(IProject project) { try { return project.hasNature(RUINature.RUI_NATURE_ID); } catch (CoreException e) { // project does not exist or is not open } return false; } /** * Returns true if the given project is accessible and it has a CE nature, * otherwise false. */ public static boolean hasCENature(IProject project) { try { return project.hasNature(CENature.CE_NATURE_ID); } catch (CoreException e) { // project does not exist or is not open } return false; } /** * Compare current eglpath with given one to see if any different. Note * that the argument classpath contains its binary output. */ public boolean isEGLPathEqualsTo(IEGLPathEntry[] newEGLPath, IPath newOutputLocation, IEGLPathEntry[] otherEGLPathWithOutput) throws EGLModelException { if (otherEGLPathWithOutput != null && otherEGLPathWithOutput.length > 0) { int length = otherEGLPathWithOutput.length; if (length == newEGLPath.length + 1) { // output is amongst file entries (last one) // compare classpath entries for (int i = 0; i < length - 1; i++) { if (!otherEGLPathWithOutput[i].equals(newEGLPath[i])) return false; } // compare binary outputs IEGLPathEntry output = otherEGLPathWithOutput[length - 1]; if (output.getContentKind() == EGLPathEntry.K_OUTPUT && output.getPath().equals(newOutputLocation)) return true; } } return false; } /* * @see IEGLProject */ public boolean isOnEGLPath(IEGLElement element) { IPath path = element.getPath(); switch (element.getElementType()) { case IEGLElement.PACKAGE_FRAGMENT_ROOT : if (!((IPackageFragmentRoot) element).isArchive()) { // ensure that folders are only excluded if all of their // children are excluded path = path.append("*"); //$NON-NLS-1$ } break; case IEGLElement.PACKAGE_FRAGMENT : if (!((IPackageFragmentRoot) element.getParent()).isArchive()) { // ensure that folders are only excluded if all of their // children are excluded path = path.append("*"); //$NON-NLS-1$ } break; } return this.isOnEGLPath(path); } private boolean isOnEGLPath(IPath path) { IEGLPathEntry[] classpath; try { classpath = this.getResolvedEGLPath(true /* * ignore unresolved * variable */ ); } catch (EGLModelException e) { return false; // not a EGL project } for (int i = 0; i < classpath.length; i++) { IEGLPathEntry entry = classpath[i]; if (entry.getPath().isPrefixOf(path) && !Util.isExcluded(path, ((EGLPathEntry) entry).fullExclusionPatternChars())) { return true; } } return false; } /* * @see IEGLProject */ public boolean isOnEGLPath(IResource resource) { IPath path = resource.getFullPath(); // ensure that folders are only excluded if all of their children are // excluded if (resource.getType() == IResource.FOLDER) { path = path.append("*"); //$NON-NLS-1$ } return this.isOnEGLPath(path); } /* * load preferences from a shareable format (VCM-wise) */ public Preferences loadPreferences() { Preferences preferences = new Preferences(); // File prefFile = // getProject().getLocation().append(PREF_FILENAME).toFile(); IPath projectMetaLocation = getProject().getPluginWorkingLocation(EDTCoreIDEPlugin.getPlugin().getDescriptor()); if (projectMetaLocation != null) { File prefFile = projectMetaLocation.append(PREF_FILENAME).toFile(); if (prefFile.exists()) { // load preferences from file InputStream in = null; try { in = new BufferedInputStream(new FileInputStream(prefFile)); preferences.load(in); return preferences; } catch (IOException e) { // problems loading preference store // - quietly ignore } finally { if (in != null) { try { in.close(); } catch (IOException e) { // ignore problems with close } } } } } return null; } /** * Open project if resource isn't closed */ protected void openWhenClosed(IProgressMonitor pm) throws EGLModelException { if (!this.fProject.isOpen()) { throw newNotPresentException(); } else { super.openWhenClosed(pm); } } /** * Reads the .eglpath file from disk and returns the list of entries it * contains (including output location entry) Returns null if .eglpath is * not present. Returns INVALID_EGLPATH if it has a format problem. */ protected IEGLPathEntry[] readEGLPathFile(boolean createMarker, boolean logProblems) { try { String xmlPath = getSharedProperty(EGLPATH_FILENAME); if (xmlPath == null) return null; return decodeEGLPath(xmlPath, createMarker, logProblems); } catch (CoreException e) { // file does not exist (or not accessible) if (createMarker && this.getProject().isAccessible()) { this.createEGLPathProblemMarker(new EGLModelStatus(IEGLModelStatusConstants.INVALID_EGLPATH_FILE_FORMAT, EGLModelResources.bind(EGLModelResources.eglpathCannotReadEGLpathFile, this.getElementName()))); } if (logProblems) { Util.log(e, "Exception while retrieving " + this.getPath() //$NON-NLS-1$ +"/.eglpath, will revert to default eglpath"); //$NON-NLS-1$ } } return null; } /** * Removes the given builder from the build spec for the given project. */ protected void removeFromBuildSpec(String builderID) throws CoreException { IProjectDescription description = getProject().getDescription(); ICommand[] commands = description.getBuildSpec(); for (int i = 0; i < commands.length; ++i) { if (commands[i].getBuilderName().equals(builderID)) { ICommand[] newCommands = new ICommand[commands.length - 1]; System.arraycopy(commands, 0, newCommands, 0, i); System.arraycopy(commands, i + 1, newCommands, i, commands.length - i - 1); description.setBuildSpec(newCommands); getProject().setDescription(description, null); return; } } } public String[] projectPrerequisites(IEGLPathEntry[] entries) throws EGLModelException { ArrayList prerequisites = new ArrayList(); // need resolution entries = getResolvedEGLPath(entries, null, true, false, null /* * no * reverse * map */ ); for (int i = 0, length = entries.length; i < length; i++) { IEGLPathEntry entry = entries[i]; if (entry.getEntryKind() == IEGLPathEntry.CPE_PROJECT) { prerequisites.add(entry.getPath().lastSegment()); } } int size = prerequisites.size(); if (size == 0) { return NO_PREREQUISITES; } else { String[] result = new String[size]; prerequisites.toArray(result); return result; } } /** * @see EGLElement#rootedAt(IEGLProject) */ public IEGLElement rootedAt(IEGLProject project) { return project; } /** * Answers an ID which is used to distinguish project/entries during * package fragment root computations */ public String rootID() { return "[PRJ]" + this.getProject().getFullPath(); //$NON-NLS-1$ } /** * Update the EGL command in the build spec (replace existing one if * present, add one first if none). */ private void setEGLCommand(IProjectDescription description, ICommand newCommand, String builderID, boolean bInsert2First) throws CoreException { ICommand[] oldCommands = description.getBuildSpec(); ICommand oldEGLCommand = getCommand(description, builderID); ICommand[] newCommands; if (oldEGLCommand == null) { // Add a EGL build spec before other builders (1FWJK7I) newCommands = new ICommand[oldCommands.length + 1]; if(bInsert2First){ System.arraycopy(oldCommands, 0, newCommands, 1, oldCommands.length); newCommands[0] = newCommand; } else { System.arraycopy(oldCommands, 0, newCommands, 0, oldCommands.length); newCommands[newCommands.length-1] = newCommand; } } else { for (int i = 0, max = oldCommands.length; i < max; i++) { if (oldCommands[i] == oldEGLCommand) { oldCommands[i] = newCommand; break; } } newCommands = oldCommands; } // Commit the spec change into the project description.setBuildSpec(newCommands); getProject().setDescription(description, null); } /** * Saves the eglpath in a shareable format (VCM-wise) only when necessary, * that is, if it is semantically different from the existing one in file. * Will never write an identical one. * * @return Return whether the .eglpath file was modified. */ public boolean saveEGLPath(IEGLPathEntry[] newEGLPath, IPath newOutputLocation) throws EGLModelException { if (!getProject().exists()) return false; IEGLPathEntry[] fileEntries = readEGLPathFile(false /* * don't create * markers */ , false /* don't log problems */ ); if (fileEntries != null && isEGLPathEqualsTo(newEGLPath, newOutputLocation, fileEntries)) { // no need to save it, it is the same return false; } // actual file saving try { setSharedProperty(EGLPATH_FILENAME, encodeEGLPath(newEGLPath, newOutputLocation, true)); return true; } catch (CoreException e) { throw new EGLModelException(e); } } /** * Save project custom preferences to shareable file (.jprefs) */ private void savePreferences(Preferences preferences) { IProject project = getProject(); if (!EGLProject.hasEGLNature(project)) return; // ignore if (preferences == null || (!preferences.needsSaving() && preferences.propertyNames().length != 0)) { // nothing to save return; } // preferences need to be saved // the preferences file is located in the plug-in's state area // at a well-known name (.eprefs) // File prefFile = // getProject().getLocation().append(PREF_FILENAME).toFile(); File prefFile = project.getPluginWorkingLocation(EDTCoreIDEPlugin.getPlugin().getDescriptor()).append(PREF_FILENAME).toFile(); if (preferences.propertyNames().length == 0) { // there are no preference settings // rather than write an empty file, just delete any existing file if (prefFile.exists()) { prefFile.delete(); // don't worry if delete unsuccessful } return; } // write file, overwriting an existing one OutputStream out = null; try { // do it as carefully as we know how so that we don't lose/mangle // the setting in times of stress out = new BufferedOutputStream(new FileOutputStream(prefFile)); preferences.store(out, null); } catch (IOException e) { // problems saving preference store - quietly // ignore } finally { if (out != null) { try { out.close(); } catch (IOException e) { // ignore problems with close } } } } /* * (non-EGLdoc) * * @see com.ibm.etools.egl.internal.model.core.IEGLProject#setOptions(java.util.Map) */ public void setOptions(Map newOptions) { Preferences preferences; setPreferences(preferences = new Preferences()); // always reset (26255) if (newOptions != null) { Iterator keys = newOptions.keySet().iterator(); while (keys.hasNext()) { String key = (String) keys.next(); if (!EGLModelManager.OptionNames.contains(key)) continue; // unrecognized option // no filtering for encoding (custom encoding for project is // allowed) String value = (String) newOptions.get(key); preferences.setDefault(key, CUSTOM_DEFAULT_OPTION_VALUE); // empty string isn't the default (26251) preferences.setValue(key, value); } } // persist options savePreferences(preferences); } /* * (non-EGLdoc) * * @see com.ibm.etools.egl.internal.model.core.IEGLProject#setOutputLocation(org.eclipse.core.runtime.IPath, * org.eclipse.core.runtime.IProgressMonitor) */ public void setOutputLocation(IPath path, IProgressMonitor monitor) throws EGLModelException { if (path == null) { throw new IllegalArgumentException(EGLModelResources.pathNullPath); } if (path.equals(getOutputLocation())) { return; } this.setRawEGLPath(SetEGLPathOperation.ReuseEGLPath, path, monitor); } /** * @see IEGLProject */ public void setRawEGLPath(IEGLPathEntry[] entries, IPath outputLocation, IProgressMonitor monitor) throws EGLModelException { setRawEGLPath(entries, outputLocation, monitor, true, // canChangeResource (as per API contract) getResolvedEGLPath(true), // ignoreUnresolvedVariable true, // needValidation true); // need to save } public void setRawEGLPath( IEGLPathEntry[] newEntries, IPath newOutputLocation, IProgressMonitor monitor, boolean canChangeResource, IEGLPathEntry[] oldResolvedPath, boolean needValidation, boolean needSave) throws EGLModelException { EGLModelManager manager = EGLModelManager.getEGLModelManager(); try { IEGLPathEntry[] newRawPath = newEntries; if (newRawPath == null) { //are we already with the default // eglpath newRawPath = defaultEGLPath(); } SetEGLPathOperation op = new SetEGLPathOperation(this, oldResolvedPath, newRawPath, newOutputLocation, canChangeResource, needValidation, needSave); op.runOperation(monitor); } catch (EGLModelException e) { manager.flush(); throw e; } } /** * @see IEGLProject */ public void setRawEGLPath(IEGLPathEntry[] entries, IProgressMonitor monitor) throws EGLModelException { setRawEGLPath(entries, SetEGLPathOperation.ReuseOutputLocation, monitor, true, // canChangeResource (as per API contract) getResolvedEGLPath(true), // ignoreUnresolvedVariable true, // needValidation true); // need to save } /** * Record a shared persistent property onto a project. Note that it is * orthogonal to IResource persistent properties, and client code has to * decide which form of storage to use appropriately. Shared properties * produce real resource files which can be shared through a VCM onto a * server. Persistent properties are not shareable. * * shared properties end up in resource files, and thus cannot be modified * during delta notifications (a CoreException would then be thrown). * * @see EGLProject#getSharedProperty(String key) */ public void setSharedProperty(String key, String value) throws CoreException { IFile rscFile = getProject().getFile(key); byte[] bytes = null; try{ bytes = value.getBytes("UTF-8");//$NON-NLS-1$ }catch (UnsupportedEncodingException e) { Util.log(e, "Could not write .eglpath with UTF-8 encoding "); //$NON-NLS-1$ // fallback to default bytes = value.getBytes(); } InputStream inputStream = new ByteArrayInputStream(bytes); // update the resource content if (rscFile.exists()) { if (rscFile.isReadOnly()) { // provide opportunity to checkout read-only .eglpath file ResourcesPlugin.getWorkspace().validateEdit(new IFile[] { rscFile }, null); } rscFile.setContents(inputStream, IResource.FORCE, null); } else { rscFile.create(inputStream, IResource.FORCE, null); } rscFile.setCharset("UTF-8"); } /** * NOTE: <code>null</code> specifies default eglpath, and an empty array * specifies an empty eglpath. * * @exception NotPresentException * if this project does not exist. */ public void setRawEGLPath0(IEGLPathEntry[] rawEntries) throws EGLModelException { EGLModelManager.PerProjectInfo info = EGLModelManager.getEGLModelManager().getPerProjectInfoCheckExistence(fProject); synchronized (info) { if (rawEntries != null) { info.eglpath = rawEntries; } // clear cache of resolved eglpath info.lastResolvedEGLPath = null; info.resolvedPathToRawEntries = null; } } /** * If a cycle is detected, then cycleParticipants contains all the paths of * projects involved in this cycle (directly and indirectly), no cycle if * the set is empty (and started empty) */ public void updateCycleParticipants( IEGLPathEntry[] preferredEGLPath, ArrayList prereqChain, HashSet cycleParticipants, IWorkspaceRoot workspaceRoot, HashSet traversed) { IPath path = this.getPath(); prereqChain.add(path); traversed.add(path); try { IEGLPathEntry[] eglpath = preferredEGLPath == null ? getResolvedEGLPath(true) : preferredEGLPath; for (int i = 0, length = eglpath.length; i < length; i++) { IEGLPathEntry entry = eglpath[i]; if (entry.getEntryKind() == IEGLPathEntry.CPE_PROJECT) { IPath prereqProjectPath = entry.getPath(); int index = cycleParticipants.contains(prereqProjectPath) ? 0 : prereqChain.indexOf(prereqProjectPath); if (index >= 0) { // refer to cycle, or in cycle itself for (int size = prereqChain.size(); index < size; index++) { cycleParticipants.add(prereqChain.get(index)); } } else { if (!traversed.contains(prereqProjectPath)) { IResource member = workspaceRoot.findMember(prereqProjectPath); if (member != null && member.getType() == IResource.PROJECT) { EGLProject project = (EGLProject) EGLCore.create((IProject) member); project.updateCycleParticipants(null, prereqChain, cycleParticipants, workspaceRoot, traversed); } } } } } } catch (EGLModelException e) { } prereqChain.remove(path); } /* * (non-EGLdoc) * * @see com.ibm.etools.egl.internal.model.core.IParent#hasChildren() */ public boolean hasChildren() throws EGLModelException { // TODO Auto-generated method stub return false; } /** * Reset the collection of package fragment roots (local ones) - only if * opened. Need to check *all* package fragment roots in order to reset * NameLookup */ public void updatePackageFragmentRoots() { if (this.isOpen()) { try { EGLProjectElementInfo info = getEGLProjectElementInfo(); IEGLPathEntry[] eglpath = getResolvedEGLPath(true); NameLookup lookup = info.getNameLookup(); if (lookup != null) { IPackageFragmentRoot[] oldRoots = lookup.fPackageFragmentRoots; IPackageFragmentRoot[] newRoots = computePackageFragmentRoots(eglpath, true); checkIdentical : { // compare all pkg fragment root lists if (oldRoots.length == newRoots.length) { for (int i = 0, length = oldRoots.length; i < length; i++) { if (!oldRoots[i].equals(newRoots[i])) { break checkIdentical; } } return; // no need to update } } info.setNameLookup(null); // discard name lookup (hold onto roots) } info.setNonEGLResources(null); info.setChildren(computePackageFragmentRoots(eglpath, false)); } catch (EGLModelException e) { try { close(); // could not do better } catch (EGLModelException ex) { } } } } public static void updateAllCycleMarkers() throws EGLModelException { EGLModelManager manager = EGLModelManager.getEGLModelManager(); IEGLProject[] projects = manager.getEGLModel().getEGLProjects(); IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); HashSet cycleParticipants = new HashSet(); HashSet traversed = new HashSet(); int length = projects.length; // compute cycle participants ArrayList prereqChain = new ArrayList(); for (int i = 0; i < length; i++) { EGLProject project = (EGLProject) projects[i]; if (!traversed.contains(project.getPath())) { prereqChain.clear(); project.updateCycleParticipants(null, prereqChain, cycleParticipants, workspaceRoot, traversed); } } //System.out.println("updateAllCycleMarkers: " + // (System.currentTimeMillis() - start) + " ms"); for (int i = 0; i < length; i++) { EGLProject project = (EGLProject) projects[i]; if (cycleParticipants.contains(project.getPath())) { IMarker cycleMarker = project.getCycleMarker(); int circularCPSeverity = IMarker.SEVERITY_ERROR; if (cycleMarker != null) { // update existing cycle marker if needed try { int existingSeverity = ((Integer) cycleMarker.getAttribute(IMarker.SEVERITY)).intValue(); if (existingSeverity != circularCPSeverity) { cycleMarker.setAttribute(IMarker.SEVERITY, circularCPSeverity); } } catch (CoreException e) { throw new EGLModelException(e); } } else { // create new marker project.createEGLPathProblemMarker(new EGLModelStatus(IEGLModelStatusConstants.EGLPATH_CYCLE, project)); } } else { project.flushEGLPathProblemMarkers(true, false); } } } /* * Set cached preferences, no preference file is saved, only info is * updated */ public void setPreferences(Preferences preferences) { IProject project = getProject(); if (!EGLProject.hasEGLNature(project)) return; // ignore EGLModelManager.PerProjectInfo perProjectInfo = EGLModelManager.getEGLModelManager().getPerProjectInfo(project, true); perProjectInfo.preferences = preferences; } /** * @param project */ public void setProject(IProject project) { fProject = project; } public IPath getBuildStateLocation() { return getProject().getFullPath().append(".buildstate"); //$NON-NLS-1$ } public class EGLPartWrapper { public static final String NO_VALUE_SET = ""; //$NON-NLS-1$ public String partName = NO_VALUE_SET; public String partPath = NO_VALUE_SET; public EGLPartWrapper(String partName, String partPath) { super(); this.partName = partName; this.partPath = partPath; } } public boolean isReadOnly() { //Check for the .readonly file if (getProject().findMember(".readonly") != null) { return true; } return isBinary(); } public EGLModelManager.PerProjectInfo getPerProjectInfo() throws EGLModelException { return EGLModelManager.getEGLModelManager().getPerProjectInfoCheckExistence(this.fProject); } /* * Resets this project's caches */ public void resetCaches() { //TODO Rocky, looks like EGL doesn't not have the cache... // EGLProjectElementInfo info = (EGLProjectElementInfo) EGLModelManager.getEGLModelManager().peekAtInfo(this); // if (info != null){ // info.resetCaches(); // } } public String[] getRequiredProjectNames() throws EGLModelException { return this.projectPrerequisites(getResolvedEGLPath(true)); } public boolean isBinary() { //Check for the binary project flag in the .eglproject IEGLProjectFileUtility util = EGLProjectFileUtilityLocator.INSTANCE.getUtil(); if (util != null) { if (util.isBinaryProject(getProject())) { return true; } } //Check to see if there is an output entry in the .eglpath try { EGLModelManager.PerProjectInfo perProjectInfo = EGLModelManager.getEGLModelManager().getPerProjectInfoCheckExistence(getProject()); //First check to see if the output location is already in the info if (perProjectInfo.outputLocation != null) { return false; } //The .eglpath file may not have been read yet, force it to read getRawEGLPath(); //At this point, if there is a output directory specified, it would have been read and set in the info return (perProjectInfo.outputLocation == null); } catch (EGLModelException e) { } return false; } @Override public IEGLProject[] getReferencingProjects() throws EGLModelException { IProject[] projects = fProject.getWorkspace().getRoot().getProjects(IContainer.INCLUDE_HIDDEN); List<IEGLProject> result = new ArrayList<IEGLProject>(projects.length); for (IProject project : projects) { if (!project.isAccessible() || (project.equals(fProject))) { continue; } IEGLProject eglProject = EGLCore.create(project); String[] referencedProjectNames = eglProject.getRequiredProjectNames(); if(referencedProjectNames == null || (referencedProjectNames.length == 0)) { continue; } for(String eglProjectName : referencedProjectNames) { if(fProject.getName().equals(eglProjectName)) { result.add(eglProject); break; } } } return result.toArray(new IEGLProject[result.size()]); } }