KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > easybeans > client > ClientContainer


1 /**
2  * EasyBeans
3  * Copyright (C) 2006 Bull S.A.S.
4  * Contact: easybeans@objectweb.org
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19  * USA
20  *
21  * --------------------------------------------------------------------------
22  * $Id: ClientContainer.java 1026 2006-08-04 14:54:10Z benoitf $
23  * --------------------------------------------------------------------------
24  */

25
26 package org.objectweb.easybeans.client;
27
28 import static org.objectweb.easybeans.util.url.URLUtils.fileToURL2;
29
30 import java.io.File JavaDoc;
31 import java.lang.reflect.InvocationTargetException JavaDoc;
32 import java.lang.reflect.Method JavaDoc;
33 import java.net.URL JavaDoc;
34 import java.net.URLClassLoader JavaDoc;
35 import java.util.ArrayList JavaDoc;
36 import java.util.Arrays JavaDoc;
37 import java.util.HashMap JavaDoc;
38 import java.util.List JavaDoc;
39 import java.util.Map JavaDoc;
40 import java.util.StringTokenizer JavaDoc;
41 import java.util.jar.Attributes JavaDoc;
42 import java.util.jar.JarFile JavaDoc;
43 import java.util.jar.Manifest JavaDoc;
44
45 import javax.naming.Context JavaDoc;
46 import javax.naming.InitialContext JavaDoc;
47 import javax.naming.LinkRef JavaDoc;
48 import javax.naming.NamingException JavaDoc;
49
50 import org.objectweb.carol.util.configuration.ConfigurationRepository;
51 import org.objectweb.easybeans.api.EZBArchive;
52 import org.objectweb.easybeans.client.xml.ApplicationClient;
53 import org.objectweb.easybeans.client.xml.ApplicationClientLoader;
54 import org.objectweb.easybeans.container.archive.ArchiveManager;
55 import org.objectweb.easybeans.deployment.Deployment;
56 import org.objectweb.easybeans.deployment.resolver.JNDIResolver;
57 import org.objectweb.easybeans.deployment.xml.struct.common.EJBRef;
58 import org.objectweb.easybeans.enhancer.EnhancerException;
59 import org.objectweb.easybeans.loader.EasyBeansClassLoader;
60 import org.objectweb.easybeans.log.JLog;
61 import org.objectweb.easybeans.log.JLogFactory;
62 import org.objectweb.easybeans.naming.NamingManager;
63 import org.objectweb.easybeans.util.files.FileUtils;
64 import org.objectweb.easybeans.util.files.FileUtilsException;
65 import org.objectweb.easybeans.util.url.URLUtilsException;
66
67 /**
68  * Defines the class use for the client container This class analyze the ear or
69  * the jar client and launch the client.
70  * @author Florent Benoit
71  */

72 public final class ClientContainer {
73
74     /**
75      * Folder to create in tmp folder.
76      */

77     private static final String JavaDoc DEFAULT_FOLDER = "EasyBeans-Deployer";
78
79     /**
80      * Main class to use to launch the application client.
81      */

82     private String JavaDoc mainClass = null;
83
84     /**
85      * Temporary directory.
86      */

87     private String JavaDoc tmpDir = null;
88
89     /**
90      * Classpath for the application client.
91      */

92     private String JavaDoc classpath = null;
93
94     /**
95      * Arguments used by the client.
96      */

97     private String JavaDoc[] args = null;
98
99     /**
100      * Extra Arguments.
101      */

102     private List JavaDoc<String JavaDoc> appArgs = null;
103
104     /**
105      * URLs resolved in the case of the extension mechanism in the Ear case.
106      */

107     private URL JavaDoc[] extensionsURLs = null;
108
109     /**
110      * Logger.
111      */

112     private JLog logger = JLogFactory.getLog(ClientContainer.class);
113
114
115     /**
116      * Reference to a JNDIResolver.
117      */

118     private JNDIResolver jndiResolver = null;
119
120     /**
121      * Jar client to use (if many).
122      */

123     private String JavaDoc jarClient = null;
124
125     /**
126      * XML Struct representing application-client.xml file.
127      */

128     private ApplicationClient applicationClient = null;
129
130     /**
131      * Constructor for a Client container.
132      * @param args the arguments of the instance of the client container
133      */

134     private ClientContainer(final String JavaDoc[] args) {
135         this.args = args;
136
137         appArgs = new ArrayList JavaDoc<String JavaDoc>();
138     }
139
140     /**
141      * Main method of the Client container.
142      * @param args the arguments of the client container
143      */

144     public static void main(final String JavaDoc[] args) {
145         // Retrieve command line parameters
146
ClientContainer cc = new ClientContainer(args);
147
148         try {
149             cc.start();
150         } catch (InvocationTargetException JavaDoc ite) {
151             Throwable JavaDoc t = ite.getTargetException();
152             String JavaDoc message = t.getMessage();
153             if (t instanceof Error JavaDoc) {
154                 System.err.println("There was the following error : " + message);
155             } else if (t instanceof Exception JavaDoc) {
156                 System.err.println("There was the following exception : " + message);
157             }
158             t.printStackTrace(System.err);
159         } catch (Exception JavaDoc e) {
160             System.err.println("There was the following exception : " + e.getMessage());
161             e.printStackTrace();
162             System.exit(-1);
163         }
164     }
165
166     /**
167      * Start the client container.
168      * @throws Exception if it fails
169      */

170     private void start() throws Exception JavaDoc {
171         analyzeArgs();
172
173         // Get the filename
174
String JavaDoc userArg = null;
175         String JavaDoc fileName = null;
176         boolean fileMode = true;
177
178         try {
179             userArg = appArgs.get(0);
180         } catch (IndexOutOfBoundsException JavaDoc ioobe) {
181             usage();
182             throw new ClientContainerException("You haven't specify a jar, an ear file or class name as argument."
183                     + "See the Usage.");
184         }
185
186         String JavaDoc className = null;
187         // Test if this is an ear or a jar file else it must be a class name
188
if (!(userArg.toLowerCase().endsWith(".jar") || userArg.toLowerCase().endsWith(".ear"))) {
189             className = userArg;
190             fileMode = false;
191         } else {
192             fileMode = true;
193             fileName = userArg;
194         }
195
196         // Build file and test if it exists
197
File JavaDoc clientJarFile = null;
198         if (fileMode) {
199             File JavaDoc argFile = new File JavaDoc(fileName);
200
201             // Unpack and analyze EAR file if it is an ear
202
if (fileName.toLowerCase().endsWith(".ear")) {
203                 clientJarFile = extractAndAnalyzeEar(argFile);
204             } else {
205                 // Client jar is the given file
206
clientJarFile = argFile;
207             }
208         }
209
210         // Carol initialisation (property)
211
ConfigurationRepository.init();
212         System.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.objectweb.carol.jndi.spi.MultiOrbInitialContextFactory");
213         System.setProperty(InitialContext.URL_PKG_PREFIXES , "org.objectweb.easybeans.naming.pkg");
214
215         // Extract Main-Class to use in the jar from the manifest
216
if (fileMode) {
217             Manifest JavaDoc manifest = new JarFile JavaDoc(clientJarFile).getManifest();
218
219             if (manifest == null) {
220                 throw new ClientContainerException("No manifest was found inside the file" + clientJarFile);
221             }
222
223             // Extract attributes
224
Attributes JavaDoc attributes = manifest.getMainAttributes();
225
226             if (attributes == null) {
227                 throw new ClientContainerException("No attributes were found in the manifest of the file '" + clientJarFile
228                         + "'.");
229             }
230             mainClass = attributes.getValue(Attributes.Name.MAIN_CLASS);
231         } else {
232             mainClass = className;
233         }
234
235         // Invoke the client if there is no need of XML parsing
236
if (!fileMode) {
237             ClassLoader JavaDoc clientCL = new URLClassLoader JavaDoc(getUserClasspathUrls());
238             Thread.currentThread().setContextClassLoader(clientCL);
239             invokeClient();
240             return;
241         }
242
243         if (mainClass == null || mainClass.length() == 0) {
244             throw new ClientContainerException("No main class was found inside the Manifest of the file '" + clientJarFile
245                     + "'. This attribute is required to launch the application client.");
246         }
247
248         logger.info("Using Main-Class : {0}", mainClass);
249
250
251         // Convert file to URL
252
URL JavaDoc clientJarURL = null;
253
254         try {
255             clientJarURL = fileToURL2(clientJarFile);
256         } catch (URLUtilsException uue) {
257             throw new ClientContainerException("Error when building an URL with the file '" + clientJarFile + "'.", uue);
258         }
259
260         // Parse xml file (if any)
261
applicationClient = ApplicationClientLoader.loadApplicationClient(clientJarFile);
262
263
264         // Build the urls for the classloader
265
URL JavaDoc[] urlsClient = null;
266
267         // URLs for the classloader
268
if (extensionsURLs != null) {
269             // There were URLs with the extension mechanism in the EAR
270
urlsClient = new URL JavaDoc[extensionsURLs.length + 1];
271
272             for (int i = 0; i < extensionsURLs.length; i++) {
273                 urlsClient[i] = extensionsURLs[i];
274
275                 logger.debug("Adding " + extensionsURLs[i] + " to the urls of the client");
276             }
277
278             urlsClient[extensionsURLs.length] = clientJarURL;
279         } else {
280             logger.debug("Only one url for urls of client");
281
282             // No extension or jar case.
283
urlsClient = new URL JavaDoc[1];
284             urlsClient[0] = clientJarURL;
285         }
286
287         // Build classloader
288
logger.debug("Building classloader with urls {0}", Arrays.asList(urlsClient));
289         EasyBeansClassLoader clientClassloader = new EasyBeansClassLoader(urlsClient,
290                 Thread.currentThread().getContextClassLoader());
291         Thread.currentThread().setContextClassLoader(clientClassloader);
292
293
294         // Build environment of the client.
295
buildENC();
296
297         // Start client
298
invokeClient();
299
300     }
301
302     /**
303      * Start the client on its main class with the thread class loader.
304      * @throws ClassNotFoundException if class is not found
305      * @throws NoSuchMethodException if method (main) is not found
306      * @throws IllegalAccessException if access is illegal
307      * @throws InvocationTargetException if invocation failed
308      * @throws EnhancerException if enhancement fails.
309      */

310     private void invokeClient() throws ClassNotFoundException JavaDoc, NoSuchMethodException JavaDoc, IllegalAccessException JavaDoc,
311             InvocationTargetException JavaDoc, EnhancerException {
312         ClassLoader JavaDoc clientClassloader = Thread.currentThread().getContextClassLoader();
313
314         if (logger.isDebugEnabled()) {
315             if (clientClassloader instanceof URLClassLoader JavaDoc) {
316                 URLClassLoader JavaDoc urlClassLoader = (URLClassLoader JavaDoc) clientClassloader;
317                 URL JavaDoc[] urls = urlClassLoader.getURLs();
318                 logger.debug("URLs of the classloader :");
319                 for (int u = 0; u < urls.length; u++) {
320                     logger.debug("URL[" + u + "] = " + urls[u]);
321                 }
322             }
323         }
324
325
326
327         // Need to enhance client class (for injected resources).
328
List JavaDoc<String JavaDoc> classesToEnhance = new ArrayList JavaDoc<String JavaDoc>();
329         classesToEnhance.add(mainClass.replace(".", "/"));
330         Map JavaDoc<String JavaDoc, Object JavaDoc> map = new HashMap JavaDoc<String JavaDoc, Object JavaDoc>();
331         map.put(JNDIResolver.NAME, jndiResolver);
332         ClientEnhancer.enhance(Thread.currentThread().getContextClassLoader(), classesToEnhance, map);
333
334
335
336         // Invoke client
337
// Launch the "class_to_run" by using our classloader.
338
Class JavaDoc clazz = clientClassloader.loadClass(mainClass);
339         Class JavaDoc[] argList = new Class JavaDoc[] {args.getClass()};
340
341         // First, call injection code
342
Method JavaDoc injectedMeth = clazz.getMethod("injectedByEasyBeans", new Class JavaDoc[] {});
343         try {
344             injectedMeth.invoke(null, new Object JavaDoc[] {});
345         } catch (Exception JavaDoc e) {
346             logger.error("Cannot perform injection on the client", e);
347         }
348
349         // Then, call lifecycle method
350
Method JavaDoc lifeCycleMeth = clazz.getMethod("easyBeansLifeCyclePostConstruct", new Class JavaDoc[] {});
351         try {
352             lifeCycleMeth.invoke(null, new Object JavaDoc[] {});
353         } catch (Exception JavaDoc e) {
354             logger.error("Cannot perform lifecycle init on the client", e);
355         }
356
357
358         Method JavaDoc meth = clazz.getMethod("main", argList);
359
360         // Remove name of the file from arguments
361
String JavaDoc[] newArgs = new String JavaDoc[appArgs.size() - 1];
362         String JavaDoc txtArgs = "";
363
364         for (int i = 0; i < newArgs.length; i++) {
365             newArgs[i] = appArgs.get(i + 1);
366             txtArgs += (newArgs[i] + " ");
367         }
368
369         logger.info("Starting the application client with the arguments '" + txtArgs + "'.");
370
371         logger.info("Starting client...");
372
373         meth.invoke(null, new Object JavaDoc[] {newArgs});
374
375         logger.debug("End of main method");
376
377     }
378
379     /**
380      * Analyze arguments and extract parameters for the client container.
381      * @throws Exception if there is an error when analyzing arguments
382      */

383     private void analyzeArgs() throws Exception JavaDoc {
384         for (int argn = 0; argn < args.length; argn++) {
385             String JavaDoc arg = args[argn];
386
387             try {
388                 if (arg.equals("-tmpDir")) {
389                     tmpDir = args[++argn];
390
391                     continue;
392                 }
393
394                 if (arg.equals("-jarClient")) {
395                     jarClient = args[++argn];
396
397                     continue;
398                 }
399
400                 if (arg.equals("-cp")) {
401                     classpath = args[++argn];
402                     continue;
403                 }
404
405                 if (arg.equals("--help") || arg.equals("-help") || arg.equals("-h") || arg.equals("-?")) {
406                     usage();
407                     System.exit(1);
408                 }
409
410                 // Add argument to the application arguments
411
appArgs.add(arg);
412             } catch (ArrayIndexOutOfBoundsException JavaDoc aioobe) {
413                 // The next argument is not in the array
414
throw new ClientContainerException("A required parameter was missing after the argument" + arg);
415             }
416         }
417     }
418
419     /**
420      * Print the usage of this client.
421      */

422     private void usage() {
423         System.out.println("Usage of this client :");
424         System.out.println("-------------------------------------------------------------------");
425         System.out.println("java -jar client.jar <client.jar|app.ear|className> [options]");
426         System.out.println("-------------------------------------------------------------------");
427         System.out.println(" -jarClient : Specify the client jar to use of the ear if many.");
428         System.out.println(" -tmpDir : Specify the temp directory where unpack the ear.");
429         System.out.println(" -cp : Specify the classpath to use for the jar client.");
430         System.out.println("-------------------------------------------------------------------");
431         System.out.println(" --help : Display this help.");
432         System.out.println(" -help : Display this help.");
433         System.out.println(" -h : Display this help.");
434         System.out.println(" -? : Display this help.");
435         System.out.println("-------------------------------------------------------------------");
436     }
437
438     /**
439      * Extract the client of an ear and analyze ear too.
440      * @param earFile ear to be analyzed
441      * @return the file of the client which was extracted
442      * @throws Exception if the analyze and/or extract fails
443      */

444     private File JavaDoc extractAndAnalyzeEar(final File JavaDoc earFile) throws Exception JavaDoc {
445
446         URL JavaDoc earUrl = null;
447
448         try {
449             earUrl = fileToURL2(earFile);
450         } catch (URLUtilsException uue) {
451             throw new ClientContainerException("Can not build an url with the filename '" + earFile + "'.", uue);
452         }
453
454         // Create classLoader
455
URL JavaDoc[] arrURL = new URL JavaDoc[1];
456         arrURL[0] = earUrl;
457
458         // Temporary directory
459
String JavaDoc tempDir = null;
460
461         if (tmpDir != null) {
462             // use specific directory
463
tempDir = tmpDir;
464             logger.debug("Use your specified temp directory '" + tempDir + "'.");
465         } else {
466             // use default
467
tempDir = System.getProperty("java.io.tmpdir");
468         }
469
470         logger.debug("Using temp directory {0}", tempDir);
471
472         // Can we write to ?
473
File JavaDoc tmpFileDir = new File JavaDoc(tempDir);
474
475         if (!tmpFileDir.exists() || !tmpFileDir.isDirectory()) {
476             throw new ClientContainerException("The temp directory '" + tempDir + "' doesn't exist or is not a directory.");
477         }
478
479         if (!tmpFileDir.canWrite()) {
480             throw new ClientContainerException("Can not write to the temporary directory '" + tempDir + "'.");
481         }
482
483         logger.info("Ear file = {0}", earFile);
484         // Unpack the ear file and get the unpacked dir
485
JarFile JavaDoc earJarFile = new JarFile JavaDoc(earFile);
486         File JavaDoc rootFolder = new File JavaDoc(System.getProperty("java.io.tmpdir") + File.separator + System.getProperty("user.name")
487                 + File.separator + DEFAULT_FOLDER);
488         rootFolder.mkdirs();
489
490         File JavaDoc tmpFolder = new File JavaDoc(rootFolder, "TMP");
491         tmpFolder.mkdirs();
492         File JavaDoc file = new File JavaDoc(tmpFolder, earFile.getName() + ".new");
493
494         try {
495             FileUtils.unpack(earJarFile, file);
496         } catch (FileUtilsException e) {
497             throw new ClientContainerException("Cannot unpack '" + earJarFile + "'.", e);
498         }
499
500         File JavaDoc fClient = null;
501
502         jndiResolver = new JNDIResolver();
503
504         File JavaDoc clientFile = null;
505         File JavaDoc[] files = file.listFiles();
506         if (files != null) {
507             if (jarClient != null) {
508                 int f = 0;
509                 File JavaDoc ff = null;
510                 boolean found = false;
511
512                 while (f < files.length && !found) {
513                     ff = files[f];
514
515                     if (ff.getPath().endsWith(jarClient)) {
516                         found = true;
517                         clientFile = ff;
518                         logger.info("Found a matching client with the name {0}", ff);
519                     }
520
521                     f++;
522                 }
523
524                 if (!found) {
525                     throw new ClientContainerException("No client with the name '" + jarClient
526                             + "' was found in this Ear file");
527                 }
528             }
529
530             for (File JavaDoc f : files) {
531                 if (f.getName().toLowerCase().endsWith("_client.jar") && clientFile == null) {
532                     clientFile = f;
533                 } else if (f.getName().toLowerCase().endsWith(".ear")) {
534                     // ear, ignore
535
continue;
536                 } else {
537                     EZBArchive archive = ArchiveManager.getInstance().getArchive(f);
538                     Deployment dep = new Deployment(archive);
539                     dep.analyze();
540                     jndiResolver.addDeployment(dep);
541                 }
542             }
543         }
544
545         logger.debug("Resolver =" + jndiResolver);
546
547         if (clientFile == null) {
548             throw new IllegalStateException JavaDoc("No client found");
549         }
550
551         // Take found or first found
552
fClient = clientFile;
553
554         logger.info("Use the application client '" + fClient + "' of the Ear '" + earUrl + "'.");
555
556         return fClient;
557     }
558
559     /**
560      * Gets the URL of user classpath (can be empty).
561      * @return URL of user classpath (-cp arg)
562      */

563     private URL JavaDoc[] getUserClasspathUrls() {
564         if (classpath == null) {
565             return new URL JavaDoc[0];
566         }
567         String JavaDoc sep = File.pathSeparator;
568         List JavaDoc<URL JavaDoc> clUser = new ArrayList JavaDoc<URL JavaDoc>();
569         StringTokenizer JavaDoc tokenizer = new StringTokenizer JavaDoc(classpath, sep);
570         while (tokenizer.hasMoreTokens()) {
571             File JavaDoc file = new File JavaDoc(tokenizer.nextToken());
572             try {
573                 clUser.add(fileToURL2(file));
574             } catch (URLUtilsException uue) {
575                 logger.warn("Cannot transform to URL the file : '" + file + "'", uue);
576             }
577         }
578         return clUser.toArray(new URL JavaDoc[0]);
579     }
580
581     /**
582      * Build ENC environment used by this client.
583      * @throws ClientContainerException if the ENC environment is not built.
584      */

585     private void buildENC() throws ClientContainerException {
586
587         // Get NamingManager reference
588
NamingManager namingManager = null;
589         try {
590             namingManager = NamingManager.getInstance();
591         } catch (NamingException JavaDoc e) {
592             throw new ClientContainerException("Cannot get a reference on the naming manager.", e);
593         }
594
595         Context JavaDoc javaCtx = null;
596         // create env
597
try {
598             javaCtx = namingManager.createEnvironmentContext("client");
599         } catch (NamingException JavaDoc e) {
600             throw new ClientContainerException("Cannot build an environment context", e);
601        }
602
603         Context JavaDoc envCtx;
604         try {
605             envCtx = javaCtx.createSubcontext("comp/env");
606         } catch (NamingException JavaDoc e) {
607             throw new ClientContainerException("Cannot create subcontext comp/env", e);
608         }
609
610         // register environment for this client.
611
namingManager.setClientContainerComponentContext(javaCtx);
612
613         // add ejb-ref
614
if (applicationClient != null) {
615             for (EJBRef ejbRef : applicationClient.getEJBRefs()) {
616                 //get name
617
String JavaDoc ejbRefName = ejbRef.getEjbRefName();
618                 // ejb-link
619
String JavaDoc ejbLink = ejbRef.getEjbLink();
620
621                 // interface
622
String JavaDoc itfName = ejbRef.getRemote();
623
624                 // Resolve reference
625
String JavaDoc jndiName = jndiResolver.getJndiNameInterface(itfName, ejbLink);
626
627                 // bind reference
628
try {
629                     logger.debug("Binding ejb-ref-name {0} with jndi-name {1}", ejbRefName, jndiName);
630                     envCtx.bind(ejbRefName, new LinkRef JavaDoc(jndiName));
631                 } catch (NamingException JavaDoc e) {
632                     throw new ClientContainerException("Cannot bind name '" + ejbRefName + "' in java:comp/env", e);
633                 }
634             }
635         }
636     }
637
638 }
639
Popular Tags