All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.ing.baker.recipe.javadsl.package.scala Maven / Gradle / Ivy

The newest version!
package com.ing.baker.recipe

import java.lang.reflect.Method
import java.util.concurrent.CompletableFuture

import com.ing.baker.recipe.javadsl.ReflectionHelpers._
import com.ing.baker.types.{Converters, Type}

import scala.collection.immutable.Seq
import scala.reflect.ClassTag

package object javadsl {

  private val interactionMethodName: String = "apply"

  def createIngredient(ingredientName: String, ingredientType: Type): common.Ingredient =
    new common.Ingredient(
      name = ingredientName,
      ingredientType = ingredientType
    )

  def parseType(javaType: java.lang.reflect.Type, errorMessage: String): Type = {
    try {
      Converters.readJavaType(javaType)
    } catch {
      case e: Exception => throw new IllegalArgumentException(errorMessage, e)
    }
  }

  def eventClassToCommonEvent(eventClass: Class[_], firingLimit: Option[Int]): common.Event = new javadsl.Event(eventClass, firingLimit)

  def interactionClassToCommonInteraction(interactionClass: Class[_], newName: Option[String]): InteractionDescriptor = {

    val name: String = interactionClass.getSimpleName

    val method: Method = interactionClass.getDeclaredMethods
      .find(_.getName == interactionMethodName)
      .getOrElse(throw new IllegalStateException(
        s"No method named '$interactionMethodName' defined on '${interactionClass.getName}'"))

    val inputIngredients: Seq[common.Ingredient] =
      method.getParameterNames.toIndexedSeq.map(name =>
        createIngredient(name,
          parseType(
            method.parameterTypeForName(name).get,
            s"Unsupported type for ingredient '$name' on interaction '${interactionClass.getName}'")))

    val output: Seq[common.Event] = {

      if (method.isAnnotationPresent(classOf[annotations.FiresEvent])) {
        val outputEventClasses: Seq[Class[_]] = method.getAnnotation(classOf[annotations.FiresEvent]).oneOf().toIndexedSeq

        outputEventClasses.foreach {
          eventClass =>
            if (method.isAnnotationPresent(classOf[annotations.AsyncInteraction])) {
              if (!method.getReturnType.isAssignableFrom(implicitly[ClassTag[CompletableFuture[_]]].runtimeClass))
                throw new common.RecipeValidationException(s"Interaction $name is declared to be async, but it doesn't return a CompletableFuture")
            } else {
              if (!method.getReturnType.isAssignableFrom(eventClass)) {
                if(method.getReturnType.isAssignableFrom(implicitly[ClassTag[CompletableFuture[_]]].runtimeClass)) {
                  throw new common.RecipeValidationException(s"Interaction $name is declared to be sync but returns a CompletableFuture. If you have written an Async interaction remember to add @AsyncInteraction annotation")
                }
                throw new common.RecipeValidationException(s"Interaction $name provides event '${eventClass.getName}' that is incompatible with it's return type.")
              }
            }
        }

        outputEventClasses.map(eventClassToCommonEvent(_, None))
      }
      else Seq.empty
    }

    InteractionDescriptor(name, inputIngredients, output, Set.empty, Set.empty, Map.empty, Map.empty, None, None, None, Map.empty, isReprovider = false, newName)
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy