Package org.apache.clerezza.triaxrs

Source Code of org.apache.clerezza.triaxrs.InjectionUtilities

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you 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.apache.clerezza.triaxrs;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

import javax.ws.rs.CookieParam;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.Encoded;
import javax.ws.rs.FormParam;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.MatrixParam;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.ext.Providers;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.clerezza.triaxrs.parameterinjectors.ContextInjector;
import org.apache.clerezza.triaxrs.parameterinjectors.CookieParameterInjector;
import org.apache.clerezza.triaxrs.parameterinjectors.FormParameterInjector;
import org.apache.clerezza.triaxrs.parameterinjectors.HeaderParameterInjector;
import org.apache.clerezza.triaxrs.parameterinjectors.MatrixParameterInjector;
import org.apache.clerezza.triaxrs.parameterinjectors.ParameterInjector;
import org.apache.clerezza.triaxrs.parameterinjectors.PathParameterInjector;
import org.apache.clerezza.triaxrs.parameterinjectors.QueryParameterInjector;
import org.apache.clerezza.triaxrs.parameterinjectors.UnsupportedFieldType;
import org.apache.clerezza.triaxrs.util.MethodUtil;
import org.wymiwyg.wrhapi.HandlerException;

/**
* utilities to create parameters for method invocation and inject other
* stuff
*
* @author szalay
*/
public class InjectionUtilities {

  private static final Logger logger = LoggerFactory.getLogger(
      InjectionUtilities.class);
  private static Map<Class<? extends Annotation>, ParameterInjector> parameterInjectorMap
      = new HashMap<Class<? extends Annotation>, ParameterInjector>() {
    //should the ParameterInjector be injected, if yes, OSGI(-DS) or lookup from Providers?

    {
      put(MatrixParam.class, new MatrixParameterInjector());
      put(QueryParam.class, new QueryParameterInjector());
      put(PathParam.class, new PathParameterInjector());
      put(CookieParam.class, new CookieParameterInjector());
      put(HeaderParam.class, new HeaderParameterInjector());
      put(Context.class, new ContextInjector());
      put(FormParam.class, new FormParameterInjector());
    }
  };

  /**
   * Creates an instance of resourceClass injecting parameters using constructor properties and fields
   *
   * @param request
   * @param resourceClass
   * @return an instance of resourceClass
   * @throws org.wymiwyg.wrhapi.HandlerException
   * @throws org.apache.clerezza.triaxrs.parameterinjectors.UnsupportedFieldType
   */
  public static Object createPreparedInstance(WebRequest request,
      Map<String, String> pathParams,
      Providers providers, Class<?> resourceClass)
      throws HandlerException, UnsupportedFieldType {

    Object instance = null;

    boolean encodingDisabled =
        resourceClass.getAnnotation(Encoded.class) != null;

    // check constructor parameters and call constructor
    Constructor<?>[] constructors = resourceClass.getConstructors();
    int countParameters = -1;
    Constructor<?> constructor = null;

    // we must use the constructor with the most parameters
    for (Constructor<?> c : constructors) {
      Class<?>[] parameters = c.getParameterTypes();
      int count = parameters.length;

      if (count > countParameters) {
        constructor = c;
        countParameters = count; //update max parameters size found so far
      }
    }

    if (constructor == null) {
      throw new HandlerException(
          "No constructor found for resource class: " + resourceClass.getName());
    }

    logger.debug("Constructor found, injecting parameters...");

    Class<?>[] parameterClasses = constructor.getParameterTypes();
    boolean encodingDisabledForConstructor = encodingDisabled
        || (constructor.getAnnotation(Encoded.class) != null);
    Annotation[][] parameterAnnotations = constructor.getParameterAnnotations();
    Object[] parameters = new Object[parameterClasses.length];

    for (int i = 0; i < parameterClasses.length; i++) {

      Annotation[] as = parameterAnnotations[i];

      if (as.length == 0) {
        //TODO make sure another constructor is tried
        throw new HandlerException(
            "Class has constructor with arguments we cannot unterstand: " +
            "(the parameter of type " + parameterClasses[i]
            + " has no annotation)");
      }

      Object paramValue = getInjectionValueForAnnotation(request,
          pathParams, providers, as,
          parameterClasses[i], encodingDisabledForConstructor);
      parameters[i] = paramValue;
    }
   
   
    logger.debug("Calling constructor {} with parameters: {}", constructor, parameters);
    try {
      instance = constructor.newInstance(parameters);
    } catch (Exception e) {
      throw new HandlerException("Error in initializing: " + e, e);
    }
    injectFields(request, pathParams, providers, instance);

    return instance;
  }

  private static int accessModifiers(int m) {
    return m & (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED);
  }

  /**
   * this method determines which values have to injected into the method
   * parameters and does it
   *
   * @param encodingDisabled true if the class containing the method is annotaed with @Encoded
   * @param providers
   */
  public static Object[] createParametersForRequest(Method method,
      WebRequest request, Map<String, String> pathParams,
      Providers providers, boolean encodingDisabled) throws HandlerException, UnsupportedFieldType {

    Class<?>[] parameters = method.getParameterTypes();

    if (parameters.length == 0) {
      return new Object[0];
    }

    Type[] parameterTypes = method.getGenericParameterTypes();
    Class<?>[] parameterClasses = method.getParameterTypes();
    Object[] result = new Object[parameters.length];
    Annotation[][] parameterAnnotations = method.getParameterAnnotations();
    boolean encodingDisabledForMethod = encodingDisabled || (method.getAnnotation(
        Encoded.class) != null);
    for (int i = 0; i < parameters.length; i++) {

      Annotation[] annotationsForThisParameter = parameterAnnotations[i];

      logger.debug("Parameter {} has annotations: {}",
          parameters[i].getName(), annotationsForThisParameter.length);

      if ((annotationsForThisParameter == null)
          || (annotationsForThisParameter.length == 0)) {

        // if the parameter has no annotations, the request body is
        // injected (this is the entity parameter)

        result[i] = request.getBodyObject(parameterClasses[i],
            parameterTypes[i], null);

        continue;
      }

      Object injectedParameter = getInjectionValueForAnnotation(request,
          pathParams,
          providers, annotationsForThisParameter, parameterTypes[i],
          encodingDisabledForMethod);
      logger.debug("Inject parameter {} to {}", i, injectedParameter);
      result[i] = injectedParameter;

    }
    return result;
  }

  /**
   * get injection value for an annotation
   *
   * @param request
   * @param pathParams
   * @param providers
   * @param annotations
   * @param parameterClass
   * @param encodingDisabled true if the @Encoded annotation has been set on a higher level (e.g. class or method)
   * @return
   * @throws org.wymiwyg.wrhapi.HandlerException
   */
  private static Object getInjectionValueForAnnotation(WebRequest request,
      Map<String, String> pathParams,
      Providers providers, Annotation[] annotations,
      Type parameterType,
      boolean encodingDisabled) throws HandlerException, UnsupportedFieldType {
    String defaultValue = getDefaultValue(annotations);
   
    final Annotation injectionAnnotation = getInjectionAnnotation(annotations);
    if (injectionAnnotation == null) {
      logger.debug("No injection annotation, do nothing: {}", annotations);
      return null;
    }
    //not checking for supertypes of annotation, should we?
    ParameterInjector<Annotation> parameterInjector = parameterInjectorMap
        .get(injectionAnnotation.annotationType());
    if (parameterInjector != null) {
      return parameterInjector.getValue(request,
          pathParams, providers,
          parameterType, injectionAnnotation,
          encodingDisabled, defaultValue);
    }
    logger.debug("Unknown annotation, do nothing: {}",
        annotations[0].getClass().getName());
    return null;
  }

  /**
   *
   * @param annotations
   * @return true if annotations contains a jax.rs @*Param or @Context Annotation
   */
  public static boolean isAnnotated(Annotation[] annotations) {
    for (Annotation annotation : annotations) {
      if (isInjectionAnnotation(annotation)) {
        return true;
      }
    }
    return false;
  }

  private static Annotation getInjectionAnnotation(Annotation[] annotations) {
    for (Annotation annotation : annotations) {
      if (isInjectionAnnotation(annotation)) {
        return annotation;
      }
    }
    return null;
  }
 
  private static String getDefaultValue(Annotation[] annotations) {
    for (Annotation annotation : annotations) {
      if(annotation.annotationType().equals(DefaultValue.class)){
        DefaultValue dv = (DefaultValue) annotation;
        return dv.value();
      }
    }
    return null;
  }

  public static void injectFields(WebRequest request, Map<String, String> pathParams,
      Providers providers, Object instance) throws HandlerException, UnsupportedFieldType {
    Class<?> resourceClass = instance.getClass();
    boolean encodingDisabled =
        resourceClass.getAnnotation(Encoded.class) != null;
    // check fields
    Field[] fields = resourceClass.getDeclaredFields();
    for (int i = 0; i < fields.length; i++) {

      Annotation[] as = fields[i].getAnnotations();

      if (as.length == 0) {
        continue;
      }

      boolean encodingDisabledForField = encodingDisabled || (fields[i].getAnnotation(
          Encoded.class) != null);

      Object fieldValue = getInjectionValueForAnnotation(request,
          pathParams, providers, as,
          fields[i].getType(), encodingDisabledForField);
      if (fieldValue != null) {
        try {
          fields[i].set(instance, fieldValue);
        } catch (IllegalAccessException iae) {
          throw new HandlerException("setting "+fields[i]+" to "+fieldValue, iae);
        }
        logger.debug("set field value: {} to {}", fields[i], fieldValue);
      }
    }

    logger.debug("Fields checked.");

    // check setter methods
    for (Method method : MethodUtil.getAnnotatedMethods(resourceClass)){
     
      int searchMod = Modifier.PUBLIC;
      int mods = accessModifiers(method.getModifiers());
      boolean modMatch = (searchMod == mods);

      if ((method.getName().startsWith("set")) && (modMatch)
          && (method.getParameterTypes().length == 1)
          && (method.getReturnType().equals(Void.TYPE))) {
       
        logger.debug("Method {} is a setter.", method);

        Annotation[] as = method.getAnnotations();
        if (as.length == 0) {
          continue;
        }
       
        boolean encodingDisabledForSetter = encodingDisabled
            || (method.getAnnotation(Encoded.class) != null);
        final Object value = getInjectionValueForAnnotation(request,
            pathParams, providers, as,
            method.getGenericParameterTypes()[0],
            encodingDisabledForSetter);

        if (value == null) {
          continue;
        }

        Object[] valuesToSet = {value};

        try {
          method.invoke(instance, valuesToSet);
        } catch (IllegalAccessException illegalAccessException) {
          throw new HandlerException(illegalAccessException);
        } catch (IllegalArgumentException illegalArgumentException) {
          throw new HandlerException(illegalArgumentException);
        } catch (InvocationTargetException invocationTargetException) {
          throw new HandlerException(invocationTargetException);
        }
      }
    }
  }

  private static boolean isInjectionAnnotation(Annotation annotation) {
    return ((annotation.annotationType().equals(Context.class)) ||
        (annotation.annotationType().equals(QueryParam.class)) ||
        (annotation.annotationType().equals(FormParam.class)) ||
        (annotation.annotationType().equals(MatrixParam.class)) ||
        (annotation.annotationType().equals(PathParam.class)) ||
        (annotation.annotationType().equals(CookieParam.class)) ||
        (annotation.annotationType().equals(HeaderParam.class)));
  }
}
TOP

Related Classes of org.apache.clerezza.triaxrs.InjectionUtilities

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.