KickJava   Java API By Example, From Geeks To Geeks.

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


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.ByteArrayInputStream JavaDoc;
23 import java.util.HashMap JavaDoc;
24 import java.util.LinkedHashMap JavaDoc;
25 import java.util.Map JavaDoc;
26 import org.apache.tools.ant.types.FileSet;
27 import org.apache.tools.ant.BuildException;
28 import org.apache.tools.ant.taskdefs.MatchingTask;
29 import org.apache.tools.ant.DirectoryScanner;
30 import java.io.File JavaDoc;
31 import java.io.FileOutputStream JavaDoc;
32 import java.io.IOException JavaDoc;
33 import java.io.InputStream JavaDoc;
34 import java.io.OutputStream JavaDoc;
35 import java.io.OutputStreamWriter JavaDoc;
36 import java.io.PrintWriter JavaDoc;
37 import java.text.Collator JavaDoc;
38 import java.text.DateFormat JavaDoc;
39 import java.text.SimpleDateFormat JavaDoc;
40 import java.util.ArrayList JavaDoc;
41 import java.util.Collection JavaDoc;
42 import java.util.Comparator JavaDoc;
43 import java.util.Date JavaDoc;
44 import java.util.HashSet JavaDoc;
45 import java.util.List JavaDoc;
46 import java.util.Set JavaDoc;
47 import java.util.TimeZone JavaDoc;
48 import java.util.TreeMap JavaDoc;
49 import java.util.TreeSet JavaDoc;
50 import java.util.zip.ZipEntry JavaDoc;
51 import java.util.zip.ZipFile JavaDoc;
52 import org.w3c.dom.Element JavaDoc;
53 import org.w3c.dom.NodeList JavaDoc;
54 import org.xml.sax.EntityResolver JavaDoc;
55 import org.xml.sax.InputSource JavaDoc;
56 import org.xml.sax.SAXException JavaDoc;
57
58 /** Makes an XML file representing update information from NBMs.
59  *
60  * @author Jesse Glick
61  */

62 public class MakeUpdateDesc extends MatchingTask {
63
64     protected boolean usedMatchingTask = false;
65     /** Set of NBMs presented as a folder in the Update Center. */
66     public /*static*/ class Group {
67         public List JavaDoc<FileSet> filesets = new ArrayList JavaDoc<FileSet>();
68     public String JavaDoc name;
69
70         /** Displayed name of the group. */
71     public void setName (String JavaDoc s) {
72         name = s;
73     }
74
75         /** Add fileset to the group of NetBeans modules **/
76         public void addFileSet (FileSet set) {
77             filesets.add(set);
78         }
79     }
80     
81     /** pointer to another xml entity to include **/
82     public class Entityinclude {
83         public String JavaDoc file;
84         /** Path to the entity file.
85          * It included as an xml-entity pointer in master .xml file.
86          */

87     public void setFile (String JavaDoc f) {
88         file = f;
89     }
90     }
91
92     private List JavaDoc<Entityinclude> entityincludes = new ArrayList JavaDoc<Entityinclude>();
93     private List JavaDoc<Group> groups = new ArrayList JavaDoc<Group>();
94     private List JavaDoc<FileSet> filesets = new ArrayList JavaDoc<FileSet>();
95
96     private File JavaDoc desc;
97
98     /** Description file to create. */
99     public void setDesc(File JavaDoc d) {
100         desc = d;
101     }
102
103     /** Module group to create **/
104     public Group createGroup () {
105     Group g = new Group ();
106     groups.add (g);
107     return g;
108     }
109
110     /** External XML entity include **/
111     public Entityinclude createEntityinclude () {
112         Entityinclude i = new Entityinclude ();
113         entityincludes.add (i);
114         return i;
115     }
116
117    /**
118      * Adds a set of files (nested fileset attribute).
119      */

120     public void addFileset(FileSet set) {
121         filesets.add(set);
122     }
123
124     private boolean automaticGrouping;
125     /**
126      * Turn on if you want modules added to the root fileset
127      * to be automatically added to a group based on their display category (if set).
128      */

129     public void setAutomaticgrouping(boolean b) {
130         automaticGrouping = b;
131     }
132     
133     private String JavaDoc dist_base;
134    /**
135     * Set distribution base, which will be enforced
136     */

137     public void setDistBase(String JavaDoc dbase) {
138         dist_base = dbase;
139     }
140     
141     // Similar to org.openide.xml.XMLUtil methods.
142
private static String JavaDoc xmlEscape(String JavaDoc s) {
143         int max = s.length();
144         StringBuffer JavaDoc s2 = new StringBuffer JavaDoc((int)(max * 1.1 + 1));
145         for (int i = 0; i < max; i++) {
146             char c = s.charAt(i);
147             switch (c) {
148                 case '<':
149                     s2.append("&lt;"); //NOI18N
150
break;
151                 case '>':
152                     s2.append("&gt;"); //NOI18N
153
break;
154                 case '&':
155                     s2.append("&amp;"); //NOI18N
156
break;
157                 case '"':
158                     s2.append("&quot;"); //NOI18N
159
break;
160                 default:
161                     s2.append(c);
162                     break;
163             }
164         }
165         return s2.toString();
166     }
167
168     public void execute () throws BuildException {
169         Group root = new Group();
170         for (FileSet fs : filesets) {
171             root.addFileSet(fs);
172         }
173         groups.add(root);
174     if (desc.exists ()) {
175         // Simple up-to-date check.
176
long time = desc.lastModified ();
177         boolean uptodate = true;
178
179     CHECK:
180             for (Group g : groups) {
181                 for (FileSet n : g.filesets) {
182                     if ( n != null ) {
183                         DirectoryScanner ds = n.getDirectoryScanner(getProject());
184                         String JavaDoc[] files = ds.getIncludedFiles();
185                         File JavaDoc bdir = ds.getBasedir();
186                         for (String JavaDoc file : files) {
187                             File JavaDoc n_file = new File JavaDoc(bdir, file);
188                             if (n_file.lastModified () > time) {
189                                 uptodate = false;
190                                 break CHECK;
191                             }
192                         }
193             }
194         }
195         }
196         if (uptodate) return;
197     }
198     log ("Creating update description " + desc.getAbsolutePath ());
199         
200         Map JavaDoc<String JavaDoc,Collection JavaDoc<Module>> modulesByGroup = loadNBMs();
201         boolean targetClustersDefined = false;
202         for (Collection JavaDoc<Module> modules : modulesByGroup.values()) {
203             for (Module m : modules) {
204                 targetClustersDefined |= m.xml.getAttributeNode("targetcluster") != null;
205             }
206         }
207         
208         // XXX Apparently cannot create a doc with entities using DOM 2.
209
try {
210             desc.delete();
211             OutputStream JavaDoc os = new FileOutputStream JavaDoc(desc);
212         try {
213                 
214                 PrintWriter JavaDoc pw = new PrintWriter JavaDoc(new OutputStreamWriter JavaDoc(os, "UTF-8")); //NOI18N
215
pw.println ("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"); //NOI18N
216
pw.println ();
217                 DateFormat JavaDoc format = new SimpleDateFormat JavaDoc("ss/mm/HH/dd/MM/yyyy"); //NOI18N
218
format.setTimeZone(TimeZone.getTimeZone("GMT")); //NOI18N
219
String JavaDoc date = format.format(new Date JavaDoc());
220                 
221             if ( entityincludes.size() > 0 ) {
222                     // prepare .ent file
223
String JavaDoc ent_name = desc.getAbsolutePath();
224                     int xml_idx = ent_name.indexOf(".xml"); //NOI18N
225
if (xml_idx != -1) {
226                         ent_name = ent_name.substring (0, xml_idx) + ".ent"; //NOI18N
227
} else {
228                         ent_name = ent_name + ".ent"; //NOI18N
229
}
230                     File JavaDoc desc_ent = new File JavaDoc(ent_name);
231                     desc_ent.delete();
232                     if (targetClustersDefined) {
233                         pw.println("<!DOCTYPE module_updates PUBLIC \"-//NetBeans//DTD Autoupdate Catalog 2.4//EN\" \"http://www.netbeans.org/dtds/autoupdate-catalog-2_4.dtd\" [");
234                     } else {
235                         // #74866: no need for targetcluster, so keep compat w/ 5.0 AU.
236
pw.println("<!DOCTYPE module_updates PUBLIC \"-//NetBeans//DTD Autoupdate Catalog 2.3//EN\" \"http://www.netbeans.org/dtds/autoupdate-catalog-2_3.dtd\" [");
237                     }
238                     // Would be better to follow order of groups and includes
239
pw.println (" <!ENTITY entity SYSTEM \"" + xmlEscape(desc_ent.getName()) + "\">"); //NOI18N
240
int inc_num=0;
241                     for (int i=0; i<entityincludes.size(); i++) {
242                         Entityinclude ei = entityincludes.get(i);
243                         pw.println (" <!ENTITY include" + i + " SYSTEM \"" + xmlEscape(ei.file) + "\">"); //NOI18N
244
}
245                     pw.println ("]>"); //NOI18N
246
pw.println ();
247                     pw.println ("<module_updates timestamp=\"" + xmlEscape(date) + "\">"); //NOI18N
248
pw.println (" &entity;"); //NOI18N
249
for (int i=0; i<entityincludes.size(); i++) {
250                         pw.println (" &include" + i + ";"); //NOI18N
251
}
252                     pw.println ("</module_updates>"); //NOI18N
253
pw.println ();
254                     pw.flush ();
255                     pw.close ();
256                 
257                     os = new FileOutputStream JavaDoc(desc_ent);
258                     pw = new PrintWriter JavaDoc(new OutputStreamWriter JavaDoc(os, "UTF-8")); //NOI18N
259
pw.println ("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"); //NOI18N
260
pw.println ("<!-- external entity include " + date + " -->");
261                     pw.println ();
262                     
263                 } else {
264                     if (targetClustersDefined) {
265                         pw.println("<!DOCTYPE module_updates PUBLIC \"-//NetBeans//DTD Autoupdate Catalog 2.4//EN\" \"http://www.netbeans.org/dtds/autoupdate-catalog-2_4.dtd\">");
266                     } else {
267                         pw.println("<!DOCTYPE module_updates PUBLIC \"-//NetBeans//DTD Autoupdate Catalog 2.3//EN\" \"http://www.netbeans.org/dtds/autoupdate-catalog-2_3.dtd\">");
268                     }
269                     pw.println ("<module_updates timestamp=\"" + date + "\">"); //NOI18N
270
pw.println ();
271                 }
272
273                 pw.println ();
274         Map JavaDoc<String JavaDoc,Element JavaDoc> licenses = new HashMap JavaDoc<String JavaDoc,Element JavaDoc>();
275                 Set<String JavaDoc> licenseNames = new HashSet JavaDoc<String JavaDoc>();
276                 
277                 for (Map.Entry JavaDoc<String JavaDoc,Collection JavaDoc<Module>> entry : modulesByGroup.entrySet()) {
278                     String JavaDoc groupName = entry.getKey();
279                     // Don't indent; embedded descriptions would get indented otherwise.
280
log("Creating group \"" + groupName + "\"");
281                     if (groupName != null) {
282                         pw.println("<module_group name=\"" + xmlEscape(groupName) + "\">");
283                         pw.println();
284                     }
285                     for (Module m : entry.getValue()) {
286                         Element JavaDoc module = m.xml;
287                         if (module.getAttribute("downloadsize").equals("0")) {
288                             module.setAttribute("downloadsize", Long.toString(m.nbm.length()));
289                         }
290                         Element JavaDoc manifest = (Element JavaDoc) module.getElementsByTagName("manifest").item(0);
291                         String JavaDoc name = manifest.getAttribute("OpenIDE-Module-Name");
292                         if (name.length() > 0) {
293                             log(" Adding module " + name + " (" + m.nbm.getAbsolutePath() + ")");
294                         }
295                         if (dist_base != null) {
296                             // fix/enforce distribution URL base
297
String JavaDoc prefix;
298                             if (dist_base.equals(".")) {
299                                 prefix = "";
300                             } else {
301                                 prefix = dist_base + "/";
302                             }
303                             module.setAttribute("distribution", prefix + m.nbm.getName());
304                         }
305                         NodeList JavaDoc licenseList = module.getElementsByTagName("license");
306                         if (licenseList.getLength() > 0) {
307                             Element JavaDoc license = (Element JavaDoc) licenseList.item(0);
308                             // XXX ideally would compare the license texts to make sure they actually match up
309
licenses.put(license.getAttribute("name"), license);
310                             module.removeChild(license);
311                         }
312                         pw.flush();
313                         XMLUtil.write(module, os);
314                         pw.println();
315                     }
316                     if (groupName != null) {
317                         pw.println("</module_group>");
318                         pw.println();
319                     }
320         }
321                 pw.flush();
322                 for (Element JavaDoc license : licenses.values()) {
323                     XMLUtil.write(license, os);
324                 }
325                 if ( entityincludes.size() <= 0 ) {
326                     pw.println ("</module_updates>"); //NOI18N
327
pw.println ();
328                 }
329                 pw.flush ();
330         pw.close ();
331         } finally {
332                 os.flush ();
333         os.close ();
334         }
335     } catch (IOException JavaDoc ioe) {
336         desc.delete ();
337         throw new BuildException("Cannot create update description", ioe, getLocation());
338     }
339     }
340
341     private static class Module {
342         public Module() {}
343         public Element JavaDoc xml;
344         public File JavaDoc nbm;
345     }
346     
347     private Map JavaDoc<String JavaDoc,Collection JavaDoc<Module>> loadNBMs() throws BuildException {
348         final Collator JavaDoc COLL = Collator.getInstance(/* XXX any particular locale? */);
349         // like COLL but handles nulls ~ ungrouped modules (sorted to top):
350
Comparator JavaDoc<String JavaDoc> groupNameComparator = new Comparator JavaDoc<String JavaDoc>() {
351             public int compare(String JavaDoc gn1, String JavaDoc gn2) {
352                 return gn1 != null ?
353                     (gn2 != null ? COLL.compare(gn1, gn2) : 1) :
354                     (gn2 != null ? -1 : 0);
355             }
356         };
357         Map JavaDoc<String JavaDoc,Collection JavaDoc<Module>> r = automaticGrouping ?
358             // generally will be creating groups on the fly, so sort them:
359
new TreeMap JavaDoc<String JavaDoc,Collection JavaDoc<Module>>(groupNameComparator) :
360             // preserve explicit order of <group>s:
361
new LinkedHashMap JavaDoc<String JavaDoc,Collection JavaDoc<Module>>();
362         // sort modules by display name (where available):
363
Comparator JavaDoc<Module> moduleDisplayNameComparator = new Comparator JavaDoc<Module>() {
364             public int compare(Module m1, Module m2) {
365                 int res = COLL.compare(getName(m1), getName(m2));
366                 return res != 0 ? res : System.identityHashCode(m1) - System.identityHashCode(m2);
367             }
368             String JavaDoc getName(Module m) {
369                 Element JavaDoc mani = (Element JavaDoc) m.xml.getElementsByTagName("manifest").item(0);
370                 String JavaDoc displayName = mani.getAttribute("OpenIDE-Module-Name");
371                 if (displayName.length() > 0) {
372                     return displayName;
373                 } else {
374                     return mani.getAttribute("OpenIDE-Module");
375                 }
376             }
377         };
378         for (Group g : groups) {
379             Collection JavaDoc<Module> modules = r.get(g.name);
380             if (modules == null) {
381                 modules = new TreeSet JavaDoc<Module>(moduleDisplayNameComparator);
382                 r.put(g.name, modules);
383             }
384             for (FileSet fs : g.filesets) {
385                 DirectoryScanner ds = fs.getDirectoryScanner(getProject());
386                 for (String JavaDoc file : ds.getIncludedFiles()) {
387                     File JavaDoc n_file = new File JavaDoc(fs.getDir(getProject()), file);
388                     try {
389                         ZipFile JavaDoc zip = new ZipFile JavaDoc(n_file);
390                         try {
391                             ZipEntry JavaDoc entry = zip.getEntry("Info/info.xml");
392                             if (entry == null) {
393                                 throw new BuildException("NBM " + n_file + " was malformed: no Info/info.xml", getLocation());
394                             }
395                             InputStream JavaDoc is = zip.getInputStream(entry);
396                             try {
397                                 Module m = new Module();
398                                 m.xml = XMLUtil.parse(new InputSource JavaDoc(is), false, false, null, new EntityResolver JavaDoc() {
399                                     public InputSource JavaDoc resolveEntity(String JavaDoc publicId, String JavaDoc systemId) throws SAXException JavaDoc, IOException JavaDoc {
400                                         return new InputSource JavaDoc(new ByteArrayInputStream JavaDoc(new byte[0]));
401                                     }
402                                 }).getDocumentElement();
403                                 m.nbm = n_file;
404                                 Collection JavaDoc<Module> target = modules;
405                                 if (automaticGrouping && g.name == null) {
406                                     // insert modules with no explicit grouping into group acc. to manifest:
407
String JavaDoc categ = ((Element JavaDoc) m.xml.getElementsByTagName("manifest").item(0)).getAttribute("OpenIDE-Module-Display-Category");
408                                     if (categ.length() > 0) {
409                                         target = r.get(categ);
410                                         if (target == null) {
411                                             target = new TreeSet JavaDoc<Module>(moduleDisplayNameComparator);
412                                             r.put(categ, target);
413                                         }
414                                     }
415                                 }
416                                 target.add(m);
417                             } finally {
418                                 is.close();
419                             }
420                         } finally {
421                             zip.close();
422                         }
423                     } catch (Exception JavaDoc e) {
424                         throw new BuildException("Cannot access nbm file: " + n_file, e, getLocation());
425                     }
426                 }
427             }
428         }
429         return r;
430     }
431         
432 }
433
Popular Tags