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 * <?xml version="1.0" encoding="UTF-8"?>
47 * <deployment xmlns="http://xml.apache.org/axis/wsdd/"
48 * xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
49 *
50 * <handler name="jmonit" type="java:info.jmonit.support.soap.AxisMonitoringHandler">
51 * <parameter name="domain" value="soap.axis"/>
52 * <parameter name="requestDomain" value="soap.axis.request"/>
53 * <parameter name="responseDomain" value="soap.axis.response"/>
54 * </handler>
55 *
56 * <transport name="http"
57 * pivot="java:org.apache.axis.transport.http.HTTPSender">
58 * <requestFlow>
59 * <handler type="jmonit"/>
60 * </requestFlow>
61 * <responseFlow>
62 * <handler type="jmonit"/>
63 * </responseFlow>
64 * </transport>
65 *
66 * </deployment>
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 }