001: /**
002: * JOnAS: Java(TM) Open Application Server
003: * Copyright (C) 1999-2004 Bull S.A.
004: * Contact: jonas-team@objectweb.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: * Initial developer(s): Ludovic BERT & Florent BENOIT
022: * --------------------------------------------------------------------------
023: * $Id: WebDeploymentDescManager.java 7467 2005-10-04 12:53:14Z sauthieg $
024: * --------------------------------------------------------------------------
025: */package org.objectweb.jonas_web.deployment.lib;
026:
027: import java.io.File;
028: import java.io.FileInputStream;
029: import java.io.IOException;
030: import java.io.InputStream;
031: import java.io.InputStreamReader;
032: import java.io.Reader;
033: import java.net.MalformedURLException;
034: import java.net.URL;
035: import java.net.URLClassLoader;
036: import java.util.Enumeration;
037: import java.util.Hashtable;
038: import java.util.List;
039: import java.util.StringTokenizer;
040: import java.util.jar.JarFile;
041: import java.util.zip.ZipEntry;
042:
043: import org.objectweb.jonas_ejb.deployment.lib.EjbDeploymentDescManager;
044:
045: import org.objectweb.jonas_lib.deployment.api.DeploymentDescException;
046: import org.objectweb.jonas_lib.deployment.api.EjbLocalRefDesc;
047: import org.objectweb.jonas_lib.deployment.api.EjbRefDesc;
048: import org.objectweb.jonas_lib.deployment.api.MessageDestinationRefDesc;
049: import org.objectweb.jonas_lib.deployment.digester.JDigester;
050: import org.objectweb.jonas_lib.deployment.lib.AbsDeploymentDescManager;
051: import org.objectweb.jonas_lib.deployment.xml.JonasMessageDestination;
052:
053: import org.objectweb.jonas_web.deployment.api.JonasWebAppDTDs;
054: import org.objectweb.jonas_web.deployment.api.JonasWebAppSchemas;
055: import org.objectweb.jonas_web.deployment.api.WebAppDTDs;
056: import org.objectweb.jonas_web.deployment.api.WebAppSchemas;
057: import org.objectweb.jonas_web.deployment.api.WebContainerDeploymentDesc;
058: import org.objectweb.jonas_web.deployment.api.WebContainerDeploymentDescException;
059: import org.objectweb.jonas_web.deployment.rules.JonasWebAppRuleSet;
060: import org.objectweb.jonas_web.deployment.rules.WebAppRuleSet;
061: import org.objectweb.jonas_web.deployment.xml.JonasWebApp;
062: import org.objectweb.jonas_web.deployment.xml.WebApp;
063:
064: import org.objectweb.jonas_ws.deployment.api.PortComponentDesc;
065: import org.objectweb.jonas_ws.deployment.api.PortComponentRefDesc;
066: import org.objectweb.jonas_ws.deployment.api.ServiceRefDesc;
067: import org.objectweb.jonas_ws.deployment.api.WSDeploymentDescException;
068: import org.objectweb.jonas_ws.deployment.lib.WSDeploymentDescManager;
069:
070: import org.objectweb.jonas.common.Log;
071:
072: import org.objectweb.util.monolog.api.BasicLevel;
073: import org.objectweb.util.monolog.api.Logger;
074:
075: /**
076: * This class provide a way for managing the WebContainerDeploymentDesc. Note
077: * that there is an intance of the WebDeploymentDescManager on each JOnAS
078: * server.
079: * @author Ludovic Bert
080: * @author Florent Benoit
081: */
082: public class WebDeploymentDescManager extends AbsDeploymentDescManager {
083:
084: /**
085: * The path to the web.xml file.
086: */
087: public static final String WEB_FILE_NAME = "WEB-INF/web.xml";
088:
089: /**
090: * The path to the jonas-web.xml file.
091: */
092: public static final String JONAS_WEB_FILE_NAME = "WEB-INF/jonas-web.xml";
093:
094: /**
095: * Flag for parser validation
096: */
097: private static boolean parsingWithValidation = true;
098:
099: /**
100: * Digester use to parse web.xml
101: */
102: private static JDigester webAppDigester = null;
103:
104: /**
105: * Digester use to parse jonas-web.xml
106: */
107: private static JDigester jonasWebAppDigester = null;
108:
109: /**
110: * Rules to parse the web.xml
111: */
112: private static WebAppRuleSet webAppRuleSet = new WebAppRuleSet();
113:
114: /**
115: * Rules to parse the jonas-web.xml
116: */
117: private static JonasWebAppRuleSet jonasWebAppRuleSet = new JonasWebAppRuleSet();
118:
119: /**
120: * The unique instance of the WebDeploymentDescManager.
121: */
122: private static WebDeploymentDescManager unique;
123:
124: /**
125: * Reference on the EjbDeploymentDescManager.
126: */
127: private EjbDeploymentDescManager ejbDDManager = null;
128:
129: /**
130: * Reference on the WSDeploymentDescManager.
131: */
132: private WSDeploymentDescManager wsDDManager = null;
133:
134: /**
135: * logger
136: */
137: private static Logger logger = Log.getLogger(Log.JONAS_WEB_PREFIX);
138:
139: /** The cache used when static getDeploymentDesc are called (WsGen case) */
140: private static Hashtable staticCache = new Hashtable();
141:
142: /**
143: * Contructs a unique new WebDeploymentDescManager.
144: */
145: private WebDeploymentDescManager() {
146: ejbDDManager = EjbDeploymentDescManager.getInstance();
147: earCLAltDDBindings = new Hashtable();
148: }
149:
150: /**
151: * Associate a ear classLoader to an hashtable which contains Association
152: * between Urls of wars and their optional alt-dd
153: */
154: private Hashtable earCLAltDDBindings = null;
155:
156: /**
157: * Get an instance of the WebDeploymentDescManager.
158: * @return the instance of the WebDeploymentDescManager.
159: */
160: public static WebDeploymentDescManager getInstance() {
161: if (unique == null) {
162: unique = new WebDeploymentDescManager();
163: }
164: return unique;
165: }
166:
167: /**
168: * Get the specified web deployment descriptor.
169: * @param url the url where to load xml deployment descriptors.
170: * @param loaderForCls classloader used to load web classes.
171: * @param earLoader the ear classloader.
172: * @return WebContainerDeploymentDesc the web deployment descriptor.
173: * @throws DeploymentDescException when WebContainerDeploymentDesc cannot be
174: * created with the given files.
175: */
176: public WebContainerDeploymentDesc getDeploymentDesc(URL url,
177: ClassLoader loaderForCls, ClassLoader earLoader)
178: throws DeploymentDescException {
179:
180: // load an instance of the WebService Manager
181: if (wsDDManager == null) {
182: wsDDManager = WSDeploymentDescManager.getInstance();
183: }
184:
185: // Check if the war exists ...
186: if (!new File(url.getFile()).exists()) {
187: String err = "Cannot get the deployment descriptor for ";
188: err = err + "'" + url.getFile()
189: + "'. The file doesn't exist.";
190: throw new WebContainerDeploymentDescException(err);
191: }
192:
193: //url used to load an alternate DDesc in the EAR case
194: URL altDDUrl = null;
195:
196: //check if it's an Ear case or not
197: Hashtable urlAltddBindings = null;
198: if (earLoader != null) {
199: //Mapping ?
200: urlAltddBindings = (Hashtable) earCLAltDDBindings
201: .get(earLoader);
202: if (urlAltddBindings == null) {
203: //If there is no mapping, the setAltDD function was badly
204: // called
205: String err = "Cannot find if there is alt-dd for '"
206: + url.getFile()
207: + "', the setAltDD function was badly called";
208: throw new WebContainerDeploymentDescException(err);
209: }
210: //Now we can get the optional alt-dd url file
211: altDDUrl = (URL) urlAltddBindings.get(url);
212: }
213:
214: // ... and get the instance of the WebContainerDeploymentDesc.
215: //If there is an alternate url for the web.xml, call the method with
216: // this param.
217: WebContainerDeploymentDesc webDD = null;
218: try {
219: if (altDDUrl != null) {
220: webDD = getInstance(url.getFile(), loaderForCls,
221: altDDUrl.getFile());
222: } else {
223: webDD = getInstance(url.getFile(), loaderForCls);
224: }
225: } catch (DeploymentDescException dde) {
226: throw new WebContainerDeploymentDescException(dde);
227: }
228:
229: // Resolve the ejb-link for ejb-ref
230: EjbRefDesc[] ejbRef = webDD.getEjbRefDesc();
231: for (int i = 0; i < ejbRef.length; i++) {
232: if (ejbRef[i].getJndiName() == null) {
233: String ejbLink = ejbRef[i].getEjbLink();
234: String ejbRefType = ejbRef[i].getEjbRefType();
235: if (ejbLink != null) {
236: if (earLoader == null) {
237: throw new WebContainerDeploymentDescException(
238: "Ejb-link is not authorized from a single war. The war must be in an ear.");
239: } else {
240: String jndiName = getJndiName(url, ejbLink,
241: earLoader, ejbRefType, true);
242: ejbRef[i].setJndiName(jndiName);
243: }
244: }
245: }
246: }
247:
248: // Resolve the ejb-link for ejb-local-ref
249: EjbLocalRefDesc[] ejbLocalRef = webDD.getEjbLocalRefDesc();
250: for (int i = 0; i < ejbLocalRef.length; i++) {
251: String ejblink = ejbLocalRef[i].getEjbLink();
252: if (earLoader == null) {
253: throw new WebContainerDeploymentDescException(
254: "Ejb-link is not authorized from a single war. The war must be in an ear.");
255: }
256: String ejbRefType = ejbLocalRef[i].getEjbRefType();
257: String ejbName = getJndiName(url, ejblink, earLoader,
258: ejbRefType, false);
259: ejbLocalRef[i].setJndiLocalName(ejbName);
260: }
261:
262: // Resolve the port-component-link for service-ref
263: ServiceRefDesc[] serviceRef = webDD.getServiceRefDesc();
264:
265: for (int i = 0; i < serviceRef.length; i++) {
266:
267: List pcRefs = serviceRef[i].getPortComponentRefs();
268: for (int j = 0; j < pcRefs.size(); j++) {
269: // for each service portComponents : resolve links
270: PortComponentRefDesc pcr = (PortComponentRefDesc) pcRefs
271: .get(j);
272: String pclink = pcr.getPortComponentLink();
273: if (pclink != null) {
274: // a pc link is defined, we resolve it
275: PortComponentDesc pcDesc = getPCDesc(url, pclink,
276: loaderForCls, earLoader);
277: pcr.setPortComponentDesc(pcDesc);
278: }
279: }
280: }
281:
282: // Resolve the message-destination-link for message-destination-ref
283: MessageDestinationRefDesc[] mdRef = webDD
284: .getMessageDestinationRefDesc();
285: for (int i = 0; i < mdRef.length; i++) {
286: if (mdRef[i].getJndiName() == null) {
287: String jndiName = mdRef[i].getJndiName();
288: String mdLink = mdRef[i].getMessageDestinationLink();
289: String mdType = mdRef[i].getMessageDestinationType();
290: String mdUsage = mdRef[i].getMessageDestinationUsage();
291: if (mdLink != null) {
292: if (earLoader == null) {
293: throw new WebContainerDeploymentDescException(
294: "Message-destination-link is not authorized from a single client jar. The client jar must be in an ear.");
295: } else {
296: String mdName = getMDJndiName(url, mdLink,
297: mdType, mdUsage, earLoader);
298: mdRef[i].setJndiName(jndiName);
299: }
300: }
301: }
302: }
303:
304: return webDD;
305: }
306:
307: /**
308: * Return the port component desc from the pcLink string. pcLink format :
309: * filename.[jar or war]#portComponentName in the same Ear File
310: * @param warURL the url of the war being parsed. This is needed because
311: * pcLink is relative. With the url and the pcLink, we can know where
312: * the file is locate.
313: * @param pcLink the pcLink tag of an port-component-ref.
314: * @param earLoader the classloader of the ear.
315: * @param moduleLoader classlaoder of the current module
316: * @return the pcLink portComponent.
317: * @throws WSDeploymentDescException when it failed
318: */
319: private PortComponentDesc getPCDesc(URL warURL, String pcLink,
320: ClassLoader moduleLoader, ClassLoader earLoader)
321: throws WSDeploymentDescException {
322:
323: // now ask WS Manager for port-component-desc
324: return wsDDManager.getPortComponentDesc(warURL, pcLink,
325: moduleLoader, earLoader);
326: }
327:
328: /**
329: * Return the JNDI name from the ejbLink string. ejbLink format :
330: * filename.jar#beanName in the same Ear File beanName in the same ejb-jar
331: * file.
332: * @param warURL the url of the war being parsed. This is needed because
333: * ejbLink is relative. With the url and the ejbLink, we can know
334: * where the file is locate.
335: * @param ejbLink the ejbLink tag of an ejb-ref.
336: * @param earLoader the classloader of the ear.
337: * @param ejbType the type of the referenced ejb in the ejb-ref tag.
338: * @param isEjbRef true if the jndi name to resolve is an ejb-ref
339: * @return the JNDI name if found, null otherwise
340: * @throws DeploymentDescException when it failed
341: */
342: private String getJndiName(URL warURL, String ejbLink,
343: ClassLoader earLoader, String ejbType, boolean isEjbRef)
344: throws DeploymentDescException {
345:
346: // Now ask EJB deployment Desc manager :
347: return ejbDDManager.getJndiName(warURL, ejbLink, earLoader,
348: ejbType, null, isEjbRef);
349: }
350:
351: /**
352: * Return the JNDI name from the mdLink string. mdLink format :
353: * filename.jar#mdName in the same Ear File
354: * @param warURL the url of the jar being parsed. This is needed because
355: * mdLink is relative. With the url and the mdLink, we can know where
356: * the file is locate.
357: * @param mdLink the mdLink tag of a message-destination-ref
358: * @param mdType the type of the referenced mdb in the
359: * message-destination-ref tag.
360: * @param mdUsage the usage of the referenced mdb in the
361: * message-destination-ref tag.
362: * @param earLoader the classloader of the ear.
363: * @return the JNDI name if found, null otherwise
364: * @throws WebContainerDeploymentDescException when it failed
365: */
366: private String getMDJndiName(URL warURL, String mdLink,
367: String mdType, String mdUsage, ClassLoader earLoader)
368: throws WebContainerDeploymentDescException {
369:
370: // Extract from the mdb link
371: // - the name of the file
372: // - the name of the destination
373: String ejbJarLink = null;
374: String destNameLink = null;
375: org.objectweb.jonas_ejb.deployment.api.DeploymentDesc dd = null;
376:
377: // Check the format of the ejb-link. It must contains .jar#
378: if (mdLink.toLowerCase().indexOf(".jar#") == -1) {
379: String err = "Message-destination-link "
380: + mdLink
381: + " has a bad format. Correct format : filename.jar#messageDestinationName";
382: throw new WebContainerDeploymentDescException(err);
383: }
384:
385: StringTokenizer st = new StringTokenizer(mdLink, LINK_SEPARATOR);
386:
387: // We must have only two elements after this step, one for the fileName
388: // before the # and the name of the message-destination after the # char
389: if (st.countTokens() != 2 || mdLink.startsWith(LINK_SEPARATOR)
390: || mdLink.endsWith(LINK_SEPARATOR)) {
391:
392: String err = "Message-destination-link "
393: + mdLink
394: + " has a bad format. Correct format : filename.jar#messageDestinationName.";
395: throw new WebContainerDeploymentDescException(err);
396: }
397:
398: //Get the token
399: ejbJarLink = st.nextToken();
400: destNameLink = st.nextToken();
401:
402: //Check if ejbJarLink is a jar or not
403: if (!ejbJarLink.endsWith(".jar")) {
404: String err = "Ejbjar filename "
405: + ejbJarLink
406: + " from the message-destination-link "
407: + mdLink
408: + " has a bad format. Correct format : filename.jar";
409: throw new WebContainerDeploymentDescException(err);
410: }
411:
412: // Now construct the URL from the absolute path from the url warURL and
413: // the relative path from ejbJarLink
414: URL ejbJarLinkUrl = null;
415: try {
416: ejbJarLinkUrl = new File(new File(warURL.getFile())
417: .getParent()
418: + File.separator + ejbJarLink).getCanonicalFile()
419: .toURL();
420: } catch (MalformedURLException mue) {
421: String err = "Error when creating an url for the ejb jar filename. Error :"
422: + mue.getMessage();
423: throw new WebContainerDeploymentDescException(err);
424: } catch (IOException ioe) {
425: String err = "Error when creating/accessing a file. Error :"
426: + ioe.getMessage();
427: throw new WebContainerDeploymentDescException(err);
428: }
429:
430: // Check if the jar exist.
431: if (!new File(ejbJarLinkUrl.getFile()).exists()) {
432: String err = "Cannot get the deployment descriptor for '"
433: + ejbJarLinkUrl.getFile()
434: + "'. The file doesn't exist.";
435: throw new WebContainerDeploymentDescException(err);
436: }
437:
438: // We've got the url
439: // Now, We can ask the Deployment Descriptor of this url
440: URL[] ddURL = new URL[1];
441: ddURL[0] = ejbJarLinkUrl;
442: URLClassLoader loaderForClsEjb = new URLClassLoader(ddURL,
443: earLoader);
444: try {
445: dd = ejbDDManager.getDeploymentDesc(ejbJarLinkUrl,
446: loaderForClsEjb, earLoader);
447: } catch (DeploymentDescException e) {
448: String err = "Cannot get the deployment descriptor for '"
449: + ejbJarLinkUrl.getFile() + "'.";
450: throw new WebContainerDeploymentDescException(err, e);
451: }
452:
453: JonasMessageDestination md = dd
454: .getJonasMessageDestination(mdLink);
455:
456: if (md == null) {
457: String err = "No message-destination-link was found for '"
458: + mdLink + "' in the file " + warURL.getFile()
459: + " specified.";
460: throw new WebContainerDeploymentDescException(err);
461: }
462:
463: //Check if the type & usage of the message-destination-ref is correct.
464: //For now checkTypeUsage(warURL, mdType, mdUsage, dd);
465:
466: return md.getJndiName();
467: }
468:
469: /**
470: * Make a cleanup of the cache of deployment descriptor. This method must be
471: * invoked after the ear deployment by the EAR service.
472: * @param earClassLoader the ClassLoader of the ear application to remove
473: * from the cache.
474: */
475: public void removeCache(ClassLoader earClassLoader) {
476: //Remove the altdd mapping
477: earCLAltDDBindings.remove(earClassLoader);
478:
479: //Then remove the cache of the ejb dd manager
480: ejbDDManager.removeCache(earClassLoader);
481: }
482:
483: /**
484: * Set the alt deployment desc which are used instead of the web.xml file
485: * which is in the war file. The alt-dd tag is in the application.xml file
486: * of the ear files and is used ony in the EAR case. ie : deployment of wars
487: * packaged into EAR applications. alt-dd tag is optionnal
488: * @param earClassLoader the ear classloader which is used for mapped the
489: * URLs of the wars to the Alt dd.
490: * @param urls the urls of the wars
491: * @param altDDs the alt-dd name for the specified war URLs
492: */
493: public void setAltDD(ClassLoader earClassLoader, URL[] urls,
494: URL[] altDDs) {
495:
496: //Associate an url to a altDD url
497: Hashtable urlAltddBindings = new Hashtable();
498:
499: //Fill the hashtable for each url
500: for (int i = 0; i < urls.length; i++) {
501: if (altDDs[i] != null) {
502: urlAltddBindings.put(urls[i], altDDs[i]);
503: }
504: }
505:
506: //Bind the hashtable
507: earCLAltDDBindings.put(earClassLoader, urlAltddBindings);
508:
509: }
510:
511: /**
512: * Get the size of the cache (number of entries in the cache). This method
513: * is used only for the tests.
514: * @return the size of the cache (number of entries in the cache).
515: */
516: public int getCacheSize() {
517: int bufferSize = 0;
518:
519: Enumeration classLoaders = earCLAltDDBindings.keys();
520: while (classLoaders.hasMoreElements()) {
521: ClassLoader loader = (ClassLoader) classLoaders
522: .nextElement();
523: Hashtable hashtab = (Hashtable) earCLAltDDBindings
524: .get(loader);
525: bufferSize = bufferSize + hashtab.size();
526: }
527:
528: return bufferSize;
529: }
530:
531: /**
532: * Get the specified web deployment descriptor.
533: * @param filename the filename where to load xml deployment descriptors.
534: * @param loader classloader used to load web classes.
535: * @return WebContainerDeploymentDesc the web deployment descriptor.
536: * @throws WebContainerDeploymentDescException when
537: * WebContainerDeploymentDesc cannot be created with the given
538: * files.
539: */
540: public static WebContainerDeploymentDesc getDeploymentDesc(
541: String filename, ClassLoader loader)
542: throws WebContainerDeploymentDescException {
543:
544: WebContainerDeploymentDesc wcdd = null;
545: // if Desc already parsed
546: if (staticCache.containsKey(filename)) {
547: wcdd = (WebContainerDeploymentDesc) staticCache
548: .get(filename);
549: } else {
550: // Check if the war exists ...
551: if (!new File(filename).exists()) {
552: String err = "Cannot get the deployment descriptor for ";
553: err += "'" + filename + "'. The file doesn't exist.";
554: throw new WebContainerDeploymentDescException(err);
555: }
556: // get the DeploymentDesc
557: try {
558: wcdd = getInstance(filename, loader);
559: } catch (DeploymentDescException dde) {
560: throw new WebContainerDeploymentDescException(dde);
561: }
562: // put in cache
563: staticCache.put(filename, wcdd);
564: }
565:
566: return wcdd;
567: }
568:
569: /**
570: * Get an instance of a WEB deployment descriptor by parsing the web.xml and
571: * jonas-web.xml deployment descriptors.
572: * @param warFileName the fileName of the war file for the deployment
573: * descriptors.
574: * @param classLoaderForCls the classloader for the classes.
575: * @param altWebXmlFilename the fileName to the web.xml for the alt-dd tag
576: * in the Ear Case. This is used for specify an alternate DDesc file.
577: * @return a WEB deployment descriptor by parsing the web.xml and
578: * jonas-web.xml deployment descriptors.
579: * @throws DeploymentDescException if the deployment descriptors are
580: * corrupted.
581: */
582: public static WebContainerDeploymentDesc getInstance(
583: String warFileName, ClassLoader classLoaderForCls,
584: String altWebXmlFilename) throws DeploymentDescException {
585:
586: // init xml contents values;
587: String xmlContent = "";
588: String jonasXmlContent = "";
589:
590: //war file
591: JarFile warFile = null;
592:
593: //Input streams
594: InputStream webInputStream = null;
595: InputStream jonasWebInputStream = null;
596:
597: //ZipEntry
598: ZipEntry webZipEntry = null;
599: ZipEntry jonasWebZipEntry = null;
600:
601: //Webapps
602: WebApp webApp;
603: JonasWebApp jonasWebApp;
604:
605: //Build the file
606: File fWar = new File(warFileName);
607:
608: //Check if the file exists.
609: if (!(fWar.exists())) {
610: String err = "' " + warFileName + "' was not found.";
611: throw new WebContainerDeploymentDescException(err);
612: }
613:
614: //Check if the Alt deploymentDesc file exists.
615: //But only if it's a non null value because it's optionnal.
616: if ((altWebXmlFilename != null)
617: && (!new File(altWebXmlFilename).exists())) {
618: String err = "The file for the altdd tag for the EAR case '"
619: + altWebXmlFilename + "' was not found.";
620: throw new WebContainerDeploymentDescException(err);
621: }
622:
623: // load the web-app deployment descriptor data (WEB-INF/web.xml
624: // and WEB-INF/jonas-web.xml)
625: try {
626:
627: //No alt-dd case
628: if (altWebXmlFilename == null) {
629:
630: //If warFile is a directory, there is no jar. Check file in the
631: // directory
632: if (fWar.isDirectory()) {
633: //lookup a WEB-INF/web.xml file
634: File webXmlF = new File(warFileName, WEB_FILE_NAME);
635: if (!webXmlF.exists()) {
636: String err = "You have choose to deploy a war directory but there is no "
637: + WEB_FILE_NAME
638: + " file in the directory "
639: + warFileName;
640: throw new WebContainerDeploymentDescException(
641: err);
642: }
643: webInputStream = new FileInputStream(webXmlF);
644: xmlContent = xmlContent(webInputStream);
645: webInputStream = new FileInputStream(webXmlF);
646: } else {
647: warFile = new JarFile(warFileName);
648: //Lookup in the JAR
649: //Check the web entry
650: webZipEntry = warFile.getEntry(WEB_FILE_NAME);
651: if (webZipEntry == null) {
652: throw new WebContainerDeploymentDescException(
653: "The entry '"
654: + WEB_FILE_NAME
655: + "' was not found in the file '"
656: + warFileName + "'.");
657: }
658: //Get the stream
659: webInputStream = warFile
660: .getInputStream(webZipEntry);
661: xmlContent = xmlContent(webInputStream);
662: webInputStream = warFile
663: .getInputStream(webZipEntry);
664: }
665: } else {
666: webInputStream = new FileInputStream(altWebXmlFilename);
667: xmlContent = xmlContent(webInputStream);
668: webInputStream = new FileInputStream(altWebXmlFilename);
669: }
670:
671: //This is a directory
672: if (fWar.isDirectory()) {
673: //lookup a WEB-INF/jonas-web.xml file
674: File webJXmlF = new File(warFileName,
675: JONAS_WEB_FILE_NAME);
676: if (webJXmlF.exists()) {
677: jonasWebInputStream = new FileInputStream(webJXmlF);
678: jonasXmlContent = xmlContent(jonasWebInputStream);
679: jonasWebInputStream = new FileInputStream(webJXmlF);
680: }
681: } else {
682: if (warFile == null) {
683: warFile = new JarFile(warFileName);
684: }
685:
686: //Check the jonas web entry
687: jonasWebZipEntry = warFile
688: .getEntry(JONAS_WEB_FILE_NAME);
689:
690: //Get the stream
691: if (jonasWebZipEntry != null) {
692: jonasWebInputStream = warFile
693: .getInputStream(jonasWebZipEntry);
694: jonasXmlContent = xmlContent(jonasWebInputStream);
695: jonasWebInputStream = warFile
696: .getInputStream(jonasWebZipEntry);
697:
698: }
699: }
700:
701: } catch (Exception e) {
702: if (warFile != null) {
703: try {
704: warFile.close();
705: } catch (IOException ioe) {
706: // We can't close the file
707: logger.log(BasicLevel.WARN, "Can't close file '"
708: + warFileName + "'");
709: }
710: }
711: throw new WebContainerDeploymentDescException(
712: "Cannot read the XML deployment descriptors of the war file '"
713: + warFileName + "'.", e);
714: }
715:
716: webApp = loadWebApp(new InputStreamReader(webInputStream),
717: WEB_FILE_NAME);
718: try {
719: webInputStream.close();
720: } catch (IOException e) {
721: // Nothing to do
722: logger.log(BasicLevel.WARN,
723: "Can't close InputStream of web.xml from '"
724: + warFileName + "'");
725: }
726:
727: // load jonas-web-app deployment descriptor data
728: // (WEB-INF/jonas-web.xml)
729: if (jonasWebInputStream != null) {
730: jonasWebApp = loadJonasWebApp(new InputStreamReader(
731: jonasWebInputStream), JONAS_WEB_FILE_NAME);
732: try {
733: jonasWebInputStream.close();
734: } catch (IOException e) {
735: // Nothing to do
736: logger.log(BasicLevel.WARN,
737: "Can't close InputStream of jonas-web.xml from '"
738: + warFileName + "'");
739: }
740: } else {
741: jonasWebApp = new JonasWebApp();
742: }
743:
744: // close the zip
745: if (warFile != null) {
746: try {
747: warFile.close();
748: } catch (IOException ioe) {
749: // We can't close the file
750: logger.log(BasicLevel.WARN, "Can't close file '"
751: + warFileName + "'");
752: }
753: }
754:
755: // instantiate web deployment descriptor
756: WebContainerDeploymentDesc webDD = new WebContainerDeploymentDesc(
757: warFileName, classLoaderForCls, webApp, jonasWebApp);
758: webDD.setXmlContent(xmlContent);
759: webDD.setJOnASXmlContent(jonasXmlContent);
760: return webDD;
761: }
762:
763: /**
764: * Get an instance of a WEB deployment descriptor by parsing the web.xml and
765: * jonas-web.xml deployment descriptors.
766: * @param warFileName the fileName of the war file for the deployment
767: * descriptors.
768: * @param classLoaderForCls the classloader for the classes.
769: * @return a WEB deployment descriptor by parsing the web.xml and
770: * jonas-web.xml deployment descriptors.
771: * @throws DeploymentDescException if the deployment descriptors are
772: * corrupted.
773: */
774: public static WebContainerDeploymentDesc getInstance(
775: String warFileName, ClassLoader classLoaderForCls)
776: throws DeploymentDescException {
777:
778: return getInstance(warFileName, classLoaderForCls, null);
779: }
780:
781: /**
782: * Load the web.xml file.
783: * @param reader the reader of the XML file.
784: * @param fileName the name of the file (web.xml).
785: * @return a structure containing the result of the web.xml parsing.
786: * @throws DeploymentDescException if the deployment descriptor is
787: * corrupted.
788: */
789: public static WebApp loadWebApp(Reader reader, String fileName)
790: throws DeploymentDescException {
791:
792: WebApp webApp = new WebApp();
793:
794: // Create if null
795: if (webAppDigester == null) {
796: webAppDigester = new JDigester(webAppRuleSet,
797: getParsingWithValidation(), true, new WebAppDTDs(),
798: new WebAppSchemas());
799: }
800:
801: try {
802: webAppDigester.parse(reader, fileName, webApp);
803: } catch (DeploymentDescException e) {
804: throw e;
805: } finally {
806: webAppDigester.push(null);
807: }
808: return webApp;
809: }
810:
811: /**
812: * Load the jonas-web.xml file.
813: * @param reader the Reader of the XML file.
814: * @param fileName the name of the file (jonas-web.xml).
815: * @return a structure containing the result of the jonas-web.xml parsing.
816: * @throws DeploymentDescException if the deployment descriptor is
817: * corrupted.
818: */
819: public static JonasWebApp loadJonasWebApp(Reader reader,
820: String fileName) throws DeploymentDescException {
821:
822: JonasWebApp jonasWebApp = new JonasWebApp();
823:
824: // Create if null
825: if (jonasWebAppDigester == null) {
826: jonasWebAppDigester = new JDigester(jonasWebAppRuleSet,
827: getParsingWithValidation(), true,
828: new JonasWebAppDTDs(), new JonasWebAppSchemas());
829: }
830:
831: try {
832: jonasWebAppDigester.parse(reader, fileName, jonasWebApp);
833: } catch (DeploymentDescException e) {
834: throw e;
835: } finally {
836: jonasWebAppDigester.push(null);
837: }
838: return jonasWebApp;
839: }
840:
841: /**
842: * Controls whether the parser is reporting all validity errors.
843: * @return if true, all external entities will be read.
844: */
845: public static boolean getParsingWithValidation() {
846: return parsingWithValidation;
847: }
848:
849: /**
850: * Controls whether the parser is reporting all validity errors.
851: * @param validation if true, all external entities will be read.
852: */
853: public static void setParsingWithValidation(boolean validation) {
854: WebDeploymentDescManager.parsingWithValidation = validation;
855: }
856:
857: }
|