This page last changed on Jul 09, 2010 by am74686.

App Client Container - Discussion Topics from asarch review and e-mail

[

Unknown macro: {TableOfContents title='App Client Container Topics'}

|(TableOfContentstitle='AppClientContainerTopics')]

We had extended discussions via e-mail on several topics since the ACC review. This page focuses on the external interfaces that have changed since the review as a result of the discussions.

1. Download individual JARs instead of an umbrella JAR

Background

In v2, deployment of an EAR creates a single umbrella JAR which contains the app client(s) in the EAR plus the transitive closure of JARs cited in an app client's Class-Path or in the EAR's library directory. "deploy --retreive local-dir" or "get-client-stubs --appname myapp local-dir" copies this umbrella JAR to the user-specified local directory. During launch the ACC expands the umbrella JAR to a temp directory and builds the class path from the expanded contents. Users have complained about the start-up time, esp. for small clients that depend on large libraries.

I proposed that v3 download the individual JARs instead of generating and downloading the umbrella JAR to the local directory. This reduces the launch time, more importantly, but also cuts down on deployment time. In e-mail Bill suggested that I poll users for input. Two responded, both preferring the individual JAR approach to one in which the ACC would extract JARs from the umbrella just-in-time, for example.

There are some open-source projects that resolve class loading and resource references to nested JARs. One-JAR essentially reads the nested JARs into memory and maps look-ups to the memory-resident nested JAR. I'm afraid of the memory usage and I could find no performance information about One-JAR on the web. Jar Jar Links creates a new single JAR that contains all the content of its input JARs, munging names to avoid collisions and using ASM to do bytecode transformations so references to colliding names are patched to refer to the new names. It does not handle dynamic look-up by resource or class names.

Plan

The user feedback - all two of them - was to go with the multi-file download approach. (There was also a resounding endorsement of the embedded API idea!) The multi-file download is the approach we've pursued. We will continue to support the ability to launch not only individual JARs but also the umbrella JAR. In v3 we will generate an additional JAR representing the EAR-level but it will not contain all the client JARs and all the libraries as the v2 umbrella JAR did; it will just contain pointers to the individual client JARs.

2. Java command support

Background

Recurring requests over time (and some v3 requirements) to let users launch clients using the java command. This is fairly straightforward for facade JARs ("cooked" JARs) for each app client which v3 generates. We control the main class of the facade JARs so it does what we want. More difficult to handle is the original ("uncooked" or "raw") app client JARs.

There is no supported API to find out from Java code which class the Java launcher chose to launch or to capture the entire java command line. The ACC needs this information or its equivalent to know the main class for injection and to locate the descriptor(s).

Plus, we need to get the gf-client.jar (which contains the ACC) on the class path. Even in a facade JAR file where we control the Class-Path we cannot generate it to refer to gf-client.jar on end-user systems - we don't know where that will be installed.

Plan

Two key parts:

A. Write a Java agent (one that does no bytecode transformations) in gf-client.jar. The {{-javaagent:$

Unknown macro: {install-root}

/modules/gf-client.jar}} option on the java command gets gf-client.jar onto the system class path. Agent arguments will indicate just how the user has launched the program. The agent does all of the prep work to get the ACC ready and the main class injected, stopping short of actually invoking the client's main method.

B. Write the appclient scripts so they:

  1. set the agent arguments to tell how the user launched the client,
  2. omit the appclient options and arguments from arguments portion of the java command, and
  3. execute a java command that will run the app client's main class.

2.1 java-command-like syntax for the appclient script

Users can format their appclient invocations very much like java commands:

appclient [jvm options] client-selection [acc options] [app args]
client-selection New in v3? For java-style
-client myClient.jar    
-jar myClient.jar X X
x/z/A.class    
x.y.z.A   X
-mainclass x.y.z.A    
-client myUmbrella.jar -mainclass x.y.z.A    
-client myUmbrella.jar -name display-name    

This is consistent with the documentation and on-line usage output from past releases in which -client appClient.jar appears before other options or arguments on the command line. We are expanding - not invalidating - the old format, adding the optional JVM options part and adding to the ways in which the user can select which client to run.

2.2 Launching with java commands

Users can launch app clients directly using java commands. For launching facade JARs we have generated,

		
java jvm options -javaagent:$

/modules/gf-client.jar main-class-selection app args

is sufficient.  The facade JAR's main class - which we control - can tell whether the user specified agent arguments or not and, if not, will do the ACC initialization itself before calling the client's main method.  This would use default values for appclient options.

To launch an original (not deployed and therefore uncooked) app client JARs with the java command users, must specify an agent argument:
java -javaagent:$

Unknown macro: {install-root}

/modules/gf-client.jar=client=jar=myClient.jar ... -jar myClient.jar app args

or
java -javaagent:$

/modules/gf-client.jar=client=class=myClient.jar ... a.b.MyClient app args

We have to ask such users to duplicate this information because the agent cannot find this out itself from Java.

As Jerome pointed out after the review, the name and location of the gf-client.jar file (as well as some of the agent arguments) becomes an exposed interface of the product if we document and support the pure java command feature.

h1. 3. Embedded API
*Plan*

A user program follows these basic steps to launch a client:

// one TargetServer for each ORB endpoint for bootstrapping
TargetServer[] servers = ...;

// Get a configurator to set up the ACC
AppClientConfigurator config = AppClientContainer.newConfigurator(servers);

// Fine-tune the ACC's configuration
config.callbackHandler("com.acme.MyHandler").authRealm("myRealm"); // Modify the config

// Get a container for a client.
URI clientURI = ...; // URI to the client JAR
AppClientContainer acc = config.newContainer(clientURI);

or

Class mainClass = ...;
acc = config.newContainer(mainClass);

String[] appArgs = ...;
acc.startClient(appArgs); // Start the client

...

acc.stop(); // stop the ACC(optional)

		

Notes:

  • Some state checking is present to make sure that a container is not started twice (or more) or stopped before it is started. But this is a fairly simple API with a simple state model which should be clear to developers. Roberto had described an alternative in which, for example, startClient would return a RunningACC which would not even have a start method, just stop, thus preventing a developer from accidentally starting a running container again.
  • A configurator is multi-use; it could be used to create multiple ACCs.
  • An ACC deals with a single app client and is single-use.
  • Invoking acc.stop() is optional. The ACC registers a shutdown handler to clean up.
  • The choices of names for "startClient" and "stop" (not "start" and not "stopClient") are intentional.
    • Conceptually and practically, invoking configurator.newContainer "starts" the ACC – the ACC becomes ready to support an app client's execution.
    • Invoking startClient really does start the client executing by finding and invoking its main method.
    • The stop method shuts down the ACC, not the client. The startClient method returns to the caller as soon as the client's main method returns to startClient, even if the client has started threads (e.g, the event dispatcher thread servicing a GUI). The ACC knows nothing about such threads and would not know how to stop them reliably even if it did know about them. The developer should write the program to invoke stop – if at all – only after the program knows the client has finished doing its work and will make no further use of the ACC's services (naming, security, etc.). Any coordination between the calling program and the client is the developer's responsibility.

Document exported from wikis.oracle.com on May 27, 2015 20:44
Copyright © 2005-2015 Oracle and/or its affiliates. All rights reserved.