001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2015 ForgeRock AS. 015 */ 016 017package org.forgerock.http.routing; 018 019import static org.forgerock.util.promise.Promises.newResultPromise; 020 021import org.forgerock.services.context.Context; 022import org.forgerock.http.Filter; 023import org.forgerock.http.Handler; 024import org.forgerock.http.header.AcceptApiVersionHeader; 025import org.forgerock.http.header.ContentApiVersionHeader; 026import org.forgerock.http.header.WarningHeader; 027import org.forgerock.http.protocol.Request; 028import org.forgerock.http.protocol.Response; 029import org.forgerock.http.protocol.Status; 030import org.forgerock.util.promise.NeverThrowsException; 031import org.forgerock.util.promise.Promise; 032import org.forgerock.util.promise.ResultHandler; 033 034/** 035 * API Version routing filter which creates a {@link ApiVersionRouterContext} 036 * which contains the default routing behaviour when the 037 * {@literal Accept-API-Version} header is set on the request. In addition also 038 * sets the {@literal Warning} and {@literal Content-API-Version} headers on 039 * the response. 040 */ 041public class ResourceApiVersionRoutingFilter implements Filter { 042 043 private final ResourceApiVersionBehaviourManager behaviourManager; 044 045 /** 046 * Constructs a new {@code ResourceApiVersionRoutingFilter} instance. 047 * 048 * @param behaviourManager The {@link ResourceApiVersionBehaviourManager} instance 049 * that manages the API Version routing settings. 050 */ 051 public ResourceApiVersionRoutingFilter(ResourceApiVersionBehaviourManager behaviourManager) { 052 this.behaviourManager = behaviourManager; 053 } 054 055 @Override 056 public Promise<Response, NeverThrowsException> filter(Context context, Request request, Handler next) { 057 final ApiVersionRouterContext apiVersionRouterContext = createApiVersionRouterContext(context); 058 final Version requestedResourceVersion; 059 try { 060 requestedResourceVersion = AcceptApiVersionHeader.valueOf(request).getResourceVersion(); 061 } catch (IllegalArgumentException e) { 062 return newResultPromise(new Response(Status.BAD_REQUEST).setEntity(e.getMessage()).setCause(e)); 063 } 064 return next.handle(apiVersionRouterContext, request) 065 .thenOnResult(new ResultHandler<Response>() { 066 @Override 067 public void handleResult(Response response) { 068 Version protocolVersion = apiVersionRouterContext.getProtocolVersion(); 069 Version resourceVersion = apiVersionRouterContext.getResourceVersion(); 070 if (resourceVersion != null) { 071 response.getHeaders().add(new ContentApiVersionHeader(protocolVersion, resourceVersion)); 072 } 073 if (apiVersionRouterContext.isWarningEnabled() && requestedResourceVersion == null) { 074 response.getHeaders().add(WarningHeader.newWarning("chf", 075 "%s should be included in the request.", AcceptApiVersionHeader.NAME)); 076 } 077 } 078 }); 079 } 080 081 /** 082 * Creates a {@link ApiVersionRouterContext} using the default version 083 * behaviour and whether to issue warnings from the 084 * {@literal behaviourManager} instance. 085 * 086 * @param context The parent context. 087 * @return A new {@code ApiVersionRouterContext}. 088 */ 089 protected ApiVersionRouterContext createApiVersionRouterContext(Context context) { 090 return new ApiVersionRouterContext(context, behaviourManager.getDefaultVersionBehaviour(), 091 behaviourManager.isWarningEnabled()); 092 } 093}