KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > nbbuild > MakeJNLP


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.nbbuild;
21
22 import java.io.File JavaDoc;
23 import java.io.FileWriter JavaDoc;
24 import java.io.IOException JavaDoc;
25 import java.io.InputStream JavaDoc;
26 import java.io.StringWriter JavaDoc;
27 import java.io.Writer JavaDoc;
28 import java.util.ArrayList JavaDoc;
29 import java.util.Collections JavaDoc;
30 import java.util.Enumeration JavaDoc;
31 import java.util.HashMap JavaDoc;
32 import java.util.HashSet JavaDoc;
33 import java.util.Iterator JavaDoc;
34 import java.util.List JavaDoc;
35 import java.util.Map JavaDoc;
36 import java.util.Properties JavaDoc;
37 import java.util.Set JavaDoc;
38 import java.util.StringTokenizer JavaDoc;
39 import java.util.jar.JarEntry JavaDoc;
40 import java.util.jar.JarFile JavaDoc;
41 import java.util.jar.Manifest JavaDoc;
42 import java.util.regex.Matcher JavaDoc;
43 import java.util.regex.Pattern JavaDoc;
44 import java.util.zip.ZipEntry JavaDoc;
45 import javax.xml.parsers.ParserConfigurationException JavaDoc;
46 import org.apache.tools.ant.BuildException;
47 import org.apache.tools.ant.DirectoryScanner;
48 import org.apache.tools.ant.Project;
49 import org.apache.tools.ant.Task;
50 import org.apache.tools.ant.taskdefs.Copy;
51 import org.apache.tools.ant.taskdefs.SignJar;
52 import org.apache.tools.ant.taskdefs.Zip;
53 import org.apache.tools.ant.types.FileSet;
54 import org.apache.tools.ant.types.ZipFileSet;
55 import org.xml.sax.SAXException JavaDoc;
56
57 /** Generates JNLP files for signed versions of the module JAR files.
58  *
59  * @author Jaroslav Tulach, Jesse Glick
60  */

61 public class MakeJNLP extends Task {
62     /** the files to work on */
63     private FileSet files;
64     private SignJar signTask;
65     
66     public FileSet createModules()
67     throws BuildException {
68         if (files != null) throw new BuildException("modules can be created just once");
69         files = new FileSet();
70         return files;
71     }
72     
73     private SignJar getSignTask() {
74         if (signTask == null) {
75             signTask = (SignJar)getProject().createTask("signjar");
76         }
77         return signTask;
78     }
79     
80     private File JavaDoc target;
81     public void setDir(File JavaDoc t) {
82         target = t;
83     }
84     
85     public void setAlias(String JavaDoc a) {
86         getSignTask().setAlias(a);
87     }
88     
89     public void setStorePass(String JavaDoc p) {
90         getSignTask().setStorepass(p);
91     }
92     
93     public void setKeystore(String JavaDoc k) {
94         getSignTask().setKeystore(k);
95     }
96     
97     private String JavaDoc codebase = "$$codebase";
98     public void setCodebase(String JavaDoc s) {
99         this.codebase = s;
100     }
101     
102     private boolean verify;
103     public void setVerify(boolean v) {
104         this.verify = v;
105     }
106     
107     private String JavaDoc verifyExcludes;
108     /** Comma separated list of allowed excluded names of files during verify
109      * phase.
110      */

111     public void setVerifyExcludes(String JavaDoc s) {
112         this.verifyExcludes = s;
113     }
114
115     private String JavaDoc permissions = "<all-permissions/>";
116     /**
117      * XML fragment pasted into the security part of the .jnlp file.
118      * Should deafult to "&lt;all-permissions/&gt;"
119      */

120     public void setPermissions(String JavaDoc s) {
121         permissions = s;
122     }
123     
124     private FileSet indirectJars;
125     /**
126      * Other JARs which should be copied into the destination directory and referred to as resources,
127      * even though they are not listed as Class-Path extensions of the module and would not normally
128      * be in its effective classpath. The basedir of the fileset should be a cluster root; for each
129      * such JAR, a file META-INF/clusterpath/$relpath will be inserted in the JAR, where $relpath is the
130      * relative path within the cluster. This permits the JAR to be located at runtime in a flat classpath,
131      * using ClassLoader.getResource.
132      */

133     public void addIndirectJars(FileSet fs) {
134         indirectJars = fs;
135     }
136     
137     public void execute() throws BuildException {
138         if (target == null) throw new BuildException("Output dir must be provided");
139         if (files == null) throw new BuildException("modules must be provided");
140         
141         try {
142             generateFiles();
143         } catch (IOException JavaDoc ex) {
144             throw new BuildException(ex);
145         }
146     }
147     
148     private void generateFiles() throws IOException JavaDoc, BuildException {
149         Set JavaDoc<String JavaDoc> indirectJarPaths = Collections.emptySet();
150         if (indirectJars != null) {
151             DirectoryScanner scan = indirectJars.getDirectoryScanner(getProject());
152             indirectJarPaths = new HashSet JavaDoc<String JavaDoc>();
153             for (String JavaDoc f : scan.getIncludedFiles()) {
154                 indirectJarPaths.add(f.replace(File.pathSeparatorChar, '/'));
155             }
156         }
157
158         DirectoryScanner scan = files.getDirectoryScanner(getProject());
159         for (String JavaDoc f : scan.getIncludedFiles()) {
160             File JavaDoc jar = new File JavaDoc (files.getDir(getProject()), f);
161             
162             if (!jar.canRead()) {
163                 throw new BuildException("Cannot read file: " + jar);
164             }
165             
166             JarFile JavaDoc theJar = new JarFile JavaDoc(jar);
167             String JavaDoc codenamebase = theJar.getManifest().getMainAttributes().getValue("OpenIDE-Module");
168             if (codenamebase == null) {
169                 throw new BuildException("Not a NetBeans Module: " + jar);
170             }
171             {
172                 int slash = codenamebase.indexOf('/');
173                 if (slash >= 0) {
174                     codenamebase = codenamebase.substring(0, slash);
175                 }
176             }
177             String JavaDoc dashcnb = codenamebase.replace('.', '-');
178             
179             String JavaDoc title;
180             String JavaDoc oneline;
181             String JavaDoc shrt;
182             
183             {
184                 String JavaDoc bundle = theJar.getManifest().getMainAttributes().getValue("OpenIDE-Module-Localizing-Bundle");
185                 Properties JavaDoc prop = new Properties JavaDoc();
186                 if (bundle != null) {
187                     ZipEntry JavaDoc en = theJar.getEntry(bundle);
188                     if (en == null) {
189                         throw new BuildException("Cannot find entry: " + bundle + " in file: " + jar);
190                     }
191                     InputStream JavaDoc is = theJar.getInputStream(en);
192                     prop.load(is);
193                     is.close();
194                 }
195                 title = prop.getProperty("OpenIDE-Module-Name", codenamebase);
196                 oneline = prop.getProperty("OpenIDE-Module-Short-Description", title);
197                 shrt = prop.getProperty("OpenIDE-Module-Long-Description", oneline);
198             }
199             
200             Map JavaDoc<String JavaDoc,List JavaDoc<File JavaDoc>> localizedFiles = verifyExtensions(jar, theJar.getManifest(), dashcnb, codenamebase, verify, indirectJarPaths);
201             
202             new File JavaDoc(target, dashcnb).mkdir();
203
204             File JavaDoc signed = new File JavaDoc(new File JavaDoc(target, dashcnb), jar.getName());
205             File JavaDoc jnlp = new File JavaDoc(target, dashcnb + ".jnlp");
206             
207             StringWriter JavaDoc writeJNLP = new StringWriter JavaDoc();
208             writeJNLP.write("<?xml version='1.0' encoding='UTF-8'?>\n");
209             writeJNLP.write("<jnlp spec='1.0+' codebase='" + codebase + "' >\n");
210             writeJNLP.write(" <information>\n");
211             writeJNLP.write(" <title>" + title + "</title>\n");
212             writeJNLP.write(" <vendor>NetBeans</vendor>\n");
213             writeJNLP.write(" <description kind='one-line'>" + oneline + "</description>\n");
214             writeJNLP.write(" <description kind='short'>" + shrt + "</description>\n");
215             writeJNLP.write(" </information>\n");
216             writeJNLP.write(permissions +"\n");
217             writeJNLP.write(" <resources>\n");
218             writeJNLP.write(" <jar HREF='" + dashcnb + '/' + jar.getName() + "'/>\n");
219             
220             processExtensions(jar, theJar.getManifest(), writeJNLP, dashcnb, codebase);
221             processIndirectJars(writeJNLP, dashcnb, codebase);
222             
223             writeJNLP.write(" </resources>\n");
224             
225             {
226                 // write down locales
227
for (Map.Entry JavaDoc<String JavaDoc,List JavaDoc<File JavaDoc>> e : localizedFiles.entrySet()) {
228                     String JavaDoc locale = e.getKey();
229                     List JavaDoc<File JavaDoc> files = e.getValue();
230                     
231                     writeJNLP.write(" <resources locale='" + locale + "'>\n");
232
233                     for (File JavaDoc n : files) {
234                         String JavaDoc name = n.getName();
235                         String JavaDoc clusterRootPrefix = jar.getParent() + File.separatorChar;
236                         String JavaDoc absname = n.getAbsolutePath();
237                         if (absname.startsWith(clusterRootPrefix)) {
238                             name = absname.substring(clusterRootPrefix.length()).replace('/', '-');
239                         }
240                         File JavaDoc t = new File JavaDoc(new File JavaDoc(target, dashcnb), name);
241                         
242                         getSignTask().setJar(n);
243                         getSignTask().setSignedjar(t);
244                         getSignTask().execute();
245                         
246                         writeJNLP.write(" <jar HREF='" + dashcnb + '/' + name + "'/>\n");
247                     }
248
249                     writeJNLP.write(" </resources>\n");
250                     
251                 }
252             }
253             
254             writeJNLP.write(" <component-desc/>\n");
255             writeJNLP.write("</jnlp>\n");
256             writeJNLP.close();
257             
258             FileWriter JavaDoc w = new FileWriter JavaDoc(jnlp);
259             w.write(writeJNLP.toString());
260             w.close();
261
262             getSignTask().setJar(jar);
263             getSignTask().setSignedjar(signed);
264             getSignTask().execute();
265                 
266                 
267             theJar.close();
268         }
269         
270     }
271     
272     private Map JavaDoc<String JavaDoc,List JavaDoc<File JavaDoc>> verifyExtensions(File JavaDoc f, Manifest JavaDoc mf, String JavaDoc dashcnb, String JavaDoc codebasename, boolean verify, Set JavaDoc<String JavaDoc> indirectJarPaths) throws IOException JavaDoc, BuildException {
273         Map JavaDoc<String JavaDoc,List JavaDoc<File JavaDoc>> localizedFiles = new HashMap JavaDoc<String JavaDoc,List JavaDoc<File JavaDoc>>();
274         
275         
276         File JavaDoc clusterRoot = f.getParentFile();
277         String JavaDoc moduleDirPrefix = "";
278         File JavaDoc updateTracking;
279         for(;;) {
280             updateTracking = new File JavaDoc(clusterRoot, "update_tracking");
281             if (updateTracking.isDirectory()) {
282                 break;
283             }
284             moduleDirPrefix = clusterRoot.getName() + "/" + moduleDirPrefix;
285             clusterRoot = clusterRoot.getParentFile();
286             if (clusterRoot == null || !clusterRoot.exists()) {
287                 if (!verify) {
288                     return localizedFiles;
289                 }
290                 
291                 throw new BuildException("Cannot find update_tracking directory for module " + f);
292             }
293         }
294         
295         File JavaDoc ut = new File JavaDoc(updateTracking, dashcnb + ".xml");
296         if (!ut.exists()) {
297             throw new BuildException("The file " + ut + " for module " + codebasename + " cannot be found");
298         }
299         
300         Map JavaDoc<String JavaDoc,String JavaDoc> fileToOwningModule = new HashMap JavaDoc<String JavaDoc,String JavaDoc>();
301         try {
302             ModuleSelector.readUpdateTracking(getProject(), ut.toString(), fileToOwningModule);
303         } catch (IOException JavaDoc ex) {
304             throw new BuildException(ex);
305         } catch (ParserConfigurationException JavaDoc ex) {
306             throw new BuildException(ex);
307         } catch (SAXException JavaDoc ex) {
308             throw new BuildException(ex);
309         }
310         
311         log("project files: " + fileToOwningModule, Project.MSG_DEBUG);
312         String JavaDoc name = relative(f, clusterRoot);
313         log(" removing: " + name, Project.MSG_DEBUG);
314         removeWithLocales(fileToOwningModule, name, clusterRoot, localizedFiles);
315         name = "config/Modules/" + dashcnb + ".xml";
316         log(" removing: " + name, Project.MSG_DEBUG);
317         removeWithLocales(fileToOwningModule, name, clusterRoot, localizedFiles);
318         name = "config/ModuleAutoDeps/" + dashcnb + ".xml";
319         log(" removing: " + name, Project.MSG_DEBUG);
320         removeWithLocales(fileToOwningModule, name, clusterRoot, localizedFiles);
321         name = "update_tracking/" + dashcnb + ".xml";
322         log(" removing: " + name, Project.MSG_DEBUG);
323         removeWithLocales(fileToOwningModule, name, clusterRoot, localizedFiles);
324         
325         
326         
327         
328         String JavaDoc path = mf.getMainAttributes().getValue("Class-Path");
329         if (path != null) {
330             StringTokenizer JavaDoc tok = new StringTokenizer JavaDoc(path, ", ");
331             while(tok.hasMoreElements()) {
332                 String JavaDoc s = tok.nextToken();
333                 File JavaDoc e = new File JavaDoc(f.getParentFile(), s);
334                 String JavaDoc r = relative(e, clusterRoot);
335                 removeWithLocales(fileToOwningModule, r, clusterRoot, localizedFiles);
336             }
337         }
338
339         fileToOwningModule.remove("ant/nblib/" + dashcnb + ".jar");
340
341         fileToOwningModule.keySet().removeAll(indirectJarPaths);
342         
343         if (verifyExcludes != null) {
344             StringTokenizer JavaDoc tok = new StringTokenizer JavaDoc(verifyExcludes, ", ");
345             while(tok.hasMoreElements()) {
346                 removeWithLocales(fileToOwningModule, tok.nextToken(), clusterRoot, localizedFiles);
347             }
348         }
349             
350         
351         if (verify) {
352             if (!fileToOwningModule.isEmpty()) {
353                 throw new BuildException(
354                     "Cannot build JNLP for module " + f + " as these files are in " +
355                     "module's NBM, but are not referenced from any path:\n" + fileToOwningModule.keySet()
356                 );
357             }
358         }
359         
360         return localizedFiles;
361     }
362     
363     private static void removeWithLocales(Map JavaDoc<String JavaDoc,String JavaDoc> removeFrom, String JavaDoc removeWhat, File JavaDoc clusterRoot, Map JavaDoc<String JavaDoc,List JavaDoc<File JavaDoc>> recordLocales) {
364         if (removeFrom.remove(removeWhat) != null && removeWhat.endsWith(".jar")) {
365             int basedir = removeWhat.lastIndexOf('/');
366             String JavaDoc base = basedir == -1 ? "" : removeWhat.substring(0, basedir);
367             String JavaDoc name = removeWhat.substring(basedir + 1, removeWhat.length() - 4);
368             Pattern JavaDoc p = Pattern.compile(base + "/locale/" + name + "(|_[a-zA-Z0-9_]+)\\.jar");
369             
370             Iterator JavaDoc it = removeFrom.keySet().iterator();
371             while (it.hasNext()) {
372                 String JavaDoc s = (String JavaDoc)it.next();
373                 Matcher JavaDoc m = p.matcher(s);
374                 if (m.matches()) {
375                     String JavaDoc locale = m.group(1).substring(1);
376                     
377                     List JavaDoc<File JavaDoc> l = recordLocales.get(locale);
378                     if (l == null) {
379                         l = new ArrayList JavaDoc<File JavaDoc>();
380                         recordLocales.put(locale, l);
381                     }
382                     l.add(new File JavaDoc(clusterRoot, s.replace('/', File.separatorChar)));
383                     it.remove();
384                 }
385             }
386         }
387     }
388
389     private void processExtensions(File JavaDoc f, Manifest JavaDoc mf, Writer JavaDoc fileWriter, String JavaDoc dashcnb, String JavaDoc codebase) throws IOException JavaDoc, BuildException {
390
391         File JavaDoc nblibJar = new File JavaDoc(new File JavaDoc(new File JavaDoc(f.getParentFile().getParentFile(), "ant"), "nblib"), dashcnb + ".jar");
392         if (nblibJar.isFile()) {
393             File JavaDoc ext = new File JavaDoc(new File JavaDoc(target, dashcnb), "ant-nblib-" + nblibJar.getName());
394             fileWriter.write(" <jar HREF='" + dashcnb + '/' + ext.getName() + "'/>\n");
395             getSignTask().setJar(nblibJar);
396             getSignTask().setSignedjar(ext);
397             getSignTask().execute();
398         }
399
400         String JavaDoc path = mf.getMainAttributes().getValue("Class-Path");
401         if (path == null) {
402             return;
403         }
404         
405         StringTokenizer JavaDoc tok = new StringTokenizer JavaDoc(path, ", ");
406         while(tok.hasMoreElements()) {
407             String JavaDoc s = tok.nextToken();
408             
409             File JavaDoc e = new File JavaDoc(f.getParentFile(), s);
410             if (!e.canRead()) {
411                 throw new BuildException("Cannot read extension " + e + " referenced from " + f);
412             }
413             String JavaDoc n = e.getName();
414             if (n.endsWith(".jar")) {
415                 n = n.substring(0, n.length() - 4);
416             }
417             
418             if (isSigned(e) != null) {
419                 Copy copy = (Copy)getProject().createTask("copy");
420                 copy.setFile(e);
421                 File JavaDoc t = new File JavaDoc(new File JavaDoc(target, dashcnb), s.replace('/', '-'));
422                 copy.setTofile(t);
423                 copy.execute();
424                 
425                 String JavaDoc extJnlpName = t.getName().replaceFirst("\\.jar$", "") + ".jnlp";
426                 File JavaDoc jnlp = new File JavaDoc(new File JavaDoc(target, dashcnb), extJnlpName);
427
428                 FileWriter JavaDoc writeJNLP = new FileWriter JavaDoc(jnlp);
429                 writeJNLP.write("<?xml version='1.0' encoding='UTF-8'?>\n");
430                 writeJNLP.write("<jnlp spec='1.0+' codebase='" + codebase + "' >\n");
431                 writeJNLP.write(" <information>\n");
432                 writeJNLP.write(" <title>" + n + "</title>\n");
433                 writeJNLP.write(" <vendor>NetBeans</vendor>\n");
434                 writeJNLP.write(" </information>\n");
435                 writeJNLP.write(permissions +"\n");
436                 writeJNLP.write(" <resources>\n");
437                 writeJNLP.write(" <jar HREF='" + dashcnb + '/' + t.getName() + "'/>\n");
438                 writeJNLP.write(" </resources>\n");
439                 writeJNLP.write(" <component-desc/>\n");
440                 writeJNLP.write("</jnlp>\n");
441                 writeJNLP.close();
442                 
443                 fileWriter.write(" <extension name='" + e.getName().replaceFirst("\\.jar$", "") + "' HREF='" + dashcnb + '/' + extJnlpName + "'/>\n");
444             } else {
445                 File JavaDoc ext = new File JavaDoc(new File JavaDoc(target, dashcnb), s.replace('/', '-'));
446                 
447                 fileWriter.write(" <jar HREF='" + dashcnb + '/' + ext.getName() + "'/>\n");
448
449                 getSignTask().setJar(e);
450                 getSignTask().setSignedjar(ext);
451                 getSignTask().execute();
452             }
453         }
454     }
455
456     private void processIndirectJars(Writer JavaDoc fileWriter, String JavaDoc dashcnb, String JavaDoc codebase) throws IOException JavaDoc, BuildException {
457         if (indirectJars == null) {
458             return;
459         }
460         DirectoryScanner scan = indirectJars.getDirectoryScanner(getProject());
461         for (String JavaDoc f : scan.getIncludedFiles()) {
462             File JavaDoc jar = new File JavaDoc(scan.getBasedir(), f);
463             String JavaDoc rel = f.replace(File.separatorChar, '/');
464             String JavaDoc sig = isSigned(jar);
465             // javaws will reject .zip files even with signatures.
466
String JavaDoc rel2 = rel.endsWith(".jar") ? rel : rel.replaceFirst("(\\.zip)?$", ".jar");
467             File JavaDoc ext = new File JavaDoc(new File JavaDoc(target, dashcnb), rel2.replace('/', '-').replaceFirst("^modules-", ""));
468             Zip jartask = (Zip) getProject().createTask("jar");
469             jartask.setDestFile(ext);
470             ZipFileSet zfs = new ZipFileSet();
471             zfs.setSrc(jar);
472             if (sig != null) {
473                 // Need to cancel original signature since we are adding one entry to the JAR.
474
zfs.setExcludes("META-INF/" + sig + ".*");
475             }
476             jartask.addZipfileset(zfs);
477             zfs = new ZipFileSet();
478             File JavaDoc blank = File.createTempFile("empty", "");
479             blank.deleteOnExit();
480             zfs.setFile(blank);
481             zfs.setFullpath("META-INF/clusterpath/" + rel);
482             jartask.addZipfileset(zfs);
483             jartask.execute();
484             blank.delete();
485             fileWriter.write(" <jar HREF='" + dashcnb + '/' + ext.getName() + "'/>\n");
486             getSignTask().setJar(ext);
487             getSignTask().setSignedjar(null);
488             getSignTask().execute();
489         }
490     }
491     
492     private static String JavaDoc relative(File JavaDoc file, File JavaDoc root) {
493         String JavaDoc sfile = file.toString().replace(File.separatorChar, '/');
494         String JavaDoc sroot = (root.toString() + File.separator).replace(File.separatorChar, '/');
495         if (sfile.startsWith(sroot)) {
496             return sfile.substring(sroot.length());
497         }
498         return sfile;
499     }
500     
501     /** return alias if signed, or null if not */
502     private static String JavaDoc isSigned(File JavaDoc f) throws IOException JavaDoc {
503         JarFile JavaDoc jar = new JarFile JavaDoc(f);
504         try {
505             Enumeration JavaDoc<JarEntry JavaDoc> en = jar.entries();
506             while (en.hasMoreElements()) {
507                 Matcher JavaDoc m = SF.matcher(en.nextElement().getName());
508                 if (m.matches()) {
509                     return m.group(1);
510                 }
511             }
512             return null;
513         } finally {
514             jar.close();
515         }
516     }
517     private static final Pattern JavaDoc SF = Pattern.compile("META-INF/(.+)\\.SF");
518     
519 }
520
Popular Tags