httpmethodrule.java
来自「resetful样式的ws样例,一种面向资源的webservices服务」· Java 代码 · 共 261 行
JAVA
261 行
/* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development * and Distribution License("CDDL") (collectively, the "License"). You * may not use this file except in compliance with the License. You can obtain * a copy of the License at https://jersey.dev.java.net/CDDL+GPL.html * or jersey/legal/LICENSE.txt. See the License for the specific * language governing permissions and limitations under the License. * * When distributing the software, include this License Header Notice in each * file and include the License file at jersey/legal/LICENSE.txt. * Sun designates this particular file as subject to the "Classpath" exception * as provided by Sun in the GPL Version 2 section of the License file that * accompanied this code. If applicable, add the following below the License * Header, with the fields enclosed by brackets [] replaced by your own * identifying information: "Portions Copyrighted [year] * [name of copyright owner]" * * Contributor(s): * * If you wish your version of this file to be governed by only the CDDL or * only the GPL Version 2, indicate your decision by adding "[Contributor] * elects to include this software in this distribution under the [CDDL or GPL * Version 2] license." If you don't indicate a single choice of license, a * recipient has the option to distribute your version of this file under * either the CDDL, the GPL Version 2 or to extend the choice of license to * its licensees as provided above. However, if you add GPL Version 2 code * and therefore, elected the GPL Version 2 license, then the option applies * only if the new code is made subject to such option by the copyright * holder. */package com.sun.jersey.impl.uri.rules;import com.sun.jersey.api.core.HttpRequestContext;import com.sun.jersey.api.core.HttpResponseContext;import com.sun.jersey.impl.ImplMessages;import com.sun.jersey.impl.http.header.AcceptableMediaType;import com.sun.jersey.impl.model.HttpHelper;import com.sun.jersey.impl.model.method.ResourceMethod;import com.sun.jersey.api.Responses;import com.sun.jersey.spi.uri.rules.UriRule;import com.sun.jersey.spi.uri.rules.UriRuleContext;import java.util.LinkedList;import java.util.List;import java.util.ListIterator;import java.util.Map;import java.util.logging.Logger;import javax.ws.rs.WebApplicationException;import javax.ws.rs.core.MediaType;import javax.ws.rs.core.MultivaluedMap;import javax.ws.rs.core.Response;/** * The rule for accepting an HTTP method. * * @author Paul.Sandoz@Sun.Com */public final class HttpMethodRule implements UriRule { private static final Logger LOGGER = Logger.getLogger(HttpMethodRule.class.getName()); private final Map<String, List<ResourceMethod>> map; private final String allow; private final boolean isSubResource; public HttpMethodRule(Map<String, List<ResourceMethod>> methods) { this(methods, false); } public HttpMethodRule(Map<String, List<ResourceMethod>> methods, boolean isSubResource) { this.map = methods; this.isSubResource = isSubResource; this.allow = getAllow(methods); } private String getAllow(Map<String, List<ResourceMethod>> methods) { StringBuilder s = new StringBuilder(); boolean first = true; for (String method : methods.keySet()) { if (!first) s.append(","); first = false; s.append(method); } return s.toString(); } public boolean accept(CharSequence path, Object resource, UriRuleContext context) { // If the path is not empty then do not accept if (path.length() > 0) return false; final HttpRequestContext request = context.getRequest(); final HttpResponseContext response = context.getResponse(); final String httpMethod = request.getHttpMethod(); final MediaType contentType = HttpHelper.getContentType(request); // Get the list of resource methods for the HTTP method List<ResourceMethod> methods = map.get(httpMethod); if (methods == null) { // No resource methods are found response.setResponse(Responses.methodNotAllowed(). header("Allow", allow).build()); // Allow any further matching rules to be processed return false; } // Get the list of matching methods List<MediaType> accept = request.getAcceptableMediaTypes(); LinkedList<ResourceMethod> matches = new LinkedList<ResourceMethod>(); MatchStatus s = match(methods, contentType, accept, matches); if (s == MatchStatus.MATCH) { // If there is a match choose the first method ResourceMethod method = matches.get(0); // If a sub-resource method then need to push the resource // (again) as as to keep in sync with the ancestor URIs if (isSubResource) { context.pushResource(resource, method.getTemplate()); // Set the template values context.setTemplateValues(method.getTemplate().getTemplateVariables()); } method.getDispatcher().dispatch(resource, context); // Verify the response // TODO verification for HEAD if (!httpMethod.equals("HEAD")) verifyResponse(method, accept, response); return true; } else if (s == MatchStatus.NO_MATCH_FOR_CONSUME) { throw new WebApplicationException(Responses.unsupportedMediaType().build()); } else if (s == MatchStatus.NO_MATCH_FOR_PRODUCE) { throw new WebApplicationException(Responses.notAcceptable().build()); } return true; } private boolean hasMessageBody(MultivaluedMap<String, String> headers) { return (headers.getFirst("Content-Length") != null || headers.getFirst("Transfer-Encoding") != null); } private enum MatchStatus { MATCH, NO_MATCH_FOR_CONSUME, NO_MATCH_FOR_PRODUCE } /** * Find the subset of methods that match the 'Content-Type' and 'Accept'. * * @param methods the list of resource methods * @param contentType the 'Content-Type'. * @param accept the 'Accept' as a list. This list * MUST be ordered with the highest quality acceptable Media type * occuring first (see * {@link com.sun.ws.rest.impl.model.MimeHelper#ACCEPT_MEDIA_TYPE_COMPARATOR}). * @param matches the list to add the matches to. * @return the match status. */ private MatchStatus match(List<ResourceMethod> methods, MediaType contentType, List<MediaType> accept, LinkedList<ResourceMethod> matches) { if (contentType != null) { // Find all methods that consume the MIME type of 'Content-Type' for (ResourceMethod method : methods) if (method.consumes(contentType)) matches.add(method); if (matches.isEmpty()) return MatchStatus.NO_MATCH_FOR_CONSUME; } else { matches.addAll(methods); } // Find all methods that produce the one or more Media types of 'Accept' ListIterator<ResourceMethod> i = matches.listIterator(); int currentQuality = AcceptableMediaType.MINUMUM_QUALITY; int currentIndex = 0; while(i.hasNext()) { int index = i.nextIndex(); int quality = i.next().produces(accept); if (quality == -1) { // No match i.remove(); } else if (quality < currentQuality) { // Match but of a lower quality than a previous match i.remove(); } else if (quality > currentQuality) { // Match and of a higher quality than the pervious match currentIndex = index; currentQuality = quality; } } if (matches.isEmpty()) return MatchStatus.NO_MATCH_FOR_PRODUCE; // Remove all methods of a lower quality at the // start of the list while (currentIndex > 0) { matches.removeFirst(); currentIndex--; } return MatchStatus.MATCH; } private void verifyResponse(ResourceMethod method, List<MediaType> accept, HttpResponseContext responseContext) { Object entity = responseContext.getEntity(); MediaType contentType = HttpHelper.getContentType( responseContext.getHttpHeaders().getFirst("Content-Type")); if (!responseContext.isCommitted() && contentType != null && entity == null) { String ct = contentType.toString(); String error = "The \"Content-Type\" header is set to " + ct + ", but the response has no entity"; LOGGER.severe(error); // TODO should this be ContainerException ??? throw new WebApplicationException(Response.serverError(). entity(error).type("text/plain").build()); } else if (contentType != null && !method.produces(contentType)) { // Check if 'Content-Type' of the responseContext is a member of @ProduceMime // The resource is not honoring the @ProduceMime contract // The 'Content-Type' is not a member of @ProduceMime. // Check if the 'Content-Type' is acceptable if (!HttpHelper.produces(contentType, accept)) { String error = ImplMessages.RESOURCE_NOT_ACCEPTABLE( method, contentType); LOGGER.severe(error); // The resource is returning a MIME type that is not acceptable // Return 500 Internal Server Error // TODO should this be ContainerException ??? throw new WebApplicationException(Response.serverError(). entity(error).type("text/plain").build()); } else { String error = ImplMessages.RESOURCE_MIMETYPE_NOT_IN_PRODUCE_MIME( method, contentType, method.getProduceMime()); LOGGER.warning(error); } } }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?