diff options
Diffstat (limited to 'container-di/src/main/scala/com/yahoo/container/di/componentgraph/core')
-rw-r--r-- | container-di/src/main/scala/com/yahoo/container/di/componentgraph/core/ComponentNode.scala | 67 | ||||
-rw-r--r-- | container-di/src/main/scala/com/yahoo/container/di/componentgraph/core/Node.scala | 2 |
2 files changed, 44 insertions, 25 deletions
diff --git a/container-di/src/main/scala/com/yahoo/container/di/componentgraph/core/ComponentNode.scala b/container-di/src/main/scala/com/yahoo/container/di/componentgraph/core/ComponentNode.scala index 16856930e54..477dfa40aad 100644 --- a/container-di/src/main/scala/com/yahoo/container/di/componentgraph/core/ComponentNode.scala +++ b/container-di/src/main/scala/com/yahoo/container/di/componentgraph/core/ComponentNode.scala @@ -1,21 +1,22 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.container.di.componentgraph.core -import java.lang.reflect.{Modifier, ParameterizedType, Constructor, Type, InvocationTargetException} +import java.lang.reflect.{Constructor, InvocationTargetException, Modifier, ParameterizedType, Type} import java.util.logging.Logger -import com.google.inject.Inject +import com.google.inject.Inject +import com.yahoo.component.{AbstractComponent, ComponentId} import com.yahoo.config.ConfigInstance -import com.yahoo.vespa.config.ConfigKey -import com.yahoo.component.{ComponentId, AbstractComponent} -import com.yahoo.container.di.{ConfigKeyT, JavaAnnotation, createKey, makeClassCovariant, removeStackTrace, preserveStackTrace} import com.yahoo.container.di.componentgraph.Provider +import com.yahoo.container.di.componentgraph.core.ComponentNode._ +import com.yahoo.container.di.componentgraph.core.Node.equalEdges +import com.yahoo.container.di.{ConfigKeyT, JavaAnnotation, createKey, makeClassCovariant, preserveStackTrace, removeStackTrace} +import com.yahoo.vespa.config.ConfigKey -import Node.equalEdges -import ComponentNode._ -import java.lang.IllegalStateException -import scala.Some -import scala.Array +import scala.concurrent.ExecutionContext.Implicits.global +import scala.concurrent.duration._ +import scala.concurrent.{Await, Future, TimeoutException} +import scala.language.postfixOps /** * @author tonytv @@ -94,24 +95,36 @@ class ComponentNode(componentId: ComponentId, case other => other } - val instance = + val instanceFuture = Future { + try { + constructor.newInstance(actualArguments: _*) + } catch { + case e: InvocationTargetException => + throw removeStackTrace(ErrorOrComponentConstructorException(cutStackTraceAtConstructor(e.getCause), s"Error constructing $idAndType")) + } + } + try { - constructor.newInstance(actualArguments: _*) + val instance = Await.result(instanceFuture, ComponentConstructTimeout) + initId(instance) } catch { - case e: InvocationTargetException => - throw removeStackTrace(constructThrowable(cutStackTraceAtConstructor(e.getCause), s"Error constructing $idAndType")) + case constructorException: ComponentConstructorException => + throw constructorException + case _:TimeoutException => + throw new ComponentConstructorException(s"Timed out after $ComponentConstructTimeout while constructing component $idAndType.") + case e: InterruptedException => + Thread.currentThread().interrupt() + throw new RuntimeException(s"Interrupted while constructing component $idAndType", e) } - - initId(instance) } - - private def constructThrowable(cause: Throwable, message: String) : Throwable = { + + private def ErrorOrComponentConstructorException(cause: Throwable, message: String) : Throwable = { if (cause != null && cause.isInstanceOf[Error]) // don't convert Errors to RuntimeExceptions new Error(message, cause) else - new RuntimeException(message, cause) + new ComponentConstructorException(message, cause) } - + private def initId(component: AnyRef) = { def checkAndSetId(c: AbstractComponent) { if (c.hasInitializedId && c.getId != componentId ) @@ -173,6 +186,9 @@ class ComponentNode(componentId: ComponentId, object ComponentNode { val log = Logger.getLogger(classOf[ComponentNode].getName) + // XXX: var for testing only. Do not reset in production code! + var ComponentConstructTimeout: FiniteDuration = 60 seconds + private def bestConstructor(clazz: Class[AnyRef]) = { val publicConstructors = clazz.getConstructors.asInstanceOf[Array[Constructor[AnyRef]]] @@ -180,7 +196,7 @@ object ComponentNode { publicConstructors filter {_.getAnnotation(classOf[Inject]) != null} match { case Array() => None case Array(single) => Some(single) - case _ => throwRuntimeExceptionRemoveStackTrace("Multiple constructors annotated with inject in class " + clazz.getName) + case _ => throwComponentConstructorException("Multiple constructors annotated with inject in class " + clazz.getName) } } @@ -188,7 +204,7 @@ object ComponentNode { def isConfigInstance(clazz: Class[_]) = classOf[ConfigInstance].isAssignableFrom(clazz) publicConstructors match { - case Array() => throwRuntimeExceptionRemoveStackTrace("No public constructors in class " + clazz.getName) + case Array() => throwComponentConstructorException("No public constructors in class " + clazz.getName) case Array(single) => single case _ => log.warning("Multiple public constructors found in class %s, there should only be one. ".format(clazz.getName) + @@ -202,9 +218,12 @@ object ComponentNode { constructorAnnotatedWithInject getOrElse constructorWithMostConfigParameters } - private def throwRuntimeExceptionRemoveStackTrace(message: String) = - throw removeStackTrace(new RuntimeException(message)) + private def throwComponentConstructorException(message: String) = + throw removeStackTrace(new ComponentConstructorException(message)) + class ComponentConstructorException(message: String, cause: Throwable) extends RuntimeException(message, cause) { + def this(message: String) = this(message, null) + } def isAbstract(clazz: Class[_ <: AnyRef]) = Modifier.isAbstract(clazz.getModifiers) } diff --git a/container-di/src/main/scala/com/yahoo/container/di/componentgraph/core/Node.scala b/container-di/src/main/scala/com/yahoo/container/di/componentgraph/core/Node.scala index 9d30552b0aa..2ec3b77ed8a 100644 --- a/container-di/src/main/scala/com/yahoo/container/di/componentgraph/core/Node.scala +++ b/container-di/src/main/scala/com/yahoo/container/di/componentgraph/core/Node.scala @@ -72,7 +72,7 @@ abstract class Node(val componentId: ComponentId) { val className = instanceType.getName if (className == componentId.getName) s"'$componentId'" - else s"'$componentId of type '$className'" + else s"'$componentId' of type '$className'" } } |