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: */package org.apache.geronimo.cxf;
017:
018: import java.io.IOException;
019: import java.io.OutputStream;
020: import java.io.Serializable;
021: import java.io.InputStream;
022: import java.net.HttpURLConnection;
023: import java.security.Principal;
024: import java.util.Iterator;
025: import java.util.ArrayList;
026: import java.util.List;
027: import java.util.Map;
028: import java.util.Enumeration;
029: import java.util.logging.Logger;
030: import javax.servlet.ServletContext;
031: import javax.servlet.http.HttpServletRequest;
032: import javax.servlet.http.HttpServletResponse;
033: import javax.xml.ws.handler.MessageContext;
034:
035: import org.apache.cxf.Bus;
036: import org.apache.cxf.message.Message;
037: import org.apache.cxf.message.MessageImpl;
038: import org.apache.cxf.security.SecurityContext;
039: import org.apache.cxf.service.model.EndpointInfo;
040: import org.apache.cxf.transport.Conduit;
041: import org.apache.cxf.transport.ConduitInitiator;
042: import org.apache.cxf.transport.Destination;
043: import org.apache.cxf.transport.MessageObserver;
044: import org.apache.cxf.transport.http.AbstractHTTPDestination;
045: import org.apache.cxf.ws.addressing.EndpointReferenceType;
046: import org.apache.geronimo.webservices.WebServiceContainer;
047: import org.apache.geronimo.webservices.WebServiceContainer.Request;
048: import org.apache.geronimo.webservices.WebServiceContainer.Response;
049:
050: public class GeronimoDestination extends AbstractHTTPDestination
051: implements Serializable {
052:
053: private MessageObserver messageObserver;
054: private boolean passSecurityContext = false;
055:
056: public GeronimoDestination(Bus bus,
057: ConduitInitiator conduitInitiator, EndpointInfo endpointInfo)
058: throws IOException {
059: super (bus, conduitInitiator, endpointInfo, true);
060: }
061:
062: public void setPassSecurityContext(boolean passSecurityContext) {
063: this .passSecurityContext = passSecurityContext;
064: }
065:
066: public boolean getPassSecurityContext() {
067: return this .passSecurityContext;
068: }
069:
070: public EndpointInfo getEndpointInfo() {
071: return this .endpointInfo;
072: }
073:
074: public void invoke(Request request, Response response)
075: throws Exception {
076: MessageImpl message = new MessageImpl();
077: message.setContent(InputStream.class, request.getInputStream());
078: message.setDestination(this );
079:
080: message.put(Request.class, request);
081: message.put(Response.class, response);
082:
083: final HttpServletRequest servletRequest = (HttpServletRequest) request
084: .getAttribute(WebServiceContainer.SERVLET_REQUEST);
085: message.put(MessageContext.SERVLET_REQUEST, servletRequest);
086:
087: HttpServletResponse servletResponse = (HttpServletResponse) request
088: .getAttribute(WebServiceContainer.SERVLET_RESPONSE);
089: message.put(MessageContext.SERVLET_RESPONSE, servletResponse);
090:
091: ServletContext servletContext = (ServletContext) request
092: .getAttribute(WebServiceContainer.SERVLET_CONTEXT);
093: message.put(MessageContext.SERVLET_CONTEXT, servletContext);
094:
095: if (this .passSecurityContext) {
096: message.put(SecurityContext.class, new SecurityContext() {
097: public Principal getUserPrincipal() {
098: return servletRequest.getUserPrincipal();
099: }
100:
101: public boolean isUserInRole(String role) {
102: return servletRequest.isUserInRole(role);
103: }
104: });
105: }
106:
107: // this calls copyRequestHeaders()
108: setHeaders(message);
109:
110: message.put(Message.HTTP_REQUEST_METHOD, servletRequest
111: .getMethod());
112: message.put(Message.PATH_INFO, servletRequest.getPathInfo());
113: message.put(Message.QUERY_STRING, servletRequest
114: .getQueryString());
115: message.put(Message.CONTENT_TYPE, servletRequest
116: .getContentType());
117: message.put(Message.ENCODING,
118: getCharacterEncoding(servletRequest
119: .getCharacterEncoding()));
120:
121: messageObserver.onMessage(message);
122: }
123:
124: private static String getCharacterEncoding(String encoding) {
125: if (encoding != null) {
126: encoding = encoding.trim();
127: // work around a bug with Jetty which results in the character
128: // encoding not being trimmed correctly:
129: // http://jira.codehaus.org/browse/JETTY-302
130: if (encoding.endsWith("\"")) {
131: encoding = encoding.substring(0, encoding.length() - 1);
132: }
133: }
134: return encoding;
135: }
136:
137: protected void copyRequestHeaders(Message message,
138: Map<String, List<String>> headers) {
139: HttpServletRequest servletRequest = (HttpServletRequest) message
140: .get(MessageContext.SERVLET_REQUEST);
141: if (servletRequest != null) {
142: Enumeration names = servletRequest.getHeaderNames();
143: while (names.hasMoreElements()) {
144: String name = (String) names.nextElement();
145:
146: List<String> headerValues = headers.get(name);
147: if (headerValues == null) {
148: headerValues = new ArrayList<String>();
149: headers.put(name, headerValues);
150: }
151:
152: Enumeration values = servletRequest.getHeaders(name);
153: while (values.hasMoreElements()) {
154: String value = (String) values.nextElement();
155: headerValues.add(value);
156: }
157: }
158: }
159: }
160:
161: public Logger getLogger() {
162: return Logger.getLogger(GeronimoDestination.class.getName());
163: }
164:
165: public Conduit getInbuiltBackChannel(Message inMessage) {
166: return new BackChannelConduit(null, inMessage);
167: }
168:
169: public Conduit getBackChannel(Message inMessage,
170: Message partialResponse, EndpointReferenceType address)
171: throws IOException {
172: Conduit backChannel = null;
173: if (address == null) {
174: backChannel = new BackChannelConduit(address, inMessage);
175: } else {
176: if (partialResponse != null) {
177: // setup the outbound message to for 202 Accepted
178: partialResponse.put(Message.RESPONSE_CODE,
179: HttpURLConnection.HTTP_ACCEPTED);
180: backChannel = new BackChannelConduit(address, inMessage);
181: } else {
182: backChannel = conduitInitiator.getConduit(endpointInfo,
183: address);
184: // ensure decoupled back channel input stream is closed
185: backChannel.setMessageObserver(new MessageObserver() {
186: public void onMessage(Message m) {
187: if (m.getContentFormats().contains(
188: InputStream.class)) {
189: InputStream is = m
190: .getContent(InputStream.class);
191: try {
192: is.close();
193: } catch (Exception e) {
194: // ignore
195: }
196: }
197: }
198: });
199: }
200: }
201: return backChannel;
202: }
203:
204: public void shutdown() {
205: }
206:
207: public void setMessageObserver(MessageObserver messageObserver) {
208: this .messageObserver = messageObserver;
209: }
210:
211: protected class BackChannelConduit implements Conduit {
212:
213: protected Message request;
214: protected EndpointReferenceType target;
215:
216: BackChannelConduit(EndpointReferenceType target, Message request) {
217: this .target = target;
218: this .request = request;
219: }
220:
221: public void close(Message msg) throws IOException {
222: msg.getContent(OutputStream.class).close();
223: }
224:
225: /**
226: * Register a message observer for incoming messages.
227: *
228: * @param observer the observer to notify on receipt of incoming
229: */
230: public void setMessageObserver(MessageObserver observer) {
231: // shouldn't be called for a back channel conduit
232: }
233:
234: public void prepare(Message message) throws IOException {
235: send(message);
236: }
237:
238: /**
239: * Send an outbound message, assumed to contain all the name-value
240: * mappings of the corresponding input message (if any).
241: *
242: * @param message the message to be sent.
243: */
244: public void send(Message message) throws IOException {
245: Response response = (Response) request.get(Response.class);
246:
247: // handle response headers
248: updateResponseHeaders(message);
249:
250: Map<String, List<String>> protocolHeaders = (Map<String, List<String>>) message
251: .get(Message.PROTOCOL_HEADERS);
252:
253: // set headers of the HTTP response object
254: Iterator headers = protocolHeaders.entrySet().iterator();
255: while (headers.hasNext()) {
256: Map.Entry entry = (Map.Entry) headers.next();
257: String headerName = (String) entry.getKey();
258: String headerValue = getHeaderValue((List) entry
259: .getValue());
260: response.setHeader(headerName, headerValue);
261: }
262:
263: message.setContent(OutputStream.class,
264: new WrappedOutputStream(message, response));
265: }
266:
267: /**
268: * @return the reference associated with the target Destination
269: */
270: public EndpointReferenceType getTarget() {
271: return target;
272: }
273:
274: /**
275: * Retreive the back-channel Destination.
276: *
277: * @return the backchannel Destination (or null if the backchannel is
278: * built-in)
279: */
280: public Destination getBackChannel() {
281: return null;
282: }
283:
284: /**
285: * Close the conduit
286: */
287: public void close() {
288: }
289: }
290:
291: private String getHeaderValue(List<String> values) {
292: Iterator iter = values.iterator();
293: StringBuffer buf = new StringBuffer();
294: while (iter.hasNext()) {
295: buf.append(iter.next());
296: if (iter.hasNext()) {
297: buf.append(", ");
298: }
299: }
300: return buf.toString();
301: }
302:
303: protected void setContentType(Message message, Response response) {
304: Map<String, List<String>> protocolHeaders = (Map<String, List<String>>) message
305: .get(Message.PROTOCOL_HEADERS);
306:
307: if (protocolHeaders == null
308: || !protocolHeaders.containsKey(Message.CONTENT_TYPE)) {
309: String ct = (String) message.get(Message.CONTENT_TYPE);
310: String enc = (String) message.get(Message.ENCODING);
311:
312: if (null != ct) {
313: if (enc != null && ct.indexOf("charset=") == -1) {
314: ct = ct + "; charset=" + enc;
315: }
316: response.setContentType(ct);
317: } else if (enc != null) {
318: response.setContentType("text/xml; charset=" + enc);
319: }
320: }
321: }
322:
323: private class WrappedOutputStream extends OutputStream {
324:
325: private Message message;
326: private Response response;
327: private OutputStream rawOutputStream;
328:
329: WrappedOutputStream(Message message, Response response) {
330: this .message = message;
331: this .response = response;
332: }
333:
334: public void write(int b) throws IOException {
335: flushHeaders();
336: this .rawOutputStream.write(b);
337: }
338:
339: public void write(byte b[]) throws IOException {
340: flushHeaders();
341: this .rawOutputStream.write(b);
342: }
343:
344: public void write(byte b[], int off, int len)
345: throws IOException {
346: flushHeaders();
347: this .rawOutputStream.write(b, off, len);
348: }
349:
350: public void flush() throws IOException {
351: flushHeaders();
352: this .rawOutputStream.flush();
353: }
354:
355: public void close() throws IOException {
356: flushHeaders();
357: this .rawOutputStream.close();
358: }
359:
360: protected void flushHeaders() throws IOException {
361: if (this .rawOutputStream != null) {
362: return;
363: }
364:
365: // set response code
366: Integer i = (Integer) this .message
367: .get(Message.RESPONSE_CODE);
368: if (i != null) {
369: this .response.setStatusCode(i.intValue());
370: }
371:
372: // set content-type
373: setContentType(this.message, this.response);
374:
375: this.rawOutputStream = this.response.getOutputStream();
376: }
377:
378: }
379:
380: }
|