001: /**
002: * EasyBeans
003: * Copyright (C) 2007 Bull S.A.S.
004: * Contact: easybeans@ow2.org
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
019: * USA
020: *
021: * --------------------------------------------------------------------------
022: * $Id: AbsDeployer.java 1970 2007-10-16 11:49:25Z benoitf $
023: * --------------------------------------------------------------------------
024: */package org.ow2.easybeans.deployer;
025:
026: import java.io.File;
027: import java.io.IOException;
028: import java.io.InputStream;
029: import java.lang.reflect.Constructor;
030: import java.lang.reflect.InvocationTargetException;
031: import java.lang.reflect.Method;
032: import java.net.URL;
033: import java.net.URLConnection;
034: import java.util.ArrayList;
035: import java.util.Iterator;
036: import java.util.List;
037:
038: import org.ow2.easybeans.api.EZBContainer;
039: import org.ow2.easybeans.api.EZBContainerException;
040: import org.ow2.easybeans.api.EZBServer;
041: import org.ow2.easybeans.loader.EasyBeansClassLoader;
042: import org.ow2.easybeans.persistence.PersistenceUnitManager;
043: import org.ow2.easybeans.persistence.xml.PersistenceXmlFileAnalyzer;
044: import org.ow2.easybeans.persistence.xml.PersistenceXmlFileAnalyzerException;
045: import org.ow2.easybeans.util.files.FileUtils;
046: import org.ow2.easybeans.util.files.FileUtilsException;
047: import org.ow2.util.ee.deploy.api.archive.ArchiveException;
048: import org.ow2.util.ee.deploy.api.archive.IArchive;
049: import org.ow2.util.ee.deploy.api.deployable.EARDeployable;
050: import org.ow2.util.ee.deploy.api.deployable.EJB3Deployable;
051: import org.ow2.util.ee.deploy.api.deployable.EJBDeployable;
052: import org.ow2.util.ee.deploy.api.deployable.IDeployable;
053: import org.ow2.util.ee.deploy.api.deployable.LibDeployable;
054: import org.ow2.util.ee.deploy.api.deployer.DeployerException;
055: import org.ow2.util.ee.deploy.api.deployer.IDeployer;
056: import org.ow2.util.ee.deploy.impl.archive.ArchiveManager;
057: import org.ow2.util.ee.deploy.impl.deployable.EARDeployableImpl;
058: import org.ow2.util.ee.deploy.impl.helper.DeployableHelper;
059: import org.ow2.util.ee.deploy.impl.helper.DeployableHelperException;
060: import org.ow2.util.log.Log;
061: import org.ow2.util.log.LogFactory;
062:
063: /**
064: * Abstract class that defines common methods for deployer.
065: * @author Florent Benoit
066: */
067: public abstract class AbsDeployer implements IDeployer {
068:
069: /**
070: * Folder to create in tmp folder.
071: */
072: public static final String DEFAULT_FOLDER = "EasyBeans-Deployer";
073:
074: /**
075: * Logger.
076: */
077: private static Log logger = LogFactory.getLog(AbsDeployer.class);
078:
079: /**
080: * Embedded server linked to this deployer.
081: */
082: private EZBServer embedded = null;
083:
084: /**
085: * @return the embedded instance used by this server.
086: */
087: public EZBServer getEmbedded() {
088: return embedded;
089: }
090:
091: /**
092: * Receive Embedded instance for this deployer.
093: * @param embedded the given instance of the embedded server.
094: */
095: public void setEmbedded(final EZBServer embedded) {
096: this .embedded = embedded;
097: }
098:
099: /**
100: * Build and return a classloader for the given EAR.
101: * @param earDeployable the given EAR
102: * @return a classloader
103: * @throws DeployerException if the classloader cannot be built
104: */
105: protected ClassLoader getClassLoaderForEAR(
106: final EARDeployable earDeployable) throws DeployerException {
107: // Get EJBs of this EAR
108: List<EJBDeployable<?>> ejbs = earDeployable.getEJBDeployables();
109:
110: // Get libraries of this EAR
111: List<LibDeployable> libs = earDeployable.getLibDeployables();
112:
113: // Create array of URLs with EJBs + Libraries
114: List<URL> urls = new ArrayList<URL>();
115: for (EJBDeployable<?> ejb : ejbs) {
116: try {
117: urls.add(ejb.getArchive().getURL());
118: } catch (ArchiveException e) {
119: throw new DeployerException(
120: "Cannot get the URL for the Archive '"
121: + ejb.getArchive() + "'.", e);
122: }
123: }
124: for (LibDeployable lib : libs) {
125: try {
126: urls.add(lib.getArchive().getURL());
127: } catch (ArchiveException e) {
128: throw new DeployerException(
129: "Cannot get the URL for the Archive '"
130: + lib.getArchive() + "'.", e);
131:
132: }
133: }
134:
135: // Create classloader with these URLs
136: URL[] arrayURLs = urls.toArray(new URL[urls.size()]);
137: return new EasyBeansClassLoader(arrayURLs, Thread
138: .currentThread().getContextClassLoader());
139: }
140:
141: /**
142: * Gets the persistence unit manager for the given EAR and classloader.
143: * @param earDeployable the ear deployable
144: * @param appClassLoader the classloader used as deployable
145: * @return the given persistence unit manager
146: */
147: protected PersistenceUnitManager getPersistenceUnitManager(
148: final EARDeployable earDeployable,
149: final ClassLoader appClassLoader) {
150: // Analyze libraries to detect persistence archive (only once for now
151: // and for all libraries)
152: // Get libraries of this EAR
153: List<LibDeployable> libs = earDeployable.getLibDeployables();
154: PersistenceUnitManager persistenceUnitManager = null;
155: for (LibDeployable lib : libs) {
156: PersistenceUnitManager builtPersistenceUnitManager = null;
157: try {
158: builtPersistenceUnitManager = PersistenceXmlFileAnalyzer
159: .analyzePersistenceXmlFile(lib.getArchive(),
160: appClassLoader);
161: } catch (PersistenceXmlFileAnalyzerException e) {
162: throw new IllegalStateException(
163: "Failure when analyzing the persistence.xml file",
164: e);
165: }
166:
167: // Existing manager and new manager found
168: if (persistenceUnitManager != null) {
169: if (builtPersistenceUnitManager != null) {
170: // Add the persistence unit infos to the existing
171: // persistence unit manager
172: persistenceUnitManager
173: .addExtraPersistenceUnitInfos(builtPersistenceUnitManager
174: .getPersistenceUnitInfos());
175: }
176: } else {
177: // New persistence manager use the built manager
178: persistenceUnitManager = builtPersistenceUnitManager;
179: }
180: }
181: return persistenceUnitManager;
182: }
183:
184: /**
185: * Gets Archives of the libraries of this EAR.
186: * @param earDeployable the given EAR deployable.
187: * @return list of archives
188: */
189: protected List<IArchive> getLibArchives(
190: final EARDeployable earDeployable) {
191:
192: // Build list
193: List<IArchive> libArchives = new ArrayList<IArchive>();
194:
195: // Get data of all libraries
196: for (LibDeployable lib : earDeployable.getLibDeployables()) {
197: libArchives.add(lib.getArchive());
198: }
199:
200: return libArchives;
201: }
202:
203: /**
204: * Deploy an EJB (called by the deploy method).
205: * @param ejbDeployable a given EJB deployable
206: * @throws DeployerException if the deployment is not done.
207: */
208: protected void deployEJB(final EJBDeployable ejbDeployable)
209: throws DeployerException {
210: logger.info("Deploying {0}", ejbDeployable);
211: EZBContainer container = getEmbedded().createContainer(
212: ejbDeployable.getArchive());
213: try {
214: container.start();
215: } catch (EZBContainerException e) {
216: getEmbedded().removeContainer(container);
217: throw new DeployerException("Cannot deploy the given EJB '"
218: + ejbDeployable + "'.", e);
219: }
220: }
221:
222: /**
223: * Build an instance of the given class.
224: * @param clazz the class to instantiate
225: * @return a new object
226: * @throws DeployerException if the class can't be loaded
227: */
228: protected static Object newInstance(final Class clazz)
229: throws DeployerException {
230: try {
231: return clazz.newInstance();
232: } catch (InstantiationException e) {
233: throw new DeployerException(
234: "Cannot make an instance of the class '" + clazz
235: + "'.", e);
236: } catch (IllegalAccessException e) {
237: throw new DeployerException(
238: "Cannot make an instance of the class '" + clazz
239: + "'.", e);
240: }
241: }
242:
243: /**
244: * Build an instance by using the given constructor and given parameters.
245: * @param constructor the constructor to use
246: * @param parameters the parameters of the given constructor
247: * @return a new object
248: * @throws DeployerException if the class can't be loaded
249: */
250: protected static Object newInstance(final Constructor constructor,
251: final Object... parameters) throws DeployerException {
252: try {
253: return constructor.newInstance(parameters);
254: } catch (IllegalArgumentException e) {
255: throw new DeployerException(
256: "Cannot create a classloader with constructor '"
257: + constructor + "'", e);
258: } catch (InstantiationException e) {
259: throw new DeployerException(
260: "Cannot create a classloader with constructor '"
261: + constructor + "'", e);
262: } catch (IllegalAccessException e) {
263: throw new DeployerException(
264: "Cannot create a classloader with constructor '"
265: + constructor + "'", e);
266: } catch (InvocationTargetException e) {
267: throw new DeployerException(
268: "Cannot create a classloader with constructor '"
269: + constructor + "'", e);
270: }
271: }
272:
273: /**
274: * Load the given class with its given classname.
275: * @param className the name of the class to load
276: * @return the class object
277: * @throws DeployerException if the class can't be loaded
278: */
279: protected static Class loadClass(final String className)
280: throws DeployerException {
281: return loadClass(className, null);
282: }
283:
284: /**
285: * Load the given class with its given classname.
286: * @param className the name of the class to load
287: * @param classLoader the given classloader (or null to use thread context classloader)
288: * @return the class object
289: * @throws DeployerException if the class can't be loaded
290: */
291: protected static Class loadClass(final String className,
292: final ClassLoader classLoader) throws DeployerException {
293: // Load the classr
294: Class clazz = null;
295: try {
296: if (classLoader != null) {
297: clazz = classLoader.loadClass(className);
298: } else {
299: clazz = Thread.currentThread().getContextClassLoader()
300: .loadClass(className);
301: }
302: } catch (ClassNotFoundException e) {
303: throw new DeployerException("Cannot load the class '"
304: + className + "'", e);
305: }
306: return clazz;
307: }
308:
309: /**
310: * Invoke the given method on the given object (null for static method) and
311: * with the given args.
312: * @param method the method to invoke
313: * @param object the object on which the method is invoked
314: * @param args the arguments of the method
315: * @return the result of the invocation
316: * @throws DeployerException if the method is not invoked
317: */
318: protected static Object invoke(final Method method,
319: final Object object, final Object... args)
320: throws DeployerException {
321: try {
322: return method.invoke(object, args);
323: } catch (IllegalArgumentException e) {
324: throw new DeployerException("Cannot invoke the method '"
325: + method + "'", e);
326: } catch (IllegalAccessException e) {
327: throw new DeployerException("Cannot invoke the method '"
328: + method + "'", e);
329: } catch (InvocationTargetException e) {
330: throw new DeployerException("Cannot invoke the method '"
331: + method + "'", e);
332: }
333: }
334:
335: /**
336: * Get the method on the given class with the given method name and the
337: * given parameters.
338: * @param clazz the class on which search the method
339: * @param methodName the name of the method to search
340: * @param parameters the class parameters of the method that is searched
341: * @return the method found
342: * @throws DeployerException if the method is not found
343: */
344: protected static Method getMethod(final Class clazz,
345: final String methodName, final Class... parameters)
346: throws DeployerException {
347: try {
348: return clazz.getMethod(methodName, parameters);
349: } catch (SecurityException e) {
350: throw new DeployerException("Cannot get the Method '"
351: + methodName + "' on the '" + clazz + "' class.", e);
352: } catch (NoSuchMethodException e) {
353: throw new DeployerException("Cannot get the Method '"
354: + methodName + "' on the '" + clazz + "' class.", e);
355: }
356: }
357:
358: /**
359: * Undeploy EJB3s of an EAR (called by the undeploy method).
360: * @param earDeployable a given EAR deployable
361: * @throws DeployerException if the deployment is not done.
362: */
363: protected void undeployEJB3FromEAR(final EARDeployable earDeployable)
364: throws DeployerException {
365: // From which deployable get the containers deployed
366: EARDeployable workingDeployable = earDeployable;
367:
368: // Check if this archive has been unpacked ?
369: EARDeployable unpackedDeployable = earDeployable
370: .getUnpackedDeployable();
371: if (unpackedDeployable != null) {
372: workingDeployable = unpackedDeployable;
373: }
374:
375: // Get Containers of this deployable
376: List<EZBContainer> containers = new ArrayList<EZBContainer>();
377: for (EJB3Deployable ejb3 : workingDeployable
378: .getEJB3Deployables()) {
379: EZBContainer container = getEmbedded().findContainer(
380: ejb3.getArchive());
381: // not found
382: if (container == null) {
383: logger
384: .warn(
385: "No container found for the archive ''{0}'', creation has maybe failed",
386: ejb3.getArchive());
387: continue;
388: }
389: // found, add it
390: containers.add(container);
391: }
392:
393: // Remove all these containers
394: for (EZBContainer container : containers) {
395: // stop it
396: container.stop();
397:
398: // remove it
399: getEmbedded().removeContainer(container);
400: }
401: }
402:
403: /**
404: * Unpack the given archive in a temp folder, then build a local EARDeployable and fill it with submodules and then return it.
405: * @param earDeployable the archive to unpack.
406: * @return a new deployable (which is unpacked)
407: * @throws DeployerException if the EAR can't be unpacked
408: */
409: protected EARDeployable unpackEARDeployable(
410: final EARDeployable earDeployable) throws DeployerException {
411: EARDeployableImpl unpackedDeployable = null;
412:
413: // Build a temp directory (which is root of all unpack)
414: File rootFolder = new File(System.getProperty("java.io.tmpdir")
415: + File.separator + DEFAULT_FOLDER + "-"
416: + System.getProperty("user.name", "default"));
417: rootFolder.mkdirs();
418:
419: // Create EAR directory in this folder (if it is not existing) for unpacking EAR
420: File earFolder = new File(rootFolder, "EAR");
421: earFolder.mkdirs();
422:
423: // Now, create a directory with the name of the given EAR
424: URL earURL = null;
425: String pathURL = null;
426: try {
427: earURL = earDeployable.getArchive().getURL();
428: } catch (ArchiveException e) {
429: throw new DeployerException(
430: "Cannot get the URL for the deployable '"
431: + earDeployable + "'.", e);
432: }
433:
434: // extract filename from the URL for creating the directory
435: pathURL = earURL.getPath();
436: String fileName = pathURL
437: .substring(pathURL.lastIndexOf("/") + 1);
438: File earUnpackedFolder = new File(earFolder, fileName);
439: earUnpackedFolder.mkdir();
440:
441: // Create new deployable
442: IArchive builtArchive = ArchiveManager.getInstance()
443: .getArchive(earUnpackedFolder);
444:
445: // Now, do a dump of each resource of the given EAR and do a dump in the local folder
446: Iterator<URL> itResouces = null;
447: try {
448: itResouces = earDeployable.getArchive().getResources();
449: } catch (ArchiveException e) {
450: throw new DeployerException(
451: "Cannot get the resources on the archive '"
452: + earDeployable.getArchive() + "'.", e);
453: }
454:
455: // Dump all resources
456: List<File> entries = new ArrayList<File>();
457: while (itResouces.hasNext()) {
458: // Dump the input stream of the URL to the local folder
459: URL url = itResouces.next();
460: URLConnection urlConnection = null;
461: try {
462: urlConnection = url.openConnection();
463: } catch (IOException e) {
464: throw new DeployerException(
465: "Cannot open the connection on the URL '" + url
466: + "'.", e);
467: }
468: urlConnection.setDefaultUseCaches(false);
469: InputStream is = null;
470: try {
471: is = urlConnection.getInputStream();
472: } catch (IOException e) {
473: throw new DeployerException(
474: "Cannot get the input stream on the URL connection '"
475: + urlConnection + "'.", e);
476: }
477:
478: // unpack file
479: File entryFile = new File(earUnpackedFolder, url.getPath()
480: .substring(url.getPath().lastIndexOf("!") + 2));
481: logger.debug(
482: "Dumping url ''{0}'' inputstream into ''{1}''",
483: url, entryFile);
484: // Create directory (if some of them are missing)
485: entryFile.getParentFile().mkdirs();
486:
487: // directory, not a file
488: if (url.toString().endsWith("/")) {
489: entryFile.mkdirs();
490: continue;
491: }
492:
493: // Dump the file
494: try {
495: FileUtils.dump(is, entryFile);
496: entries.add(entryFile);
497: } catch (FileUtilsException e) {
498: throw new DeployerException(
499: "Cannot dump the inputstream of url '" + url
500: + "' into file '" + entryFile + "'.", e);
501: } finally {
502: try {
503: is.close();
504: } catch (IOException e) {
505: logger
506: .warn(
507: "Problem when closing the input stream on url ''{0}''",
508: url, e);
509: }
510: }
511: }
512:
513: // Now, analyze each entry of the unpacked EAR
514: unpackedDeployable = new EARDeployableImpl(builtArchive);
515: unpackedDeployable.setOriginalDeployable(earDeployable);
516: earDeployable.setUnpackedDeployable(unpackedDeployable);
517:
518: for (File entryFile : entries) {
519: // Get archive
520: IArchive tmpArchive = ArchiveManager.getInstance()
521: .getArchive(entryFile);
522:
523: // Valid archive, then get the type of the deployable
524: if (tmpArchive != null) {
525: // Analyze the new file
526: IDeployable tmpDeployable = null;
527: try {
528: tmpDeployable = DeployableHelper
529: .getDeployable(tmpArchive);
530: } catch (DeployableHelperException e) {
531: throw new DeployerException(
532: "Cannot get a deployable on the file '"
533: + entryFile + "'.", e);
534: }
535: // Add the deployable into the EAR deployable
536: unpackedDeployable.addDeployable(tmpDeployable);
537: }
538: }
539:
540: return unpackedDeployable;
541: }
542:
543: /**
544: * Checks if the given deployable is deployed or not.
545: * @param deployable test if a given deployable is already deployed.
546: * @return true if it is deployed else false
547: * @throws DeployerException if the undeploy operation fails.
548: */
549: public boolean isDeployed(final IDeployable<?> deployable)
550: throws DeployerException {
551: throw new UnsupportedOperationException("Not yet supported");
552: }
553:
554: /**
555: * Checks if the given deployable is supported by the Deployer.
556: * @param deployable the deployable to be checked
557: * @return true if it is supported, else false.
558: */
559: public boolean supports(final IDeployable<?> deployable) {
560: throw new UnsupportedOperationException("Not yet supported");
561: }
562:
563: }
|