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.transport.http_jetty;
019:
020: import java.io.IOException;
021: import java.io.InputStream;
022: import java.net.MalformedURLException;
023: import java.net.URL;
024: import java.security.GeneralSecurityException;
025: import java.security.Principal;
026: import java.util.logging.Level;
027: import java.util.logging.Logger;
028:
029: import javax.servlet.http.HttpServletRequest;
030: import javax.servlet.http.HttpServletResponse;
031:
032: import org.apache.cxf.Bus;
033: import org.apache.cxf.common.logging.LogUtils;
034: import org.apache.cxf.common.util.StringUtils;
035: import org.apache.cxf.message.ExchangeImpl;
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.ConduitInitiator;
041: import org.apache.cxf.transport.http.AbstractHTTPDestination;
042: import org.apache.cxf.transport.http.HTTPSession;
043: import org.apache.cxf.transport.https.SSLUtils;
044: import org.apache.cxf.transports.http.QueryHandler;
045: import org.apache.cxf.transports.http.QueryHandlerRegistry;
046: import org.mortbay.jetty.HttpConnection;
047: import org.mortbay.jetty.Request;
048:
049: public class JettyHTTPDestination extends AbstractHTTPDestination {
050:
051: private static final Logger LOG = LogUtils
052: .getL7dLogger(JettyHTTPDestination.class);
053:
054: protected JettyHTTPServerEngine engine;
055: protected JettyHTTPTransportFactory transportFactory;
056: protected JettyHTTPServerEngineFactory serverEngineFactory;
057: protected URL nurl;
058:
059: /**
060: * This variable signifies that finalizeConfig() has been called.
061: * It gets called after this object has been spring configured.
062: * It is used to automatically reinitialize things when resources
063: * are reset, such as setTlsServerParameters().
064: */
065: private boolean configFinalized;
066:
067: /**
068: * Constructor, using Jetty server engine.
069: *
070: * @param b the associated Bus
071: * @param ci the associated conduit initiator
072: * @param endpointInfo the endpoint info of the destination
073: * @throws IOException
074: */
075: public JettyHTTPDestination(Bus b, JettyHTTPTransportFactory ci,
076: EndpointInfo endpointInfo) throws IOException {
077: //Add the defualt port if the address is missing it
078: super (b, ci, endpointInfo, true);
079: this .transportFactory = ci;
080: this .serverEngineFactory = ci.getJettyHTTPServerEngineFactory();
081: nurl = new URL(endpointInfo.getAddress());
082: }
083:
084: protected Logger getLogger() {
085: return LOG;
086: }
087:
088: /**
089: * Post-configure retreival of server engine.
090: */
091: protected void retrieveEngine() throws GeneralSecurityException,
092: IOException {
093:
094: engine = serverEngineFactory.retrieveJettyHTTPServerEngine(nurl
095: .getPort());
096: if (engine == null) {
097: engine = serverEngineFactory.createJettyHTTPServerEngine(
098: nurl.getPort(), nurl.getProtocol());
099: }
100:
101: assert engine != null;
102:
103: // When configuring for "http", however, it is still possible that
104: // Spring configuration has configured the port for https.
105: if (!nurl.getProtocol().equals(engine.getProtocol())) {
106: throw new IllegalStateException("Port " + engine.getPort()
107: + " is configured with wrong protocol \""
108: + engine.getProtocol() + "\" for \"" + nurl + "\"");
109: }
110: }
111:
112: /**
113: * This method is used to finalize the configuration
114: * after the configuration items have been set.
115: *
116: */
117: public void finalizeConfig() throws GeneralSecurityException,
118: IOException {
119:
120: assert !configFinalized;
121:
122: retrieveEngine();
123: configFinalized = true;
124: }
125:
126: /**
127: * Activate receipt of incoming messages.
128: */
129: protected void activate() {
130: LOG.log(Level.FINE, "Activating receipt of incoming messages");
131: try {
132: URL url = new URL(endpointInfo.getAddress());
133: engine.addServant(url, new JettyHTTPHandler(this ,
134: contextMatchOnExact()));
135:
136: } catch (Exception e) {
137: LOG.log(Level.WARNING, "URL creation failed: ", e);
138: }
139: }
140:
141: /**
142: * Deactivate receipt of incoming messages.
143: */
144: protected void deactivate() {
145: LOG
146: .log(Level.FINE,
147: "Deactivating receipt of incoming messages");
148: engine.removeServant(nurl);
149: }
150:
151: /**
152: * @return the associated conduit initiator
153: */
154: protected ConduitInitiator getConduitInitiator() {
155: return conduitInitiator;
156: }
157:
158: private String getBasePath(String addr) {
159: try {
160: return new URL(addr).getPath();
161: } catch (MalformedURLException e) {
162: return null;
163: }
164: }
165:
166: private synchronized void updateEndpointAddress(String addr) {
167: // only update the EndpointAddress if the base path is equal
168: // make sure we don't broke the get operation?parament query
169: String address = endpointInfo.getAddress();
170: if (getBasePath(address).equals(getBasePath(addr))) {
171: endpointInfo.setAddress(addr);
172: }
173: }
174:
175: protected void doService(HttpServletRequest req,
176: HttpServletResponse resp) throws IOException {
177: Request baseRequest = (req instanceof Request) ? (Request) req
178: : HttpConnection.getCurrentConnection().getRequest();
179:
180: if (getServer().isSetRedirectURL()) {
181: resp.sendRedirect(getServer().getRedirectURL());
182: resp.flushBuffer();
183: baseRequest.setHandled(true);
184: return;
185: }
186: QueryHandlerRegistry queryHandlerRegistry = bus
187: .getExtension(QueryHandlerRegistry.class);
188:
189: if (null != req.getQueryString()
190: && queryHandlerRegistry != null) {
191: String requestURL = req.getRequestURL() + "?"
192: + req.getQueryString();
193: String pathInfo = req.getPathInfo();
194: for (QueryHandler qh : queryHandlerRegistry.getHandlers()) {
195: if (qh.isRecognizedQuery(requestURL, pathInfo,
196: endpointInfo)) {
197: //replace the endpointInfo address with request url only for get wsdl
198: updateEndpointAddress(req.getRequestURL()
199: .toString());
200: resp.setContentType(qh.getResponseContentType(
201: requestURL, pathInfo));
202: qh.writeResponse(requestURL, pathInfo,
203: endpointInfo, resp.getOutputStream());
204: resp.getOutputStream().flush();
205: baseRequest.setHandled(true);
206: return;
207: }
208: }
209: }
210:
211: // REVISIT: service on executor if associated with endpoint
212: serviceRequest(req, resp);
213: }
214:
215: protected void serviceRequest(final HttpServletRequest req,
216: final HttpServletResponse resp) throws IOException {
217: Request baseRequest = (req instanceof Request) ? (Request) req
218: : HttpConnection.getCurrentConnection().getRequest();
219: try {
220: if (LOG.isLoggable(Level.FINE)) {
221: LOG.fine("Service http request on thread: "
222: + Thread.currentThread());
223: }
224:
225: MessageImpl inMessage = new MessageImpl();
226: inMessage.setContent(InputStream.class, req
227: .getInputStream());
228: inMessage.put(HTTP_REQUEST, req);
229: inMessage.put(HTTP_RESPONSE, resp);
230: inMessage.put(Message.HTTP_REQUEST_METHOD, req.getMethod());
231: inMessage.put(Message.PATH_INFO, req.getContextPath()
232: + req.getPathInfo());
233:
234: inMessage.put(Message.QUERY_STRING, req.getQueryString());
235: inMessage.put(Message.CONTENT_TYPE, req.getContentType());
236: if (!StringUtils.isEmpty(endpointInfo.getAddress())) {
237: inMessage.put(Message.BASE_PATH, new URL(endpointInfo
238: .getAddress()).getPath());
239: }
240: inMessage.put(Message.FIXED_PARAMETER_ORDER,
241: isFixedParameterOrder());
242: inMessage.put(Message.ASYNC_POST_RESPONSE_DISPATCH,
243: Boolean.TRUE);
244: inMessage.put(SecurityContext.class, new SecurityContext() {
245: public Principal getUserPrincipal() {
246: return req.getUserPrincipal();
247: }
248:
249: public boolean isUserInRole(String role) {
250: return req.isUserInRole(role);
251: }
252: });
253:
254: setHeaders(inMessage);
255: inMessage.setDestination(this );
256:
257: SSLUtils.propogateSecureSession(req, inMessage);
258:
259: ExchangeImpl exchange = new ExchangeImpl();
260: exchange.setInMessage(inMessage);
261: exchange.setSession(new HTTPSession(req));
262:
263: incomingObserver.onMessage(inMessage);
264:
265: resp.flushBuffer();
266: baseRequest.setHandled(true);
267: } finally {
268: if (LOG.isLoggable(Level.FINE)) {
269: LOG.fine("Finished servicing http request on thread: "
270: + Thread.currentThread());
271: }
272: }
273: }
274:
275: @Override
276: public void shutdown() {
277: transportFactory.removeDestination(endpointInfo);
278:
279: super .shutdown();
280: }
281:
282: public ServerEngine getEngine() {
283: return engine;
284: }
285:
286: }
|