View Javadoc

1   /*
2    * Copyright 2005-2011 the original author or authors.
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  
17  package org.springframework.ws.server.endpoint;
18  
19  import java.io.StringWriter;
20  import javax.xml.transform.OutputKeys;
21  import javax.xml.transform.Source;
22  import javax.xml.transform.Transformer;
23  import javax.xml.transform.TransformerConfigurationException;
24  import javax.xml.transform.TransformerException;
25  import javax.xml.transform.stream.StreamResult;
26  
27  import org.springframework.ws.WebServiceMessage;
28  import org.springframework.ws.context.MessageContext;
29  import org.springframework.ws.server.EndpointInterceptor;
30  import org.springframework.xml.transform.TransformerObjectSupport;
31  
32  import org.apache.commons.logging.Log;
33  import org.apache.commons.logging.LogFactory;
34  
35  /**
36   * Abstract base class for <code>EndpointInterceptor</code> instances that log a part of a
37   * <code>WebServiceMessage</code>. By default, both request and response messages are logged, but this behaviour can be
38   * changed using the <code>logRequest</code> and <code>logResponse</code> properties.
39   *
40   * @author Arjen Poutsma
41   * @since 1.0.0
42   */
43  public abstract class AbstractLoggingInterceptor extends TransformerObjectSupport implements EndpointInterceptor {
44  
45      /**
46       * The default <code>Log</code> instance used to write trace messages. This instance is mapped to the implementing
47       * <code>Class</code>.
48       */
49      protected transient Log logger = LogFactory.getLog(getClass());
50  
51      private boolean logRequest = true;
52  
53      private boolean logResponse = true;
54  
55      /** Indicates whether the request should be logged. Default is <code>true</code>. */
56      public final void setLogRequest(boolean logRequest) {
57          this.logRequest = logRequest;
58      }
59  
60      /** Indicates whether the response should be logged. Default is <code>true</code>. */
61      public final void setLogResponse(boolean logResponse) {
62          this.logResponse = logResponse;
63      }
64  
65      /**
66       * Set the name of the logger to use. The name will be passed to the underlying logger implementation through
67       * Commons Logging, getting interpreted as log category according to the logger's configuration.
68       * <p/>
69       * This can be specified to not log into the category of a class but rather into a specific named category.
70       *
71       * @see org.apache.commons.logging.LogFactory#getLog(String)
72       * @see org.apache.log4j.Logger#getLogger(String)
73       * @see java.util.logging.Logger#getLogger(String)
74       */
75      public void setLoggerName(String loggerName) {
76          this.logger = LogFactory.getLog(loggerName);
77      }
78  
79      /**
80       * Logs the request message payload. Logging only occurs if <code>logRequest</code> is set to <code>true</code>,
81       * which is the default.
82       *
83       * @param messageContext the message context
84       * @return <code>true</code>
85       * @throws TransformerException when the payload cannot be transformed to a string
86       */
87      public final boolean handleRequest(MessageContext messageContext, Object endpoint) throws TransformerException {
88          if (logRequest && isLogEnabled()) {
89              logMessageSource("Request: ", getSource(messageContext.getRequest()));
90          }
91          return true;
92      }
93  
94      /**
95       * Logs the response message payload. Logging only occurs if <code>logResponse</code> is set to <code>true</code>,
96       * which is the default.
97       *
98       * @param messageContext the message context
99       * @return <code>true</code>
100      * @throws TransformerException when the payload cannot be transformed to a string
101      */
102     public boolean handleResponse(MessageContext messageContext, Object endpoint) throws Exception {
103         if (logResponse && isLogEnabled()) {
104             logMessageSource("Response: ", getSource(messageContext.getResponse()));
105         }
106         return true;
107     }
108 
109     /** Does nothing by default. Faults are not logged. */
110     public boolean handleFault(MessageContext messageContext, Object endpoint) throws Exception {
111         return true;
112     }
113 
114     /** Does nothing by default*/
115     public void afterCompletion(MessageContext messageContext, Object endpoint, Exception ex) {
116     }
117 
118     /**
119      * Determine whether the {@link #logger} field is enabled.
120      * <p/>
121      * Default is <code>true</code> when the "debug" level is enabled. Subclasses can override this to change the level
122      * under which logging occurs.
123      */
124     protected boolean isLogEnabled() {
125         return logger.isDebugEnabled();
126     }
127 
128     private Transformer createNonIndentingTransformer() throws TransformerConfigurationException {
129         Transformer transformer = createTransformer();
130         transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
131         transformer.setOutputProperty(OutputKeys.INDENT, "no");
132         return transformer;
133     }
134 
135     /**
136      * Logs the given {@link Source source} to the {@link #logger}, using the message as a prefix.
137      * <p/>
138      * By default, this message creates a string representation of the given source, and delegates to {@link
139      * #logMessage(String)}.
140      *
141      * @param logMessage the log message
142      * @param source     the source to be logged
143      * @throws TransformerException in case of errors
144      */
145     protected void logMessageSource(String logMessage, Source source) throws TransformerException {
146         if (source != null) {
147             Transformer transformer = createNonIndentingTransformer();
148             StringWriter writer = new StringWriter();
149             transformer.transform(source, new StreamResult(writer));
150             String message = logMessage + writer.toString();
151             logMessage(message);
152         }
153     }
154 
155     /**
156      * Logs the given string message.
157      * <p/>
158      * By default, this method uses a "debug" level of logging. Subclasses can override this method to change the level
159      * of logging used by the logger.
160      *
161      * @param message the message
162      */
163     protected void logMessage(String message) {
164         logger.debug(message);
165     }
166 
167     /**
168      * Abstract template method that returns the <code>Source</code> for the given <code>WebServiceMessage</code>.
169      *
170      * @param message the message
171      * @return the source of the message
172      */
173     protected abstract Source getSource(WebServiceMessage message);
174 }