001: /**
002: *
003: * Licensed to the Apache Software Foundation (ASF) under one or more
004: * contributor license agreements. See the NOTICE file distributed with
005: * this work for additional information regarding copyright ownership.
006: * The ASF licenses this file to You under the Apache License, Version 2.0
007: * (the "License"); you may not use this file except in compliance with
008: * 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, software
013: * distributed under the License is distributed on an "AS IS" BASIS,
014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */package org.apache.openejb.server.cxf;
018:
019: import org.apache.cxf.Bus;
020: import org.apache.cxf.message.Message;
021: import org.apache.cxf.message.MessageImpl;
022: import org.apache.cxf.security.SecurityContext;
023: import org.apache.cxf.service.model.EndpointInfo;
024: import org.apache.cxf.transport.Conduit;
025: import org.apache.cxf.transport.ConduitInitiator;
026: import org.apache.cxf.transport.Destination;
027: import org.apache.cxf.transport.MessageObserver;
028: import org.apache.cxf.transport.http.AbstractHTTPDestination;
029: import org.apache.cxf.ws.addressing.EndpointReferenceType;
030: import org.apache.openejb.server.webservices.WsConstants;
031: import org.apache.openejb.server.httpd.HttpRequest;
032: import org.apache.openejb.server.httpd.HttpResponse;
033:
034: import javax.servlet.ServletContext;
035: import javax.servlet.http.HttpServletRequest;
036: import javax.servlet.http.HttpServletResponse;
037: import javax.xml.ws.handler.MessageContext;
038: import java.io.IOException;
039: import java.io.InputStream;
040: import java.io.OutputStream;
041: import java.net.HttpURLConnection;
042: import java.security.Principal;
043: import java.util.ArrayList;
044: import java.util.Enumeration;
045: import java.util.Iterator;
046: import java.util.List;
047: import java.util.Map;
048: import java.util.logging.Logger;
049:
050: public class HttpDestination extends AbstractHTTPDestination {
051: private MessageObserver messageObserver;
052: private boolean passSecurityContext = false;
053:
054: public HttpDestination(Bus bus, ConduitInitiator conduitInitiator,
055: EndpointInfo endpointInfo) throws IOException {
056: super (bus, conduitInitiator, endpointInfo, true);
057: }
058:
059: public void setPassSecurityContext(boolean passSecurityContext) {
060: this .passSecurityContext = passSecurityContext;
061: }
062:
063: public boolean getPassSecurityContext() {
064: return this .passSecurityContext;
065: }
066:
067: public EndpointInfo getEndpointInfo() {
068: return this .endpointInfo;
069: }
070:
071: public void invoke(HttpRequest request, HttpResponse response)
072: throws Exception {
073: MessageImpl message = new MessageImpl();
074: message.setContent(InputStream.class, request.getInputStream());
075: message.setDestination(this );
076:
077: message.put(HttpRequest.class, request);
078: message.put(HttpResponse.class, response);
079:
080: final HttpServletRequest servletRequest = (HttpServletRequest) request
081: .getAttribute(HttpRequest.SERVLET_REQUEST);
082: message.put(MessageContext.SERVLET_REQUEST, servletRequest);
083:
084: HttpServletResponse servletResponse = (HttpServletResponse) request
085: .getAttribute(HttpRequest.SERVLET_RESPONSE);
086: message.put(MessageContext.SERVLET_RESPONSE, servletResponse);
087:
088: ServletContext servletContext = (ServletContext) request
089: .getAttribute(HttpRequest.SERVLET_CONTEXT);
090: message.put(MessageContext.SERVLET_CONTEXT, servletContext);
091:
092: if (this .passSecurityContext && servletRequest != null) {
093: message.put(SecurityContext.class, new SecurityContext() {
094: public Principal getUserPrincipal() {
095: return servletRequest.getUserPrincipal();
096: }
097:
098: public boolean isUserInRole(String role) {
099: return servletRequest.isUserInRole(role);
100: }
101: });
102: }
103:
104: // this calls copyRequestHeaders()
105: setHeaders(message);
106:
107: message.put(Message.HTTP_REQUEST_METHOD, request.getMethod()
108: .toString());
109: message.put(Message.PATH_INFO, request.getURI().getPath());
110: message.put(Message.QUERY_STRING, request.getURI()
111: .getFragment());
112: message.put(Message.CONTENT_TYPE, request.getContentType());
113: if (servletRequest != null) {
114: message.put(Message.ENCODING,
115: getCharacterEncoding(servletRequest
116: .getCharacterEncoding()));
117: }
118:
119: getMessageObserver().onMessage(message);
120: }
121:
122: private static String getCharacterEncoding(String encoding) {
123: if (encoding != null) {
124: encoding = encoding.trim();
125: // work around a bug with Jetty which results in the character
126: // encoding not being trimmed correctly:
127: // http://jira.codehaus.org/browse/JETTY-302
128: if (encoding.endsWith("\"")) {
129: encoding = encoding.substring(0, encoding.length() - 1);
130: }
131: }
132: return encoding;
133: }
134:
135: protected void copyRequestHeaders(Message message,
136: Map<String, List<String>> headers) {
137: HttpServletRequest servletRequest = (HttpServletRequest) message
138: .get(MessageContext.SERVLET_REQUEST);
139: if (servletRequest != null) {
140: Enumeration names = servletRequest.getHeaderNames();
141: while (names.hasMoreElements()) {
142: String name = (String) names.nextElement();
143:
144: List<String> headerValues = headers.get(name);
145: if (headerValues == null) {
146: headerValues = new ArrayList<String>();
147: headers.put(name, headerValues);
148: }
149:
150: Enumeration values = servletRequest.getHeaders(name);
151: while (values.hasMoreElements()) {
152: String value = (String) values.nextElement();
153: headerValues.add(value);
154: }
155: }
156: }
157: }
158:
159: public Logger getLogger() {
160: return Logger.getLogger(HttpDestination.class.getName());
161: }
162:
163: public Conduit getInbuiltBackChannel(Message inMessage) {
164: return new BackChannelConduit(null, inMessage);
165: }
166:
167: public Conduit getBackChannel(Message inMessage,
168: Message partialResponse, EndpointReferenceType address)
169: throws IOException {
170: Conduit backChannel = null;
171: if (address == null) {
172: backChannel = new BackChannelConduit(address, inMessage);
173: } else {
174: if (partialResponse != null) {
175: // setup the outbound message to for 202 Accepted
176: partialResponse.put(Message.RESPONSE_CODE,
177: HttpURLConnection.HTTP_ACCEPTED);
178: backChannel = new BackChannelConduit(address, inMessage);
179: } else {
180: backChannel = conduitInitiator.getConduit(endpointInfo,
181: address);
182: // ensure decoupled back channel input stream is closed
183: backChannel.setMessageObserver(new MessageObserver() {
184: public void onMessage(Message m) {
185: if (m.getContentFormats().contains(
186: InputStream.class)) {
187: InputStream is = m
188: .getContent(InputStream.class);
189: try {
190: is.close();
191: } catch (Exception e) {
192: // ignore
193: }
194: }
195: }
196: });
197: }
198: }
199: return backChannel;
200: }
201:
202: public void shutdown() {
203: }
204:
205: public synchronized MessageObserver getMessageObserver() {
206: return messageObserver;
207: }
208:
209: public synchronized void setMessageObserver(
210: MessageObserver messageObserver) {
211: this .messageObserver = messageObserver;
212: }
213:
214: protected class BackChannelConduit implements Conduit {
215:
216: protected Message request;
217: protected EndpointReferenceType target;
218:
219: BackChannelConduit(EndpointReferenceType target, Message request) {
220: this .target = target;
221: this .request = request;
222: }
223:
224: public void close(Message msg) throws IOException {
225: msg.getContent(OutputStream.class).close();
226: }
227:
228: /**
229: * Register a message observer for incoming messages.
230: *
231: * @param observer the observer to notify on receipt of incoming
232: */
233: public void setMessageObserver(MessageObserver observer) {
234: // shouldn't be called for a back channel conduit
235: }
236:
237: public void prepare(Message message) throws IOException {
238: send(message);
239: }
240:
241: /**
242: * Send an outbound message, assumed to contain all the name-value
243: * mappings of the corresponding input message (if any).
244: *
245: * @param message the message to be sent.
246: */
247: public void send(Message message) throws IOException {
248: HttpResponse response = request.get(HttpResponse.class);
249:
250: // handle response headers
251: updateResponseHeaders(message);
252:
253: Map<String, List<String>> protocolHeaders = getProtocolHeaders(message);
254:
255: // set headers of the HTTP response object
256: for (Map.Entry<String, List<String>> entry : protocolHeaders
257: .entrySet()) {
258: String headerName = entry.getKey();
259: String headerValue = getHeaderValue(entry.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, HttpResponse response) {
304: Map<String, List<String>> protocolHeaders = getProtocolHeaders(message);
305:
306: if (protocolHeaders == null
307: || !protocolHeaders.containsKey(Message.CONTENT_TYPE)) {
308: String ct = (String) message.get(Message.CONTENT_TYPE);
309: String enc = (String) message.get(Message.ENCODING);
310:
311: if (null != ct) {
312: if (enc != null && ct.indexOf("charset=") == -1) {
313: ct = ct + "; charset=" + enc;
314: }
315: response.setContentType(ct);
316: } else if (enc != null) {
317: response.setContentType("text/xml; charset=" + enc);
318: }
319: }
320: }
321:
322: @SuppressWarnings({"unchecked"})
323: private Map<String, List<String>> getProtocolHeaders(Message message) {
324: Map<String, List<String>> protocolHeaders = (Map<String, List<String>>) message
325: .get(Message.PROTOCOL_HEADERS);
326: return protocolHeaders;
327: }
328:
329: private class WrappedOutputStream extends OutputStream {
330:
331: private Message message;
332: private HttpResponse response;
333: private OutputStream rawOutputStream;
334:
335: WrappedOutputStream(Message message, HttpResponse response) {
336: this .message = message;
337: this .response = response;
338: }
339:
340: public void write(int b) throws IOException {
341: flushHeaders();
342: this .rawOutputStream.write(b);
343: }
344:
345: public void write(byte b[]) throws IOException {
346: flushHeaders();
347: this .rawOutputStream.write(b);
348: }
349:
350: public void write(byte b[], int off, int len)
351: throws IOException {
352: flushHeaders();
353: this .rawOutputStream.write(b, off, len);
354: }
355:
356: public void flush() throws IOException {
357: flushHeaders();
358: this .rawOutputStream.flush();
359: }
360:
361: public void close() throws IOException {
362: flushHeaders();
363: this .rawOutputStream.close();
364: }
365:
366: protected void flushHeaders() throws IOException {
367: if (this .rawOutputStream != null) {
368: return;
369: }
370:
371: // set response code
372: Integer i = (Integer) this .message
373: .get(Message.RESPONSE_CODE);
374: if (i != null) {
375: this .response.setStatusCode(i.intValue());
376: }
377:
378: // set content-type
379: setContentType(this.message, this.response);
380:
381: this.rawOutputStream = this.response.getOutputStream();
382: }
383:
384: }
385:
386: }
|