--- a/core.startup/nbproject/project.xml Tue Jan 19 14:36:18 2010 +0100 +++ a/core.startup/nbproject/project.xml Tue Jan 19 20:15:01 2010 +0100 @@ -60,7 +60,7 @@ - 7.25 + 7.34 --- a/core.startup/src/org/netbeans/core/startup/layers/ArchiveURLMapper.java Tue Jan 19 14:36:18 2010 +0100 +++ a/core.startup/src/org/netbeans/core/startup/layers/ArchiveURLMapper.java Tue Jan 19 20:15:01 2010 +0100 @@ -159,13 +159,8 @@ if (reference == null || (jfs = reference.get()) == null) { jfs = findJarFileSystemInRepository(file); if (jfs == null) { - try { - jfs = new JarFileSystem(); - File aRoot = FileUtil.normalizeFile(file); - jfs.setJarFile(aRoot); - } catch (PropertyVetoException pve) { - throw new AssertionError(pve); - } + File aRoot = FileUtil.normalizeFile(file); + jfs = new JarFileSystem(aRoot); } mountRoots.put(file, new JFSReference(jfs)); } --- a/openide.filesystems/apichanges.xml Tue Jan 19 14:36:18 2010 +0100 +++ a/openide.filesystems/apichanges.xml Tue Jan 19 20:15:01 2010 +0100 @@ -46,6 +46,23 @@ Filesystems API + + + Effective constructor for JarFileSystem + + + + + +

+ New constructor for JarFileSystem + that initializes everything without opening the underlaying + JAR file. +

+
+ + +
Support for recursive listeners --- a/openide.filesystems/nbproject/project.properties Tue Jan 19 14:36:18 2010 +0100 +++ a/openide.filesystems/nbproject/project.properties Tue Jan 19 20:15:01 2010 +0100 @@ -44,4 +44,4 @@ javadoc.main.page=org/openide/filesystems/doc-files/api.html javadoc.arch=${basedir}/arch.xml javadoc.apichanges=${basedir}/apichanges.xml -spec.version.base=7.33.0 +spec.version.base=7.34.0 --- a/openide.filesystems/src/org/openide/filesystems/JarFileSystem.java Tue Jan 19 14:36:18 2010 +0100 +++ a/openide.filesystems/src/org/openide/filesystems/JarFileSystem.java Tue Jan 19 20:15:01 2010 +0100 @@ -71,6 +71,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import java.util.zip.ZipException; +import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.openide.util.RequestProcessor; import org.openide.util.Utilities; @@ -88,7 +89,7 @@ static final long serialVersionUID = -98124752801761145L; /** One request proccesor shared for all instances of JarFileSystem*/ - private static RequestProcessor req = new RequestProcessor("JarFs - modification watcher", 1, false, false); // NOI18N + private static final RequestProcessor req = new RequestProcessor("JarFs - modification watcher", 1, false, false); // NOI18N /** Controlls the LocalFileSystem's automatic refresh. * If the refresh time interval is set from the System.property, than this value is used. @@ -171,6 +172,31 @@ setCapability(cap); } + /** Creates new JAR for a given JAR file. This constructor + * behaves basically like: + *
+     * JarFileSystem fs = new JarFileSystem();
+     * fs.setJarFile(jar);
+     * 
+ * but it is more effective in some situations. It does not open and + * read the content of the jar file immediately. Instead + * it waits until somebody asks for resources from inside the JAR. + * + * @param jar location of the JAR file + * @since 7.34 + */ + public JarFileSystem(File jar) throws IOException { + this(); + try { + setJarFile(jar, true, false); + } catch (PropertyVetoException ex) { + // cannot happen, setSystemName can throw the exception only + // if the filesystem is already in Repository, which this one + // is not. + throw (IOException)new IOException().initCause(ex); + } + } + /* Creates Reference. In FileSystem, which subclasses AbstractFileSystem, you can overload method * createReference(FileObject fo) to achieve another type of Reference (weak, strong etc.) * @param fo is FileObject. It`s reference yourequire to get. @@ -233,7 +259,7 @@ * @throws IOException if the file is not valid */ public void setJarFile(final File aRoot) throws IOException, PropertyVetoException { - setJarFile(aRoot, true); + setJarFile(aRoot, true, true); } @SuppressWarnings("deprecation") // need to set it for compat @@ -241,7 +267,7 @@ setSystemName(s); } - private void setJarFile(final File aRoot, boolean refreshRoot) + private void setJarFile(final File aRoot, boolean refreshRoot, boolean openJar) throws IOException, PropertyVetoException { if (!aRoot.equals(FileUtil.normalizeFile(aRoot))) { throw new IllegalArgumentException( @@ -279,18 +305,20 @@ JarFile tempJar = null; - try { - tempJar = new JarFile(s); - LOGGER.log(Level.FINE, "opened: "+ System.currentTimeMillis()+ " " + s);//NOI18N - } catch (ZipException e) { - throw new FSException(NbBundle.getMessage(JarFileSystem.class, "EXC_NotValidJarFile2", e.getLocalizedMessage(), s)); + if (openJar) { + try { + tempJar = new JarFile(s); + LOGGER.log(Level.FINE, "opened: "+ System.currentTimeMillis()+ " " + s);//NOI18N + } catch (ZipException e) { + throw new FSException(NbBundle.getMessage(JarFileSystem.class, "EXC_NotValidJarFile2", e.getLocalizedMessage(), s)); + } } synchronized (closeSync) { _setSystemName(s); closeCurrentRoot(false); - jar = tempJar; + setJar(tempJar); openRequestTime = System.currentTimeMillis(); root = new File(s); @@ -328,7 +356,7 @@ if ((f != null) && !f.equals(aRoot)) { try { - setJarFile(f, false); + setJarFile(f, false, true); } catch (IOException iex) { ExternalUtil.exception(iex); } catch (PropertyVetoException pvex) { @@ -688,18 +716,7 @@ // 150% of time from last open request, but between CLOSE_DELAY_MIN and CLOSE_DELAY_MAX closeDelay = (int) Math.min(CLOSE_DELAY_MAX, Math.max(CLOSE_DELAY_MIN, (1.5 * requestPeriod))); - JarFile j = jar; - - if (j != null) { - return j; - } - - if ((jar == null) && (root != null)) { - jar = new JarFile(root); - LOGGER.log(Level.FINE, "opened: "+ System.currentTimeMillis()+ " " + root.getAbsolutePath());//NOI18N - } - - return jar; + return getJar(true); } } @@ -724,15 +741,16 @@ return new Runnable() { public void run() { synchronized (closeSync) { - if (jar != null) { + final JarFile jarFile = getJar(false); + if (jarFile != null) { try { - jar.close(); + jarFile.close(); LOGGER.log(Level.FINE, "closed: "+ System.currentTimeMillis()+ " " + root.getAbsolutePath());//NOI18N } catch (Exception exc) { // ignore exception during closing, just log it ExternalUtil.exception(exc); } finally { - jar = null; + setJar(null); closeTask = null; } } @@ -895,7 +913,10 @@ synchronized (closeSync) { j = reOpenJarFile(); - JarEntry je = j.getJarEntry(file); + JarEntry je = null; + if (j != null) { + je = j.getJarEntry(file); + } if (je != null) { return je; @@ -907,6 +928,29 @@ return new JarEntry(file); } + /** + * @return the jar + */ + private JarFile getJar(boolean create) { + assert Thread.holdsLock(closeSync); + if (jar == null && create) { + try { + jar = new JarFile(root); + LOGGER.log(Level.FINE, "opened: {0} {1}", new Object[]{System.currentTimeMillis(), root.getAbsolutePath()}); //NOI18N + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + } + } + return jar; + } + + /** + * @param jar the jar to set + */ + private void setJar(JarFile jar) { + this.jar = jar; + } + /** Use soft-references to not throw away the data that quickly. * JarFS if often queried for its FOs e.g. by java parser, which * leaves the references immediately. --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ ba5cca4b8d8e Tue Jan 19 20:15:01 2010 +0100 @@ -0,0 +1,80 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2010 Sun Microsystems, Inc. + */ + +package org.openide.filesystems; + +import java.io.File; +import java.util.jar.JarException; +import org.netbeans.junit.NbTestCase; + +/** + * + * @author Jaroslav Tulach + */ +public class JarFileSystemHidden extends NbTestCase { + + public JarFileSystemHidden(String name) { + super(name); + } + + public void testLazyJarForNonExistingConstructor() throws Exception { + File f = new File(getWorkDir(), "broken.jar"); + f.createNewFile(); + + JarFileSystem fs = new JarFileSystem(f); + + assertEquals("No children", 0, fs.getRoot().getChildren().length); + } + + public void testEagerJarForNonExistingSetter() throws Exception { + File f = new File(getWorkDir(), "broken.jar"); + f.createNewFile(); + + JarFileSystem fs = new JarFileSystem(); + try { + fs.setJarFile(f); + fail("This shall fail, with JarException as the file cannot be opened"); + } catch (FSException ex) { + assertTrue(ex.getMessage(), ex.getMessage().contains("Error in JAR")); + } + + assertEquals("No children", 0, fs.getRoot().getChildren().length); + } + +} --- a/openide.filesystems/test/unit/src/org/openide/filesystems/JarFileSystemTest.java Tue Jan 19 14:36:18 2010 +0100 +++ a/openide.filesystems/test/unit/src/org/openide/filesystems/JarFileSystemTest.java Tue Jan 19 20:15:01 2010 +0100 @@ -72,7 +72,8 @@ /*failing tests*/ suite.addTestSuite(URLMapperTestHidden.class); suite.addTestSuite(URLMapperTestInternalHidden.class); - suite.addTestSuite(FileUtilTestHidden.class); + suite.addTestSuite(FileUtilTestHidden.class); + suite.addTestSuite(JarFileSystemHidden.class); return new JarFileSystemTest(suite); }