diff --git a/platform/platform-api/src/com/intellij/ide/plugins/IdeaPluginDescriptorImpl.java b/platform/platform-api/src/com/intellij/ide/plugins/IdeaPluginDescriptorImpl.java index 9dd680be9ab5..7c6b8656b2d8 100644 --- a/platform/platform-api/src/com/intellij/ide/plugins/IdeaPluginDescriptorImpl.java +++ b/platform/platform-api/src/com/intellij/ide/plugins/IdeaPluginDescriptorImpl.java @@ -102,12 +102,16 @@ public class IdeaPluginDescriptorImpl implements IdeaPluginDescriptor { protected static StringInterner ourInterner = new StringInterner(); + public void readExternal(Document document, final URL url) throws InvalidDataException, FileNotFoundException { + document = JDOMXIncluder.resolve(document, url.toExternalForm()); + JDOMUtil.internElement(document.getRootElement(), ourInterner); + readExternal(document.getRootElement()); + } + public void readExternal(final URL url) throws InvalidDataException, FileNotFoundException { try { Document document = JDOMUtil.loadDocument(url); - document = JDOMXIncluder.resolve(document, url.toExternalForm()); - JDOMUtil.internElement(document.getRootElement(), ourInterner); - readExternal(document.getRootElement()); + readExternal(document, url); } catch (FileNotFoundException e) { throw e; diff --git a/platform/platform-api/src/com/intellij/ide/plugins/PluginManager.java b/platform/platform-api/src/com/intellij/ide/plugins/PluginManager.java index a1bd41e362c7..25cc13e1d9d8 100644 --- a/platform/platform-api/src/com/intellij/ide/plugins/PluginManager.java +++ b/platform/platform-api/src/com/intellij/ide/plugins/PluginManager.java @@ -36,6 +36,7 @@ import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.util.BuildNumber; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.JDOMUtil; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.ArrayUtil; @@ -44,8 +45,10 @@ import com.intellij.util.graph.CachingSemiGraph; import com.intellij.util.graph.DFSTBuilder; import com.intellij.util.graph.Graph; import com.intellij.util.graph.GraphGenerator; +import com.intellij.util.lang.JarMemoryLoader; import com.intellij.util.xmlb.XmlSerializationException; import gnu.trove.THashMap; +import org.jdom.Document; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -58,6 +61,8 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.*; import java.util.*; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; /** * @author mike @@ -85,6 +90,8 @@ public class PluginManager { private static final Map ourId2Index = new THashMap(); @NonNls private static final String MODULE_DEPENDENCY_PREFIX = "com.intellij.module"; private static final List ourAvailableModules = new ArrayList(); + private static final boolean ourOptimize = "true".equals(System.getProperty("idea.optimize")); + public static long startupStart; @@ -107,7 +114,13 @@ public class PluginManager { public static synchronized IdeaPluginDescriptor[] getPlugins() { if (ourPlugins == null) { long start = System.currentTimeMillis(); - initializePlugins(); + try { + initializePlugins(); + } + catch (RuntimeException e) { + getLogger().error(e); + throw e; + } getLogger().info(ourPlugins.length + " plugins initialized in " + (System.currentTimeMillis() - start) + " ms"); logPlugins(); ClassloaderUtil.clearJarURLCache(); @@ -814,17 +827,24 @@ public class PluginManager { if (files == null || files.length == 0) { return null; } + Arrays.sort(files, new Comparator() { + @Override + public int compare(File o1, File o2) { + if (o2.getName().startsWith((file.getName()))) return Integer.MAX_VALUE; + if (o1.getName().startsWith((file.getName()))) return -Integer.MAX_VALUE; + if (o2.getName().startsWith("resources")) return -Integer.MAX_VALUE; + if (o1.getName().startsWith("resources")) return Integer.MAX_VALUE; + return 0; + } + }); for (final File f : files) { if (ClassloaderUtil.isJarOrZip(f)) { - IdeaPluginDescriptorImpl descriptor1 = loadDescriptorFromJar(f, fileName); - if (descriptor1 != null) { - if (descriptor != null) { - getLogger().info("Cannot load " + file + " because two or more plugin.xml's detected"); - return null; - } - descriptor = descriptor1; + descriptor = loadDescriptorFromJar(f, fileName); + if (descriptor != null) { descriptor.setPath(file); + return descriptor; } + getLogger().warn("Cannot load descriptor from " + f.getName() + ""); } else if (f.isDirectory()) { IdeaPluginDescriptorImpl descriptor1 = loadDescriptorFromDir(f, fileName); @@ -883,14 +903,31 @@ public class PluginManager { @Nullable private static IdeaPluginDescriptorImpl loadDescriptorFromJar(File file, @NonNls String fileName) { try { - - IdeaPluginDescriptorImpl descriptor = new IdeaPluginDescriptorImpl(file); - URI fileURL = file.toURI(); URL jarURL = new URL( "jar:" + StringUtil.replace(fileURL.toASCIIString(), "!", "%21") + "!/META-INF/" + fileName ); + IdeaPluginDescriptorImpl descriptor = new IdeaPluginDescriptorImpl(file); + FileInputStream in = new FileInputStream(file); + ZipInputStream zipStream = new ZipInputStream(in); + try { + ZipEntry entry = zipStream.getNextEntry(); + if (entry.getName().equals(JarMemoryLoader.SIZE_ENTRY)) { + entry = zipStream.getNextEntry(); + if (entry.getName().equals("META-INF/" + fileName)) { + byte[] content = FileUtil.loadBytes(zipStream, (int)entry.getSize()); + Document document = JDOMUtil.loadDocument(new ByteArrayInputStream(content)); + descriptor.readExternal(document, jarURL); + return descriptor; + } + } + } + finally { + zipStream.close(); + in.close(); + } + descriptor.readExternal(jarURL); return descriptor; } @@ -904,6 +941,9 @@ public class PluginManager { catch (Exception e) { getLogger().info("Cannot load " + file, e); } + catch (Throwable e) { + getLogger().info("Cannot load " + file, e); + } return null; } diff --git a/platform/platform-impl/testData/pluginDescriptor/asp.jar b/platform/platform-impl/testData/pluginDescriptor/asp.jar new file mode 100644 index 000000000000..69a1c6d27c7d Binary files /dev/null and b/platform/platform-impl/testData/pluginDescriptor/asp.jar differ diff --git a/platform/platform-impl/testData/pluginDescriptor/resources_en.jar b/platform/platform-impl/testData/pluginDescriptor/resources_en.jar new file mode 100644 index 000000000000..f14264f84290 Binary files /dev/null and b/platform/platform-impl/testData/pluginDescriptor/resources_en.jar differ diff --git a/platform/platform-impl/testSrc/com/intellij/ide/plugins/PluginDescriptorTest.java b/platform/platform-impl/testSrc/com/intellij/ide/plugins/PluginDescriptorTest.java new file mode 100644 index 000000000000..660eceb3f605 --- /dev/null +++ b/platform/platform-impl/testSrc/com/intellij/ide/plugins/PluginDescriptorTest.java @@ -0,0 +1,19 @@ +package com.intellij.ide.plugins; + +import com.intellij.openapi.application.PathManager; +import junit.framework.TestCase; + +import java.io.File; + +/** + * @author Dmitry Avdeev + * Date: 7/14/11 + */ +public class PluginDescriptorTest extends TestCase { + + public void testDescriptorLoading() throws Exception { + String path = PathManager.getHomePath().replace(File.separatorChar, '/') + "/community/platform/platform-impl/testData/pluginDescriptor"; + IdeaPluginDescriptorImpl descriptor = PluginManager.loadDescriptorFromJar(new File(path + "/asp.jar")); + assertNotNull(descriptor); + } +} diff --git a/platform/util/src/com/intellij/util/io/zip/ReorderJarsMain.java b/platform/util/src/com/intellij/util/io/zip/ReorderJarsMain.java index 27331db2418a..7b5782d86268 100644 --- a/platform/util/src/com/intellij/util/io/zip/ReorderJarsMain.java +++ b/platform/util/src/com/intellij/util/io/zip/ReorderJarsMain.java @@ -59,6 +59,8 @@ public class ReorderJarsMain { final List orderedEntries = toReorder.get(jarUrl); Collections.sort(entries, new Comparator() { public int compare(JBZipEntry o1, JBZipEntry o2) { + if ("META-INF/plugin.xml".equals(o2.getName())) return Integer.MAX_VALUE; + if ("META-INF/plugin.xml".equals(o1.getName())) return -Integer.MAX_VALUE; if (orderedEntries.contains(o1.getName())) { return orderedEntries.contains(o2.getName()) ? orderedEntries.indexOf(o1.getName()) - orderedEntries.indexOf(o2.getName()) : -1; } diff --git a/platform/util/testData/reorderJars/zkm.jar b/platform/util/testData/reorderJars/zkm.jar new file mode 100644 index 000000000000..c1d6620b4872 Binary files /dev/null and b/platform/util/testData/reorderJars/zkm.jar differ diff --git a/platform/util/testData/reorderJars/zkmOrder.txt b/platform/util/testData/reorderJars/zkmOrder.txt new file mode 100644 index 000000000000..87e1541df888 --- /dev/null +++ b/platform/util/testData/reorderJars/zkmOrder.txt @@ -0,0 +1 @@ +com/intellij/zkm/ZKMBundle.class:/zkm.jar diff --git a/platform/util/testSrc/com/intellij/util/io/zip/ReorderJarsTest.java b/platform/util/testSrc/com/intellij/util/io/zip/ReorderJarsTest.java index 548ca134691c..8f74ac52c9db 100644 --- a/platform/util/testSrc/com/intellij/util/io/zip/ReorderJarsTest.java +++ b/platform/util/testSrc/com/intellij/util/io/zip/ReorderJarsTest.java @@ -65,6 +65,31 @@ public class ReorderJarsTest extends TestCase { assertTrue(Arrays.equals(data, bytes)); } + public void testName() throws Exception { + + } + + public void testPluginXml() throws Exception { + String path = PathManager.getHomePath().replace(File.separatorChar, '/') + "/community/platform/util/testData/reorderJars"; + + ReorderJarsMain.main(new String[] { path + "/zkmOrder.txt", path, myTempDirectory.getPath() } ); + File[] files = myTempDirectory.listFiles(); + File file = files[0]; + assertEquals("zkm.jar", file.getName()); + + JBZipFile zipFile = new JBZipFile(file); + try { + List entries = zipFile.getEntries(); + System.out.println(entries); + assertEquals(JarMemoryLoader.SIZE_ENTRY, entries.get(0).getName()); + assertEquals("META-INF/plugin.xml", entries.get(1).getName()); + } + finally { + zipFile.close(); + } + + } + @Override protected void setUp() throws Exception { super.setUp();