<commit_before>/*
 * Copyright (c) 2013-2014 the original author or authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.qiweb.runtime.routes;

import java.lang.reflect.InvocationHandler;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Collectors;
import javassist.util.proxy.MethodHandler;
import javassist.util.proxy.Proxy;
import javassist.util.proxy.ProxyFactory;
import org.qiweb.api.Application;
import org.qiweb.api.exceptions.QiWebException;
import org.qiweb.api.exceptions.RouteNotFoundException;
import org.qiweb.api.http.Method;
import org.qiweb.api.routes.ControllerCallRecorder;
import org.qiweb.api.routes.ReverseRoute;
import org.qiweb.api.routes.ReverseRoutes;
import org.qiweb.api.routes.Route;
import org.qiweb.runtime.dev.DevShellRoutesProvider;

import static org.qiweb.api.Mode.DEV;
import static org.qiweb.api.exceptions.IllegalArguments.ensureNotNull;
import static org.qiweb.api.http.Method.CONNECT;
import static org.qiweb.api.http.Method.DELETE;
import static org.qiweb.api.http.Method.GET;
import static org.qiweb.api.http.Method.HEAD;
import static org.qiweb.api.http.Method.OPTIONS;
import static org.qiweb.api.http.Method.PATCH;
import static org.qiweb.api.http.Method.POST;
import static org.qiweb.api.http.Method.PUT;
import static org.qiweb.api.http.Method.TRACE;

public class ReverseRoutesInstance
    implements ReverseRoutes
{
    private final Application application;

    public ReverseRoutesInstance( Application application )
    {
        this.application = application;
    }

    @Override
    public <T> ReverseRoute options( Class<T> controllerType, ControllerCallRecorder<T> callRecorder )
    {
        return of( OPTIONS, controllerType, callRecorder );
    }

    @Override
    public <T> ReverseRoute get( Class<T> controllerType, ControllerCallRecorder<T> callRecorder )
    {
        return of( GET, controllerType, callRecorder );
    }

    @Override
    public <T> ReverseRoute head( Class<T> controllerType, ControllerCallRecorder<T> callRecorder )
    {
        return of( HEAD, controllerType, callRecorder );
    }

    @Override
    public <T> ReverseRoute post( Class<T> controllerType, ControllerCallRecorder<T> callRecorder )
    {
        return of( POST, controllerType, callRecorder );
    }

    @Override
    public <T> ReverseRoute put( Class<T> controllerType, ControllerCallRecorder<T> callRecorder )
    {
        return of( PUT, controllerType, callRecorder );
    }

    @Override
    public <T> ReverseRoute delete( Class<T> controllerType, ControllerCallRecorder<T> callRecorder )
    {
        return of( DELETE, controllerType, callRecorder );
    }

    @Override
    public <T> ReverseRoute trace( Class<T> controllerType, ControllerCallRecorder<T> callRecorder )
    {
        return of( TRACE, controllerType, callRecorder );
    }

    @Override
    public <T> ReverseRoute patch( Class<T> controllerType, ControllerCallRecorder<T> callRecorder )
    {
        return of( PATCH, controllerType, callRecorder );
    }

    @Override
    public <T> ReverseRoute connect( Class<T> controllerType, ControllerCallRecorder<T> callRecorder )
    {
        return of( CONNECT, controllerType, callRecorder );
    }

    @Override
    public <T> ReverseRoute of( String httpMethod, Class<T> controllerType, ControllerCallRecorder<T> callRecorder )
    {
        return of( Method.valueOf( httpMethod ), controllerType, callRecorder );
    }

    @Override
    public <T> ReverseRoute of( Method httpMethod, Class<T> controllerType, ControllerCallRecorder<T> callRecorder )
    {
        ensureNotNull( "HTTP method", httpMethod );
        ensureNotNull( "Controller Type", controllerType );
        ensureNotNull( "Call Recorder", callRecorder );

        // Prepare recording proxy
        T controllerProxy;
        ControllerCallHandler handler = new ControllerCallHandler();
        if( controllerType.isInterface() )
        {
            Class<?>[] interfaces = new Class<?>[ 1 ];
            interfaces[0] = controllerType;
            controllerProxy = (T) java.lang.reflect.Proxy.newProxyInstance(
                Thread.currentThread().getContextClassLoader(),
                interfaces,
                handler
            );
        }
        else
        {
            try
            {
                ProxyFactory proxyFactory = new ProxyFactory();
                proxyFactory.setSuperclass( controllerType );
                controllerProxy = (T) proxyFactory.createClass().newInstance();
                ( (Proxy) controllerProxy ).setHandler( handler );
            }
            catch( InstantiationException | IllegalAccessException ex )
            {
                throw new QiWebException( "Unable to reverse route", ex );
            }
        }

        // Record Controller Method Call
        try
        {
            callRecorder.recordCall( controllerProxy );
        }
        catch( Exception ex )
        {
            throw new QiWebException(
                "Error while recording Controller call for Reverse routing: " + ex.getMessage(),
                ex
            );
        }

        // Find Route
        for( Route route : application.routes() )
        {
            if( application.mode() == DEV && DevShellRoutesProvider.isDevShell( route ) )
            {
                // Skip DevShell Routes
                continue;
            }
            if( route.httpMethod().equals( httpMethod )
                && route.controllerType().getName().equals( controllerType.getName() )
                && route.controllerMethodName().equals( handler.methodName )
                && Arrays.equals( route.controllerMethod().getParameterTypes(), handler.paramsTypes ) )
            {
                // Found!
                RouteInstance instance = (RouteInstance) route;
                Map<String, Object> parameters = new LinkedHashMap<>();
                int idx = 0;
                for( String paramName : instance.controllerParams().names() )
                {
                    parameters.put( paramName, handler.paramsValues[idx] );
                    idx++;
                }
                String unboundPath = route.unbindParameters( application.parameterBinders(), parameters );
                return new ReverseRouteInstance( httpMethod, unboundPath, application.defaultCharset() );
            }
        }
        // No matching Route Found
        throw new RouteNotFoundException(
            httpMethod,
            controllerType + "." + handler.methodName
            + "(" + Arrays.toString( handler.paramsTypes ) + ")"
        );
    }
<commit_msg>Runtime, minor: remove useless dev routes filter, #71<commit_after>/*
 * Copyright (c) 2013-2014 the original author or authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.qiweb.runtime.routes;

import java.lang.reflect.InvocationHandler;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Collectors;
import javassist.util.proxy.MethodHandler;
import javassist.util.proxy.Proxy;
import javassist.util.proxy.ProxyFactory;
import org.qiweb.api.Application;
import org.qiweb.api.exceptions.QiWebException;
import org.qiweb.api.exceptions.RouteNotFoundException;
import org.qiweb.api.http.Method;
import org.qiweb.api.routes.ControllerCallRecorder;
import org.qiweb.api.routes.ReverseRoute;
import org.qiweb.api.routes.ReverseRoutes;
import org.qiweb.api.routes.Route;

import static org.qiweb.api.exceptions.IllegalArguments.ensureNotNull;
import static org.qiweb.api.http.Method.CONNECT;
import static org.qiweb.api.http.Method.DELETE;
import static org.qiweb.api.http.Method.GET;
import static org.qiweb.api.http.Method.HEAD;
import static org.qiweb.api.http.Method.OPTIONS;
import static org.qiweb.api.http.Method.PATCH;
import static org.qiweb.api.http.Method.POST;
import static org.qiweb.api.http.Method.PUT;
import static org.qiweb.api.http.Method.TRACE;

public class ReverseRoutesInstance
    implements ReverseRoutes
{
    private final Application application;

    public ReverseRoutesInstance( Application application )
    {
        this.application = application;
    }

    @Override
    public <T> ReverseRoute options( Class<T> controllerType, ControllerCallRecorder<T> callRecorder )
    {
        return of( OPTIONS, controllerType, callRecorder );
    }

    @Override
    public <T> ReverseRoute get( Class<T> controllerType, ControllerCallRecorder<T> callRecorder )
    {
        return of( GET, controllerType, callRecorder );
    }

    @Override
    public <T> ReverseRoute head( Class<T> controllerType, ControllerCallRecorder<T> callRecorder )
    {
        return of( HEAD, controllerType, callRecorder );
    }

    @Override
    public <T> ReverseRoute post( Class<T> controllerType, ControllerCallRecorder<T> callRecorder )
    {
        return of( POST, controllerType, callRecorder );
    }

    @Override
    public <T> ReverseRoute put( Class<T> controllerType, ControllerCallRecorder<T> callRecorder )
    {
        return of( PUT, controllerType, callRecorder );
    }

    @Override
    public <T> ReverseRoute delete( Class<T> controllerType, ControllerCallRecorder<T> callRecorder )
    {
        return of( DELETE, controllerType, callRecorder );
    }

    @Override
    public <T> ReverseRoute trace( Class<T> controllerType, ControllerCallRecorder<T> callRecorder )
    {
        return of( TRACE, controllerType, callRecorder );
    }

    @Override
    public <T> ReverseRoute patch( Class<T> controllerType, ControllerCallRecorder<T> callRecorder )
    {
        return of( PATCH, controllerType, callRecorder );
    }

    @Override
    public <T> ReverseRoute connect( Class<T> controllerType, ControllerCallRecorder<T> callRecorder )
    {
        return of( CONNECT, controllerType, callRecorder );
    }

    @Override
    public <T> ReverseRoute of( String httpMethod, Class<T> controllerType, ControllerCallRecorder<T> callRecorder )
    {
        return of( Method.valueOf( httpMethod ), controllerType, callRecorder );
    }

    @Override
    public <T> ReverseRoute of( Method httpMethod, Class<T> controllerType, ControllerCallRecorder<T> callRecorder )
    {
        ensureNotNull( "HTTP method", httpMethod );
        ensureNotNull( "Controller Type", controllerType );
        ensureNotNull( "Call Recorder", callRecorder );

        // Prepare recording proxy
        T controllerProxy;
        ControllerCallHandler handler = new ControllerCallHandler();
        if( controllerType.isInterface() )
        {
            Class<?>[] interfaces = new Class<?>[ 1 ];
            interfaces[0] = controllerType;
            controllerProxy = (T) java.lang.reflect.Proxy.newProxyInstance(
                Thread.currentThread().getContextClassLoader(),
                interfaces,
                handler
            );
        }
        else
        {
            try
            {
                ProxyFactory proxyFactory = new ProxyFactory();
                proxyFactory.setSuperclass( controllerType );
                controllerProxy = (T) proxyFactory.createClass().newInstance();
                ( (Proxy) controllerProxy ).setHandler( handler );
            }
            catch( InstantiationException | IllegalAccessException ex )
            {
                throw new QiWebException( "Unable to reverse route", ex );
            }
        }

        // Record Controller Method Call
        try
        {
            callRecorder.recordCall( controllerProxy );
        }
        catch( Exception ex )
        {
            throw new QiWebException(
                "Error while recording Controller call for Reverse routing: " + ex.getMessage(),
                ex
            );
        }

        // Find Route
        for( Route route : application.routes() )
        {
            if( route.httpMethod().equals( httpMethod )
                && route.controllerType().getName().equals( controllerType.getName() )
                && route.controllerMethodName().equals( handler.methodName )
                && Arrays.equals( route.controllerMethod().getParameterTypes(), handler.paramsTypes ) )
            {
                // Found!
                RouteInstance instance = (RouteInstance) route;
                Map<String, Object> parameters = new LinkedHashMap<>();
                int idx = 0;
                for( String paramName : instance.controllerParams().names() )
                {
                    parameters.put( paramName, handler.paramsValues[idx] );
                    idx++;
                }
                String unboundPath = route.unbindParameters( application.parameterBinders(), parameters );
                return new ReverseRouteInstance( httpMethod, unboundPath, application.defaultCharset() );
            }
        }
        // No matching Route Found
        throw new RouteNotFoundException(
            httpMethod,
            controllerType + "." + handler.methodName
            + "(" + Arrays.toString( handler.paramsTypes ) + ")"
        );
    }

{'fraction_non_alphanumeric': 0.09322573794860904, 'fraction_numerical': 0.0022651659941955123, 'mean_word_length': 2.573994434606628, 'pattern_counts': {'":': 0, '<': 77, '<?xml version=': 0, '>': 77, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3321274', 'n_tokens_mistral': 3827, 'n_tokens_neox': 3646, 'n_words': 953}