2012-06-14 10 views
11

Ich habe an CXF mit serverseitigen Interzeptoren herumgespielt. Aber es scheint, dass es keine triviale Aufgabe ist, einfache eingehende und ausgehende Interzeptoren zu implementieren, die mir eine einfache Zeichenfolge geben, die das SOAP-XML enthält.Wie man ein- und ausgehende Seife xml auf einfache Weise mit Apache CXF erhalten?

Ich brauche das einfache XML im Interceptor, damit ich sie für bestimmte Protokollierungsaufgaben verwenden kann. Die Standard-LogIn & LogOut-Interzeptoren sind der Aufgabe nicht gewachsen. Ist jemand bereit, ein Beispiel zu geben, wie ich einen einfachen eingehenden Interceptor implementieren könnte, der in der Lage ist, den eingehenden SOAP-XML-Code und einen ausgehenden Interceptor zu erhalten, um den SOAP-XML-Code erneut zu erhalten?

Antwort

13

den Code für einen eingehenden Interceptor hier gefunden: Logging request/response with Apache CXF as XML

Postausgangs Interceptor:

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) { 
      } 
     } 
    } 
} 
+1

Was ist der Vorteil des Rückrufs? – Basil

+1

Die onClose() -Methode im Callback wird aufgerufen, nachdem der Ausgabestream geleert wurde und seine Daten für den Abruf verfügbar sind. – annkatrin

+1

Wofür steht das 'Limit' in diesem Beispiel? Es wird nirgendwo deklariert ... – Cleankod

6

ich nicht die oben genannte Lösung für mich arbeiten konnte. Dies ist, was ich entwickelt und hoffen, kann es anderen helfen:

Meine "incoming" Interceptor:

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); 
    } 
} 

Mein "outgoing" Interceptor:

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); 
    } 
} 

Etwas, das ich meiner Feder Rahmen Anwendung hinzugefügt Kontext-XML (denken Sie daran, die beiden Interzeptoren in der XML-Datei ebenfalls zu definieren) ...

Hinweis: Es gibt andere Möglichkeiten zum Hinzufügen der Interzeptoren, z. B. über Annotationen, mit denen Sie nur bestimmte Soap-Dienste abfangen können. Der obige Weg des Hinzufügens von Interzeptoren der "Bus" würde alle Ihre Soap-Dienste abfangen.

+0

Ich habe genau das gemacht, was Sie vorgeschlagen haben, aber mein 'loggingOutInterceptor' wurde nicht durchlaufen. Für den 'loggingInInterceptor' funktioniert es ordnungsgemäß als Erwartung. Weißt du, warum? Vielen Dank. – bryannguyen

4

Ich möchte nur eine weitere Option teilen, wie eingehende und ausgehende Nachrichten zur gleichen Zeit für einige Protokollierungszwecke, zum Beispiel Protokollanforderungen und entsprechende Antworten auf die Datenbank zu erhalten.

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(); 
} 
} 

und dann mit webservice

<jaxws:endpoint id="wsEndpoint" implementor="#myWS" address="/myWS" > 
    <jaxws:handlers> 
     <bean class="com.package.handlers.CxfLoggingHandler"/> 
    </jaxws:handlers> 
</jaxws:endpoint> 
+0

Es funktioniert perfekt, wenn 'if (outgoingMessage) {' mit 'if (!outboundMessage) {' – Ivano85

+0

Hm, sollte es sein" if (outgoingMessage) ". Da eingehende Nachrichten für die Zukunft gespeichert werden sollen und wir outgoingMessage haben, können wir die Daten protokollieren, da wir jetzt Zugriff auf eingehende und ausgehende Nachrichten haben. – error1009

+0

Entschuldigung, Sie haben Recht, denn dies ist ein Endpunkt: P ... Ich habe es Client-Seite verwendet, so war die ausgehende Nachricht in meinem Fall und die eingehende Nachricht die Antwort. Ich habe es sehr geschätzt, tolle Lösung ;-) – Ivano85

3

Beispiel für das Schreiben den Text in eine String, mit Haken, dass Handler verbinden einige benutzerdefinierte Eigenschaften und Filterung des Antrags XML für die Erfassung:

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; 
    } 
} 

Für ein voll funktionsfähiges Beispiel mit Ausgabe-Interzeptoren, siehe meine CXF module auf Github.