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 }