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*/ 016package org.forgerock.openig.filter; 017 018 019import static org.forgerock.openig.http.Responses.newInternalServerError; 020 021import org.forgerock.http.Filter; 022import org.forgerock.http.Handler; 023import org.forgerock.http.protocol.Request; 024import org.forgerock.http.protocol.Response; 025import org.forgerock.services.context.Context; 026import org.forgerock.util.promise.NeverThrowsException; 027import org.forgerock.util.promise.Promise; 028import org.forgerock.util.promise.PromiseImpl; 029import org.forgerock.util.promise.ResultHandler; 030import org.forgerock.util.promise.RuntimeExceptionHandler; 031 032/** 033 * This filter aims to guarantee the caller that it will always get a Response to process, even if the {@literal next} 034 * returns a promise completed with a {@link RuntimeException}, or even if a {@link RuntimeException} is thrown. 035 */ 036public class RuntimeExceptionFilter implements Filter { 037 038 @Override 039 public Promise<Response, NeverThrowsException> filter(Context context, Request request, Handler next) { 040 // Wraps the result's promise into another promise so we can ensure that in every case we return a Response. 041 final PromiseImpl<Response, NeverThrowsException> promise = PromiseImpl.create(); 042 043 try { 044 next.handle(context, request) 045 .thenOnResult(new ResultHandler<Response>() { 046 @Override 047 public void handleResult(Response result) { 048 promise.handleResult(result); 049 } 050 }) 051 .thenOnRuntimeException(onRuntimeException(promise)); 052 // Note : it's not possible to instantiate a NeverThrowsException so there's no need to add an 053 // ExceptionHandler<NeverThrowsException> 054 } catch (RuntimeException exception) { 055 // next.handle can throw such exceptions 056 onRuntimeException(promise).handleRuntimeException(exception); 057 } 058 return promise; 059 } 060 061 private RuntimeExceptionHandler onRuntimeException(final PromiseImpl<Response, NeverThrowsException> promise) { 062 return new RuntimeExceptionHandler() { 063 @Override 064 public void handleRuntimeException(RuntimeException exception) { 065 promise.handleResult(errorResponse(exception)); 066 } 067 }; 068 } 069 070 private static Response errorResponse(Exception exception) { 071 return newInternalServerError().setCause(exception); 072 } 073 074}