/******************************************************************************* * 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(); } }