blob: fbd7fad2d377cb8cad8c75976e77267cc4e38659 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2001, 2006 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.jem.internal.beaninfo.core;
/*
*/
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
import org.eclipse.jdt.core.*;
import org.w3c.dom.*;
import org.eclipse.jem.internal.beaninfo.adapters.*;
/**
* Beaninfo entry. Location of the beaninfos. Much like a standard classpath entry.
* The BeanInfos are either in a jar or another project. They can be supplied as
* a local file in the project, or as an external jar, or as external jar through a
* variable, or an external jar through a plugin.
* <p>
* An external jar through containers is not valid because container are attached to
* projects. they aren't standalone.
*
* @version 1.0
* @author
*/
public class BeaninfoEntry implements IBeaninfosDocEntry {
final static String sBeaninfo = "beaninfo"; // Beaninfo entry, shared with BeaninfosDoc. //$NON-NLS-1$
public static final int BIE_PLUGIN = 100; // Beaninfo jar can be found in a plugin.
static int kindFromString(String kindStr) {
if (kindStr == null || kindStr.length() == 0)
return BIE_PLUGIN; // Default to plugin. If coming from beaninfoconfig, there should always be kind. But if coming from plugin.xml there shouldn't be one.
if (kindStr.equalsIgnoreCase("con")) //$NON-NLS-1$
return IClasspathEntry.CPE_CONTAINER;
if (kindStr.equalsIgnoreCase("var")) //$NON-NLS-1$
return IClasspathEntry.CPE_VARIABLE;
if (kindStr.equalsIgnoreCase("src")) //$NON-NLS-1$
return IClasspathEntry.CPE_SOURCE;
if (kindStr.equalsIgnoreCase("lib")) //$NON-NLS-1$
return IClasspathEntry.CPE_LIBRARY;
if (kindStr.equalsIgnoreCase("plugin")) //$NON-NLS-1$
return BIE_PLUGIN;
return -1;
}
static String kindToString(int kind) {
switch (kind) {
case IClasspathEntry.CPE_PROJECT :
return "src"; // backward compatibility //$NON-NLS-1$
case IClasspathEntry.CPE_SOURCE :
return "src"; //$NON-NLS-1$
case IClasspathEntry.CPE_LIBRARY :
return "lib"; //$NON-NLS-1$
case IClasspathEntry.CPE_VARIABLE :
return "var"; //$NON-NLS-1$
case IClasspathEntry.CPE_CONTAINER:
return "con"; //$NON-NLS-1$
case BIE_PLUGIN:
return "plugin"; //$NON-NLS-1$
default :
return "unknown"; //$NON-NLS-1$
}
}
/**
* Return the appropriate kind of entry when we know it is a classpath entry.
*/
public static IClasspathEntry createEntry(int kind, IPath path, IProject project, boolean isExported) {
switch (kind) {
case IClasspathEntry.CPE_LIBRARY :
if (path.isAbsolute())
return JavaCore.newLibraryEntry(path, null, null, isExported);
break;
case IClasspathEntry.CPE_SOURCE :
if (path.isAbsolute()) {
// must be an entry in this project or specify another project
String projSegment = path.segment(0);
if (project != null && projSegment != null && projSegment.equals(project.getName())) {
// this project
return JavaCore.newSourceEntry(path);
} else {
// another project
return JavaCore.newProjectEntry(path, isExported);
}
}
break;
case IClasspathEntry.CPE_VARIABLE :
return JavaCore.newVariableEntry(path, null, null, isExported);
case IClasspathEntry.CPE_CONTAINER:
return JavaCore.newContainerEntry(path, isExported);
}
return null;
}
/**
* Read the entry in from the element.
*/
public static BeaninfoEntry readEntry(IReader reader, Object element, IProject project) {
String elementKind = reader.getAttribute(element, BeaninfosDoc.sKind);
String pathStr = reader.getAttribute(element, BeaninfosDoc.sPath);
// ensure path is absolute
IPath path = new Path(pathStr);
int kind = kindFromString(elementKind);
if (kind != IClasspathEntry.CPE_VARIABLE && kind != IClasspathEntry.CPE_CONTAINER && kind != BIE_PLUGIN && !path.isAbsolute()) {
path = project != null ? project.getFullPath().append(path) : path.makeAbsolute(); // Some folder/jar within this project
}
// exported flag
String exportedString = reader.getAttribute(element, BeaninfosDoc.sExported);
boolean isExported = "true".equalsIgnoreCase(exportedString); //$NON-NLS-1$
//$NON-NLS-1$
// recreate the entry
IClasspathEntry cpEntry = null;
IPath pluginPath = null;
if (kind != BIE_PLUGIN) {
cpEntry = createEntry(kind, path, project, isExported);
} else {
if (path.isAbsolute())
pluginPath = path;
else {
// Kludge This should only be a plugin type if from configuration element. So we will cast to that
// and get the plugin id to create an absolute plugin path.
if (element instanceof IConfigurationElement) {
pluginPath = new Path('/'+((IConfigurationElement) element).getDeclaringExtension().getContributor().getName()).append(path);
} else
return null; // Not valid because can't have plugin from .beaninfoconfig file.
}
}
ArrayList searchpaths = new ArrayList();
Object children = reader.getChildren(element);
int childrenLength = reader.getLength(children);
for (int i = 0; i < childrenLength; i++) {
Object child = reader.getItem(children, i);
if (reader.isNodeTypeElement(child)) {
Object entry = null;
if (reader.getNodeName(child).equalsIgnoreCase(SearchpathEntry.sSearchpath)) {
entry = SearchpathEntry.readEntry(reader, child, project, true);
}
if (entry != null)
searchpaths.add(entry);
}
}
if (cpEntry != null)
return new BeaninfoEntry(
cpEntry,
(SearchpathEntry[]) searchpaths.toArray(new SearchpathEntry[searchpaths.size()]),
isExported);
else return new BeaninfoEntry(
pluginPath,
(SearchpathEntry[]) searchpaths.toArray(new SearchpathEntry[searchpaths.size()]),
isExported);
}
protected IClasspathEntry entry; // Store it as a classpath entry for convienence. It is the RAW classpath entry. This is only used when pointing to something other than a plugin.
protected IPath pluginPath; // When stored in a plugin, this will be set instead.
protected boolean isExported;
protected SearchpathEntry[] searchpaths;
/**
* Used when the beaninfo jar is within a plugin. In that case, the first segment
* of the path is the plugin descriptor, and the rest is the path from the plugin
* directory to the jar.
*/
public BeaninfoEntry(IPath pluginPath, SearchpathEntry[] searchpaths, boolean isExported) {
this(searchpaths, isExported);
this.pluginPath = pluginPath;
}
/**
* Used when the beaninfo jar/folder is either an external jar/folder or is somewhere else
* in the workspace. In that case the entry is the RAW classpath entry to that code.
*/
public BeaninfoEntry(IClasspathEntry entry, SearchpathEntry[] searchpaths, boolean isExported) {
this(searchpaths, isExported);
this.entry = entry;
}
protected BeaninfoEntry(SearchpathEntry[] searchpaths, boolean isExported) {
this.isExported = isExported;
this.searchpaths = searchpaths != null ? searchpaths : new SearchpathEntry[0];
}
public SearchpathEntry[] getSearchPaths() {
return searchpaths;
}
public void setSearchPaths(SearchpathEntry[] searchpaths) {
this.searchpaths = searchpaths;
}
public boolean isExported() {
return isExported;
}
public void setIsExported(boolean isExported) {
this.isExported = isExported;
}
public Node writeEntry(Document doc, IProject project) {
Element element = doc.createElement(sBeaninfo);
IPath path = null;
if (entry != null) {
element.setAttribute(BeaninfosDoc.sKind, kindToString(entry.getEntryKind()));
path = entry.getPath();
if (entry.getEntryKind() != IClasspathEntry.CPE_VARIABLE && entry.getEntryKind() != IClasspathEntry.CPE_CONTAINER) {
// translate to project relative from absolute (unless a device path)
if (path.isAbsolute()) {
if (path.segment(0).equals(project.getFullPath().segment(0))) {
path = path.removeFirstSegments(1);
path = path.makeRelative();
} else {
path = path.makeAbsolute();
}
}
}
} else {
element.setAttribute(BeaninfosDoc.sKind, kindToString(BIE_PLUGIN));
path = pluginPath;
}
element.setAttribute(BeaninfosDoc.sPath, path.toString()); //$NON-NLS-1$
if (isExported()) {
element.setAttribute(BeaninfosDoc.sExported, "true"); //$NON-NLS-1$
}
for (int i = 0; i < searchpaths.length; i++) {
SearchpathEntry spe = searchpaths[i];
element.appendChild(spe.writeEntry(doc, project));
}
return element;
}
/**
* If this is not a plugin info, then return the classpath entry.
*/
public IClasspathEntry getClasspathEntry() {
return entry;
}
/**
* Return the resolved classpaths. Each entry in the array will be either:
* 1) IProject - If it is a project type entry. Want the whole project
* 2) String - an absolute external path to a jar
* 3) IPath - a path to a plugin jar. The first segment is the plugin id, the rest is the path relative to that plugin.
*
*
* @param javaProject
* @return The array of paths, or <code>null</code> if no paths.
*
* @since 1.0.0
*/
public Object[] getClasspath(IJavaProject javaProject) {
if (entry != null) {
// It is a standard CPE Entry.
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
List paths = new ArrayList(1);
IClasspathEntry resolvedEntry = JavaCore.getResolvedClasspathEntry(entry);
resolveEntry(root, paths, resolvedEntry, javaProject);
return paths.toArray();
} else if (pluginPath != null)
return new Object[] {pluginPath};
return null;
}
private void resolveEntry(IWorkspaceRoot root, List paths, IClasspathEntry entry, IJavaProject javaProject) {
switch (entry.getEntryKind()) {
case IClasspathEntry.CPE_PROJECT :
IProject reqProject = (IProject) root.findMember(entry.getPath().lastSegment());
// Project entries only have one segment.
if (reqProject != null && reqProject.isOpen())
paths.add(reqProject);
break;
case IClasspathEntry.CPE_SOURCE :
reqProject = (IProject) root.findMember(entry.getPath().segment(0));
// Find project from the first segment.
IJavaProject jProject = JavaCore.create(reqProject);
if (jProject != null) {
try {
IPath outputLocation = jProject.getOutputLocation();
IResource resource = root.findMember(outputLocation);
if (resource != null) {
paths.add(resource.getLocation().toString());
}
} catch(JavaModelException e) {
}
}
break;
case IClasspathEntry.CPE_LIBRARY :
IResource library = root.findMember(entry.getPath());
// can be external or in workspace
paths.add((library != null) ? library.getLocation().toString() : entry.getPath().toString());
break;
case IClasspathEntry.CPE_CONTAINER:
try {
IClasspathContainer container = JavaCore.getClasspathContainer(entry.getPath(), javaProject);
if (container != null) {
IClasspathEntry[] entries = container.getClasspathEntries();
for (int i = 0; i < entries.length; i++) {
resolveEntry(root, paths, entries[i], javaProject);
}
}
} catch (JavaModelException e) {
BeaninfoPlugin.getPlugin().getLogger().log(e, Level.WARNING);
}
}
}
public int getKind() {
return entry != null ? entry.getEntryKind() : BIE_PLUGIN;
}
public IPath getPath() {
return entry != null ? entry.getPath() : pluginPath;
}
public boolean equals(Object other) {
if (this == other)
return true;
if (!(other instanceof BeaninfoEntry))
return false;
// Return equal if the classpath entry is the same classpath entry or plugin path entry.
// The search path doesn't have any affect on the semantic equality.
BeaninfoEntry otherEntry = (BeaninfoEntry) other;
if (isExported != otherEntry.isExported)
return false;
if (entry != null)
return entry.equals(otherEntry.entry);
return pluginPath.equals(otherEntry.pluginPath);
}
public int hashCode() {
if (entry != null)
return entry.hashCode() ^ (isExported ? Boolean.TRUE : Boolean.FALSE).hashCode();
else
return pluginPath.hashCode() ^ (isExported ? Boolean.TRUE : Boolean.FALSE).hashCode();
}
}