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.openig.http; 018 019import static java.lang.String.format; 020 021import java.util.concurrent.CountDownLatch; 022 023import org.forgerock.http.Handler; 024import org.forgerock.http.protocol.Request; 025import org.forgerock.http.protocol.Response; 026import org.forgerock.http.protocol.Status; 027import org.forgerock.services.context.Context; 028import org.forgerock.util.promise.ResultHandler; 029 030/** 031 * Provide out-of-the-box, pre-configured {@link Response} objects. 032 */ 033public final class Responses { 034 035 /** 036 * Empty private constructor for utility. 037 */ 038 private Responses() { } 039 040 /** 041 * Generates an empty {@literal Internal Server Error} response ({@literal 500}). 042 * 043 * @return an empty {@literal Internal Server Error} response ({@literal 500}). 044 */ 045 public static Response newInternalServerError() { 046 return new Response(Status.INTERNAL_SERVER_ERROR); 047 } 048 049 /** 050 * Generates an {@literal Internal Server Error} response ({@literal 500}) whose content is set to the given {@code 051 * exception}'s message. 052 * 053 * @param exception 054 * wrapped exception 055 * @return a configured {@literal Internal Server Error} response ({@literal 500}). 056 */ 057 public static Response newInternalServerError(Exception exception) { 058 return newInternalServerError(exception.getMessage()) 059 .setCause(exception); 060 } 061 062 /** 063 * Generates an {@literal Internal Server Error} response ({@literal 500}) whose content is set to a concatenation 064 * of the given {@code message} and {@code exception}'s message. 065 * 066 * @param message 067 * first part of the response's content 068 * @param exception 069 * wrapped exception 070 * @return a configured {@literal Internal Server Error} response ({@literal 500}). 071 */ 072 public static Response newInternalServerError(String message, Exception exception) { 073 return newInternalServerError(format("%s: %s", message, exception.getMessage())).setCause(exception); 074 } 075 076 /** 077 * Generates an {@literal Internal Server Error} response ({@literal 500}) whose content is set to the given {@code 078 * message}. 079 * 080 * @param message 081 * response's content 082 * @return a configured {@literal Internal Server Error} response ({@literal 500}). 083 */ 084 public static Response newInternalServerError(String message) { 085 return newInternalServerError().setEntity(message); 086 } 087 088 /** 089 * Generates an empty {@literal Not Found} response ({@literal 404}). 090 * 091 * @return an empty {@literal Not Found} response ({@literal 404}). 092 */ 093 public static Response newNotFound() { 094 return new Response(Status.NOT_FOUND); 095 } 096 097 /** 098 * Generates a {@literal Not Found} response ({@literal 404}) whose content is set to the given {@code message}. 099 * 100 * @param message 101 * response's content 102 * @return a configured {@literal Not Found} response ({@literal 404}). 103 */ 104 public static Response newNotFound(String message) { 105 return newNotFound().setEntity(message); 106 } 107 108 /** 109 * Executes a blocking call with the given {@code handler}, {@code context} and {@code request}, returning 110 * the {@link Response} when fully available. 111 * 112 * <p>This function is here to fix a concurrency issue where a caller thread is blocking a promise and is 113 * resumed before all of the ResultHandlers and Function of the blocked promise have been invoked. 114 * That may lead to concurrent consumption of {@link org.forgerock.http.io.BranchingInputStream} that is a 115 * not thread safe object. 116 * 117 * @param handler Handler for handling the given request 118 * @param context Context to be used for the invocation 119 * @param request request to be executed 120 * @return a ready to used {@link Response} 121 * @throws InterruptedException if either {@link org.forgerock.util.promise.Promise#getOrThrow()} or 122 * {@link CountDownLatch#await()} is interrupted. 123 */ 124 public static Response blockingCall(final Handler handler, final Context context, final Request request) 125 throws InterruptedException { 126 127 final CountDownLatch latch = new CountDownLatch(1); 128 Response response = handler.handle(context, request) 129 // Decrement the latch at the very end of the listener's sequence 130 .thenOnResult(new ResultHandler<Response>() { 131 @Override 132 public void handleResult(Response result) { 133 latch.countDown(); 134 } 135 }) 136 // Block the promise, waiting for the response 137 .getOrThrow(); 138 139 // Wait for the latch to be released so we can make sure that all of the Promise's ResultHandlers and Functions 140 // have been invoked 141 latch.await(); 142 143 return response; 144 } 145}