/*******************************************************************************
* Copyright (c) 2006 Zend Corporation and 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:
* Zend and IBM - Initial implementation
*******************************************************************************/
package org2.eclipse.php.internal.core.project.options.includepath;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ProjectScope;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.resources.WorkspaceJob;
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.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.osgi.util.NLS;
import org.eclipse.ui.preferences.IWorkingCopyManager;
import org.w3c.dom.Element;
import org2.eclipse.php.internal.core.CoreMessages;
import org2.eclipse.php.internal.core.project.IIncludePathEntry;
import org2.eclipse.php.internal.core.project.options.PHPProjectOptions;
import org2.eclipse.php.internal.core.project.options.XMLWriter;
import org2.eclipse.php.internal.core.util.preferences.XMLPreferencesReader;
import com.aptana.core.util.StringUtil;
import com.aptana.editor.php.epl.PHPEplPlugin;
import com.aptana.editor.php.util.Key;
public class IncludePathEntry implements IIncludePathEntry
{
public static final String TAG_INCLUDEPATH = "includepath"; //$NON-NLS-1$
public static final String TAG_INCLUDEPATHENTRY = "includepathentry"; //$NON-NLS-1$
public static final String TAG_ENTRY_KIND = "kind"; //$NON-NLS-1$
public static final String TAG_CONTENT_KIND = "contentKind"; //$NON-NLS-1$
public static final String TAG_PATH = "path"; //$NON-NLS-1$
public static final String TAG_RESOURCE = "resource"; //$NON-NLS-1$
public static final String TAG_ROOTPATH = "rootpath"; //$NON-NLS-1$
public static final String TAG_EXPORTED = "exported"; //$NON-NLS-1$
public static final String TAG_CREATEDREFERENCE = "createdReference"; //$NON-NLS-1$
public int entryKind;
public int contentKind;
public IPath path;
public IResource resource;
public boolean isExported;
private boolean createdReference;
/**
* Creates a class path entry of the specified kind with the given path.
*/
public IncludePathEntry(int contentKind, int entryKind, IPath path, IResource resource, boolean isExported)
{
this.contentKind = contentKind;
this.entryKind = entryKind;
this.path = path;
this.resource = resource;
this.isExported = isExported;
}
/**
* This method gets the include path entries for a given project
*
* @param preferenceKey
* @param project
* @param projectScope
* @param workingCopyManager
* @return List of IIncludePathEntrys for a given project
*/
public static List<IIncludePathEntry> getIncludePathEntriesFromPreferences(Key preferenceKey, IProject project,
ProjectScope projectScope, IWorkingCopyManager workingCopyManager)
{
if (preferenceKey == null || project == null || projectScope == null)
{
throw new IllegalArgumentException("Null arguments are not allowed"); //$NON-NLS-1$
}
List<IIncludePathEntry> entries = new ArrayList<IIncludePathEntry>();
Map[] maps = XMLPreferencesReader.read(preferenceKey, projectScope, workingCopyManager);
if (maps != null)
{
for (Map map : maps)
{
IncludePathEntryDescriptor descriptor = new IncludePathEntryDescriptor();
descriptor.restoreFromMap(map);
entries.add(IncludePathEntry.elementDecode(descriptor, project.getFullPath()));
}
}
return entries;
}
/**
* This method gets the include path entries for a given project as a string and returns a "decoded" List of
* IIncludePathEntrys
*
* @param String
* representing the entries they way they are saved into the preferences
* @param project
* @return List of IIncludePathEntrys for a given project
*/
public static List<IIncludePathEntry> getIncludePathEntriesFromPreferences(String entriesString, IProject project)
{
if (entriesString == null || project == null)
{
throw new IllegalArgumentException("Null arguments are not allowed"); //$NON-NLS-1$
}
List<IIncludePathEntry> entries = new ArrayList<IIncludePathEntry>();
Map[] maps = XMLPreferencesReader.getHashFromStoredValue(entriesString);
if (maps != null)
{
for (Map map : maps)
{
IncludePathEntryDescriptor descriptor = new IncludePathEntryDescriptor();
descriptor.restoreFromMap(map);
entries.add(IncludePathEntry.elementDecode(descriptor, project.getFullPath()));
}
}
return entries;
}
public int getContentKind()
{
return contentKind;
}
public int getEntryKind()
{
return entryKind;
}
public IPath getPath()
{
return this.path;
}
public IResource getResource()
{
return this.resource;
}
public boolean isExported()
{
return isExported;
}
public static IIncludePathEntry elementDecode(Element element, PHPProjectOptions options)
{
if (element == null || options == null)
{
throw new IllegalArgumentException("Null arguments are not allowed"); //$NON-NLS-1$
}
IPath projectPath = options.getProject().getFullPath();
String entryKindAttr = element.getAttribute(TAG_ENTRY_KIND);
String contentKindAttr = element.getAttribute(TAG_CONTENT_KIND);
String pathAttr = element.getAttribute(TAG_PATH);
String resourceAttr = element.getAttribute(TAG_RESOURCE);
// exported flag (optional)
boolean isExported = element.getAttribute(TAG_EXPORTED).equals("true"); //$NON-NLS-1$
IIncludePathEntry entry = getEntry(pathAttr, entryKindAttr, contentKindAttr, resourceAttr, isExported,
projectPath);
return entry;
}
public static IIncludePathEntry elementDecode(IncludePathEntryDescriptor descriptor, IPath projectPath)
{
if (descriptor == null || projectPath == null)
{
throw new IllegalArgumentException("Null arguments are not allowed"); //$NON-NLS-1$
}
IIncludePathEntry entry = getEntry(descriptor.getPath(), descriptor.getEntryKind(),
descriptor.getContentKind(), descriptor.getResourceName(), descriptor.isExported(), projectPath);
return entry;
}
public static IIncludePathEntry getEntry(String sPath, String sEntryKind, String sContentKind, String sResource,
boolean isExported, IPath projectPath)
{
if (sPath == null || sEntryKind == null || sContentKind == null || sResource == null || projectPath == null)
{
throw new IllegalArgumentException("Null arguments are not allowed"); //$NON-NLS-1$
}
// ensure path is absolute
IPath path = new Path(sPath);
int entryKind = entryKindFromString(sEntryKind);
if (entryKind != IIncludePathEntry.IPE_VARIABLE && entryKind != IIncludePathEntry.IPE_CONTAINER
&& !path.isAbsolute())
{
path = projectPath.append(path);
}
IResource resource = null;
// recreate the CP entry
IIncludePathEntry entry = null;
switch (entryKind)
{
case IIncludePathEntry.IPE_PROJECT:
try
{
resource = ResourcesPlugin.getWorkspace().getRoot().getProject(sResource);
}
catch (Exception e)
{
// Do nothing
}
entry = newProjectEntry(path, resource, isExported);
break;
case IIncludePathEntry.IPE_LIBRARY:
case IIncludePathEntry.IPE_JRE:
entry = new IncludePathEntry(contentKindFromString(sContentKind), IIncludePathEntry.IPE_LIBRARY, path,
resource, isExported);
break;
case IIncludePathEntry.IPE_SOURCE:
// must be an entry in this project or specify another project
entry = newSourceEntry(path, resource);
break;
case IIncludePathEntry.IPE_VARIABLE:
entry = newVariableEntry(path, resource, isExported);
break;
case IIncludePathEntry.IPE_CONTAINER:
entry = newContainerEntry(path, resource, isExported);
break;
default:
throw new AssertionError(NLS.bind(CoreMessages.getString("includePath_unknownKind"), sEntryKind));
}
return entry;
}
public static IIncludePathEntry newProjectEntry(IPath path, IResource resource, boolean isExported)
{
if (path == null || resource == null)
{
throw new IllegalArgumentException("Null arguments are not allowed"); //$NON-NLS-1$
}
if (!path.isAbsolute())
{
throw new IllegalArgumentException("Path for IIncludePathEntry must be absolute"); //$NON-NLS-1$
}
return new IncludePathEntry(K_SOURCE, IIncludePathEntry.IPE_PROJECT, path, resource, isExported);
}
public static IIncludePathEntry newContainerEntry(IPath containerPath, IResource containerResource,
boolean isExported)
{
if (containerPath == null)
{
throw new IllegalArgumentException("Container path cannot be null"); //$NON-NLS-1$
}
if (containerPath.segmentCount() < 1)
{
throw new IllegalArgumentException(
"Illegal include path container path: \'" + containerPath.makeRelative().toString() + "\', must have at least one segment (containerID+hints)"); //$NON-NLS-1$//$NON-NLS-2$
}
return new IncludePathEntry(K_SOURCE, IIncludePathEntry.IPE_CONTAINER, containerPath, containerResource,
isExported);
}
public static IIncludePathEntry newVariableEntry(IPath variablePath, IResource variableResource, boolean isExported)
{
if (variablePath == null)
{
throw new IllegalArgumentException("Variable path cannot be null"); //$NON-NLS-1$
}
if (variablePath.segmentCount() < 1)
{
throw new IllegalArgumentException(
"Illegal classpath variable path: \'" + variablePath.makeRelative().toString() + "\', must have at least one segment"); //$NON-NLS-1$//$NON-NLS-2$
}
return new IncludePathEntry(K_SOURCE, IIncludePathEntry.IPE_VARIABLE, variablePath, variableResource,
isExported);
}
public static IIncludePathEntry newSourceEntry(IPath path, IResource resource)
{
if (path == null)
{
throw new IllegalArgumentException("Source path cannot be null"); //$NON-NLS-1$
}
if (!path.isAbsolute())
{
throw new IllegalArgumentException("Path for IIncludePathEntry must be absolute"); //$NON-NLS-1$
}
return new IncludePathEntry(K_SOURCE, IIncludePathEntry.IPE_SOURCE, path, resource, false);
}
public void elementEncode(XMLWriter writer, IPath projectPath, boolean newLine)
{
// Keeping this as a HashMap (not a Map) for the XMLWriter
HashMap parameters = new HashMap();
parameters.put(TAG_ENTRY_KIND, IncludePathEntry.entryKindToString(this.entryKind));
parameters.put(TAG_CONTENT_KIND, IncludePathEntry.contentKindToString(this.contentKind));
parameters.put(TAG_CREATEDREFERENCE, createdReference ? "true" : "false"); //$NON-NLS-1$ //$NON-NLS-2$
IPath xmlPath = this.path;
if (this.entryKind != IIncludePathEntry.IPE_VARIABLE && this.entryKind != IIncludePathEntry.IPE_CONTAINER)
{
// translate to project relative from absolute (unless a device path)
if (projectPath != null && projectPath.isPrefixOf(xmlPath))
{
if (xmlPath.segment(0).equals(projectPath.segment(0)))
{
xmlPath = xmlPath.removeFirstSegments(1);
xmlPath = xmlPath.makeRelative();
}
else
{
xmlPath = xmlPath.makeAbsolute();
}
}
}
parameters.put(TAG_PATH, String.valueOf(xmlPath));
if (resource != null)
{
parameters.put(TAG_RESOURCE, resource.getName());
}
if (this.isExported)
{
parameters.put(TAG_EXPORTED, "true");//$NON-NLS-1$
}
writer.printTag(TAG_INCLUDEPATHENTRY, parameters);
writer.endTag(TAG_INCLUDEPATHENTRY);
}
public String elementEncode(IPath projectPath)
{
IncludePathEntryDescriptor descriptor = new IncludePathEntryDescriptor(this, projectPath);
return descriptor.toString();
}
public static void updateProjectReferences(IIncludePathEntry[] newEntries, IIncludePathEntry[] oldEntries,
final IProject project, SubProgressMonitor monitor)
{
try
{
boolean changedReferences = false;
final IProjectDescription projectDescription = project.getDescription();
List<IProject> referenced = new ArrayList<IProject>();
List<String> referencedNames = new ArrayList<String>();
IProject[] referencedProjects = projectDescription.getReferencedProjects();
for (IProject refProject : referencedProjects)
{
referenced.add(refProject);
referencedNames.add(refProject.getName());
}
for (IIncludePathEntry oldEntry : oldEntries)
{
if (oldEntry.getEntryKind() == IIncludePathEntry.IPE_PROJECT)
{
String projectName = oldEntry.getPath().lastSegment();
if (!containsProject(newEntries, projectName))
{
if (((IncludePathEntry) oldEntry).createdReference)
{
int index = referencedNames.indexOf(projectName);
if (index >= 0)
{
changedReferences = true;
referencedNames.remove(index);
referenced.remove(index);
}
}
}
}
}
for (IIncludePathEntry newEntry : newEntries)
{
if (newEntry.getEntryKind() == IIncludePathEntry.IPE_PROJECT)
{
String projectName = newEntry.getPath().lastSegment();
if (!containsProject(oldEntries, projectName))
{
if (!referencedNames.contains(projectName))
{
changedReferences = true;
((IncludePathEntry) newEntry).createdReference = true;
referenced.add(ResourcesPlugin.getWorkspace().getRoot().getProject(projectName));
referencedNames.add(projectName);
}
}
}
}
if (changedReferences)
{
IProject[] referenceProjects = (IProject[]) referenced.toArray(new IProject[referenced.size()]);
projectDescription.setReferencedProjects(referenceProjects);
WorkspaceJob job = new WorkspaceJob(CoreMessages.getString("IncludePathEntry_2")) //$NON-NLS-1$
{
public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException
{
project.setDescription(projectDescription, monitor);
return Status.OK_STATUS;
}
};
job.setRule(project.getParent());
job.schedule();
}
}
catch (CoreException e)
{
PHPEplPlugin.logError(e);
}
}
private static boolean containsProject(IIncludePathEntry[] entries, String projectName)
{
for (IIncludePathEntry entry : entries)
{
if (entry.getEntryKind() == IIncludePathEntry.IPE_PROJECT)
{
if (entry.getPath().lastSegment().equals(projectName))
{
return true;
}
}
}
return false;
}
/**
* Returns the entry kind of a <code>PackageFragmentRoot</code> from its <code>String</code> form.
*/
static int entryKindFromString(String kindStr)
{
if (kindStr.equalsIgnoreCase("prj")) //$NON-NLS-1$
{
return IIncludePathEntry.IPE_PROJECT;
}
if (kindStr.equalsIgnoreCase("var")) //$NON-NLS-1$
{
return IIncludePathEntry.IPE_VARIABLE;
}
if (kindStr.equalsIgnoreCase("con")) //$NON-NLS-1$
{
return IIncludePathEntry.IPE_CONTAINER;
}
if (kindStr.equalsIgnoreCase("src")) //$NON-NLS-1$
{
return IIncludePathEntry.IPE_SOURCE;
}
if (kindStr.equalsIgnoreCase("lib")) //$NON-NLS-1$
{
return IIncludePathEntry.IPE_LIBRARY;
}
if (kindStr.equalsIgnoreCase("jre")) //$NON-NLS-1$
{
return IIncludePathEntry.IPE_JRE;
}
return -1;
}
/**
* Returns a <code>String</code> for the entry kind of a class path entry.
*/
static String entryKindToString(int kind)
{
switch (kind)
{
case IIncludePathEntry.IPE_PROJECT:
return "prj"; //$NON-NLS-1$
case IIncludePathEntry.IPE_SOURCE:
return "src"; //$NON-NLS-1$
case IIncludePathEntry.IPE_LIBRARY:
return "lib"; //$NON-NLS-1$
case IIncludePathEntry.IPE_JRE:
return "jre"; //$NON-NLS-1$
case IIncludePathEntry.IPE_VARIABLE:
return "var"; //$NON-NLS-1$
case IIncludePathEntry.IPE_CONTAINER:
return "con"; //$NON-NLS-1$
default:
return "unknown"; //$NON-NLS-1$
}
}
/**
* Returns the content kind of a <code>PackageFragmentRoot</code> from its <code>String</code> form.
*/
static int contentKindFromString(String kindStr)
{
if (kindStr.equalsIgnoreCase("binary")) //$NON-NLS-1$
{
return IIncludePathEntry.K_BINARY;
}
if (kindStr.equalsIgnoreCase("source")) //$NON-NLS-1$
{
return IIncludePathEntry.K_SOURCE;
}
return -1;
}
/**
* Returns a <code>String</code> for the content kind of a class path entry.
*/
static String contentKindToString(int kind)
{
switch (kind)
{
case IIncludePathEntry.K_BINARY:
return "binary"; //$NON-NLS-1$
case IIncludePathEntry.K_SOURCE:
return "source"; //$NON-NLS-1$
default:
return "unknown"; //$NON-NLS-1$
}
}
public String validate()
{
String message = null;
switch (entryKind)
{
case IIncludePathEntry.IPE_PROJECT:
if (resource == null || !resource.exists())
{
message = CoreMessages.getString("IncludePathEntry_4") + path.toOSString(); //$NON-NLS-1$
}
break;
case IIncludePathEntry.IPE_LIBRARY:
case IIncludePathEntry.IPE_JRE:
if (resource == null || !resource.exists())
{
File file = new File(path.toOSString());
if (!file.exists())
{
message = CoreMessages.getString("IncludePathEntry_5") + path.toOSString(); //$NON-NLS-1$
}
}
break;
case IIncludePathEntry.IPE_SOURCE:
if (resource == null || !resource.exists())
{
message = CoreMessages.getString("IncludePathEntry_6") + path.toOSString(); //$NON-NLS-1$
}
break;
case IIncludePathEntry.IPE_VARIABLE:
// if (resource == null || !resource.exists())
// message = "included variable not found: " + path.toOSString();
break;
case IIncludePathEntry.IPE_CONTAINER:
break;
default:
throw new AssertionError(NLS.bind(CoreMessages.getString("includePath_unknownKind"), StringUtil.EMPTY)); //$NON-NLS-1$
}
return message;
}
/*
* (non-Javadoc)
* @see org2.eclipse.php.internal.core.project.IIncludePathEntry#setResource(org.eclipse.core.resources.IResource)
*/
public void setResource(IResource resource)
{
this.resource = resource;
}
public int hashCode()
{
final int PRIME = 31;
int result = 1;
result = PRIME * result + contentKind;
result = PRIME * result + entryKind;
result = PRIME * result + ((path == null) ? 0 : path.hashCode());
return result;
}
public boolean equals(Object obj)
{
if (this == obj)
{
return true;
}
if (obj == null)
{
return false;
}
if (getClass() != obj.getClass())
{
return false;
}
IncludePathEntry other = (IncludePathEntry) obj;
if (contentKind != other.contentKind)
{
return false;
}
if (entryKind != other.entryKind)
{
return false;
}
if (path == null)
{
if (other.path != null)
{
return false;
}
}
else if (!path.equals(other.path))
{
return false;
}
return true;
}
}