Mailing Lists: Apple Mailing Lists

Image of Mac OS face in stamp
 
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Double clickable script question[Explanation of SOLUTION]



Dear Greg

Thanks for your comments.

On 04/10/2004, at 7:35 AM, Greg Guerin wrote:

David Darby <email@hidden> wrote:

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.


Referring to the 1.4 Info.plist properties:

<http://developer.apple.com/documentation/Java/Reference/ Java14JavaDict/index.ht
ml>


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.


String cmdarray[] = { "sh", "pathToApp/MyApp.app/Contents/MacOS/JavaApplicationStub", "-client"};
String cmdarray[] = { "/bin/sh", "pathToApp/MyApp.app/Contents/MacOS/JavaApplicationStub", "-client"};
String cmdarray[] = { "bash", "pathToApp/MyApp.app/Contents/MacOS/JavaApplicationStub", "-client"};
String cmdarray[] = { "open", "pathToApp/MyApp.app/Contents/MacOS/JavaApplicationStub", "-client"};


All of the above cause no compile errors, but the same failure to instantiate the JVM and no launching of the java bundled application.

I've also tried using:

String cmdarray[] = { "open", "pathToApp/MyApp.app/Contents/MacOS/JavaApplicationStub", "-client"};
String cmdarray[] = { "open", "pathToApp/MyApp.app/Contents/MacOS/JavaApplicationStub"};


but these fail to launch MyApp instead leaving me in the Terminal application.

And:

String cmdarray[] = { "open", "pathToApp/MyApp.app", "-client"};
String cmdarray[] = { "open", "pathToApp/MyApp.app"};

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

This email sent to email@hidden
References: 
 >Re: Double clickable script question[Explanation of SOLUTION] (From: Greg Guerin <email@hidden>)



Visit the Apple Store online or at retail locations.
1-800-MY-APPLE

Contact Apple | Terms of Use | Privacy Policy

Copyright © 2007 Apple Inc. All rights reserved.