blob: 32e0391ee63cc1ae99a63f8e9acec8549a9fa8d4 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.util;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.util.Map;
import java.util.TreeMap;
import javax.xml.transform.stream.StreamSource;
import org.apache.camel.Exchange;
import org.apache.camel.Message;
import org.apache.camel.StreamCache;
import org.apache.camel.component.file.GenericFile;
import org.apache.camel.converter.jaxp.BytesSource;
import org.apache.camel.converter.jaxp.StringSource;
/**
* Some helper methods when working with {@link org.apache.camel.Message}.
*
* @version
*/
public final class MessageHelper {
/**
* Utility classes should not have a public constructor.
*/
private MessageHelper() {
}
/**
* Extracts the given body and returns it as a String, that
* can be used for logging etc.
* <p/>
* Will handle stream based bodies wrapped in StreamCache.
*
* @param message the message with the body
* @return the body as String, can return <tt>null</null> if no body
*/
public static String extractBodyAsString(Message message) {
if (message == null) {
return null;
}
StreamCache newBody = message.getBody(StreamCache.class);
if (newBody != null) {
message.setBody(newBody);
}
Object answer = message.getBody(String.class);
if (answer == null) {
answer = message.getBody();
}
if (newBody != null) {
// Reset the InputStreamCache
newBody.reset();
}
return answer != null ? answer.toString() : null;
}
/**
* Gets the given body class type name as a String.
* <p/>
* Will skip java.lang. for the build in Java types.
*
* @param message the message with the body
* @return the body typename as String, can return <tt>null</null> if no body
*/
public static String getBodyTypeName(Message message) {
if (message == null) {
return null;
}
String answer = ObjectHelper.classCanonicalName(message.getBody());
if (answer != null && answer.startsWith("java.lang.")) {
return answer.substring(10);
}
return answer;
}
/**
* If the message body contains a {@link StreamCache} instance, reset the cache to
* enable reading from it again.
*
* @param message the message for which to reset the body
*/
public static void resetStreamCache(Message message) {
if (message == null) {
return;
}
if (message.getBody() instanceof StreamCache) {
((StreamCache) message.getBody()).reset();
}
}
/**
* Returns the MIME content type on the message or <tt>null</tt> if none defined
*/
public static String getContentType(Message message) {
return message.getHeader(Exchange.CONTENT_TYPE, String.class);
}
/**
* Returns the MIME content encoding on the message or <tt>null</tt> if none defined
*/
public static String getContentEncoding(Message message) {
return message.getHeader(Exchange.CONTENT_ENCODING, String.class);
}
/**
* Extracts the body for logging purpose.
* <p/>
* Will clip the body if its too big for logging.
* Will prepend the message with <tt>Message: </tt>
*
* @see org.apache.camel.Exchange#LOG_DEBUG_BODY_STREAMS
* @see org.apache.camel.Exchange#LOG_DEBUG_BODY_MAX_CHARS
* @param message the message
* @return the logging message
*/
public static String extractBodyForLogging(Message message) {
return extractBodyForLogging(message, "Message: ");
}
/**
* Extracts the body for logging purpose.
* <p/>
* Will clip the body if its too big for logging.
*
* @see org.apache.camel.Exchange#LOG_DEBUG_BODY_STREAMS
* @see org.apache.camel.Exchange#LOG_DEBUG_BODY_MAX_CHARS
* @param message the message
* @param prepend a message to prepend
* @return the logging message
*/
public static String extractBodyForLogging(Message message, String prepend) {
boolean streams = false;
if (message.getExchange() != null) {
String property = message.getExchange().getContext().getProperties().get(Exchange.LOG_DEBUG_BODY_STREAMS);
if (property != null) {
streams = message.getExchange().getContext().getTypeConverter().convertTo(Boolean.class, property);
}
}
// default to 1000 chars
int maxChars = 1000;
if (message.getExchange() != null) {
String property = message.getExchange().getContext().getProperties().get(Exchange.LOG_DEBUG_BODY_MAX_CHARS);
if (property != null) {
maxChars = message.getExchange().getContext().getTypeConverter().convertTo(Integer.class, property);
}
}
return extractBodyForLogging(message, prepend, streams, maxChars);
}
/**
* Extracts the body for logging purpose.
* <p/>
* Will clip the body if its too big for logging.
*
* @see org.apache.camel.Exchange#LOG_DEBUG_BODY_MAX_CHARS
* @param message the message
* @param prepend a message to prepend
* @param allowStreams whether or not streams is allowed
* @param maxChars limit to maximum number of chars. Use 0 or negative value to not limit at all.
* @return the logging message
*/
public static String extractBodyForLogging(Message message, String prepend, boolean allowStreams, int maxChars) {
Object obj = message.getBody();
if (obj == null) {
return prepend + "[Body is null]";
}
if (obj instanceof StringSource || obj instanceof BytesSource) {
// these two are okay
} else if (!allowStreams && obj instanceof StreamCache) {
return prepend + "[Body is instance of org.apache.camel.StreamCache]";
} else if (!allowStreams && obj instanceof StreamSource) {
return prepend + "[Body is instance of java.xml.transform.StreamSource]";
} else if (!allowStreams && obj instanceof InputStream) {
return prepend + "[Body is instance of java.io.InputStream]";
} else if (!allowStreams && obj instanceof OutputStream) {
return prepend + "[Body is instance of java.io.OutputStream]";
} else if (!allowStreams && obj instanceof Reader) {
return prepend + "[Body is instance of java.io.Reader]";
} else if (!allowStreams && obj instanceof Writer) {
return prepend + "[Body is instance of java.io.Writer]";
} else if (obj instanceof GenericFile || obj instanceof File) {
return prepend + "[Body is file based: " + obj + "]";
}
// is the body a stream cache
StreamCache cache;
if (obj instanceof StreamCache) {
cache = (StreamCache) obj;
} else {
cache = null;
}
// grab the message body as a string
String body;
if (message.getExchange() != null) {
body = message.getExchange().getContext().getTypeConverter().convertTo(String.class, obj);
} else {
body = obj.toString();
}
// reset stream cache after use
if (cache != null) {
cache.reset();
}
if (body == null) {
return prepend + "[Body is null]";
}
// clip body if length enabled and the body is too big
if (maxChars > 0 && body.length() > maxChars) {
body = body.substring(0, maxChars) + "... [Body clipped after " + maxChars + " chars, total length is " + body.length() + "]";
}
return prepend + body;
}
/**
* Dumps the message as a generic XML structure.
*
* @param message the message
* @return the XML
*/
public static String dumpAsXml(Message message) {
StringBuilder sb = new StringBuilder();
sb.append("<message>\n");
// headers
if (message.hasHeaders()) {
sb.append("<headers>\n");
// sort the headers so they are listed A..Z
Map<String, Object> headers = new TreeMap<String, Object>(message.getHeaders());
for (Map.Entry<String, Object> entry : headers.entrySet()) {
Object value = entry.getValue();
String type = ObjectHelper.classCanonicalName(value);
sb.append("<header key=\"" + entry.getKey() + "\"");
if (type != null) {
sb.append(" type=\"" + type + "\"");
}
sb.append(">");
// dump header value as XML, use Camel type converter to convert to String
if (value != null) {
String xml = message.getExchange().getContext().getTypeConverter().convertTo(String.class, value);
if (xml != null) {
// is the header value already XML
if (xml.startsWith("<") && xml.endsWith(">")) {
sb.append(xml);
} else {
// no its not xml so xml encode it
sb.append(StringHelper.xmlEncode(xml));
}
}
}
sb.append("</header>\n");
}
sb.append("</headers>\n");
}
sb.append("<body");
String type = ObjectHelper.classCanonicalName(message.getBody());
if (type != null) {
sb.append(" type=\"" + type + "\"");
}
sb.append(">");
// dump body value as XML, use Camel type converter to convert to String
String xml = message.getBody(String.class);
if (xml != null) {
// is the body already XML
if (xml.startsWith("<") && xml.endsWith(">")) {
sb.append(xml);
} else {
// no its not xml so xml encode it
sb.append(StringHelper.xmlEncode(xml));
}
}
sb.append("</body>\n");
sb.append("</message>");
return sb.toString();
}
}