Package com.eclipsesource.jaxrs.consumer.internal

Source Code of com.eclipsesource.jaxrs.consumer.internal.ResourceInvocationHandler

/*******************************************************************************
* Copyright (c) 2012,2013 EclipseSource and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*    Holger Staudacher - initial API and implementation
******************************************************************************/
package com.eclipsesource.jaxrs.consumer.internal;

import static javax.ws.rs.core.Response.Status.Family.CLIENT_ERROR;
import static javax.ws.rs.core.Response.Status.Family.SERVER_ERROR;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.HEAD;
import javax.ws.rs.OPTIONS;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.Invocation.Builder;
import javax.ws.rs.core.Form;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status.Family;
import javax.ws.rs.ext.Provider;

import org.glassfish.jersey.message.internal.MediaTypes;


public class ResourceInvocationHandler implements InvocationHandler {

  private final Client client;
  private final String baseUrl;

  public ResourceInvocationHandler( String serviceUrl, Object... customProviders ) {
    ClientBuilder clientBuilder = ClientBuilder.newBuilder();
    registerProviders( clientBuilder, customProviders );
    this.client = clientBuilder.sslContext( ClientHelper.createSSLContext() )
                               .hostnameVerifier( ClientHelper.createHostNameVerifier() )
                               .build();
    this.baseUrl = serviceUrl;
  }

  private void registerProviders( ClientBuilder clientBuilder, Object[] customProviders ) {
    if( customProviders != null ) {
      for( Object provider : customProviders ) {
        if( provider.getClass().isAnnotationPresent( Provider.class ) ) {
          clientBuilder.register( provider );
        } else {
          throw new IllegalArgumentException( provider.getClass().getName() + " is not annotated with @Provider" );
        }
      }
    }
  }

  @Override
  public Object invoke( Object proxy, Method method, Object[] parameter ) throws Throwable {
    RequestConfigurer configurer = new RequestConfigurer( client, baseUrl, method, parameter );
    return sendRequest( method, parameter, configurer );
  }

  private Object sendRequest( Method method, Object[] parameter, RequestConfigurer configurer ) {
    Object result = null;
    Builder request = configurer.configure();
    if( method.isAnnotationPresent( GET.class ) ) {
      result = sendGetRequest( configurer, method, request );
    } if( method.isAnnotationPresent( POST.class ) ) {
      result = sendPostRequest( configurer, method, parameter, request );
    } if( method.isAnnotationPresent( PUT.class ) ) {
      result = sendPutRequest( configurer, method, parameter, request );
    } if( method.isAnnotationPresent( DELETE.class ) ) {
      result = sendDeleteRequest( configurer, method, request );
    } if( method.isAnnotationPresent( HEAD.class ) ) {
      result = sendHeadRequest( configurer, method, request );
    } if( method.isAnnotationPresent( OPTIONS.class ) ) {
      result = sendOptionsRequest( configurer, method, request );
    }
    return result;
  }

  private Object sendGetRequest( RequestConfigurer configurer, Method method, Builder request ) {
    checkHasNoFormParameter( method );
    Response response = request.get();
    validateResponse( configurer, response, "GET" );
    return response.readEntitymethod.getReturnType()  );
  }

  private Object sendPostRequest( RequestConfigurer configurer, Method method, Object[] parameter, Builder request ) {
    Response response = request.post( getPostEntity( method, parameter ) );
    validateResponse( configurer, response, "POST" );
    return response.readEntity( method.getReturnType() );
  }

  private Object sendPutRequest( RequestConfigurer configurer, Method method, Object[] parameter, Builder request ) {
    Response response = request.put( getEntity( method, parameter ) );
    validateResponse( configurer, response, "PUT" );
    return response.readEntity( method.getReturnType() );
  }

  private Object sendDeleteRequest( RequestConfigurer configurer, Method method, Builder request ) {
    Response response = request.delete();
    validateResponse( configurer, response, "DELETE" );
    return response.readEntity( method.getReturnType() );
  }

  private Object sendHeadRequest( RequestConfigurer configurer, Method method, Builder request ) {
    Response response = request.head();
    validateResponse( configurer, response, "HEAD" );
    return response.readEntity( method.getReturnType() );
  }

  private Object sendOptionsRequest( RequestConfigurer configurer, Method method, Builder request ) {
    Response response = request.options();
    validateResponse( configurer, response, "OPTIONS" );
    return response.readEntity( method.getReturnType() );
  }

  private void validateResponse( RequestConfigurer configurer, Response response, String method ) {
    Family family = response.getStatusInfo().getFamily();
    if( family == SERVER_ERROR || family == CLIENT_ERROR ) {
      RequestError requestError = new RequestError( configurer, response, method );
      throw new IllegalStateException( requestError.getMessage() );
    }
  }

  private void checkHasNoFormParameter( Method method ) {
    if( hasFormParameter( method ) ) {
      throw new IllegalStateException( "@GET methods can not have @FormParam parameters." );
    }
  }

  private Entity<?> getPostEntity( Method method, Object[] parameter ) {
    Entity<?> result;
    try {
      result = getEntity( method, parameter );
    } catch( IllegalStateException noEntityException ) {
      result = null;
    }
    return result;
  }

  private Entity<?> getEntity( Method method, Object[] parameter ) {
    Entity<?> result = null;
    if( hasFormParameter( method ) ) {
      Form form = computeForm( method, parameter );
      result = Entity.form( form );
    } else {
      result = determineBodyParameter( method, parameter );
    }
    return result;
  }

  private boolean hasFormParameter( Method method ) {
    Annotation[][] parameterAnnotations = method.getParameterAnnotations();
    for( int i = 0; i < parameterAnnotations.length; i++ ) {
      Annotation[] annotations = parameterAnnotations[ i ];
      for( Annotation annotation : annotations ) {
        if( annotation.annotationType() == FormParam.class ) {
          return true;
        }
      }
    }
    return false;
  }

  private Form computeForm( Method method, Object[] parameter ) {
    Form result = new Form();
    Annotation[][] parameterAnnotations = method.getParameterAnnotations();
    for( int i = 0; i < parameterAnnotations.length; i++ ) {
      Annotation[] annotations = parameterAnnotations[ i ];
      String paramName = extractFormParam( annotations );
      if( paramName != null ) {
        result.param( paramName, parameter[ i ].toString() );
      }
    }
    return result.asMap().isEmpty() ? null : result;
  }

  private String extractFormParam( Annotation[] annotations ) {
    for( Annotation annotation : annotations ) {
      if( annotation.annotationType() == FormParam.class ) {
        return ( ( FormParam )annotation ).value();
      }
    }
    return null;
  }

  private Entity<?> determineBodyParameter( Method method, Object[] parameter ) {
    Entity<?> result = null;
    Annotation[][] parameterAnnotations = method.getParameterAnnotations();
    checkParametersForAnnotation( method, parameterAnnotations );
    int firstNonAnnotatedParameter = getFirstNonAnnotatedParameter( parameterAnnotations );
    if( firstNonAnnotatedParameter != -1 ) {
      result =  Entity.entity( parameter[ firstNonAnnotatedParameter ], determineContentType( method ) );
    } else {
      throw new IllegalStateException( "Can not find entity for method " + method.getName()
                                       + ". It has no non-annotated parameter" );
    }
    return result;
  }

  private int getFirstNonAnnotatedParameter( Annotation[][] parameterAnnotations ) {
    int firstNonAnnotatedParameter = -1;
    for( int i = 0; i < parameterAnnotations.length; i++ ) {
      Annotation[] annotations = parameterAnnotations[ i ];
      if( annotations.length == 0 ) {
        firstNonAnnotatedParameter = i;
        break;
      }
    }
    return firstNonAnnotatedParameter;
  }

  private void checkParametersForAnnotation( Method method, Annotation[][] parameterAnnotations ) {
    if( parameterAnnotations.length == 0 ) {
      throw new IllegalStateException( "Can not find entity for method "
                                       + method.getName() + ". It has no paramters." );
    }
  }

  // TODO: Think about a better determination of the content type
  private MediaType determineContentType( Method method ) {
    MediaType result = MediaType.TEXT_PLAIN_TYPE;
    if( method.isAnnotationPresent( Consumes.class ) ) {
      result = MediaTypes.createFrom( method.getAnnotation( Consumes.class ) ).get( 0 );
    }
    return result;
  }
}
TOP

Related Classes of com.eclipsesource.jaxrs.consumer.internal.ResourceInvocationHandler

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.