001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.servicemix.components.http;
018:
019: import java.io.IOException;
020: import java.util.Iterator;
021: import java.util.Map;
022: import java.util.Map.Entry;
023:
024: import javax.jbi.JBIException;
025: import javax.jbi.component.ComponentContext;
026: import javax.jbi.messaging.DeliveryChannel;
027: import javax.jbi.messaging.ExchangeStatus;
028: import javax.jbi.messaging.InOnly;
029: import javax.jbi.messaging.InOut;
030: import javax.jbi.messaging.MessageExchange;
031: import javax.jbi.messaging.MessageExchangeFactory;
032: import javax.jbi.messaging.NormalizedMessage;
033: import javax.servlet.ServletException;
034: import javax.servlet.http.HttpServletRequest;
035: import javax.servlet.http.HttpServletResponse;
036: import javax.xml.XMLConstants;
037: import javax.xml.transform.Source;
038: import javax.xml.transform.dom.DOMSource;
039:
040: import org.apache.servicemix.components.util.ComponentSupport;
041: import org.apache.servicemix.jbi.jaxp.SourceTransformer;
042: import org.codehaus.xfire.DefaultXFire;
043: import org.codehaus.xfire.MessageContext;
044: import org.codehaus.xfire.XFire;
045: import org.codehaus.xfire.aegis.AegisBindingProvider;
046: import org.codehaus.xfire.attachments.Attachment;
047: import org.codehaus.xfire.attachments.Attachments;
048: import org.codehaus.xfire.fault.XFireFault;
049: import org.codehaus.xfire.service.Service;
050: import org.codehaus.xfire.service.invoker.BeanInvoker;
051: import org.codehaus.xfire.service.binding.ObjectServiceFactory;
052: import org.codehaus.xfire.soap.SoapConstants;
053: import org.codehaus.xfire.soap.handler.ReadHeadersHandler;
054: import org.codehaus.xfire.transport.http.XFireServletController;
055: import org.w3c.dom.Document;
056: import org.w3c.dom.Element;
057: import org.w3c.dom.Node;
058:
059: public class HttpSoapInOutBinding extends ComponentSupport implements
060: HttpBinding {
061:
062: protected XFire xfire;
063: protected XFireServletController controller;
064: protected Service service;
065: protected boolean defaultInOut = true;
066: protected String soapAction = "\"\"";
067: protected SourceTransformer transformer;
068:
069: public HttpSoapInOutBinding() {
070: }
071:
072: public void init(ComponentContext context) throws JBIException {
073: super .init(context);
074: xfire = new DefaultXFire();
075: ObjectServiceFactory factory = new ObjectServiceFactory(xfire
076: .getTransportManager(), new AegisBindingProvider());
077: factory.setVoidOneWay(true);
078: factory.setStyle(SoapConstants.STYLE_DOCUMENT);
079: if (isDefaultInOut()) {
080: service = factory.create(InOutService.class);
081: service.setInvoker(new BeanInvoker(new InOutService(this )));
082: } else {
083: service = factory.create(InOnlyService.class);
084: service
085: .setInvoker(new BeanInvoker(new InOnlyService(this )));
086: }
087: xfire.getServiceRegistry().register(service);
088: controller = new Controller(xfire);
089: transformer = new SourceTransformer();
090: }
091:
092: public void process(HttpServletRequest request,
093: HttpServletResponse response) throws ServletException,
094: IOException {
095: controller.doService(request, response);
096: }
097:
098: public void invokeInOnly(Source source, MessageContext context)
099: throws XFireFault {
100: if (source == null) {
101: throw new XFireFault("Invalid source.", XFireFault.SENDER);
102: }
103: try {
104: if (soapAction != null) {
105: XFireServletController.getResponse().setHeader(
106: "SOAPAction", soapAction);
107: }
108: DeliveryChannel channel = getDeliveryChannel();
109: MessageExchangeFactory factory = channel
110: .createExchangeFactory();
111: InOnly exchange = factory.createInOnlyExchange();
112: populateExchange(exchange, source, context);
113: boolean result = channel.sendSync(exchange);
114: if (!result) {
115: throw new XFireFault("Error sending exchange",
116: XFireFault.SENDER);
117: }
118: } catch (XFireFault e) {
119: throw e;
120: } catch (Exception e) {
121: throw new XFireFault(e);
122: }
123: }
124:
125: public Source invokeInOut(Source source, MessageContext context)
126: throws XFireFault {
127: if (source == null) {
128: throw new XFireFault("Invalid source.", XFireFault.SENDER);
129: }
130: try {
131: if (soapAction != null) {
132: XFireServletController.getResponse().setHeader(
133: "SOAPAction", soapAction);
134: }
135: DeliveryChannel channel = getDeliveryChannel();
136: MessageExchangeFactory factory = channel
137: .createExchangeFactory();
138: InOut exchange = factory.createInOutExchange();
139: populateExchange(exchange, source, context);
140: boolean result = channel.sendSync(exchange);
141: if (!result) {
142: throw new XFireFault("Error sending exchange",
143: XFireFault.SENDER);
144: }
145: if (exchange.getStatus() == ExchangeStatus.ERROR) {
146: Exception e = exchange.getError();
147: if (e == null) {
148: throw new XFireFault("Received error",
149: XFireFault.SENDER);
150: } else {
151: throw new XFireFault(e, XFireFault.SENDER);
152: }
153: }
154: NormalizedMessage outMessage = exchange.getOutMessage();
155: if (outMessage == null) {
156: exchange.setError(new Exception(
157: "Expected an out message"));
158: channel.sendSync(exchange);
159: throw new XFireFault("No response", XFireFault.SENDER);
160: }
161: Source src = exchange.getOutMessage().getContent();
162: exchange.setStatus(ExchangeStatus.DONE);
163: channel.send(exchange);
164: src = transformer.toDOMSource(src);
165: return src;
166: } catch (XFireFault e) {
167: throw e;
168: } catch (Exception e) {
169: throw new XFireFault(e);
170: }
171: }
172:
173: protected void populateExchange(MessageExchange exchange,
174: Source src, MessageContext ctx) throws Exception {
175: // TODO: Retrieve properties
176: NormalizedMessage inMessage = exchange.createMessage();
177: // Add removed namespace declarations from the parents
178: Map namespaces = (Map) ctx
179: .getProperty(ReadHeadersHandler.DECLARED_NAMESPACES);
180: Node node = transformer.toDOMNode(src);
181: Element element;
182: if (node instanceof Element) {
183: element = (Element) node;
184: } else if (node instanceof Document) {
185: element = ((Document) node).getDocumentElement();
186: } else {
187: throw new UnsupportedOperationException(
188: "Unable to handle nodes of type "
189: + node.getNodeType());
190: }
191: // Copy embedded namespaces from the envelope into the body root
192: for (Iterator it = namespaces.entrySet().iterator(); it
193: .hasNext();) {
194: Entry entry = (Entry) it.next();
195: if (element.getAttributes().getNamedItemNS(
196: XMLConstants.XMLNS_ATTRIBUTE_NS_URI,
197: (String) entry.getKey()) == null) {
198: element.setAttributeNS(
199: XMLConstants.XMLNS_ATTRIBUTE_NS_URI,
200: XMLConstants.XMLNS_ATTRIBUTE + ":"
201: + (String) entry.getKey(),
202: (String) entry.getValue());
203: }
204: }
205: // Set the source
206: inMessage.setContent(new DOMSource(element));
207: // Retrieve attachments
208: Attachments attachments = (Attachments) ctx.getInMessage()
209: .getAttachments();
210: if (attachments != null) {
211: for (Iterator it = attachments.getParts(); it.hasNext();) {
212: Attachment part = (Attachment) it.next();
213: inMessage.addAttachment(part.getId(), part
214: .getDataHandler());
215: }
216: }
217: exchange.setMessage(inMessage, "in");
218: }
219:
220: public static class InOnlyService {
221: private HttpSoapInOutBinding component;
222:
223: public InOnlyService() {
224: }
225:
226: public InOnlyService(HttpSoapInOutBinding component) {
227: this .component = component;
228: }
229:
230: public void invokeInOnly(Source source, MessageContext context)
231: throws XFireFault {
232: this .component.invokeInOnly(source, context);
233: }
234: }
235:
236: public static class InOutService {
237: private HttpSoapInOutBinding component;
238:
239: public InOutService() {
240: }
241:
242: public InOutService(HttpSoapInOutBinding component) {
243: this .component = component;
244: }
245:
246: public Source invokeInOut(Source source, MessageContext context)
247: throws XFireFault {
248: return this .component.invokeInOut(source, context);
249: }
250: }
251:
252: public class Controller extends XFireServletController {
253: public Controller(XFire xfire) {
254: super (xfire);
255: }
256:
257: protected String getService(HttpServletRequest request) {
258: return service.getSimpleName();
259: }
260: }
261:
262: // Properties
263: //-------------------------------------------------------------------------
264: public boolean isDefaultInOut() {
265: return defaultInOut;
266: }
267:
268: /**
269: * Sets whether an InOut (the default) or an InOnly message exchange will be used by default.
270: */
271: public void setDefaultInOut(boolean defaultInOut) {
272: this .defaultInOut = defaultInOut;
273: }
274:
275: public String getSoapAction() {
276: return soapAction;
277: }
278:
279: public void setSoapAction(String soapAction) {
280: this.soapAction = soapAction;
281: }
282:
283: }
|