001: /**
002: * JOnAS: Java(TM) Open Application Server
003: * Copyright (C) 1999-2005 Bull S.A.
004: * Contact: jonas-team@objectweb.org
005: *
006: * This library is free software; you can redistribute it and/or modify it under
007: * the terms of the GNU Lesser General Public License as published by the Free
008: * Software Foundation; either version 2.1 of the License, or any later version.
009: *
010: * This library is distributed in the hope that it will be useful, but WITHOUT
011: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
012: * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
013: * details.
014: *
015: * You should have received a copy of the GNU Lesser General Public License
016: * along with this library; if not, write to the Free Software Foundation, Inc.,
017: * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: *
019: * --------------------------------------------------------------------------
020: * $Id: ServiceRefDesc.java 6661 2005-04-28 08:43:27Z benoitf $
021: * --------------------------------------------------------------------------
022: */package org.objectweb.jonas_ws.deployment.api;
023:
024: import java.io.File;
025: import java.io.IOException;
026: import java.io.InputStream;
027: import java.net.URL;
028: import java.util.HashMap;
029: import java.util.Hashtable;
030: import java.util.Iterator;
031: import java.util.List;
032: import java.util.Map;
033: import java.util.Set;
034: import java.util.Vector;
035: import javax.xml.namespace.QName;
036: import org.objectweb.jonas_ejb.lib.BeanNaming;
037: import org.objectweb.jonas_lib.I18n;
038: import org.objectweb.jonas_lib.deployment.api.DeploymentDescException;
039: import org.objectweb.jonas_lib.deployment.api.HandlerDesc;
040: import org.objectweb.jonas_lib.deployment.xml.Handler;
041: import org.objectweb.jonas_lib.deployment.xml.JonasInitParam;
042: import org.objectweb.jonas_lib.deployment.xml.JonasPortComponentRef;
043: import org.objectweb.jonas_lib.deployment.xml.JonasServiceRef;
044: import org.objectweb.jonas_lib.deployment.xml.PortComponentRef;
045: import org.objectweb.jonas_lib.deployment.xml.ServiceRef;
046: import org.objectweb.jonas_ws.deployment.lib.MappingFileManager;
047: import org.objectweb.jonas_ws.deployment.lib.wrapper.MappingFileManagerWrapper;
048: import org.objectweb.jonas.common.Log;
049: import org.objectweb.jonas.server.Server;
050: import org.objectweb.util.monolog.api.BasicLevel;
051: import org.objectweb.util.monolog.api.Logger;
052:
053: /**
054: * A ServiceRefDesc describe a dependancy from a J2EE component onto a
055: * WebService (it is a Web Service Client). The component will have the hability
056: * to lookup the Service Implementation and use it.
057: *
058: * @author Guillaume Sauthier
059: * @author Xavier Delplanque
060: */
061: public class ServiceRefDesc {
062:
063: /**
064: * javax.xml.rpc.Service classname
065: */
066: private static final String JAVAX_XML_RPC_SERVICE = "javax.xml.rpc.Service";
067:
068: /**
069: * logger
070: */
071: private static Logger logger = Log.getLogger(Log.JONAS_WS_PREFIX);
072:
073: /**
074: * Internationalization
075: */
076: private static I18n i18n = I18n.getInstance(ServiceRefDesc.class);
077:
078: /** All the params of the ServiceRefDesc */
079: private Hashtable params = new Hashtable();
080:
081: /** The list of PortComponentRefs */
082: private Vector pcRefs = new Vector();
083:
084: /** The list of Handlers */
085: private Vector hRefs = new Vector();
086:
087: /** The WSDLFile of the ServiceRefDesc */
088: private WSDLFile wsdl;
089:
090: /** The alternate WSDLFile of the ServiceRefDesc */
091: private WSDLFile altWsdl;
092:
093: /** The MappingFile of the ServiceRefDesc */
094: private MappingFile mapping;
095:
096: /** The name of the ServiceRefDesc (used in lookup) */
097: private String name;
098:
099: /** The service interface */
100: private Class serviceInterface;
101:
102: /** The Service QName */
103: private QName serviceQName = null;
104:
105: /** The Module file (directory or jar) */
106: private File moduleFile = null;
107:
108: /** WSDL FileName */
109: private String wsdlFileName = null;
110:
111: /** jaxrpc mapping file name */
112: private String mappingFileName = null;
113:
114: /** alt-wsdl URL */
115: private URL alternateWSDL = null;
116:
117: /** local URL of the uptodate WSDL */
118: private URL localWSDLURL = null;
119:
120: /** local URL os the mapping file */
121: private URL mappingFileURL = null;
122:
123: /**
124: * Creates a new ServiceRefDesc object.
125: * @param classLoader web class loader
126: * @param sref generated object containing service-ref informations.
127: * @param jsref JOnAS specific service-ref informations.
128: * @param filename the name of the archive where retrieve WSDL and mapping
129: * files
130: * @throws WSDeploymentDescException if the wsdl file is undefined or if
131: * informations in wsdl and handler doesn't match.
132: */
133: public ServiceRefDesc(ClassLoader classLoader, ServiceRef sref,
134: JonasServiceRef jsref, String filename)
135: throws WSDeploymentDescException {
136:
137: if (filename != null) {
138: moduleFile = new File(filename);
139: }
140:
141: // setup the classloader
142: ClassLoader loader = classLoader;
143:
144: // set ServiceRefDesc name
145: name = sref.getServiceRefName();
146:
147: // set Service QName (if exists)
148: if (sref.getServiceQname() != null) {
149: serviceQName = sref.getServiceQname().getQName();
150: }
151:
152: // set Service Interface
153: String si = sref.getServiceInterface().trim();
154:
155: try {
156: serviceInterface = loader.loadClass(si);
157: } catch (ClassNotFoundException cnf) {
158: throw new WSDeploymentDescException(getI18n().getMessage(
159: "ServiceRefDesc.serviceIntfNotFound", si), cnf); //$NON-NLS-1$
160: }
161:
162: // this interface must implements javax.xml.rpc.Service
163: if (!javax.xml.rpc.Service.class
164: .isAssignableFrom(serviceInterface)) {
165: String err = getI18n()
166: .getMessage(
167: "ServiceRefDesc.mustExtService", serviceInterface.getName()); //$NON-NLS-1$
168: throw new WSDeploymentDescException(err);
169: }
170:
171: // ServiceRefDesc init parameters : jonas specific deployment desc
172: if (jsref != null) {
173: List jipl = jsref.getJonasInitParamList();
174:
175: for (int i = 0; i < jipl.size(); i++) {
176: // add in params table each init parameter name and associated value
177: JonasInitParam p = (JonasInitParam) jipl.get(i);
178: params.put(p.getParamName().trim(), p.getParamValue()
179: .trim());
180: }
181: }
182:
183: // fill portComponentRef list
184: Map links = linkPCR2JPCR(sref, jsref);
185: List pcrl = sref.getPortComponentRefList();
186:
187: for (int i = 0; i < pcrl.size(); i++) {
188: // for each reference, build and add a PortComponentRef Object
189: PortComponentRef ref = (PortComponentRef) pcrl.get(i);
190: JonasPortComponentRef jref = (JonasPortComponentRef) links
191: .get(ref.getServiceEndpointInterface());
192: pcRefs.add(new PortComponentRefDesc(loader, ref, jref));
193: }
194:
195: // fill handlers list
196: List hl = sref.getHandlerList();
197: Handler h = null;
198:
199: for (int i = 0; i < hl.size(); i++) {
200: // for each reference, build and add a HandlerRef Object
201: // get the standard dd handler
202: h = (Handler) hl.get(i);
203: // build and add a new handler
204: try {
205: hRefs.add(new HandlerDesc(loader, h));
206: } catch (DeploymentDescException dde) {
207: throw new WSDeploymentDescException(dde);
208: }
209: }
210:
211: // if alt-wsdl defined AND running online
212: if (jsref != null && jsref.getAltWsdl() != null
213: && isJonasRuntime()) {
214: if (logger.isLoggable(BasicLevel.DEBUG)) {
215: logger.log(BasicLevel.DEBUG, "loading alt-wsdl : "
216: + jsref.getAltWsdl());
217: }
218: try {
219: alternateWSDL = new URL(jsref.getAltWsdl());
220: altWsdl = new WSDLFile(alternateWSDL, jsref
221: .getAltWsdl());
222: } catch (IOException e) {
223: String err = "Cannot load alternate WSDL Stream from "
224: + jsref.getAltWsdl();
225: throw new WSDeploymentDescException(err);
226: }
227: }
228:
229: // get ServiceRefDesc WSDLFile name
230: String wf = sref.getWsdlFile();
231: if (wf != null) {
232: this .wsdlFileName = wf.trim();
233: wsdl = new WSDLFile(loader, wsdlFileName);
234:
235: localWSDLURL = loader.getResource(wsdlFileName);
236: }
237:
238: if (getWSDLFile() != null) {
239: if ((getWSDLFile().getNbServices() > 1)
240: && (serviceQName == null)) {
241: String err = getI18n()
242: .getMessage(
243: "ServiceRefDesc.serviceQnameNotDef", wsdlFileName, name); //$NON-NLS-1$
244: throw new WSDeploymentDescException(err);
245: } else if ((getWSDLFile().getNbServices() == 1)
246: && (serviceQName == null)) {
247: // When the WSDL defines only 1 service, we can retrieve
248: // automatically the service QName for service-ref
249: serviceQName = getWSDLFile().getServiceQname();
250: } else {
251: // serviceQName not null
252: // check service QName existence in WSDL
253: if (isJonasRuntime()) {
254: if (!getWSDLFile().hasService(serviceQName)) {
255: throw new WSDeploymentDescException(
256: getI18n()
257: .getMessage(
258: "ServiceRefDesc.serviceNotFoundInWSDL", serviceQName, wsdlFileName)); //$NON-NLS-1$
259: }
260: }
261: }
262:
263: }
264:
265: // get ServiceRefDesc MappingFile name
266: String mf = sref.getJaxrpcMappingFile();
267:
268: if (mf != null) {
269: this .mappingFileName = mf.trim();
270: this .mappingFileURL = loader.getResource(mappingFileName);
271: setMappingFile(loader);
272: }
273:
274: // mapping is required when generated service interface is specified
275: if (!serviceInterface.getName().equals(JAVAX_XML_RPC_SERVICE)
276: && (mapping == null)) {
277: throw new WSDeploymentDescException(
278: getI18n()
279: .getMessage(
280: "ServiceRefDesc.mappingRequired", serviceInterface.getName())); //$NON-NLS-1$
281: }
282:
283: validate();
284: }
285:
286: /**
287: * @return Returns true if called in a JOnAS runtime (in a container, ...).
288: */
289: private boolean isJonasRuntime() {
290:
291: if (Server.isStarted()) {
292: // we're in jonas runtime
293: // but if we're doing deploy stuff, return false
294: Throwable t = new Exception();
295: StackTraceElement[] elem = t.getStackTrace();
296: for (int i = 0; i < elem.length; i++) {
297: if ("org.objectweb.jonas_ws.wsgen.wrapper.WsGenWrapper"
298: .equals(elem[i].getClassName())) {
299: return false;
300: }
301: if ("org.objectweb.jonas_lib.genclientstub.wrapper.ClientGenStubWrapper"
302: .equals(elem[i].getClassName())) {
303: return false;
304: }
305: if ("org.objectweb.jonas_ejb.genic.wrapper.GenicServiceWrapper"
306: .equals(elem[i].getClassName())) {
307: return false;
308: }
309: }
310: return true;
311:
312: } else {
313: // offline mode or client container
314: ClassLoader cl = this .getClass().getClassLoader();
315: try {
316: cl.loadClass("org.objectweb.jonas.server.Bootstrap");
317: } catch (ClassNotFoundException e) {
318: // we're in client container
319: // => jonas runtime
320: return true;
321: }
322: // loading successful => we're not in client container
323: return false;
324: }
325: }
326:
327: /**
328: * @param sref ServiceRef instance
329: * @param jsref linked JonasServiceRef instance
330: * @return Returns a map associating the PortComponentRef.sei with the JonasPortComponentRef
331: */
332: private Map linkPCR2JPCR(ServiceRef sref, JonasServiceRef jsref) {
333: Map res = new HashMap();
334: // for each port-component-ref
335: for (Iterator i = sref.getPortComponentRefList().iterator(); i
336: .hasNext();) {
337: PortComponentRef pcr = (PortComponentRef) i.next();
338: res.put(pcr.getServiceEndpointInterface(), null);
339: }
340: // jonas-port-component-ref(s)
341: if (jsref != null) {
342:
343: // get all jonas-port-component.sei
344: Set keys = res.keySet();
345:
346: // for each jonas-port-component
347: for (Iterator i = jsref.getJonasPortComponentRefList()
348: .iterator(); i.hasNext();) {
349: JonasPortComponentRef jpcr = (JonasPortComponentRef) i
350: .next();
351: String sei = jpcr.getServiceEndpointInterface();
352:
353: if ((sei != null) && (keys.contains(sei))) {
354: // jonas-port-component-ref linked to port-component-ref
355: res.put(sei, jpcr);
356: } else {
357: String err = "jonas-port-component-ref '"
358: + sei
359: + "' is not linked to any port-component-ref. It will be ignored.";
360: logger.log(BasicLevel.WARN, err);
361: }
362: }
363: }
364: return res;
365: }
366:
367: /**
368: * Return the list of PortComponentRef.
369: * @return the list of PortComponentRef
370: */
371: public List getPortComponentRefs() {
372: return pcRefs;
373: }
374:
375: /**
376: * Return the list of Handler.
377: * @return the list of Handler
378: */
379: public List getHandlerRefs() {
380: return hRefs;
381: }
382:
383: /**
384: * Return the name used for Service interface lookup.
385: * @return the service-ref-name value
386: */
387: public String getServiceRefName() {
388: return name;
389: }
390:
391: /**
392: * Return the Class object representing the service-interface.
393: * @return the Class object representing the service-interface.
394: */
395: public Class getServiceInterface() {
396: return serviceInterface;
397: }
398:
399: /**
400: * Return the WSDLFile object describing the WebService.
401: * @return the WSDLFile object describing the WebService.
402: */
403: public WSDLFile getWSDLFile() {
404: // if alt-wsdl is not set, use standard wsdl-file
405: WSDLFile file = altWsdl;
406: if (file == null) {
407: file = wsdl;
408: }
409: return file;
410: }
411:
412: /**
413: * Return the MappingFile object.
414: * @return the MappingFile object.
415: */
416: public MappingFile getMappingFile() {
417: return mapping;
418: }
419:
420: /**
421: * Return all the params of the ServiceRefDesc as an Hashtable.
422: * @return all the params of the ServiceRefDesc as an Hashtable.
423: */
424: public Hashtable getParams() {
425: return params;
426: }
427:
428: /**
429: * Return the value of the specified parameter
430: * @param name the parameter to retrieve
431: * @return the value of the specified parameter
432: */
433: public String getParam(String name) {
434: return (String) params.get(name);
435: }
436:
437: /**
438: * Return the name of WSDL inside of the module.
439: * @return the name of WSDL inside of the module
440: */
441: public String getWsdlFileName() {
442: return wsdlFileName;
443: }
444:
445: /**
446: * Return the QName identifying the service in the WSDL. can return null if
447: * WSDL not defined.
448: * @return Return the QName identifying the service in the WSDL (can be
449: * null).
450: */
451: public QName getServiceQName() {
452: return serviceQName;
453: }
454:
455: /**
456: * @see java.lang.String#hashCode()
457: */
458: public int hashCode() {
459: return this .name.hashCode();
460: }
461:
462: /**
463: * Return <code>true</code> if the parameter is a ServiceRefDesc and if it
464: * equals this object. Return <code>false</code> else.
465: * @param other the object to compare
466: * @return true if objects are equals
467: */
468: public boolean equals(Object other) {
469: if (other == null) {
470: return false;
471: }
472:
473: if (!(other instanceof ServiceRefDesc)) {
474: return false;
475: }
476:
477: ServiceRefDesc sr = (ServiceRefDesc) other;
478:
479: if (!mapping.equals(sr.getMappingFile())) {
480: return false;
481: }
482:
483: if (!wsdl.equals(sr.getWSDLFile())) {
484: return false;
485: }
486:
487: if (!params.equals(sr.getParams())) {
488: return false;
489: }
490:
491: for (Iterator i = sr.getPortComponentRefs().iterator(); i
492: .hasNext();) {
493: PortComponentRefDesc pcr = (PortComponentRefDesc) i.next();
494:
495: if (!pcRefs.contains(pcr)) {
496: return false;
497: }
498: }
499:
500: for (Iterator i = sr.getHandlerRefs().iterator(); i.hasNext();) {
501: HandlerDesc hr = (HandlerDesc) i.next();
502:
503: if (!hRefs.contains(hr)) {
504: return false;
505: }
506: }
507:
508: return true;
509: }
510:
511: /**
512: * Create the MappingFile.
513: * @param loader ClassLoader containing mapping file
514: * @throws WSDeploymentDescException When MappingFile creation fails.
515: */
516: private void setMappingFile(ClassLoader loader)
517: throws WSDeploymentDescException {
518:
519: // build the MappingFile
520: // Build Mapping file
521: if (moduleFile != null) {
522: if (isRunningInClientContainer()) {
523: mapping = MappingFileManager.getInstance(moduleFile,
524: mappingFileName);
525: } else {
526: mapping = MappingFileManagerWrapper.getMappingFile(
527: moduleFile, mappingFileName);
528: }
529: } else {
530: // Try to get the mapping from the ClassLoader
531: InputStream is = null;
532: if (loader != null) {
533: is = loader.getResourceAsStream(mappingFileName);
534: if (is != null) {
535: // build the MappingFile
536: if (isRunningInClientContainer()) {
537: mapping = MappingFileManager.getInstance(is,
538: mappingFileName);
539: } else {
540: mapping = MappingFileManagerWrapper
541: .getMappingFile(is, mappingFileName);
542: }
543: } else {
544: throw new WSDeploymentDescException(
545: getI18n()
546: .getMessage(
547: "ServiceRefDesc.mappingFileNotFoundInLoader", mappingFileName)); //$NON-NLS-1$
548: }
549: } else {
550: throw new WSDeploymentDescException(getI18n()
551: .getMessage(
552: "ServiceRefDesc.mappingFileNotFound")); //$NON-NLS-1$
553: }
554: }
555: }
556:
557: /**
558: * @return Returns true if current execution takes place inside a
559: * ClientContainer
560: */
561: private boolean isRunningInClientContainer() {
562: return (System.getProperty("jonas.base") == null);
563: }
564:
565: /**
566: * Validate the ServiceRefDesc
567: * @throws WSDeploymentDescException DOCUMENT ME!
568: */
569: private void validate() throws WSDeploymentDescException {
570: // validate informations :
571: // TODO pcLinkExist
572:
573: if ((wsdlFileName != null)
574: && ((mappingFileName == null) || (""
575: .equals(mappingFileName)))) {
576: // Must have a mapping file along with WSDL
577: throw new WSDeploymentDescException(getI18n().getMessage(
578: "ServiceRefDesc.missingMappingFile", this .name)); //$NON-NLS-1$
579: }
580:
581: // Port validity between handlers and wsdl
582: for (int i = 0; i < hRefs.size(); i++) {
583: HandlerDesc myHRef = (HandlerDesc) hRefs.get(i);
584: List pnl = myHRef.getPortNames();
585:
586: for (int j = 0; j < pnl.size(); j++) {
587: if (!getWSDLFile().hasPort((String) pnl.get(j))) {
588: // the handler use a port undefined in the wsdl
589: throw new WSDeploymentDescException(
590: getI18n()
591: .getMessage(
592: "ServiceRefDesc.undefinedPort", myHRef.getName(), pnl.get(j), wsdlFileName)); //$NON-NLS-1$
593: }
594: }
595: }
596:
597: // Check service-interface
598: // if service interface is not generic, Full WSDL Knowledge is required
599: if (!serviceInterface.equals(javax.xml.rpc.Service.class)) {
600: if ((getWSDLFile() == null)
601: || ((getWSDLFile() != null) && (getWSDLFile()
602: .getDefinition().getServices().values()
603: .size() == 0))) {
604: throw new WSDeploymentDescException(
605: getI18n()
606: .getMessage(
607: "ServiceRefDesc.wsdlMissingInformation", serviceInterface.getName(), name)); //$NON-NLS-1$
608: }
609:
610: // Check mapping for GeneratedServiceInterface
611: String namespaceURI = serviceQName.getNamespaceURI();
612: String realPackage = BeanNaming
613: .getPackageName(serviceInterface.getName());
614:
615: // real != mapping provided package
616: if (!realPackage.equals(mapping.getMapping(namespaceURI))) {
617: throw new WSDeploymentDescException(
618: getI18n()
619: .getMessage(
620: "ServiceRefDesc.needPackageMapping", mappingFileName, realPackage)); //$NON-NLS-1$
621: }
622:
623: /*
624: * TODO : Uncomment this part will require substancial modification
625: * to number of tests (integ + unit) // -> We need to create
626: * generated clients interfaces for each endpoint ... // keep
627: * service QName namespaceURI (targetNamespace) // check mapping for
628: * ServiceEndpointInterface when having a generated
629: * service-interface for (Iterator p = pcRefs.iterator() ;
630: * p.hasNext() ; ) { PortComponentRef pcr = (PortComponentRef)
631: * p.next(); String sei = pcr.getSei().getName(); realPackage =
632: * BeanNaming.getPackageName(sei); if
633: * (!realPackage.equals(mapping.getMapping(namespaceURI))) throw new
634: * WSDeploymentDescException("jaxrpc-mapping-file '" +
635: * mappingFileName + "' need a mapping for package '" + realPackage +
636: * "'"); }
637: */
638: }
639: }
640:
641: /**
642: * @return Returns the i18n.
643: */
644: protected static I18n getI18n() {
645: return i18n;
646: }
647:
648: /**
649: * @return Returns the alternate WSDL URL (may be null).
650: */
651: public URL getAlternateWsdlURL() {
652: return alternateWSDL;
653: }
654:
655: /**
656: * @return Returns the URL where the uptodate WSDL can be found.
657: */
658: public URL getLocalWSDLURL() {
659: return localWSDLURL;
660: }
661:
662: /**
663: * @return Returns the URL where the mapping file can be found.
664: */
665: public URL getMappingFileURL() {
666: return mappingFileURL;
667: }
668: }
|