diff --git a/akka-spring/src/main/scala/ActiveObjectFactoryBean.scala b/akka-spring/src/main/scala/ActiveObjectFactoryBean.scala index 03f0f50df3..6f62c5a8c4 100644 --- a/akka-spring/src/main/scala/ActiveObjectFactoryBean.scala +++ b/akka-spring/src/main/scala/ActiveObjectFactoryBean.scala @@ -6,7 +6,8 @@ package se.scalablesolutions.akka.spring import java.beans.PropertyDescriptor import java.lang.reflect.Method - +import javax.annotation.PreDestroy +import javax.annotation.PostConstruct import reflect.BeanProperty import org.springframework.beans.BeanWrapperImpl @@ -82,7 +83,10 @@ class ActiveObjectFactoryBean extends AbstractFactoryBean[AnyRef] with Logging w if (hasInterface) argumentList += "i" if (hasDispatcher) argumentList += "d" - setProperties(create(argumentList)) + postConstruct( + setProperties( + create(argumentList))) + } /** @@ -91,7 +95,25 @@ class ActiveObjectFactoryBean extends AbstractFactoryBean[AnyRef] with Logging w override def destroyInstance(instance:AnyRef) { ActiveObject.stop(instance) } - + + /** + * Invokes any method annotated with @PostConstruct + * When interfaces are specified, this method is invoked both on the + * target instance and on the active object, so a developer is free do decide + * where the annotation should be. If no interface is specified it is only invoked + * on the active object + */ + private def postConstruct(ref:AnyRef) : AnyRef = { + // Invoke postConstruct method if any + for(method <- ref.getClass.getMethods) { + if(method.isAnnotationPresent(classOf[PostConstruct])) { + method.invoke(ref) + } + } + ref + } + + private def setProperties(ref:AnyRef) : AnyRef = { if(hasSetDependecies) { return ref @@ -119,8 +141,6 @@ class ActiveObjectFactoryBean extends AbstractFactoryBean[AnyRef] with Logging w throw new AkkaBeansException("Either property@ref or property@value must be set on property element") } } - //un-set so next bean can be managed - hasSetDependecies = false ref } @@ -144,6 +164,8 @@ class ActiveObjectFactoryBean extends AbstractFactoryBean[AnyRef] with Logging w } } + + private[akka] def createConfig: ActiveObjectConfiguration = { val config = new ActiveObjectConfiguration().timeout(timeout) if (hasRestartCallbacks) config.restartCallbacks(pre, post) @@ -153,10 +175,11 @@ class ActiveObjectFactoryBean extends AbstractFactoryBean[AnyRef] with Logging w } def aNewInstance[T <: AnyRef](clazz: Class[T]) : T = { var ref = clazz.newInstance().asInstanceOf[T] - setProperties(ref) + postConstruct( + setProperties(ref)) hasSetDependecies = true ref -} + } private[akka] def isRemote = (host != null) && (!host.isEmpty) diff --git a/akka-spring/src/test/java/se/scalablesolutions/akka/spring/Pojo.java b/akka-spring/src/test/java/se/scalablesolutions/akka/spring/Pojo.java index 42e1e393e7..04995b75c8 100644 --- a/akka-spring/src/test/java/se/scalablesolutions/akka/spring/Pojo.java +++ b/akka-spring/src/test/java/se/scalablesolutions/akka/spring/Pojo.java @@ -2,12 +2,15 @@ package se.scalablesolutions.akka.spring; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; +import javax.annotation.PreDestroy; +import javax.annotation.PostConstruct; public class Pojo implements PojoInf,ApplicationContextAware { private String string; private boolean gotApplicationContext = false; + private boolean postConstructInvoked = false; public boolean gotApplicationContext() { return gotApplicationContext; @@ -23,5 +26,14 @@ public class Pojo implements PojoInf,ApplicationContextAware { public String getString() { return string; } - + + @PostConstruct + public void create() { + postConstructInvoked = true; + } + + public boolean isPostConstructInvoked() { + return postConstructInvoked; +} + } diff --git a/akka-spring/src/test/java/se/scalablesolutions/akka/spring/PojoInf.java b/akka-spring/src/test/java/se/scalablesolutions/akka/spring/PojoInf.java index db31841f17..70d64245db 100644 --- a/akka-spring/src/test/java/se/scalablesolutions/akka/spring/PojoInf.java +++ b/akka-spring/src/test/java/se/scalablesolutions/akka/spring/PojoInf.java @@ -1,8 +1,14 @@ package se.scalablesolutions.akka.spring; +import javax.annotation.PreDestroy; +import javax.annotation.PostConstruct; + public interface PojoInf { public String getString(); public boolean gotApplicationContext(); - + public boolean isPostConstructInvoked(); + + @PostConstruct + public void create(); } diff --git a/akka-spring/src/test/scala/ActiveObjectFactoryBeanTest.scala b/akka-spring/src/test/scala/ActiveObjectFactoryBeanTest.scala index 5055fb6184..68dac8e97c 100644 --- a/akka-spring/src/test/scala/ActiveObjectFactoryBeanTest.scala +++ b/akka-spring/src/test/scala/ActiveObjectFactoryBeanTest.scala @@ -72,6 +72,8 @@ class ActiveObjectFactoryBeanTest extends Spec with ShouldMatchers { val pojoInf = ctx.getBean("pojoInf").asInstanceOf[PojoInf]; println("pojoInf = " + pojoInf.getString) + Thread.sleep(200) + assert(pojoInf.isPostConstructInvoked) assert(pojoInf.getString == "akka rocks") assert(pojoInf.gotApplicationContext) }