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: */package org.apache.cxf.jaxws;
019:
020: import java.lang.reflect.InvocationHandler;
021: import java.lang.reflect.Method;
022: import java.net.HttpURLConnection;
023: import java.util.HashMap;
024: import java.util.Map;
025: import java.util.concurrent.ConcurrentHashMap;
026: import java.util.concurrent.FutureTask;
027: import java.util.logging.Logger;
028:
029: import javax.xml.namespace.QName;
030: import javax.xml.soap.SOAPFault;
031: import javax.xml.ws.AsyncHandler;
032: import javax.xml.ws.Binding;
033: import javax.xml.ws.BindingProvider; //TODO JAX-WS 2.1
034: //import javax.xml.ws.EndpointReference;
035: import javax.xml.ws.Response;
036: import javax.xml.ws.WebServiceException;
037: import javax.xml.ws.handler.MessageContext.Scope;
038: import javax.xml.ws.http.HTTPBinding;
039: import javax.xml.ws.http.HTTPException;
040: import javax.xml.ws.soap.SOAPBinding;
041: import javax.xml.ws.soap.SOAPFaultException;
042:
043: import org.w3c.dom.Node;
044:
045: import org.apache.cxf.binding.soap.SoapFault;
046: import org.apache.cxf.common.i18n.Message;
047: import org.apache.cxf.common.logging.LogUtils;
048: import org.apache.cxf.endpoint.Client;
049: import org.apache.cxf.endpoint.Endpoint;
050: import org.apache.cxf.frontend.MethodDispatcher;
051: import org.apache.cxf.helpers.CastUtils;
052: import org.apache.cxf.jaxws.context.WrappedMessageContext;
053: import org.apache.cxf.jaxws.support.ContextPropertiesMapping;
054: import org.apache.cxf.service.model.BindingOperationInfo;
055:
056: public class JaxWsClientProxy extends
057: org.apache.cxf.frontend.ClientProxy implements
058: InvocationHandler, BindingProvider {
059:
060: private static final Logger LOG = LogUtils
061: .getL7dLogger(JaxWsClientProxy.class);
062:
063: protected Map<String, Object> requestContext = new ConcurrentHashMap<String, Object>();
064:
065: protected ThreadLocal<Map<String, Object>> responseContext = new ThreadLocal<Map<String, Object>>();
066:
067: private final Binding binding;
068:
069: public JaxWsClientProxy(Client c, Binding b) {
070: super (c);
071: this .binding = b;
072: setupEndpointAddressContext(getClient().getEndpoint());
073: }
074:
075: private void setupEndpointAddressContext(Endpoint endpoint) {
076: // NOTE for jms transport the address would be null
077: if (null != endpoint
078: && null != endpoint.getEndpointInfo().getAddress()) {
079: getRequestContext().put(
080: BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
081: endpoint.getEndpointInfo().getAddress());
082: }
083: }
084:
085: public Object invoke(Object proxy, Method method, Object[] args)
086: throws Throwable {
087:
088: Endpoint endpoint = getClient().getEndpoint();
089: String address = endpoint.getEndpointInfo().getAddress();
090: MethodDispatcher dispatcher = (MethodDispatcher) endpoint
091: .getService().get(MethodDispatcher.class.getName());
092: BindingOperationInfo oi = dispatcher.getBindingOperation(
093: method, endpoint);
094: if (oi == null) {
095: // check for method on BindingProvider and Object
096: if (method.getDeclaringClass()
097: .equals(BindingProvider.class)
098: || method.getDeclaringClass().equals(
099: BindingProviderImpl.class)
100: || method.getDeclaringClass().equals(Object.class)) {
101: return method.invoke(this );
102: }
103:
104: Message msg = new Message("NO_OPERATION_INFO", LOG, method
105: .getName());
106: throw new WebServiceException(msg.toString());
107: }
108:
109: Object[] params = args;
110: if (null == params) {
111: params = new Object[0];
112: }
113:
114: Map<String, Object> reqContext = this .getRequestContextCopy();
115: Map<String, Object> respContext = this .getResponseContext();
116:
117: // Clear the response context's hold information
118: // Not call the clear Context is to avoid the error
119: // that getResponseContext() could be called by Client code first
120: respContext.clear();
121:
122: Map<String, Object> context = new HashMap<String, Object>();
123:
124: // need to do context mapping from jax-ws to cxf message
125: ContextPropertiesMapping.mapRequestfromJaxws2Cxf(reqContext);
126:
127: context.put(Client.REQUEST_CONTEXT, reqContext);
128: context.put(Client.RESPONSE_CONTEXT, respContext);
129:
130: reqContext.put(Method.class.getName(), method);
131: reqContext.put(Client.REQUEST_METHOD, method);
132: boolean isAsync = method.getName().endsWith("Async");
133:
134: Object result = null;
135: try {
136: if (isAsync) {
137: result = invokeAsync(method, oi, params, context);
138: } else {
139: result = invokeSync(method, oi, params, context);
140: }
141: } catch (WebServiceException wex) {
142: throw wex.fillInStackTrace();
143: } catch (Exception ex) {
144: for (Class<?> excls : method.getExceptionTypes()) {
145: if (excls.isInstance(ex)) {
146: throw ex.fillInStackTrace();
147: }
148: }
149:
150: if (getBinding() instanceof HTTPBinding) {
151: HTTPException exception = new HTTPException(
152: HttpURLConnection.HTTP_INTERNAL_ERROR);
153: exception.initCause(ex);
154: throw exception;
155: } else if (getBinding() instanceof SOAPBinding) {
156: SOAPFault soapFault = ((SOAPBinding) getBinding())
157: .getSOAPFactory().createFault();
158:
159: if (ex instanceof SoapFault) {
160: soapFault.setFaultString(((SoapFault) ex)
161: .getReason());
162: soapFault.setFaultCode(((SoapFault) ex)
163: .getFaultCode());
164:
165: Node nd = soapFault.getOwnerDocument().importNode(
166: ((SoapFault) ex).getOrCreateDetail(), true);
167: soapFault.addDetail().appendChild(nd);
168:
169: } else {
170: soapFault.setFaultCode(new QName(
171: "http://cxf.apache.org/faultcode",
172: "HandlerFault"));
173: String msg = ex.getMessage();
174: if (msg != null) {
175: soapFault.setFaultString(msg);
176: }
177: }
178:
179: SOAPFaultException exception = new SOAPFaultException(
180: soapFault);
181: exception.initCause(ex);
182: throw exception;
183: } else {
184: throw new WebServiceException(ex);
185: }
186: } finally {
187: if (addressChanged(address)) {
188: setupEndpointAddressContext(getClient().getEndpoint());
189: }
190: }
191:
192: // need to do context mapping from cxf message to jax-ws
193: ContextPropertiesMapping.mapResponsefromCxf2Jaxws(respContext);
194: Map<String, Scope> scopes = CastUtils
195: .cast((Map<?, ?>) respContext
196: .get(WrappedMessageContext.SCOPES));
197: if (scopes != null) {
198: for (Map.Entry<String, Scope> scope : scopes.entrySet()) {
199: if (scope.getValue() == Scope.HANDLER) {
200: respContext.remove(scope.getKey());
201: }
202: }
203: }
204: return result;
205:
206: }
207:
208: private boolean addressChanged(String address) {
209: return !(address == null
210: || getClient().getEndpoint().getEndpointInfo() == null || address
211: .equals(getClient().getEndpoint().getEndpointInfo()
212: .getAddress()));
213: }
214:
215: private Object invokeAsync(Method method, BindingOperationInfo oi,
216: Object[] params, Map<String, Object> context) {
217:
218: FutureTask<Object> f = new FutureTask<Object>(
219: new JAXWSAsyncCallable(this , method, oi, params,
220: context));
221:
222: Endpoint endpoint = getClient().getEndpoint();
223: endpoint.getExecutor().execute(f);
224: Response<?> r = new AsyncResponse<Object>(f, Object.class);
225: if (params.length > 0
226: && params[params.length - 1] instanceof AsyncHandler) {
227: // callback style
228: AsyncCallbackFuture callback = new AsyncCallbackFuture(r,
229: (AsyncHandler) params[params.length - 1]);
230: endpoint.getExecutor().execute(callback);
231: return callback;
232: } else {
233: return r;
234: }
235: }
236:
237: private Map<String, Object> getRequestContextCopy() {
238: Map<String, Object> realMap = new HashMap<String, Object>();
239: WrappedMessageContext ctx = new WrappedMessageContext(realMap,
240: Scope.APPLICATION);
241: for (Map.Entry<String, Object> ent : requestContext.entrySet()) {
242: ctx.put(ent.getKey(), ent.getValue());
243: }
244: return realMap;
245: }
246:
247: public Map<String, Object> getRequestContext() {
248: return requestContext;
249: }
250:
251: public Map<String, Object> getResponseContext() {
252: if (null == responseContext.get()) {
253: responseContext.set(new HashMap<String, Object>());
254: }
255: return responseContext.get();
256: }
257:
258: public Binding getBinding() {
259: return binding;
260: }
261:
262: /*
263: // TODO JAX-WS 2.1
264: public EndpointReference getEndpointReference() {
265: // TODO
266: throw new UnsupportedOperationException();
267: }
268:
269: public <T extends EndpointReference> T getEndpointReference(Class<T> clazz) {
270: // TODO
271: throw new UnsupportedOperationException();
272: }
273: */
274: }
|