com.agapsys.rcf.Controller Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of rcf-core Show documentation
Show all versions of rcf-core Show documentation
REST Controller Framework for java back-end applications
/*
* Copyright 2015 Agapsys Tecnologia Ltda-ME.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.agapsys.rcf;
import com.agapsys.rcf.exceptions.ClientException;
import com.agapsys.rcf.exceptions.ForbiddenException;
import com.agapsys.rcf.exceptions.UnauthorizedException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
import java.util.Set;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* Servlet responsible by mapping methods to actions
*/
public class Controller extends ActionServlet {
//
// ========================================================================
public static final String METHOD_NAME_MAPPING = "?";
//
// -------------------------------------------------------------------------
private static final Set EMPTY_ROLE_SET = Collections.unmodifiableSet(new LinkedHashSet());
private static final Object[] EMPTY_OBJ_ARRAY = new Object[] {};
// -------------------------------------------------------------------------
//
/** Defines a Data Transfer Object */
public static interface Dto {
/**
* Returns a transfer object associated with this instance.
*
* @return a transfer object associated with this instance.
*/
public T getDto();
}
/** Name of the session attribute used to store current user. */
public static final String SESSION_ATTR_USER = Controller.class.getName() + ".SESSION_ATTR_USER";
/** Name of the default session attribute used to store CSRF token. */
public static final String SESSION_ATTR_CSRF_TOKEN = Controller.class.getName() + ".SESSION_ATTR_CSRF_TOKEN";
/** Name of the header used to send/retrieve a CSRF token. */
public static final String CSRF_HEADER = "X-Csrf-Token";
// Default size of CSRF token
private static final int CSRF_TOKEN_LENGTH = 128;
private static String __getRandom(int length) {
char[] chars = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
return __getRandom(length, chars);
}
private static String __getRandom(int length, char[] chars) {
if (length < 1) throw new IllegalArgumentException("Invalid length: " + length);
if (chars == null || chars.length == 0) throw new IllegalArgumentException("Null/Empty chars");
StringBuilder sb = new StringBuilder();
Random random = new Random();
for (int i = 0; i < length; i++) {
char c = chars[random.nextInt(chars.length)];
sb.append(c);
}
return sb.toString();
}
// =========================================================================
//
private class MethodCallerAction implements Action {
private final String[] requiredRoles;
private final Method method;
private final boolean secured;
private MethodCallerAction(Method method, boolean secured, String[] requiredRoles) {
if (!Modifier.isPublic(method.getModifiers()))
throw new RuntimeException("Action method is not public: " + method.toGenericString());
this.method = method;
this.requiredRoles = requiredRoles;
this.secured = secured || requiredRoles.length > 0;
}
private Object[] __getCallParams(Method method, ActionRequest request, ActionResponse response) throws IOException {
if (method.getParameterCount() == 0) return EMPTY_OBJ_ARRAY;
List argList = new LinkedList();
for (Parameter param : method.getParameters()) {
Class> paramClass = param.getType();
if (JsonRequest.class.isAssignableFrom(paramClass)) {
argList.add(new JsonRequest(request));
continue;
}
if (JsonResponse.class.isAssignableFrom(paramClass)) {
argList.add(new JsonResponse(response));
continue;
}
if (ActionRequest.class.isAssignableFrom(paramClass)) {
argList.add(request);
continue;
}
if (ActionResponse.class.isAssignableFrom(paramClass)) {
argList.add(response);
continue;
}
if (HttpServletRequest.class.isAssignableFrom(paramClass)) {
argList.add(request.getServletRequest());
continue;
}
if (HttpServletResponse.class.isAssignableFrom(paramClass)) {
argList.add(response.getServletResponse());
continue;
}
// It's a json for an object or a list of objects...
JsonRequest jsonRequest = new JsonRequest(request);
if (Collection.class.isAssignableFrom(paramClass)) {
// Must be a list...
if (!List.class.isAssignableFrom(paramClass))
throw new UnsupportedOperationException(String.format("Unsupported param type: %s", paramClass));
Type pType = param.getParameterizedType();
if (! (pType instanceof ParameterizedType))
throw new UnsupportedOperationException("Missing list element type");
Type elementType = ((ParameterizedType) pType).getActualTypeArguments()[0];
if (!elementType.getClass().equals(Class.class))
throw new UnsupportedOperationException("Unsupported list element type: " + elementType);
argList.add(jsonRequest.readList((Class)elementType));
} else {
// It's an object...
argList.add(jsonRequest.readObject(paramClass));
}
}
return argList.toArray();
}
private void __checkSecurity(ActionRequest request, ActionResponse response) throws ServletException, IOException, UnauthorizedException, ForbiddenException {
if (secured) {
User user = getUser(request);
if (user == null)
throw new UnauthorizedException("Unauthorized");
Set userRoles = user.getRoles();
if (userRoles == null)
userRoles = EMPTY_ROLE_SET;
for (String requiredRole : requiredRoles) {
if (!userRoles.contains(requiredRole))
throw new ForbiddenException();
}
}
}
private Object __getSingleDto(Object obj) {
if (obj == null)
return null;
if (obj instanceof Dto)
return ((Dto) obj).getDto();
return obj;
}
private List __getDtoList(List objList) {
List dto = new LinkedList();
for (Object obj : objList) {
dto.add(__getSingleDto(obj));
}
return dto;
}
private Map __getDtoMap(Map
© 2015 - 2025 Weber Informatics LLC | Privacy Policy