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