KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > enterprise > appclient > jws > boot > JWSACCMain


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23 package com.sun.enterprise.appclient.jws.boot;
24
25 import com.sun.enterprise.appclient.Main;
26 import com.sun.enterprise.appclient.jws.Util;
27 import java.io.BufferedReader JavaDoc;
28 import java.io.BufferedWriter JavaDoc;
29 import java.io.File JavaDoc;
30 import java.io.FileNotFoundException JavaDoc;
31 import java.io.FileOutputStream JavaDoc;
32 import java.io.IOException JavaDoc;
33 import java.io.InputStream JavaDoc;
34 import java.io.InputStreamReader JavaDoc;
35 import java.io.OutputStreamWriter JavaDoc;
36 import java.lang.reflect.InvocationTargetException JavaDoc;
37 import java.lang.reflect.Method JavaDoc;
38 import java.net.InetAddress JavaDoc;
39 import java.net.MalformedURLException JavaDoc;
40 import java.net.URI JavaDoc;
41 import java.net.URISyntaxException JavaDoc;
42 import java.net.URL JavaDoc;
43 import java.net.URLClassLoader JavaDoc;
44 import java.security.Policy JavaDoc;
45 import java.text.MessageFormat JavaDoc;
46 import java.util.Arrays JavaDoc;
47 import java.util.Vector JavaDoc;
48 import java.util.jar.JarFile JavaDoc;
49 import javax.swing.SwingUtilities JavaDoc;
50
51 /**
52  *Alternate main class for ACC, used when launched by Java Web Start.
53  *<p>
54  *This class assigns security permissions needed by the app server code and
55  *by the app client code, then starts the regular app client container.
56  *<p>
57  *Note that any logic this class executes that requires privileged access
58  *must occur either:
59  *- from a class in the signed jar containing this class, or
60  *- after setPermissions has been invoked.
61  *This is because Java Web Start grants elevated permissions only to the classes
62  *in the appserv-jwsacc-signed.jar at the beginning. Only after setPermissions
63  *has been invoked can other app server-provided code run with all permissions.
64  *
65  * @author tjquinn
66  */

67 public class JWSACCMain implements Runnable JavaDoc {
68     
69 // /** path to a class in one of the app server lib jars downloaded by Java Web Start */
70
// private static final String APPSERVER_LIB_CLASS_NAME = "com.sun.enterprise.server.ApplicationServer";
71

72     /** name of the permissions template */
73     private static final String JavaDoc PERMISSIONS_TEMPLATE_NAME = "jwsclient.policy";
74     
75     /** placeholder used in the policy template to substitute dynamically-generated grant clauses */
76     private static final String JavaDoc GRANT_CLAUSES_PROPERTY_EXPR = "${grant.clauses}";
77     
78     /** line separator */
79     private static final String JavaDoc lineSep = System.getProperty("line.separator");
80     
81     /** the instance of the acc's main class */
82     private static Main accMain = null;
83     
84     /** the user-specified security policy template to use */
85     private static String JavaDoc jwsPolicyTemplateURL = null;
86     
87     /** unpublished command-line argument conveying jwsacc information */
88     private static final String JavaDoc JWSACC_ARGUMENT_PREFIX = "-jwsacc";
89     
90     private static final String JavaDoc JWSACC_EXIT_AFTER_RETURN = "ExitAfterReturn";
91     
92     /** grant clause template for dynamically populating the policy */
93     private static final String JavaDoc GRANT_CLAUSE_TEMPLATE = "grant codeBase \"{0}\" '{'\n" +
94     " permission java.security.AllPermission;\n" +
95         "'}';";
96     
97     /**
98      * request to exit the JVM upon return from the client - should be set (via
99      * the -jwsacc command-line argument value) only for
100      * command-line clients; otherwise it can prematurely end the JVM when
101      * the GUI and other user work is continuing
102      */

103     private static boolean exitAfterReturn = false;
104     
105     /** helper for building the class loader and policy changes */
106     private static ClassPathManager classPathManager = null;
107     
108     /** URLs for downloaded JAR files to be used in the class path */
109     private static URL JavaDoc [] downloadedJarURLs;
110     
111     /** make the arguments passed to the constructor available to the main method */
112     private String JavaDoc args[];
113     
114     /** Creates a new instance of JWSMain */
115     public JWSACCMain(String JavaDoc[] args) {
116         this.args = args;
117     }
118     
119     /**
120      * @param args the command line arguments
121      */

122     public static void main(String JavaDoc[] args) {
123         try {
124             classPathManager = getClassPathManager();
125             args = prepareJWSArgs(args);
126             downloadedJarURLs = classPathManager.locateDownloadedJars();
127         } catch (Throwable JavaDoc thr) {
128             System.err.println("Error locating downloaded jars");
129             thr.printStackTrace();
130             System.exit(1);
131         }
132         
133         /*
134          *Before creating the new instance of the real ACC main, set permissions
135          *so ACC and the user's app client can function properly.
136          */

137         setPermissions();
138
139         /*
140          *Make sure that the main ACC class is instantiated and run in the
141          *same thread. Java Web Start may not normally do so.
142          */

143         JWSACCMain jwsACCMain = new JWSACCMain(args);
144
145         try {
146             SwingUtilities.invokeAndWait(jwsACCMain);
147             /*
148              *Note that the app client is responsible for closing all GUI
149              *components or the JVM will never exit.
150              */

151         } catch (Throwable JavaDoc thr) {
152             System.err.println("Error attempting to launch JWSACCMain.main");
153             thr.printStackTrace(System.err);
154             System.exit(1);
155         }
156             
157     }
158     
159     public void run() {
160 // Main.main(args);
161
int exitValue = 0;
162         try {
163             File JavaDoc downloadedAppclientJarFile = findAppClientFileForJWSLaunch(getClass().getClassLoader());
164
165             ClassLoader JavaDoc loader = prepareClassLoader(downloadedAppclientJarFile);
166
167             /*
168              *Set a property that the ACC will retrieve during a JWS launch
169              *to locate the app client jar file.
170              */

171             System.setProperty("com.sun.aas.downloaded.appclient.jar", downloadedAppclientJarFile.getAbsolutePath());
172
173             Thread.currentThread().setContextClassLoader(loader);
174
175             /*
176              *Use the prepared class loader to load the ACC main method, prepare
177              *the arguments to the constructor, and invoke the static main method.
178              */

179             Method JavaDoc mainMethod = null;
180             Class JavaDoc mainClass = Class.forName("com.sun.enterprise.appclient.Main", false /* initialize */, loader);
181             mainMethod = mainClass.getMethod(
182                     "main",
183                     new Class JavaDoc[] { String JavaDoc[].class } );
184             Object JavaDoc params [] = new Object JavaDoc [1];
185             params[0] = args;
186             mainMethod.invoke(null /* no object -> static method invocation */, params);
187         } catch(Throwable JavaDoc thr) {
188             exitValue = 1;
189             throw new RuntimeException JavaDoc(thr);
190         } finally {
191             /*
192              *If the user has requested, invoke System.exit as soon as the main
193              *method returns. Do so on the Swing event thread so the ACC
194              *main can complete whatever it may be doing.
195              */

196             if (exitAfterReturn) {
197                 SwingUtilities.invokeLater(new Runnable JavaDoc() {
198                     private int statusValue;
199                     public void run() {
200                         System.out.printf("Exiting after return from client with status %1$d%n", statusValue);
201                         System.exit(statusValue);
202                     }
203                     
204                     public Runnable JavaDoc init(int exitStatus) {
205                         statusValue = exitStatus;
206                         return this;
207                     }
208                 }.init(exitValue));
209             }
210         }
211     }
212     
213     /**
214      *Process any command line arguments that are targeted for the
215      *Java Web Start ACC main program (this class) as opposed to the
216      *regular ACC or the client itself.
217      *@param args the original command line arguments
218      *@return command arguments with any handled by JWS ACC removed
219      */

220     private static String JavaDoc[] prepareJWSArgs(String JavaDoc[] args) {
221         Vector JavaDoc<String JavaDoc> JWSACCArgs = new Vector JavaDoc<String JavaDoc>();
222         Vector JavaDoc<String JavaDoc> nonJWSACCArgs = new Vector JavaDoc<String JavaDoc>();
223         for (String JavaDoc arg : args) {
224             if (arg.startsWith(JWSACC_ARGUMENT_PREFIX)) {
225                 JWSACCArgs.add(arg.substring(JWSACC_ARGUMENT_PREFIX.length()));
226             } else {
227                 nonJWSACCArgs.add(arg);
228             }
229         }
230         
231         processJWSArgs(JWSACCArgs);
232         return nonJWSACCArgs.toArray(new String JavaDoc[nonJWSACCArgs.size()]);
233     }
234     
235     /**
236      *Interpret the JWSACC arguments (if any) supplied on the command line.
237      *@param args the JWSACC arguments
238      */

239     private static void processJWSArgs(Vector JavaDoc<String JavaDoc> args) {
240         for (String JavaDoc arg : args) {
241             if (arg.equals(JWSACC_EXIT_AFTER_RETURN)) {
242                 exitAfterReturn = true;
243             }
244         }
245     }
246     
247     private static void setPermissions() {
248         String JavaDoc JWSACCMainClassName = JWSACCMain.class.getName();
249         try {
250             /*
251              *Get the permissions template and write it to a temporary file.
252              */

253             String JavaDoc permissionsTemplate = Util.loadResource(JWSACCMain.class, PERMISSIONS_TEMPLATE_NAME);
254             
255             /*
256              *Prepare the grant clauses for the downloaded jars and substitute
257              *those clauses into the policy template.
258              */

259             StringBuilder JavaDoc grantClauses = new StringBuilder JavaDoc();
260
261             for (URL JavaDoc url : downloadedJarURLs) {
262                 grantClauses.append(MessageFormat.format(GRANT_CLAUSE_TEMPLATE, url.toExternalForm()));
263             }
264             
265             String JavaDoc substitutedPermissionsTemplate = permissionsTemplate.replace(GRANT_CLAUSES_PROPERTY_EXPR, grantClauses.toString());
266             boolean retainTempFiles = Boolean.getBoolean(Main.APPCLIENT_RETAIN_TEMP_FILES_PROPERTYNAME);
267             File JavaDoc policyFile = writeTextToTempFile(substitutedPermissionsTemplate, "jwsacc", ".policy", retainTempFiles);
268
269             refreshPolicy(policyFile);
270             
271         } catch (IOException JavaDoc ioe) {
272             throw new RuntimeException JavaDoc("Error loading permissions template", ioe);
273         }
274     }
275
276     /**
277      *Locates the first free policy.url.x setting.
278      *@return the int value for the first unused policy setting
279      */

280     public static int firstFreePolicyIndex() {
281         int i = 0;
282         String JavaDoc propValue;
283         do {
284             propValue = java.security.Security.getProperty("policy.url." + String.valueOf(++i));
285         } while ((propValue != null) && ( ! propValue.equals("")));
286         
287         return i;
288     }
289     
290     /**
291      *Refreshes the current policy object using the contents of the specified file
292      *as additional policy.
293      *@param policyFile the file containing additional policy
294      */

295     public static void refreshPolicy(File JavaDoc policyFile) {
296         int idx = firstFreePolicyIndex();
297         URI JavaDoc policyFileURI = policyFile.toURI();
298         java.security.Security.setProperty("policy.url." + idx, policyFileURI.toASCIIString());
299         Policy JavaDoc p = Policy.getPolicy();
300         p.refresh();
301     }
302     
303     /**
304      *The methods below are duplicates from the com.sun.enterprise.appclient.jws.Util class.
305      *At the time this class is running, Java Web Start will not yet permit the Util class to
306      *use the elevated permissions. In fact, this class is in the process of granting
307      *those permissions to all app server code. By including the code here, Java Web Start
308      *will permit it to run because this class was loaded from a trusted jar file.
309      */

310
311     /**
312       *Writes the provided text to a temporary file marked for deletion on exit.
313       *@param the content to be written
314       *@param prefix for the temp file, conforming to the File.createTempFile requirements
315       *@param suffix for the temp file
316       *@return File object for the newly-created temp file
317       *@throws IOException for any errors writing the temporary file
318       *@throws FileNotFoundException if the temp file cannot be opened for any reason
319       */

320      private static File JavaDoc writeTextToTempFile(String JavaDoc content, String JavaDoc prefix, String JavaDoc suffix, boolean retainTempFiles) throws IOException JavaDoc, FileNotFoundException JavaDoc {
321         BufferedWriter JavaDoc wtr = null;
322         try {
323             File JavaDoc result = File.createTempFile(prefix, suffix);
324             if ( ! retainTempFiles) {
325                 result.deleteOnExit();
326             }
327             FileOutputStream JavaDoc fos = new FileOutputStream JavaDoc(result);
328             wtr = new BufferedWriter JavaDoc(new OutputStreamWriter JavaDoc(fos));
329             wtr.write(content);
330             wtr.close();
331             return result;
332         } finally {
333             if (wtr != null) {
334                 wtr.close();
335             }
336         }
337     }
338      
339     /**
340      *Create the class loader for loading code from the unsigned downloaded
341      *app server jars.
342      *<p>
343      *During a Java Web Start launch the ACC will be run under this class loader.
344      *Otherwise the JNLPClassLoader will load any stub classes that are
345      *packaged at the top-level of the generated app client jar file. (It can
346      *see them because it downloaded the gen'd app client jar, and therefore
347      *includes the downloaded jar in its class path. This allows it to see the
348      *classes at the top level of the jar but does not automatically let it see
349      *classes in the jars nested within the gen'd app client jar. As a result,
350      *the JNLPClassLoader would be the one to try to define the class for a
351      *web services stub, for instance. But the loader will not be able to find
352      *other classes and interfaces needed to completely define the class -
353      *because these are in the jars nested inside the gen'd app client jar. So
354      *the attempt to define the class would fail.
355      *@param downloadedAppclientJarFile the app client jar file
356      *@return the class loader
357      */

358     private static ClassLoader JavaDoc prepareClassLoader(File JavaDoc downloadedAppclientJarFile) throws IOException JavaDoc, URISyntaxException JavaDoc, ClassNotFoundException JavaDoc, NoSuchMethodException JavaDoc, IllegalAccessException JavaDoc, InvocationTargetException JavaDoc {
359         ClassLoader JavaDoc ldr = new URLClassLoader JavaDoc(downloadedJarURLs, classPathManager.getParentClassLoader());
360         return ldr;
361     }
362     
363     /*
364      *Returns the jar that contains the specified resource.
365      *@param target entry name to look for
366      *@param loader the class loader to use in finding the resource
367      *@return File object for the jar or directory containing the entry
368      */

369     private static File JavaDoc findContainingJar(String JavaDoc target, ClassLoader JavaDoc loader) throws IllegalArgumentException JavaDoc, URISyntaxException JavaDoc, MalformedURLException JavaDoc, IllegalAccessException JavaDoc, InvocationTargetException JavaDoc {
370         /*
371          *Use the specified class loader to find the resource.
372          */

373         URL JavaDoc resourceURL = loader.getResource(target);
374         return classPathManager.findContainingJar(resourceURL);
375     }
376     
377     /**
378      *Locate the app client jar file during a Java Web Start launch.
379      *@param loader the class loader to use in searching for the descriptor entries
380      *@return File object for the client jar file
381      *@throws IllegalArgumentException if the loader finds neither descriptor
382      */

383     private File JavaDoc findAppClientFileForJWSLaunch(ClassLoader JavaDoc loader) throws URISyntaxException JavaDoc, MalformedURLException JavaDoc, IllegalAccessException JavaDoc, InvocationTargetException JavaDoc {
384         /*
385          *The downloaded jar should contain either META-INF/application.xml or
386          *META-INF/application-client.xml. Look for either one and locate the
387          *jar from the URL.
388          */

389         File JavaDoc containingJar = findContainingJar("META-INF/application.xml", loader);
390         if (containingJar == null) {
391             containingJar = findContainingJar("META-INF/application-client.xml", loader);
392         }
393         if (containingJar == null) {
394 // needs i18n
395
// throw new IllegalArgumentException(localStrings.getString("appclient.JWSnoDownloadedDescr"));
396
throw new IllegalArgumentException JavaDoc("Could not locate META-INF/application.xml or META-INF/application-client.xml");
397         }
398         return containingJar;
399     }
400     
401     /**
402      *Return the class path manager appropriate to the current version.
403      *@return the correct type of ClassPathManager
404      */

405     public static ClassPathManager getClassPathManager() throws ClassNotFoundException JavaDoc, NoSuchMethodException JavaDoc {
406         return ClassPathManager.getClassPathManager();
407     }
408 }
409
Popular Tags