summaryrefslogtreecommitdiffstats
path: root/container-di/src/main/scala/com/yahoo/container/di/componentgraph/core
diff options
context:
space:
mode:
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.scala67
-rw-r--r--container-di/src/main/scala/com/yahoo/container/di/componentgraph/core/Node.scala2
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'"
}
}