Bundled app launcher changes

Igor Nekrestyanov igor.nekrestyanov at oracle.com
Fri Feb 10 16:30:49 PST 2012

On 2/10/12 2:28 PM, Greg Brown wrote:
>> But bundle Info.plist and this can be heavily customized. Make sense to support that (e.g. like jar task supports customizing manifest)
> Can you provide some examples of what you might want to customize in a Java app bundle's Info.plist? The Java app itself can't access that information, so I'm wondering why you'd want to do this.
E.g. you may use external framework like Sparkle and set things like 
where to get autoupdate feed.
Or register help files, etc.

I do not see why Java app should not have access to these properties.
Even if there is no standard API to do so right now one can easily have 
native lib to export properties from NSApplication if needed.
>>>> Questions:
>>>>    a) How one specify set of jars?
>>> Use one or more nested<classpath>   fileset elements.
>>>>    b) What if application expects jars/resources to be in the multiple folders?
>>> You can use multiple<classpath>   elements.
>> Would you mind to give an example of this?
>> E.g. NB typically generate something like
>>    dist/app.jar
>>    dist/lib/dep-lib1.jar
>>    dist/lib/dep-lib2.jar
> <classpath dir="dist" includes="*.jar"/>
> <classpath dir="dist/lib" includes="*.jar"/>
>> How do i package it to preserve structure?
> That isn't currently supported. Why might you want to do that?
Because your app may depend on this structure.
E.g. jre depends on presence bin , lib, etc.
Granted Netbeans may be not "best" example of how to package java app as 
bundle on Mac but IMHO it is good example of complex app
and good use case to investigate.

In my local NB 7.1 installation directory structure is quite 
complicated. Here is what happens at top level (it goes at least 2-3 
levels deeper).

> igor$ find /Applications/NetBeans/NetBeans\ 7.1\ RC1.app -type f 
> -maxdepth 4
> /Applications/NetBeans/NetBeans 7.1 RC1.app/Contents/Info.plist
> /Applications/NetBeans/NetBeans 7.1 
> RC1.app/Contents/Resources/NetBeans/CREDITS.html
> /Applications/NetBeans/NetBeans 7.1 
> RC1.app/Contents/Resources/NetBeans/DISTRIBUTION.txt
> /Applications/NetBeans/NetBeans 7.1 
> RC1.app/Contents/Resources/NetBeans/LEGALNOTICE.txt
> /Applications/NetBeans/NetBeans 7.1 
> RC1.app/Contents/Resources/NetBeans/LICENSE.txt
> /Applications/NetBeans/NetBeans 7.1 
> RC1.app/Contents/Resources/NetBeans/moduleCluster.properties
> /Applications/NetBeans/NetBeans 7.1 
> RC1.app/Contents/Resources/NetBeans/netbeans.css
> /Applications/NetBeans/NetBeans 7.1 
> RC1.app/Contents/Resources/NetBeans/README.html
> /Applications/NetBeans/NetBeans 7.1 
> RC1.app/Contents/Resources/NetBeans/THIRDPARTYLICENSE.txt
> /Applications/NetBeans/NetBeans 7.1 
> RC1.app/Contents/Resources/netbeans.icns

>>>>    c) How do i specify data or other resource files to be included?
>>> Include them on your classpath (e.g. in your class directory or JAR files), as you would with any other Java application.
>> Do you mean i can include folder to the classpath and then all subdirectories will be copied over to the bundle?
> Yes.
ok, this is good.
>> I am not sure how this classpath element work.
> It's just a regular Ant FileSet.
IMHO, regular ant fileset will not flatten directory structure by default.

If it is like regular fileset then why do we need new element and not 
reusing fileset?

>> Also, with this approach the app running in the dev environment will be different from app running from the bundle.
>> E.g. you have to set classpath again.
> Yes. But this is no different from the existing JarBundler tool provided with OS X or the open-source JarBundler Ant task that serves a similar purpose:
> http://informagen.com/JarBundler/
ok good to know.
but why do we think it is best/ideal way?

Do we try to stay compatible with that tool?
>> Can you elaborate a bit why do we want to set classpath at the package time?
> Because we need to know which JARs/class files need to be added to the app bundle.
Ant has plenty of existing mechanism to define resource sets.
Why we need new one? Why it needs to be "ordered" list?
>>>>    f) Why we refer to Java Runtime?
>>>>          runtime="${env.JAVA_HOME}/../.."
>>>>       IMHO, we could assume people install JDK and should point to JDK bundle root as root for cobundle.
>>> In order to comply with Apple's licensing policy for app store redistribution, we need to support an embedded JRE. If you do not specify a JRE, the launcher will look for a locally-installed shared runtime.
>> I understand why we cobundle JRE. I do not understand why we expect developer to provide reference to it in this way.
> How would you expect developers to reference it?
<javaruntime sdk="path/to/jdk.bundle"/>

>> My understanding is that JRE to cobundle will always be in the
>>    jdk.bundle/MacOS/Contents/Home/jre
> I'm not sure that is a reasonable assumption. Why not allow the developer to choose?
As far as i understand
    a) ant task we are discussing will come with jdk bundle
    b) jdk bundle is the only planned way to distribute openjdk on Mac
    c) there will be no official JRE bundle on Mac

What other options we want to support?
>> Based on your example it seem that developer need to point to "jdk.bundle/MacOS/Contents/Home" and this exposes internals of jdk bundle.
> No, the developer just needs to point at the top-level bundle directory (e.g. /Library/Java/JavaVirtualMachines/1.7.0.jre).
There will be no JRE bundle for Mac.
>>>>   g) Any way to specify minimum platform requirements (even dmg has it)?
>>> Which platform? Java, OS X, or both?
>> OS X version.
>> E.g. need 10.7.3, etc.
> I see. We could add attributes for this to the Ant task.
>>>> Specifically i am thinking it will be useful to have
>>>>    a) some kind of "resource" element that could include arbitrary set of filesets
>>>>        And resources could be of different types (e.g. jars, native, frameworks, icon, "custom", etc)
>>> Fundamentally, this is a tool for packaging Java apps, so I'm not sure what the value would be in supporting non-Java resources. All of your Java resources just need to be on your classpath.
>> I do not follow here.
>> ...
>> Assuming everything is on classpath is not realistic, IMHO.
> OK, sure. But if your app needs access to something outside of the class path, you can still use standard Java APIs to get to it (e.g. java.io.File). There are no standard Java APIs for accessing the contents of a Mac app bundle, so (IMO) there's not much point in supporting bundle-specific customizations.
Sure but question i have is not about APIs to use.
The question is how do i package my app as a bundle to preserve relative 
paths to the resources it may need.
>>>>    b) application descriptor - most of what you have on bundledapp right now
>>>>          (but not java runtime location, dest file, etc.)
>>> Can you elaborate on this? I'm not sure what you mean.
>> Ok, here is tentative example
>>    <bundleapp outputdirectory="." name="SwingSet2">
>>       <!-- Application properties. This is effectively plist. May be wise to support reference to predefined plist in the file -->
>>       <properties
>>         displayname="SwingSet 2"
>>         identifier="com.oracle.javax.swing.SwingSet2"
>>         shortversion="1.0"
>>         >
>>         <!-- custom plist property, see "/usr/libexec/PlistBuddy -h" -->
>>         <property name=":SUFeedURL" value="http://somewhere/sparkle-appcast.xml"/>
>>         <property name=":CFBundleDocumentTypes:2:CFBundleTypeExtensions" value="aaa"/>
>>       </properties>
>>        <javaruntime sdk="path/to/jdk.bundle">
>>         <option value="-Xms32M"/>
>>         <option value="-Xmx256M"/>
>>         <option value="-Dapple.laf.useScreenMenuBar=true"/>
>>       </javaruntime>
>>       <!-- Expect that SwingSet2.jar has classpath element pointing to other dependent jars -->
>>       <application main="SwingSet2.jar">
>>         <argument value="foo=bar"/>
>>       </application>
>>       <resources>   <!-- default type are "app" resources -->
>>          <!-- includes both jar and native libs -->
>>          <!-- e.g. we could have SwingSet.jar, lib/one.jar, lib/two.jar, docs/README.html, lib/macosx/something-native.dylib -->
>>          <fileset basedir="${dist.dir}" includes="**"/>
>>       </resources>
>>       <resources type="framework">
>>          <fileset basedir="Sparkle.src" includes="**"/>
>>       </resources>
>>       <resource type="icon">   <!-- if present then copied and used as bundle icon -->
>>          <fileset .../>
>>       </resource>
>>    </bundleapp>
> This just seems like a more verbose way of representing the same information. What would be the advantage of restructuring it this way?
I tried to represent information from your sample and illustrate how it 
can be further customized.
It still serve for the same goal (to generate bundle) => it has to be 
similar :)

Perhaps you can provide an example of how this customizations can be 
done with existing task?

IMHO benefits here are:
    - reusing existing ant types whenever is possible
    - split configuration into logical groups (instead one giant set of 
possible options)
    - flexibility in specifying different resource sets (and no attempts 
to define classpath, etc.)
    - ability to define some of elements outside of bundleapp and then 
refer to them using refid
        (allows to reuse them, e.g. if you need to package bunch of 
sample apps want to reuse all runtime details, etc.)
    - somewhat more object model
> The current task properties are designed to map basically 1:1 to the java command-line executable arguments. The generated app bundle is simply a more "Mac-friendly" way of launching a standard Java app. From the command line:
> Usage: java [-options] class [args...]
Alright, using this model what i am suggesting is start with

 > java [-options] -jar app.jar [args ..]

And  separate 2 parts:
    a) runtime + runtime  options
    b) app + arguments

Then you also need
    c) what resources include into bundle (app may have complex sets)
    d) customize bundle properties
> The class path and native library path are handled separately because we need to know which files to embed in the app bundle. However,<classpath>  corresponds directly to -Djava.class.path, and<nativeLibrary>  corresponds directly to -Djava.library.path; again, pretty obvious.
I'd argue that attempt to set any of them explicitly is not needed.
Moreover setting -Djava.library.pathis bad practice, app need to know 
how to load native resource that is relative to its jar.
In worst case it can pass this as runtime option.

Is there any IDE that generate java package in this way?
Assuming that to launch it from command line user need to pass 
-Djava.library.path or -Djava.class.path but yet it will work right a 
way in the IDE?


More information about the macosx-port-dev mailing list