KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > axis > handlers > soap > SOAPService


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  * Copyright (c) 2001-2003 The Apache Software Foundation. All rights
5  * reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright
15  * notice, this list of conditions and the following disclaimer in
16  * the documentation and/or other materials provided with the
17  * distribution.
18  *
19  * 3. The end-user documentation included with the redistribution,
20  * if any, must include the following acknowledgment:
21  * "This product includes software developed by the
22  * Apache Software Foundation (http://www.apache.org/)."
23  * Alternately, this acknowledgment may appear in the software itself,
24  * if and wherever such third-party acknowledgments normally appear.
25  *
26  * 4. The names "Axis" and "Apache Software Foundation" must
27  * not be used to endorse or promote products derived from this
28  * software without prior written permission. For written
29  * permission, please contact apache@apache.org.
30  *
31  * 5. Products derived from this software may not be called "Apache",
32  * nor may "Apache" appear in their name, without prior written
33  * permission of the Apache Software Foundation.
34  *
35  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46  * SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Apache Software Foundation. For more
51  * information on the Apache Software Foundation, please see
52  * <http://www.apache.org/>.
53  */

54
55 package org.jboss.axis.handlers.soap;
56
57 import org.jboss.axis.AxisEngine;
58 import org.jboss.axis.AxisFault;
59 import org.jboss.axis.Constants;
60 import org.jboss.axis.Handler;
61 import org.jboss.axis.MessageContext;
62 import org.jboss.axis.SimpleTargetedChain;
63 import org.jboss.axis.attachments.Attachments;
64 import org.jboss.axis.description.ServiceDesc;
65 import org.jboss.axis.encoding.TypeMappingRegistry;
66 import org.jboss.axis.enums.Style;
67 import org.jboss.axis.enums.Use;
68 import org.jboss.axis.handlers.BasicHandler;
69 import org.jboss.axis.handlers.HandlerChainImpl;
70 import org.jboss.axis.handlers.HandlerInfoChainFactory;
71 import org.jboss.axis.message.SOAPEnvelopeAxisImpl;
72 import org.jboss.axis.message.SOAPHeaderElementAxisImpl;
73 import org.jboss.axis.providers.BasicProvider;
74 import org.jboss.axis.soap.SOAPConstants;
75 import org.jboss.axis.utils.LockableHashtable;
76 import org.jboss.axis.utils.Messages;
77 import org.jboss.axis.utils.XMLUtils;
78 import org.jboss.logging.Logger;
79 import org.w3c.dom.Document JavaDoc;
80
81 import javax.xml.namespace.QName JavaDoc;
82 import java.io.File JavaDoc;
83 import java.io.FileInputStream JavaDoc;
84 import java.io.IOException JavaDoc;
85 import java.io.InputStream JavaDoc;
86 import java.util.ArrayList JavaDoc;
87 import java.util.Enumeration JavaDoc;
88 import java.util.Hashtable JavaDoc;
89 import java.util.Vector JavaDoc;
90
91
92 /**
93  * A <code>SOAPService</code> is a Handler which encapsulates a SOAP
94  * invocation. It has an request chain, an response chain, and a pivot-point,
95  * and handles the SOAP semantics when invoke()d.
96  *
97  * @author Glen Daniels (gdaniels@macromedia.com)
98  * @author Doug Davis (dug@us.ibm.com)
99  */

100 public class SOAPService extends SimpleTargetedChain
101 {
102    private static Logger log = Logger.getLogger(SOAPService.class.getName());
103
104    /**
105     * Valid transports for this service
106     * (server side only!)
107     * <p/>
108     * !!! For now, if this is null, we assume all
109     * transports are valid.
110     */

111    private Vector JavaDoc validTransports = null;
112
113    /**
114     * Does this service require a high-fidelity SAX recording of messages?
115     * (default is true)
116     */

117    private boolean highFidelityRecording = true;
118
119    /**
120     * How does this service wish data which would normally be sent as
121     * an attachment to be sent? Default for requests is
122     * org.jboss.axis.attachments.Attachments.SEND_TYPE_DEFAULT,
123     * and the default for responses is to match the request.
124     */

125    private int sendType = Attachments.SEND_TYPE_NOTSET;
126
127    /**
128     * Our ServiceDescription. Holds pretty much all the interesting
129     * metadata about this service.
130     */

131    private ServiceDesc serviceDescription = new ServiceDesc();
132    private AxisEngine engine;
133
134    /**
135     * Actor list - these are just the service-specific ones
136     */

137    ArrayList JavaDoc actors = new ArrayList JavaDoc();
138
139    /**
140     * Get the service-specific actor list
141     *
142     * @return
143     */

144    public ArrayList JavaDoc getServiceActors()
145    {
146       return actors;
147    }
148
149    /**
150     * Get the merged actor list for this service, including engine-wide
151     * actor URIs.
152     *
153     * @return
154     */

155    public ArrayList JavaDoc getActors()
156    {
157       ArrayList JavaDoc acts = (ArrayList JavaDoc)actors.clone(); // ??? cache this?
158

159       // TODO: a SOAPService should always be associated with an engine,
160
// so this should never be null.... check all paths to ensure that
161
// constraint is true.
162
if (engine != null)
163       {
164          acts.addAll(engine.getActorURIs());
165       }
166       return acts;
167    }
168
169
170    /**
171     * SOAPResponseHandler is used to inject SOAP semantics just before
172     * the pivot handler.
173     */

174    private class SOAPResponseHandler extends BasicHandler
175    {
176       public SOAPResponseHandler()
177       {
178       }
179
180       public void invoke(MessageContext msgContext) throws AxisFault
181       {
182          // Do SOAP semantics here
183
if (log.isDebugEnabled())
184          {
185             log.debug(Messages.getMessage("semanticCheck00"));
186          }
187
188          checkMustUnderstand(msgContext);
189       }
190
191       /**
192        * Check whether we should throw MustUnderstand fault. Now, if there is an actor that is not
193        * service actor and there is a MustUnderstand flat to 1, we will need to throw the fault exception
194        * since we don't know how to handle it.
195        *
196        * @param msgContext
197        * @throws AxisFault
198        */

199       private void checkMustUnderstand(MessageContext msgContext) throws AxisFault
200       {
201          String JavaDoc svcActor = ""; // can't handle other actor for now.
202

203          // 1. Check mustUnderstands
204
SOAPEnvelopeAxisImpl env = msgContext.getRequestMessage().getSOAPEnvelope();
205          Vector JavaDoc headers = env.getHeaders(); // TODO get only headers with actors.
206
Vector JavaDoc misunderstoodHeaders = null;
207          Enumeration JavaDoc en = headers.elements();
208          while (en.hasMoreElements())
209          {
210             SOAPHeaderElementAxisImpl header = (SOAPHeaderElementAxisImpl)en.
211                     nextElement();
212 /*
213                 if (header.getMustUnderstand() && !header.isProcessed()) {
214                     if (misunderstoodHeaders == null)
215                         misunderstoodHeaders = new Vector();
216                     misunderstoodHeaders.addElement(header);
217                 }
218 */

219             if (header.getActor() != null && header.getMustUnderstand() &&
220                     header.getActor() != svcActor)
221             {
222                if (misunderstoodHeaders == null)
223                   misunderstoodHeaders = new Vector JavaDoc();
224                misunderstoodHeaders.addElement(header);
225             }
226          }
227
228          SOAPConstants soapConstants = msgContext.getSOAPConstants();
229          // !!! we should indicate SOAP1.2 compliance via the
230
// MessageContext, not a boolean here....
231

232          if (misunderstoodHeaders != null)
233          {
234             AxisFault fault =
235                     new AxisFault(soapConstants.getMustunderstandFaultQName(),
236                             null, null,
237                             null, null,
238                             null);
239
240             StringBuffer JavaDoc whatWasMissUnderstood = new StringBuffer JavaDoc(256);
241
242             // !!! If SOAP 1.2, insert misunderstood fault headers here
243
if (soapConstants == SOAPConstants.SOAP12_CONSTANTS)
244             {
245                en = misunderstoodHeaders.elements();
246                while (en.hasMoreElements())
247                {
248                   SOAPHeaderElementAxisImpl badHeader = (SOAPHeaderElementAxisImpl)en.
249                           nextElement();
250                   QName JavaDoc badQName = new QName JavaDoc(badHeader.getNamespaceURI(),
251                           badHeader.getName());
252
253                   if (whatWasMissUnderstood.length() != 0) whatWasMissUnderstood.append(", ");
254                   whatWasMissUnderstood.append(badQName.toString());
255
256                   SOAPHeaderElementAxisImpl newHeader = new
257                           SOAPHeaderElementAxisImpl(Constants.URI_SOAP12_ENV,
258                                   Constants.ELEM_NOTUNDERSTOOD);
259                   newHeader.addAttribute(null,
260                           Constants.ATTR_QNAME,
261                           badQName);
262
263                   fault.addHeader(newHeader);
264                }
265             }
266
267             fault.setFaultString(Messages.getMessage("noUnderstand00",
268                     whatWasMissUnderstood.toString()));
269
270             throw fault;
271          }
272       }
273    }
274
275    /**
276     * Standard, no-arg constructor.
277     */

278    public SOAPService()
279    {
280       setOptionsLockable(true);
281       initHashtable();
282
283       // For now, always assume we're the ultimate destination.
284
actors.add("");
285    }
286
287    /**
288     * Constructor with real or null request, pivot, and response
289     * handlers. A special request handler is specified to inject
290     * SOAP semantics.
291     */

292    public SOAPService(Handler reqHandler, Handler pivHandler,
293                       Handler respHandler)
294    {
295       this();
296       init(reqHandler, null, pivHandler, new SOAPResponseHandler(), respHandler);
297    }
298
299    public TypeMappingRegistry getTypeMappingRegistry()
300    {
301       return serviceDescription.getTypeMappingRegistry();
302    }
303
304    /**
305     * Convenience constructor for wrapping SOAP semantics around
306     * "service handlers" which actually do work.
307     */

308    public SOAPService(Handler serviceHandler)
309    {
310       init(null, null, serviceHandler, new SOAPResponseHandler(), null);
311    }
312
313    /**
314     * Tell this service which engine it's deployed to.
315     */

316    public void setEngine(AxisEngine engine)
317    {
318       if (engine == null)
319          throw new IllegalArgumentException JavaDoc(Messages.getMessage("nullEngine"));
320
321       this.engine = engine;
322       getTypeMappingRegistry().delegate(engine.getTypeMappingRegistry());
323    }
324
325    public AxisEngine getEngine()
326    {
327       return engine;
328    }
329
330    public boolean availableFromTransport(String JavaDoc transportName)
331    {
332       if (validTransports != null)
333       {
334          for (int i = 0; i < validTransports.size(); i++)
335          {
336             if (validTransports.elementAt(i).equals(transportName))
337                return true;
338          }
339          return false;
340       }
341
342       return true;
343    }
344
345    public Style getStyle()
346    {
347       return serviceDescription.getStyle();
348    }
349
350    public void setStyle(Style style)
351    {
352       serviceDescription.setStyle(style);
353    }
354
355    public Use getUse()
356    {
357       return serviceDescription.getUse();
358    }
359
360    public void setUse(Use style)
361    {
362       serviceDescription.setUse(style);
363    }
364
365    public ServiceDesc getServiceDescription()
366    {
367       return serviceDescription;
368    }
369
370    /**
371     * Returns a service description with the implementation class filled in.
372     * Syncronized to prevent simutaneous modification of serviceDescription.
373     */

374    public synchronized ServiceDesc getInitializedServiceDesc(MessageContext msgContext)
375            throws AxisFault
376    {
377
378       if (serviceDescription.getImplClass() == null)
379       {
380
381          // Let the provider do the work of filling in the service
382
// descriptor. This is so that it can decide itself how best
383
// to map the Operations. In the future, we may want to support
384
// providers which don't strictly map to Java class backends
385
// (BSFProvider, etc.), and as such we hand off here.
386
if (pivotHandler instanceof BasicProvider)
387          {
388             ((BasicProvider)pivotHandler).initServiceDesc(this, msgContext);
389          }
390
391       }
392
393       return serviceDescription;
394    }
395
396    public void setServiceDescription(ServiceDesc serviceDescription)
397    {
398       if (serviceDescription == null)
399       {
400          // FIXME: Throw NPE?
401
return;
402       }
403       this.serviceDescription = serviceDescription;
404    }
405
406    public void setPropertyParent(Hashtable parent)
407    {
408       if (options == null)
409       {
410          options = new LockableHashtable();
411       }
412       ((LockableHashtable)options).setParent(parent);
413    }
414
415    /**
416     * Generate WSDL. If we have a specific file configured in the
417     * ServiceDesc, just return that. Otherwise run through all the Handlers
418     * (including the provider) and call generateWSDL() on them via our
419     * parent's implementation.
420     */

421    public void generateWSDL(MessageContext msgContext) throws AxisFault
422    {
423       if (serviceDescription == null ||
424               serviceDescription.getWSDLFile() == null)
425       {
426          super.generateWSDL(msgContext);
427          return;
428       }
429       InputStream JavaDoc instream = null;
430
431       // Got a WSDL file in the service description, so try and read it
432
try
433       {
434          String JavaDoc filename = serviceDescription.getWSDLFile();
435          File JavaDoc file = new File JavaDoc(filename);
436          if (file.exists())
437          {
438             //if this resolves to a file, load it
439
instream = new FileInputStream JavaDoc(filename);
440          }
441          else
442          {
443             //else load a named resource in our classloader.
444
ClassLoader JavaDoc classLoader = msgContext.getClassLoader();
445             if (classLoader == null)
446                classLoader = getClass().getClassLoader();
447
448             instream = classLoader.getResourceAsStream(filename);
449             if (instream == null)
450             {
451                String JavaDoc errorText = Messages.getMessage("wsdlFileMissing", filename);
452                throw new AxisFault(errorText);
453             }
454          }
455          Document JavaDoc doc = XMLUtils.newDocument(instream);
456          msgContext.setProperty("WSDL", doc);
457       }
458       catch (Exception JavaDoc e)
459       {
460          throw AxisFault.makeFault(e);
461       }
462       finally
463       {
464          if (instream != null)
465          {
466             try
467             {
468                instream.close();
469             }
470             catch (IOException JavaDoc e)
471             {
472             }
473          }
474       }
475    }
476    /*********************************************************************
477     * Administration and management APIs
478     *
479     * These can get called by various admin adapters, such as JMX MBeans,
480     * our own Admin client, web applications, etc...
481     *
482     *********************************************************************
483     */

484
485    /**
486     * Placeholder for "enable this service" method
487     */

488    public void start()
489    {
490    }
491
492    /**
493     * Placeholder for "disable this service" method
494     */

495    public void stop()
496    {
497    }
498
499    /**
500     * Make this service available on a particular transport
501     */

502    public void enableTransport(String JavaDoc transportName)
503    {
504       if (log.isDebugEnabled())
505       {
506          log.debug(Messages.getMessage("enableTransport00", "" + this, transportName));
507       }
508
509       if (validTransports == null)
510          validTransports = new Vector JavaDoc();
511       validTransports.addElement(transportName);
512    }
513
514    /**
515     * Disable access to this service from a particular transport
516     */

517    public void disableTransport(String JavaDoc transportName)
518    {
519       if (validTransports != null)
520       {
521          validTransports.removeElement(transportName);
522       }
523    }
524
525    public boolean needsHighFidelityRecording()
526    {
527       return highFidelityRecording;
528    }
529
530    public void setHighFidelityRecording(boolean highFidelityRecording)
531    {
532       this.highFidelityRecording = highFidelityRecording;
533    }
534
535    // see org.jboss.axis.attachments.Attachments
536
public int getSendType()
537    {
538       return sendType;
539    }
540
541    public void setSendType(int sendType)
542    {
543       this.sendType = sendType;
544    }
545
546    public void invoke(MessageContext msgContext) throws AxisFault
547    {
548       HandlerInfoChainFactory handlerFactory = (HandlerInfoChainFactory)this.getOption(Constants.ATTR_HANDLERINFOCHAIN);
549       HandlerChainImpl handlerImpl = null;
550       if (handlerFactory != null) handlerImpl = (HandlerChainImpl)handlerFactory.createHandlerChain();
551       boolean result = true;
552
553       if (handlerImpl != null)
554       {
555          result = handlerImpl.handleRequest(msgContext);
556       }
557
558       if (result)
559       {
560          super.invoke(msgContext);
561       }
562       else
563       {
564          msgContext.setPastPivot(true);
565       }
566
567       if (handlerImpl != null)
568       {
569          handlerImpl.handleResponse(msgContext);
570          handlerImpl.destroy();
571       }
572    }
573 }
574
Popular Tags