Lets start withough any akka or other magic, except for Guice.
I started by creating a chatserver:
public class ChatServer {
@Inject
public ChatServer() {
}
private List<Message> messages = new ArrayList<Message>();
private Set<ChatSession> sessions = new HashSet<ChatSession>();
private Vector<byte[]> storage = new Vector<byte[]>();
public void login(ChatSession chatSession) {
sessions.add(chatSession);
}
public List<Message> getLog() {
return Collections.unmodifiableList(messages);
}
public void sendMessage(Message message) {
storeMessage(message);
for (ChatSession chatSession : sessions) {
chatSession.recieveMessage(message);
}
}
private void storeMessage(Message message) {
messages.add(message);
storage.add(message.toString().getBytes());
}
}
This is just a simple class, that stores messages in byteformat in a vector.It might seem weird to have the Vector store byte[] instead of message, but later we will change it to a PersistentVector, and that uses byte[] to store it in the backend.
And we need some clients:
public class ChatSession {
private String userName;
private final List<Message> messages = new ArrayList<Message>();
@Inject
private ChatServer chatServer;
public void login() {
chatServer.login(this);
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserName() {
return userName;
}
public void recieveMessage(Message message) {
messages.add(message);
}
public void sendMessage(String text) {
Message message = new Message(userName, text);
chatServer.sendMessage(message);
}
public List<Message> getLog() {
return messages;
}
}
Here we inject the Chatserver with @Inject directly on the variable declaration
we can use it in a simple testcase:
public class IntegrationTest {
Module m;
@Before
public void setup() {
m = new AbstractModule() {
@Override
protected void configure() {
bind(ChatSession.class);
bind(ChatServer.class).asEagerSingleton();
}
};
}
@Test
public void integrationTest() throws InterruptedException {
Injector inj = Guice.createInjector(m);
final ChatSession userOne = inj.getInstance(ChatSession.class);
userOne.setUserName("userOne");
userOne.login();
final ChatSession userTwo = inj.getInstance(ChatSession.class);
userTwo.setUserName("userTwo");
userTwo.login();
userOne.sendMessage("Hello");
userTwo.sendMessage("Another Message 1");
Thread.sleep(400); //wait for messages to finish
assertEquals(2, userOne.getLog().size());
assertEquals(2, userTwo.getLog().size());
assertEquals(userTwo.getLog(), userOne.getLog());
}
}
Here we create two chatsessions with our guice injector. And since we have bound ChatServer as a singleton they will have the same instance of chatserver injected.
Now the next step is to add akka to the project. i will add that to a seperate post
Hi Mikael,
SvaraRaderaI don't know much about the active objects, but it seems to me that the ChatServer can be accessed by clients concurrently. If that is the case, you need some form of synchronisation on the internals of the ChatServer.
I think that is one of the points (although i actually don't make that point, maybe i should). Since the ChatServer after beeing transformed by akka and activeobjects, it behaves as an actor. And the synchronisation problem should be solved?
SvaraRaderaalso with the @transactionrequired annotation, everything is done in a transaction, and rolled back and retried if something has changed.
if i have not missunderstood something that is :-)