diff --git a/apisupport.harness/jnlp-src/org/netbeans/modules/apisupport/jnlplauncher/InstalledFileLocatorImpl.java b/apisupport.harness/jnlp-src/org/netbeans/modules/apisupport/jnlplauncher/InstalledFileLocatorImpl.java --- a/apisupport.harness/jnlp-src/org/netbeans/modules/apisupport/jnlplauncher/InstalledFileLocatorImpl.java +++ b/apisupport.harness/jnlp-src/org/netbeans/modules/apisupport/jnlplauncher/InstalledFileLocatorImpl.java @@ -42,17 +42,22 @@ package org.netbeans.modules.apisupport.jnlplauncher; import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.net.URI; import java.net.URL; import java.util.Iterator; import org.openide.modules.InstalledFileLocator; +import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.openide.util.lookup.ServiceProvider; /** * Special locator for JNLP mode. - * Currently just locates JARs with the special META-INF/clusterpath/$relpath - * entry inserted by common.xml -> . + * Locates files in userdir; JARs with the special META-INF/clusterpath/$relpath entry; + * and JARs present in extra-files.jar. * @author Jesse Glick */ @ServiceProvider(service=InstalledFileLocator.class, supersedes="org.netbeans.core.startup.InstalledFileLocatorImpl") @@ -103,6 +108,31 @@ } } } + try { + InputStream is = loader.getResourceAsStream("META-INF/files/" + relativePath); + if (is != null) { + try { + // XXX could try to cache previously created files + File temp = File.createTempFile("nbjnlp-", relativePath.replaceFirst("^.+/", "")); + temp.deleteOnExit(); + OutputStream os = new FileOutputStream(temp); + try { + byte[] buf = new byte[4096]; + int read; + while ((read = is.read(buf)) != -1) { + os.write(buf, 0, read); + } + } finally { + os.close(); + } + return temp; + } finally { + is.close(); + } + } + } catch (IOException x) { + Exceptions.printStackTrace(x); + } } return null; } diff --git a/apisupport.harness/release/README b/apisupport.harness/release/README --- a/apisupport.harness/release/README +++ b/apisupport.harness/release/README @@ -855,6 +855,15 @@ entry META-INF/clusterpath/$path where $path is the ('/'-separated) path within the cluster where the JAR would be found in a normal installation. +jnlp.indirect.files [since 7.0M1] - optional pattern of files in the cluster to + load in JNLP mode. The module may load these files using InstalledFileLocator + using the same path in regular as in JNLP mode. Note that the physical path on + disk to the resulting file will not necessarily contain the directory prefix + that the file in the cluster uses, so do not expect that file.getParentFile() + is meaningful. The implementation creates a JAR entry META-INF/files/$path + where $path is the ('/'-separated) path within the cluster where the file + would be found in a normal installation. + jnlp.verify.excludes - the default implementation of "jnlp" task in common.xml does verification and compares that all files from module NBM are really referenced from the JNLP file. Sometimes not all of them need to be, for diff --git a/nbbuild/antsrc/org/netbeans/nbbuild/MakeJNLP.java b/nbbuild/antsrc/org/netbeans/nbbuild/MakeJNLP.java --- a/nbbuild/antsrc/org/netbeans/nbbuild/MakeJNLP.java +++ b/nbbuild/antsrc/org/netbeans/nbbuild/MakeJNLP.java @@ -48,11 +48,11 @@ import java.io.StringWriter; import java.io.Writer; import java.util.ArrayList; -import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Properties; @@ -155,6 +155,18 @@ public void addIndirectJars(FileSet fs) { indirectJars = fs; } + + private FileSet indirectFiles; + /** + * Other non-JAR files which should be made available to InstalledFileLocator. + * The basedir of the fileset should be a cluster root; each + * such file will be packed into a ZIP entry META-INF/files/$relpath + * where the JAR will be available at runtime in a flat classpath, + * using ClassLoader.getResource. + */ + public void addIndirectFiles(FileSet fs) { + indirectFiles = fs; + } private boolean signJars = true; /** @@ -204,12 +216,13 @@ } private void generateFiles() throws IOException, BuildException { - Set indirectJarPaths = Collections.emptySet(); - if (indirectJars != null) { - DirectoryScanner scan = indirectJars.getDirectoryScanner(getProject()); - indirectJarPaths = new HashSet(); - for (String f : scan.getIncludedFiles()) { - indirectJarPaths.add(f.replace(File.pathSeparatorChar, '/')); + Set indirectFilePaths = new HashSet(); + for (FileSet fs : new FileSet[] {indirectJars, indirectFiles}) { + if (fs != null) { + DirectoryScanner scan = fs.getDirectoryScanner(getProject()); + for (String f : scan.getIncludedFiles()) { + indirectFilePaths.add(f.replace(File.pathSeparatorChar, '/')); + } } } @@ -263,7 +276,7 @@ } } - Map> localizedFiles = verifyExtensions(jar, theJar.getManifest(), dashcnb, codenamebase, verify, indirectJarPaths); + Map> localizedFiles = verifyExtensions(jar, theJar.getManifest(), dashcnb, codenamebase, verify, indirectFilePaths); new File(targetFile, dashcnb).mkdir(); @@ -286,10 +299,11 @@ } else { writeJNLP.write(" \n"); } - writeJNLP.write(" \n"); + writeJNLP.write(" \n"); processExtensions(jar, theJar.getManifest(), writeJNLP, dashcnb, codebase); - processIndirectJars(writeJNLP, dashcnb, codebase); + processIndirectJars(writeJNLP, dashcnb); + processIndirectFiles(writeJNLP, dashcnb); writeJNLP.write(" \n"); @@ -334,7 +348,7 @@ } - private Map> verifyExtensions(File f, Manifest mf, String dashcnb, String codebasename, boolean verify, Set indirectJarPaths) throws IOException, BuildException { + private Map> verifyExtensions(File f, Manifest mf, String dashcnb, String codebasename, boolean verify, Set indirectFilePaths) throws IOException, BuildException { Map> localizedFiles = new HashMap>(); @@ -403,7 +417,7 @@ fileToOwningModule.remove("ant/nblib/" + dashcnb + ".jar"); - fileToOwningModule.keySet().removeAll(indirectJarPaths); + fileToOwningModule.keySet().removeAll(indirectFilePaths); if (verifyExcludes != null) { StringTokenizer tok = new StringTokenizer(verifyExcludes, ", "); @@ -515,7 +529,7 @@ } } - private void processIndirectJars(Writer fileWriter, String dashcnb, String codebase) throws IOException, BuildException { + private void processIndirectJars(Writer fileWriter, String dashcnb) throws IOException, BuildException { if (indirectJars == null) { return; } @@ -523,7 +537,12 @@ for (String f : scan.getIncludedFiles()) { File jar = new File(scan.getBasedir(), f); String rel = f.replace(File.separatorChar, '/'); - String sig = isSigned(jar); + String sig; + try { + sig = isSigned(jar); + } catch (IOException x) { + throw new BuildException("Cannot check signature on " + jar, x, getLocation()); + } // javaws will reject .zip files even with signatures. String rel2 = rel.endsWith(".jar") ? rel : rel.replaceFirst("(\\.zip)?$", ".jar"); File ext = new File(new File(targetFile, dashcnb), rel2.replace('/', '-').replaceFirst("^modules-", "")); @@ -549,6 +568,32 @@ } } + private void processIndirectFiles(Writer fileWriter, String dashcnb) throws IOException, BuildException { + if (indirectFiles == null) { + return; + } + DirectoryScanner scan = indirectFiles.getDirectoryScanner(getProject()); + Map entries = new LinkedHashMap(); + for (String f : scan.getIncludedFiles()) { + entries.put(f.replace(File.separatorChar, '/'), new File(scan.getBasedir(), f)); + } + if (entries.isEmpty()) { + return; + } + File ext = new File(new File(targetFile, dashcnb), "extra-files.jar"); + Zip jartask = (Zip) getProject().createTask("jar"); + jartask.setDestFile(ext); + for (Map.Entry entry : entries.entrySet()) { + ZipFileSet zfs = new ZipFileSet(); + zfs.setFile(entry.getValue()); + zfs.setFullpath("META-INF/files/" + entry.getKey()); + jartask.addZipfileset(zfs); + } + jartask.execute(); + fileWriter.write(" \n"); + signOrCopy(ext, null); + } + private static String relative(File file, File root) { String sfile = file.toString().replace(File.separatorChar, '/'); String sroot = (root.toString() + File.separator).replace(File.separatorChar, '/'); diff --git a/nbbuild/templates/common.xml b/nbbuild/templates/common.xml --- a/nbbuild/templates/common.xml +++ b/nbbuild/templates/common.xml @@ -283,6 +283,8 @@ + + @@ -301,6 +303,7 @@ +