/* * JBoss, Home of Professional Open Source. * Copyright 2010, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.wsf.stack.cxf.saaj; import static org.jboss.wsf.stack.cxf.Messages.MESSAGES; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.xml.soap.MessageFactory; import javax.xml.soap.MimeHeader; import javax.xml.soap.MimeHeaders; import javax.xml.soap.SOAPConnection; import javax.xml.soap.SOAPConstants; import javax.xml.soap.SOAPException; import javax.xml.soap.SOAPMessage; import org.apache.cxf.Bus; import org.apache.cxf.BusFactory; import org.apache.cxf.helpers.IOUtils; import org.apache.cxf.helpers.LoadingByteArrayOutputStream; import org.apache.cxf.message.Exchange; import org.apache.cxf.message.ExchangeImpl; import org.apache.cxf.message.Message; import org.apache.cxf.message.MessageImpl; import org.apache.cxf.service.model.EndpointInfo; import org.apache.cxf.transport.Conduit; import org.apache.cxf.transport.ConduitInitiator; import org.apache.cxf.transport.ConduitInitiatorManager; import org.apache.cxf.transport.MessageObserver; import org.apache.cxf.transport.http.HTTPConduit; import org.jboss.logging.Logger; public class SOAPConnectionImpl extends SOAPConnection { private volatile boolean closed = false; @Override public SOAPMessage call(SOAPMessage msgOut, Object addressObject) throws SOAPException { checkClosed(); String address = getAddress(addressObject); ConduitInitiator ci = getConduitInitiator(address); // create a new Message and Exchange EndpointInfo info = new EndpointInfo(); info.setAddress(address); Message outMessage = new MessageImpl(); Exchange exch = new ExchangeImpl(); outMessage.setExchange(exch); exch.put("org.apache.cxf.transport.process_fault_on_http_400", true); //JBWS-3945 // sent SOAPMessage try { final Conduit c = ci.getConduit(info, BusFactory.getThreadDefaultBus(false)); //TODO verify bus if (msgOut.saveRequired()) { msgOut.saveChanges(); } Map<String, List<String>> outHeaders = new HashMap<String, List<String>>(); for (Iterator<?> it = msgOut.getMimeHeaders().getAllHeaders(); it.hasNext();) { MimeHeader mimeHeader = (MimeHeader)it.next(); if ("Content-Type".equals(mimeHeader.getName())) { outMessage.put(Message.CONTENT_TYPE, mimeHeader.getValue()); } // disable the chunked encoding if requested if ("Transfer-Encoding".equals(mimeHeader.getName()) && "disabled".equals(mimeHeader.getValue()) && c instanceof HTTPConduit) { ((HTTPConduit)c).getClient().setAllowChunking(false); continue; } List<String> values = outHeaders.get(mimeHeader.getName()); if (values == null) { values = new ArrayList<String>(); outHeaders.put(mimeHeader.getName(), values); } values.add(mimeHeader.getValue()); } outMessage.put(Message.HTTP_REQUEST_METHOD, "POST"); outMessage.put(Message.PROTOCOL_HEADERS, outHeaders); c.prepare(outMessage); OutputStream outs = outMessage.getContent(OutputStream.class); msgOut.writeTo(outs); c.setMessageObserver(createMessageObserver(c)); c.close(outMessage); } catch (Exception ex) { throw MESSAGES.soapMessageCouldNotBeSent(ex); } // read SOAPMessage return readSoapMessage(exch); } @Override public SOAPMessage get(Object addressObject) throws SOAPException { checkClosed(); String address = getAddress(addressObject); ConduitInitiator ci = getConduitInitiator(address); // create a new Message and Exchange EndpointInfo info = new EndpointInfo(); info.setAddress(address); Message outMessage = new MessageImpl(); Exchange exch = new ExchangeImpl(); outMessage.setExchange(exch); // sent GET request try { final Conduit c = ci.getConduit(info, BusFactory.getThreadDefaultBus(false)); //TODO verify bus if (c instanceof HTTPConduit) { ((HTTPConduit)c).getClient().setAutoRedirect(true); } outMessage.put(Message.HTTP_REQUEST_METHOD, "GET"); c.prepare(outMessage); c.setMessageObserver(createMessageObserver(c)); c.close(outMessage); } catch (Exception ex) { throw MESSAGES.getRequestCouldNotBeSent(ex); } // read SOAPMessage return readSoapMessage(exch); } @Override public void close() throws SOAPException { if (this.closed) { throw MESSAGES.connectionAlreadyClosed(); } this.closed = true; } private String getAddress(Object addressObject) throws SOAPException { if (addressObject instanceof URL || addressObject instanceof String) { return addressObject.toString(); } throw MESSAGES.addressTypeNotSupported(addressObject.getClass()); } private ConduitInitiator getConduitInitiator(String address) throws SOAPException { ConduitInitiator ci = null; try { //do not use getThreadDefaultBus(true) in order to avoid getting the default bus Bus bus = BusFactory.getThreadDefaultBus(false); if (bus == null) { bus = BusFactory.newInstance().createBus(); } ConduitInitiatorManager mgr = bus.getExtension(ConduitInitiatorManager.class); if (address.startsWith("http")) { ci = mgr.getConduitInitiator("http://cxf.apache.org/transports/http"); } if (ci == null) { ci = mgr.getConduitInitiatorForUri(address); } } catch (Exception ex) { throw MESSAGES.noConduitInitiatorAvailableFor2(address, ex); } if (ci == null) { throw MESSAGES.noConduitInitiatorAvailableFor(address); } return ci; } @SuppressWarnings("unchecked") private MessageObserver createMessageObserver(final Conduit c) { return new MessageObserver() { public void onMessage(Message inMessage) { LoadingByteArrayOutputStream bout = new LoadingByteArrayOutputStream(); try { IOUtils.copy(inMessage.getContent(InputStream.class), bout); inMessage.getExchange().put(InputStream.class, bout.createInputStream()); Map<String, List<String>> inHeaders = (Map<String, List<String>>)inMessage.get(Message.PROTOCOL_HEADERS); inMessage.getExchange().put(Message.PROTOCOL_HEADERS, inHeaders); c.close(inMessage); } catch (IOException e) { //ignore Logger.getLogger(SOAPConnectionImpl.class).trace(e); } } }; } @SuppressWarnings("unchecked") private SOAPMessage readSoapMessage(Exchange exch) throws SOAPException { // read SOAPMessage try { InputStream ins = exch.get(InputStream.class); Map<String, List<String>> inHeaders = (Map<String, List<String>>)exch.get(Message.PROTOCOL_HEADERS); MimeHeaders mimeHeaders = new MimeHeaders(); if (inHeaders != null) { for (Map.Entry<String, List<String>> entry : inHeaders.entrySet()) { if (entry.getValue() != null) { for (String value : entry.getValue()) { mimeHeaders.addHeader(entry.getKey(), value); } } } } if (ins == null) return null; //if inputstream is empty, no need to build if (ins.markSupported()) { ins.mark(1); final int bytesRead = ins.read(new byte[1]); ins.reset(); if (bytesRead == -1) { return null; } } else if (ins.available() == 0) { return null; } MessageFactory msgFac = MessageFactory.newInstance(SOAPConstants.DYNAMIC_SOAP_PROTOCOL); return msgFac.createMessage(mimeHeaders, ins); } catch (Exception ex) { throw MESSAGES.soapMessageCouldNotBeRead(ex); } } private void checkClosed() throws SOAPException { if (closed) { throw MESSAGES.cantSendMessagesOnClosedConnection(); } } }