001: /*
002: * Copyright (c) 1998-2007 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Emil Ong
028: */
029:
030: package com.caucho.soap.jaxws;
031:
032: import com.caucho.soap.reflect.WebServiceIntrospector;
033: import com.caucho.soap.skeleton.Skeleton;
034: import com.caucho.util.L10N;
035: import com.caucho.util.ThreadPool;
036: import com.caucho.xml.stream.StaxUtil;
037: import com.caucho.xml.stream.XMLStreamReaderImpl;
038: import com.caucho.xml.stream.XMLStreamWriterImpl;
039:
040: import javax.xml.bind.JAXBContext;
041: import javax.xml.namespace.QName;
042:
043: import javax.xml.soap.SOAPException;
044: import static javax.xml.soap.SOAPConstants.*;
045:
046: import javax.xml.ws.AsyncHandler;
047: import javax.xml.ws.Binding;
048: import javax.xml.ws.BindingProvider;
049: import javax.xml.ws.Dispatch;
050: import javax.xml.ws.Response;
051: import javax.xml.ws.Service;
052: import javax.xml.ws.WebServiceException;
053: import javax.xml.ws.handler.HandlerResolver;
054: import javax.xml.ws.http.HTTPBinding;
055: import javax.xml.ws.soap.SOAPBinding;
056: import javax.xml.ws.spi.ServiceDelegate;
057:
058: import java.io.ByteArrayInputStream;
059: import java.io.ByteArrayOutputStream;
060: import java.io.CharArrayReader;
061: import java.io.CharArrayWriter;
062: import java.io.InputStream;
063: import java.io.IOException;
064: import java.io.OutputStream;
065: import java.io.OutputStreamWriter;
066:
067: import java.lang.reflect.Proxy;
068:
069: import java.net.MalformedURLException;
070: import java.net.URL;
071: import java.net.URLConnection;
072:
073: import java.util.HashMap;
074: import java.util.Iterator;
075: import java.util.Map;
076: import java.util.concurrent.Executor;
077: import java.util.concurrent.Future;
078: import java.util.logging.Logger;
079: import java.util.logging.Level;
080:
081: import org.w3c.dom.Document;
082: import org.w3c.dom.Node;
083:
084: /**
085: * Dispatch
086: */
087: public abstract class AbstractDispatch<T> implements Dispatch<T> {
088: private final static L10N L = new L10N(AbstractDispatch.class);
089: private final static Logger log = Logger
090: .getLogger(AbstractDispatch.class.getName());
091:
092: protected final String _bindingId;
093: protected final Executor _executor;
094: protected Service.Mode _mode;
095: protected String _soapNamespace;
096:
097: protected final Binding _binding;
098: protected final HashMap<String, Object> _requestContext = new HashMap<String, Object>();
099: protected final HashMap<String, Object> _responseContext = new HashMap<String, Object>();
100:
101: public AbstractDispatch(String bindingId, Binding binding,
102: Service.Mode mode, Executor executor)
103: throws WebServiceException {
104: _bindingId = bindingId;
105: _mode = mode;
106: _executor = executor;
107: _binding = binding;
108:
109: if (bindingId.equals(SOAPBinding.SOAP11HTTP_BINDING)
110: || bindingId
111: .equals(SOAPBinding.SOAP11HTTP_MTOM_BINDING))
112: _soapNamespace = URI_NS_SOAP_1_1_ENVELOPE;
113: else if (bindingId.equals(SOAPBinding.SOAP12HTTP_BINDING)
114: || bindingId
115: .equals(SOAPBinding.SOAP12HTTP_MTOM_BINDING))
116: _soapNamespace = URI_NS_SOAP_1_2_ENVELOPE;
117: else if (bindingId.equals(HTTPBinding.HTTP_BINDING))
118: _mode = Service.Mode.MESSAGE;
119: else
120: throw new WebServiceException(L.l(
121: "Unknown binding id: {0}", bindingId));
122: }
123:
124: //
125: // javax.xml.ws.Dispatch
126: //
127:
128: public T invoke(T msg) throws WebServiceException {
129: if (log.isLoggable(Level.FINEST))
130: log.finest("AbstractDispatch.invoke(" + msg + ")");
131:
132: ResponseImpl<T> response = new ResponseImpl<T>();
133:
134: invokeNow(msg, response);
135:
136: try {
137: return response.get();
138: } catch (Exception e) {
139: throw new WebServiceException(e);
140: }
141: }
142:
143: public Response<T> invokeAsync(T msg) {
144: if (log.isLoggable(Level.FINEST))
145: log.finest("AbstractDispatch.invokeAsync(" + msg + ")");
146:
147: ResponseImpl<T> response = new ResponseImpl<T>();
148:
149: _executor.execute(new AsyncInvoker(msg, response));
150:
151: return response;
152: }
153:
154: public Future<?> invokeAsync(T msg, AsyncHandler<T> handler) {
155: if (log.isLoggable(Level.FINEST))
156: log.finest("AbstractDispatch.invokeAsync(" + msg + ","
157: + handler + ")");
158:
159: ResponseImpl<T> response = new ResponseImpl<T>();
160:
161: _executor.execute(new AsyncInvoker(msg, response, handler));
162:
163: return response;
164: }
165:
166: public void invokeOneWay(T msg) throws WebServiceException {
167: if (log.isLoggable(Level.FINEST))
168: log.finest("AbstractDispatch.invokeOneWay(" + msg + ")");
169:
170: invokeNow(msg, null);
171: }
172:
173: //
174: // javax.xml.ws.BindingProvider
175: //
176:
177: public Binding getBinding() {
178: return _binding;
179: }
180:
181: public Map<String, Object> getRequestContext() {
182: return _requestContext;
183: }
184:
185: public Map<String, Object> getResponseContext() {
186: return _responseContext;
187: }
188:
189: protected abstract void writeRequest(T msg, OutputStream out)
190: throws WebServiceException;
191:
192: protected abstract T formatResponse(byte[] response)
193: throws WebServiceException;
194:
195: private void invokeNow(T msg, ResponseImpl<T> response)
196: throws WebServiceException {
197: if (log.isLoggable(Level.FINEST))
198: log.finest("AbstractDispatch.invokeNow(" + msg + ")");
199:
200: InputStream in = null;
201: OutputStream out = null;
202:
203: try {
204: String urlSpec = (String) _requestContext
205: .get(ENDPOINT_ADDRESS_PROPERTY);
206:
207: if (urlSpec == null)
208: throw new WebServiceException(L
209: .l("Endpoint address not set"));
210:
211: URL url = new URL(urlSpec);
212: URLConnection connection = url.openConnection();
213:
214: if (response != null)
215: connection.setDoInput(true);
216:
217: connection.setDoOutput(true);
218:
219: // send request
220: out = connection.getOutputStream();
221:
222: OutputStreamWriter writer = null;
223:
224: if (_mode == Service.Mode.PAYLOAD) {
225: writer = new OutputStreamWriter(out);
226:
227: JAXWSUtil
228: .writeStartSOAPEnvelope(writer, _soapNamespace);
229: }
230:
231: writeRequest(msg, out);
232:
233: if (_mode == Service.Mode.PAYLOAD)
234: JAXWSUtil.writeEndSOAPEnvelope(writer);
235:
236: out.flush();
237:
238: // read response
239: in = connection.getInputStream();
240:
241: // XXX for some reason, it seems this is necessary to force the output
242: if (response == null) {
243: while (in.read() >= 0) {
244: }
245:
246: return;
247: }
248:
249: ByteArrayOutputStream buffer = new ByteArrayOutputStream();
250:
251: if (_mode == Service.Mode.PAYLOAD) {
252: JAXWSUtil.extractSOAPBody(in, buffer);
253: } else {
254: // XXX is a copy necessary here or should we expect the client to
255: // close the InputStream?
256: int ch = -1;
257:
258: while ((ch = in.read()) != -1)
259: buffer.write(ch);
260: }
261:
262: response.set(formatResponse(buffer.toByteArray()));
263: response.setContext(connection.getHeaderFields());
264: } catch (WebServiceException e) {
265: throw e;
266: } catch (Exception e) {
267: throw new WebServiceException(e);
268: } finally {
269: try {
270: if (out != null)
271: out.close();
272:
273: if (in != null)
274: in.close();
275: } catch (IOException e) {
276: throw new WebServiceException(e);
277: }
278: }
279: }
280:
281: protected class AsyncInvoker implements Runnable {
282: private final T _msg;
283: private final ResponseImpl<T> _response;
284: private final AsyncHandler<T> _handler;
285:
286: public AsyncInvoker(T msg, ResponseImpl<T> response) {
287: this (msg, response, null);
288: }
289:
290: public AsyncInvoker(T msg, ResponseImpl<T> response,
291: AsyncHandler<T> handler) {
292: _msg = msg;
293: _response = response;
294: _handler = handler;
295: }
296:
297: public void run() {
298: try {
299: invokeNow(_msg, _response);
300: } catch (Exception e) {
301: _response.setException(e);
302: }
303:
304: if (_handler != null)
305: _handler.handleResponse(_response);
306: }
307: }
308: }
|