Как получить входящий и исходящий soap xml простым способом с помощью Apache CXF?
я возился с перехватчиками на стороне сервера на CXF. Но кажется, что это не тривиальная задача реализовать простые входящие и исходящие перехватчики, которые дают мне простую строку, содержащую SOAP XML.
Мне нужно иметь простой XML в перехватчике, чтобы я мог использовать их для конкретных задач ведения журнала. Стандартные перехватчики входа и выхода из системы не справляются с этой задачей. Кто-нибудь готов поделиться примером того, как я мог бы реализовать простой входящий перехватчик, который может получить входящий SOAP XML и исходящий перехватчик, чтобы снова получить SOAP XML?
4 ответов
нашел код для входящего перехватчика здесь: запрос/ответ регистрации с Apache CXF как XML
мой исходящий перехватчик:
import java.io.OutputStream;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.io.CacheAndWriteOutputStream;
import org.apache.cxf.io.CachedOutputStream;
import org.apache.cxf.io.CachedOutputStreamCallback;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.Phase;
public class MyLogInterceptor extends LoggingOutInterceptor {
public MyLogInterceptor() {
super(Phase.PRE_STREAM);
}
@Override
public void handleMessage(Message message) throws Fault {
OutputStream out = message.getContent(OutputStream.class);
final CacheAndWriteOutputStream newOut = new CacheAndWriteOutputStream(out);
message.setContent(OutputStream.class, newOut);
newOut.registerCallback(new LoggingCallback());
}
public class LoggingCallback implements CachedOutputStreamCallback {
public void onFlush(CachedOutputStream cos) {
}
public void onClose(CachedOutputStream cos) {
try {
StringBuilder builder = new StringBuilder();
cos.writeCacheTo(builder, limit);
// here comes my xml:
String soapXml = builder.toString();
} catch (Exception e) {
}
}
}
}
Я не мог заставить вышеупомянутое решение работать на меня. Это то, что я разработал и надеюсь, что это может помочь другим:
мой" входящий " перехватчик:
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingMessage;
public class MyCxfSoapInInterceptor extends LoggingInInterceptor {
public MyCxfSoapInInterceptor() {
super();
}
@Override
protected String formatLoggingMessage(LoggingMessage loggingMessage) {
String soapXmlPayload = loggingMessage.getPayload() != null ? loggingMessage.getPayload().toString() : null;
// do what you want with the payload... in my case, I stuck it in a JMS Queue
return super.formatLoggingMessage(loggingMessage);
}
}
мой" исходящий " перехватчик:
import org.apache.cxf.interceptor.LoggingMessage;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
public class MyCxfSoapOutInterceptor extends LoggingOutInterceptor {
public MyCxfSoapOutInterceptor() {
super();
}
@Override
protected String formatLoggingMessage(LoggingMessage loggingMessage) {
String soapXmlPayload = loggingMessage.getPayload() != null ? loggingMessage.getPayload().toString() : null;
// do what you want with the payload... in my case, I stuck it in a JMS Queue
return super.formatLoggingMessage(loggingMessage);
}
}
что-то, что я добавил в свой контекст приложения spring framework XML (не забудьте также определить два перехватчика в XML-файле)...
...
<cxf:bus>
<cxf:inInterceptors>
<ref bean="myCxfSoapInInterceptor"/>
</cxf:inInterceptors>
<cxf:inFaultInterceptors>
<ref bean="myCxfSoapInInterceptor"/>
</cxf:inFaultInterceptors>
<cxf:outInterceptors>
<ref bean="myCxfSoapOutInterceptor"/>
</cxf:outInterceptors>
<cxf:outFaultInterceptors>
<ref bean="myCxfSoapOutInterceptor"/>
</cxf:outFaultInterceptors>
</cxf:bus>
...
Примечание, есть и другие способы добавить перехватчики, такие как через аннотации, которые позволят вам перехватывать только определенные службы soap. Вышеуказанный способ добавления перехватчиков "шина" перехватит все ваши службы soap.
Я просто хочу поделиться еще одним вариантом, как одновременно получать входящие и исходящие сообщения для некоторых целей ведения журнала, например, запросы журнала и соответствующие ответы на базу данных.
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import java.io.StringWriter;
import java.util.Collections;
import java.util.Set;
public class CxfLoggingHandler implements SOAPHandler<SOAPMessageContext> {
private static final String SOAP_REQUEST_MSG_KEY = "REQ_MSG";
public Set<QName> getHeaders() {
return Collections.EMPTY_SET;
}
public boolean handleMessage(SOAPMessageContext context) {
Boolean outgoingMessage = (Boolean) context.get (MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (outgoingMessage) {
// it is outgoing message. let's work
SOAPPart request = (SOAPPart)context.get(SOAP_REQUEST_MSG_KEY);
String requestString = convertDomToString(request);
String responseString = convertDomToString(context.getMessage().getSOAPPart());
String soapActionURI = ((QName)context.get(MessageContext.WSDL_OPERATION)).getLocalPart();
// now you can output your request, response, and ws-operation
} else {
// it is incoming message, saving it for future
context.put(SOAP_REQUEST_MSG_KEY, context.getMessage().getSOAPPart());
}
return true;
}
public boolean handleFault(SOAPMessageContext context) {
return handleMessage(context);
}
private String convertDomToString(SOAPPart soap){
final StringWriter sw = new StringWriter();
try {
TransformerFactory.newInstance().newTransformer().transform(
new DOMSource(soap),
new StreamResult(sw));
} catch (TransformerException e) {
// do something
}
return sw.toString();
}
}
а затем подключите этот обработчик к webservice
<jaxws:endpoint id="wsEndpoint" implementor="#myWS" address="/myWS" >
<jaxws:handlers>
<bean class="com.package.handlers.CxfLoggingHandler"/>
</jaxws:handlers>
</jaxws:endpoint>
Пример записи текста в StringBuffer, с крючками для захвата некоторых пользовательских свойств и фильтрации запроса XML:
public class XMLLoggingInInterceptor extends AbstractPhaseInterceptor<Message> {
private static final String LOCAL_NAME = "MessageID";
private static final int PROPERTIES_SIZE = 128;
private String name = "<interceptor name not set>";
protected PrettyPrinter prettyPrinter = null;
protected Logger logger;
protected Level reformatSuccessLevel;
protected Level reformatFailureLevel;
public XMLLoggingInInterceptor() {
this(LogUtils.getLogger(XMLLoggingInInterceptor.class), Level.INFO, Level.WARNING);
}
public XMLLoggingInInterceptor(PrettyPrinter prettyPrinter) {
this(LogUtils.getLogger(XMLLoggingInInterceptor.class), Level.INFO, Level.WARNING);
this.prettyPrinter = prettyPrinter;
}
public XMLLoggingInInterceptor(Logger logger, Level reformatSuccessLevel, Level reformatFailureLevel) {
super(Phase.RECEIVE);
this.logger = logger;
this.reformatSuccessLevel = reformatSuccessLevel;
this.reformatFailureLevel = reformatFailureLevel;
}
public XMLLoggingInInterceptor(PrettyPrinter prettyPrinter, Logger logger, Level reformatSuccessLevel, Level reformatFailureLevel) {
this(logger, reformatSuccessLevel, reformatFailureLevel);
this.prettyPrinter = prettyPrinter;
this.logger = logger;
}
public void setName(String name) {
this.name = name;
}
public void handleMessage(Message message) throws Fault {
if (!logger.isLoggable(reformatSuccessLevel)) {
return;
}
InputStream in = message.getContent(InputStream.class);
if (in == null) {
return;
}
StringBuilder buffer;
CachedOutputStream cache = new CachedOutputStream();
try {
InputStream origIn = in;
IOUtils.copy(in, cache);
if (cache.size() > 0) {
in = cache.getInputStream();
} else {
in = new ByteArrayInputStream(new byte[0]);
}
// set the inputstream back as message payload
message.setContent(InputStream.class, in);
cache.close();
origIn.close();
int contentSize = (int) cache.size();
buffer = new StringBuilder(contentSize + PROPERTIES_SIZE);
cache.writeCacheTo(buffer, "UTF-8");
} catch (IOException e) {
throw new Fault(e);
}
// decode chars from bytes
char[] chars = new char[buffer.length()];
buffer.getChars(0, chars.length, chars, 0);
// reuse buffer
buffer.setLength(0);
// perform local logging - to the buffer
buffer.append(name);
logProperties(buffer, message);
// pretty print XML
if(prettyPrinter.process(chars, 0, chars.length, buffer)) {
// log as normal
logger.log(reformatSuccessLevel, buffer.toString());
} else {
// something unexpected - log as exception
buffer.append(" was unable to format XML:\n");
buffer.append(chars); // unmodified XML
logger.log(reformatFailureLevel, buffer.toString());
}
}
/**
* Gets theMessageID header in the list of headers.
*
*/
protected String getIdHeader(Message message) {
return getHeader(message, LOCAL_NAME);
}
protected String getHeader(Message message, String name) {
List<Header> headers = (List<Header>) message.get(Header.HEADER_LIST);
if(headers != null) {
for(Header header:headers) {
if(header.getName().getLocalPart().equalsIgnoreCase(name)) {
return header.getObject().toString();
}
}
}
return null;
}
/**
* Method intended for use within subclasses. Log custom field here.
*
* @param message message
*/
protected void logProperties(StringBuilder buffer, Message message) {
final String messageId = getIdHeader(message);
if(messageId != null) {
buffer.append(" MessageId=");
buffer.append(messageId);
}
}
public void setPrettyPrinter(PrettyPrinter prettyPrinter) {
this.prettyPrinter = prettyPrinter;
}
public PrettyPrinter getPrettyPrinter() {
return prettyPrinter;
}
public Logger getLogger() {
return logger;
}
public String getName() {
return name;
}
public Level getReformatFailureLevel() {
return reformatFailureLevel;
}
public Level getReformatSuccessLevel() {
return reformatSuccessLevel;
}
public void setReformatFailureLevel(Level reformatFailureLevel) {
this.reformatFailureLevel = reformatFailureLevel;
}
public void setReformatSuccessLevel(Level reformatSuccessLevel) {
this.reformatSuccessLevel = reformatSuccessLevel;
}
public void setLogger(Logger logger) {
this.logger = logger;
}
}
для полностью рабочего примера с выходными перехватчиками см. my модуль CXF на github.