package microservices.sample.base.ratpack; import com.google.gson.Gson; import com.google.inject.Inject; import com.google.inject.Singleton; import microservices.sample.InvalidValueException; import microservices.sample.ResourceNotFoundException; import ratpack.exec.Fulfiller; import ratpack.func.Action; import ratpack.handling.Context; import ratpack.http.TypedData; import java.net.HttpURLConnection; import java.util.function.Consumer; /** * Helper class for reading and writing json objects in ratpack handlers. * * @author mamad * @since 15/03/15. */ @Singleton public class HandlerHelper { public static final String JSON_MIME_TYPE = "application/json"; private final Gson gson; @Inject public HandlerHelper(Gson gson) { this.gson = gson; } public static Action<String> newJsonAction(Context context) { return newJsonAction(context, HttpURLConnection.HTTP_OK); } /** * Return a lambda function which writes the input json string to the response and sets the mime type and response code. * * @param context request/response context * @param httpStatusCode response code * @return lambda function */ public static Action<String> newJsonAction(Context context, int httpStatusCode) { return json -> context .getResponse() .status(httpStatusCode) .send(JSON_MIME_TYPE, json); } public static Action<Throwable> newErrorAction(Context context) { return throwable -> { if (throwable instanceof InvalidValueException) { StatusHelper.sendBadRequest(context, throwable.getMessage()); } else if (throwable instanceof ResourceNotFoundException) { StatusHelper.sendNotFound(context, ((ResourceNotFoundException) throwable).getId()); } else { StatusHelper.sendInternalError(context, throwable); } }; } public static void handleRequestWithPromise(Context context, Action<Fulfiller<String>> action) { context.promise(action).onError(HandlerHelper.newErrorAction(context)).then(HandlerHelper.newJsonAction(context)); } public <T> T fromBody(Context context, Class<T> typeClass) { TypedData requestBody = context.getRequest().getBody(); T requestObject = gson.fromJson(requestBody.getText(), typeClass); /** * enable leak detection: -Dio.netty.leakDetectionLevel=advanced or call ResourceLeakDetector.setLevel() * see http://stackoverflow.com/a/25856285 * * IMPORTANT: call release after every access to request body, otherwise there will be memory leak. * see http://netty.io/wiki/reference-counted-objects.html */ requestBody.getBuffer().release(); return requestObject; } /** * Creates a new lambda to convert the response object to json and pass it to the fulfiller * * @param fulfiller fulfiller of an asynchronous promise. * @param <T> type of input object * @return lambda consumer */ public <T> Consumer<T> newJsonConsumer(Fulfiller<String> fulfiller) { return response -> fulfiller.success(gson.toJson(response)); } }