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.json.resource; 018 019import org.forgerock.services.context.Context; 020import org.forgerock.http.routing.ResourceApiVersionBehaviourManager; 021import org.forgerock.http.routing.ApiVersionRouterContext; 022import org.forgerock.http.routing.Version; 023import org.forgerock.util.promise.ExceptionHandler; 024import org.forgerock.util.promise.Promise; 025import org.forgerock.util.promise.ResultHandler; 026 027/** 028 * API Version routing filter which creates a {@link ApiVersionRouterContext} 029 * which contains the default routing behaviour when the 030 * {@literal Accept-API-Version} header is set on the request. In addition also 031 * sets the {@literal Warning} and {@literal Content-API-Version} headers on 032 * the response. 033 */ 034public class ResourceApiVersionRoutingFilter extends org.forgerock.http.routing.ResourceApiVersionRoutingFilter 035 implements Filter { 036 037 ResourceApiVersionRoutingFilter(ResourceApiVersionBehaviourManager behaviourManager) { 038 super(behaviourManager); 039 } 040 041 @Override 042 public Promise<ActionResponse, ResourceException> filterAction(Context context, ActionRequest request, 043 RequestHandler next) { 044 final ApiVersionRouterContext apiVersionRouterContext = createApiVersionRouterContext(context); 045 return wrapWithApiVersionInfo(apiVersionRouterContext, request, 046 next.handleAction(apiVersionRouterContext, request)); 047 } 048 049 @Override 050 public Promise<ResourceResponse, ResourceException> filterCreate(Context context, CreateRequest request, 051 RequestHandler next) { 052 final ApiVersionRouterContext apiVersionRouterContext = createApiVersionRouterContext(context); 053 return wrapWithApiVersionInfo(apiVersionRouterContext, request, 054 next.handleCreate(apiVersionRouterContext, request)); 055 } 056 057 @Override 058 public Promise<ResourceResponse, ResourceException> filterDelete(Context context, DeleteRequest request, 059 RequestHandler next) { 060 final ApiVersionRouterContext apiVersionRouterContext = createApiVersionRouterContext(context); 061 return wrapWithApiVersionInfo(apiVersionRouterContext, request, 062 next.handleDelete(apiVersionRouterContext, request)); 063 } 064 065 @Override 066 public Promise<ResourceResponse, ResourceException> filterPatch(Context context, PatchRequest request, 067 RequestHandler next) { 068 final ApiVersionRouterContext apiVersionRouterContext = createApiVersionRouterContext(context); 069 return wrapWithApiVersionInfo(apiVersionRouterContext, request, 070 next.handlePatch(apiVersionRouterContext, request)); 071 } 072 073 @Override 074 public Promise<QueryResponse, ResourceException> filterQuery(Context context, QueryRequest request, 075 QueryResourceHandler handler, RequestHandler next) { 076 final ApiVersionRouterContext apiVersionRouterContext = createApiVersionRouterContext(context); 077 return wrapWithApiVersionInfo(apiVersionRouterContext, request, 078 next.handleQuery(apiVersionRouterContext, request, handler)); 079 } 080 081 @Override 082 public Promise<ResourceResponse, ResourceException> filterRead(Context context, ReadRequest request, 083 RequestHandler next) { 084 final ApiVersionRouterContext apiVersionRouterContext = createApiVersionRouterContext(context); 085 return wrapWithApiVersionInfo(apiVersionRouterContext, request, 086 next.handleRead(apiVersionRouterContext, request)); 087 } 088 089 @Override 090 public Promise<ResourceResponse, ResourceException> filterUpdate(Context context, UpdateRequest request, 091 RequestHandler next) { 092 final ApiVersionRouterContext apiVersionRouterContext = createApiVersionRouterContext(context); 093 return wrapWithApiVersionInfo(apiVersionRouterContext, request, 094 next.handleUpdate(apiVersionRouterContext, request)); 095 } 096 097 private <V extends Response> Promise<V, ResourceException> wrapWithApiVersionInfo( 098 final ApiVersionRouterContext apiVersionRouterContext, final Request request, 099 Promise<V, ResourceException> promise) { 100 return promise 101 .thenOnResult(new ResultHandler<V>() { 102 @Override 103 public void handleResult(V response) { 104 setApiVersionInfo(apiVersionRouterContext, request, response); 105 } 106 }) 107 .thenOnException(new ExceptionHandler<ResourceException>() { 108 @Override 109 public void handleException(ResourceException e) { 110 setApiVersionInfo(apiVersionRouterContext, request, e); 111 } 112 }); 113 } 114 115 static void setApiVersionInfo(ApiVersionRouterContext apiVersionRouterContext, Request request, Response response) { 116 Version resourceVersion = apiVersionRouterContext.getResourceVersion(); 117 if (resourceVersion != null) { 118 response.setResourceApiVersion(resourceVersion); 119 } 120 if (apiVersionRouterContext.isWarningEnabled() && request.getResourceVersion() == null) { 121 AdviceContext adviceContext = apiVersionRouterContext.asContext(AdviceContext.class); 122 if (!adviceContext.getAdvices().containsKey("crest")) { 123 adviceContext.putAdvice("Warning", AdviceWarning.getNotPresent("CREST", "Accept-API-Version") 124 .toString()); 125 } 126 } 127 } 128}