Java tutorial
/** This file is part of Waarp Project. Copyright 2009, Frederic Bregier, and individual contributors by the @author tags. See the COPYRIGHT.txt in the distribution for a full listing of individual contributors. All Waarp Project is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Waarp is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Waarp . If not, see <http://www.gnu.org/licenses/>. */ package org.waarp.gateway.kernel.rest; import java.util.HashSet; import java.util.Set; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpResponse; import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.multipart.FileUpload; import org.waarp.common.logging.WaarpLogger; import org.waarp.common.logging.WaarpLoggerFactory; import org.waarp.common.utility.WaarpStringUtils; import org.waarp.gateway.kernel.exception.HttpForbiddenRequestException; import org.waarp.gateway.kernel.exception.HttpIncorrectRequestException; import org.waarp.gateway.kernel.exception.HttpInvalidAuthenticationException; import org.waarp.gateway.kernel.exception.HttpMethodNotAllowedRequestException; import org.waarp.gateway.kernel.exception.HttpNotFoundRequestException; import org.waarp.gateway.kernel.rest.DataModelRestMethodHandler.COMMAND_TYPE; import org.waarp.gateway.kernel.rest.HttpRestHandler.METHOD; import com.fasterxml.jackson.databind.node.ArrayNode; /** * Rest Method handler (used by Http Rest Handler) * * @author "Frederic Bregier" * */ public abstract class RestMethodHandler { /** * Internal Logger */ private static final WaarpLogger logger = WaarpLoggerFactory.getLogger(RestMethodHandler.class); protected final String name; protected final String path; protected final Set<METHOD> methods; protected final boolean isBodyJsonDecode; protected final RestConfiguration restConfiguration; /** * @param name * name associated with this Method Handler (to enable some HashMap or Enum classification) * @param path * associated base Path * @param isBodyJsonDecode * Is this method Handler using a Json as Body * @param config * the associated configuration * @param method * the associated methods */ public RestMethodHandler(String name, String path, boolean isBodyJsonDecode, RestConfiguration config, METHOD... method) { this.name = name; this.path = path; this.methods = new HashSet<HttpRestHandler.METHOD>(); setMethods(method); setMethods(METHOD.OPTIONS); this.isBodyJsonDecode = isBodyJsonDecode; this.restConfiguration = config; } protected void setMethods(METHOD... method) { for (METHOD method2 : method) { methods.add(method2); } } /** * Will assign the intersection of both set of Methods * * @param selectedMethods * the selected Methods among available * @param validMethod * the validMethod for this handler */ protected void setIntersectionMethods(METHOD[] selectedMethods, METHOD... validMethod) { Set<METHOD> set = new HashSet<METHOD>(); for (METHOD method : validMethod) { set.add(method); } Set<METHOD> set2 = new HashSet<METHOD>(); for (METHOD method : selectedMethods) { set2.add(method); } set.retainAll(set2); METHOD[] methodsToSet = set.toArray(new METHOD[0]); setMethods(methodsToSet); } public String getName() { return name; } public String getPath() { return path; } /** * * @param method * @return True if the Method is valid for this Handler */ public boolean isMethodIncluded(METHOD method) { return methods.contains(method); } /** * Check the session (arguments, result) vs handler correctness, called before any BODY elements but after URI and HEADER. * * @param handler * @param arguments * @param result * @throws HttpForbiddenRequestException */ public abstract void checkHandlerSessionCorrectness(HttpRestHandler handler, RestArgument arguments, RestArgument result) throws HttpForbiddenRequestException; /** * Get a new Http Uploaded File from BODY * * @param handler * @param data * @param arguments * @param result * @throws HttpIncorrectRequestException */ public abstract void getFileUpload(HttpRestHandler handler, FileUpload data, RestArgument arguments, RestArgument result) throws HttpIncorrectRequestException; /** * Get data from BODY (supposedly a Json) * * @param handler * @param body * @param arguments * @param result * @return the object related to BODY decoding * @throws HttpIncorrectRequestException */ public abstract Object getBody(HttpRestHandler handler, ByteBuf body, RestArgument arguments, RestArgument result) throws HttpIncorrectRequestException; /** * Called when all Data were passed to the handler * * @param handler * @param arguments * @param result * @param body * @throws HttpIncorrectRequestException * @throws HttpNotFoundRequestException */ public abstract void endParsingRequest(HttpRestHandler handler, RestArgument arguments, RestArgument result, Object body) throws HttpIncorrectRequestException, HttpInvalidAuthenticationException, HttpNotFoundRequestException; /** * Called when an exception occurs * * @param handler * @param arguments * @param result * @param body * @param exception * @return the status to used in sendReponse */ public HttpResponseStatus handleException(HttpRestHandler handler, RestArgument arguments, RestArgument result, Object body, Exception exception) { if (exception instanceof HttpInvalidAuthenticationException) { result.setResult(HttpResponseStatus.UNAUTHORIZED); return HttpResponseStatus.UNAUTHORIZED; } else if (exception instanceof HttpForbiddenRequestException) { result.setResult(HttpResponseStatus.FORBIDDEN); return HttpResponseStatus.FORBIDDEN; } else if (exception instanceof HttpIncorrectRequestException) { result.setResult(HttpResponseStatus.BAD_REQUEST); return HttpResponseStatus.BAD_REQUEST; } else if (exception instanceof HttpMethodNotAllowedRequestException) { result.setResult(HttpResponseStatus.METHOD_NOT_ALLOWED); return HttpResponseStatus.METHOD_NOT_ALLOWED; } else if (exception instanceof HttpNotFoundRequestException) { result.setResult(HttpResponseStatus.NOT_FOUND); return HttpResponseStatus.NOT_FOUND; } else { result.setResult(HttpResponseStatus.INTERNAL_SERVER_ERROR); return HttpResponseStatus.INTERNAL_SERVER_ERROR; } } /** * Send a response (correct or not) * * @param handler * @param ctx * @param arguments * @param result * @param body * @param status * @return The ChannelFuture if this response will need the channel to be closed, else null */ public abstract ChannelFuture sendResponse(HttpRestHandler handler, ChannelHandlerContext ctx, RestArgument arguments, RestArgument result, Object body, HttpResponseStatus status); protected ChannelFuture sendOptionsResponse(HttpRestHandler handler, ChannelHandlerContext ctx, RestArgument result, HttpResponseStatus status) { String list = result.getAllowOption(); String answer = result.toString(); ByteBuf buffer = Unpooled.wrappedBuffer(answer.getBytes(WaarpStringUtils.UTF8)); HttpResponse response = handler.getResponse(buffer); if (status == HttpResponseStatus.UNAUTHORIZED) { ChannelFuture future = ctx.writeAndFlush(response); return future; } response.headers().add(HttpHeaders.Names.CONTENT_TYPE, "application/json"); response.headers().add(HttpHeaders.Names.REFERER, handler.getRequest().uri()); response.headers().add(HttpHeaders.Names.ALLOW, list); logger.debug("Msg ready"); ChannelFuture future = ctx.writeAndFlush(response); if (handler.isWillClose()) { System.err.println("Will close session in RestMethodHandler"); return future; } return null; } /** * Options command that all handler should implement * * @param handler * @param arguments * @param result */ protected void optionsCommand(HttpRestHandler handler, RestArgument arguments, RestArgument result) { result.setCommand(COMMAND_TYPE.OPTIONS); METHOD[] realmethods = METHOD.values(); boolean[] allMethods = new boolean[realmethods.length]; for (METHOD methoditem : methods) { allMethods[methoditem.ordinal()] = true; } String allow = null; for (int i = 0; i < allMethods.length; i++) { if (allMethods[i]) { if (allow == null) { allow = realmethods[i].name(); } else { allow += "," + realmethods[i].name(); } } } result.addOptions(allow, path, getDetailedAllow()); } /** * * @return the detail of the method handler */ protected abstract ArrayNode getDetailedAllow(); /** * @return the isBodyJson */ public boolean isBodyJsonDecoded() { return isBodyJsonDecode; } }