KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sourceforge > jarbundler > JarBundler


1 /*
2  * A Mac OS X Jar Bundler Ant Task.
3  *
4  * Copyright (c) 2003, Seth J. Morabito <sethm@loomcom.com> All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the Free
8  * Software Foundation; either version 2 of the License, or (at your option)
9  * any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along with
17  * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
18  * Place - Suite 330, Boston, MA 02111-1307, USA.
19  */

20
21 package net.sourceforge.jarbundler;
22
23 // This package's imports
24
import net.sourceforge.jarbundler.AppBundleProperties;
25 import net.sourceforge.jarbundler.DocumentType;
26 import net.sourceforge.jarbundler.JavaProperty;
27 import net.sourceforge.jarbundler.PropertyListWriter;
28
29 // Java I/O
30
import java.io.BufferedWriter JavaDoc;
31 import java.io.BufferedReader JavaDoc;
32 import java.io.File JavaDoc;
33 import java.io.FileWriter JavaDoc;
34 import java.io.FileReader JavaDoc;
35 import java.io.IOException JavaDoc;
36 import java.io.InputStream JavaDoc;
37 import java.io.PrintWriter JavaDoc;
38
39 // Java Utility
40
import java.util.ArrayList JavaDoc;
41 import java.util.HashSet JavaDoc;
42 import java.util.Iterator JavaDoc;
43 import java.util.List JavaDoc;
44 import java.util.Set JavaDoc;
45
46 // Apache Jakarta
47
import org.apache.tools.ant.BuildException;
48 import org.apache.tools.ant.FileScanner;
49 import org.apache.tools.ant.Project;
50 import org.apache.tools.ant.Task;
51
52 import org.apache.tools.ant.types.FileList;
53 import org.apache.tools.ant.types.FileSet;
54 import org.apache.tools.ant.types.PatternSet;
55
56 import org.apache.tools.ant.taskdefs.MatchingTask;
57 import org.apache.tools.ant.taskdefs.Chmod;
58 import org.apache.tools.ant.taskdefs.Delete;
59
60 import org.apache.tools.ant.util.FileUtils;
61
62
63 // Java language imports
64
import java.lang.Boolean JavaDoc;
65 import java.lang.Process JavaDoc;
66 import java.lang.Runtime JavaDoc;
67 import java.lang.String JavaDoc;
68 import java.lang.System JavaDoc;
69
70 /**
71  * <p>
72  * An ant task which creates a Mac OS X Application Bundle for a Java
73  * application.
74  * </p>
75  *
76  * <dl>
77  * <dt>dir</dt>
78  * <dd>The directory into which to put the new application bundle.</dd>
79  * <dt>name</dt>
80  * <dd>The name of the application bundle. Note that the maximum length of this
81  * name is 16 characters, and it will be silently cropped if it is longer than
82  * this.</dd>
83  * <dt>mainclass</dt>
84  * <dd>The main Java class to call when running the application.</dd>
85  * </dl>
86  *
87  * <p>
88  * One of the following three MUST be used:
89  *
90  * <ol>
91  * <li>jars Space or comma-separated list of JAR files to include.; OR</li>
92  * <li>One or more nested &lt;jarfileset&gt;s. These are normal ANT FileSets;
93  * OR </li>
94  * <li>One or more nested &lt;jarfilelist&gt;s. These are standard ANT
95  * FileLists. </li>
96  * </ol>
97  *
98  * <p>
99  * Optional attributes:
100  *
101  * <p>
102  * The following attributes are not required, but you can use them to override
103  * default behavior.
104  *
105  * <dl>
106  * <dt>verbose
107  * <dd>If true, show more verbose output while running the task
108  *
109  * <dt>version
110  * <dd>Version information about your application (e.g., "1.0")
111  *
112  * <dt>infostring
113  * <dd>String to show in the "Get Info" dialog
114  * </dl>
115  *
116  * These attributes control the fine-tuning of the "Mac OS X" look and feel.
117  *
118  * <dl>
119  * <dt>arguments
120  * <dd>Command line arguments. (no default)
121  *
122  * <dt>smalltabs
123  * <dd>Use small tabs. (default "false") Deprecated under JVM 1.4.1
124  *
125  * <dt>antialiasedgraphics
126  * <dd>Use anti-aliased graphics (default "false")
127  *
128  * <dt>antialiasedtext
129  * <dd>Use anti-aliased text (default "false")
130  *
131  * <dt>bundleid
132  * <dd>Unique identifier for this bundle, in the form of a Java package. No
133  * default.
134  *
135  * <dt>buildnumber
136  * <dd>Unique identifier for this build
137  *
138  * <dt>developmentregion
139  * <dd>Development Region. Default "English".
140  *
141  * <dt>execs
142  * <dd>Files to be copied into "Resources/MacOS" and made executable
143  *
144  * <dt>liveresize
145  * <dd>Use "Live resizing" (default "false") Deprecated under JVM 1.4.1
146  *
147  *
148  * <dt>growbox
149  * <dd>Show growbox (default "true")
150  *
151  * <dt>growboxintrudes
152  * <dd>Intruding growbox (default "false") Deprecated under JVM 1.4.1
153  *
154  * <dt>screenmenu
155  * <dd>Put swing menu into Mac OS X menu bar.
156  *
157  * <dt>type
158  * <dd>Bundle type (default "APPL")
159  *
160  * <dt>signature
161  * <dd>Bundle Signature (default "????")
162  *
163  * <dt>stubfile
164  * <dd>The Java Application Stub file to copy for your application (default
165  * MacOS system stub file)
166  * </dl>
167  *
168  * <p>
169  * Rarely used optional attributes.
170  * <dl>
171  * <dt>chmod
172  * <dd>Full path to the chmod command. This almost certainly does NOT need to
173  * be set.
174  * </dl>
175  *
176  * <p>
177  * The task also supports nested &lt;execfileset&gt; and/or &lt;execfilelist&gt;
178  * elements, and &lt;resourcefileset&gt; and/or &lt;resourcefilelist&gt;
179  * elements, which are standard Ant FileSet and FileList elements. In the first
180  * case, the referenced files are copied to the <code>Contents/MacOS</code>
181  * directory and made executable, and in the second they are copied to the
182  * <code>Contents/Resources</code> directory and not made executable. If you
183  * winrces, note that in fact the files are installed in locations which have
184  * the same relation to the <code>Contents/Resources</code> directory as the
185  * files in the FileSet or FileList have to the 'dir' attribute. Thus in the
186  * case:
187  *
188  * <pre>
189  * &lt;resourcefileset dir=&quot;builddir/architectures&quot;
190  * includes=&quot;ppc/*.jnilib&quot;/&gt;
191  * </pre>
192  *
193  * <p>
194  * the <code>*.jnilib</code> files will be installed in
195  * <code>Contents/Resources/ppc</code>.
196  *
197  * <p>
198  * The task supports a nested &lt;javaproperty&gt; element, which allows you to
199  * specify further properties which are set for the JVM when the application is
200  * launched. This takes a required <code>key</code> attribute, giving the
201  * property key, plus an attribute giving the property value, which may be one
202  * of <code>value</code>, giving the string value of the property,
203  * <code>file</code>, setting the value of the property to be the absolute
204  * path of the given file, or <code>path</code>, which sets the value to the
205  * given path. If you are setting paths here, recall that, within the bundle,
206  * <code>$APP_PACKAGE</code> is set to the root directory of the bundle (ie,
207  * the path to the <code>foo.app</code> directory), and <code>$JAVAROOT</code>
208  * to the directory <code>Contents/Resources/Java</code>.
209  *
210  * <p>
211  * Minimum example:
212  *
213  * <pre>
214  *
215  * &lt;jarbundler dir=&quot;release&quot; name=&quot;Bar Project&quot; mainclass=&quot;org.bar.Main&quot;
216  * jars=&quot;bin/Bar.jar&quot; /&gt;
217  * </pre>
218  *
219  * <p>
220  * Using Filesets
221  *
222  * <pre>
223  * &lt;jarbundler dir=&quot;release&quot; name=&quot;Bar Project&quot; mainclass=&quot;org.bar.Main&quot;&gt;
224  * &lt;jarfileset dir=&quot;bin&quot;&gt;
225  * &lt;include name=&quot;*.jar&quot; /&gt;
226  * &lt;exclude name=&quot;test.jar&quot; /&gt;
227  * &lt;/jarfileset&gt;
228  * &lt;execfileset dir=&quot;execs&quot;&gt;
229  * &lt;include name=&quot;**&quot; /&gt;
230  * &lt;/execfileset&gt;
231  * &lt;/jarbundler&gt;
232  * </pre>
233  *
234  * <p>
235  * Much Longer example:
236  * </p>
237  *
238  * <pre>
239  * &lt;jarbundler dir=&quot;release&quot;
240  * name=&quot;Foo Project&quot;
241  * mainclass=&quot;org.bar.Main&quot;
242  * version=&quot;1.0 b 1&quot;
243  * infostring=&quot;Foo Project (c) 2002&quot;
244  * type=&quot;APPL&quot;
245  * jars=&quot;bin/foo.jar bin/bar.jar&quot;
246  * execs=&quot;exec/foobar&quot;
247  * signature=&quot;????&quot;
248  * workingdirectory=&quot;temp&quot;
249  * icon=&quot;resources/foo.icns&quot;
250  * jvmversion=&quot;1.4.1+&quot;
251  * vmoptions=&quot;-Xmx256m&quot;/&gt;
252  * </pre>
253  *
254  * http://developer.apple.com/documentation/MacOSX/Conceptual/BPRuntimeConfig/
255  */

256 public class JarBundler extends MatchingTask {
257
258     private static final String JavaDoc DEFAULT_STUB = "/System/Library/Frameworks/JavaVM.framework/Versions/Current/Resources/MacOS/JavaApplicationStub";
259
260     private static final String JavaDoc ABOUTMENU_KEY = "com.apple.mrj.application.apple.menu.about.name";
261     private static final Set JavaDoc menuItems = new HashSet JavaDoc();
262     private File JavaDoc mAppIcon;
263
264     private File JavaDoc mRootDir;
265
266     private final List JavaDoc mJavaFileLists = new ArrayList JavaDoc();
267     private final List JavaDoc mJarFileSets = new ArrayList JavaDoc();
268
269     private final List JavaDoc mExecFileLists = new ArrayList JavaDoc();
270     private final List JavaDoc mExecFileSets = new ArrayList JavaDoc();
271
272     private final List JavaDoc mResourceFileLists = new ArrayList JavaDoc();
273     private final List JavaDoc mResourceFileSets = new ArrayList JavaDoc();
274
275     private final List JavaDoc mJarFileLists = new ArrayList JavaDoc();
276     private final List JavaDoc mJavaFileSets = new ArrayList JavaDoc();
277
278     private final List JavaDoc mExtraClassPathFileLists = new ArrayList JavaDoc();
279     private final List JavaDoc mExtraClassPathFileSets = new ArrayList JavaDoc();
280
281     private final List JavaDoc mJarAttrs = new ArrayList JavaDoc();
282
283     private final List JavaDoc mExecAttrs = new ArrayList JavaDoc();
284
285     private final List JavaDoc mExtraClassPathAttrs = new ArrayList JavaDoc();
286     
287     private final List JavaDoc mHelpBooks = new ArrayList JavaDoc();
288
289     private boolean mVerbose = false;
290     private boolean mShowPlist = false;
291
292     // Java properties used by Mac OS X Java applications
293

294     private File JavaDoc mStubFile = new File JavaDoc(DEFAULT_STUB);
295
296     private Boolean JavaDoc mAntiAliasedGraphics = null;
297
298     private Boolean JavaDoc mAntiAliasedText = null;
299
300     private Boolean JavaDoc mLiveResize = null;
301
302     private Boolean JavaDoc mScreenMenuBar = null;
303
304     private Boolean JavaDoc mGrowbox = null;
305
306     private Boolean JavaDoc mGrowboxIntrudes = null;
307
308     // The root of the application bundle
309
private File JavaDoc bundleDir;
310
311     // "Contents" directory
312
private File JavaDoc mContentsDir;
313
314     // "Contents/MacOS" directory
315
private File JavaDoc mMacOsDir;
316
317     // "Contents/Resources" directory
318
private File JavaDoc mResourcesDir;
319
320     // "Contents/Resources/Java" directory
321
private File JavaDoc mJavaDir;
322
323     // Full path to the 'chmod' command. Can be overridden
324
// with the 'chmod' attribute. Won't cause any harm if
325
// not set, or if this executable doesn't exist.
326

327
328     private AppBundleProperties bundleProperties = new AppBundleProperties();
329
330     // Ant file utilities
331

332     private FileUtils mFileUtils = FileUtils.getFileUtils();
333
334     /***************************************************************************
335      * Retreive task attributes
336      **************************************************************************/

337
338     /**
339      * Arguments to the
340      *
341      * @param s
342      * The arguments to pass to the application being launched.
343      */

344     public void setArguments(String JavaDoc s) {
345         bundleProperties.setArguments(s);
346     }
347
348     /**
349      * Override the stub file path to build on non-MacOS platforms
350      *
351      * @param file
352      * the path to the stub file
353      */

354     public void setStubFile(File JavaDoc file) {
355         mStubFile = (file.exists()) ? file : new File JavaDoc(DEFAULT_STUB);
356         bundleProperties.setCFBundleExecutable(file.getName());
357     }
358
359     /**
360      * Setter for the "dir" attribute (required)
361      */

362     public void setDir(File JavaDoc f) {
363         mRootDir = f;
364     }
365
366     /**
367      * Setter for the "name" attribute (required) This attribute names the
368      * output application bundle and asks as the CFBundleName if 'bundlename' is
369      * not specified
370      */

371     public void setName(String JavaDoc s) {
372         bundleProperties.setApplicationName(s);
373     }
374
375     /**
376      * Setter for the "shortname" attribute (optional) This key identifies the
377      * short name of the bundle. This name should be less than 16 characters
378      * long and be suitable for displaying in the menu and the About box. The
379      * name is (silently) cropped to this if necessary.
380      */

381     public void setShortName(String JavaDoc s) {
382         bundleProperties.setCFBundleName(s);
383     }
384
385     /**
386      * Setter for the "mainclass" attribute (required)
387      */

388     public void setMainClass(String JavaDoc s) {
389         bundleProperties.setMainClass(s);
390     }
391
392     /**
393      * Setter for the "WorkingDirectory" attribute (optional)
394      */

395     public void setWorkingDirectory(String JavaDoc s) {
396         bundleProperties.setWorkingDirectory(s);
397     }
398
399     /**
400      * Setter for the "icon" attribute (optional)
401      */

402
403     public void setIcon(File JavaDoc f) {
404         mAppIcon = f;
405         bundleProperties.setCFBundleIconFile(f.getName());
406     }
407
408     /**
409      * Setter for the "bundleid" attribute (optional) This key specifies a
410      * unique identifier string for the bundle. This identifier should be in the
411      * form of a Java-style package name, for example com.mycompany.myapp. The
412      * bundle identifier can be used to locate the bundle at runtime. The
413      * preferences system uses this string to identify applications uniquely.
414      *
415      * No default.
416      */

417     public void setBundleid(String JavaDoc s) {
418         bundleProperties.setCFBundleIdentifier(s);
419     }
420
421     /**
422      * Setter for the "developmentregion" attribute(optional) Default "English".
423      */

424     public void setDevelopmentregion(String JavaDoc s) {
425         bundleProperties.setCFBundleDevelopmentRegion(s);
426     }
427
428     /**
429      * Setter for the "aboutmenuname" attribute (optional)
430      */

431     public void setAboutmenuname(String JavaDoc s) {
432         bundleProperties.setCFBundleName(s);
433     }
434
435     /**
436      * Setter for the "smalltabs" attribute (optional)
437      */

438     public void setSmallTabs(boolean b) {
439         bundleProperties.addJavaProperty("com.apple.smallTabs", new Boolean JavaDoc(b)
440                 .toString());
441     }
442
443     /**
444      * Setter for the "vmoptions" attribute (optional)
445      */

446     public void setVmoptions(String JavaDoc s) {
447         bundleProperties.setVMOptions(s);
448     }
449
450     /**
451      * Setter for the "antialiasedgraphics" attribute (optional)
452      */

453     public void setAntialiasedgraphics(boolean b) {
454         mAntiAliasedGraphics = new Boolean JavaDoc(b);
455     }
456
457     /**
458      * Setter for the "antialiasedtext" attribute (optional)
459      */

460     public void setAntialiasedtext(boolean b) {
461         mAntiAliasedText = new Boolean JavaDoc(b);
462     }
463
464     /**
465      * Setter for the "screenmenu" attribute (optional)
466      */

467     public void setScreenmenu(boolean b) {
468         mScreenMenuBar = new Boolean JavaDoc(b);
469     }
470
471     /**
472      * Setter for the "growbox" attribute (optional)
473      */

474     public void setGrowbox(boolean b) {
475         mGrowbox = new Boolean JavaDoc(b);
476     }
477
478     /**
479      * Setter for the "growboxintrudes" attribute (optional)
480      */

481     public void setGrowboxintrudes(boolean b) {
482         mGrowboxIntrudes = new Boolean JavaDoc(b);
483     }
484
485     /**
486      * Setter for the "liveresize" attribute (optional)
487      */

488     public void setLiveresize(boolean b) {
489         mLiveResize = new Boolean JavaDoc(b);
490     }
491
492     /**
493      * Setter for the "type" attribute (optional)
494      */

495     public void setType(String JavaDoc s) {
496         bundleProperties.setCFBundlePackageType(s);
497     }
498
499     /**
500      * Setter for the "signature" attribute (optional)
501      */

502     public void setSignature(String JavaDoc s) {
503         bundleProperties.setCFBundleSignature(s);
504     }
505
506     /**
507      * Setter for the "jvmversion" attribute (optional)
508      */

509     public void setJvmversion(String JavaDoc s) {
510         bundleProperties.setJVMVersion(s);
511     }
512
513     /**
514      * Setter for the "infostring" attribute (optional) This key identifies a
515      * human-readable plain text string displaying the copyright information for
516      * the bundle. The Finder displays this information in the Info window of
517      * the bundle. (This string was also known as the long version string in Mac
518      * OS 9). The format of the key should be of the following format: "&copy;
519      * Great Software, Inc, 1999". You can localize this string by including it
520      * in the InfoPlist.strings file of the appropriate .lproj directory.
521      */

522
523     public void setInfoString(String JavaDoc s) {
524         bundleProperties.setCFBundleGetInfoString(s);
525     }
526
527     /**
528      * Setter for the "shortinfostring" attribute (optional) This key identifies
529      * the marketing version of the bundle. The marketing version is a string
530      * that usually displays the major and minor version of the bundle. This
531      * string is usually of the form n.n.n where n is a number. The first number
532      * is the major version number of the bundle. The second and third numbers
533      * are minor revision numbers. You may omit minor revision numbers as
534      * appropriate. The value of this key is displayed in the default About box
535      * for Cocoa applications.
536      *
537      * The value for this key differs from the value for "CFBundleVersion",
538      * which identifies a specific build number. The CFBundleShortVersionString
539      * value represents a more formal version that does not change with every
540      * build.
541      */

542     public void setShortInfoString(String JavaDoc s) {
543         setVersion(s);
544     }
545
546     /**
547      * Setter for the "verbose" attribute (optional)
548      */

549     public void setVerbose(boolean verbose) {
550         this.mVerbose = verbose;
551     }
552     public void setShowPlist(boolean showPlist) {
553         this.mShowPlist = showPlist;
554     }
555
556
557
558
559     /**
560      * Setter for the "buildnumber" attribute (optional) This key specifies the
561      * exact build version of the bundle. This string is usually of the form
562      * nn.n.nxnnn where n is a digit and x is a character from the set [abdf].
563      * The first number is the major version number of the bundle and can
564      * contain one or two digits to represent a number in the range 0-99. The
565      * second and third numbers are minor revision numbers and must be a single
566      * numeric digit. The fourth set of digits is the specific build number for
567      * the release.
568      *
569      * You may omit minor revision and build number information as appropriate.
570      * You may also omit major and minor revision information and specify only a
571      * build number. For example, valid version numbers include: 1.0.1,
572      * 1.2.1b10, 1.2d200, d125, 101, and 1.0.
573      *
574      * The value of this key typically changes between builds and is displayed
575      * in the Cocoa About panel in parenthesis. To specify the version
576      * information of a released bundle, use the CFBundleShortVersionString key.
577      */

578     public void setBuild(String JavaDoc s) {
579         bundleProperties.setCFBundleVersion(s);
580     }
581
582     /**
583      * Setter for the version attribute (optional). It is this property, not
584      * CFBundleVersion, which should receive the `short' version string. See for
585      * example
586      * <http://developer.apple.com/documentation/MacOSX/Conceptual/BPRuntimeConfig/>
587      */

588     public void setVersion(String JavaDoc s) {
589         bundleProperties.setCFBundleShortVersionString(s);
590     }
591
592     public void setHelpBookFolder(String JavaDoc s) {
593         bundleProperties.setCFBundleHelpBookFolder(s);
594     }
595
596     public void setHelpBookName(String JavaDoc s) {
597         bundleProperties.setCFBundleHelpBookName(s);
598     }
599
600     /**
601      * Setter for the "jars" attribute (required if no "jarfileset" is present)
602      */

603     public void setJars(String JavaDoc s) {
604         PatternSet patset = new PatternSet();
605         patset.setIncludes(s);
606
607         String JavaDoc[] jarNames = patset.getIncludePatterns(getProject());
608
609         for (int i = 0; i < jarNames.length; i++)
610             mJarAttrs.add(getProject().resolveFile(jarNames[i]));
611     }
612
613     /**
614      * Setter for the "jar" attribute (required if no "jarfileset" is present)
615      */

616     public void setJar(File JavaDoc s) {
617         mJarAttrs.add(s);
618     }
619
620     /**
621      * Setter for the "execs" attribute (optional)
622      */

623     public void setExecs(String JavaDoc s) {
624         PatternSet patset = new PatternSet();
625         patset.setIncludes(s);
626
627         String JavaDoc[] execNames = patset.getIncludePatterns(getProject());
628
629         for (int i = 0; i < execNames.length; i++) {
630             File JavaDoc f = new File JavaDoc(execNames[i]);
631             mExecAttrs.add(f);
632         }
633     }
634
635     /**
636      * Setter for the "extraclasspath" attribute (optional)
637      */

638     public void setExtraclasspath(String JavaDoc s) {
639         PatternSet patset = new PatternSet();
640         patset.setIncludes(s);
641
642         String JavaDoc[] cpNames = patset.getIncludePatterns(getProject());
643
644         for (int i = 0; i < cpNames.length; i++) {
645             File JavaDoc f = new File JavaDoc(cpNames[i]);
646             mExtraClassPathAttrs.add(f);
647         }
648     }
649
650     /**
651      * Set the 'chmod' executable.
652      */

653     public void setChmod(String JavaDoc s) {
654         log("The \"chmod\" attribute has deprecaited, using the ANT Chmod task internally");
655     }
656
657     /***************************************************************************
658      * Nested tasks - derived from FileList and FileSet
659      **************************************************************************/

660
661     public void addJarfileset(FileSet fs) {
662         mJarFileSets.add(fs);
663     }
664
665     public void addJarfilelist(FileList fl) {
666         mJarFileLists.add(fl);
667     }
668
669     public void addExecfileset(FileSet fs) {
670         mExecFileSets.add(fs);
671     }
672
673     public void addExecfilelist(FileList fl) {
674         mExecFileLists.add(fl);
675     }
676
677     public void addResourcefileset(FileSet fs) {
678         mResourceFileSets.add(fs);
679     }
680
681     public void addResourcefilelist(FileList fl) {
682         mResourceFileLists.add(fl);
683     }
684
685     public void addJavafileset(FileSet fs) {
686         mJavaFileSets.add(fs);
687     }
688
689     public void addJavafilelist(FileList fl) {
690         mJavaFileLists.add(fl);
691     }
692
693     public void addExtraclasspathfileset(FileSet fs) {
694         mExtraClassPathFileSets.add(fs);
695     }
696
697     public void addExtraclasspathfilelist(FileList fl) {
698         mExtraClassPathFileLists.add(fl);
699     }
700
701
702     /***************************************************************************
703      * Nested tasks - new tasks with custom attributes
704      **************************************************************************/

705
706
707     public void addConfiguredJavaProperty(JavaProperty javaProperty)
708             throws BuildException {
709
710         String JavaDoc name = javaProperty.getName();
711         String JavaDoc value = javaProperty.getValue();
712
713         if ((name == null) || (value == null))
714             throw new BuildException(
715                     "'<javaproperty>' must have both 'name' and 'value' attibutes");
716
717         bundleProperties.addJavaProperty(name, value);
718     }
719
720     public void addConfiguredDocumentType(DocumentType documentType) throws BuildException {
721
722         String JavaDoc name = documentType.getName();
723         String JavaDoc role = documentType.getRole();
724         List JavaDoc osTypes = documentType.getOSTypes();
725         List JavaDoc extensions = documentType.getExtensions();
726         List JavaDoc mimeTypes = documentType.getMimeTypes();
727
728         if ((name == null) || (role == null))
729             throw new BuildException(
730                     "'<documenttype>' must have both a 'name' and a 'role' attibute");
731
732         if ((osTypes.isEmpty()) && (extensions.isEmpty()) && (mimeTypes.isEmpty()))
733             throw new BuildException(
734                     "'<documenttype>' of \""
735                             + name
736                             + "\" must have 'osTypes' or 'extensions' or 'mimeTypes'");
737
738         bundleProperties.addDocumentType(documentType);
739     }
740
741     public void addConfiguredService(Service service) {
742     
743         //if (service.getPortName() == null)
744
// throw new BuildException("\"<service>\" must have a \"portName\" attribute");
745

746         if (service.getMessage() == null)
747             throw new BuildException("\"<service>\" must have a \"message\" attribute");
748         
749         String JavaDoc menuItem = service.getMenuItem();
750         if (menuItem == null)
751             throw new BuildException("\"<service>\" must have a \"menuItem\" attribute");
752         if (!menuItems.add(menuItem))
753             throw new BuildException("\"<service>\" \"menuItem\" value must be unique");
754         
755         if (service.getSendTypes().isEmpty() && service.getReturnTypes().isEmpty())
756             throw new BuildException("\"<service>\" must have either a \"sendTypes\" attribute, a \"returnTypes\" attribute or both");
757         
758         String JavaDoc keyEquivalent = service.getKeyEquivalent();
759         if ((keyEquivalent != null) && (1 != keyEquivalent.length()))
760             throw new BuildException("\"<service>\" \"keyEquivalent\" must be one character if present");
761         
762         String JavaDoc timeoutString = service.getTimeout();
763         if (timeoutString != null) {
764             long timeout = -1;
765             try {
766                 timeout = Long.parseLong(timeoutString);
767             } catch (NumberFormatException JavaDoc nfe) {
768                 throw new BuildException("\"<service>\" \"timeout\" must be a positive integral number");
769             }
770             if (timeout < 0)
771                 throw new BuildException("\"<service>\" \"timeout\" must not be negative");
772         }
773         
774         bundleProperties.addService(service);
775     }
776     
777     public void addConfiguredHelpBook(HelpBook helpBook) {
778     
779         // Validity check on 'foldername'
780
if (helpBook.getFolderName() == null) {
781             if (bundleProperties.getCFBundleHelpBookFolder() == null)
782                 throw new BuildException("Either the '<helpbook>' attribute 'foldername' or the '<jarbundler>' attribute 'helpbookfolder' must be defined");
783             helpBook.setFolderName(bundleProperties.getCFBundleHelpBookFolder());
784         }
785
786         // Validity check on 'title'
787
if (helpBook.getName() == null) {
788             if (bundleProperties.getCFBundleHelpBookName() == null)
789                 throw new BuildException("Either the '<helpbook>' attribute 'name' or the '<jarbundler>' attribute 'helpbookname' must be defined");
790             helpBook.setName(bundleProperties.getCFBundleHelpBookName());
791         }
792
793         // Make sure some file were selected...
794
List JavaDoc fileLists = helpBook.getFileLists();
795         List JavaDoc fileSets = helpBook.getFileSets();
796
797         if ( fileLists.isEmpty() && fileSets.isEmpty() )
798             throw new BuildException("The '<helpbook>' task must have either " +
799                                      "'<fileset>' or '<filelist>' nested tags");
800
801
802         mHelpBooks.add(helpBook);
803     }
804
805
806
807     /***************************************************************************
808      * Execute the task
809      **************************************************************************/

810
811     /**
812      * The method executing the task
813      */

814
815     public void execute() throws BuildException {
816
817         // Delete any existing Application bundle directory structure
818

819         bundleDir = new File JavaDoc(mRootDir, bundleProperties.getApplicationName() + ".app");
820
821         if (bundleDir.exists()) {
822             Delete deleteTask = new Delete();
823             deleteTask.setProject(getProject());
824             deleteTask.setDir(bundleDir);
825             deleteTask.execute();
826         }
827
828         // Validate - look for required attributes
829
// ///////////////////////////////////////////
830

831         if (mRootDir == null)
832             throw new BuildException("Required attribute \"dir\" is not set.");
833
834         if (mJarAttrs.isEmpty() && mJarFileSets.isEmpty()
835                 && mJarFileLists.isEmpty())
836             throw new BuildException("Either the attribute \"jar\" must "
837                     + "be set, or one or more jarfilelists or "
838                     + "jarfilesets must be added.");
839
840         if (!mJarAttrs.isEmpty()
841                 && (!mJarFileSets.isEmpty() || !mJarFileLists.isEmpty()))
842             throw new BuildException(
843                     "Cannot set both the attribute "
844                             + "\"jars\" and use jar filesets/filelists. Use only one or the other.");
845
846         if (bundleProperties.getApplicationName() == null)
847             throw new BuildException("Required attribute \"name\" is not set.");
848
849         if (bundleProperties.getMainClass() == null)
850             throw new BuildException(
851                     "Required attribute \"mainclass\" is not set.");
852
853         // /////////////////////////////////////////////////////////////////////////////////////
854

855         // Set up some Java properties
856

857         // About Menu, deprecated under 1.4+
858
if (useOldPropertyNames())
859             bundleProperties.addJavaProperty(ABOUTMENU_KEY, bundleProperties
860                     .getCFBundleName());
861
862         // Anti Aliased Graphics, renamed in 1.4+
863
String JavaDoc antiAliasedProperty = useOldPropertyNames()
864                 ? "com.apple.macosx.AntiAliasedGraphicsOn"
865                 : "apple.awt.antialiasing";
866
867         if (mAntiAliasedGraphics != null)
868             bundleProperties.addJavaProperty(antiAliasedProperty,
869                     mAntiAliasedGraphics.toString());
870
871         // Anti Aliased Text, renamed in 1.4+
872
String JavaDoc antiAliasedTextProperty = useOldPropertyNames()
873                 ? "com.apple.macosx.AntiAliasedTextOn"
874                 : "apple.awt.textantialiasing";
875
876         if (mAntiAliasedText != null)
877             bundleProperties.addJavaProperty(antiAliasedTextProperty,
878                     mAntiAliasedText.toString());
879
880         // Live Resize, deprecated under 1.4+
881
if (useOldPropertyNames() && (mLiveResize != null))
882             bundleProperties.addJavaProperty(
883                     "com.apple.mrj.application.live-resize", mLiveResize
884                             .toString());
885
886         // Screen Menu Bar, renamed in 1.4+
887
String JavaDoc screenMenuBarProperty = useOldPropertyNames()
888                 ? "com.apple.macos.useScreenMenuBar"
889                 : "apple.laf.useScreenMenuBar";
890
891         if (mScreenMenuBar != null)
892             bundleProperties.addJavaProperty(screenMenuBarProperty,
893                     mScreenMenuBar.toString());
894
895         // Growbox, added with 1.4+
896
if ((useOldPropertyNames() == false) && (mGrowbox != null))
897             bundleProperties.addJavaProperty("apple.awt.showGrowBox", mGrowbox
898                     .toString());
899
900         // Growbox Intrudes, deprecated under 1.4+
901
if (useOldPropertyNames() && (mGrowboxIntrudes != null))
902             bundleProperties.addJavaProperty(
903                     "com.apple.mrj.application.growbox.intrudes",
904                     mGrowboxIntrudes.toString());
905
906         if (!mRootDir.exists()
907                 || (mRootDir.exists() && !mRootDir.isDirectory()))
908             throw new BuildException(
909                     "Destination directory specified by \"dir\" "
910                             + "attribute must already exist.");
911
912         if (bundleDir.exists())
913             throw new BuildException("The directory/bundle \""
914                     + bundleDir.getName()
915                     + "\" already exists, cannot continue.");
916
917         // Status message
918
log("Creating application bundle: " + bundleDir);
919
920         if (!bundleDir.mkdir())
921             throw new BuildException("Unable to create bundle: " + bundleDir);
922
923         // Make the Contents directory
924
mContentsDir = new File JavaDoc(bundleDir, "Contents");
925
926         if (!mContentsDir.mkdir())
927             throw new BuildException("Unable to create directory "
928                     + mContentsDir);
929
930         // Make the "MacOS" directory
931
mMacOsDir = new File JavaDoc(mContentsDir, "MacOS");
932
933         if (!mMacOsDir.mkdir())
934             throw new BuildException("Unable to create directory " + mMacOsDir);
935
936         // Make the Resources directory
937
mResourcesDir = new File JavaDoc(mContentsDir, "Resources");
938
939         if (!mResourcesDir.mkdir())
940             throw new BuildException("Unable to create directory "
941                     + mResourcesDir);
942
943         // Make the Resources/Java directory
944
mJavaDir = new File JavaDoc(mResourcesDir, "Java");
945
946         if (!mJavaDir.mkdir())
947             throw new BuildException("Unable to create directory " + mJavaDir);
948
949         // Copy icon file to resource dir. If no icon parameter
950
// is supplied, the default icon will be used.
951

952         if (mAppIcon != null) {
953         
954
955             try {
956                 File JavaDoc dest = new File JavaDoc(mResourcesDir, mAppIcon.getName());
957
958                 if(mVerbose)
959                     log("Copying application icon file to \"" + bundlePath(dest) + "\"");
960
961                 mFileUtils.copyFile(mAppIcon, dest);
962             } catch (IOException JavaDoc ex) {
963                 throw new BuildException("Cannot copy icon file: " + ex);
964             }
965         }
966
967         // Copy document type icons, if any, to the resource dir
968
try {
969             Iterator JavaDoc itor = bundleProperties.getDocumentTypes().iterator();
970
971             while (itor.hasNext()) {
972                 DocumentType documentType = (DocumentType) itor.next();
973                 File JavaDoc iconFile = documentType.getIconFile();
974                 if (iconFile != null) {
975                     File JavaDoc dest = new File JavaDoc(mResourcesDir, iconFile.getName());
976                     if(mVerbose)
977                         log("Copying document icon file to \"" + bundlePath(dest) + "\"");
978                     mFileUtils.copyFile(iconFile, dest);
979                 }
980             }
981         } catch (IOException JavaDoc ex) {
982             throw new BuildException("Cannot copy document icon file: " + ex);
983         }
984
985         // Copy application jar(s) from the "jars" attribute (if any)
986
processJarAttrs();
987
988         // Copy application jar(s) from the nested jarfileset element(s)
989
processJarFileSets();
990
991         // Copy application jar(s) from the nested jarfilelist element(s)
992
processJarFileLists();
993
994         // Copy executable(s) from the "execs" attribute (if any)
995
processExecAttrs();
996
997         // Copy executable(s) from the nested execfileset element(s)
998
processExecFileSets();
999
1000        // Copy executable(s) from the nested execfilelist element(s)
1001
processExecFileLists();
1002
1003        // Copy resource(s) from the nested resourcefileset element(s)
1004
processResourceFileSets();
1005
1006        // Copy resource(s) from the nested javafileset element(s)
1007
processJavaFileSets();
1008
1009        // Copy resource(s) from the nested resourcefilelist element(s)
1010
processResourceFileLists();
1011
1012        // Copy resource(s) from the nested javafilelist element(s)
1013
processJavaFileLists();
1014
1015        // Add external classpath references from the extraclasspath attributes
1016
processExtraClassPathAttrs();
1017
1018        // Add external classpath references from the nested
1019
// extraclasspathfileset element(s)
1020
processExtraClassPathFileSets();
1021
1022        // Add external classpath references from the nested
1023
// extraclasspathfilelist attributes
1024
processExtraClassPathFileLists();
1025
1026        // Copy HelpBooks into place
1027
copyHelpBooks();
1028
1029        // Copy the JavaApplicationStub file from the Java system directory to
1030
// the MacOS directory
1031
copyApplicationStub();
1032
1033        // Create the Info.plist file
1034
writeInfoPlist();
1035
1036        // Create the PkgInfo file
1037
writePkgInfo();
1038
1039        // Done!
1040
}
1041
1042    /***************************************************************************
1043     * Private utility methods.
1044     **************************************************************************/

1045
1046    private void setExecutable(File JavaDoc f) {
1047
1048        Chmod chmodTask = new Chmod();
1049        chmodTask.setProject(getProject());
1050        chmodTask.setFile(f);
1051        chmodTask.setPerm("ugo+rx");
1052
1053        if (mVerbose)
1054            log("Setting \"" + bundlePath(f) + "\" to executable");
1055
1056        chmodTask.execute();
1057
1058    }
1059
1060    /**
1061     * Utility method to determine whether this app bundle is targeting a 1.3 or
1062     * 1.4 VM. The Mac OS X 1.3 VM uses different Java property names from the
1063     * 1.4 VM to hint at native Mac OS X look and feel options. For example, on
1064     * 1.3 the Java property to tell the VM to display Swing menu bars as screen
1065     * menus is "com.apple.macos.useScreenMenuBar". Under 1.4, it becomes
1066     * "apple.laf.useScreenMenuBar". Such is the price of progress, I suppose.
1067     *
1068     * Obviously, this logic may need refactoring in the future.
1069     */

1070
1071    private boolean useOldPropertyNames() {
1072        return (bundleProperties.getJVMVersion().startsWith("1.3"));
1073    }
1074
1075    private void processJarAttrs() throws BuildException {
1076
1077        try {
1078
1079            for (Iterator JavaDoc jarIter = mJarAttrs.iterator(); jarIter.hasNext();) {
1080                File JavaDoc src = (File JavaDoc) jarIter.next();
1081                File JavaDoc dest = new File JavaDoc(mJavaDir, src.getName());
1082
1083                if (mVerbose)
1084                    log("Copying JAR file to \"" + bundlePath(dest) + "\"");
1085                
1086
1087                mFileUtils.copyFile(src, dest);
1088                bundleProperties.addToClassPath(dest.getName());
1089            }
1090        } catch (IOException JavaDoc ex) {
1091            throw new BuildException("Cannot copy jar file: " + ex);
1092        }
1093    }
1094
1095    private void processJarFileSets() throws BuildException {
1096
1097        for (Iterator JavaDoc jarIter = mJarFileSets.iterator(); jarIter.hasNext();) {
1098
1099            FileSet fs = (FileSet) jarIter.next();
1100
1101            Project p = fs.getProject();
1102            File JavaDoc srcDir = fs.getDir(p);
1103            FileScanner ds = fs.getDirectoryScanner(p);
1104            fs.setupDirectoryScanner(ds, p);
1105            ds.scan();
1106
1107            String JavaDoc[] files = ds.getIncludedFiles();
1108
1109            try {
1110
1111                for (int i = 0; i < files.length; i++) {
1112                    String JavaDoc fileName = files[i];
1113                    File JavaDoc src = new File JavaDoc(srcDir, fileName);
1114                    File JavaDoc dest = new File JavaDoc(mJavaDir, fileName);
1115
1116                    if (mVerbose)
1117                        log("Copying JAR file to \"" + bundlePath(dest) + "\"");
1118
1119                    mFileUtils.copyFile(src, dest);
1120                    bundleProperties.addToClassPath(fileName);
1121                }
1122
1123            } catch (IOException JavaDoc ex) {
1124                throw new BuildException("Cannot copy jar file: " + ex);
1125            }
1126        }
1127    }
1128
1129    private void processJarFileLists() throws BuildException {
1130
1131        for (Iterator JavaDoc jarIter = mJarFileLists.iterator(); jarIter.hasNext();) {
1132            FileList fl = (FileList) jarIter.next();
1133            Project p = fl.getProject();
1134            File JavaDoc srcDir = fl.getDir(p);
1135            String JavaDoc[] files = fl.getFiles(p);
1136
1137            try {
1138
1139                for (int i = 0; i < files.length; i++) {
1140                    String JavaDoc fileName = files[i];
1141                    File JavaDoc src = new File JavaDoc(srcDir, fileName);
1142                    File JavaDoc dest = new File JavaDoc(mJavaDir, fileName);
1143
1144                    if (mVerbose)
1145                        log("Copying JAR file to \"" + bundlePath(dest) + "\"");
1146                    
1147
1148                    mFileUtils.copyFile(src, dest);
1149                    bundleProperties.addToClassPath(fileName);
1150                }
1151            } catch (IOException JavaDoc ex) {
1152                throw new BuildException("Cannot copy jar file: " + ex);
1153            }
1154        }
1155    }
1156
1157    private void processExtraClassPathAttrs() throws BuildException {
1158
1159        for (Iterator JavaDoc jarIter = mExtraClassPathAttrs.iterator(); jarIter
1160                .hasNext();) {
1161            File JavaDoc src = (File JavaDoc) jarIter.next();
1162            bundleProperties.addToExtraClassPath(src.getPath());
1163        }
1164    }
1165
1166    private void processExtraClassPathFileSets() throws BuildException {
1167
1168        for (Iterator JavaDoc jarIter = mExtraClassPathFileSets.iterator(); jarIter
1169                .hasNext();) {
1170            FileSet fs = (FileSet) jarIter.next();
1171            Project p = fs.getProject();
1172            File JavaDoc srcDir = fs.getDir(p);
1173            FileScanner ds = fs.getDirectoryScanner(p);
1174            fs.setupDirectoryScanner(ds, p);
1175            ds.scan();
1176
1177            String JavaDoc[] files = ds.getIncludedFiles();
1178
1179            for (int i = 0; i < files.length; i++) {
1180                File JavaDoc f = new File JavaDoc(srcDir, files[i]);
1181                bundleProperties.addToExtraClassPath(f.getPath());
1182            }
1183        }
1184    }
1185
1186    private void processExtraClassPathFileLists() throws BuildException {
1187
1188        for (Iterator JavaDoc jarIter = mExtraClassPathFileLists.iterator(); jarIter
1189                .hasNext();) {
1190            FileList fl = (FileList) jarIter.next();
1191            Project p = fl.getProject();
1192            File JavaDoc srcDir = fl.getDir(p);
1193            String JavaDoc[] files = fl.getFiles(p);
1194
1195            for (int i = 0; i < files.length; i++) {
1196                File JavaDoc f = new File JavaDoc(srcDir, files[i]);
1197                bundleProperties.addToExtraClassPath(f.getPath());
1198            }
1199        }
1200    }
1201
1202    private void processExecAttrs() throws BuildException {
1203
1204        try {
1205
1206            for (Iterator JavaDoc execIter = mExecAttrs.iterator(); execIter.hasNext();) {
1207                File JavaDoc src = (File JavaDoc) execIter.next();
1208                File JavaDoc dest = new File JavaDoc(mMacOsDir, src.getName());
1209
1210                if (mVerbose)
1211                    log("Copying exec file to \"" + bundlePath(dest) + "\"");
1212                
1213
1214                mFileUtils.copyFile(src, dest);
1215                setExecutable(dest);
1216            }
1217        } catch (IOException JavaDoc ex) {
1218            throw new BuildException("Cannot copy exec file: " + ex);
1219        }
1220    }
1221
1222    // Methods for copying FileSets into the application bundle ///////////////////////////////
1223

1224    // Files for the Contents/MacOS directory
1225
private void processExecFileSets() {
1226        processCopyingFileSets(mExecFileSets, mMacOsDir, true);
1227    }
1228
1229    // Files for the Contents/Resources directory
1230
private void processResourceFileSets() {
1231        processCopyingFileSets(mResourceFileSets, mResourcesDir, false);
1232    }
1233
1234    // Files for the Contents/Resources/Java directory
1235
private void processJavaFileSets() {
1236        processCopyingFileSets(mJavaFileSets, mJavaDir, false);
1237    }
1238
1239    private void processCopyingFileSets(List JavaDoc fileSets, File JavaDoc targetdir, boolean setExec) {
1240
1241        for (Iterator JavaDoc execIter = fileSets.iterator(); execIter.hasNext();) {
1242            FileSet fs = (FileSet) execIter.next();
1243            Project p = fs.getProject();
1244            File JavaDoc srcDir = fs.getDir(p);
1245            FileScanner ds = fs.getDirectoryScanner(p);
1246            fs.setupDirectoryScanner(ds, p);
1247            ds.scan();
1248
1249            String JavaDoc[] files = ds.getIncludedFiles();
1250
1251            if (files.length == 0) {
1252                // this is probably an error -- warn about it
1253
System.err
1254                        .println("WARNING: fileset for copying from directory "
1255                                + srcDir + ": no files found");
1256            } else {
1257                try {
1258                    for (int i = 0; i < files.length; i++) {
1259                        String JavaDoc fileName = files[i];
1260                        File JavaDoc src = new File JavaDoc(srcDir, fileName);
1261                        File JavaDoc dest = new File JavaDoc(targetdir, fileName);
1262                        
1263                        if (mVerbose)
1264                            log("Copying "
1265                                    + (setExec ? "exec" : "resource")
1266                                    + " file to \"" + bundlePath(dest) +"\"");
1267                        
1268                        mFileUtils.copyFile(src, dest);
1269                        if (setExec)
1270                            setExecutable(dest);
1271                    }
1272                } catch (IOException JavaDoc ex) {
1273                    throw new BuildException("Cannot copy file: " + ex);
1274                }
1275            }
1276        }
1277    }
1278
1279    // Methods for copying FileLists into the application bundle /////////////////////////////
1280

1281    // Files for the Contents/MacOS directory
1282
private void processExecFileLists() throws BuildException {
1283        processCopyingFileLists(mExecFileLists, mMacOsDir, true);
1284    }
1285
1286    // Files for the Contents/Resources directory
1287
private void processResourceFileLists() throws BuildException {
1288        processCopyingFileLists(mResourceFileLists, mResourcesDir, false);
1289    }
1290
1291    // Files for the Contents/Resources/Java directory
1292
private void processJavaFileLists() throws BuildException {
1293        processCopyingFileLists(mJavaFileLists, mJavaDir, false);
1294    }
1295
1296    private void processCopyingFileLists(List JavaDoc fileLists, File JavaDoc targetDir, boolean setExec) throws BuildException {
1297
1298        for (Iterator JavaDoc execIter = fileLists.iterator(); execIter.hasNext();) {
1299
1300            FileList fl = (FileList) execIter.next();
1301            Project p = fl.getProject();
1302            File JavaDoc srcDir = fl.getDir(p);
1303            String JavaDoc[] files = fl.getFiles(p);
1304
1305            if (files.length == 0) {
1306                // this is probably an error -- warn about it
1307
System.err.println("WARNING: filelist for copying from directory "
1308                                + srcDir + ": no files found");
1309            } else {
1310                try {
1311                    for (int i = 0; i < files.length; i++) {
1312                        String JavaDoc fileName = files[i];
1313                        File JavaDoc src = new File JavaDoc(srcDir, fileName);
1314                        File JavaDoc dest = new File JavaDoc(targetDir, fileName);
1315                        
1316                        if (mVerbose)
1317                            log("Copying "
1318                                    + (setExec ? "exec" : "resource")
1319                                    + " file to \"" + bundlePath(dest) +"\"");
1320                        
1321                        mFileUtils.copyFile(src, dest);
1322                        if (setExec)
1323                            setExecutable(dest);
1324                    }
1325                } catch (IOException JavaDoc ex) {
1326                    throw new BuildException("Cannot copy jar file: " + ex);
1327                }
1328            }
1329        }
1330    }
1331
1332
1333
1334    private void copyHelpBooks() {
1335
1336        for (Iterator JavaDoc itor = mHelpBooks.iterator(); itor.hasNext();) {
1337
1338            HelpBook helpBook = (HelpBook)itor.next();
1339            
1340            String JavaDoc folderName = helpBook.getFolderName();
1341            String JavaDoc name = helpBook.getName();
1342            String JavaDoc locale = helpBook.getLocale();
1343            
1344            List JavaDoc fileLists = helpBook.getFileLists();
1345            List JavaDoc fileSets = helpBook.getFileSets();
1346
1347
1348            File JavaDoc helpBookDir = null;
1349            
1350            if (locale == null) {
1351            
1352                // Set the Bundle entries for a nonlocalized Help Book
1353
if (folderName != null)
1354                    bundleProperties.setCFBundleHelpBookFolder(folderName);
1355                
1356                if (name != null)
1357                    bundleProperties.setCFBundleHelpBookName(name);
1358                
1359                // The non-localized Help Book is top level "/Resources"
1360
helpBookDir = new File JavaDoc(mResourcesDir, folderName);
1361                helpBookDir.mkdir();
1362
1363                if(mVerbose)
1364                    log("Creating Help Book at \"" +
1365                                        bundlePath(helpBookDir) + "\"");
1366
1367                
1368            } else {
1369
1370                // The localized Help Book is "/Resources/locale.lproj"
1371

1372                File JavaDoc lproj = new File JavaDoc(mResourcesDir, locale + ".lproj");
1373                lproj.mkdir();
1374                helpBookDir = new File JavaDoc(lproj, folderName);
1375                helpBookDir.mkdir();
1376
1377                if(mVerbose)
1378                    log("Creating Help Book for \"" + locale +
1379                                        "\" at \"" + bundlePath(helpBookDir) + "\"");
1380
1381                // Create a local file to override the Bundle settings
1382
File JavaDoc infoPList = new File JavaDoc(lproj, "InfoPlist.strings");
1383                PrintWriter JavaDoc writer = null;
1384                try {
1385                    writer = new PrintWriter JavaDoc(new FileWriter JavaDoc(infoPList));
1386                    writer.println("CFBundleHelpBookFolder = \"" + folderName + "\";");
1387                    writer.println("CFBundleHelpBookName = \"" + name + "\";");
1388                    writer.println("CFBundleName = \"" + bundleProperties.getCFBundleName() + "\";");
1389                } catch (IOException JavaDoc ioe) {
1390                    throw new BuildException("IOException in writing Help Book locale: " + locale);
1391                } finally {
1392                    mFileUtils.close(writer);
1393                }
1394            }
1395
1396            // Write the Help Book source files into the bundle
1397

1398            processCopyingFileSets(fileSets, helpBookDir, false);
1399            processCopyingFileLists(fileLists, helpBookDir, false);
1400
1401        }
1402    }
1403
1404
1405
1406
1407    // Copy the application stub into the bundle
1408
// /////////////////////////////////////////////
1409

1410    private void copyApplicationStub() throws BuildException {
1411
1412        File JavaDoc newStubFile = new File JavaDoc(mMacOsDir, bundleProperties.getCFBundleExecutable());
1413
1414        if (mVerbose)
1415            log("Copying Java application stub to \"" + bundlePath(newStubFile) + "\"");
1416
1417        try {
1418            mFileUtils.copyFile(mStubFile, newStubFile);
1419        } catch (IOException JavaDoc ex) {
1420            throw new BuildException("Cannot copy Java Application Stub: " + ex);
1421        }
1422
1423        // Set the permissions on the stub file to executable
1424

1425        setExecutable(newStubFile);
1426    }
1427
1428    private void writeInfoPlist() throws BuildException {
1429        PropertyListWriter listWriter = new PropertyListWriter(bundleProperties);
1430        File JavaDoc infoPlist = new File JavaDoc(mContentsDir, "Info.plist");
1431
1432        listWriter.writeFile(infoPlist);
1433        
1434        if (mVerbose)
1435            log("Creating \"" + bundlePath(infoPlist) + "\" file");
1436
1437
1438        if (mShowPlist) {
1439            try {
1440                BufferedReader JavaDoc in = new BufferedReader JavaDoc(new FileReader JavaDoc(infoPlist));
1441                String JavaDoc str;
1442                while ((str = in.readLine()) != null)
1443                    log(str);
1444                in.close();
1445            } catch (IOException JavaDoc e) {
1446                throw new BuildException(e);
1447            }
1448        }
1449    }
1450
1451
1452    //
1453
// Write the PkgInfo file into the application bundle
1454
//
1455

1456    private void writePkgInfo() throws BuildException {
1457        File JavaDoc pkgInfo = new File JavaDoc(mContentsDir, "PkgInfo");
1458        PrintWriter JavaDoc writer = null;
1459
1460        try {
1461            writer = new PrintWriter JavaDoc(new BufferedWriter JavaDoc(new FileWriter JavaDoc(pkgInfo)));
1462            writer.print(bundleProperties.getCFBundlePackageType());
1463            writer.println(bundleProperties.getCFBundleSignature());
1464            writer.flush();
1465        } catch (IOException JavaDoc ex) {
1466            throw new BuildException("Cannot create PkgInfo file: " + ex);
1467        } finally {
1468            mFileUtils.close(writer);
1469        }
1470    }
1471
1472    private String JavaDoc bundlePath(File JavaDoc bundleFile) {
1473    
1474        String JavaDoc rootPath = bundleDir.getAbsolutePath();
1475        String JavaDoc thisPath = bundleFile.getAbsolutePath();
1476    
1477        return thisPath.substring(rootPath.length());
1478    
1479    }
1480}
1481
Popular Tags