[r302] Bug 82891 - Source lookup based upon the classpath info stored in manifest file in a JAR
diff --git a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/StandardSourcePathProvider.java b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/StandardSourcePathProvider.java
index 4ea31e9..65243a5 100644
--- a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/StandardSourcePathProvider.java
+++ b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/StandardSourcePathProvider.java
@@ -11,10 +11,16 @@
 package org.eclipse.jdt.launching;
 
 
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.jar.Attributes;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
 
 import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
 import org.eclipse.debug.core.ILaunchConfiguration;
 import org.eclipse.jdt.internal.launching.DefaultProjectClasspathEntry;
 import org.eclipse.jdt.internal.launching.VariableClasspathEntry;
@@ -67,10 +73,13 @@
 					} else if (typeId.equals(VariableClasspathEntry.TYPE_ID)) {
 						// add the archive itself - we currently do not allow a source attachment
 						res = JavaRuntime.resolveRuntimeClasspathEntry(entry, configuration);
-					}
+					} else {
+                        res = JavaRuntime.resolveRuntimeClasspathEntry(entry, configuration);
+                    }
 					if (res != null) {
 						for (int j = 0; j < res.length; j++) {
 							all.add(res[j]);
+                            addManifestReferences(res[j], all);
 						}
 					}
 					break;
@@ -78,6 +87,7 @@
 					IRuntimeClasspathEntry[] resolved =JavaRuntime.resolveRuntimeClasspathEntry(entries[i], configuration);
 					for (int j = 0; j < resolved.length; j++) {
 						all.add(resolved[j]);
+                        addManifestReferences(resolved[j], all);
 					}
 					break;
 			}
@@ -85,4 +95,51 @@
 		return (IRuntimeClasspathEntry[])all.toArray(new IRuntimeClasspathEntry[all.size()]);
 	}
 
+    /**
+     * If the given entry is an archive, adds any archives referenced by the associated manifest.
+     * 
+     * @param entry runtime classpath entry
+     * @param all list to add references to
+     */
+    protected void addManifestReferences(IRuntimeClasspathEntry entry, List all) {
+        if (entry.getType() == IRuntimeClasspathEntry.ARCHIVE) {
+            String location = entry.getLocation();
+            if (location != null) {
+                JarFile jar = null;
+                try {
+                    jar = new JarFile(location);
+                    Manifest manifest = jar.getManifest();
+                    if (manifest != null) {
+                        Attributes mainAttributes = manifest.getMainAttributes();
+                        if (mainAttributes != null) {
+                            String value = mainAttributes.getValue(Attributes.Name.CLASS_PATH);
+                            if (value != null) {
+                                String[] entries = value.split("\\s+"); //$NON-NLS-1$
+                                IPath base = new Path(location);
+                                base = base.removeLastSegments(1);
+                                for (int i = 0; i < entries.length; i++) {
+                                    IPath path = base.append(entries[i]);
+                                    if (path.toFile().exists()) {
+                                        IRuntimeClasspathEntry ref = JavaRuntime.newArchiveRuntimeClasspathEntry(path);
+                                        if (!all.contains(ref)) {
+                                            all.add(ref);
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                } catch (IOException e) {
+                } finally {
+                    if (jar != null) {
+                        try {
+                            jar.close();
+                        } catch (IOException e) {
+                        }
+                    }
+                }
+            }
+        }
+    }
+
 }