<file_sep>package sybrix.easygsp2.exceptions;

/**
 * Created by dsmith on 8/16/15.
 */
public class InvokeControllerActionException extends HttpException {

        public InvokeControllerActionException() {
                super(500);
        }

        public InvokeControllerActionException(String message) {
                super(message,500);
        }

        public InvokeControllerActionException(String message, Throwable cause) {
                super(message, cause,500);
        }

        public InvokeControllerActionException(Throwable cause) {
                super(cause,500);
        }

        protected InvokeControllerActionException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
                super(message, cause, enableSuppression, writableStackTrace,500);
        }
}
<file_sep>package sybrix.easygsp2.categories;

public class MethodSecurity {
        boolean secured = false;
        String [] roles = {};

        public MethodSecurity(boolean secured, String[] roles) {
                this.secured = secured;
                this.roles = roles;
        }

        public boolean isSecured() {
                return secured;
        }

        public void setSecured(boolean secured) {
                this.secured = secured;
        }

        public String[] getRoles() {
                return roles;
        }

        public void setRoles(String[] roles) {
                this.roles = roles;
        }
}
<file_sep>package sybrix.easygsp2.data;

import com.fasterxml.jackson.core.JsonProcessingException;
import sybrix.easygsp2.exceptions.SerializerException;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Type;

public interface Serializer {
        public void write(Object o, OutputStream outputStream) throws SerializerException;

        String toString(Object o);

        Object parse(String xmlString, Class cls);

        Object parse(String xmlString);

        Object parse(InputStream inputStream, int length);

        Object parse(InputStream inputStream, int length, Class clazz, Type modelType);

}
<file_sep>package sybrix.easygsp2.anno;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Created by dsmith on 4/19/15.
 */

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface Api {

        String[] url();

        String[] method() default {"*"};

        String[] roles() default {"*"};

        String[] accepts() default {};

        String[] contentType() default {};
}<file_sep>package sybrix.easygsp2.util;


import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;
import java.net.URLDecoder;


/**
 * Created by IntelliJ IDEA.
 * User: dsmith
 * Date: Apr 12, 2007
 * Time: 6:12:40 PM
 */
public class CookieManager {
        //private static final Logger log = Logger.getLogger(CookieManager.class);
        public static final int DAY = 60 * 60 * 24;

        /**
         * Returns an instance to the specified cookie.
         *
         * @param cookieName String
         * @return Cookie - returns null if the cookie doesn't exists.
         */
        public static Cookie getCookie(String cookieName, HttpServletRequest request) {

                Cookie c[] = request.getCookies();
                if (c != null) {
                        for (int x = 0; x < c.length; x++) {
                                if (c[x].getName().equals(cookieName)) {
                                        return c[x];
                                }
                        }
                }
                return null;
        }

        public static Cookie createCookie(String cookieName, String value, int expiresInDays) {
                Cookie cookie = new Cookie(cookieName, value);
                cookie.setMaxAge(60 * 60 * 24 * expiresInDays);
                cookie.setPath("/");
                return cookie;

        }

        public static Map<String, String> getCookieMap(Cookie cookie, HttpServletRequest request) {
                if (request.getAttribute(cookie.getName() + "_cookie") == null) {
                        String _value =cookie.getValue();
                        String pair[] = _value.split(";");


                        Map map = new HashMap();
                        for (int i = 0; i < pair.length; i++) {
                                int index = pair[i].indexOf('=');
                                if (index > -1) {
                                        String name = pair[i].substring(0, index);
                                        String value = pair[i].substring(index + 1, pair[i].length());

                                        map.put(name, value);
                                }
                        }
                        request.setAttribute(cookie.getName() + "_cookie", map);
                }



                return (Map) request.getAttribute(cookie.getName() + "_cookie");
        }


//        public static String getCookieMapValue(Map map) {
//                Iterator i = map.keySet().iterator();
//                StringBuffer val = new StringBuffer(100);
//                while (i.hasNext()) {
//                        String key = i.next().toString();
//                        String value = map.get(key).toString();
//                        if (key.trim().length() > 0)
//                                val.append(key).append("=").append(value).append(";");
//                }
//
//                Encrypt enc = new Encrypt();
//                try {
//                        byte encrypted[] = enc.encrypt(val.toString().getBytes());
//                        return java.net.URLEncoder.encode(Utilities.base64Encode(encrypted),"UTF-8");
//                } catch (Exception e) {
//                        log.error(e.getMessage(), e);
//                }
//
//                return "";
//        }
//
//        public static String decryptValue(String val) {
//                Encrypt enc = new Encrypt();
//                byte[] decoded = null;
//                try {
//                        String urlDecoded = URLDecoder.decode(val,"UTF-8");
//                        decoded = enc.base64Decode(urlDecoded);
//                        byte[] decrypted = enc.decrypt(decoded);
//                        return new String(decrypted);
//                }catch(Exception e){
//                        log.error(e.getMessage(),e);
//                }
//
//                return "";
//        }


//        private static byte[] padBytes(byte value[]) {
//                int len = 8;
//                int originalLength = value.length;
//                if (value.length > len) {
//                        len = ((value.length / 8) + 1) * 8;
//                }
//
//                value = Utilities.increaseArrayLength(value, len);
//
//                return value;
//        }
//
//        private static String pad(String value) {
//                int len = 8;
//                if (value.length() > len) {
//                        len = ((value.length() / 8) + 1) * 8;
//                }
//
//                StringBuffer v = new StringBuffer(len);
//                v.append(value);
//
//                for (int i = 0; i < len - value.length(); i++) {
//                        v.append(" ");
//                }
//
//                return v.toString();
//        }


}
<file_sep>package sybrix.easygsp2;

import groovy.lang.*;
import io.jsonwebtoken.ExpiredJwtException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.LoaderClassPath;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.io.FileUtils;
import org.codehaus.groovy.control.CompilerConfiguration;
import org.codehaus.groovy.runtime.GroovyCategorySupport;
import org.codehaus.groovy.runtime.InvokerHelper;
import org.reflections.Reflections;
import org.reflections.scanners.MethodAnnotationsScanner;
import org.reflections.scanners.SubTypesScanner;
import org.reflections.scanners.TypeElementsScanner;
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;
import sybrix.easygsp2.anno.Api;
import sybrix.easygsp2.anno.Content;
import sybrix.easygsp2.anno.Secured;
import sybrix.easygsp2.categories.RoutingCategory;
import sybrix.easygsp2.controllers.JwtController;
import sybrix.easygsp2.data.Serializer;
import sybrix.easygsp2.data.XmlSerializer;
import sybrix.easygsp2.email.EmailService;
import sybrix.easygsp2.exceptions.*;
import sybrix.easygsp2.fileupload.FileUpload;
import sybrix.easygsp2.framework.*;
import sybrix.easygsp2.http.MediaType;
import sybrix.easygsp2.http.ControllerResponse;
import sybrix.easygsp2.http.MimeTypes;
import sybrix.easygsp2.models.CreateClientRequest;
import sybrix.easygsp2.routing.MethodAndRole;
import sybrix.easygsp2.routing.Route;
import sybrix.easygsp2.routing.Routes;
import sybrix.easygsp2.routing.UrlParameter;
import sybrix.easygsp2.security.*;
import sybrix.easygsp2.templates.RequestError;
import sybrix.easygsp2.templates.TemplateInfo;
import sybrix.easygsp2.templates.TemplateWriter;
import sybrix.easygsp2.util.PropertiesFile;

import javax.activation.MimeType;
import javax.activation.MimeTypeParseException;
import javax.servlet.*;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.Principal;
import java.util.*;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;

import org.slf4j.LoggerFactory;
import sybrix.easygsp2.util.StringUtil;

import static sybrix.easygsp2.util.StringUtil.combine;

/**
 * Created by dsmith on 7/19/16.
 */
public class EasyGsp2 {
        private static final org.slf4j.Logger logger = LoggerFactory.getLogger(EasyGsp2.class);

        private static final String JSON_SERIALIZER_CLASS = "sybrix.easygsp2.data.JsonSerializerImpl";
        private static final String XML_SERIALIZER_CLASS = "sybrix.easygsp2.data.XmlSerializerImpl";
        public static final String ROUTE_REQUEST_ATTR = "__route__";

        public static final MimeType APPLICATION_JSON = parseMimeType("application/json");
        public static final MimeType APPLICATION_XML = parseMimeType("application/xml");
        public static final MimeType APPLICATION_HTML_TEXT = parseMimeType("text/html");

        private static Map<String, sybrix.easygsp2.routing.Route> routes = new LinkedHashMap<String, sybrix.easygsp2.routing.Route>();
        private GroovyClassLoader groovyClassLoader;
        private PropertiesFile propertiesFile;
        private ServletContext context;

        protected Serializer jsonSerializerInstance;
        protected XmlSerializer xmlSerializerInstance;
        protected List<Pattern> ignoredUrlPatterns;

        private Set<String> classesWithApiAnnotation = new HashSet<String>();
        private Map<String, String> methods = new HashMap<String, String>();
        private boolean isServlet = false;
        private AppListener appListener;

        private Validator validator;
        private EmailService emailService;
        private AuthenticationService authenticationService;
        private Map<String, Object> dynamicProperties = new HashMap<>();

        public static EasyGsp2 instance;

        public EasyGsp2(FilterConfig config) {
                init(config.getServletContext(), config);
        }

        public EasyGsp2(ServletConfig config) {
                init(config.getServletContext(), config);
        }

        public void init(ServletContext servletContext, Object config) {
                try {
                        instance = this;
                        this.context = servletContext;
                        System.setProperty("easygsp.version", "@easygsp_version");

                        logger.info(
                                "\nEASYGSP_VERSION: " + System.getProperty("easygsp.version") +
                                        "\nJRE_HOME: " + System.getProperty("java.home") +
                                        "\nJAVA_VERSION: " + System.getProperty("java.version") +
                                        "\nGROOVY_VERSION: " + GroovySystem.getVersion() +
                                        "\n"
                        );

                        propertiesFile = new PropertiesFile("classPath:easygsp.properties");
                        servletContext.setAttribute(PropertiesFile.KEY, propertiesFile);

                        if (config instanceof ServletConfig) {
                                isServlet = true;
                        }

                        // delete tmp dir
                        File folder = new File(propertiesFile.getString("easygsp.tmp.dir", System.getProperty("java.io.tmpdir")));
                        if (folder.exists()) {
                                FileUtils.cleanDirectory(folder);
                        } else {
                                folder.mkdirs();
                        }

                        CompilerConfiguration configuration = new CompilerConfiguration();
                        configuration.setTargetDirectory(getCompiledClassesDir());
                        //configuration.setRecompileGroovySource(propertiesFile.getString("mode", "dev1").equalsIgnoreCase("dev"));

                        groovyClassLoader = new GroovyClassLoader(this.getClass().getClassLoader(), configuration);
                        //groovyClassLoader.addURL(getSourcePath(propertiesFile));

                        ignoredUrlPatterns = new ArrayList<Pattern>();

                        ThreadBag.set(new ThreadVariables(this.context, null, null, routes, null, null, groovyClassLoader));

                        if (propertiesFile.getString("authentication.service") != null) {
                                Class clsAuth = Class.forName(propertiesFile.getString("authentication.service"));
                                authenticationService = (AuthenticationService) clsAuth.newInstance();
                        } else {
                                logger.debug("No authentication.service value found");
                        }

                        if (propertiesFile.getString("email.service") != null) {
                                emailService = (EmailService) Class.forName(propertiesFile.getString("email.service")).newInstance();
                                context.setAttribute("emailService", emailService);
                        } else {
                                logger.debug("No email.service value found");
                        }

                        loadDefaultRoutes();//1
                        loadApiMethods(propertiesFile);//2
                        loadUnannotatedClasses(propertiesFile, "controllers.package"); //3 order matters
                        loadUnannotatedClasses(propertiesFile, "api.controllers.package"); //3 order matters
                        loadSerializers(propertiesFile);
                        loadPropertiesIntoContext(servletContext, propertiesFile);
                        loadJwtValues(propertiesFile);

                        String appListenerClass = null;
                        if (config instanceof ServletConfig) {
                                appListenerClass = ((ServletConfig) config).getInitParameter("appListener");
                        } else if (config instanceof FilterConfig) {
                                appListenerClass = ((FilterConfig) config).getInitParameter("appListener");
                        }
                        // load DB String queries
                        ThreadBag.set(new ThreadVariables(servletContext));

                        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
                        validator = factory.getValidator();

                        if (appListenerClass != null) {
                                Class cls = Class.forName(appListenerClass, false, groovyClassLoader);
                                //appListener = (AppListener) cls.newInstance();
                                appListener = (AppListener) ClassFactory.create(cls, this);
                                appListener.onApplicationStart(servletContext);
                        }

                } catch (Throwable e) {
                        logger.error("error occurred easygsp init()", e);
                } finally {
                        ThreadBag.remove();
                }
        }

        private void loadDefaultRoutes() {
                if (propertiesFile.getBoolean("jwt.controller.enabled", false)) {
                        Routes.add("POST", propertiesFile.getString("jwt.token.url", "/api/token"), JwtController.class, "generateToken", new Class[]{HttpServletRequest.class, HttpServletResponse.class}, null, new String[]{MediaType.JSON}, new String[]{MediaType.JSON}, false);
                        Routes.add("POST", propertiesFile.getString("jwt.tokenMobile.url", "/api/tokenMobile"), JwtController.class, "generateTokenFromPhone", new Class[]{HttpServletRequest.class, HttpServletResponse.class}, null, new String[]{MediaType.JSON}, new String[]{MediaType.JSON}, false);
                        Routes.add("POST", "/client", JwtController.class, "createClient", new Class[]{CreateClientRequest.class, HttpServletRequest.class}, new String[]{}, new String[]{MediaType.JSON}, new String[]{MediaType.JSON}, true);
                }
        }

        private void loadJwtValues(PropertiesFile propertiesFile) {

                JwtUtil jwtUtil = new JwtUtil(propertiesFile.getString("jwt.alg", "HS256"));
                String key = propertiesFile.getString("jwt.key");
                if (key == null) {
                        logger.info("no jwt key found. generating key....");
                        key = jwtUtil.generateKey();
                        logger.info("generated jwt key, HS256: " + key);
                }

                jwtUtil.loadKey(key);
                JwtUtil.instance = jwtUtil;
        }

        protected AppListener getAppListener() {
                return appListener;
        }

        public String getCompiledClassesDir() {
                try {
                        File f = new File(this.getClass().getClassLoader().getResource("./../../WEB-INF/classes").toURI());
                        logger.info("compiled classed dir: " + f.getAbsolutePath());
                        return f.getAbsolutePath();
                } catch (Exception e) {
                        throw new RuntimeException("failed on getCompiledClassesDir()", e);
                }
        }

        private URL getSourcePath(PropertiesFile propertiesFile) {
                String dir = propertiesFile.getProperty("source.dir", null);
                URL url = null;
                try {
                        if (dir != null) {
                                url = new File(dir).toURI().toURL();
                        } else {
                                url = this.getClass().getClassLoader().getResource("./../../");
                        }

                        logger.info("source path: " + url.getFile());
                        return url;
                } catch (MalformedURLException e) {
                        throw new RuntimeException("Failed to determine source directory.  " + e.getMessage(), e);
                }
        }

        public boolean doRequest(final EasyGspServletRequest httpServletRequest, final HttpServletResponse httpServletResponse) throws ServletException {


                String uri = null;
                String contextPath = httpServletRequest.getServletContext().getContextPath();
                if (contextPath.length() > 1) {
                        uri = httpServletRequest.getRequestURI().substring(contextPath.length());
                } else {
                        uri = httpServletRequest.getRequestURI();
                }


                logger.debug("processing web request, method: " + httpServletRequest.getMethod() + ", uri: " + uri);
                Boolean continueFilterChain = false;

                List<MimeType> acceptHeaderMimeTypes;

                try {
                        acceptHeaderMimeTypes = parseAcceptHeader(httpServletRequest.getHeader("Accept"));

                        for (Pattern s : ignoredUrlPatterns) {
                                if (s.matcher(uri).matches()) {
                                        logger.debug("url: " + uri + " found on ignore list");
                                        return true;
                                }
                        }

                        // default it to null, if you set it we'll know
                        httpServletResponse.setContentType(null);

                        final boolean isMultiPart = isMultiPart(httpServletRequest.getContentType());
                        final List<FileItem> uploads = FileUpload.parseFileUploads(httpServletRequest, propertiesFile);

                        ThreadBag.set(new ThreadVariables(this.context, httpServletRequest, httpServletResponse, routes, null, null, groovyClassLoader));
                          logger.debug("searching for matching route for uri: " + uri);

                        final sybrix.easygsp2.routing.Route route = findRoute(uri, httpServletRequest.getMethod());
                        if (route == null) {
                                if (httpServletRequest.getMethod().equalsIgnoreCase("GET")) {
                                        logger.warn("remember- unannotated get() requires an Id parameter {<\\d+$>id}, index() does not");
                                }
                                throw new NoMatchingRouteException("No route found for: " + uri);
                        }

                        String extension = StringUtil.extractFileExtension(uri);


                        Closure closure = new Closure(this) {

                                Class controllerClass = null;
                                boolean isApiController = false;

                                public Object call() {

                                        MimeType returnContentType = null;

                                        try {
                                                checkUserAuthorization(route, httpServletRequest);

                                                appListener.onRequestStart(httpServletRequest);

                                                String contentType = httpServletRequest.getContentType();
                                                int contentLength = httpServletRequest.getContentLength();

                                                Method m = null;

                                                controllerClass = route.getControllerClass();
                                                m = route.getControllerMethod();

                                                GroovyObject controller = ClassFactory.create(controllerClass, getOwner());

                                                List<String> s = lookupParameterNames(m, groovyClassLoader);
                                                Parameter[] parameters = m.getParameters();

                                                logger.debug("invoking method " + controllerClass.getName() + "." + m.getName() + "(), parameters: " + extractParameterTypes(parameters));
                                                logger.debug("parameter names: " + s);
                                                Enumeration<String> names = httpServletRequest.getHeaderNames();

                                                while (names.hasMoreElements()) {
                                                        String header = names.nextElement();
                                                        logger.debug("header name/value: " + header + ":" + httpServletRequest.getHeader(header));
                                                }

                                                Object[] params = new Object[parameters.length];

                                                int i = 0;
                                                for (Parameter p : parameters) {
                                                        String parameterName = p.getName();
                                                        if (s.size() >= parameters.length) {
                                                                parameterName = s.get(i);
                                                        }

                                                        Class clazz = p.getType();
                                                        Type genericType = extractGenericType(p);

                                                        if (clazz == javax.servlet.http.HttpServletRequest.class || parameterName.equalsIgnoreCase("request")) {
                                                                params[i] = httpServletRequest;

                                                        } else if (clazz == HttpServletResponse.class || parameterName.equalsIgnoreCase("response")) {
                                                                params[i] = httpServletResponse;
                                                        } else if ((clazz == List.class && genericType == FileItem.class) || parameterName.equalsIgnoreCase("uploads") && isMultiPart) {
                                                                params[i] = uploads;
                                                        } else if ((clazz == FileItem.class) && isMultiPart) {
                                                                params[i] = getFileItemByName(uploads, parameterName);
                                                        } else if (clazz == ServletContext.class || parameterName.equalsIgnoreCase("app")) {

                                                                params[i] = httpServletRequest.getServletContext();
                                                        } else if (clazz == RequestContext.class || parameterName.equalsIgnoreCase("context")) {
                                                                RequestContext requestContext = new RequestContext();
                                                                requestContext.setApp(httpServletRequest.getServletContext());
                                                                requestContext.setProperties(propertiesFile);
                                                                requestContext.setUserPrincipal(httpServletRequest.getUserPrincipal());
                                                                requestContext.setRequest(httpServletRequest);
                                                                requestContext.setResponse(httpServletResponse);

                                                                params[i] = requestContext;
                                                        } else if (clazz == PropertiesFile.class || parameterName.equalsIgnoreCase("propertiesFile")) {
                                                                params[i] = propertiesFile;

                                                        } else if (clazz == UserPrincipal.class || clazz == Principal.class) {

                                                                params[i] = httpServletRequest.getUserPrincipal();

                                                        } else {

                                                                String valFromRequestParameter = null;

                                                                if (route.getParameters().size() > 0) {
                                                                        UrlParameter urlParameter = route.getParameters().get(parameterName);
                                                                        if (urlParameter == null && m.getName().equalsIgnoreCase("get")) {
                                                                                logger.debug("unannotated method, did not find default parameter named \"id\", trying \"" + parameterName + "\" instead");
                                                                                urlParameter = route.getParameters().get("id");
                                                                                if (urlParameter == null) {
                                                                                        throw new BadRequestException("parameter name 'id' required. parameter name: " + parameterName);
                                                                                }
                                                                        }
                                                                        if (urlParameter.getValue() != null) {
                                                                                valFromRequestParameter = urlParameter.getValue();
                                                                        } else if (valFromRequestParameter == null) {
                                                                                valFromRequestParameter = httpServletRequest.getParameter(parameterName);
                                                                        }
                                                                } else {
                                                                        valFromRequestParameter = httpServletRequest.getParameter(parameterName);
                                                                }

                                                                if (valFromRequestParameter != null) {
                                                                        params[i] = castToType(valFromRequestParameter, clazz);

                                                                } else if (contentLength > 0 && isJson(contentType)) {

                                                                        Object obj = null;
                                                                        if (clazz.getTypeName().equals("java.lang.Object")) {
                                                                                obj = jsonSerializerInstance.parse(httpServletRequest.getInputStream(), contentLength);
                                                                        } else {

                                                                                obj = jsonSerializerInstance.parse(httpServletRequest.getInputStream(), contentLength, clazz, genericType);
                                                                        }
                                                                        params[i] = obj;

                                                                } else if (contentLength > 0 && isXML(contentType)) {
                                                                        Object obj = null;
                                                                        if (clazz.getTypeName().equals("java.lang.Object")) {
                                                                                obj = xmlSerializerInstance.fromXml(httpServletRequest.getInputStream(), contentLength);
                                                                        } else {
                                                                                obj = xmlSerializerInstance.fromXml(httpServletRequest.getInputStream(), contentLength, clazz);
                                                                        }
                                                                        params[i] = obj;

                                                                } else { //if (contentType != null && contentLength > 0 && isFormUrlEncoded(contentType) ||) {
                                                                        Object obj = clazz.newInstance();
                                                                        populateBean(obj, httpServletRequest);
                                                                        params[i] = obj;
                                                                }
                                                        }

                                                        i++;
                                                }

                                                //checkUserAuthorization(route, httpServletRequest);

                                                isApiController = isApiController(controllerClass);
                                                returnContentType = getContentReturnType(isApiController, httpServletResponse, acceptHeaderMimeTypes, route, extension);

                                                List errors = validateParameters(params);
                                                if (errors.size() > 0) {
                                                        throw new BadRequestException(errors);
                                                }

                                                Object _controllerResponse = invokeControllerAction(controller, m, params, route);

                                                ControllerResponse controllerResponse = ControllerResponse.parse(_controllerResponse);
                                                if (controllerResponse.forwarded()) {
                                                        httpServletRequest.getRequestDispatcher(controllerResponse.getUrl()).forward(httpServletRequest, httpServletResponse);
                                                        return false; // return now, don't continue filter chain.
                                                }

                                                if (controllerResponse.redirected()) {
                                                        httpServletResponse.sendRedirect(controllerResponse.getUrl());
                                                        return false; // return now, don't continue filter chain.
                                                }

                                                if (controllerResponse.getHttpCode() != null) {
                                                        httpServletResponse.setStatus(controllerResponse.getHttpCode());
                                                }

                                                logger.debug("controllers returned: " + _controllerResponse);

                                                Object redirectIssued = httpServletRequest.getAttribute("__redirect__");

                                                if (Boolean.TRUE.equals(redirectIssued)) {
                                                        return false;
                                                }

                                                logger.debug("return content type: " + returnContentType.toString());

                                                if (returnContentType.getBaseType().equals(APPLICATION_HTML_TEXT.getBaseType())) {
                                                        logger.debug("processing view " + _controllerResponse);
                                                        ThreadBag.get().getTemplateInfo().setErrorOccurred(false);
                                                        return processControllerResponse(controllerResponse, httpServletResponse, httpServletRequest);

                                                } else {
                                                        if (returnContentType.getBaseType().equals(APPLICATION_JSON.getBaseType())) {
                                                                //httpServletResponse.flushBuffer();

                                                                if (controllerResponse.getIsEntity() && controllerResponse.getEntity() != null) {
                                                                        logger.debug("sending json response to client");
                                                                        jsonSerializerInstance.write(controllerResponse.getEntity(), httpServletResponse.getOutputStream());
                                                                        //httpServletResponse.flushBuffer();
                                                                } else {
                                                                        logger.debug("controllers method returned null object, that's a 200 OK");
                                                                }
                                                        }
                                                }

                                                return false;

                                        } catch (UnauthorizedException e) {
                                                //if (e.getMessage().equalsIgnoreCase("EMAIL_NOT_VALIDATED")) {
                                                processException(e, true, returnContentType, httpServletRequest, httpServletResponse);
                                                //}
                                                return false;
                                        } catch (HttpException e) {
                                                logger.debug(e.getMessage(), e);
                                                processException(e, isApiController, returnContentType, httpServletRequest, httpServletResponse);

                                                return false;
                                        } catch (java.lang.IllegalArgumentException e) {
                                                logger.error("controllers", e);
//                                        } catch (NoMatchingRouteException | NoMatchingAcceptHeaderException | UnauthorizedException e) {
//                                                sendError(e.getStatus(), new CustomServletBinding(httpServletRequest.getServletContext(), httpServletRequest, httpServletResponse), e.getCause().getCause());
//                                                return false;

                                        } catch (Exception e) {
                                                logger.error(e.getMessage(), e);

                                                processException(new HttpException(e, HttpServletResponse.SC_INTERNAL_SERVER_ERROR), isApiController, returnContentType, httpServletRequest, httpServletResponse);

                                                return false;
                                        }

                                        return null;
                                }
                        };

                        continueFilterChain = (Boolean) GroovyCategorySupport.use(CustomServletCategory.class, closure);

                } catch (NoMatchingRouteException e) {
                        if (isContentTypeAccepted(httpServletRequest, APPLICATION_JSON)) {
                                processException(e, true, APPLICATION_JSON, httpServletRequest, httpServletResponse);
                        } else {
                                sendError(e.getStatus(), new CustomServletBinding(this.context, httpServletRequest, httpServletResponse), e);
                        }

                        continueFilterChain = false;
                } catch (InvokeControllerActionException e) {

                        sendError(500, new CustomServletBinding(this.context, httpServletRequest, httpServletResponse), e.getCause().getCause());
                        //throw new ServletException(e.getCause());
                } catch (Exception e) {
                        logger.error(e.getMessage(), e);
                        sendError(500, new CustomServletBinding(this.context, httpServletRequest, httpServletResponse), e.getCause().getCause());
                        //throw new ServletException(e);
                } finally {
                        try {
                                if (appListener != null) {
                                        appListener.onRequestEnd(httpServletRequest);
                                }
                        } catch (Throwable e) {
                                e.printStackTrace();
                        }
                        ThreadBag.remove();
                }

                return continueFilterChain;
        }

        public MimeType getContentReturnType(Boolean apiRequest, HttpServletResponse httpServletResponse, List<MimeType> acceptHeaderMimeTypes, Route route, String extension) throws MimeTypeParseException {
                if (httpServletResponse.getContentType() == null) {

                        MimeType m = determineMimeTypeToReturn(apiRequest, acceptHeaderMimeTypes, route, extension);
                        httpServletResponse.setContentType(m.toString());

                        return m;

                } else {
                        return new MimeType(httpServletResponse.getContentType());
                }
        }

        public void processException(HttpException e, boolean apiRequest, MimeType returnContentType, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
                try {

                        httpServletResponse.setStatus(e.getStatus());


                        if (returnContentType.getBaseType().equals(APPLICATION_XML.getBaseType())) {
                                //msg = xmlSerializerInstance.toString(e.getConstraintErrors());
                                logger.error("IMPLEMENT XML toString on Serializer");
                        } else if (returnContentType.getBaseType().equals(APPLICATION_JSON.getBaseType()) && apiRequest) {
                                String msg = "";
                                if (e.getStatus() == 500) {
                                        ApiError apiError = new ApiError("Server error occurred.  Try again.");
                                        apiError.setCode(e.getStatus());
                                        if (e instanceof BadRequestException) {
                                                apiError.setMessages(((BadRequestException) e).getConstraintErrors());
                                        }

                                        msg = jsonSerializerInstance.toString(apiError);
                                } else {
                                        ApiError apiError = new ApiError(e.getMessage());
                                        if (e.getErrorCode() != null) {
                                                apiError.setCode(e.getErrorCode());
                                        } else {
                                                apiError.setCode(e.getStatus());
                                        }

                                        if (e instanceof BadRequestException) {
                                                apiError.setMessages(((BadRequestException) e).getConstraintErrors());
                                        }
                                        msg = jsonSerializerInstance.toString(apiError);
                                }

                                httpServletResponse.getOutputStream().write(msg.getBytes());

                        } else if (returnContentType.getBaseType().equals(APPLICATION_HTML_TEXT.getBaseType())) {
                                sendError(e.getStatus(), new CustomServletBinding(httpServletRequest.getServletContext(), httpServletRequest, httpServletResponse), extractException(e));
                        }

                } catch (Exception x) {
                        logger.debug("error occurred writing back to client on bad request", e);
                }
        }

        private Throwable extractException(HttpException e) {

                if (e.getCause() == null)
                        return e;
                else {
                        return e.getCause().getCause();
                }
        }

        private void checkUserAuthorization(Route route, EasyGspServletRequest httpServletRequest) throws UnauthorizedException {
                try {
                        if (route.isSecure()) {
                                UserPrincipal userPrincipal = (UserPrincipal) httpServletRequest.getUserPrincipal();
                                if (userPrincipal.getId() == null) {
                                        throw new UnauthorizedException();
                                }

                                if (route.getRoles().size() == 0) {
                                        // only authentication is required when route.getRoles.size ==0
                                        return;
                                }
                                // check for role
                                for (String role : route.getRoles()) {
                                        if (httpServletRequest.isUserInRole(role)) {
                                                return;
                                        }
                                }
                                throw new UnauthorizedException();
                        }

                } catch (ExpiredJwtException | NullPointerException e) {
                        throw new UnauthorizedException();
                }
        }

        public static Cookie getCookie(String cookieName, HttpServletRequest request) {

                Cookie c[] = request.getCookies();
                if (c != null) {
                        for (int x = 0; x < c.length; x++) {
                                if (c[x].getName().equals(cookieName)) {
                                        return c[x];
                                }
                        }
                }
                return null;
        }

        private List<ValidationMessage> validateParameters(Object[] params) {

                List constraintViolations = new ArrayList();

                for (Object o : params) {
                        if (o == null || o instanceof ServletContext || o instanceof FileItem || o instanceof ServletRequest || o instanceof ServletResponse) {
                                continue;
                        }

                        Set _constraintViolations = validator.validate(o);
                        for (Object c : _constraintViolations) {
                                ConstraintViolation constraintViolation = ((ConstraintViolation) c);
                                ValidationMessage vm = new ValidationMessage(constraintViolation.getPropertyPath().toString(), constraintViolation.getMessage());
                                constraintViolations.add(vm);
                        }
                }

                return constraintViolations;
        }

        private MimeType determineMimeTypeToReturn(Boolean apiRequest, List<MimeType> accepts, Route route, String extension) throws MimeTypeParseException {
                if (accepts == null) {
                        accepts = new ArrayList<MimeType>();
                }

                if (accepts.size() == 0) {
                        if (apiRequest == true) {
                                return MimeTypes.getMimeTypes().get(".json");
                        } else {
                                return MimeTypes.getMimeTypes().get(".html");
                        }
                }

                if (!StringUtil.isEmpty(extension) && route.getProducesMimeType().size() == 0) {
                        if (MimeTypes.getMimeTypes().containsKey(extension)) {
                                return MimeTypes.getMimeTypes().get(extension);
                        }
                }
                if (apiRequest) {
                        route.setProduces(new String[]{propertiesFile.getString("default.response.contentType", MediaType.JSON)});
                }

                for (MimeType accept : accepts) {
                        MimeType m = isContentTypeAccepted(accept, route.getProducesMimeType());
                        if (m != null) {
                                return m;
                        }
                }

                throw new UnsupportedContentType("");
                // check method
                // check class
                // check default return type
        }

        private MimeType calculateContentType(ControllerResponse controllerResponse, sybrix.easygsp2.routing.Route route, HttpServletResponse response, HttpServletRequest request, Boolean isApiCall) throws MimeTypeParseException {


                // if there's only one, the use it
                if (route.getProduces().length == 1) {
                        return new MimeType(route.getProduces()[0]);
                } else if (route.getProduces().length == 0 && controllerResponse.getIsString()) {
                        return APPLICATION_HTML_TEXT;
                }

                // if you set it manually use it
                if (response.getContentType() != null && response.getContentType().length() > 0) {
                        return new MimeType(response.getContentType());
                }

                MimeType defaultMimeType = null;
                if (isApiCall) {
                        defaultMimeType = new MimeType(propertiesFile.getString("api.default.response.contentType", "application/json"));
                } else {
                        defaultMimeType = new MimeType(propertiesFile.getString("default.response.contentType", "text/html"));
                }

                // if you don't set, figure it out based on what you returned from the method
                if (route.getProduces().length == 0) {
                        if (controllerResponse.getIsJsonSluper()) {
                                return APPLICATION_JSON;
                        } else if (controllerResponse.getIsXMLSlurper()) {
                                return APPLICATION_XML;
                        } else {
                                if (defaultMimeType.getBaseType().equals(APPLICATION_JSON.getBaseType())) {
                                        return APPLICATION_JSON;
                                } else if (defaultMimeType.getBaseType().equals(APPLICATION_XML.getBaseType())) {
                                        return APPLICATION_XML;
                                } else {
                                        return defaultMimeType;
                                }
                        }
                }

                return defaultMimeType;
        }

        private List<MimeType> parseAcceptHeader(String acceptHeader) {

                List<MimeType> accepts = new ArrayList();
                String header = null;
                if (acceptHeader != null) {
                        try {
                                String[] parts = acceptHeader.split(",");
                                for (String s : parts) {
                                        header = s;
                                        accepts.add(new MimeType(header));
                                }
                        } catch (MimeTypeParseException e) {
                                logger.debug("MimeTypeParseException, " + e.getMessage() + ", acceptHeader Param:" + acceptHeader + ", bad header: " + header);
                        }
                }

                return accepts;

        }

        //                private boolean isContentTypeAccepted(){
//
//                String accept = request.getHeader("Accept");
//                String[] acceptsHeader = {};
//
//                if (accept != null) {
//                        acceptsHeader = accept.split(",");
//                }
//
//                // no accepts header
//                if (acceptsHeader == null) {
//                        acceptsHeader = route.getProduces().length == 0 ? defaultContentType.split(",") : route.getProduces()[0].split(",");
//                }
//
//                String[] returns = route.getProduces();
//                String[] returnContentType = null;
//                if (returns.length == 0) {
//                        returnContentType = defaultContentType.split(",");
//                }
//
//
//                MimeType mimeType = findMimeTypeMatch(acceptsHeader, returnContentType);
//
//                if (mimeType != null) {
//                        response.setContentType(mimeType.toString());
//                        return mimeType.toString();
//                } else {
//                        logger.info("unable to determine response content type");
//                        return null;
//                }
//
//        }

        private MimeType isContentTypeAccepted(MimeType sought, List<MimeType> listToSearch) {
                if (listToSearch.size() == 0) {
                        logger.debug("no \"produces\" in @Api annotation, letting it through");
                        return null;
                }
                for (MimeType m : listToSearch) {
                        if (sought.match(m) || m.getPrimaryType().equals("*") || sought.getPrimaryType().equals("*")) {
                                return m;
                        }
                }

                if (sought.getPrimaryType().equals("*") && listToSearch.size() == 0) {
                        return sought;
                }

                return null;
        }

        private boolean isContentTypeAccepted(HttpServletRequest request, MimeType soughtMimeType) {
                try {
                        if (request.getHeader("Accept") == null) {
                                return true;
                        }

                        for (String r : request.getHeader("Accept").split(",")) {
                                MimeType mimeType = new MimeType(r);

                                if (soughtMimeType.match(mimeType) || mimeType.getPrimaryType().equals("*")) {
                                        return true;
                                }
                        }

                        return false;

                } catch (Exception e) {
                        logger.debug(e.getMessage(), e);
                        return false;
                }
        }


        private MimeType findMimeTypeMatch(String[] acceptsHeader, String[] returnContentType) {
                try {
                        if (returnContentType == null) {
                                return null;
                        }
                        for (String r : returnContentType) {
                                MimeType returnMime = new MimeType(r);
                                for (String a : acceptsHeader) {
                                        if (returnMime.match(a)) {
                                                return returnMime;
                                        }
                                }
                        }
                } catch (Exception e) {
                        e.printStackTrace();
                }

                return null;
        }

        private boolean compare(String s1, String s2) {
                return s1.trim().toLowerCase().equals(s2.trim().toLowerCase());
        }

        private FileItem getFileItemByName(List<FileItem> uploads, String parameterName) {
                for (FileItem i : uploads) {
                        if (i.getFieldName().equals(parameterName)) {
                                return i;
                        }
                }

                return null;
        }

        private Type extractGenericType(Parameter p) {
                try {
                        return ((ParameterizedTypeImpl) p.getParameterizedType()).getActualTypeArguments()[0];
                } catch (Exception e) {
                        return null;
                }
        }

        private boolean processControllerResponse(ControllerResponse controllerResponse, HttpServletResponse httpServletResponse, HttpServletRequest httpServletRequest) throws URISyntaxException, IOException, ServletException {
                ThreadBag.get().setTemplateRequest(true);
                Binding binding = ThreadBag.get().getBinding();

                if (binding == null) {
                        binding = new CustomServletBinding(context, httpServletRequest, httpServletResponse);
                }

                if (controllerResponse.getIsString() && controllerResponse.getEntity().toString().endsWith(".jsp") && isServlet) {

                        RequestDispatcher rd = httpServletRequest.getServletContext().getRequestDispatcher("/indexs.jsp");
                        rd.forward(httpServletRequest, httpServletResponse);

                } else if (controllerResponse.getIsString() && controllerResponse.getEntity().toString().endsWith(".jsp") && isServlet == false) {
                        RequestDispatcher rd = httpServletRequest.getServletContext().getRequestDispatcher("/indexs.jsp");
                        rd.forward(httpServletRequest, httpServletResponse);
                        return true;
                } else if (controllerResponse.getIsString() && !controllerResponse.getEntity().toString().endsWith(".jsp")) {

                        URL f = Thread.currentThread().getContextClassLoader().getResource("./../../WEB-INF/views/" + controllerResponse.getViewTemplate());

                        if (f == null) {
                                throw new NoViewTemplateFound("View template  '" + controllerResponse.toString() + "' not found!!!");
                        }

                        ThreadBag.get().setViewFolder(f.getPath());
                        File requestedViewFile = new File(f.toURI());
                        ThreadBag.get().setTemplateFilePath(requestedViewFile.getAbsolutePath());

                        ThreadBag.get().getTemplateInfo().setRequestUri(controllerResponse.toString());
                        ThreadBag.get().getTemplateInfo().setAppFolderClassPathLocation("./../../WEB-INF/views/");
                        ThreadBag.get().getTemplateInfo().setRequestFile(requestedViewFile);

                        try {
                                TemplateWriter templateWriter = new TemplateWriter(groovyClassLoader);
                                templateWriter.process(httpServletResponse, ThreadBag.get().getTemplateInfo(), binding);
                                return false;
                        } catch (HttpException e) {
                                logger.debug(e.getMessage(), e);
                                sendError(e.getStatus(), binding, e.getCause());
                                return false;
                        } catch (Throwable e) {
                                logger.debug(e.getMessage(), e);
                                sendError(500, binding, e.getCause());
                                return false;
                        }
                }

                return true;
        }


        protected void sendError(int httpStatusCode, Binding binding, Throwable e) {
                try {

                        ThreadBag.get().getTemplateInfo().setErrorOccurred(true);
                        try {
                                //  ThreadBag.get().getResponse().sendError(errorCode, e.getMessage());
                        } catch (IllegalStateException il) {

                        }
                        ThreadBag.get().getResponse().setStatus(httpStatusCode);
                        RequestError requestError = ThreadBag.get().getRequestError();
                        requestError.setErrorCode(httpStatusCode);
                        requestError.setScriptPath(ThreadBag.get().getTemplateFilePath());
                        requestError.setErrorMessage(e.getMessage() == null ? "" : e.getMessage());
                        requestError.setException(e, "", "");

                        StackTraceElement stackTraceElement = findErrorInStackTrace(binding, e);
                        String errorSource = highlightErrorSource(stackTraceElement);
                        requestError.setSource(errorSource.toString());

                        String path = ThreadBag.get().getTemplateFilePath();//.replace(appPath, "").replace(appPath2, "");
                        if (stackTraceElement != null) {

                                String lineNumberMessage = "Error occurred in <span class=\"path\">" + path + "</span> @ lineNumber: " + (stackTraceElement.getLineNumber());
                                requestError.setLineNumberMessage(lineNumberMessage);
                                requestError.setLineNumber(stackTraceElement.getLineNumber());
                        } else {
                                requestError.setLineNumberMessage("");
                                if (ThreadBag.get().isTemplateRequest()) {
                                        String lineNumberMessage = "Error occurred in <span class=\"path\">" + path + "</span>";
                                        requestError.setLineNumberMessage(lineNumberMessage);
                                }
                                requestError.setLineNumber(-1);
                        }

                        File errorFile = getErrorFileContents(httpStatusCode);
                        ThreadBag.get().getTemplateInfo().setRequestFile(errorFile);

                        binding.setVariable("exceptionName", e.getClass().getName());
                        binding.setVariable("requestError", requestError);
                        processErrorTemplateRequest(ThreadBag.get().getResponse(), ThreadBag.get().getTemplateInfo(), binding);

                        ThreadBag.get().getResponse().flushBuffer();

                } catch (Throwable e1) {
                        logger.debug(e1.getMessage(), e1);
                        //sendError(errorCode, response, e, stackTraceElement, binding);
                }
        }

        private String highlightErrorSource(StackTraceElement stackTraceElement) {
                StringBuffer lineBuffer = new StringBuffer();

                if (stackTraceElement != null) {
                        try {
                                File f = new File(ThreadBag.get().getTemplateFilePath());
                                BufferedReader br = new BufferedReader(new FileReader(f));
                                String line = null;

                                int lineCt = 1;

                                while ((line = br.readLine()) != null) {
                                        if (lineCt >= stackTraceElement.getLineNumber() - 10 && (lineCt <= stackTraceElement.getLineNumber() + 10)) {
                                                lineBuffer.append("<div class=\"sourceLine\"><div class=\"sourceLineNumber\">").append(lineCt).append("</div>");
                                                lineBuffer.append("<div class=\"sourceCode\">");
                                                lineBuffer.append(line.length() == 0 ? "&nbsp;" : StringUtil.htmlEncode(line).replaceAll(" ", "&nbsp;"));
                                                lineBuffer.append("</div></div>");
                                        }

                                        lineCt++;
                                }

                                br.close();
                        } catch (Exception ex) {
                                logger.debug("Unable to parse source code to display on error page", ex);
                        }
                }

                return lineBuffer.toString();
        }

        private File getErrorFileContents(int errorCode) throws IOException {
                String defaultTemplateExtension = propertiesFile.getString("default.template.extension", "gsp");
                String tmpDir = propertiesFile.getString("easygsp.tmp.dir", System.getProperty("java.io.tmpdir"));

                InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("./errors/error" + errorCode + "." + defaultTemplateExtension);
                File errorFile = new File(tmpDir + File.separator + "errors" + File.separator + "error" + errorCode + "." + defaultTemplateExtension);

                // createFile if it doesn't exist
                if (!errorFile.exists()) {
                        new File(tmpDir + File.separator + "errors").mkdir();
                        FileOutputStream outputStream = new FileOutputStream(errorFile);

                        byte[] buff = new byte[1024];

                        while (true) {
                                int len = inputStream.read(buff, 0, buff.length);
                                if (len < 0)
                                        break;
                                outputStream.write(buff, 0, len);
                        }
                        outputStream.close();
                }

                return errorFile;
        }

        private void processErrorTemplateRequest(HttpServletResponse httpServletResponse, TemplateInfo templateInfo, Binding binding) {
                try {
                        TemplateWriter templateWriter = new TemplateWriter(groovyClassLoader);
                        templateWriter.process(httpServletResponse, templateInfo, binding);

                } catch (Exception e) {
                        e.printStackTrace();
                }
        }


        private static StackTraceElement findErrorInStackTrace(Binding binding, Throwable e) {

                if (ThreadBag.get().isTemplateRequest()) {
                        if (e.getStackTrace() != null && ThreadBag.get().getTemplateInfo() != null) {

                                for (StackTraceElement stackTraceElement : e.getStackTrace()) {
                                        if (stackTraceElement.getFileName() != null) {
                                                if (stackTraceElement.getFileName().startsWith(ThreadBag.get().getTemplateInfo().getUniqueTemplateScriptName())) {
                                                        return stackTraceElement;
                                                }
                                        }
                                }
                        }
                } else {
//                        String appPath = RequestThreadInfo.get().getApplication().getAppPath();
//                        String currentFile = ThreadBag.get().getTemplateFilePath().substring(appPath.length() + 1);
//
//                        for (StackTraceElement stackTraceElement : e.getStackTrace()) {
//                                if (stackTraceElement.getFileName() != null) {
//                                        if (stackTraceElement.getFileName().endsWith(currentFile)) {
//                                                return stackTraceElement;
//                                        }
//                                }
//                        }
                }

                return null;
        }

        private void loadPropertiesIntoContext(ServletContext app, PropertiesFile propertiesFile) {
                for (String s : propertiesFile.stringPropertyNames()) {
                        app.setAttribute(s, propertiesFile.get(s));

                        if (s.matches("ignore\\.url\\.pattern\\.\\d+$")) {
                                ignoredUrlPatterns.add(Pattern.compile(propertiesFile.getString(s)));
                        }
                }
        }

        private void loadUnannotatedClasses(PropertiesFile propertiesFile, String packageName) {
                logger.debug("loading unannotated controllers classes");
                String defaultPackageName = propertiesFile.getString(packageName);

                Reflections reflections = new Reflections(defaultPackageName, new TypeElementsScanner(), new SubTypesScanner(false));
                Set<String> types = reflections.getAllTypes();

                for (String cls : types) {
                        if (classesWithApiAnnotation.contains(cls)) {
                                //    continue;
                        }

                        if (cls.endsWith("Controller")) {
                                logger.debug("parsing class: " + cls);
                                StringBuffer sb = new StringBuffer();

                                String _api = cls.substring(defaultPackageName.length() + 1, cls.length() - "Controller".length());
                                for (String s : _api.split("\\.")) {
                                        sb.append(s.substring(0, 1).toLowerCase());
                                        sb.append(s.substring(1, s.length()));
                                        sb.append("/");
                                }
                                String api = sb.substring(0, sb.length() - 1);
                                String pattern = "/" + api;

                                Class clazz = parseClassName(cls);

                                String[] classMethods = {"list", "index", "get", "put", "post", "delete"};

                                if (clazz != null) {
                                        String mediaType[] = {propertiesFile.getString("default.response.contentType", MediaType.HTML)};

                                        String[] accepts = mediaType;
                                        String[] returns = determineDefaultReturnType(clazz);
                                        boolean isApiController = isApiController(clazz);

                                        Secured securedAnno = (Secured) clazz.getAnnotation(Secured.class);
                                        String[] classRoles = securedAnno == null ? new String[]{} : securedAnno.value();

                                        for (String classMethod : classMethods) {
                                                String _pattern = pattern;
                                                String _method = classMethod;

                                                if (classMethod.equalsIgnoreCase("list")) {
                                                        if (isApiController) {
                                                                _method = "list";
                                                        } else {
                                                                _method = "index";
                                                        }
                                                }

                                                if (classMethod.equalsIgnoreCase("DELETE") || classMethod.equalsIgnoreCase("GET")) {
                                                        _pattern = pattern + "/{<\\d+$>id}";
                                                }

                                                String httpMethod = (classMethod.equalsIgnoreCase("list") || classMethod.equalsIgnoreCase("index")) ? "GET" : classMethod.toUpperCase();

                                                if (!Routes.contains(_pattern, httpMethod)) {
                                                        MethodAndRole method = extractMethod(clazz, _method);
                                                        if (method.getSecure() == false) {
                                                                method.setSecure(securedAnno != null);
                                                        }

                                                        if (method.getMethod() != null) {
                                                                String[] roles = combine(method.getRoles(), classRoles);

                                                                Routes.add(method.getMethod(), _pattern, httpMethod, new Class[]{}, roles, accepts, returns, method.getSecure());
                                                                //route.setSecure();
                                                        }
                                                }
                                        }

                                }
                        } else {
                                logger.warn("class: " + cls + " doesn't end with 'Controller', skipping as controllers");
                        }
                }
        }


        private boolean isApiController(Class clazz) {

                String apiControllerPackage = propertiesFile.getString("api.controllers.package", "");

                if (clazz.getPackage().getName().equals(apiControllerPackage)) {
                        return true;
                }

                return false;
        }

        private String[] determineDefaultReturnType(Class clazz) {
                Content content = null;
                try {
                        content = (Content) clazz.getAnnotation(Content.class);
                        if (content != null) {
                                String returnType = content.returns();

                                if (returnType != null) {
                                        return new String[]{returnType};
                                }
                        }
                } catch (Exception e) {
                        logger.debug("unable to get Content annotation form class " + clazz.getName());
                }

                String controllerPackage = propertiesFile.getString("controllers.package", "");
                String apiControllerPackage = propertiesFile.getString("api.controllers.package", "");

                if (clazz.getPackage().getName().equals(controllerPackage)) {
                        return new String[]{propertiesFile.getString("default.response.contentType", MediaType.JSON)};
                } else if (clazz.getPackage().getName().equals(apiControllerPackage)) {
                        return new String[]{propertiesFile.getString("api.default.response.contentType", MediaType.HTML)};
                }

                return new String[]{};
        }

        private Class parseClassName(String cls) {
                try {
                        return Class.forName(cls);
                } catch (ClassNotFoundException e) {
                        return null;
                }
        }

        private MethodAndRole extractMethod(Class cls, String methodName) {
                MethodAndRole methodAndRole = new MethodAndRole();

                try {
                        Method foundMethod = null;
                        for (Method m : cls.getDeclaredMethods()) {
                                if (m.getName().equals(methodName)) {
                                        if (foundMethod == null) {
                                                foundMethod = m;
                                        } else {
                                                logger.error("method " + methodName + "() found in class: " + cls.getName() + ", not allowed in when using routing by naming convention only.  Use @api annotation instead.");
                                                break;
                                        }
                                }
                        }

                        if (foundMethod == null) {
                                return methodAndRole;
                        }

                        Method m = foundMethod;
                        methodAndRole.setMethod(m);

                        Annotation annotation = m.getDeclaredAnnotation(Secured.class);
                        if (annotation != null) {
                                methodAndRole.setSecure(true);
                                String[] roles = ((Secured) annotation).value();
                                methodAndRole.setRoles(roles);
                        }

                } catch (Exception e) {
                        logger.debug(methodName.toLowerCase() + "() method not found in class " + cls.getName());
                        return methodAndRole;
                }

                return methodAndRole;
        }

        private void loadApiMethods(PropertiesFile propertiesFile) {
                logger.debug("loading annotated controllers methods...");
                Reflections reflections = new Reflections("", new MethodAnnotationsScanner(), new SubTypesScanner());
                Set<Method> methods = reflections.getMethodsAnnotatedWith(Api.class);

                for (Method m : methods) {

                        Api classAnno = extractClassAnnotation(m.getDeclaringClass().getDeclaredAnnotations());
                        classesWithApiAnnotation.add(m.getDeclaringClass().getName());

                        Api methodAnno = m.getDeclaredAnnotation(Api.class);

                        Secured securedClassAnno = (Secured) m.getDeclaringClass().getAnnotation(Secured.class);
                        String[] classRolesFromSecureAnnotation = securedClassAnno == null ? new String[]{} : securedClassAnno.value();

                        Secured securedMethodAnno = m.getDeclaredAnnotation(Secured.class);
                        String[] methodRolesFromSecureAnnotation = securedMethodAnno == null ? new String[]{} : securedMethodAnno.value();

                        boolean secured = (securedMethodAnno != null || securedClassAnno != null);

                        if (methodAnno.url().length > 0) {
                                logger.debug("loading class: " + m.getDeclaringClass().getName() + ", method: " + m.getName() + "(), url: " + methodAnno.url());

                                for (String classPattern : classAnno.url()) {
                                        for (String _pattern : methodAnno.url()) {

                                                String pattern = classPattern + _pattern;

                                                String[] httpMethods = combine(methodAnno.method(), classAnno.method());
                                                for (String httpMethod : httpMethods) {
                                                        if (httpMethod.equals("*")) {
                                                                httpMethods = sybrix.easygsp2.routing.Route.HTTP_METHODS;
                                                                break;
                                                        }
                                                }

                                                for (String httpMethod : httpMethods) {
                                                        String[] securedRoles = combine(classRolesFromSecureAnnotation, methodRolesFromSecureAnnotation);
                                                        String[] roles = combine(methodAnno.roles(), securedRoles, classAnno.roles());

                                                        String[] accepts = methodAnno.accepts() != null ? classAnno.accepts() : methodAnno.accepts();
                                                        String[] returns = methodAnno.contentType() != null ? classAnno.contentType() : methodAnno.contentType();
                                                        if (returns.length == 0) {
                                                                returns = determineDefaultReturnType(m.getDeclaringClass());
                                                        }

                                                        Routes.add(m, pattern, httpMethod, null, roles, accepts, returns, secured);
                                                }
                                        }
                                }

                        } else {
                                logger.info("no patterns found for method " + m);
                        }
                }
        }

        private Api extractClassAnnotation(Annotation[] declaredAnnotations) {

                for (Annotation declaredAnnotation : declaredAnnotations) {
                        if (declaredAnnotation instanceof Api) {
                                return (Api) declaredAnnotation;
                        }
                }

                return _dummy.class.getDeclaredAnnotation(Api.class);
        }


        private Set<String> toList(String[] methods) {
                Set<String> l = new HashSet<String>();
                if (methods != null) {
                        for (String m : methods) {
                                l.add(m);
                        }
                }
                return l;
        }

        private void loadSerializers(PropertiesFile propertiesFile) {
                String jsonSerializer = null;
                String xmlSerializer = null;

                try {
                        jsonSerializer = propertiesFile.getString("json.serializer.class", JSON_SERIALIZER_CLASS);
                        logger.debug("JsonSerializer: " + jsonSerializer);
                        jsonSerializerInstance = (Serializer) Class.forName(jsonSerializer, false, groovyClassLoader).newInstance();
                } catch (Exception e) {
                        if (JSON_SERIALIZER_CLASS.equalsIgnoreCase(jsonSerializer)) {
                                logger.error("Unable to instantiate default json serializer: " + JSON_SERIALIZER_CLASS);
                        } else {
                                logger.warn("error occurred instantiating jsonSerializer: " + jsonSerializer + ", attempting to use default: " + JSON_SERIALIZER_CLASS);

                                try {
                                        jsonSerializerInstance = (Serializer) Class.forName(jsonSerializer, false, groovyClassLoader).newInstance();
                                } catch (Exception e1) {
                                        logger.error("Unable to instantiate default json serializer: " + JSON_SERIALIZER_CLASS);
                                }
                        }
                }

                try {
                        xmlSerializer = propertiesFile.getString("xml.serializer.class", XML_SERIALIZER_CLASS);
                        logger.debug("XmlSerializer: " + xmlSerializer);
                        xmlSerializerInstance = (XmlSerializer) Class.forName(xmlSerializer, false, groovyClassLoader).newInstance();
                } catch (Exception e) {
                        logger.warn("error occurred instantiating xmlSerializer: " + xmlSerializer + ", attempting to use default: " + XML_SERIALIZER_CLASS);

                        try {
                                xmlSerializerInstance = (XmlSerializer) Class.forName(xmlSerializer, false, groovyClassLoader).newInstance();
                        } catch (Exception e1) {
                                logger.error("Unable to instantiate default xml serializer: " + XML_SERIALIZER_CLASS);
                        }
                }
        }

        private Object invokeControllerAction(GroovyObject controller, Method m, Object[] params, sybrix.easygsp2.routing.Route route) throws HttpException, InvokeControllerActionException {
                try {

                        return m.invoke(controller, params);
                } catch (Exception e) {
                        if (e.getCause() instanceof HttpException) {
                                throw (HttpException) e.getCause();

                        } else {
                                if (route.isDuplicate()) {
                                        logger.error("url pattern: " + route.getPath() + " exists on multiple methods.");
                                }
                                logger.error(e.getMessage(), e);
                                throw new InvokeControllerActionException("unable to invoke method " + m.getDeclaringClass().getName() + "." + m.getName() + extractParameterTypes(m.getParameters()) + ",  attempted: " + m.getName() + extractParameterTypes(params), e);
                        }
                }
        }

        public Object populateBean(Object obj, HttpServletRequest request) {

                try {
                        Object value = null;
                        String property = null;

                        BeanInfo sourceInfo = Introspector.getBeanInfo(obj.getClass());
                        PropertyDescriptor[] sourceDescriptors = sourceInfo.getPropertyDescriptors();

                        for (int x = 0; x < sourceDescriptors.length; x++) {
                                try {

                                        if (sourceDescriptors[x].getReadMethod() != null && sourceDescriptors[x].getWriteMethod() != null) {

                                                property = sourceDescriptors[x].getName();
                                                Class params[] = sourceDescriptors[x].getWriteMethod().getParameterTypes();

                                                String val = request.getParameter(property);
                                                if (val != null) {
                                                        value = castToType(val, Class.forName(params[0].getName()));

                                                        if (obj instanceof GroovyObject) {
                                                                MetaClass metaClass = InvokerHelper.getMetaClass(obj);
                                                                metaClass.setProperty(obj, sourceDescriptors[x].getName(), value);
                                                        } else {
                                                                sourceDescriptors[x].getWriteMethod().invoke(obj, new Object[]{value});
                                                        }
                                                }
                                        }
                                } catch (Exception e) {
                                        logger.warn("BeanUtil.populate failed. method=" + property + ", value=" + value, e);
                                }
                        }

                } catch (Exception e) {
                        logger.error("Error occurred populating object from request", e);
                }
                return obj;
        }


        private Object castToType(String valFromRequestParameter, Class clazz) {
                try {
                        if (clazz == Object.class) {
                                return valFromRequestParameter;
                        } else if (clazz.getName().equals("char")) {
                                return new Character(valFromRequestParameter.toCharArray()[0]);
                        } else if (clazz.getName().equals("int")) {
                                return new Integer(valFromRequestParameter);
                        } else if (clazz.getName().equals("long") || clazz.getName().equals("java.lang.Long")) {
                                return new Long(valFromRequestParameter);
                        } else if (clazz.getName().equals("double")) {
                                return new Double(valFromRequestParameter);
                        } else if (clazz.getName().equals("float")) {
                                return new Float(valFromRequestParameter);
                        } else if (clazz.getName().equals("short")) {
                                return new Short(valFromRequestParameter);
                        } else if (clazz.getName().equals("boolean")) {
                                return new Boolean(valFromRequestParameter);
                        }

                        Constructor c = clazz.getConstructor(String.class);
                        return c.newInstance(valFromRequestParameter);

                } catch (NoSuchMethodException e) {
                        e.printStackTrace();
                } catch (InvocationTargetException e) {
                        e.printStackTrace();
                } catch (InstantiationException e) {
                        e.printStackTrace();
                } catch (IllegalAccessException e) {
                        e.printStackTrace();
                }
                return null;
        }

        private String extractParameterTypes(Parameter[] parameters) {
                StringBuffer stringBuffer = new StringBuffer();
                stringBuffer.append("(");
                for (Parameter p : parameters) {
                        stringBuffer.append(p.getType().getName()).append(",");
                }

                if (stringBuffer.length() > 1) {
                        stringBuffer.setLength(stringBuffer.length() - 1);
                }

                stringBuffer.append(")");
                return stringBuffer.toString();
        }

        private String extractParameterTypes(Object[] parameters) {
                StringBuffer stringBuffer = new StringBuffer();
                stringBuffer.append("(");
                for (Object p : parameters) {
                        if (p == null) {
                                stringBuffer.append("null").append(",");
                        } else {
                                stringBuffer.append(p.getClass().getName()).append("=").append(p).append(",");
                        }
                }

                if (stringBuffer.length() > 1) {
                        stringBuffer.setLength(stringBuffer.length() - 1);
                }

                stringBuffer.append(")");
                return stringBuffer.toString();
        }

        private void loadRoutes() throws IOException, URISyntaxException, ClassNotFoundException {

                final Class c = groovyClassLoader.parseClass(new File(this.getClass().getClassLoader().getResource("./routes.groovy").toURI()));

                Closure closure = new Closure(groovyClassLoader) {

                        public Object call() {
                                try {
                                        Binding binding = new Binding();
                                        binding.setVariable("rroutes", routes);
                                        binding.setVariable("groovyClassLoader", groovyClassLoader);

                                        Script routesScript = InvokerHelper.createScript(c, binding);
                                        routesScript.invokeMethod("run", new Object[]{});
                                } catch (Exception e) {
                                        logger.error("error in routes.groovy", e);
                                }

                                return null;
                        }
                };
                GroovyCategorySupport.use(RoutingCategory.class, closure);
        }


        public static sybrix.easygsp2.routing.Route findRoute(String uri, String method) {
                for (sybrix.easygsp2.routing.Route r : routes.values()) {
                        if (r.matches(uri, method)) {
                                logger.debug("matching route found! " + r.toString());
                                return r;
                        }
                }

                logger.debug("no matching route found for " + uri);

                return null;
        }


        private static boolean isJson(String contentType) {

                return contentType == null ? false : contentType.contains(APPLICATION_JSON.getBaseType());
        }

        private static boolean isXML(String contentType) {
                return contentType == null ? false : contentType.contains(APPLICATION_XML.getBaseType());
        }

        private static boolean isFormUrlEncoded(String contentType) {
                return contentType.contains("application/x-www-form-urlencoded");
        }

        private static boolean isMultiPart(String contentType) {
                if (contentType == null)
                        return false;

                return contentType.startsWith("multipart/");
        }

        private String[] extractControllerAndActionName(String contextName, String uri) {
                String[] parts = uri.split("/");
                StringBuffer controller = new StringBuffer();
                String action = "index";

                if (parts.length == 0) {
                        controller.append("Default");
                } else {
                        if (contextName.equals(parts[0])) {
                                controller.append(parts[1]);
                                if (parts.length > 2) {
                                        action = parts[2];
                                }
                        } else {
                                controller.append(parts[0]);
                                if (parts.length > 1) {
                                        action = parts[1];
                                }
                        }
                }
                controller.append("Controller");
                controller.replace(0, 1, String.valueOf(controller.charAt(0)).toUpperCase());

                return new String[]{controller.toString(), action};
        }

        //taken from playframework
        public List<String> lookupParameterNames(Method method, ClassLoader classLoader) {
                try {
                        List<String> parameters = new ArrayList<String>();

                        ClassPool classPool = new ClassPool();
                        classPool.appendSystemPath();
                        classPool.appendClassPath(new LoaderClassPath(this.getClass().getClassLoader()));
                        classPool.appendClassPath("/Users/dsmith/Temp/groovy");

                        CtClass ctClass = classPool.get(method.getDeclaringClass().getName());
                        CtClass[] cc = new CtClass[method.getParameterTypes().length];
                        for (int i = 0; i < method.getParameterTypes().length; i++) {
                                cc[i] = classPool.get(method.getParameterTypes()[i].getName());
                        }
                        CtMethod ctMethod = ctClass.getDeclaredMethod(method.getName(), cc);

                        // Signatures names
                        CodeAttribute codeAttribute = (CodeAttribute) ctMethod.getMethodInfo().getAttribute("Code");
                        if (codeAttribute != null) {
                                LocalVariableAttribute localVariableAttribute = (LocalVariableAttribute) codeAttribute.getAttribute("LocalVariableTable");
                                if (localVariableAttribute != null && localVariableAttribute.tableLength() >= ctMethod.getParameterTypes().length) {
                                        for (int i = 0; i < localVariableAttribute.tableLength(); i++) {
                                                String name = localVariableAttribute.getConstPool().getUtf8Info(localVariableAttribute.nameIndex(i));
                                                if (!name.equals("this") && !parameters.contains(name)) {
                                                        parameters.add(name);
                                                }
                                        }
                                }
                        }

                        return parameters;
                } catch (Exception e) {
                        throw new RuntimeException(e);
                }
        }

        public static File toFile(String path) throws URISyntaxException {
                URL f = Thread.currentThread().getContextClassLoader().getResource(path);
                return new File(f.toURI());
        }

        @Api(url = "", method = "", roles = "")
        private static class _dummy {

        }

        private static MimeType parseMimeType(String s) {
                try {
                        return new MimeType(s);
                } catch (MimeTypeParseException e) {
                        return null;
                }
        }

        public Validator getValidator() {
                return validator;
        }

        public void setValidator(Validator validator) {
                this.validator = validator;
        }

        public PropertiesFile getPropertiesFile() {
                return propertiesFile;
        }

        public EmailService getEmailService() {
                return emailService;
        }

        public AuthenticationService getAuthenticationService() {
                return authenticationService;
        }

        public Map<String, Object> getDynamicProperties() {
                return dynamicProperties;
        }

}
<file_sep>rootProject.name = 'easygsp2'
<file_sep>package sybrix.easygsp2.framework;

import groovy.lang.Binding;
import groovy.lang.GroovyClassLoader;
import groovy.sql.Sql;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import sybrix.easygsp2.routing.Route;
import sybrix.easygsp2.security.JwtUtil;
import sybrix.easygsp2.security.UserPrincipal;
import sybrix.easygsp2.templates.RequestError;
import sybrix.easygsp2.templates.TemplateInfo;

import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

public class ThreadVariables {

        private ServletContext app;
        private HttpServletRequest request;
        private HttpServletResponse response;
        private TemplateInfo templateInfo;
        private String viewFolder;
        private GroovyClassLoader groovyClassLoader;
        private Binding binding;
        private Map<String, Route> routes;
        private Sql sql;
        private RequestError requestError;
        private boolean isTemplateRequest;
        private String templateFilePath;
        private UserPrincipal userPrincipal;
        private Jws<Claims> claims;

        public ThreadVariables(ServletContext app) {
                this.app = app;
                this.requestError = new RequestError();
        }

        public ThreadVariables(ServletContext app, ServletRequest request, ServletResponse response, Map<String,Route> routes, Sql sql, TemplateInfo templateInfo, GroovyClassLoader groovyClassLoader) {
                this.app = app;
                this.request = (HttpServletRequest)request;
                this.response = (HttpServletResponse)response;
                this.templateInfo = templateInfo;
                this.binding = binding;
                this.groovyClassLoader = groovyClassLoader;
                this.routes = routes;
                this.sql = sql;
                this.requestError = new RequestError();
                try {
                        this.claims = JwtUtil.parseJwtClaims((HttpServletRequest) request);
                }catch (Exception e){
                }
        }

        public Jws<Claims> getClaims() {
                return claims;
        }

        public HttpServletRequest getRequest() {
                return request;
        }

        public HttpServletResponse getResponse() {
                return response;
        }

        public String getViewFolder() {
                return viewFolder;
        }

        public void setViewFolder(String viewFolder) {
                this.viewFolder = viewFolder;
        }

        public Binding getBinding() {
                return binding;

        }

        public TemplateInfo getTemplateInfo() {
                if (templateInfo == null){
                        templateInfo = new TemplateInfo();
                }

                return templateInfo;
        }

        public GroovyClassLoader getGroovyClassLoader() {
                return groovyClassLoader;
        }

        public ServletContext getApp() {
                return app;
        }

        public Map<String, Route> getRoutes() {
                return routes;
        }

        public Sql getSql() {
                return sql;
        }

        public void setSql(Sql sql){
                this.sql = sql;
        }

        public RequestError getRequestError() {
                return requestError;
        }

        public boolean isTemplateRequest() {
                return isTemplateRequest;
        }

        public void setTemplateRequest(boolean templateRequest) {
                isTemplateRequest = templateRequest;
        }

        public String getTemplateFilePath() {
                return templateFilePath;
        }

        public void setTemplateFilePath(String templateFilePath) {
                this.templateFilePath = templateFilePath;
        }

        public UserPrincipal getUserPrincipal() {
                return userPrincipal;
        }

        public void setUserPrincipal(UserPrincipal userPrincipal) {
                this.userPrincipal = userPrincipal;
        }
}

<file_sep>package sybrix.easygsp2.framework;


public class ThreadBag {

        private static final ThreadLocal<ThreadVariables> _id = new ThreadLocal<ThreadVariables>() {

                protected ThreadVariables initialValue() {
                        return null;
                }
        };

        public static ThreadVariables get() {
                return _id.get();
        }

        public static void set(ThreadVariables id) {
                _id.set(id);
        }

        public static void remove() {
                try {
                        if (_id.get().getSql() != null) {
                                _id.get().getSql().close();
                        }
                } catch (Throwable e) {
                        //do nothing
                }

                try {
                        _id.set(null);
                        _id.remove();
                } catch (Throwable e) {
                        //do nothing
                }
        }
}
<file_sep># easygsp-framework

Because I really hate Spring and really like Groovy
It's a great product but Roo and Boot both just added  more annotations and confusion.

Spring supports groovy so you can write a controller that looks almost exactly like this Spring, but you can't escape Spring's annotations.  It's so many...so so many.  


####How is it different?
Quite honestly, from a dev's perspective, it's not that different.  EasyGsp is designed for use with Groovy. 
and has smaller ambitions than Spring. Spring inspired this framework but from this point on, let's stop talking about Spring.

As of now, EasyGsp supports 2 annotations.  @Api and @Secured
I'm sure more will come but as of now that's it.  

Here's a controller in EasyGsp:  
```groovy
def ProfileController {
    def get(id){
        def db = SqlConnection(...)
        // do some database stuff
        new Profile(username:db.username, lastname:db.lastname)
    }
    
    def post(ProfileRequest profileRequest){
            
    }
    
    def post(ProfileRequest profileRequest){
          "forward:/api/images?q=a"   
    }
    
    def post(ProfileRequest profileRequest){
            new ControllerResponse(forwarded:true, url:'/url/image')   
    }
}
```





<file_sep>plugins {
        id 'groovy'
	    id 'maven-publish'
        id 'java-library'
}

group = 'sybrix-easygsp2'

version = '1.0.0-SNAPSHOT'

repositories {
        mavenCentral()
        mavenLocal()
}

publishing {
        publications {
                myLibrary(MavenPublication) {
                        from components.java
                }
        }
}

java {
        //withJavadocJar()
        withSourcesJar()
}

dependencies {
        compileOnly 'org.codehaus.groovy:groovy-all:3.0.5'

        api 'com.sun.mail:javax.mail:1.5.5'

        api 'com.squareup.okhttp3:okhttp:4.0.1'
        api 'com.squareup.okhttp3:logging-interceptor:4.0.1'

        compileOnly 'org.codehaus.groovy:groovy-all:3.0.5'
        testImplementation 'org.codehaus.groovy:groovy-all:3.0.5'


        api 'commons-fileupload:commons-fileupload:1.3.2'
        api 'net.sourceforge.jregex:jregex:1.2_01'
        api 'org.javassist:javassist:3.20.0-GA'
        api 'org.reflections:reflections:0.9.10'
        api 'commons-codec:commons-codec:1.9'

        api 'com.fasterxml.jackson.core:jackson-core:2.8.0'
        api 'com.fasterxml.jackson.core:jackson-annotations:2.8.0'
        api 'com.fasterxml.jackson.core:jackson-databind:2.8.0'
        api 'io.jsonwebtoken:jjwt:0.9.0'

        api 'org.hibernate.validator:hibernate-validator:6.0.7.Final'

        api 'org.mindrot:jbcrypt:0.4'

        api 'org.slf4j:slf4j-ext:1.8.0-alpha2'

        compileOnly 'javax.servlet:javax.servlet-api:3.1.0'
        compileOnly group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.10.0'
        compileOnly group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.10.0'
        compileOnly group: 'javax.persistence', name: 'persistence-api', version: '1.0.2'

//        api 'sybrix:easygsp-util:1.0.0'
}


apply plugin: 'idea'
<file_sep>package sybrix.easygsp2.util;

import java.math.BigDecimal;


public class NumberUtil {

        public static Double toDbl(Object val, Double defaultVal) {
                if (val == null) {
                        return defaultVal;
                }
                try {
                        return toDbl(val);
                } catch (Exception e) {
                        return defaultVal;
                }

        }

        public static Double toDbl(Object val) {
                if (val == null || StringUtil.isEmpty(val.toString())) {
                        return null;
                }

                return Double.parseDouble(val.toString());

        }

        public static BigDecimal toBD(Object val) {
                if (val == null || StringUtil.isEmpty(val.toString())) {
                        return null;
                }

                return new BigDecimal(val.toString());

        }

        public static BigDecimal toBD(Object val, BigDecimal defaultVal) {
                if (val == null) {
                        return defaultVal;
                }

                try {
                        return toBD(val);
                } catch (Exception e) {
                        return defaultVal;
                }
        }


        public static Integer toInt(Object val, Integer defaultVal) {
                if (val == null) {
                        return defaultVal;
                }

                try {
                        return toInt(val);
                } catch (Exception e) {
                        return defaultVal;
                }
        }

        public static Integer toInt(Object val) {
                if (val == null || StringUtil.isEmpty(val.toString())) {
                        return null;
                }
                return Integer.parseInt(val.toString());
        }

        public static Long toLong(Object val, Long defaultValue) {
                if (val == null) {
                        return defaultValue;
                }

                try {
                        return toLong(val);
                } catch (Exception e) {
                        return defaultValue;
                }
        }

        public static Long toLong(Object val) {

                if (val == null || StringUtil.isEmpty(val.toString())) {
                        return null;
                }

                if (val instanceof Number) {
                        return ((Number) val).longValue();
                } else {
                        return Long.parseLong(val.toString());
                }
        }

        public static BigDecimal round(BigDecimal d, Integer scale) {
                return d.setScale(scale, BigDecimal.ROUND_HALF_UP);
        }



}
<file_sep>package sybrix.easygsp2.util;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by dsmith on 9/4/16.
 */
public class CollectionsUtil {

        public static <T> List<T> toList(T[] methods) {
                List<T> l = new ArrayList<T>();
                if (methods != null) {
                        for (T m : methods) {
                                l.add(m);
                        }
                }
                return l;
        }

        public static <T> T[] toArray(List<T> list) {
                T[] ary = (T[]) new Object[list.size()];
                list.toArray(ary);

                return ary;
        }

        public static <T> T[] add(T[] ary1, T[] ary2) {
                int i = ary1 != null ? ary1.length : 0;
                i = i + (ary2 != null ? ary2.length : 0);

                T[] ary = (T[])new Object[i];

                if (ary1!=null){
                        for(int x=0;x<ary1.length;x++){
                                ary[x] = ary1[x];
                        }
                }

                if (ary2!=null){
                        for(int x=0;x<ary2.length;x++){
                                ary[x] = ary2[x];
                        }
                }

                return ary;
        }
}
<file_sep>package sybrix.easygsp2.exceptions;


public class NoViewTemplateFound extends RuntimeException {
        public NoViewTemplateFound(String msg) {
                super(msg);
        }
}
