View Javadoc

1   /*
2    ~ Copyright 2006-2007 Nicolas De Loof.
3    ~
4    ~ Licensed under the Apache License, Version 2.0 (the "License");
5    ~ you may not use this file except in compliance with the License.
6    ~ You may obtain a copy of the License at
7    ~
8    ~      http://www.apache.org/licenses/LICENSE-2.0
9    ~
10   ~ Unless required by applicable law or agreed to in writing, software
11   ~ distributed under the License is distributed on an "AS IS" BASIS,
12   ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   ~ See the License for the specific language governing permissions and
14   ~ limitations under the License.
15   */
16  package org.jmonit.support.jaxrpc;
17  
18  import java.util.Iterator;
19  
20  import javax.xml.namespace.QName;
21  import javax.xml.rpc.Call;
22  import javax.xml.rpc.handler.GenericHandler;
23  import javax.xml.rpc.handler.MessageContext;
24  import javax.xml.rpc.handler.soap.SOAPMessageContext;
25  import javax.xml.soap.AttachmentPart;
26  import javax.xml.soap.SOAPException;
27  import javax.xml.soap.SOAPMessage;
28  
29  import org.jmonit.Monitoring;
30  import org.jmonit.Probe;
31  import org.jmonit.log.Log;
32  
33  /**
34   * Axis handler to monitor Time for SAOP invocation. Three jMonit domains are
35   * used for Axis SOAP monitoring :
36   * <ul>
37   * <li><b>axis</b> for timing.</li>
38   * <li><b>axis.sent</b> for bytes sent.</li>
39   * <li><b>axis.received</b> for bytes received.</li>
40   * </ul>
41   * <p>
42   * You have to configure your Axis client by including in the client-config.wsdd
43   * file (Axis client configuration file):
44   * 
45   * <pre>
46   *      &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
47   *      &lt;deployment xmlns=&quot;http://xml.apache.org/axis/wsdd/&quot;
48   *      xmlns:java=&quot;http://xml.apache.org/axis/wsdd/providers/java&quot;&gt;
49   * 
50   *        &lt;handler name=&quot;jmonit&quot; type=&quot;java:info.jmonit.support.soap.AxisMonitoringHandler&quot;&gt;
51   *          &lt;parameter name=&quot;domain&quot; value=&quot;soap.axis&quot;/&gt;
52   *          &lt;parameter name=&quot;requestDomain&quot; value=&quot;soap.axis.request&quot;/&gt;
53   *          &lt;parameter name=&quot;responseDomain&quot; value=&quot;soap.axis.response&quot;/&gt;
54   *        &lt;/handler&gt;
55   * 
56   *        &lt;transport name=&quot;http&quot;
57   *        pivot=&quot;java:org.apache.axis.transport.http.HTTPSender&quot;&gt;
58   *          &lt;requestFlow&gt;
59   *            &lt;handler type=&quot;jmonit&quot;/&gt;
60   *          &lt;/requestFlow&gt;
61   *          &lt;responseFlow&gt;
62   *            &lt;handler type=&quot;jmonit&quot;/&gt;
63   *          &lt;/responseFlow&gt;
64   *        &lt;/transport&gt;
65   * 
66   *      &lt;/deployment&gt;
67   * </pre>
68   * 
69   * Handler parameter can be used to override default domains. This can be
70   * usefull if you are both using Axis as Web service client and as server-side
71   * SOAP stack, where request/response have inverted roles.
72   * 
73   * @author <a href="mailto:ndeloof@sourceforge.net">Nicolas De Loof</a>
74   */
75  public class JaxRpcMonitoringHandler
76      extends GenericHandler
77  {
78      private static final String PROBE = Probe.class.getName();
79  
80      /** Logger */
81      private static Log log = Log.getLog( JaxRpcMonitoringHandler.class );
82  
83      public boolean handleRequest( MessageContext context )
84      {
85          Probe probe = Monitoring.start( getAction( context ) );
86          context.setProperty( PROBE, probe );
87          return true;
88      };
89  
90      public boolean handleResponse( MessageContext context )
91      {
92          stopMonitoring( context, true );
93          return true;
94      };
95  
96      public boolean handleFault( MessageContext context )
97      {
98          stopMonitoring( context, false );
99          return true;
100     };
101 
102     /**
103      * Extract the Action from the message, either by getting the Jax-rpc
104      * header, or by getting the SOAP message first element.
105      * <p>
106      * TODO : Does this work for any SOAP message ?
107      * 
108      * @param context Jax-rpc context
109      * @return soapAction of the SOAP message
110      */
111     protected String getAction( MessageContext context )
112     {
113         String soapAction = (String) context.getProperty( Call.SOAPACTION_URI_PROPERTY );
114         if ( soapAction == null && context instanceof SOAPMessageContext )
115         {
116             SOAPMessageContext soapContext = (SOAPMessageContext) context;
117             SOAPMessage message = soapContext.getMessage();
118             try
119             {
120                 soapAction = message.getSOAPBody().getFirstChild().getNodeName();
121             }
122             catch ( Exception e )
123             {
124                 // ignored
125             }
126         }
127 
128         if ( soapAction == null )
129         {
130             log.warn( "Failed to extract the SOAP action" );
131             soapAction = "unknown";
132         }
133 
134         // Experiment on Axis shows "ns1:" namespace is set on response, and not
135         // set on request, so remove any namespace prefix
136         int i = soapAction.indexOf( ':' );
137         if ( i >= 0 )
138         {
139             soapAction = soapAction.substring( i + 1 );
140         }
141 
142         return soapAction;
143     }
144 
145     /**
146      * End monitoring for a SOAP invocation.
147      * <p>
148      * Stops the running probe and add messages weight to request/response bytes
149      * monitors.
150      * 
151      * @param msgContext Axis message context
152      */
153     protected void stopMonitoring( MessageContext context, boolean success )
154     {
155         Probe probe = (Probe) context.getProperty( PROBE );
156         if ( !success )
157         {
158             Monitoring.add( getAction( context ) + ".faults", probe.getElapsedTime() );
159         }
160         probe.stop( success );
161         context.removeProperty( PROBE );
162 
163         if ( context instanceof SOAPMessageContext )
164         {
165             SOAPMessageContext soapContext = (SOAPMessageContext) context;
166             SOAPMessage message = soapContext.getMessage();
167             try
168             {
169                 long size = 0;
170                 for ( Iterator iterator = message.getAttachments(); iterator.hasNext(); )
171                 {
172                     AttachmentPart attachment = (AttachmentPart) iterator.next();
173                     size += attachment.getSize();
174                 }
175                 size += 0; // FIXME : HOW to get the SOAP message weight
176             }
177             catch ( SOAPException e )
178             {
179                 // Failed to compute SOAP message weight
180             }
181         }
182     }
183 
184     /**
185      * {@inheritDoc}
186      * 
187      * @see javax.xml.rpc.handler.GenericHandler#getHeaders()
188      */
189     public QName[] getHeaders()
190     {
191         return new QName[0];
192     }
193 }