Package org.qi4j.library.rest.server.restlet.requestreader

Source Code of org.qi4j.library.rest.server.restlet.requestreader.DefaultRequestReader

package org.qi4j.library.rest.server.restlet.requestreader;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Date;
import java.util.Map;
import org.qi4j.api.association.AssociationDescriptor;
import org.qi4j.api.common.Optional;
import org.qi4j.api.constraint.Name;
import org.qi4j.api.entity.EntityReference;
import org.qi4j.api.injection.scope.Service;
import org.qi4j.api.injection.scope.Structure;
import org.qi4j.api.property.PropertyDescriptor;
import org.qi4j.api.service.qualifier.Tagged;
import org.qi4j.api.structure.Module;
import org.qi4j.api.util.Dates;
import org.qi4j.api.value.ValueBuilder;
import org.qi4j.api.value.ValueComposite;
import org.qi4j.api.value.ValueDeserializer;
import org.qi4j.api.value.ValueSerialization;
import org.qi4j.api.value.ValueSerializationException;
import org.qi4j.functional.Function;
import org.qi4j.functional.Iterables;
import org.qi4j.library.rest.server.spi.RequestReader;
import org.restlet.Request;
import org.restlet.Response;
import org.restlet.data.CharacterSet;
import org.restlet.data.Form;
import org.restlet.data.MediaType;
import org.restlet.data.Parameter;
import org.restlet.data.Status;
import org.restlet.representation.EmptyRepresentation;
import org.restlet.representation.Representation;
import org.restlet.resource.ResourceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static org.qi4j.api.util.Annotations.isType;
import static org.qi4j.functional.Iterables.filter;
import static org.qi4j.functional.Iterables.first;
import static org.qi4j.functional.Iterables.iterable;
import static org.qi4j.functional.Iterables.matchesAny;

/**
* Convert request into method arguments.
*
* TODO: This should be split into many classes to handle the different cases.
* TODO: This does not support ManyAssociations
* TODO: This does not support NamedAssociations
*/
public class DefaultRequestReader
    implements RequestReader
{
    private static final Logger LOGGER = LoggerFactory.getLogger( DefaultRequestReader.class );
    @Structure
    private Module module;

    @Service
    @Tagged( ValueSerialization.Formats.JSON )
    private ValueDeserializer valueDeserializer;

    @Override
    @SuppressWarnings( "unchecked" )
    public Object[] readRequest( Request request, Method method )
        throws ResourceException
    {
        if( request.getMethod().equals( org.restlet.data.Method.GET ) )
        {
            Object[] args = new Object[ method.getParameterTypes().length ];

            Form queryAsForm = Request.getCurrent().getResourceRef().getQueryAsForm();
            Form entityAsForm;
            Representation representation = Request.getCurrent().getEntity();
            if( representation != null && !EmptyRepresentation.class.isInstance( representation ) )
            {
                entityAsForm = new Form( representation );
            }
            else
            {
                entityAsForm = new Form();
            }

            if( queryAsForm.isEmpty() && entityAsForm.isEmpty() )
            {
                // Nothing submitted yet - show form
                return null;
            }

            if( args.length == 1 )
            {
                if( ValueComposite.class.isAssignableFrom( method.getParameterTypes()[0] ) )
                {
                    Class<?> valueType = method.getParameterTypes()[0];
                    args[0] = getValueFromForm( (Class<ValueComposite>) valueType, queryAsForm, entityAsForm );
                    return args;
                }
                else if( Form.class.equals( method.getParameterTypes()[0] ) )
                {
                    args[0] = queryAsForm.isEmpty() ? entityAsForm : queryAsForm;
                    return args;
                }
                else if( Response.class.equals( method.getParameterTypes()[0] ) )
                {
                    args[0] = Response.getCurrent();
                    return args;
                }
            }
            parseMethodArguments( method, args, queryAsForm, entityAsForm );

            return args;
        }
        else
        {

            Object[] args = new Object[ method.getParameterTypes().length ];
            Class<? extends ValueComposite> commandType = (Class<? extends ValueComposite>) method.getParameterTypes()[0];
            if( method.getParameterTypes()[0].equals( Response.class ) )
            {
                return new Object[]
                {
                    Response.getCurrent()
                };
            }
            Representation representation = Request.getCurrent().getEntity();
            MediaType type = representation.getMediaType();
            if( type == null )
            {
                Form queryAsForm = Request.getCurrent().getResourceRef().getQueryAsForm( CharacterSet.UTF_8 );
                if( ValueComposite.class.isAssignableFrom( method.getParameterTypes()[0] ) )
                {
                    args[0] = getValueFromForm( commandType, queryAsForm, new Form() );
                }
                else
                {
                    parseMethodArguments( method, args, queryAsForm, new Form() );
                }
                return args;
            }
            else
            {
                if( method.getParameterTypes()[0].equals( Representation.class ) )
                {
                    // Command method takes Representation as input
                    return new Object[]
                    {
                        representation
                    };
                }
                else if( method.getParameterTypes()[0].equals( Form.class ) )
                {
                    // Command method takes Form as input
                    return new Object[]
                    {
                        new Form( representation )
                    };
                }
                else if( ValueComposite.class.isAssignableFrom( method.getParameterTypes()[0] ) )
                {
                    // Need to parse input into ValueComposite
                    if( type.equals( MediaType.APPLICATION_JSON ) )
                    {
                        String json = Request.getCurrent().getEntityAsText();
                        if( json == null )
                        {
                            LOGGER.error( "Restlet bug http://restlet.tigris.org/issues/show_bug.cgi?id=843 detected. "
                                          + "Notify developers!" );
                            throw new ResourceException( Status.SERVER_ERROR_INTERNAL,
                                                         "Bug in Restlet encountered; notify developers!" );
                        }

                        Object command = module.newValueFromSerializedState( commandType, json );
                        args[0] = command;
                        return args;
                    }
                    else if( type.equals( MediaType.TEXT_PLAIN ) )
                    {
                        String text = Request.getCurrent().getEntityAsText();
                        if( text == null )
                        {
                            LOGGER.error( "Restlet bug http://restlet.tigris.org/issues/show_bug.cgi?id=843 detected. "
                                          + "Notify developers!" );
                            throw new ResourceException( Status.SERVER_ERROR_INTERNAL,
                                                         "Bug in Restlet encountered; notify developers!" );
                        }
                        args[0] = text;
                        return args;
                    }
                    else if( type.equals( ( MediaType.APPLICATION_WWW_FORM ) ) )
                    {

                        Form queryAsForm = Request.getCurrent().getResourceRef().getQueryAsForm();
                        Form entityAsForm;
                        if( representation != null
                            && !EmptyRepresentation.class.isInstance( representation )
                            && representation.isAvailable() )
                        {
                            entityAsForm = new Form( representation );
                        }
                        else
                        {
                            entityAsForm = new Form();
                        }

                        Class<?> valueType = method.getParameterTypes()[0];
                        args[0] = getValueFromForm( (Class<ValueComposite>) valueType, queryAsForm, entityAsForm );
                        return args;
                    }
                    else
                    {
                        throw new ResourceException( Status.CLIENT_ERROR_BAD_REQUEST,
                                                     "Command has to be in JSON format" );
                    }
                }
                else if( method.getParameterTypes()[0].isInterface() && method.getParameterTypes().length == 1 )
                {
                    Form queryAsForm = Request.getCurrent().getResourceRef().getQueryAsForm();
                    Form entityAsForm;
                    if( representation != null
                        && !EmptyRepresentation.class.isInstance( representation )
                        && representation.isAvailable() )
                    {
                        entityAsForm = new Form( representation );
                    }
                    else
                    {
                        entityAsForm = new Form();
                    }

                    args[0] = module.currentUnitOfWork().get( method.getParameterTypes()[0],
                                                              getValue( "entity", queryAsForm, entityAsForm ) );

                    return args;
                }
                else
                {
                    Form queryAsForm = Request.getCurrent().getResourceRef().getQueryAsForm();
                    Form entityAsForm;
                    if( representation != null
                        && !EmptyRepresentation.class.isInstance( representation )
                        && representation.isAvailable() )
                    {
                        entityAsForm = new Form( representation );
                    }
                    else
                    {
                        entityAsForm = new Form();
                    }

                    parseMethodArguments( method, args, queryAsForm, entityAsForm );

                    return args;
                }
            }
        }
    }

    private ValueComposite getValueFromForm( Class<? extends ValueComposite> valueType,
                                             final Form queryAsForm,
                                             final Form entityAsForm
    )
    {
        ValueBuilder<? extends ValueComposite> builder = module.newValueBuilderWithState(
            valueType,
            new Function<PropertyDescriptor, Object>()
        {
            @Override
            public Object map( PropertyDescriptor propertyDescriptor )
            {
                Parameter param = queryAsForm.getFirst( propertyDescriptor.qualifiedName().name() );

                if( param == null )
                {
                    param = entityAsForm.getFirst( propertyDescriptor.qualifiedName().name() );
                }

                if( param != null )
                {
                    String value = param.getValue();
                    if( value != null )
                    {
                        try
                        {
                            return valueDeserializer.deserialize( propertyDescriptor.valueType(), value );
                        }
                        catch( ValueSerializationException e )
                        {
                            throw new IllegalArgumentException( "Query parameter has invalid JSON format", e );
                        }
                    }
                }

                return null;
            }
            },
            new Function<AssociationDescriptor, EntityReference>()
            {
                @Override
                public EntityReference map( AssociationDescriptor associationDescriptor )
                {
                    Parameter param = queryAsForm.getFirst( associationDescriptor.qualifiedName().name() );

                    if( param == null )
                    {
                        param = entityAsForm.getFirst( associationDescriptor.qualifiedName().name() );
                    }

                    if( param != null )
                    {
                        return EntityReference.parseEntityReference( param.getValue() );
                    }
                    else
                    {
                        return null;
                    }
                }
            },
            new Function<AssociationDescriptor, Iterable<EntityReference>>()
            {
                @Override
                public Iterable<EntityReference> map( AssociationDescriptor associationDescriptor )
                {
                    // TODO
                    return Iterables.empty();
                }
            },
            new Function<AssociationDescriptor, Map<String, EntityReference>>()
            {
                @Override
                public Map<String, EntityReference> map( AssociationDescriptor from )
                {
                    // TODO
                    return Collections.emptyMap();
                }
            }
        );

        return builder.newInstance();
    }

    @SuppressWarnings( "unchecked" )
    private void parseMethodArguments( Method method, Object[] args, Form queryAsForm, Form entityAsForm )
    {
        // Parse each argument separately using the @Name annotation as help
        int idx = 0;
        for( Annotation[] annotations : method.getParameterAnnotations() )
        {
            Name name = (Name) first( filter( isType( Name.class ), iterable( annotations ) ) );

            if( name == null )
            {
                throw new IllegalStateException( "No @Name annotation found on parameter of method:" + method );
            }

            String argString = getValue( name.value(), queryAsForm, entityAsForm );

            // Parameter conversion
            Class<?> parameterType = method.getParameterTypes()[idx];
            Object arg = null;
            if( parameterType.equals( String.class ) )
            {
                arg = argString;
            }
            else if( parameterType.equals( EntityReference.class ) )
            {
                arg = EntityReference.parseEntityReference( argString );
            }
            else if( parameterType.isEnum() )
            {
                arg = Enum.valueOf( (Class<Enum>) parameterType, argString );
            }
            else if( Integer.TYPE.isAssignableFrom( parameterType ) )
            {
                arg = Integer.valueOf( argString );
            }
            else if( Integer.class.isAssignableFrom( parameterType ) )
            {
                if( argString != null )
                {
                    arg = Integer.valueOf( argString );
                }
            }
            else if( Long.TYPE.isAssignableFrom( parameterType ) )
            {
                arg = Long.valueOf( argString );
            }
            else if( Long.class.isAssignableFrom( parameterType ) )
            {
                if( argString != null )
                {
                    arg = Long.valueOf( argString );
                }
            }
            else if( Short.TYPE.isAssignableFrom( parameterType ) )
            {
                arg = Short.valueOf( argString );
            }
            else if( Short.class.isAssignableFrom( parameterType ) )
            {
                if( argString != null )
                {
                    arg = Short.valueOf( argString );
                }
            }
            else if( Double.TYPE.isAssignableFrom( parameterType ) )
            {
                arg = Double.valueOf( argString );
            }
            else if( Double.class.isAssignableFrom( parameterType ) )
            {
                if( argString != null )
                {
                    arg = Double.valueOf( argString );
                }
            }
            else if( Float.TYPE.isAssignableFrom( parameterType ) )
            {
                arg = Float.valueOf( argString );
            }
            else if( Float.class.isAssignableFrom( parameterType ) )
            {
                if( argString != null )
                {
                    arg = Float.valueOf( argString );
                }
            }
            else if( Character.TYPE.isAssignableFrom( parameterType ) )
            {
                arg = argString.charAt( 0 );
            }
            else if( Character.class.isAssignableFrom( parameterType ) )
            {
                if( argString != null )
                {
                    arg = argString.charAt( 0 );
                }
            }
            else if( Boolean.TYPE.isAssignableFrom( parameterType ) )
            {
                arg = Boolean.valueOf( argString );
            }
            else if( Boolean.class.isAssignableFrom( parameterType ) )
            {
                if( argString != null )
                {
                    arg = Boolean.valueOf( argString );
                }
            }
            else if( Date.class.isAssignableFrom( parameterType ) )
            {
                arg = Dates.fromString( argString );
            }
            else if( parameterType.isInterface() )
            {
                arg = module.currentUnitOfWork().get( parameterType, argString );
            }
            else
            {
                throw new IllegalArgumentException( "Don't know how to parse parameter " + name.value()
                                                    + " of type " + parameterType.getName() );
            }

            if( arg == null && !matchesAny( isType( Optional.class ), iterable( annotations ) ) )
            {
                throw new IllegalArgumentException( "Parameter " + name.value() + " was not set" );
            }

            args[idx++] = arg;
        }
    }

    private String getValue( String name, Form queryAsForm, Form entityAsForm )
    {
        String value = queryAsForm.getFirstValue( name );
        if( value == null )
        {
            value = entityAsForm.getFirstValue( name );
        }
        return value;
    }
}
TOP

Related Classes of org.qi4j.library.rest.server.restlet.requestreader.DefaultRequestReader

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.