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 }