Java tutorial
/* * Copyright 2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sprintapi.api.http; import java.io.IOException; import java.io.InputStream; import java.util.Date; import java.util.Locale; import java.util.Map; import javax.servlet.GenericServlet; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.CopyUtils; import org.sprintapi.api.ErrorException; import org.sprintapi.api.Request; import org.sprintapi.api.RequestHolder; import org.sprintapi.api.ResourceDescriptor; import org.sprintapi.api.Response; import org.sprintapi.api.content.ContentAdapter; import org.sprintapi.api.content.ContentDescriptor; import org.sprintapi.api.content.ContentHolder; import org.sprintapi.api.http.headers.HttpAcceptHeader; import org.sprintapi.api.http.lang.HttpDate; import org.sprintapi.api.method.Method; import org.sprintapi.api.method.MethodDescriptor; public abstract class HttpServlet extends GenericServlet { private static final long serialVersionUID = 5919203442935383094L; protected abstract ResourceDescriptor resolve(String uri); protected void doService(HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws ErrorException, IOException { final RequestHolder<Object> request = new RequestHolder<Object>(getUri(httpRequest)); request.setContext(httpRequest.getContextPath()); // Resolve incoming URL and get resource descriptor final ResourceDescriptor resourceDsc = resolve(request.getUri()); // Does the requested resource exist? if (resourceDsc == null) { throw new ErrorException(request.getUri(), HttpServletResponse.SC_NOT_FOUND); } // Is requested method supported? if (httpRequest.getMethod() == null) { throw new ErrorException(request.getUri(), HttpServletResponse.SC_BAD_REQUEST); } try { request.setMethod(Method.valueOf(httpRequest.getMethod().toUpperCase(Locale.US))); } catch (IllegalArgumentException ex) { throw new ErrorException(request.getUri(), HttpServletResponse.SC_NOT_IMPLEMENTED); } if (request.getMethod() == null) { throw new ErrorException(request.getUri(), HttpServletResponse.SC_NOT_IMPLEMENTED); } // Get supported methods for requested resource Map<Method, MethodDescriptor<?, ?>> methods = resourceDsc.methods(); // Get requested method descriptors for the resource MethodDescriptor<?, ?> methodDsc = (methods != null) ? methods.get(request.getMethod()) : null; // Is requested method supported? if ((methodDsc == null)) { throw new ErrorException(request.getUri(), HttpServletResponse.SC_METHOD_NOT_ALLOWED); } ContentAdapter<InputStream, ?> inputContentAdapter = null; // Is request body expected? if (request.getMethod().isRequestBody()) { String requestContentType = httpRequest.getContentType(); inputContentAdapter = (methodDsc.consumes() != null) ? methodDsc.consumes().get(requestContentType) : null; if (inputContentAdapter == null) { throw new ErrorException(request.getUri(), HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE); } } else if (httpRequest.getContentLength() > 0) { // Unexpected request body throw new ErrorException(request.getUri(), HttpServletResponse.SC_BAD_REQUEST); } ContentAdapter<?, InputStream> outputContentAdapter = null; String responseContentType = null; // Is response body expected? if (request.getMethod().isResponseBody()) { // Check Accept header HttpAcceptHeader acceptHeader = HttpAcceptHeader .read(httpRequest.getHeader(ContentDescriptor.META_ACCEPT)); if (acceptHeader != null) { Map<String, ?> produces = methodDsc.produces(); // Response content negotiation if (produces != null) { int weight = 0; for (String ct : produces.keySet()) { int tw = acceptHeader.accept(ct); if (tw > weight) { weight = tw; responseContentType = ct; outputContentAdapter = (ContentAdapter<?, InputStream>) produces.get(ct); } } } if (outputContentAdapter == null) { throw new ErrorException(request.getUri(), HttpServletResponse.SC_NOT_ACCEPTABLE); } } } if (inputContentAdapter != null) { ContentHolder<Object> lc = new ContentHolder<Object>(); lc.setBody(inputContentAdapter.transform(request.getUri(), httpRequest.getInputStream())); request.setContent(lc); } // Invoke resource method Response response = methodDsc.invoke((Request) request); if (response == null) { throw new ErrorException(request.getUri(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } // Write response status int responseStatus = (response.getStatus() > 0) ? response.getStatus() : HttpServletResponse.SC_OK; httpResponse.setStatus(responseStatus); if (response.getContent() == null) { return; } // Write response headers if (response.getContent().getMetaNames() != null) { for (String metaName : response.getContent().getMetaNames()) { Object metaValue = response.getContent().getMeta(metaName); if (metaValue != null) { if (metaValue instanceof Date) { httpResponse.setHeader(metaName, HttpDate.RFC1123_FORMAT.format(((Date) metaValue))); } else { httpResponse.setHeader(metaName, metaValue.toString()); } } } } if ((HttpServletResponse.SC_CREATED == responseStatus)) { httpResponse.setHeader(ContentDescriptor.META_LOCATION, response.getContext() + response.getUri()); } if ((response.getContent().getBody() == null) || (HttpServletResponse.SC_NOT_MODIFIED == responseStatus)) { return; } // Write response body if (outputContentAdapter != null) { httpResponse.setHeader(ContentDescriptor.META_CONTENT_TYPE, responseContentType); InputStream is = ((ContentAdapter<Object, InputStream>) outputContentAdapter) .transform(request.getUri(), response.getContent().getBody()); if (is != null) { CopyUtils.copy(is, httpResponse.getOutputStream()); } } } @Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { HttpServletRequest nativeHttpRequest = null; HttpServletResponse nativeHttpResponse = null; try { nativeHttpRequest = (HttpServletRequest) servletRequest; nativeHttpResponse = (HttpServletResponse) servletResponse; doService(nativeHttpRequest, nativeHttpResponse); } catch (ClassCastException e) { throw new ServletException("non-HTTP request or response"); } catch (ErrorException e) { if (nativeHttpResponse != null) { handleError(e, nativeHttpResponse); return; } throw new ServletException(e); } catch (Exception e) { if (nativeHttpResponse != null) { handleError(new ErrorException(getUri(nativeHttpRequest), HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e), nativeHttpResponse); return; } throw new ServletException(e); } } protected abstract void handleError(ErrorException ex, HttpServletResponse httpResponse); protected static String getUri(final HttpServletRequest httpRequest) { if (httpRequest == null) { return null; } final String context = httpRequest.getContextPath(); return (context != null) ? httpRequest.getRequestURI().substring(context.length()) : httpRequest.getRequestURI(); } }