I am trying to implement the same functionality on Mac for an existing
Windows (java) application that has two states -admin (default) and
-client
which are determined by the command line option following the
application
(eg MyApp) path. The client state is crippled in some ways.
Exactly how is that functionality represented on Windows? That is,
how are
the two possible application states presented to the desktop-based
Windows
user?
The admin version is the default. Double clicking the main application
will launch the administrator version (which is installed in a shared
directory). The client version is launched by double clicking a batch
file in the same directory as the main application. The administrator
then can make short cuts to this batch file from anywhere on the
network (ie on client machines). (There is an installer which does this
for the administrator.) Hence the same application can be used by
clients and administrators. This is so files created by the application
(when used by networked clients) are all on the same directory without
clients having to navigate around to find the shared directory.
Are there two separate double-clickable icons? Two documents and an
app?
Or is only one state double-clickable and the other only obtainable by
command-line? Or are they both command-lines only?
Hence there are only two "files" visible to the administrator. The main
application and the batch file. Both are double clickable and the
command line element is hidden but underlies the change in application
functionality.
Exactly how do you want the two possible states presented to the
desktop-based Mac OS X user?
My preference is to have two double clickable applications. First, the
main application which the administrator double clicks (with added
admin functionality). This is the default which occurs when the bundled
Mac java app is double clicked. Second, the apple script compiled as an
application which is named eg. "MyApp Client". An alias can be created
on every networked client machine which will open the client version.
This currently works just fine with client created files being created
in the admin version's directory. The only minor issue with using an
apple script is that (as yet) I don't know how to give it an icon to
match the admin version branding.
There were minor compile errors only and I created the jar file (eg
MyApp.jar) using ant and the windows compatible build.xml script. The
client version worked just fine when invoked from a shell using "java
MyApp.jar -client". I then needed to create a double clickable
Mac-like
bundle with the appropriate icon etc. This was easy using jarbundler
additions to the xml.build script (jar bundler is cool). But, then I
could
not work out how to invoke the bundled application using the -client
option. Hence, my posts to this august list.
Double-clicked apps on different platforms have different requirements
and
expectations. In general, a Mac OS X bundled app is entirely
self-contained and self-starting. It does not require additional
command-line args.
Another way of saying this is that a Mac OS X double-clicked app gets
no
command-line args, so it should default as appropriate. In your case,
if
there are no args, the program should default to the same state as
"-client". You can do this with Info.plist, or in pure Java.
I suggest using the Arguments key under the Java dictionary, with
"-client"
as the Arguments value. This should have the effect of running your
app in
client-mode when the app-bundle is double-clicked. I think that's the
simplest answer to at least part of what you want (client-mode launch).
In pure Java, you simply create a small class like the following, and
then
use it as the Main-Class of the app-bundle:
public class ClientMain
{
private static String[] clientArgs = { "-client" };
public static void main( String[] args )
{ MyApp.main( clientArgs ); }
}
Since any Java class can have a main() method, this strategy makes it
easy
to have different entry-points that result in different states or
behaviors. The different entry-points can even be classes you've
added to
a third-party program, that make it do the things you want in the way
you
want them.
Also, I frequently use system properties in lieu of command-line args,
because they are a little easier to manage in Info.plist, and easier
to set
up defaults for in Java. In some cases, absence of an arg causes
retrieval
of an equivalent property-name (e.g. "app.mode" in absence of -client
or
-admin arg), with appropriate fallback. Or it can go the other way,
with
an arg causing my code to set a property for other parts of the app to
read.
I think of args as positional parameters, and properties as named
parameters, so circumstances and convenience determine how they all
interact.
Thank you for these suggestions, but as far as I can tell they create a
separate standalone client only mode application. We don't want to
provide separate client applications that always work in client mode,
since this complicates installation and management over the network.
Each client application would have to be told (manually) where to put
its created data files. This happens automatically with the above
arrangement. In other words, we have one application that runs just
fine resident in memory on the client machine but saves all its files
and gets its preferences etc from the shared directory.
In passing, I concur that tweaking the Info.plist is a very powerful
technique, eg I did play around with your Prelude script technique in
which you change the JavaApplicationStub reference in the
CFBundleExecutable property to a shell script in the
MyApp.app/Contents/MacOS directory can accomplish the customization to
a client standalone without any difficulty, but unfortunately it's not
what is required in our situation.
[SNIP]
Unfortunately I failed to get this working. Runtime.exec() either did
nothing or returned errors. Note that the release application name
actually
contains a space (which is an added complication, as in "My App"). I
suspect the problems were due to incorrect syntax (eg escaping of
spaces in
my application's name in the path).
The problem was in how you invoked exec(). You didn't break down the
command-line into individual args. The exec() methods are not
command-line
interpreters. The String[] versions in particular do no additional
parsing.
public void run_client_app() {
String scriptpath = "<path to
MyApp>/MyApp/Contents/MacOS/JavaApplicationStub -client";
String cmdarray[] = new String[]{"sh", scriptpath};
You either need to quote the args you pass to 'sh', or you need the
following form, with each distinct arg as a separate String. Either
way,
you also need the ".app" suffix on the app-bundle name:
Sorry. I did include the ".app" in my code listing but for some reason
deleted it when I changed the application name...
String cmdarray[] = {
"/path to app/My App.app/Contents/MacOS/JavaApplicationStub",
"-client" };
You can accomplish the same thing using:
a) an Info.plist with "Arguments" key of "-client".
b) a Java main() entry-point that needs no overt "-client" arg.
c) a Java main() taking mode in a property, + "Property" key in
Info.plist
d) a CFBundleExecutable of a shell-script, which executes the 'java'
command.
Any one of those is simpler than a Java program that runs 'sh' to run a
JavaApplicationStub that runs another Java program.
This leads to the following print out in the console window:
Picked up _JAVA_OPTIONS: -Xdebug -Xnoagent
-Xrunjdwp:transport=dt_local,server=y,address=8007
-[NSJavaVirtualMachine initWithClassPath:] cannot instantiate a Java
virtual machine
sh
/Users/ddarby/Documents/Projects/DgD_CPP_Applns/Qt_Stuff/
CogStateApplns/ConcussionSentinelClient/Sentinel/mac_dist/
ConcussionSentinel.app/Contents/MacOS/JavaApplicationStub
Process exit code: 126
The first arg to JavaApplicationStub should be a -psn arg, which is
normally supplied by LaunchServices (via Finder or via the 'open'
command).
See my HowTo article on "More Open Files", and play around with the
contents of the prelude shell-script, to see exactly what an
app-bundle is
launched with when double-clicked or when run via 'open'. The 'echo
"$@"'
command may still be in the downloadable example.
Your error message makes me think you're somehow running a Cocoa-Java
app,
but that's just a guess.
-- GG
Thanks for your suggestions. I've tried the following and still can't
get it to work.
both of which do initiate the launch of MyApp but it keeps bouncing in
the dock and never actually completes launching. (Command shell
launching using the first of these with the client option leads to an
error since open does not support this option.)
What specifically am I doing wrong? The same error about not
instantiating the JVM occurs each time so clearly there's something
fundamentally wrong with my code:
-[NSJavaVirtualMachine initWithClassPath:] cannot instantiate a Java
virtual machine
A/Prof David Darby
Em email@hidden
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Java-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/java-dev/email@hidden