fixed final issues with AW proxy integration and remaining tests
This commit is contained in:
parent
e0591005ed
commit
bbec315eb2
29 changed files with 933 additions and 866 deletions
|
|
@ -56,5 +56,6 @@
|
|||
<classpathentry kind="lib" path="/Users/jboner/src/scala/akka/lib/commons-collections-3.2.1.jar"/>
|
||||
<classpathentry kind="lib" path="/Users/jboner/src/scala/akka/lib/commons-lang-2.4.jar"/>
|
||||
<classpathentry kind="lib" path="/Users/jboner/src/scala/akka/lib/high-scale-lib.jar"/>
|
||||
<classpathentry kind="lib" path="/Users/jboner/src/scala/akka/lib/jersey-client-1.1.0-ea.jar"/>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
|
|
|
|||
|
|
@ -24,31 +24,37 @@
|
|||
<groupId>com.sun.grizzly</groupId>
|
||||
<artifactId>grizzly-servlet-webserver</artifactId>
|
||||
<version>1.9.9</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey</groupId>
|
||||
<artifactId>jersey-server</artifactId>
|
||||
<version>1.0.3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey</groupId>
|
||||
<artifactId>jersey-json</artifactId>
|
||||
<version>1.0.3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey</groupId>
|
||||
<artifactId>jersey-client</artifactId>
|
||||
<version>1.1.0-ea</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey</groupId>
|
||||
<artifactId>jersey-atom</artifactId>
|
||||
<version>1.0.3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.5</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jmock</groupId>
|
||||
|
|
|
|||
|
|
@ -32,17 +32,14 @@ public class ActiveObjectGuiceConfiguratorTest extends TestCase {
|
|||
}).configureActiveObjects(
|
||||
new RestartStrategy(new AllForOne(), 3, 5000), new Component[]{
|
||||
new Component(
|
||||
"foo",
|
||||
Foo.class,
|
||||
FooImpl.class,
|
||||
new LifeCycle(new Permanent(), 1000),
|
||||
1000),
|
||||
10000),
|
||||
new Component(
|
||||
"bar",
|
||||
Bar.class,
|
||||
BarImpl.class,
|
||||
new LifeCycle(new Permanent(), 1000),
|
||||
1000)
|
||||
10000)
|
||||
}).inject().supervise();
|
||||
|
||||
}
|
||||
|
|
@ -51,7 +48,7 @@ public class ActiveObjectGuiceConfiguratorTest extends TestCase {
|
|||
messageLog = "";
|
||||
Foo foo = conf.getActiveObject(Foo.class);
|
||||
Bar bar = conf.getActiveObject(Bar.class);
|
||||
assertTrue(foo.getBar().toString().equals(bar.toString()));
|
||||
assertEquals(foo.getBar(), bar);
|
||||
}
|
||||
|
||||
public void testGuiceExternalDependencyInjection() {
|
||||
|
|
@ -66,7 +63,7 @@ public class ActiveObjectGuiceConfiguratorTest extends TestCase {
|
|||
String str = conf.getActiveObject(String.class);
|
||||
fail("exception should have been thrown");
|
||||
} catch (Exception e) {
|
||||
assertEquals("Class string has not been put under supervision (by passing in the config to the supervise() method", e.getMessage());
|
||||
assertEquals("Class [java.lang.String] has not been put under supervision (by passing in the config to the 'configureActiveObjects' and then invoking 'supervise') method", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -113,57 +110,4 @@ public class ActiveObjectGuiceConfiguratorTest extends TestCase {
|
|||
}
|
||||
}
|
||||
|
||||
interface Foo {
|
||||
public String foo(String msg);
|
||||
@oneway public void bar(String msg);
|
||||
public void longRunning();
|
||||
public void throwsException();
|
||||
public Bar getBar();
|
||||
}
|
||||
|
||||
class FooImpl implements Foo {
|
||||
@Inject private Bar bar;
|
||||
public Bar getBar() {
|
||||
return bar;
|
||||
}
|
||||
public String foo(String msg) {
|
||||
return msg + "return_foo ";
|
||||
}
|
||||
public void bar(String msg) {
|
||||
bar.bar(msg);
|
||||
}
|
||||
public void longRunning() {
|
||||
try {
|
||||
Thread.sleep(10000);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
public void throwsException() {
|
||||
throw new RuntimeException("expected");
|
||||
}
|
||||
}
|
||||
|
||||
interface Bar {
|
||||
@oneway void bar(String msg);
|
||||
Ext getExt();
|
||||
}
|
||||
|
||||
class BarImpl implements Bar {
|
||||
@Inject private Ext ext;
|
||||
public Ext getExt() {
|
||||
return ext;
|
||||
}
|
||||
public void bar(String msg) {
|
||||
}
|
||||
}
|
||||
|
||||
interface Ext {
|
||||
void ext();
|
||||
}
|
||||
|
||||
class ExtImpl implements Ext {
|
||||
public void ext() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
package se.scalablesolutions.akka.api;
|
||||
|
||||
import se.scalablesolutions.akka.annotation.oneway;
|
||||
|
||||
public interface Bar {
|
||||
@oneway
|
||||
void bar(String msg);
|
||||
Ext getExt();
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package se.scalablesolutions.akka.api;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
public class BarImpl implements Bar {
|
||||
@Inject
|
||||
private Ext ext;
|
||||
public Ext getExt() {
|
||||
return ext;
|
||||
}
|
||||
public void bar(String msg) {
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package se.scalablesolutions.akka.api;
|
||||
|
||||
public interface Ext {
|
||||
void ext();
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package se.scalablesolutions.akka.api;
|
||||
|
||||
public class ExtImpl implements Ext {
|
||||
public void ext() {
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package se.scalablesolutions.akka.api;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import se.scalablesolutions.akka.annotation.oneway;
|
||||
|
||||
public class Foo {
|
||||
@Inject
|
||||
private Bar bar;
|
||||
public Bar getBar() {
|
||||
return bar;
|
||||
}
|
||||
public String foo(String msg) {
|
||||
return msg + "return_foo ";
|
||||
}
|
||||
@oneway
|
||||
public void bar(String msg) {
|
||||
bar.bar(msg);
|
||||
}
|
||||
public void longRunning() {
|
||||
try {
|
||||
Thread.sleep(10000);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
public void throwsException() {
|
||||
throw new RuntimeException("expected");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
package se.scalablesolutions.akka.api;
|
||||
|
||||
public interface InMemFailer {
|
||||
public void fail();
|
||||
public class InMemFailer {
|
||||
public void fail() {
|
||||
throw new RuntimeException("expected");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,68 @@
|
|||
package se.scalablesolutions.akka.api;
|
||||
|
||||
import se.scalablesolutions.akka.annotation.state;
|
||||
import se.scalablesolutions.akka.annotation.transactional;
|
||||
import se.scalablesolutions.akka.kernel.*;
|
||||
|
||||
public interface InMemStateful {
|
||||
// transactional
|
||||
@transactional
|
||||
public void success(String key, String msg);
|
||||
public class InMemStateful {
|
||||
@state private TransactionalMap<String, String> mapState = new InMemoryTransactionalMap<String, String>();
|
||||
@state private TransactionalVector<String> vectorState = new InMemoryTransactionalVector<String>();
|
||||
@state private TransactionalRef<String> refState = new TransactionalRef<String>();
|
||||
|
||||
public String getMapState(String key) {
|
||||
return (String)mapState.get(key).get();
|
||||
}
|
||||
|
||||
public String getVectorState() {
|
||||
return (String)vectorState.last();
|
||||
}
|
||||
|
||||
public String getRefState() {
|
||||
return (String)refState.get().get();
|
||||
}
|
||||
|
||||
public void setMapState(String key, String msg) {
|
||||
mapState.put(key, msg);
|
||||
}
|
||||
|
||||
public void setVectorState(String msg) {
|
||||
vectorState.add(msg);
|
||||
}
|
||||
|
||||
public void setRefState(String msg) {
|
||||
refState.swap(msg);
|
||||
}
|
||||
|
||||
@transactional
|
||||
public void failure(String key, String msg, InMemFailer failer);
|
||||
public void success(String key, String msg) {
|
||||
mapState.put(key, msg);
|
||||
vectorState.add(msg);
|
||||
refState.swap(msg);
|
||||
}
|
||||
|
||||
//@transactional
|
||||
//public void clashOk(String key, String msg, InMemClasher clasher);
|
||||
@transactional
|
||||
public void failure(String key, String msg, InMemFailer failer) {
|
||||
mapState.put(key, msg);
|
||||
vectorState.add(msg);
|
||||
refState.swap(msg);
|
||||
failer.fail();
|
||||
}
|
||||
|
||||
//@transactional
|
||||
//public void clashNotOk(String key, String msg, InMemClasher clasher);
|
||||
@transactional
|
||||
public void thisMethodHangs(String key, String msg, InMemFailer failer) {
|
||||
setMapState(key, msg);
|
||||
}
|
||||
|
||||
// non-transactional
|
||||
public String getState(String key);
|
||||
/*
|
||||
public void clashOk(String key, String msg, InMemClasher clasher) {
|
||||
mapState.put(key, msg);
|
||||
clasher.clash();
|
||||
}
|
||||
|
||||
public void setState(String key, String value);
|
||||
}
|
||||
public void clashNotOk(String key, String msg, InMemClasher clasher) {
|
||||
mapState.put(key, msg);
|
||||
clasher.clash();
|
||||
this.success("clash", "clash");
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
package se.scalablesolutions.akka.api;
|
||||
|
||||
import se.scalablesolutions.akka.annotation.state;
|
||||
import se.scalablesolutions.akka.kernel.TransactionalMap;
|
||||
import se.scalablesolutions.akka.kernel.InMemoryTransactionalMap;
|
||||
|
||||
public class InMemStatefulImpl implements InMemStateful {
|
||||
@state
|
||||
private TransactionalMap<String, String> state = new InMemoryTransactionalMap<String, String>();
|
||||
|
||||
public String getState(String key) {
|
||||
return state.get(key).get();
|
||||
}
|
||||
|
||||
public void setState(String key, String msg) {
|
||||
state.put(key, msg);
|
||||
}
|
||||
|
||||
public void success(String key, String msg) {
|
||||
state.put(key, msg);
|
||||
}
|
||||
|
||||
public void failure(String key, String msg, InMemFailer failer) {
|
||||
state.put(key, msg);
|
||||
failer.fail();
|
||||
}
|
||||
|
||||
/*
|
||||
public void clashOk(String key, String msg, InMemClasher clasher) {
|
||||
state.put(key, msg);
|
||||
clasher.clash();
|
||||
}
|
||||
|
||||
public void clashNotOk(String key, String msg, InMemClasher clasher) {
|
||||
state.put(key, msg);
|
||||
clasher.clash();
|
||||
this.success("clash", "clash");
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
@ -4,11 +4,8 @@
|
|||
|
||||
package se.scalablesolutions.akka.api;
|
||||
|
||||
import se.scalablesolutions.akka.annotation.*;
|
||||
import se.scalablesolutions.akka.kernel.config.*;
|
||||
import static se.scalablesolutions.akka.kernel.config.JavaConfig.*;
|
||||
import se.scalablesolutions.akka.kernel.TransactionalMap;
|
||||
import se.scalablesolutions.akka.kernel.InMemoryTransactionalMap;
|
||||
import se.scalablesolutions.akka.kernel.config.*;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
|
|
@ -22,35 +19,68 @@ public class InMemoryStateTest extends TestCase {
|
|||
new RestartStrategy(new AllForOne(), 3, 5000),
|
||||
new Component[] {
|
||||
// FIXME: remove string-name, add ctor to only accept target class
|
||||
new Component("inmem-stateful", InMemStateful.class, InMemStatefulImpl.class, new LifeCycle(new Permanent(), 1000), 10000000),
|
||||
new Component("inmem-failer", InMemFailer.class, InMemFailerImpl.class, new LifeCycle(new Permanent(), 1000), 1000)
|
||||
new Component(InMemStateful.class, new LifeCycle(new Permanent(), 1000), 10000000),
|
||||
new Component(InMemFailer.class, new LifeCycle(new Permanent(), 1000), 1000)
|
||||
//new Component("inmem-clasher", InMemClasher.class, InMemClasherImpl.class, new LifeCycle(new Permanent(), 1000), 100000)
|
||||
}).inject().supervise();
|
||||
}
|
||||
|
||||
|
||||
protected void tearDown() {
|
||||
conf.stop();
|
||||
}
|
||||
|
||||
public void testShouldNotRollbackStateForStatefulServerInCaseOfSuccess() {
|
||||
public void testMapShouldNotRollbackStateForStatefulServerInCaseOfSuccess() {
|
||||
InMemStateful stateful = conf.getActiveObject(InMemStateful.class);
|
||||
stateful.setState("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "init"); // set init state
|
||||
stateful.setMapState("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "init"); // set init state
|
||||
stateful.success("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "new state"); // transactional
|
||||
stateful.success("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "new state"); // to trigger commit
|
||||
assertEquals("new state", stateful.getState("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess"));
|
||||
assertEquals("new state", stateful.getMapState("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess"));
|
||||
}
|
||||
|
||||
public void testShouldRollbackStateForStatefulServerInCaseOfFailure() {
|
||||
public void testMapShouldRollbackStateForStatefulServerInCaseOfFailure() {
|
||||
InMemStateful stateful = conf.getActiveObject(InMemStateful.class);
|
||||
stateful.setMapState("testShouldRollbackStateForStatefulServerInCaseOfFailure", "init"); // set init state
|
||||
InMemFailer failer = conf.getActiveObject(InMemFailer.class);
|
||||
try {
|
||||
stateful.failure("testShouldRollbackStateForStatefulServerInCaseOfFailure", "new state", failer); // call failing transactional method
|
||||
fail("should have thrown an exception");
|
||||
} catch (RuntimeException e) {
|
||||
} // expected
|
||||
assertEquals("init", stateful.getMapState("testShouldRollbackStateForStatefulServerInCaseOfFailure")); // check that state is == init state
|
||||
}
|
||||
|
||||
public void testVectorShouldNotRollbackStateForStatefulServerInCaseOfSuccess() {
|
||||
InMemStateful stateful = conf.getActiveObject(InMemStateful.class);
|
||||
stateful.setState("testShouldRollbackStateForStatefulServerInCaseOfFailure", "init"); // set init state
|
||||
InMemFailer failer = conf.getActiveObject(InMemFailer.class);
|
||||
try {
|
||||
stateful.failure("testShouldRollbackStateForStatefulServerInCaseOfFailure", "new state", failer); // call failing transactional method
|
||||
fail("should have thrown an exception");
|
||||
} catch (RuntimeException e) {
|
||||
} // expected
|
||||
assertEquals("init", stateful.getState("testShouldRollbackStateForStatefulServerInCaseOfFailure")); // check that state is == init state
|
||||
stateful.setVectorState("init"); // set init state
|
||||
stateful.success("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "new state"); // transactional
|
||||
stateful.success("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "new state"); // to trigger commit
|
||||
assertEquals("new state", stateful.getVectorState());
|
||||
}
|
||||
|
||||
public void testVectorShouldRollbackStateForStatefulServerInCaseOfFailure() {
|
||||
InMemStateful stateful = conf.getActiveObject(InMemStateful.class);
|
||||
stateful.setVectorState("init"); // set init state
|
||||
InMemFailer failer = conf.getActiveObject(InMemFailer.class);
|
||||
try {
|
||||
stateful.failure("testShouldRollbackStateForStatefulServerInCaseOfFailure", "new state", failer); // call failing transactional method
|
||||
fail("should have thrown an exception");
|
||||
} catch (RuntimeException e) {
|
||||
} // expected
|
||||
assertEquals("init", stateful.getVectorState()); // check that state is == init state
|
||||
}
|
||||
|
||||
public void testNestedNonTransactionalMethodHangs() {
|
||||
InMemStateful stateful = conf.getActiveObject(InMemStateful.class);
|
||||
stateful.setMapState("testShouldRollbackStateForStatefulServerInCaseOfFailure", "init"); // set init state
|
||||
InMemFailer failer = conf.getActiveObject(InMemFailer.class);
|
||||
try {
|
||||
stateful.thisMethodHangs("testShouldRollbackStateForStatefulServerInCaseOfFailure", "new state", failer); // call failing transactional method
|
||||
fail("should have thrown an exception");
|
||||
} catch (RuntimeException e) {
|
||||
} // expected
|
||||
assertEquals("init", stateful.getMapState("testShouldRollbackStateForStatefulServerInCaseOfFailure")); // check that state is == init state
|
||||
}
|
||||
|
||||
/*
|
||||
*/
|
||||
// public void testShouldRollbackStateForStatefulServerInCaseOfMessageClash()
|
||||
|
|
|
|||
|
|
@ -5,8 +5,10 @@ import javax.ws.rs.GET;
|
|||
import javax.ws.rs.Produces;
|
||||
|
||||
@Path("/foo")
|
||||
public interface JerseyFoo {
|
||||
public class JerseyFoo {
|
||||
@GET
|
||||
@Produces({"application/json"})
|
||||
public String foo();
|
||||
}
|
||||
public String foo() {
|
||||
return "hello foo";
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
package se.scalablesolutions.akka.api;
|
||||
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Produces;
|
||||
|
||||
//@Path("/foo")
|
||||
public class JerseyFooImpl implements JerseyFoo {
|
||||
//@GET
|
||||
//@Produces({"application/json"})
|
||||
public String foo() {
|
||||
return "hello foo";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package se.scalablesolutions.akka.api;
|
||||
|
||||
import se.scalablesolutions.akka.kernel.TransactionalMap;
|
||||
import se.scalablesolutions.akka.kernel.CassandraPersistentTransactionalMap;
|
||||
|
||||
public class PersistentClasher {
|
||||
private TransactionalMap state = new CassandraPersistentTransactionalMap(this);
|
||||
|
||||
public String getState(String key) {
|
||||
return (String)state.get(key).get();
|
||||
}
|
||||
|
||||
public void setState(String key, String msg) {
|
||||
state.put(key, msg);
|
||||
}
|
||||
|
||||
public void clash() {
|
||||
state.put("clasher", "was here");
|
||||
// spend some time here
|
||||
|
||||
// FIXME: this statement gives me this error:
|
||||
// se.scalablesolutions.akka.kernel.ActiveObjectException:
|
||||
// Unexpected message [!(scala.actors.Channel@c2b2f6,ErrRef[Right(null)])]
|
||||
// to
|
||||
// [GenericServer[se.scalablesolutions.akka.api.StatefulImpl]] from
|
||||
// [GenericServer[se.scalablesolutions.akka.api.ClasherImpl]]]
|
||||
// try { Thread.sleep(1000); } catch (InterruptedException e) {}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package se.scalablesolutions.akka.api;
|
||||
|
||||
public class InMemFailerImpl implements InMemFailer {
|
||||
public class PersistentFailer {
|
||||
public void fail() {
|
||||
throw new RuntimeException("expected");
|
||||
}
|
||||
|
|
@ -6,11 +6,6 @@ package se.scalablesolutions.akka.api;
|
|||
|
||||
import se.scalablesolutions.akka.annotation.*;
|
||||
import se.scalablesolutions.akka.kernel.config.*;
|
||||
import se.scalablesolutions.akka.kernel.config.JavaConfig.AllForOne;
|
||||
import se.scalablesolutions.akka.kernel.config.JavaConfig.Component;
|
||||
import se.scalablesolutions.akka.kernel.config.JavaConfig.LifeCycle;
|
||||
import se.scalablesolutions.akka.kernel.config.JavaConfig.Permanent;
|
||||
import se.scalablesolutions.akka.kernel.config.JavaConfig.RestartStrategy;
|
||||
import static se.scalablesolutions.akka.kernel.config.JavaConfig.*;
|
||||
import se.scalablesolutions.akka.kernel.Kernel;
|
||||
import se.scalablesolutions.akka.kernel.TransactionalMap;
|
||||
|
|
@ -29,11 +24,11 @@ public class PersistentStateTest extends TestCase {
|
|||
|
||||
protected void setUp() {
|
||||
conf.configureActiveObjects(
|
||||
new JavaConfig.RestartStrategy(new JavaConfig.AllForOne(), 3, 5000),
|
||||
new RestartStrategy(new AllForOne(), 3, 5000),
|
||||
new Component[] {
|
||||
new Component("persistent-stateful", PersistentStateful.class, PersistentStatefulImpl.class, new LifeCycle(new Permanent(), 1000), 10000000),
|
||||
new Component("persistent-failer", PersistentFailer.class, PersistentFailerImpl.class, new LifeCycle(new Permanent(), 1000), 1000),
|
||||
new Component("persistent-clasher", PersistentClasher.class, PersistentClasherImpl.class, new LifeCycle(new Permanent(), 1000), 100000)
|
||||
new Component(PersistentStateful.class, new LifeCycle(new Permanent(), 1000), 10000000),
|
||||
new Component(PersistentFailer.class, new LifeCycle(new Permanent(), 1000), 1000),
|
||||
new Component(PersistentClasher.class, new LifeCycle(new Permanent(), 1000), 100000)
|
||||
}).supervise();
|
||||
}
|
||||
|
||||
|
|
@ -61,96 +56,3 @@ public class PersistentStateTest extends TestCase {
|
|||
assertEquals("init", stateful.getState("testShouldRollbackStateForStatefulServerInCaseOfFailure")); // check that state is == init state
|
||||
}
|
||||
}
|
||||
|
||||
interface PersistentStateful {
|
||||
@transactional
|
||||
public void success(String key, String msg);
|
||||
|
||||
@transactional
|
||||
public void failure(String key, String msg, PersistentFailer failer);
|
||||
|
||||
@transactional
|
||||
public void clashOk(String key, String msg, PersistentClasher clasher);
|
||||
|
||||
@transactional
|
||||
public void clashNotOk(String key, String msg, PersistentClasher clasher);
|
||||
|
||||
public String getState(String key);
|
||||
|
||||
public void setState(String key, String value);
|
||||
}
|
||||
|
||||
class PersistentStatefulImpl implements PersistentStateful {
|
||||
private TransactionalMap state = new CassandraPersistentTransactionalMap(this);
|
||||
|
||||
public String getState(String key) {
|
||||
return (String)state.get(key).get();
|
||||
}
|
||||
|
||||
public void setState(String key, String msg) {
|
||||
state.put(key, msg);
|
||||
}
|
||||
|
||||
public void success(String key, String msg) {
|
||||
state.put(key, msg);
|
||||
}
|
||||
|
||||
public void failure(String key, String msg, PersistentFailer failer) {
|
||||
state.put(key, msg);
|
||||
failer.fail();
|
||||
}
|
||||
|
||||
public void clashOk(String key, String msg, PersistentClasher clasher) {
|
||||
state.put(key, msg);
|
||||
clasher.clash();
|
||||
}
|
||||
|
||||
public void clashNotOk(String key, String msg, PersistentClasher clasher) {
|
||||
state.put(key, msg);
|
||||
clasher.clash();
|
||||
clasher.clash();
|
||||
}
|
||||
}
|
||||
|
||||
interface PersistentFailer {
|
||||
public void fail();
|
||||
}
|
||||
|
||||
class PersistentFailerImpl implements PersistentFailer {
|
||||
public void fail() {
|
||||
throw new RuntimeException("expected");
|
||||
}
|
||||
}
|
||||
|
||||
interface PersistentClasher {
|
||||
public void clash();
|
||||
|
||||
public String getState(String key);
|
||||
|
||||
public void setState(String key, String value);
|
||||
}
|
||||
|
||||
class PersistentClasherImpl implements PersistentClasher {
|
||||
private TransactionalMap state = new CassandraPersistentTransactionalMap(this);
|
||||
|
||||
public String getState(String key) {
|
||||
return (String)state.get(key).get();
|
||||
}
|
||||
|
||||
public void setState(String key, String msg) {
|
||||
state.put(key, msg);
|
||||
}
|
||||
|
||||
public void clash() {
|
||||
state.put("clasher", "was here");
|
||||
// spend some time here
|
||||
|
||||
// FIXME: this statement gives me this error:
|
||||
// se.scalablesolutions.akka.kernel.ActiveObjectException:
|
||||
// Unexpected message [!(scala.actors.Channel@c2b2f6,ErrRef[Right(null)])]
|
||||
// to
|
||||
// [GenericServer[se.scalablesolutions.akka.api.StatefulImpl]] from
|
||||
// [GenericServer[se.scalablesolutions.akka.api.ClasherImpl]]]
|
||||
// try { Thread.sleep(1000); } catch (InterruptedException e) {}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
package se.scalablesolutions.akka.api;
|
||||
|
||||
import se.scalablesolutions.akka.kernel.TransactionalMap;
|
||||
import se.scalablesolutions.akka.kernel.CassandraPersistentTransactionalMap;
|
||||
import se.scalablesolutions.akka.annotation.transactional;
|
||||
|
||||
public class PersistentStateful {
|
||||
private TransactionalMap state = new CassandraPersistentTransactionalMap(this);
|
||||
|
||||
public String getState(String key) {
|
||||
return (String)state.get(key).get();
|
||||
}
|
||||
|
||||
public void setState(String key, String msg) {
|
||||
state.put(key, msg);
|
||||
}
|
||||
|
||||
@transactional
|
||||
public void success(String key, String msg) {
|
||||
state.put(key, msg);
|
||||
}
|
||||
|
||||
@transactional
|
||||
public void failure(String key, String msg, PersistentFailer failer) {
|
||||
state.put(key, msg);
|
||||
failer.fail();
|
||||
}
|
||||
|
||||
@transactional
|
||||
public void clashOk(String key, String msg, PersistentClasher clasher) {
|
||||
state.put(key, msg);
|
||||
clasher.clash();
|
||||
}
|
||||
|
||||
@transactional
|
||||
public void clashNotOk(String key, String msg, PersistentClasher clasher) {
|
||||
state.put(key, msg);
|
||||
clasher.clash();
|
||||
clasher.clash();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
package se.scalablesolutions.akka.api;
|
||||
|
||||
import com.sun.jersey.api.container.grizzly.GrizzlyWebContainerFactory;
|
||||
import com.sun.jersey.api.client.Client;
|
||||
import com.sun.jersey.api.client.WebResource;
|
||||
import com.sun.grizzly.http.SelectorThread;
|
||||
|
|
@ -18,7 +17,6 @@ import javax.servlet.Servlet;
|
|||
import org.junit.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Map;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
|
|
@ -39,9 +37,7 @@ public class RestTest extends TestSuite {
|
|||
new JavaConfig.RestartStrategy(new JavaConfig.AllForOne(), 3, 5000),
|
||||
new JavaConfig.Component[] {
|
||||
new JavaConfig.Component(
|
||||
"jersey-foo",
|
||||
JerseyFoo.class,
|
||||
JerseyFooImpl.class,
|
||||
new JavaConfig.LifeCycle(new JavaConfig.Permanent(), 1000), 10000000)
|
||||
}).inject().supervise();
|
||||
selector = startJersey();
|
||||
|
|
|
|||
|
|
@ -10,10 +10,11 @@ import config.ScalaConfig._
|
|||
|
||||
import java.util.{List => JList, ArrayList}
|
||||
import java.lang.reflect.{Method, Field}
|
||||
import java.lang.annotation.Annotation
|
||||
|
||||
import org.codehaus.aspectwerkz.intercept.{Advisable, AroundAdvice}
|
||||
import org.codehaus.aspectwerkz.joinpoint.{MethodRtti, JoinPoint}
|
||||
import org.codehaus.aspectwerkz.proxy.Proxy
|
||||
import java.lang.annotation.Annotation
|
||||
|
||||
import org.apache.camel.{Processor, Exchange}
|
||||
|
||||
|
|
@ -39,11 +40,11 @@ class ActiveObjectFactory {
|
|||
}
|
||||
|
||||
def newInstance[T](intf: Class[T], target: AnyRef, server: GenericServerContainer): T = {
|
||||
ActiveObject.newInstance(intf, target, server)
|
||||
ActiveObject.newInstance(intf, target, server)
|
||||
}
|
||||
|
||||
def supervise(restartStrategy: RestartStrategy, components: JList[Worker]): Supervisor =
|
||||
ActiveObject.supervise(restartStrategy, components.toArray.toList.asInstanceOf[List[Worker]])
|
||||
def supervise(restartStrategy: RestartStrategy, components: List[Worker]): Supervisor =
|
||||
ActiveObject.supervise(restartStrategy, components)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -61,13 +62,13 @@ object ActiveObject {
|
|||
def newInstance[T](target: Class[T], server: GenericServerContainer): T = {
|
||||
val proxy = Proxy.newInstance(target, false, true)
|
||||
// FIXME switch to weaving in the aspect at compile time
|
||||
proxy.asInstanceOf[Advisable].aw_addAdvice("execution(* *.*(..))", new ActorAroundAdvice(target, proxy, server))
|
||||
proxy.asInstanceOf[Advisable].aw_addAdvice("execution(* *.*(..))", new TransactionalAroundAdvice(target, proxy, server))
|
||||
proxy.asInstanceOf[T]
|
||||
}
|
||||
|
||||
def newInstance[T](intf: Class[T], target: AnyRef, server: GenericServerContainer): T = {
|
||||
val proxy = Proxy.newInstance(Array(intf), Array(target), false, true)
|
||||
proxy.asInstanceOf[Advisable].aw_addAdvice("execution(* *.*(..))", new ActorAroundAdvice(intf, target, server))
|
||||
proxy.asInstanceOf[Advisable].aw_addAdvice("execution(* *.*(..))", new TransactionalAroundAdvice(intf, target, server))
|
||||
proxy.asInstanceOf[T]
|
||||
}
|
||||
|
||||
|
|
@ -79,16 +80,6 @@ object ActiveObject {
|
|||
supervisor ! se.scalablesolutions.akka.kernel.Start
|
||||
supervisor
|
||||
}
|
||||
|
||||
/*
|
||||
private def supervise(proxy: AnyRef): Supervisor =
|
||||
supervise(
|
||||
RestartStrategy(OneForOne, 5, 1000),
|
||||
Worker(
|
||||
proxy.server,
|
||||
LifeCycle(Permanent, 100))
|
||||
:: Nil)
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -96,30 +87,27 @@ object ActiveObject {
|
|||
*/
|
||||
|
||||
// FIXME: STM that allows concurrent updates, detects collision, rolls back and restarts
|
||||
sealed class ActorAroundAdvice(target: Class[_],
|
||||
targetInstance: AnyRef,
|
||||
val server: GenericServerContainer) extends AroundAdvice {
|
||||
val (maps, vectors, refs) = getTransactionalItemsFor(targetInstance)
|
||||
sealed class TransactionalAroundAdvice(target: Class[_],
|
||||
targetInstance: AnyRef,
|
||||
server: GenericServerContainer) extends AroundAdvice {
|
||||
val (maps, vectors, refs) = getTransactionalItemsFor(targetInstance)
|
||||
server.transactionalRefs = refs
|
||||
server.transactionalMaps = maps
|
||||
server.transactionalVectors = vectors
|
||||
|
||||
import ActiveObject.threadBoundTx
|
||||
private[this] var activeTx: Option[Transaction] = None
|
||||
|
||||
|
||||
def invoke(joinpoint: JoinPoint): AnyRef = {
|
||||
// FIXME: switch to using PCD annotation matching, break out into its own aspect + switch to StaticJoinPoint
|
||||
val method = joinpoint.getRtti.asInstanceOf[MethodRtti].getMethod
|
||||
val rtti = joinpoint.getRtti.asInstanceOf[MethodRtti]
|
||||
val method = rtti.getMethod
|
||||
if (method.isAnnotationPresent(Annotations.transactional)) {
|
||||
if (activeTx.isDefined) {
|
||||
val tx = activeTx.get
|
||||
//val cflowTx = threadBoundTx.get
|
||||
// if (cflowTx.isDefined && cflowTx.get != tx) {
|
||||
// new tx in scope; try to commit
|
||||
tx.commit(server)
|
||||
threadBoundTx.set(None)
|
||||
activeTx = None
|
||||
// }
|
||||
}
|
||||
// FIXME: check if we are already in a transaction if so NEST (set parent)
|
||||
val newTx = new Transaction
|
||||
|
|
@ -134,37 +122,14 @@ sealed class ActorAroundAdvice(target: Class[_],
|
|||
activeTx = Some(currentTx)
|
||||
}
|
||||
activeTx = threadBoundTx.get
|
||||
invoke(joinpoint, activeTx)
|
||||
//invoke(Invocation(method, joinpoint.getRtti.asInstanceOf[MethodRtti].getParameterValues, targetInstance, activeTx))
|
||||
}
|
||||
|
||||
private def invoke(joinpoint: JoinPoint, tx: Option[Transaction]): AnyRef = {
|
||||
// FIXME: switch to using PCD annotation matching, break out into its own aspect + switch to StaticJoinPoint
|
||||
val result: AnyRef =
|
||||
/*
|
||||
if (joinpoint.target.isInstanceOf[MessageDriven] &&
|
||||
joinpoint.method.getName == "onMessage") {
|
||||
val m = joinpoint.method
|
||||
|
||||
val endpointName = m.getDeclaringClass.getName + "." + m.getName
|
||||
val activeObjectName = m.getDeclaringClass.getName
|
||||
val endpoint = conf.getRoutingEndpoint(conf.lookupUriFor(m))
|
||||
val producer = endpoint.createProducer
|
||||
val exchange = endpoint.createExchange
|
||||
exchange.getIn().setBody(joinpoint)
|
||||
producer.process(exchange)
|
||||
val fault = exchange.getException();
|
||||
if (fault != null) throw new InvocationTargetException(fault)
|
||||
|
||||
// FIXME: need some timeout and future here...
|
||||
exchange.getOut.getBody
|
||||
|
||||
} else */
|
||||
// FIXME: switch to using PCD annotation matching, break out into its own aspect + switch to StaticJoinPoint
|
||||
if (joinpoint.getRtti.asInstanceOf[MethodRtti].getMethod.isAnnotationPresent(Annotations.oneway)) {
|
||||
server ! (tx, joinpoint)
|
||||
if (rtti.getMethod.isAnnotationPresent(Annotations.oneway)) {
|
||||
server ! (activeTx, joinpoint)
|
||||
} else {
|
||||
val result: ErrRef[AnyRef] =
|
||||
server !!! ((tx, joinpoint), {
|
||||
server !!! ((activeTx, joinpoint), {
|
||||
var ref = ErrRef(activeTx)
|
||||
ref() = throw new ActiveObjectInvocationTimeoutException("Invocation to active object [" + targetInstance.getClass.getName + "] timed out after " + server.timeout + " milliseconds")
|
||||
ref
|
||||
|
|
@ -172,8 +137,7 @@ sealed class ActorAroundAdvice(target: Class[_],
|
|||
try {
|
||||
result()
|
||||
} catch {
|
||||
case e =>
|
||||
println("$$$$$$$$$$$$$$ " + joinpoint)
|
||||
case e =>
|
||||
rollback(result.tx)
|
||||
throw e
|
||||
}
|
||||
|
|
@ -190,29 +154,41 @@ sealed class ActorAroundAdvice(target: Class[_],
|
|||
threadBoundTx.set(Some(tx))
|
||||
}
|
||||
|
||||
private def getTransactionalItemsFor(targetInstance: AnyRef):
|
||||
/**
|
||||
* Search for transactional items for a specific target instance, crawl the class hierarchy recursively up to the top.
|
||||
*/
|
||||
private def getTransactionalItemsFor(targetInstance: AnyRef):
|
||||
Tuple3[List[TransactionalMap[_, _]], List[TransactionalVector[_]], List[TransactionalRef[_]]] = {
|
||||
require(targetInstance != null)
|
||||
var maps: List[TransactionalMap[_, _]] = Nil
|
||||
var vectors: List[TransactionalVector[_]] = Nil
|
||||
var refs: List[TransactionalRef[_]] = Nil
|
||||
var maps: List[TransactionalMap[_, _]] = Nil
|
||||
var refs: List[TransactionalRef[_]] = Nil
|
||||
var vectors: List[TransactionalVector[_]] = Nil
|
||||
|
||||
def getTransactionalItemsFor(target: Class[_]):
|
||||
Tuple3[List[TransactionalMap[_, _]], List[TransactionalVector[_]], List[TransactionalRef[_]]] = {
|
||||
for {
|
||||
field <- targetInstance.getClass.getDeclaredFields.toArray.toList.asInstanceOf[List[Field]]
|
||||
fieldType = field.getType
|
||||
if fieldType == classOf[TransactionalMap[_, _]] ||
|
||||
fieldType == classOf[TransactionalVector[_]] ||
|
||||
fieldType == classOf[TransactionalRef[_]]
|
||||
txItem = {
|
||||
field.setAccessible(true)
|
||||
field.get(targetInstance)
|
||||
field <- target.getDeclaredFields.toArray.toList.asInstanceOf[List[Field]]
|
||||
fieldType = field.getType
|
||||
if fieldType == classOf[TransactionalMap[_, _]] ||
|
||||
fieldType == classOf[TransactionalVector[_]] ||
|
||||
fieldType == classOf[TransactionalRef[_]]
|
||||
txItem = {
|
||||
field.setAccessible(true)
|
||||
field.get(targetInstance)
|
||||
}
|
||||
if txItem != null
|
||||
} {
|
||||
if (txItem.isInstanceOf[TransactionalMap[_, _]]) maps ::= txItem.asInstanceOf[TransactionalMap[_, _]]
|
||||
else if (txItem.isInstanceOf[TransactionalRef[_]]) refs ::= txItem.asInstanceOf[TransactionalRef[_]]
|
||||
else if (txItem.isInstanceOf[TransactionalVector[_]]) vectors ::= txItem.asInstanceOf[TransactionalVector[_]]
|
||||
}
|
||||
if txItem != null
|
||||
} {
|
||||
if (txItem.isInstanceOf[TransactionalMap[_, _]]) maps ::= txItem.asInstanceOf[TransactionalMap[_, _]]
|
||||
else if (txItem.isInstanceOf[TransactionalRef[_]]) refs ::= txItem.asInstanceOf[TransactionalRef[_]]
|
||||
else if (txItem.isInstanceOf[TransactionalVector[_]]) vectors ::= txItem.asInstanceOf[TransactionalVector[_]]
|
||||
val parent = target.getSuperclass
|
||||
if (parent == null) (maps, vectors, refs)
|
||||
else getTransactionalItemsFor(parent)
|
||||
}
|
||||
(maps, vectors, refs)
|
||||
|
||||
// start the search for transactional items, crawl the class hierarchy up until we reach 'null'
|
||||
getTransactionalItemsFor(targetInstance.getClass)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -244,60 +220,10 @@ private[kernel] class Dispatcher(val targetName: String) extends GenericServer {
|
|||
case unexpected =>
|
||||
throw new ActiveObjectException("Unexpected message [" + unexpected + "] to [" + this + "] from [" + sender + "]")
|
||||
}
|
||||
|
||||
|
||||
override def toString(): String = "GenericServer[" + targetName + "]"
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a snapshot of the current invocation.
|
||||
*
|
||||
* @author <a href="http://jonasboner.com">Jonas Bonér</a>
|
||||
*/
|
||||
private[kernel] case class Invocation(val method: Method,
|
||||
val args: Array[AnyRef],
|
||||
val target: AnyRef,
|
||||
val tx: Option[Transaction]) {
|
||||
method.setAccessible(true)
|
||||
|
||||
def invoke: AnyRef = synchronized {
|
||||
println("======== " + this.toString)
|
||||
if (method.getDeclaringClass.isInterface) {
|
||||
target.getClass.getDeclaredMethod(method.getName, method.getParameterTypes).invoke(target, args:_*)
|
||||
} else method.invoke(target, args:_*)
|
||||
}
|
||||
|
||||
override def toString: String = synchronized {
|
||||
"Invocation [method: " + method.getName + ", args: " + argsToString(args) + ", target: " + target + "]"
|
||||
}
|
||||
|
||||
override def hashCode(): Int = synchronized {
|
||||
var result = HashCode.SEED
|
||||
result = HashCode.hash(result, method)
|
||||
result = HashCode.hash(result, args)
|
||||
result = HashCode.hash(result, target)
|
||||
result
|
||||
}
|
||||
|
||||
override def equals(that: Any): Boolean = synchronized {
|
||||
that != null &&
|
||||
that.isInstanceOf[Invocation] &&
|
||||
that.asInstanceOf[Invocation].method == method &&
|
||||
that.asInstanceOf[Invocation].target == target &&
|
||||
isEqual(that.asInstanceOf[Invocation].args, args)
|
||||
}
|
||||
|
||||
private[this] def isEqual(a1: Array[Object], a2: Array[Object]): Boolean =
|
||||
(a1 == null && a2 == null) ||
|
||||
(a1 != null &&
|
||||
a2 != null &&
|
||||
a1.size == a2.size &&
|
||||
a1.zip(a2).find(t => t._1 == t._2).isDefined)
|
||||
|
||||
private[this] def argsToString(array: Array[Object]): String =
|
||||
array.foldLeft("(")(_ + " " + _) + ")"
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
ublic class CamelInvocationHandler implements InvocationHandler {
|
||||
private final Endpoint endpoint;
|
||||
|
|
@ -332,4 +258,24 @@ ublic class CamelInvocationHandler implements InvocationHandler {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (joinpoint.target.isInstanceOf[MessageDriven] &&
|
||||
joinpoint.method.getName == "onMessage") {
|
||||
val m = joinpoint.method
|
||||
|
||||
val endpointName = m.getDeclaringClass.getName + "." + m.getName
|
||||
val activeObjectName = m.getDeclaringClass.getName
|
||||
val endpoint = conf.getRoutingEndpoint(conf.lookupUriFor(m))
|
||||
val producer = endpoint.createProducer
|
||||
val exchange = endpoint.createExchange
|
||||
exchange.getIn().setBody(joinpoint)
|
||||
producer.process(exchange)
|
||||
val fault = exchange.getException();
|
||||
if (fault != null) throw new InvocationTargetException(fault)
|
||||
|
||||
// FIXME: need some timeout and future here...
|
||||
exchange.getOut.getBody
|
||||
|
||||
} else
|
||||
|
||||
*/
|
||||
|
|
@ -23,6 +23,7 @@ case class HotSwap(code: Option[PartialFunction[Any, Unit]]) extends GenericServ
|
|||
* @author <a href="http://jonasboner.com">Jonas Bonér</a>
|
||||
*/
|
||||
trait GenericServer extends Actor {
|
||||
private val actorScheduler = new ManagedActorScheduler
|
||||
|
||||
/**
|
||||
* Template method implementing the server logic.
|
||||
|
|
@ -62,6 +63,8 @@ trait GenericServer extends Actor {
|
|||
|
||||
def act = loop { react { genericBase orElse actorBase } }
|
||||
|
||||
//override protected def scheduler = actorScheduler
|
||||
|
||||
private def actorBase: PartialFunction[Any, Unit] = hotswap getOrElse body
|
||||
|
||||
private var hotswap: Option[PartialFunction[Any, Unit]] = None
|
||||
|
|
@ -226,6 +229,7 @@ class GenericServerContainer(
|
|||
*/
|
||||
def !!: T = {
|
||||
require(server != null)
|
||||
println("---------- SERVER " + server + " MESSAGE " + message)
|
||||
val future: FutureWithTimeout[T] = lock.withReadLock { server !!! message }
|
||||
future.receiveWithin(time) match {
|
||||
case None => errorHandler
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Copyright (C) 2009 Scalable Solutions.
|
||||
*/
|
||||
* Copyright (C) 2009 Scalable Solutions.
|
||||
*/
|
||||
|
||||
package se.scalablesolutions.akka.kernel
|
||||
|
||||
|
|
@ -12,9 +12,45 @@ import scala.actors.{FJTaskScheduler2, Scheduler, IScheduler, Actor}
|
|||
|
||||
// FIXME: add managing interface to this class using JMX
|
||||
// FIXME: configure one instance per GenericServer
|
||||
object ManagedActorScheduler extends Logging {
|
||||
|
||||
class ManagedActorScheduler extends IScheduler with Logging {
|
||||
protected var threadPoolSize = 10
|
||||
protected val threadPool = Executors.newFixedThreadPool(threadPoolSize)
|
||||
|
||||
def execute(fun: => Unit): Unit = threadPool.execute(new Runnable {
|
||||
def run = {
|
||||
try {
|
||||
fun
|
||||
} catch {
|
||||
case e => log.error("Actor scheduler", e)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
def execute(task: Runnable) = threadPool.execute(new Runnable {
|
||||
def run = {
|
||||
try {
|
||||
task.run
|
||||
} catch {
|
||||
case e => log.error("Actor scheduler", e)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
def tick(a: Actor): Unit = {}
|
||||
|
||||
def shutdown: Unit = threadPool.shutdown
|
||||
|
||||
def onLockup(handler: () => Unit): Unit = {}
|
||||
|
||||
def onLockup(millis: Int)(handler: () => Unit): Unit = {}
|
||||
|
||||
def printActorDump: Unit = {}
|
||||
}
|
||||
|
||||
object GlobalManagedActorScheduler extends Logging {
|
||||
@volatile private var isRegistered = false
|
||||
private var threadPoolSize = 10
|
||||
private var threadPoolSize = 10
|
||||
|
||||
def register = synchronized {
|
||||
if (!isRegistered) {
|
||||
|
|
@ -24,38 +60,8 @@ object ManagedActorScheduler extends Logging {
|
|||
fj.shutdown
|
||||
case _ =>
|
||||
}
|
||||
|
||||
Scheduler.impl = {
|
||||
val threadPool = Executors.newFixedThreadPool(threadPoolSize)
|
||||
new IScheduler {
|
||||
def execute(fun: => Unit): Unit = threadPool.execute(new Runnable {
|
||||
def run = {
|
||||
try {
|
||||
fun
|
||||
} catch {
|
||||
case e => log.error("Actor scheduler", e)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
def execute(task: Runnable) = es.execute(new Runnable {
|
||||
def run = {
|
||||
try {
|
||||
task.run
|
||||
} catch {
|
||||
case e => log.error("Actor scheduler", e)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
def tick(a: Actor): Unit = {}
|
||||
def shutdown: Unit = { threadPool.shutdown }
|
||||
def onLockup(handler: () => Unit): Unit = {}
|
||||
def onLockup(millis: Int)(handler: () => Unit): Unit = {}
|
||||
def printActorDump: Unit = {}
|
||||
}
|
||||
}
|
||||
Scheduler.impl = new ManagedActorScheduler
|
||||
isRegistered = true
|
||||
}
|
||||
isRegistered = true
|
||||
}
|
||||
}
|
||||
|
|
@ -29,9 +29,10 @@ class ActiveObjectGuiceConfigurator extends ActiveObjectConfigurator with CamelC
|
|||
private var supervisor: Supervisor = _
|
||||
private var restartStrategy: RestartStrategy = _
|
||||
private var components: List[Component] = _
|
||||
private var workers: List[Worker] = Nil
|
||||
private var bindings: List[DependencyBinding] = Nil
|
||||
private var configRegistry = new HashMap[Class[_], Component] // TODO is configRegistry needed?
|
||||
private var activeObjectRegistry = new HashMap[Class[_], Tuple2[Component, GenericServerContainer]]
|
||||
private var activeObjectRegistry = new HashMap[Class[_], Tuple4[AnyRef, AnyRef, Component, GenericServerContainer]]
|
||||
private var activeObjectFactory = new ActiveObjectFactory
|
||||
private var camelContext = new DefaultCamelContext
|
||||
private var modules = new java.util.ArrayList[Module]
|
||||
|
|
@ -44,23 +45,14 @@ class ActiveObjectGuiceConfigurator extends ActiveObjectConfigurator with CamelC
|
|||
* @return the active object for the class
|
||||
*/
|
||||
override def getActiveObject[T](clazz: Class[T]): T = synchronized {
|
||||
log.debug("Creating new active object [%s]", clazz.getName)
|
||||
log.debug("Retrieving active object [%s]", clazz.getName)
|
||||
if (injector == null) throw new IllegalStateException("inject() and/or supervise() must be called before invoking getActiveObject(clazz)")
|
||||
val activeObjectOption: Option[Tuple2[Component, GenericServerContainer]] = activeObjectRegistry.get(clazz)
|
||||
if (activeObjectOption.isDefined) {
|
||||
val (component, server) = activeObjectOption.get
|
||||
server.setTimeout(component.timeout)
|
||||
val proxy = if (component.intf == null) { // subclassing proxy
|
||||
activeObjectFactory.newInstance(component.target, server).asInstanceOf[T]
|
||||
} else { // delegating proxy
|
||||
component.target.getConstructor(Array[Class[_]]()).setAccessible(true)
|
||||
val targetInstance = component.target.newInstance.asInstanceOf[AnyRef] // TODO: perhaps need to put in registry
|
||||
activeObjectFactory.newInstance(component.intf, targetInstance, server).asInstanceOf[T]
|
||||
}
|
||||
injector.injectMembers(proxy)
|
||||
proxy
|
||||
} else throw new IllegalStateException("Class [" + clazz.getName + "] has not been put under supervision (by passing in the config to the 'supervise') method")
|
||||
val (proxy, targetInstance, component, server) =
|
||||
activeObjectRegistry.getOrElse(clazz, throw new IllegalStateException("Class [" + clazz.getName + "] has not been put under supervision (by passing in the config to the 'configureActiveObjects' and then invoking 'supervise') method"))
|
||||
injector.injectMembers(targetInstance)
|
||||
proxy.asInstanceOf[T]
|
||||
}
|
||||
|
||||
/*
|
||||
override def getActiveObjectProxy(clazz: Class[_]): ActiveObjectProxy = synchronized {
|
||||
log.debug("Looking up active object proxy [%s]", clazz.getName)
|
||||
|
|
@ -74,8 +66,12 @@ class ActiveObjectGuiceConfigurator extends ActiveObjectConfigurator with CamelC
|
|||
injector.getInstance(clazz).asInstanceOf[T]
|
||||
}
|
||||
|
||||
override def getComponentInterfaces: List[Class[_]] = components.map(_.intf)
|
||||
|
||||
override def getComponentInterfaces: List[Class[_]] =
|
||||
for (c <- components) yield {
|
||||
if (c.intf.isDefined) c.intf.get
|
||||
else c.target
|
||||
}
|
||||
|
||||
override def getRoutingEndpoint(uri: String): Endpoint = synchronized {
|
||||
camelContext.getEndpoint(uri)
|
||||
}
|
||||
|
|
@ -88,17 +84,46 @@ class ActiveObjectGuiceConfigurator extends ActiveObjectConfigurator with CamelC
|
|||
camelContext.getEndpoints(uri)
|
||||
}
|
||||
|
||||
override def configureActiveObjects(restartStrategy: RestartStrategy, components: List[Component]): ActiveObjectConfigurator = synchronized {
|
||||
override def configureActiveObjects(
|
||||
restartStrategy: RestartStrategy,
|
||||
components: List[Component]): ActiveObjectConfigurator = synchronized {
|
||||
this.restartStrategy = restartStrategy
|
||||
this.components = components.toArray.toList.asInstanceOf[List[Component]]
|
||||
bindings = for (c <- this.components)
|
||||
yield new DependencyBinding(c.intf, c.target) // build up the Guice interface class -> impl class bindings
|
||||
bindings = for (component <- this.components) yield {
|
||||
if (component.intf.isDefined) newDelegatingProxy(component)
|
||||
else newSubclassingProxy(component)
|
||||
}
|
||||
//camelContext.getRegistry.asInstanceOf[JndiRegistry].bind(component.name, activeObjectProxy)
|
||||
//for (method <- component.intf.getDeclaredMethods.toList) registerMethodForUri(method, component.name)
|
||||
//log.debug("Registering active object in Camel context under the name [%s]", component.target.getName)
|
||||
val deps = new java.util.ArrayList[DependencyBinding](bindings.size)
|
||||
for (b <- bindings) deps.add(b)
|
||||
modules.add(new ActiveObjectGuiceModule(deps))
|
||||
this
|
||||
}
|
||||
|
||||
private def newSubclassingProxy(component: Component): DependencyBinding = {
|
||||
val targetClass = component.target
|
||||
val server = new GenericServerContainer(targetClass.getName, () => new Dispatcher(component.target.getName))
|
||||
server.setTimeout(component.timeout)
|
||||
workers ::= Worker(server, component.lifeCycle)
|
||||
val proxy = activeObjectFactory.newInstance(targetClass, server).asInstanceOf[AnyRef]
|
||||
activeObjectRegistry.put(targetClass, (proxy, proxy, component, server))
|
||||
new DependencyBinding(targetClass, proxy)
|
||||
}
|
||||
|
||||
private def newDelegatingProxy(component: Component): DependencyBinding = {
|
||||
val targetClass = component.intf.get
|
||||
val server = new GenericServerContainer(targetClass.getName, () => new Dispatcher(component.target.getName))
|
||||
server.setTimeout(component.timeout)
|
||||
workers ::= Worker(server, component.lifeCycle)
|
||||
component.target.getConstructor(Array[Class[_]]()).setAccessible(true)
|
||||
val targetInstance = component.target.newInstance.asInstanceOf[AnyRef] // TODO: perhaps need to put in registry
|
||||
val proxy = activeObjectFactory.newInstance(targetClass, targetInstance, server).asInstanceOf[AnyRef]
|
||||
activeObjectRegistry.put(targetClass, (proxy, targetInstance, component, server))
|
||||
new DependencyBinding(targetClass, proxy)
|
||||
}
|
||||
|
||||
override def inject: ActiveObjectConfigurator = synchronized {
|
||||
if (injector != null) throw new IllegalStateException("inject() has already been called on this configurator")
|
||||
injector = Guice.createInjector(modules)
|
||||
|
|
@ -107,17 +132,6 @@ class ActiveObjectGuiceConfigurator extends ActiveObjectConfigurator with CamelC
|
|||
|
||||
override def supervise: ActiveObjectConfigurator = synchronized {
|
||||
if (injector == null) inject
|
||||
var workers = new java.util.ArrayList[Worker]
|
||||
for (component <- components) {
|
||||
val target = if (component.intf != null) component.intf // TODO: use Option
|
||||
else component.target
|
||||
val server = new GenericServerContainer(target.getName, () => new Dispatcher(component.target.getName))
|
||||
activeObjectRegistry.put(target, (component, server))
|
||||
workers.add(Worker(server, component.lifeCycle))
|
||||
//camelContext.getRegistry.asInstanceOf[JndiRegistry].bind(component.name, activeObjectProxy)
|
||||
for (method <- component.intf.getDeclaredMethods.toList) registerMethodForUri(method, component.name)
|
||||
log.debug("Registering active object in Camel context under the name [%s]", component.target.getName)
|
||||
}
|
||||
supervisor = activeObjectFactory.supervise(restartStrategy, workers)
|
||||
//camelContext.addComponent(AKKA_CAMEL_ROUTING_SCHEME, new ActiveObjectComponent(this))
|
||||
//camelContext.start
|
||||
|
|
@ -154,7 +168,7 @@ class ActiveObjectGuiceConfigurator extends ActiveObjectConfigurator with CamelC
|
|||
def reset = synchronized {
|
||||
modules = new java.util.ArrayList[Module]
|
||||
configRegistry = new HashMap[Class[_], Component]
|
||||
activeObjectRegistry = new HashMap[Class[_], Tuple2[Component, GenericServerContainer]]
|
||||
activeObjectRegistry = new HashMap[Class[_], Tuple4[AnyRef, AnyRef, Component, GenericServerContainer]]
|
||||
methodToUriRegistry = new HashMap[Method, String]
|
||||
injector = null
|
||||
restartStrategy = null
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ class ActiveObjectGuiceConfiguratorForJava {
|
|||
this
|
||||
}
|
||||
|
||||
|
||||
def getComponentInterfaces: List[Class[_]] = {
|
||||
val al = new ArrayList[Class[_]]
|
||||
for (c <- INSTANCE.getComponentInterfaces) al.add(c)
|
||||
|
|
|
|||
|
|
@ -33,11 +33,18 @@ object ScalaConfig {
|
|||
case object Transient extends Scope
|
||||
case object Temporary extends Scope
|
||||
|
||||
case class Component(val name: String,
|
||||
val intf: Class[_],
|
||||
class Component(_intf: Class[_],
|
||||
val target: Class[_],
|
||||
val lifeCycle: LifeCycle,
|
||||
val timeout: Int) extends Server
|
||||
val timeout: Int) extends Server {
|
||||
val intf: Option[Class[_]] = if (_intf == null) None else Some(_intf)
|
||||
}
|
||||
object Component {
|
||||
def apply(intf: Class[_], target: Class[_], lifeCycle: LifeCycle, timeout: Int) =
|
||||
new Component(intf, target, lifeCycle, timeout)
|
||||
def apply(target: Class[_], lifeCycle: LifeCycle, timeout: Int) =
|
||||
new Component(null, target, lifeCycle, timeout)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -81,13 +88,14 @@ object JavaConfig {
|
|||
}
|
||||
|
||||
abstract class Server extends ConfigElement
|
||||
class Component(@BeanProperty val name: String,
|
||||
@BeanProperty val intf: Class[_],
|
||||
class Component(@BeanProperty val intf: Class[_],
|
||||
@BeanProperty val target: Class[_],
|
||||
@BeanProperty val lifeCycle: LifeCycle,
|
||||
@BeanProperty val timeout: Int) extends Server {
|
||||
def this(target: Class[_], lifeCycle: LifeCycle, timeout: Int) =
|
||||
this(null, target, lifeCycle, timeout)
|
||||
def transform = se.scalablesolutions.akka.kernel.config.ScalaConfig.Component(
|
||||
name, intf, target, lifeCycle.transform, timeout)
|
||||
intf, target, lifeCycle.transform, timeout)
|
||||
def newWorker(server: GenericServerContainer) =
|
||||
se.scalablesolutions.akka.kernel.config.ScalaConfig.Worker(server, lifeCycle.transform)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,30 +32,29 @@ class JerseySpec extends Spec with ShouldMatchers {
|
|||
|
||||
describe("A Jersey REST service") {
|
||||
it("should ...") {
|
||||
//val selector = startJersey
|
||||
//oselector.start
|
||||
|
||||
val selector = startJersey
|
||||
selector.start
|
||||
/*
|
||||
val conf = new ActiveObjectGuiceConfigurator
|
||||
conf.configureActiveObjects(
|
||||
RestartStrategy(AllForOne, 3, 5000),
|
||||
Component(
|
||||
"jerseyfoo",
|
||||
classOf[resource.JerseyFoo],
|
||||
classOf[resource.JerseyFooImpl],
|
||||
LifeCycle(Permanent, 1000),
|
||||
1000) ::
|
||||
Nil).supervise
|
||||
|
||||
conf.getActiveObject(classOf[resource.JerseyFoo])
|
||||
*/
|
||||
|
||||
/*
|
||||
/*
|
||||
val client = Client.create
|
||||
val webResource = client.resource(UriBuilder.fromUri("http://localhost/").port(9998).build)
|
||||
//val webResource = client.resource("http://localhost:9998/foo")
|
||||
val responseMsg = webResource.get(classOf[String])
|
||||
responseMsg should equal ("Hello World")
|
||||
selector.stopEndpoint
|
||||
*/
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -79,20 +78,14 @@ class JerseySpec extends Spec with ShouldMatchers {
|
|||
package resource {
|
||||
import javax.ws.rs.{Produces, Path, GET}
|
||||
|
||||
trait JerseyFoo {
|
||||
def foo: String
|
||||
}
|
||||
trait JerseyBar {
|
||||
def bar(msg: String): String
|
||||
}
|
||||
|
||||
@Path("/foo")
|
||||
class JerseyFooImpl extends JerseyFoo {
|
||||
class JerseyFoo {
|
||||
@GET
|
||||
@Produces(Array("application/json"))
|
||||
def foo: String = { val ret = "JerseyFoo.foo"; println(ret); ret }
|
||||
}
|
||||
class JerseyBarImpl extends JerseyBar {
|
||||
@Path("/foo")
|
||||
class JerseyFooSub extends JerseyFoo
|
||||
class JerseyBar {
|
||||
def bar(msg: String) = msg + "return_bar "
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,9 @@ public class ActiveObjectGuiceModule extends AbstractModule {
|
|||
bind(ResourceProviderFactory.class);
|
||||
for (int i = 0; i < bindings.size(); i++) {
|
||||
final DependencyBinding db = bindings.get(i);
|
||||
bind((Class) db.getInterface()).to((Class) db.getTarget()).in(Singleton.class);
|
||||
//if (db.getInterface() != null) bind((Class) db.getInterface()).to((Class) db.getTarget()).in(Singleton.class);
|
||||
//else
|
||||
this.bind(db.getInterface()).toInstance(db.getTarget());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,16 +9,16 @@ package se.scalablesolutions.akka.kernel.config;
|
|||
*/
|
||||
public class DependencyBinding {
|
||||
private final Class intf;
|
||||
private final Class target;
|
||||
private final Object target;
|
||||
|
||||
public DependencyBinding(final Class intf, final Class target) {
|
||||
public DependencyBinding(final Class intf, final Object target) {
|
||||
this.intf = intf;
|
||||
this.target = target;
|
||||
}
|
||||
public Class getInterface() {
|
||||
return intf;
|
||||
}
|
||||
public Class getTarget() {
|
||||
public Object getTarget() {
|
||||
return target;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue