001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied. See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019
020 package org.apache.geronimo.cxf.ejb;
021
022 import java.lang.reflect.Method;
023 import java.util.List;
024
025 import javax.interceptor.AroundInvoke;
026 import javax.interceptor.InvocationContext;
027 import javax.xml.soap.SOAPMessage;
028 import javax.xml.stream.XMLStreamReader;
029 import javax.xml.transform.dom.DOMSource;
030 import javax.xml.ws.Binding;
031
032 import org.apache.commons.logging.Log;
033 import org.apache.commons.logging.LogFactory;
034 import org.apache.cxf.Bus;
035 import org.apache.cxf.binding.soap.SoapMessage;
036 import org.apache.cxf.binding.soap.interceptor.MustUnderstandInterceptor;
037 import org.apache.cxf.endpoint.Endpoint;
038 import org.apache.cxf.interceptor.AbstractInDatabindingInterceptor;
039 import org.apache.cxf.interceptor.Interceptor;
040 import org.apache.cxf.interceptor.InterceptorChain;
041 import org.apache.cxf.interceptor.OutgoingChainInterceptor;
042 import org.apache.cxf.interceptor.ServiceInvokerInterceptor;
043 import org.apache.cxf.jaxws.handler.logical.LogicalHandlerInInterceptor;
044 import org.apache.cxf.jaxws.handler.soap.SOAPHandlerInterceptor;
045 import org.apache.cxf.jaxws.support.JaxWsEndpointImpl;
046 import org.apache.cxf.message.Exchange;
047 import org.apache.cxf.message.Message;
048 import org.apache.cxf.phase.PhaseInterceptorChain;
049 import org.apache.cxf.phase.PhaseManager;
050 import org.apache.cxf.service.Service;
051 import org.apache.cxf.staxutils.StaxUtils;
052 import org.w3c.dom.Element;
053
054 public class EJBInterceptor {
055
056 private static final Log LOG = LogFactory.getLog(EJBInterceptor.class);
057
058 private Exchange exchange;
059 private Bus bus;
060 private EJBEndpoint ejbEndpoint;
061 private List<Object> params;
062 private Method method;
063
064 public EJBInterceptor(List<Object> params,
065 Method method,
066 EJBEndpoint endpoint,
067 Bus bus,
068 Exchange exchange) {
069 this.params = params;
070 this.method = method;
071 this.ejbEndpoint = endpoint;
072 this.bus = bus;
073 this.exchange = exchange;
074 }
075
076 private static void copyDataBindingInterceptors(PhaseInterceptorChain newChain,
077 InterceptorChain oldChain) {
078 for (Interceptor interceptor : oldChain) {
079 if (interceptor instanceof AbstractInDatabindingInterceptor) {
080 LOG.debug("Added data binding interceptor: " + interceptor);
081 newChain.add(interceptor);
082 }
083 }
084 }
085
086 @AroundInvoke
087 public Object intercept(InvocationContext context) throws Exception {
088 Endpoint endpoint = this.exchange.get(Endpoint.class);
089 Service service = endpoint.getService();
090 Binding binding = ((JaxWsEndpointImpl) endpoint).getJaxwsBinding();
091
092 this.exchange.put(InvocationContext.class, context);
093
094 if (binding.getHandlerChain() == null || binding.getHandlerChain().isEmpty()) {
095 // no handlers so let's just directly invoke the bean
096 LOG.debug("No handlers found.");
097
098 EJBMethodInvoker invoker = (EJBMethodInvoker) service.getInvoker();
099 return invoker.directEjbInvoke(this.exchange, this.method, this.params);
100
101 } else {
102 // have handlers so have to run handlers now and redo data binding
103 // as handlers can change the soap message
104 LOG.debug("Handlers found.");
105
106 // inject handlers (on first call only)
107 this.ejbEndpoint.injectHandlers();
108
109 Message inMessage = this.exchange.getInMessage();
110 PhaseInterceptorChain chain =
111 new PhaseInterceptorChain(this.bus.getExtension(PhaseManager.class).getInPhases());
112
113 chain.setFaultObserver(endpoint.getOutFaultObserver());
114
115 /*
116 * Since we have to re-do data binding and the XMLStreamReader
117 * contents are already consumed by prior data binding step
118 * we have to reinitialize the XMLStreamReader from the SOAPMessage
119 * created by SAAJInInterceptor.
120 */
121 if (inMessage instanceof SoapMessage) {
122 try {
123 reserialize((SoapMessage)inMessage);
124 } catch (Exception e) {
125 throw new RuntimeException("Failed to reserialize soap message", e);
126 }
127 } else {
128 // TODO: how to handle XML/HTTP binding?
129 }
130
131 this.exchange.setOutMessage(null);
132
133 // install default interceptors
134 chain.add(new ServiceInvokerInterceptor());
135 chain.add(new OutgoingChainInterceptor());
136
137 // install interceptors for handler processing
138 chain.add(new MustUnderstandInterceptor());
139 chain.add(new LogicalHandlerInInterceptor(binding));
140 chain.add(new SOAPHandlerInterceptor(binding));
141
142 // install data binding interceptors
143 copyDataBindingInterceptors(chain, inMessage.getInterceptorChain());
144
145 InterceptorChain oldChain = inMessage.getInterceptorChain();
146 inMessage.setInterceptorChain(chain);
147 try {
148 chain.doIntercept(inMessage);
149 } finally {
150 inMessage.setInterceptorChain(oldChain);
151 }
152
153 // TODO: the result should be deserialized from SOAPMessage
154 Object result = getResult();
155
156 return result;
157 }
158 }
159
160 private Object getResult() {
161 Message outMessage = this.exchange.getOutMessage();
162 if (outMessage == null) {
163 return null;
164 } else {
165 List<?> result = outMessage.getContent(List.class);
166 if (result == null) {
167 return outMessage.get(Object.class);
168 } else if (result.isEmpty()) {
169 return null;
170 } else {
171 return result.get(0);
172 }
173 }
174 }
175
176 private void reserialize(SoapMessage message) throws Exception {
177 SOAPMessage soapMessage = message.getContent(SOAPMessage.class);
178 if (soapMessage == null) {
179 return;
180 }
181
182 XMLStreamReader xmlReader = message.getContent(XMLStreamReader.class);
183 StaxUtils.readDocElements(soapMessage.getSOAPBody(), xmlReader, true);
184 DOMSource bodySource = new DOMSource(soapMessage.getSOAPPart().getEnvelope().getBody());
185 xmlReader = StaxUtils.createXMLStreamReader(bodySource);
186 xmlReader.nextTag();
187 xmlReader.nextTag(); // move past body tag
188 message.setContent(XMLStreamReader.class, xmlReader);
189 }
190
191 }