KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > apisupport > project > EditableManifest


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.modules.apisupport.project;
21
22 import java.io.BufferedReader JavaDoc;
23 import java.io.IOException JavaDoc;
24 import java.io.InputStream JavaDoc;
25 import java.io.InputStreamReader JavaDoc;
26 import java.io.OutputStream JavaDoc;
27 import java.io.OutputStreamWriter JavaDoc;
28 import java.io.Writer JavaDoc;
29 import java.util.ArrayList JavaDoc;
30 import java.util.Collections JavaDoc;
31 import java.util.HashSet JavaDoc;
32 import java.util.Iterator JavaDoc;
33 import java.util.LinkedList JavaDoc;
34 import java.util.List JavaDoc;
35 import java.util.Locale JavaDoc;
36 import java.util.Set JavaDoc;
37 import java.util.regex.Matcher JavaDoc;
38 import java.util.regex.Pattern JavaDoc;
39
40 /**
41  * Similar to {@link java.util.jar.Manifest} but preserves all formatting when changes are made.
42  * Methods which take a section name can accept null for the main section.
43  * (This style is in contrast to that used in {@link java.util.jar.Attributes}.
44  * Does not implement esoteric aspects of the manifest spec such as signature recognition
45  * and line wrapping after 72 characters, but does produce output which can be read
46  * by {@link java.util.jar.Manifest} and Ant's <code>&lt;jar&gt;</code> task.
47  * Will not touch the formatting of any line unless you ask to change it, nor
48  * reorder lines, etc., except to correct line endings or insert a final newline.
49  * Newly added sections and attributes are inserted in alphabetical order.
50  * @author Jesse Glick
51  */

52 public final class EditableManifest {
53     
54     private static final String JavaDoc MANIFEST_VERSION = "Manifest-Version"; // NOI18N
55
private static final String JavaDoc MANIFEST_VERSION_VALUE = "1.0"; // NOI18N
56

57     private final Section mainSection;
58     private final List JavaDoc<Section> sections;
59     
60     /**
61      * Creates an almost empty manifest.
62      * Contains just <code>Manifest-Version: 1.0</code>.
63      */

64     public EditableManifest() {
65         try {
66             mainSection = new Section(Collections.singletonList(new Line(MANIFEST_VERSION, MANIFEST_VERSION_VALUE)), true, 1);
67         } catch (IOException JavaDoc e) {
68             throw new AssertionError JavaDoc(e);
69         }
70         sections = new ArrayList JavaDoc();
71     }
72     
73     /**
74      * Creates a manifest object from an existing manifest file.
75      * @param is a stream to load content from (in UTF-8 encoding)
76      * @throws IOException if reading the stream failed, or the contents were syntactically malformed
77      */

78     public EditableManifest(InputStream JavaDoc is) throws IOException JavaDoc {
79         BufferedReader JavaDoc r = new BufferedReader JavaDoc(new InputStreamReader JavaDoc(is, "UTF-8")); // NOI18N
80
sections = new LinkedList JavaDoc();
81         String JavaDoc text;
82         int blankLines = 0;
83         List JavaDoc<Line> lines = new ArrayList JavaDoc();
84         Section _mainSection = null;
85         while (true) {
86             text = r.readLine();
87             if (text == null || (text.length() > 0 && blankLines > 0)) {
88                 Section s = new Section(lines, _mainSection == null, blankLines);
89                 if (_mainSection == null) {
90                     _mainSection = s;
91                 } else {
92                     sections.add(s);
93                 }
94                 lines.clear();
95                 blankLines = 0;
96             }
97             if (text != null) {
98                 if (text.length() > 0) {
99                     Line line;
100                     if (text.charAt(0) == ' ') {
101                         if (lines.isEmpty()) {
102                             throw new IOException JavaDoc("Continuation lines only allowed for attributes"); // NOI18N
103
}
104                         Line prev = (Line) lines.remove(lines.size() - 1);
105                         line = new Line(prev.name, prev.value + text.substring(1), prev.text + System.getProperty("line.separator") + text);
106                     } else {
107                         line = new Line(text);
108                     }
109                     lines.add(line);
110                 } else {
111                     blankLines++;
112                 }
113             } else {
114                 break;
115             }
116         }
117         mainSection = _mainSection;
118         Set JavaDoc<String JavaDoc> names = new HashSet JavaDoc();
119         Iterator JavaDoc it = sections.iterator();
120         while (it.hasNext()) {
121             Section s = (Section) it.next();
122             if (!names.add(s.name)) {
123                 throw new IOException JavaDoc("Duplicated section names: " + s.name); // NOI18N
124
}
125         }
126     }
127     
128     /**
129      * Stores the manifest to a file.
130      * @param os a stream to write content to (in UTF-8 encoding, using platform default line endings)
131      * @throws IOException if writing to the stream failed
132      */

133     public void write(OutputStream JavaDoc os) throws IOException JavaDoc {
134         Writer JavaDoc w = new OutputStreamWriter JavaDoc(os, "UTF-8"); // NOI18N
135
mainSection.write(w, !sections.isEmpty());
136         Iterator JavaDoc it = sections.iterator();
137         while (it.hasNext()) {
138             ((Section) it.next()).write(w, it.hasNext());
139         }
140         w.flush();
141     }
142     
143     /**
144      * Adds a new section.
145      * It will be added in alphabetical order relative to other sections, if they
146      * are already alphabetized.
147      * @param name the new section name
148      * @throws IllegalArgumentException if a section with that name already existed
149      */

150     public void addSection(String JavaDoc name) throws IllegalArgumentException JavaDoc {
151         if (name == null) {
152             throw new IllegalArgumentException JavaDoc();
153         }
154         if (findSection(name) != null) {
155             throw new IllegalArgumentException JavaDoc(name);
156         }
157         int i;
158         for (i = 0; i < sections.size(); i++) {
159             Section s = (Section) sections.get(i);
160             if (s.name.compareTo(name) > 0) {
161                 break;
162             }
163         }
164         sections.add(i, new Section(name));
165     }
166
167     /**
168      * Removes a section.
169      * @param name the section name to delete
170      * @throws IllegalArgumentException if there was no such section
171      */

172     public void removeSection(String JavaDoc name) throws IllegalArgumentException JavaDoc {
173         if (name == null) {
174             throw new IllegalArgumentException JavaDoc();
175         }
176         Iterator JavaDoc it = sections.iterator();
177         while (it.hasNext()) {
178             Section s = (Section) it.next();
179             if (s.name.equals(name)) {
180                 it.remove();
181                 return;
182             }
183         }
184         throw new IllegalArgumentException JavaDoc(name);
185     }
186     
187     /**
188      * Gets a list of all named sections (not including the main section).
189      * @return a list of section names
190      */

191     public Set JavaDoc<String JavaDoc> getSectionNames() {
192         Set JavaDoc<String JavaDoc> names = new HashSet JavaDoc();
193         Iterator JavaDoc it = sections.iterator();
194         while (it.hasNext()) {
195             Section s = (Section) it.next();
196             names.add(s.name);
197         }
198         return names;
199     }
200     
201     private Section findSection(String JavaDoc section) {
202         if (section == null) {
203             return mainSection;
204         } else {
205             Iterator JavaDoc it = sections.iterator();
206             while (it.hasNext()) {
207                 Section s = (Section) it.next();
208                 if (s.name.equals(section)) {
209                     return s;
210                 }
211             }
212             return null;
213         }
214     }
215     
216     /**
217      * Find the value of an attribute.
218      * @param name the attribute name (case-insensitive)
219      * @param section the name of the section to look in, or null for the main section
220      * @return the attribute value, or null if not defined
221      * @throws IllegalArgumentException if the named section does not exist
222      */

223     public String JavaDoc getAttribute(String JavaDoc name, String JavaDoc section) throws IllegalArgumentException JavaDoc {
224         Section s = findSection(section);
225         if (s == null) {
226             throw new IllegalArgumentException JavaDoc(section);
227         }
228         return s.getAttribute(name);
229     }
230     
231     /**
232      * Changes the value of an attribute, or adds the attribute if it does not yet exist.
233      * If it is being added, it will be added in alphabetical order relative to
234      * other attributes in the same section, if they are already alphabetized.
235      * @param name the attribute name (case-insensitive if it already exists)
236      * @param value the new attribute value
237      * @param section the name of the section to add it to, or null for the main section
238      * @throws IllegalArgumentException if the named section does not exist
239      */

240     public void setAttribute(String JavaDoc name, String JavaDoc value, String JavaDoc section) throws IllegalArgumentException JavaDoc {
241         Section s = findSection(section);
242         if (s == null) {
243             throw new IllegalArgumentException JavaDoc(section);
244         }
245         s.setAttribute(name, value);
246     }
247     
248     /**
249      * Removes an attribute.
250      * @param name the attribute name to delete (case-insensitive)
251      * @param section the name of the section to remove it from, or null for the main section
252      * @throws IllegalArgumentException if the named section or attribute do not exist
253      */

254     public void removeAttribute(String JavaDoc name, String JavaDoc section) throws IllegalArgumentException JavaDoc {
255         Section s = findSection(section);
256         if (s == null) {
257             throw new IllegalArgumentException JavaDoc(section);
258         }
259         s.removeAttribute(name);
260     }
261     
262     /**
263      * Gets a list of all attributes.
264      * @param section the name of the section to examine, or null for the main section
265      * @throws IllegalArgumentException if the named section does not exist
266      */

267     public Set JavaDoc<String JavaDoc> getAttributeNames(String JavaDoc section) throws IllegalArgumentException JavaDoc {
268         Section s = findSection(section);
269         if (s == null) {
270             throw new IllegalArgumentException JavaDoc(section);
271         }
272         return s.getAttributeNames();
273     }
274     
275     private static final class Line {
276         
277         private static final Pattern JavaDoc NAME_VALUE = Pattern.compile("([^: ]+) *: *(.*)"); // NOI18N
278

279         public final String JavaDoc text;
280         public final String JavaDoc name;
281         public final String JavaDoc value;
282         
283         public Line(String JavaDoc text) throws IOException JavaDoc {
284             this.text = text;
285             assert text.length() > 0;
286             Matcher JavaDoc m = NAME_VALUE.matcher(text);
287             if (m.matches()) {
288                 name = m.group(1);
289                 value = m.group(2);
290             } else {
291                 throw new IOException JavaDoc("Malformed line: " + text); // NOI18N
292
}
293         }
294         
295         public Line(String JavaDoc name, String JavaDoc value) {
296             this(name, value, name + ": " + value); // NOI18N
297
}
298         
299         public Line(String JavaDoc name, String JavaDoc value, String JavaDoc text) {
300             this.name = name;
301             this.value = value;
302             this.text = text;
303         }
304         
305         public void write(Writer JavaDoc w) throws IOException JavaDoc {
306             w.write(text);
307             newline(w);
308         }
309         
310     }
311     
312     private static void newline(Writer JavaDoc w) throws IOException JavaDoc {
313         w.write(System.getProperty("line.separator")); // NOI18N
314
}
315     
316     private static final class Section {
317         
318         private static final String JavaDoc NAME = "Name"; // NOI18N
319

320         public final String JavaDoc name;
321         private final List JavaDoc<Line> lines;
322         private final int blankLinesAfter;
323         
324         public Section(List JavaDoc<Line> lines, boolean main, int blankLinesAfter) throws IOException JavaDoc {
325             this.lines = new ArrayList JavaDoc(lines);
326             this.blankLinesAfter = blankLinesAfter;
327             if (main) {
328                 name = null;
329                 if (!lines.isEmpty()) {
330                     Line first = (Line) lines.get(0);
331                     if (first.name.equalsIgnoreCase(NAME)) {
332                         throw new IOException JavaDoc("Cannot start with a named section"); // NOI18N
333
}
334                 }
335             } else {
336                 assert !lines.isEmpty();
337                 Line first = (Line) lines.get(0);
338                 if (!first.name.equalsIgnoreCase(NAME)) {
339                     throw new IOException JavaDoc("Section did not start with " + NAME); // NOI18N
340
}
341                 name = first.value;
342                 if (name.length() == 0) {
343                     throw new IOException JavaDoc("Cannot have a blank section name"); // NOI18N
344
}
345             }
346             Set JavaDoc<String JavaDoc> attrNames = new HashSet JavaDoc();
347             Iterator JavaDoc it = lines.iterator();
348             if (!main) {
349                 it.next();
350             }
351             while (it.hasNext()) {
352                 String JavaDoc name = ((Line) it.next()).name;
353                 if (name.equals(NAME)) {
354                     throw new IOException JavaDoc("Sections not separated by blank lines"); // NOI18N
355
} else if (!attrNames.add(name.toLowerCase(Locale.US))) {
356                     throw new IOException JavaDoc("Duplicated attributes in a section: " + name); // NOI18N
357
}
358             }
359         }
360         
361         public Section(String JavaDoc name) {
362             this.name = name;
363             lines = new ArrayList JavaDoc();
364             lines.add(new Line(NAME, name)); // NOI18N
365
blankLinesAfter = 1;
366         }
367         
368         private Line findAttribute(String JavaDoc name) {
369             Iterator JavaDoc it = lines.iterator();
370             if (this.name != null) {
371                 it.next();
372             }
373             while (it.hasNext()) {
374                 Line line = (Line) it.next();
375                 if (line.name.equalsIgnoreCase(name)) {
376                     return line;
377                 }
378             }
379             return null;
380         }
381         
382         private int findAttributeIndex(String JavaDoc name) {
383             for (int i = (this.name != null ? 1 : 0); i < lines.size(); i++) {
384                 Line line = (Line) lines.get(i);
385                 if (line.name.equalsIgnoreCase(name)) {
386                     return i;
387                 }
388             }
389             return -1;
390         }
391         
392         public String JavaDoc getAttribute(String JavaDoc name) {
393             Line line = findAttribute(name);
394             if (line != null) {
395                 return line.value;
396             } else {
397                 return null;
398             }
399         }
400         
401         public void setAttribute(String JavaDoc name, String JavaDoc value) {
402             for (int i = (this.name != null ? 1 : 0); i < lines.size(); i++) {
403                 Line line = (Line) lines.get(i);
404                 if (name.equalsIgnoreCase(line.name)) {
405                     if (line.value.equals(value)) {
406                         // No change, leave alone to preserve formatting.
407
return;
408                     }
409                     // Edit this line.
410
lines.remove(i);
411                     int insertionPoint = name.equalsIgnoreCase(MANIFEST_VERSION) ? 0 : i;
412                     lines.add(insertionPoint, new Line(name, value));
413                     return;
414                 }
415             }
416             // Didn't find an existing line. Look for the right place to insert this one.
417
int insertionPoint;
418             if (name.equalsIgnoreCase(MANIFEST_VERSION)) {
419                 insertionPoint = 0;
420             } else {
421                 insertionPoint = lines.size();
422                 for (int i = (this.name != null ? 1 : 0); i < lines.size(); i++) {
423                     Line line = (Line) lines.get(i);
424                     int comp = line.name.compareToIgnoreCase(name);
425                     assert comp != 0;
426                     if (comp > 0 && !line.name.equalsIgnoreCase(MANIFEST_VERSION)) {
427                         insertionPoint = i;
428                         break;
429                     }
430                 }
431             }
432             lines.add(insertionPoint, new Line(name, value));
433         }
434         
435         public void removeAttribute(String JavaDoc name) throws IllegalArgumentException JavaDoc {
436             int i = findAttributeIndex(name);
437             if (i != -1) {
438                 lines.remove(i);
439             } else {
440                 throw new IllegalArgumentException JavaDoc(name);
441             }
442         }
443         
444         public Set JavaDoc<String JavaDoc> getAttributeNames() {
445             Set JavaDoc<String JavaDoc> attrNames = new HashSet JavaDoc();
446             Iterator JavaDoc it = lines.iterator();
447             if (name != null) {
448                 it.next();
449             }
450             while (it.hasNext()) {
451                 attrNames.add(((Line) it.next()).name);
452             }
453             return attrNames;
454         }
455         
456         public void write(Writer JavaDoc w, boolean forceBlankLine) throws IOException JavaDoc {
457             Iterator JavaDoc it = lines.iterator();
458             while (it.hasNext()) {
459                 Line line = (Line) it.next();
460                 line.write(w);
461             }
462             for (int i = 0; i < blankLinesAfter; i++) {
463                 newline(w);
464             }
465             if (forceBlankLine && blankLinesAfter == 0) {
466                 newline(w);
467             }
468         }
469         
470     }
471     
472 }
473
Popular Tags