001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.launching;
011:
012: import java.io.IOException;
013: import java.util.ArrayList;
014: import java.util.Collection;
015: import java.util.HashSet;
016: import java.util.List;
017: import java.util.jar.Attributes;
018: import java.util.jar.JarFile;
019: import java.util.jar.Manifest;
020:
021: import org.eclipse.core.runtime.CoreException;
022: import org.eclipse.core.runtime.IPath;
023: import org.eclipse.core.runtime.Path;
024: import org.eclipse.debug.core.ILaunchConfiguration;
025: import org.eclipse.jdt.internal.launching.DefaultProjectClasspathEntry;
026: import org.eclipse.jdt.internal.launching.VariableClasspathEntry;
027:
028: /**
029: * Default implementation of source lookup path computation and resolution.
030: * <p>
031: * This class may be subclassed.
032: * </p>
033: * @since 2.0
034: */
035: public class StandardSourcePathProvider extends
036: StandardClasspathProvider {
037:
038: /* (non-Javadoc)
039: * @see org.eclipse.jdt.launching.IRuntimeClasspathProvider#computeUnresolvedClasspath(org.eclipse.debug.core.ILaunchConfiguration)
040: */
041: public IRuntimeClasspathEntry[] computeUnresolvedClasspath(
042: ILaunchConfiguration configuration) throws CoreException {
043: boolean useDefault = configuration
044: .getAttribute(
045: IJavaLaunchConfigurationConstants.ATTR_DEFAULT_SOURCE_PATH,
046: true);
047: IRuntimeClasspathEntry[] entries = null;
048: if (useDefault) {
049: // the default source lookup path is the same as the classpath
050: entries = super .computeUnresolvedClasspath(configuration);
051: } else {
052: // recover persisted source path
053: entries = recoverRuntimePath(configuration,
054: IJavaLaunchConfigurationConstants.ATTR_SOURCE_PATH);
055: }
056: return entries;
057:
058: }
059:
060: /* (non-Javadoc)
061: * @see org.eclipse.jdt.launching.IRuntimeClasspathProvider#resolveClasspath(org.eclipse.jdt.launching.IRuntimeClasspathEntry[], org.eclipse.debug.core.ILaunchConfiguration)
062: */
063: public IRuntimeClasspathEntry[] resolveClasspath(
064: IRuntimeClasspathEntry[] entries,
065: ILaunchConfiguration configuration) throws CoreException {
066: List all = new UniqueList(entries.length);
067: for (int i = 0; i < entries.length; i++) {
068: switch (entries[i].getType()) {
069: case IRuntimeClasspathEntry.PROJECT:
070: // a project resolves to itself for source lookup (rather than the class file output locations)
071: all.add(entries[i]);
072: break;
073: case IRuntimeClasspathEntry.OTHER:
074: IRuntimeClasspathEntry2 entry = (IRuntimeClasspathEntry2) entries[i];
075: String typeId = entry.getTypeId();
076: IRuntimeClasspathEntry[] res = null;
077: if (typeId.equals(DefaultProjectClasspathEntry.TYPE_ID)) {
078: // add the resolved children of the project
079: IRuntimeClasspathEntry[] children = entry
080: .getRuntimeClasspathEntries(configuration);
081: res = JavaRuntime.resolveSourceLookupPath(children,
082: configuration);
083: } else if (typeId
084: .equals(VariableClasspathEntry.TYPE_ID)) {
085: // add the archive itself - we currently do not allow a source attachment
086: res = JavaRuntime.resolveRuntimeClasspathEntry(
087: entry, configuration);
088: } else {
089: res = JavaRuntime.resolveRuntimeClasspathEntry(
090: entry, configuration);
091: }
092: if (res != null) {
093: for (int j = 0; j < res.length; j++) {
094: all.add(res[j]);
095: addManifestReferences(res[j], all);
096: }
097: }
098: break;
099: default:
100: IRuntimeClasspathEntry[] resolved = JavaRuntime
101: .resolveRuntimeClasspathEntry(entries[i],
102: configuration);
103: for (int j = 0; j < resolved.length; j++) {
104: all.add(resolved[j]);
105: addManifestReferences(resolved[j], all);
106: }
107: break;
108: }
109: }
110: return (IRuntimeClasspathEntry[]) all
111: .toArray(new IRuntimeClasspathEntry[all.size()]);
112: }
113:
114: /**
115: * If the given entry is an archive, adds any archives referenced by the associated manifest.
116: *
117: * @param entry runtime classpath entry
118: * @param all list to add references to
119: */
120: protected void addManifestReferences(IRuntimeClasspathEntry entry,
121: List all) {
122: if (entry.getType() == IRuntimeClasspathEntry.ARCHIVE) {
123: String location = entry.getLocation();
124: if (location != null) {
125: JarFile jar = null;
126: try {
127: jar = new JarFile(location, false);
128: Manifest manifest = jar.getManifest();
129: if (manifest != null) {
130: Attributes mainAttributes = manifest
131: .getMainAttributes();
132: if (mainAttributes != null) {
133: String value = mainAttributes
134: .getValue(Attributes.Name.CLASS_PATH);
135: if (value != null) {
136: String[] entries = value.split("\\s+"); //$NON-NLS-1$
137: IPath base = new Path(location);
138: base = base.removeLastSegments(1);
139: for (int i = 0; i < entries.length; i++) {
140: IPath path = base
141: .append(entries[i]);
142: if (path.toFile().exists()) {
143: IRuntimeClasspathEntry ref = JavaRuntime
144: .newArchiveRuntimeClasspathEntry(path);
145: if (!all.contains(ref)) {
146: all.add(ref);
147: }
148: }
149: }
150: }
151: }
152: }
153: } catch (IOException e) {
154: } finally {
155: if (jar != null) {
156: try {
157: jar.close();
158: } catch (IOException e) {
159: }
160: }
161: }
162: }
163: }
164: }
165:
166: /*
167: * An ArrayList that acts like a set -i.e. does not allow duplicate items.
168: * hack for bug 112774
169: */
170: class UniqueList extends ArrayList {
171: private static final long serialVersionUID = -7402160651027036270L;
172: HashSet set;
173:
174: public UniqueList(int length) {
175: super (length);
176: set = new HashSet(length);
177: }
178:
179: public void add(int index, Object element) {
180: if (set.add(element))
181: super .add(index, element);
182: }
183:
184: public boolean add(Object o) {
185: if (set.add(o))
186: return super .add(o);
187: return false;
188: }
189:
190: public boolean addAll(Collection c) {
191: if (set.addAll(c))
192: return super .addAll(c);
193: return false;
194: }
195:
196: public boolean addAll(int index, Collection c) {
197: if (set.addAll(c))
198: return super .addAll(index, c);
199: return false;
200: }
201:
202: public void clear() {
203: set.clear();
204: super .clear();
205: }
206:
207: public boolean contains(Object elem) {
208: return set.contains(elem);
209: }
210:
211: public void ensureCapacity(int minCapacity) {
212: super .ensureCapacity(minCapacity);
213: }
214:
215: public Object remove(int index) {
216: Object object = super .remove(index);
217: set.remove(object);
218: return object;
219: }
220:
221: protected void removeRange(int fromIndex, int toIndex) {
222: for (int index = fromIndex; index <= toIndex; index++)
223: remove(index);
224: }
225:
226: public Object set(int index, Object element) {
227: set.remove(element);
228: if (set.add(element))
229: return super .set(index, element);
230: return null; //should not happen.
231: }
232: }
233:
234: }
|