FileDocCategorySizeDatePackage
JWSACCMain.javaAPI DocGlassfish v2 API19900Fri May 04 22:34:22 BST 2007com.sun.enterprise.appclient.jws.boot

JWSACCMain

public class JWSACCMain extends Object implements Runnable
Alternate main class for ACC, used when launched by Java Web Start.

This class assigns security permissions needed by the app server code and by the app client code, then starts the regular app client container.

Note that any logic this class executes that requires privileged access must occur either: - from a class in the signed jar containing this class, or - after setPermissions has been invoked. This is because Java Web Start grants elevated permissions only to the classes in the appserv-jwsacc-signed.jar at the beginning. Only after setPermissions has been invoked can other app server-provided code run with all permissions.

author
tjquinn

Fields Summary
private static final String
PERMISSIONS_TEMPLATE_NAME
name of the permissions template
private static final String
GRANT_CLAUSES_PROPERTY_EXPR
placeholder used in the policy template to substitute dynamically-generated grant clauses
private static final String
lineSep
line separator
private static com.sun.enterprise.appclient.Main
accMain
the instance of the acc's main class
private static String
jwsPolicyTemplateURL
the user-specified security policy template to use
private static final String
JWSACC_ARGUMENT_PREFIX
unpublished command-line argument conveying jwsacc information
private static final String
JWSACC_EXIT_AFTER_RETURN
private static final String
JWSACC_FORCE_ERROR
private static final String
JWSACC_KEEP_JWS_CLASS_LOADER
private static final String
JWSACC_RUN_ON_SWING_THREAD
private static final String
GRANT_CLAUSE_TEMPLATE
grant clause template for dynamically populating the policy
private static boolean
exitAfterReturn
request to exit the JVM upon return from the client - should be set (via the -jwsacc command-line argument value) only for command-line clients; otherwise it can prematurely end the JVM when the GUI and other user work is continuing
private static boolean
keepJWSClassLoader
private static boolean
runOnSwingThread
private static ClassPathManager
classPathManager
helper for building the class loader and policy changes
private static URL[]
downloadedJarURLs
URLs for downloaded JAR files to be used in the class path
private static final ResourceBundle
rb
localizable strings
private String[]
args
make the arguments passed to the constructor available to the main method
Constructors Summary
public JWSACCMain(String[] args)
Creates a new instance of JWSMain

    
           
       
        this.args = args;
    
Methods Summary
private static java.lang.StringdotToSlash(java.lang.String orig)

        return orig.replaceAll("\\.","/");
    
private java.io.FilefindAppClientFileForJWSLaunch(java.lang.ClassLoader loader)
Locate the app client jar file during a Java Web Start launch.

param
loader the class loader to use in searching for the descriptor entries
return
File object for the client jar file
throws
IllegalArgumentException if the loader finds neither descriptor

        /*
         *The downloaded jar should contain either META-INF/application.xml or
         *META-INF/application-client.xml.  Look for either one and locate the
         *jar from the URL.
         */
        File containingJar = findContainingJar("META-INF/application.xml", loader);
        if (containingJar == null) {
            containingJar = findContainingJar("META-INF/application-client.xml", loader);
        }
        if (containingJar == null) {
//            needs i18n
//            throw new IllegalArgumentException(localStrings.getString("appclient.JWSnoDownloadedDescr"));
            throw new IllegalArgumentException("Could not locate META-INF/application.xml or META-INF/application-client.xml");
        }
        return containingJar;
    
private static java.io.FilefindContainingJar(java.lang.String target, java.lang.ClassLoader loader)

        File result = null;
        /*
         *Use the specified class loader to find the resource.
         */
        URL resourceURL = loader.getResource(target);
        if (resourceURL != null) {
            result = classPathManager.findContainingJar(resourceURL);
        }
        return result;
    
public static intfirstFreePolicyIndex()
Locates the first free policy.url.x setting.

return
the int value for the first unused policy setting

        int i = 0;
        String propValue;
        do {
            propValue = java.security.Security.getProperty("policy.url." + String.valueOf(++i));
        } while ((propValue != null) && ( ! propValue.equals("")));
        
        return i;
    
public static ClassPathManagergetClassPathManager()
Return the class path manager appropriate to the current version.

return
the correct type of ClassPathManager

        return ClassPathManager.getClassPathManager(keepJWSClassLoader);
    
public static voidmain(java.lang.String[] args)

param
args the command line arguments

        try {
            args = prepareJWSArgs(args);
            try {
                classPathManager = getClassPathManager();
                downloadedJarURLs = classPathManager.locateDownloadedJars();
            } catch (Throwable thr) {
                throw new IllegalArgumentException(rb.getString("jwsacc.errorLocJARs"), thr);
            }

            /*
             *Before creating the new instance of the real ACC main, set permissions
             *so ACC and the user's app client can function properly.
             */
            setPermissions();

            /*
             *Make sure that the main ACC class is instantiated and run in the
             *same thread.  Java Web Start may not normally do so.
             */
            JWSACCMain jwsACCMain = new JWSACCMain(args);

            if (runOnSwingThread) {
                SwingUtilities.invokeAndWait(jwsACCMain);
            } else {
                jwsACCMain.run();
            }
            /*
             *Note that the app client is responsible for closing all GUI
             *components or the JVM will never exit.
             */
        } catch (Throwable thr) {
           System.exit(1);
        }
    
private static java.lang.ClassLoaderprepareClassLoader(java.io.File downloadedAppclientJarFile)
Create the class loader for loading code from the unsigned downloaded app server jars.

During a Java Web Start launch the ACC will be run under this class loader. Otherwise the JNLPClassLoader will load any stub classes that are packaged at the top-level of the generated app client jar file. (It can see them because it downloaded the gen'd app client jar, and therefore includes the downloaded jar in its class path. This allows it to see the classes at the top level of the jar but does not automatically let it see classes in the jars nested within the gen'd app client jar. As a result, the JNLPClassLoader would be the one to try to define the class for a web services stub, for instance. But the loader will not be able to find other classes and interfaces needed to completely define the class - because these are in the jars nested inside the gen'd app client jar. So the attempt to define the class would fail.

param
downloadedAppclientJarFile the app client jar file
return
the class loader

        ClassLoader ldr = new URLClassLoader(downloadedJarURLs, classPathManager.getParentClassLoader());
        return ldr;
    
private static java.lang.String[]prepareJWSArgs(java.lang.String[] args)
Process any command line arguments that are targeted for the Java Web Start ACC main program (this class) as opposed to the regular ACC or the client itself.

param
args the original command line arguments
return
command arguments with any handled by JWS ACC removed

        Vector<String> JWSACCArgs = new Vector<String>();
        Vector<String> nonJWSACCArgs = new Vector<String>();
        for (String arg : args) {
            if (arg.startsWith(JWSACC_ARGUMENT_PREFIX)) {
                JWSACCArgs.add(arg.substring(JWSACC_ARGUMENT_PREFIX.length()));
            } else {
                nonJWSACCArgs.add(arg);
            }
        }
        
        processJWSArgs(JWSACCArgs);
        return nonJWSACCArgs.toArray(new String[nonJWSACCArgs.size()]);
    
private static voidprocessJWSArgs(java.util.Vector args)
Interpret the JWSACC arguments (if any) supplied on the command line.

param
args the JWSACC arguments

        for (String arg : args) {
            if (arg.equals(JWSACC_EXIT_AFTER_RETURN)) {
                exitAfterReturn = true;
            } else if (arg.equals(JWSACC_FORCE_ERROR)) {
                throw new RuntimeException("Forced error - testing only");
            } else if (arg.equals(JWSACC_KEEP_JWS_CLASS_LOADER)) {
                keepJWSClassLoader = true;
            } else if (arg.equals(JWSACC_RUN_ON_SWING_THREAD)) {
                runOnSwingThread = true;
            }
        }
    
public static voidrefreshPolicy(java.io.File policyFile)
Refreshes the current policy object using the contents of the specified file as additional policy.

param
policyFile the file containing additional policy

        int idx = firstFreePolicyIndex();
        URI policyFileURI = policyFile.toURI();
        java.security.Security.setProperty("policy.url." + idx, policyFileURI.toASCIIString());
        Policy p = Policy.getPolicy();
        p.refresh();
    
public voidrun()

//        Main.main(args);
        int exitValue = 0;
        try {
            File downloadedAppclientJarFile = findAppClientFileForJWSLaunch(getClass().getClassLoader());

            URL[] persistenceJarURLs = classPathManager.locatePersistenceJARs();
            
            ClassLoader loader = prepareClassLoader(downloadedAppclientJarFile);

            /*
             *Set a property that the ACC will retrieve during a JWS launch
             *to locate the app client jar file.
             */
            System.setProperty("com.sun.aas.downloaded.appclient.jar", downloadedAppclientJarFile.getAbsolutePath());

            Thread.currentThread().setContextClassLoader(loader);

            /*
             *Use the prepared class loader to load the ACC main method, prepare
             *the arguments to the constructor, and invoke the static main method.
             */
            Constructor constr = null;
            Class mainClass = Class.forName("com.sun.enterprise.appclient.MainWithModuleSupport", true /* initialize */, loader);
            constr = mainClass.getConstructor(
                    new Class[] { String[].class, URL[].class } );
            constr.newInstance(args, persistenceJarURLs);
        } catch(Throwable thr) {
            exitValue = 1;
            /*
             *Display the throwable and stack trace to System.err, then
             *display it to the user using the GUI dialog box.
             */
            System.err.println(rb.getString("jwsacc.errorLaunch"));
            System.err.println(thr.toString());
            thr.printStackTrace();
            ErrorDisplayDialog.showErrors(thr, rb);
        } finally {
            /*
             *If the user has requested, invoke System.exit as soon as the main 
             *method returns.  Do so on the Swing event thread so the ACC
             *main can complete whatever it may be doing.
             */
            if (exitAfterReturn || (exitValue != 0)) {
                Runnable exit = new Runnable() {
                    private int statusValue;
                    public void run() {
                        System.out.printf("Exiting after return from client with status %1$d%n", statusValue);
                        System.exit(statusValue);
                    }
                    
                    public Runnable init(int exitStatus) {
                        statusValue = exitStatus;
                        return this;
                    }
                }.init(exitValue);

                if (runOnSwingThread) {
                    SwingUtilities.invokeLater(exit);
                } else {
                    exit.run();
                }
            }
        }
    
private static voidsetPermissions()

        String JWSACCMainClassName = JWSACCMain.class.getName();
        try {
            /*
             *Get the permissions template and write it to a temporary file.
             */
            String permissionsTemplate = Util.loadResource(JWSACCMain.class, PERMISSIONS_TEMPLATE_NAME);
            
            /*
             *Prepare the grant clauses for the downloaded jars and substitute 
             *those clauses into the policy template.
             */
            StringBuilder grantClauses = new StringBuilder();

            for (URL url : downloadedJarURLs) {
                grantClauses.append(MessageFormat.format(GRANT_CLAUSE_TEMPLATE, url.toExternalForm()));
            }
            
            String substitutedPermissionsTemplate = permissionsTemplate.replace(GRANT_CLAUSES_PROPERTY_EXPR, grantClauses.toString());
            boolean retainTempFiles = Boolean.getBoolean(Main.APPCLIENT_RETAIN_TEMP_FILES_PROPERTYNAME);
            File policyFile = writeTextToTempFile(substitutedPermissionsTemplate, "jwsacc", ".policy", retainTempFiles);

            refreshPolicy(policyFile);
            
        } catch (IOException ioe) {
            throw new RuntimeException("Error loading permissions template", ioe);
        }
    
private static java.io.FilewriteTextToTempFile(java.lang.String content, java.lang.String prefix, java.lang.String suffix, boolean retainTempFiles)
Writes the provided text to a temporary file marked for deletion on exit.

param
the content to be written
param
prefix for the temp file, conforming to the File.createTempFile requirements
param
suffix for the temp file
return
File object for the newly-created temp file
throws
IOException for any errors writing the temporary file
throws
FileNotFoundException if the temp file cannot be opened for any reason

        BufferedWriter wtr = null;
        try {
            File result = File.createTempFile(prefix, suffix);
            if ( ! retainTempFiles) {
                result.deleteOnExit();
            }
            FileOutputStream fos = new FileOutputStream(result);
            wtr = new BufferedWriter(new OutputStreamWriter(fos));
            wtr.write(content);
            wtr.close();
            return result;
        } finally {
            if (wtr != null) {
                wtr.close();
            }
        }