package org.jboss.resteasy.core; import org.jboss.resteasy.resteasy_jaxrs.i18n.Messages; import org.jboss.resteasy.spi.HttpRequest; import org.jboss.resteasy.spi.HttpRequestPreprocessor; import org.jboss.resteasy.util.MediaTypeHelper; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerRequestFilter; import javax.ws.rs.container.PreMatching; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; /** * <p>Enables content negotiation through a query parameter, instead of the Accept Header.</p> * <p>To enable this feature, use the context-param in web.xml:</p> * <p/> * <code> * <context-param><br /> *     <param-name><strong>resteasy.media.type.param.mapping</strong></param-name><br /> *     <param-value><i>someName</i></param-value><br /> * </context-param><br /> * </code> * <p>So, in a request like * <code>http://service.foo.com/resouce?someName=application/xml</code> * the application/xml media type will received the highest priority in the content negotiation. * <p>In the cases where the request contains both the parameter and the Accept header, the parameter will be more relevant. * <p>It is possible to left the <code>param-value</code> empty, what will cause the processor to look for an <strong>accept</strong> parameter. * * @author <a href="leandro.ferro@gmail.com">Leandro Ferro Luzia</a> * @version $Revision: 1.2 $ */ @PreMatching public class AcceptParameterHttpPreprocessor implements ContainerRequestFilter { private final String paramMapping; /** * Create a new AcceptParameterHttpPreprocessor. * * @param paramMapping The name of query parameter that will be used to do the content negotiation */ public AcceptParameterHttpPreprocessor(String paramMapping) { if (paramMapping == null || paramMapping.matches("\\s+")) throw new IllegalArgumentException(Messages.MESSAGES.constructorMappingInvalid()); this.paramMapping = paramMapping; } @Override public void filter(ContainerRequestContext request) throws IOException { MultivaluedMap<String, String> params = request.getUriInfo().getQueryParameters(false); if (params != null) { List<String> accepts = params.get(paramMapping); if (accepts != null && !accepts.isEmpty()) { List<MediaType> mediaTypes = new ArrayList<MediaType>(); for (String accept : accepts) { try { accept = URLDecoder.decode(accept, StandardCharsets.UTF_8.name()); request.getHeaders().add(HttpHeaders.ACCEPT, accept); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } mediaTypes.addAll(MediaTypeHelper.parseHeader(accept)); } } } } }