2012-12-13 22 views
5

Próbuję utworzyć zdalny program rozsyłający z CXF przy użyciu pliku javax.xml.w.Provider, jak wyjaśniono tutaj: http://cxf.apache.org/docs/jax-ws-dispatch-api.html. Mam klienta CXF skonfigurowany WSAddressing, SOAP12_HTTP_BINDING i następujących konfiguracjach WSS4J: WSS4JWysyłanie w usłudze CXF WS kończy się niepowodzeniem, a następnie wraca do klienta.

Klienta w przechwytujących:

inProps.put("action",     "Timestamp Signature Encrypt");  
inProps.put("passwordType",   "PasswordText"); 
    ... 

Client WSS4J OUT przechwytywania:

protected static final String WSU_NS = 
    "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd";           
protected static final String SOAP12_NS = "http://www.w3.org/2003/05/soap-envelope"; 
protected static final String SOAP11_NS = "http://schemas.xmlsoap.org/soap/envelope"; 
protected static final String WSA_NS = "http://www.w3.org/2005/08/addressing"; 
protected static final String WSSE_NS="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"; 

String userForPswCallback = ... 
Map<String, Object> props = new HashMap<String, Object>(); 
props.put("action",     "UsernameToken Timestamp Signature Encrypt"); 
props.put("passwordType",   "PasswordText"); 
... 
props.put("encryptionParts",  "{Content}{"+SOAP12_NS+"}Body;{Element}{"+WSSE_NS+"}UsernameToken"); 
props.put("signatureKeyIdentifier", "DirectReference"); 
props.put("signatureParts",   "{Element}{"+SOAP12_NS+"}Body;" + 
       "{Element}{"+WSSE_NS+"}UsernameToken;" + 
       "{Element}{"+WSA_NS+"}Action;" + 
       "{Element}{"+WSA_NS+"}MessageID;" + 
       "{Element}{"+WSA_NS+"}To;" + 
       "{Element}{"+WSA_NS+"}ReplyTo"); 

Na dyspozytora stronie publikuję następująca usługa wysyłająca:

@WebServiceProvider(targetNamespace = JettyConstants.PersistenceNameSpace, 
        serviceName=JettyConstants.PersistenceService, 
        portName=JettyConstants.PersistencePort) 
@ServiceMode (Service.Mode.MESSAGE) 
public class PersistenceProvider implements Provider<Source> { 
    private static final Logger log = Logger.getLogger(PersistenceProvider.class); 

    private TransformerFactory transformerFactory; 

    public PersistenceProvider() { 
     // Complete 
    } 

    private static final DocumentBuilderFactory BUILDER_FACTORY = DocumentBuilderFactory.newInstance(); 
    static { 
      BUILDER_FACTORY.setNamespaceAware(true); 
    } 

    public Source invoke(Source request) { 
     try { 
      DOMSource sourceInvoke = null; 

      //get userName and userPassword from the interceptor chain (added in a custom interceptor) 
      String userName = (String)(PhaseInterceptorChain.getCurrentMessage().get("product.username")); 
      String userPassword = (String)(PhaseInterceptorChain.getCurrentMessage().get("product.password")); 

      //insert extracted into a org.w3c.dom.Document 
      DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 
      dbf.setNamespaceAware(true); 
      DocumentBuilder builder = null; 
      org.w3c.dom.Document doc = null; 

      try { 
       builder = dbf.newDocumentBuilder(); 
       InputStream is = convertMessageToInputStream(request); 
       doc = builder.parse(is);     
      } catch (Exception e) { 
       e.printStackTrace(); 
       return null; 
      } 

      NodeList node = doc.getElementsByTagNameNS("*","Security"); 
      node.item(0).getParentNode().removeChild(node.item(0)); 

      // Add extra header to the envelop... 
      ... 

      sourceInvoke = new DOMSource(doc);     

      // 1. Resolve target service based on wsContext 
      QName targetService = new QName(JettyConstants.PersistenceNameSpace,JettyConstants.PersistenceService); 
      QName targetPort = new QName(JettyConstants.PersistenceNameSpace,JettyConstants.PersistencePort); 
      String targetEndpoint = DispatchStarter.getNewVelocityDestination(false)+"/Persistence"; 

    /* ****************************************** INVOKE THE REMOTE SERVER *************************************** */   
      // 2. Create dispatcher 
      Dispatch<Source> dispatcher = createDispatcher(targetService, targetPort, targetEndpoint);  

      // 3. Invoke target service 
      Source response = dispatcher.invoke(sourceInvoke);           

    /* *********************************************************************************************************** */   

      // 4. Return service response to consumer 
      DOMSource domS = toDOMSourceFromSAX((SAXSource)response); 

      //get the doc to modify it: 
      DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 
      dbf.setNamespaceAware(true); 
      DocumentBuilder builder = null; 
      org.w3c.dom.Document doc = null; 
      builder = dbf.newDocumentBuilder(); 
      doc = (org.w3c.dom.Document) domS.getNode();     

      // 4.1. Take just the body content out of the response received from the server: 
      NodeList body_el = doc.getElementsByTagNameNS("*", "Body").item(0).getChildNodes(); 

      DocumentBuilderFactory docf = DocumentBuilderFactory.newInstance(); 
      Document docnew = docf.newDocumentBuilder().newDocument(); 
      Node newNode = docnew.createElementNS(body_el.item(0).getNamespaceURI(), body_el.item(0).getLocalName()); 
      Node nodeComplete = docnew.adoptNode(body_el.item(0).cloneNode(true));  

      // 4.2. Create the SAXSource to send back to the client through CXF stack 
      ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 
      Source xmlSource = new DOMSource(nodeComplete); 
      Result outputTarget = new StreamResult(outputStream); 
      TransformerFactory.newInstance().newTransformer().transform(xmlSource, outputTarget); 
      InputStream is = new ByteArrayInputStream(outputStream.toByteArray()); 
      InputSource inputSource = new InputSource(is); 
      SAXSource finalRes = new SAXSource(inputSource);    

      return finalRes; 

     } catch (Exception ex) { 
      ex.printStackTrace(); 
     } 
     return null; 
    } 

    private Dispatch<Source> createDispatcher(QName serviceName, QName portName, String targetEndpoint) { 
     Service service = Service.create(serviceName);   
     String actualBinding = SOAPBinding.SOAP12HTTP_BINDING; 
     service.addPort(portName, actualBinding, targetEndpoint); 
     Dispatch<Source> dispatcher = service.createDispatch(portName, Source.class, 
       Service.Mode.MESSAGE); 
     return dispatcher; 
    } 
} 

PersistenceProvider (dyspozytor) jest opublikowany w następujących WSS4JInterceptors

Dispatcher WSS4J Dispatcher IN interceptors: 

    Map<String, Object> inProps = new HashMap<String, Object>(); 
    inProps.put(WSHandlerConstants.ACTION, "UsernameToken Timestamp Signature Encrypt"); 
    inProps.put("passwordType",   "PasswordText"); 
    ... 

Dispatcher WSS4J Dispatcher OUT interceptors: 

    protected static final String WSU_NS = 
     "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"; 

    protected static final String SOAP_NS = "http://www.w3.org/2003/05/soap-envelope"; 
    protected static final String WSA_NS = "http://www.w3.org/2005/08/addressing"; 

    outProps.put(WSHandlerConstants.ACTION, "Timestamp Signature Encrypt"); 
    outProps.put("passwordType",   "PasswordText"); 
    ... 
    outProps.put("encryptionParts",   "{Content}{"+SOAP_NS+"}Body"); 
    ... 
    outProps.put("signatureParts",   "{Element}{" + WSU_NS + "}Timestamp;" + 
         "{Element}{"+SOAP_NS+"}Body;" + 
         "{Element}{"+WSA_NS+"}Action;" + 
         "{Element}{"+WSA_NS+"}MessageID;" + 
         "{Element}{"+WSA_NS+"}To;" + 
         "{Element}{"+WSA_NS+"}RelatesTo"); 

i z włączonym WSAddressingFeature. Mogę przekierować żądania z mojego klienta na serwer zdalny i otrzymuję odpowiedź z powrotem od zdalnego serwera po stronie dyspozytora. Niestety, gdy próbuję wysłać odpowiedź z powrotem do klienta (czyli po zestawieniu powrotnej PersistenceProvider metodą # invoke) pojawia się następujący wyjątek:

{http://dbproxyservice/}PersistenceService#{http://dispatch/}invoke has thrown exception, unwinding now 
org.apache.cxf.binding.soap.SoapFault: Error creating SOAPMessage 
     at org.apache.cxf.jaxws.interceptors.MessageModeOutInterceptor$MessageModeOutInterceptorInternal.handleMessage(MessageModeOutInterceptor.java:210) 
     at org.apache.cxf.jaxws.interceptors.MessageModeOutInterceptor$MessageModeOutInterceptorInternal.handleMessage(MessageModeOutInterceptor.java:182) 
     at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263) 
     at org.apache.cxf.interceptor.OutgoingChainInterceptor.handleMessage(OutgoingChainInterceptor.java:77) 
     at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263) 
     at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:123) 
     at org.apache.cxf.transport.http_jetty.JettyHTTPDestination.serviceRequest(JettyHTTPDestination.java:323) 
     at org.apache.cxf.transport.http_jetty.JettyHTTPDestination.doService(JettyHTTPDestination.java:289) 
     at org.apache.cxf.transport.http_jetty.JettyHTTPHandler.handle(JettyHTTPHandler.java:72) 
     at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:942) 
     at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:878) 
     at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:117) 
     at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:250) 
     at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:110) 
     at org.eclipse.jetty.server.Server.handle(Server.java:349) 
     at org.eclipse.jetty.server.HttpConnection.handleRequest(HttpConnection.java:441) 
     at org.eclipse.jetty.server.HttpConnection$RequestHandler.content(HttpConnection.java:936) 
     at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:893) 
     at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:224) 
     at org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:52) 
     at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:586) 
     at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:44) 
     at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:598) 
     at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:533) 
     at java.lang.Thread.run(Thread.java:662) 
Caused by: com.ctc.wstx.exc.WstxEOFException: Unexpected EOF in prolog 
at [row,col {unknown-source}]: [1,0] 
     at com.ctc.wstx.sr.StreamScanner.throwUnexpectedEOF(StreamScanner.java:677) 
     at com.ctc.wstx.sr.BasicStreamReader.handleEOF(BasicStreamReader.java:2104) 
     at com.ctc.wstx.sr.BasicStreamReader.nextFromProlog(BasicStreamReader.java:2010) 
     at com.ctc.wstx.sr.BasicStreamReader.next(BasicStreamReader.java:1102) 
     at org.apache.cxf.staxutils.StaxUtils.copy(StaxUtils.java:551) 
     at org.apache.cxf.staxutils.StaxUtils.copy(StaxUtils.java:513) 
     at org.apache.cxf.staxutils.StaxUtils.copy(StaxUtils.java:467) 
     at org.apache.cxf.jaxws.interceptors.MessageModeOutInterceptor$MessageModeOutInterceptorInternal.handleMessage(MessageModeOutInterceptor.java:204) 
     ... 24 more 
[10Dec 18:59:51,881] ([email protected]) WARN PhaseInterceptorChain - Interceptor for {http://dbproxyservice/}PersistenceService#{http://dispatch/}invoke has thrown exception, unwinding now 
java.lang.NullPointerException 
     at org.apache.cxf.ws.addressing.ContextUtils.hasEmptyAction(ContextUtils.java:358) 
     at org.apache.cxf.ws.addressing.MAPAggregator.assembleGeneric(MAPAggregator.java:686) 
     at org.apache.cxf.ws.addressing.MAPAggregator.aggregate(MAPAggregator.java:660) 
     at org.apache.cxf.ws.addressing.MAPAggregator.mediate(MAPAggregator.java:515) 
     at org.apache.cxf.ws.addressing.MAPAggregator.handleMessage(MAPAggregator.java:228) 
     at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263) 
     at org.apache.cxf.interceptor.AbstractFaultChainInitiatorObserver.onMessage(AbstractFaultChainInitiatorObserver.java:107) 
     at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:323) 
     at org.apache.cxf.interceptor.OutgoingChainInterceptor.handleMessage(OutgoingChainInterceptor.java:77) 
     at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263) 
     at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:123) 
     at org.apache.cxf.transport.http_jetty.JettyHTTPDestination.serviceRequest(JettyHTTPDestination.java:323) 
     at org.apache.cxf.transport.http_jetty.JettyHTTPDestination.doService(JettyHTTPDestination.java:289) 
     at org.apache.cxf.transport.http_jetty.JettyHTTPHandler.handle(JettyHTTPHandler.java:72) 
     at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:942) 
     at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:878) 
     at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:117) 
     at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:250) 
     at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:110) 
     at org.eclipse.jetty.server.Server.handle(Server.java:349) 
     at org.eclipse.jetty.server.HttpConnection.handleRequest(HttpConnection.java:441) 
     at org.eclipse.jetty.server.HttpConnection$RequestHandler.content(HttpConnection.java:936) 
     at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:893) 
     at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:224) 
     at org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:52) 
     at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:586) 
     at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:44) 
     at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:598) 
     at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:533) 
     at java.lang.Thread.run(Thread.java:662) 

masz żadnych wskazówek, aby uniknąć tego błędu? W szczególności, co mam zrobić, aby wysłać odpowiedź invoke z powrotem do klienta za pośrednictwem stosu CXF? Czy to prawda, aby pozbyć się wszystkich nagłówków ze zdalnego serwera w punkcie 4 żądania powyżej PersistenceProvider #? Zrobiłem to, ponieważ myślałem, że przetworniki CXF od dyspozytora zbudują kopertę od podstaw wokół Ciała. Czy to jest poprawne?

Dziękujemy!

Odpowiedz

1

Gotcha! Rzeczą, która działa, jest transformacja javax.xml.transform.Source zwrócona przez metodę invoke w PersistenceProvider (dispatcher) do DOMSource. To pozwala CXF prawidłowo wypełniać ciało wychodzące mydlanej otoczki.

Problem rozwiązany. Pełna historia here!

Powiązane problemy