001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common Development
008: * and Distribution License("CDDL") (collectively, the "License"). You
009: * may not use this file except in compliance with the License. You can obtain
010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
012: * language governing permissions and limitations under the License.
013: *
014: * When distributing the software, include this License Header Notice in each
015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
016: * Sun designates this particular file as subject to the "Classpath" exception
017: * as provided by Sun in the GPL Version 2 section of the License file that
018: * accompanied this code. If applicable, add the following below the License
019: * Header, with the fields enclosed by brackets [] replaced by your own
020: * identifying information: "Portions Copyrighted [year]
021: * [name of copyright owner]"
022: *
023: * Contributor(s):
024: *
025: * If you wish your version of this file to be governed by only the CDDL or
026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
027: * elects to include this software in this distribution under the [CDDL or GPL
028: * Version 2] license." If you don't indicate a single choice of license, a
029: * recipient has the option to distribute your version of this file under
030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
031: * its licensees as provided above. However, if you add GPL Version 2 code
032: * and therefore, elected the GPL Version 2 license, then the option applies
033: * only if the new code is made subject to such option by the copyright
034: * holder.
035: */
036:
037: package com.sun.xml.ws.transport.http.servlet;
038:
039: import com.sun.xml.ws.resources.WsservletMessages;
040: import com.sun.xml.ws.transport.http.HttpAdapter;
041: import com.sun.xml.ws.util.exception.JAXWSExceptionBase;
042: import com.sun.xml.ws.util.localization.Localizable;
043: import com.sun.xml.ws.util.localization.Localizer;
044:
045: import javax.servlet.ServletContext;
046: import javax.servlet.ServletException;
047: import javax.servlet.ServletRequest;
048: import javax.servlet.http.HttpServletRequest;
049: import javax.servlet.http.HttpServletResponse;
050: import javax.xml.soap.MimeHeaders;
051: import javax.xml.ws.Binding;
052: import javax.xml.ws.http.HTTPBinding;
053: import java.io.IOException;
054: import java.io.PrintWriter;
055: import java.util.ArrayList;
056: import java.util.Enumeration;
057: import java.util.HashMap;
058: import java.util.List;
059: import java.util.Locale;
060: import java.util.Map;
061: import java.util.logging.Level;
062: import java.util.logging.Logger;
063:
064: /**
065: * Called by {@link WSServlet} to choose {@link HttpAdapter}
066: * and sends a request to it.
067: *
068: * <p>
069: * One instance of this object is created, and then shared across
070: * {@link WSServlet} instances (the container might deploy many of them,
071: * depending on how the user writes {@code web.xml}.)
072: *
073: * @author WS Development Team
074: */
075: public class WSServletDelegate {
076:
077: /**
078: * All {@link ServletAdapter}s that are deployed in the current web appliation.
079: */
080: public final List<ServletAdapter> adapters;
081:
082: private final Map<String, ServletAdapter> fixedUrlPatternEndpoints = new HashMap<String, ServletAdapter>();
083: private final List<ServletAdapter> pathUrlPatternEndpoints = new ArrayList<ServletAdapter>();
084: private final Map<Locale, Localizer> localizerMap = new HashMap<Locale, Localizer>();
085:
086: public WSServletDelegate(List<ServletAdapter> adapters,
087: ServletContext context) {
088: this .adapters = adapters;
089:
090: for (ServletAdapter info : adapters)
091: registerEndpointUrlPattern(info);
092:
093: localizerMap
094: .put(defaultLocalizer.getLocale(), defaultLocalizer);
095:
096: if (logger.isLoggable(Level.INFO)) {
097: logger.info(WsservletMessages.SERVLET_INFO_INITIALIZE());
098: }
099:
100: // compatibility.
101: String publishStatusPageParam = context
102: .getInitParameter(WSServlet.JAXWS_RI_PROPERTY_PUBLISH_STATUS_PAGE);
103: if (publishStatusPageParam != null)
104: HttpAdapter.publishStatusPage = Boolean
105: .parseBoolean(publishStatusPageParam);
106: }
107:
108: public void destroy() {
109: if (logger.isLoggable(Level.INFO)) {
110: logger.info(WsservletMessages.SERVLET_INFO_DESTROY());
111: }
112:
113: for (ServletAdapter a : adapters) {
114: try {
115: a.getEndpoint().dispose();
116: } catch (Throwable e) {
117: logger.log(Level.SEVERE, e.getMessage(), e);
118: }
119: }
120: }
121:
122: public void doGet(HttpServletRequest request,
123: HttpServletResponse response, ServletContext context)
124: throws ServletException {
125:
126: try {
127: ServletAdapter target = getTarget(request);
128: if (target != null) {
129: if (logger.isLoggable(Level.FINEST)) {
130: logger
131: .finest(WsservletMessages
132: .SERVLET_TRACE_GOT_REQUEST_FOR_ENDPOINT(target.name));
133: }
134: target.handle(context, request, response);
135: } else {
136: Localizer localizer = getLocalizerFor(request);
137: writeNotFoundErrorPage(localizer, response,
138: "Invalid Request");
139: }
140: } catch (JAXWSExceptionBase e) {
141: logger.log(Level.SEVERE, defaultLocalizer.localize(e), e);
142: response
143: .setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
144: } catch (Throwable e) {
145: if (e instanceof Localizable) {
146: logger.log(Level.SEVERE, defaultLocalizer
147: .localize((Localizable) e), e);
148: } else {
149: logger.log(Level.SEVERE, "caught throwable", e);
150: }
151:
152: response
153: .setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
154: }
155: }
156:
157: /**
158: * processes web service requests by finding the {@link ServletAdapter}
159: * created by the {@link WSServletContextListener} and creating a
160: * {@link ServletConnectionImpl}.
161: *
162: * @param request the HTTP request object
163: * @param response the HTTP response object
164: */
165: public void doPost(HttpServletRequest request,
166: HttpServletResponse response, ServletContext context)
167: throws ServletException {
168: doGet(request, response, context);
169: }
170:
171: /**
172: * Handles HTTP PUT for XML/HTTP binding based endpoints
173: */
174: public void doPut(HttpServletRequest request,
175: HttpServletResponse response, ServletContext context)
176: throws ServletException {
177: // TODO: unify this into doGet.
178: try {
179: ServletAdapter target = getTarget(request);
180: if (target != null) {
181: if (logger.isLoggable(Level.FINEST)) {
182: logger
183: .finest(WsservletMessages
184: .SERVLET_TRACE_GOT_REQUEST_FOR_ENDPOINT(target.name));
185: }
186: } else {
187: Localizer localizer = getLocalizerFor(request);
188: writeNotFoundErrorPage(localizer, response,
189: "Invalid request");
190: return;
191: }
192: Binding binding = target.getEndpoint().getBinding();
193: if (binding instanceof HTTPBinding) {
194: target.handle(context, request, response);
195: } else {
196: response
197: .setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
198: }
199: } catch (JAXWSExceptionBase e) {
200: logger.log(Level.SEVERE, defaultLocalizer.localize(e), e);
201: response
202: .setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
203: } catch (Throwable e) {
204: if (e instanceof Localizable) {
205: logger.log(Level.SEVERE, defaultLocalizer
206: .localize((Localizable) e), e);
207: } else {
208: logger.log(Level.SEVERE, "caught throwable", e);
209: }
210: response
211: .setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
212: }
213: }
214:
215: /**
216: * Handles HTTP DELETE for XML/HTTP binding based endpoints
217: */
218: public void doDelete(HttpServletRequest request,
219: HttpServletResponse response, ServletContext context)
220: throws ServletException {
221:
222: // At preseent, there is no difference for between PUT and DELETE processing
223: doPut(request, response, context);
224: }
225:
226: private void writeNotFoundErrorPage(Localizer localizer,
227: HttpServletResponse response, String message)
228: throws IOException {
229: response.setStatus(HttpServletResponse.SC_NOT_FOUND);
230: response.setContentType("text/html");
231: PrintWriter out = response.getWriter();
232: out.println("<html>");
233: out.println("<head><title>");
234: out.println(WsservletMessages.SERVLET_HTML_TITLE());
235: out.println("</title></head>");
236: out.println("<body>");
237: out.println(WsservletMessages.SERVLET_HTML_NOT_FOUND(message));
238: out.println("</body>");
239: out.println("</html>");
240: }
241:
242: protected static MimeHeaders getHeaders(HttpServletRequest req) {
243: Enumeration enums = req.getHeaderNames();
244: MimeHeaders headers = new MimeHeaders();
245:
246: while (enums.hasMoreElements()) {
247: String headerName = (String) enums.nextElement();
248: String headerValue = req.getHeader(headerName);
249: headers.addHeader(headerName, headerValue);
250: }
251:
252: return headers;
253: }
254:
255: private void registerEndpointUrlPattern(ServletAdapter a) {
256: String urlPattern = a.urlPattern;
257: if (urlPattern.indexOf("*.") != -1) {
258: // cannot deal with implicit mapping right now
259: logger
260: .warning(WsservletMessages
261: .SERVLET_WARNING_IGNORING_IMPLICIT_URL_PATTERN(a.name));
262: } else if (urlPattern.endsWith("/*")) {
263: pathUrlPatternEndpoints.add(a);
264: } else {
265: if (fixedUrlPatternEndpoints.containsKey(urlPattern)) {
266: logger
267: .warning(WsservletMessages
268: .SERVLET_WARNING_DUPLICATE_ENDPOINT_URL_PATTERN(a.name));
269: } else {
270: fixedUrlPatternEndpoints.put(urlPattern, a);
271: }
272: }
273: }
274:
275: /**
276: * Determines which {@link ServletAdapter} serves the given request.
277: */
278: protected ServletAdapter getTarget(HttpServletRequest request) {
279:
280: /*System.err.println("----");
281: System.err.println("CONTEXT PATH : " + request.getContextPath());
282: System.err.println("PATH INFO : " + request.getPathInfo());
283: System.err.println("PATH TRANSLATED: " + request.getPathTranslated());
284: System.err.println("QUERY STRING : " + request.getQueryString());
285: System.err.println("REQUEST URI : " + request.getRequestURI());
286: System.err.println();
287: */
288:
289: String path = request.getRequestURI().substring(
290: request.getContextPath().length());
291: ServletAdapter result = fixedUrlPatternEndpoints.get(path);
292: if (result == null) {
293: for (ServletAdapter candidate : pathUrlPatternEndpoints) {
294: String noSlashStar = candidate.getValidPath();
295: if (path.equals(noSlashStar)
296: || path.startsWith(noSlashStar + "/")
297: || path.startsWith(noSlashStar + "?")) {
298: result = candidate;
299: break;
300: }
301: }
302: }
303:
304: return result;
305: }
306:
307: protected Localizer getLocalizerFor(ServletRequest request) {
308: Locale locale = request.getLocale();
309: if (locale.equals(defaultLocalizer.getLocale())) {
310: return defaultLocalizer;
311: }
312:
313: synchronized (localizerMap) {
314: Localizer localizer = localizerMap.get(locale);
315: if (localizer == null) {
316: localizer = new Localizer(locale);
317: localizerMap.put(locale, localizer);
318: }
319: return localizer;
320: }
321: }
322:
323: private static final Localizer defaultLocalizer = new Localizer();
324: private static final Logger logger = Logger
325: .getLogger(com.sun.xml.ws.util.Constants.LoggingDomain
326: + ".servlet.http");
327:
328: }
|