From f0e53bc049a584e7f6c01a6b45968e40064e4d7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Bon=C3=A9r?= Date: Wed, 17 Mar 2010 14:31:50 +0100 Subject: [PATCH 01/11] moved akka.annotation._ to akka.actor.annotation._ to be merged in with akka-core OSGi bundle --- akka-camel/src/main/scala/service/ConsumerPublisher.scala | 2 +- akka-camel/src/test/scala/service/CamelServiceTest.scala | 2 +- akka-core/src/main/scala/actor/ActiveObject.scala | 2 +- .../src/test/java/se/scalablesolutions/akka/api/Bar.java | 2 +- .../src/test/java/se/scalablesolutions/akka/api/Foo.java | 2 +- .../java/se/scalablesolutions/akka/api/InMemStateful.java | 8 ++++---- .../scalablesolutions/akka/api/InMemStatefulNested.java | 4 ++-- .../se/scalablesolutions/akka/api/PersistentClasher.java | 2 +- .../se/scalablesolutions/akka/api/PersistentStateful.java | 4 ++-- .../akka/api/PersistentStatefulNested.java | 4 ++-- .../akka-sample-camel/src/main/scala/Actors.scala | 2 +- .../main/java/sample/java/PersistentSimpleService.java | 6 +++--- .../src/main/java/sample/java/SimpleService.java | 6 +++--- .../scalablesolutions/akka/annotation/configuration.java | 2 +- .../se/scalablesolutions/akka/annotation/consume.java | 2 +- .../se/scalablesolutions/akka/annotation/immutable.java | 2 +- .../akka/annotation/inittransactionalstate.java | 2 +- .../java/se/scalablesolutions/akka/annotation/oneway.java | 2 +- .../se/scalablesolutions/akka/annotation/postrestart.java | 2 +- .../se/scalablesolutions/akka/annotation/prerestart.java | 2 +- .../java/se/scalablesolutions/akka/annotation/state.java | 2 +- .../akka/annotation/transactionrequired.java | 2 +- 22 files changed, 32 insertions(+), 32 deletions(-) diff --git a/akka-camel/src/main/scala/service/ConsumerPublisher.scala b/akka-camel/src/main/scala/service/ConsumerPublisher.scala index dee30882f1..a6509e2694 100644 --- a/akka-camel/src/main/scala/service/ConsumerPublisher.scala +++ b/akka-camel/src/main/scala/service/ConsumerPublisher.scala @@ -9,7 +9,7 @@ import java.util.concurrent.CountDownLatch import org.apache.camel.builder.RouteBuilder import se.scalablesolutions.akka.actor.{ActorUnregistered, ActorRegistered, Actor} -import se.scalablesolutions.akka.annotation.consume +import se.scalablesolutions.akka.actor.annotation.consume import se.scalablesolutions.akka.camel.{Consumer, CamelContextManager} import se.scalablesolutions.akka.util.Logging diff --git a/akka-camel/src/test/scala/service/CamelServiceTest.scala b/akka-camel/src/test/scala/service/CamelServiceTest.scala index 8fafea4687..a3b0f5c913 100644 --- a/akka-camel/src/test/scala/service/CamelServiceTest.scala +++ b/akka-camel/src/test/scala/service/CamelServiceTest.scala @@ -5,7 +5,7 @@ import org.junit.Assert._ import org.scalatest.junit.JUnitSuite import se.scalablesolutions.akka.actor.Actor -import se.scalablesolutions.akka.annotation.consume +import se.scalablesolutions.akka.actor.annotation.consume import se.scalablesolutions.akka.camel.{CamelContextManager, Consumer, Message} import org.junit.{Ignore, Before, After, Test} diff --git a/akka-core/src/main/scala/actor/ActiveObject.scala b/akka-core/src/main/scala/actor/ActiveObject.scala index d88f0e861b..9b5a6b409a 100644 --- a/akka-core/src/main/scala/actor/ActiveObject.scala +++ b/akka-core/src/main/scala/actor/ActiveObject.scala @@ -19,7 +19,7 @@ import java.net.InetSocketAddress import java.lang.reflect.{InvocationTargetException, Method} object Annotations { - import se.scalablesolutions.akka.annotation._ + import se.scalablesolutions.akka.actor.annotation._ val oneway = classOf[oneway] val transactionrequired = classOf[transactionrequired] val prerestart = classOf[prerestart] diff --git a/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/Bar.java b/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/Bar.java index 9a3ff80aca..3d85d89a17 100644 --- a/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/Bar.java +++ b/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/Bar.java @@ -1,6 +1,6 @@ package se.scalablesolutions.akka.api; -import se.scalablesolutions.akka.annotation.oneway; +import se.scalablesolutions.akka.actor.annotation.oneway; public interface Bar { @oneway diff --git a/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/Foo.java b/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/Foo.java index bb9cfd83d4..962f0b9424 100644 --- a/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/Foo.java +++ b/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/Foo.java @@ -1,7 +1,7 @@ package se.scalablesolutions.akka.api; import com.google.inject.Inject; -import se.scalablesolutions.akka.annotation.oneway; +import se.scalablesolutions.akka.actor.annotation.oneway; public class Foo extends se.scalablesolutions.akka.serialization.Serializable.JavaJSON { @Inject diff --git a/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/InMemStateful.java b/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/InMemStateful.java index 8bc60ad922..afe2f2e232 100644 --- a/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/InMemStateful.java +++ b/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/InMemStateful.java @@ -1,9 +1,9 @@ package se.scalablesolutions.akka.api; -import se.scalablesolutions.akka.annotation.transactionrequired; -import se.scalablesolutions.akka.annotation.prerestart; -import se.scalablesolutions.akka.annotation.postrestart; -import se.scalablesolutions.akka.annotation.inittransactionalstate; +import se.scalablesolutions.akka.actor.annotation.transactionrequired; +import se.scalablesolutions.akka.actor.annotation.prerestart; +import se.scalablesolutions.akka.actor.annotation.postrestart; +import se.scalablesolutions.akka.actor.annotation.inittransactionalstate; import se.scalablesolutions.akka.stm.*; @transactionrequired diff --git a/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/InMemStatefulNested.java b/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/InMemStatefulNested.java index ca6b345766..932dc2c162 100644 --- a/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/InMemStatefulNested.java +++ b/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/InMemStatefulNested.java @@ -1,7 +1,7 @@ package se.scalablesolutions.akka.api; -import se.scalablesolutions.akka.annotation.transactionrequired; -import se.scalablesolutions.akka.annotation.inittransactionalstate; +import se.scalablesolutions.akka.actor.annotation.transactionrequired; +import se.scalablesolutions.akka.actor.annotation.inittransactionalstate; import se.scalablesolutions.akka.stm.*; @transactionrequired diff --git a/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/PersistentClasher.java b/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/PersistentClasher.java index caa755ab83..d5c1bdf00c 100644 --- a/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/PersistentClasher.java +++ b/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/PersistentClasher.java @@ -2,7 +2,7 @@ package se.scalablesolutions.akka.api; import se.scalablesolutions.akka.persistence.common.*; import se.scalablesolutions.akka.persistence.cassandra.*; -import se.scalablesolutions.akka.annotation.inittransactionalstate; +import se.scalablesolutions.akka.actor.annotation.inittransactionalstate; public class PersistentClasher { private PersistentMap state; diff --git a/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/PersistentStateful.java b/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/PersistentStateful.java index 176c551e13..6a8d3353b7 100644 --- a/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/PersistentStateful.java +++ b/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/PersistentStateful.java @@ -1,7 +1,7 @@ package se.scalablesolutions.akka.api; -import se.scalablesolutions.akka.annotation.inittransactionalstate; -import se.scalablesolutions.akka.annotation.transactionrequired; +import se.scalablesolutions.akka.actor.annotation.inittransactionalstate; +import se.scalablesolutions.akka.actor.annotation.transactionrequired; import se.scalablesolutions.akka.persistence.common.*; import se.scalablesolutions.akka.persistence.cassandra.*; diff --git a/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/PersistentStatefulNested.java b/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/PersistentStatefulNested.java index a919279c0a..bd931ef108 100644 --- a/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/PersistentStatefulNested.java +++ b/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/PersistentStatefulNested.java @@ -1,7 +1,7 @@ package se.scalablesolutions.akka.api; -import se.scalablesolutions.akka.annotation.inittransactionalstate; -import se.scalablesolutions.akka.annotation.transactionrequired; +import se.scalablesolutions.akka.actor.annotation.inittransactionalstate; +import se.scalablesolutions.akka.actor.annotation.transactionrequired; import se.scalablesolutions.akka.persistence.common.*; import se.scalablesolutions.akka.persistence.cassandra.*; diff --git a/akka-samples/akka-sample-camel/src/main/scala/Actors.scala b/akka-samples/akka-sample-camel/src/main/scala/Actors.scala index 11367dedb4..c82b29afc9 100644 --- a/akka-samples/akka-sample-camel/src/main/scala/Actors.scala +++ b/akka-samples/akka-sample-camel/src/main/scala/Actors.scala @@ -1,7 +1,7 @@ package sample.camel import se.scalablesolutions.akka.actor.{Actor, RemoteActor} -import se.scalablesolutions.akka.annotation.consume +import se.scalablesolutions.akka.actor.annotation.consume import se.scalablesolutions.akka.camel.{Producer, Message, Consumer} import se.scalablesolutions.akka.util.Logging diff --git a/akka-samples/akka-sample-rest-java/src/main/java/sample/java/PersistentSimpleService.java b/akka-samples/akka-sample-rest-java/src/main/java/sample/java/PersistentSimpleService.java index 2597e45d95..221b5613b8 100644 --- a/akka-samples/akka-sample-rest-java/src/main/java/sample/java/PersistentSimpleService.java +++ b/akka-samples/akka-sample-rest-java/src/main/java/sample/java/PersistentSimpleService.java @@ -8,9 +8,9 @@ import javax.ws.rs.Path; import javax.ws.rs.GET; import javax.ws.rs.Produces; -import se.scalablesolutions.akka.annotation.transactionrequired; -import se.scalablesolutions.akka.annotation.prerestart; -import se.scalablesolutions.akka.annotation.postrestart; +import se.scalablesolutions.akka.actor.annotation.transactionrequired; +import se.scalablesolutions.akka.actor.annotation.prerestart; +import se.scalablesolutions.akka.actor.annotation.postrestart; import se.scalablesolutions.akka.persistence.common.PersistentMap; import se.scalablesolutions.akka.persistence.cassandra.CassandraStorage; diff --git a/akka-samples/akka-sample-rest-java/src/main/java/sample/java/SimpleService.java b/akka-samples/akka-sample-rest-java/src/main/java/sample/java/SimpleService.java index 0d86b2d37b..b10bcdaea4 100644 --- a/akka-samples/akka-sample-rest-java/src/main/java/sample/java/SimpleService.java +++ b/akka-samples/akka-sample-rest-java/src/main/java/sample/java/SimpleService.java @@ -8,9 +8,9 @@ import javax.ws.rs.Path; import javax.ws.rs.GET; import javax.ws.rs.Produces; -import se.scalablesolutions.akka.annotation.transactionrequired; -import se.scalablesolutions.akka.annotation.prerestart; -import se.scalablesolutions.akka.annotation.postrestart; +import se.scalablesolutions.akka.actor.annotation.transactionrequired; +import se.scalablesolutions.akka.actor.annotation.prerestart; +import se.scalablesolutions.akka.actor.annotation.postrestart; import se.scalablesolutions.akka.stm.TransactionalState; import se.scalablesolutions.akka.stm.TransactionalMap; diff --git a/akka-util-java/src/main/java/se/scalablesolutions/akka/annotation/configuration.java b/akka-util-java/src/main/java/se/scalablesolutions/akka/annotation/configuration.java index b0139ac6f0..9c5375398b 100644 --- a/akka-util-java/src/main/java/se/scalablesolutions/akka/annotation/configuration.java +++ b/akka-util-java/src/main/java/se/scalablesolutions/akka/annotation/configuration.java @@ -2,7 +2,7 @@ * Copyright (C) 2009-2010 Scalable Solutions AB */ -package se.scalablesolutions.akka.annotation; +package se.scalablesolutions.akka.actor.annotation; import java.lang.annotation.*; diff --git a/akka-util-java/src/main/java/se/scalablesolutions/akka/annotation/consume.java b/akka-util-java/src/main/java/se/scalablesolutions/akka/annotation/consume.java index 3f8ab9455a..17ac05bf17 100644 --- a/akka-util-java/src/main/java/se/scalablesolutions/akka/annotation/consume.java +++ b/akka-util-java/src/main/java/se/scalablesolutions/akka/annotation/consume.java @@ -2,7 +2,7 @@ * Copyright (C) 2009-2010 Scalable Solutions AB */ -package se.scalablesolutions.akka.annotation; + package se.scalablesolutions.akka.actor.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/akka-util-java/src/main/java/se/scalablesolutions/akka/annotation/immutable.java b/akka-util-java/src/main/java/se/scalablesolutions/akka/annotation/immutable.java index 9dd2d17322..84dbbf4636 100644 --- a/akka-util-java/src/main/java/se/scalablesolutions/akka/annotation/immutable.java +++ b/akka-util-java/src/main/java/se/scalablesolutions/akka/annotation/immutable.java @@ -2,7 +2,7 @@ * Copyright (C) 2009-2010 Scalable Solutions AB */ -package se.scalablesolutions.akka.annotation; +package se.scalablesolutions.akka.actor.annotation; import java.lang.annotation.*; diff --git a/akka-util-java/src/main/java/se/scalablesolutions/akka/annotation/inittransactionalstate.java b/akka-util-java/src/main/java/se/scalablesolutions/akka/annotation/inittransactionalstate.java index 50e42546ad..35c5f05afe 100644 --- a/akka-util-java/src/main/java/se/scalablesolutions/akka/annotation/inittransactionalstate.java +++ b/akka-util-java/src/main/java/se/scalablesolutions/akka/annotation/inittransactionalstate.java @@ -2,7 +2,7 @@ * Copyright (C) 2009-2010 Scalable Solutions AB */ -package se.scalablesolutions.akka.annotation; +package se.scalablesolutions.akka.actor.annotation; import java.lang.annotation.*; diff --git a/akka-util-java/src/main/java/se/scalablesolutions/akka/annotation/oneway.java b/akka-util-java/src/main/java/se/scalablesolutions/akka/annotation/oneway.java index fa7084bb07..45440b5613 100644 --- a/akka-util-java/src/main/java/se/scalablesolutions/akka/annotation/oneway.java +++ b/akka-util-java/src/main/java/se/scalablesolutions/akka/annotation/oneway.java @@ -2,7 +2,7 @@ * Copyright (C) 2009-2010 Scalable Solutions AB */ -package se.scalablesolutions.akka.annotation; +package se.scalablesolutions.akka.actor.annotation; import java.lang.annotation.*; diff --git a/akka-util-java/src/main/java/se/scalablesolutions/akka/annotation/postrestart.java b/akka-util-java/src/main/java/se/scalablesolutions/akka/annotation/postrestart.java index d003a38df8..5eed474832 100644 --- a/akka-util-java/src/main/java/se/scalablesolutions/akka/annotation/postrestart.java +++ b/akka-util-java/src/main/java/se/scalablesolutions/akka/annotation/postrestart.java @@ -2,7 +2,7 @@ * Copyright (C) 2009-2010 Scalable Solutions AB */ -package se.scalablesolutions.akka.annotation; +package se.scalablesolutions.akka.actor.annotation; import java.lang.annotation.*; diff --git a/akka-util-java/src/main/java/se/scalablesolutions/akka/annotation/prerestart.java b/akka-util-java/src/main/java/se/scalablesolutions/akka/annotation/prerestart.java index e65f38cad6..94f9a01405 100644 --- a/akka-util-java/src/main/java/se/scalablesolutions/akka/annotation/prerestart.java +++ b/akka-util-java/src/main/java/se/scalablesolutions/akka/annotation/prerestart.java @@ -2,7 +2,7 @@ * Copyright (C) 2009-2010 Scalable Solutions AB */ -package se.scalablesolutions.akka.annotation; +package se.scalablesolutions.akka.actor.annotation; import java.lang.annotation.*; diff --git a/akka-util-java/src/main/java/se/scalablesolutions/akka/annotation/state.java b/akka-util-java/src/main/java/se/scalablesolutions/akka/annotation/state.java index 1e627dde8e..509d129c1b 100644 --- a/akka-util-java/src/main/java/se/scalablesolutions/akka/annotation/state.java +++ b/akka-util-java/src/main/java/se/scalablesolutions/akka/annotation/state.java @@ -2,7 +2,7 @@ * Copyright (C) 2009-2010 Scalable Solutions AB */ -package se.scalablesolutions.akka.annotation; +package se.scalablesolutions.akka.actor.annotation; import java.lang.annotation.*; diff --git a/akka-util-java/src/main/java/se/scalablesolutions/akka/annotation/transactionrequired.java b/akka-util-java/src/main/java/se/scalablesolutions/akka/annotation/transactionrequired.java index c45482c467..c41a09ee46 100644 --- a/akka-util-java/src/main/java/se/scalablesolutions/akka/annotation/transactionrequired.java +++ b/akka-util-java/src/main/java/se/scalablesolutions/akka/annotation/transactionrequired.java @@ -2,7 +2,7 @@ * Copyright (C) 2009-2010 Scalable Solutions AB */ -package se.scalablesolutions.akka.annotation; +package se.scalablesolutions.akka.actor.annotation; import java.lang.annotation.*; From b9451a5991ee8b66ba17c8b27021e89e8cc93209 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Bon=C3=A9r?= Date: Wed, 17 Mar 2010 15:10:22 +0100 Subject: [PATCH 02/11] Made "sbt publish" publish artifacts to local Maven repo --- project/build/AkkaProject.scala | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/project/build/AkkaProject.scala b/project/build/AkkaProject.scala index 326daab975..158f193494 100644 --- a/project/build/AkkaProject.scala +++ b/project/build/AkkaProject.scala @@ -60,6 +60,7 @@ class AkkaParent(info: ProjectInfo) extends DefaultProject(info) { // ------------------------------------------------------------ // repositories + val embeddedrepo = "embedded repo" at "file://" + akkaHome + "/embedded-repo" val sunjdmk = "sunjdmk" at "http://wp5.e-taxonomy.eu/cdmlib/mavenrepo" val databinder = "DataBinder" at "http://databinder.net/repo" val configgy = "Configgy" at "http://www.lag.net/repo" @@ -67,7 +68,6 @@ class AkkaParent(info: ProjectInfo) extends DefaultProject(info) { val codehaus_snapshots = "Codehaus Snapshots" at "http://snapshots.repository.codehaus.org" val jboss = "jBoss" at "http://repository.jboss.org/maven2" val guiceyfruit = "GuiceyFruit" at "http://guiceyfruit.googlecode.com/svn/repo/releases/" - val embeddedrepo = "embedded repo" at "http://guice-maven.googlecode.com/svn/trunk" val google = "google" at "http://google-maven-repository.googlecode.com/svn/repository" val m2 = "m2" at "http://download.java.net/maven/2" @@ -126,18 +126,17 @@ class AkkaParent(info: ProjectInfo) extends DefaultProject(info) { // ------------------------------------------------------------ // publishing - Credentials(Path.userHome / ".akka_publish_credentials", log) override def managedStyle = ManagedStyle.Maven + val publishTo = Resolver.file("maven-local", new java.io.File((Path.userHome / ".m2" / "repository").toString)) - val publishTo = "Scalable Solutions Maven Repository" at "~/tmp/akka" -// val publishTo = "Scalable Solutions Maven Repository" at "http://scalablesolutions.se/akka/repository/" + // Credentials(Path.userHome / ".akka_publish_credentials", log) val sourceArtifact = Artifact(artifactID, "src", "jar", Some("sources"), Nil, None) // val docsArtifact = Artifact(artifactID, "docs", "jar", Some("javadoc"), Nil, None) override def packageDocsJar = defaultJarPath("-javadoc.jar") override def packageSrcJar= defaultJarPath("-sources.jar") override def packageToPublishActions = super.packageToPublishActions ++ Seq(packageDocs, packageSrc) - + override def pomExtra = 2009 http://akkasource.org @@ -153,7 +152,7 @@ class AkkaParent(info: ProjectInfo) extends DefaultProject(info) { - // ------------------------------------------------------------ + // ------------------------------------------------------------ // subprojects class AkkaCoreProject(info: ProjectInfo) extends DefaultProject(info) { val netty = "org.jboss.netty" % "netty" % "3.2.0.BETA1" % "compile" From 6acd56a53d739df934ebdfd01ae78863b5591fe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Bon=C3=A9r?= Date: Wed, 17 Mar 2010 15:56:12 +0100 Subject: [PATCH 03/11] Changed Chat sample to use server-managed remote actors + changed the how-to-run-sample doc. --- .../src/main/scala/ChatServer.scala | 69 +++++++++++-------- 1 file changed, 41 insertions(+), 28 deletions(-) diff --git a/akka-samples/akka-sample-chat/src/main/scala/ChatServer.scala b/akka-samples/akka-sample-chat/src/main/scala/ChatServer.scala index ff79df252b..dcf8f74d6b 100644 --- a/akka-samples/akka-sample-chat/src/main/scala/ChatServer.scala +++ b/akka-samples/akka-sample-chat/src/main/scala/ChatServer.scala @@ -1,30 +1,38 @@ -/**ChatStorage +/** * Copyright (C) 2009-2010 Scalable Solutions AB . */ package se.scalablesolutions.akka.sample.chat -import se.scalablesolutions.akka.actor.{SupervisorFactory, Actor, RemoteActor} -import se.scalablesolutions.akka.stm.Transaction._ -import se.scalablesolutions.akka.persistence.common.PersistentVector -import se.scalablesolutions.akka.persistence.redis.RedisStorage -import se.scalablesolutions.akka.remote.RemoteServer -import se.scalablesolutions.akka.util.Logging -import se.scalablesolutions.akka.config.ScalaConfig._ -import se.scalablesolutions.akka.config.OneForOneStrategy - import scala.collection.mutable.HashMap +import se.scalablesolutions.akka.actor.{SupervisorFactory, Actor, RemoteActor} +import se.scalablesolutions.akka.remote.{RemoteNode, RemoteClient} +import se.scalablesolutions.akka.persistence.common.PersistentVector +import se.scalablesolutions.akka.persistence.redis.RedisStorage +import se.scalablesolutions.akka.stm.Transaction._ +import se.scalablesolutions.akka.config.ScalaConfig._ +import se.scalablesolutions.akka.config.OneForOneStrategy +import se.scalablesolutions.akka.util.Logging + /****************************************************************************** - To run the sample: - 1. Run 'mvn install' (builds and deploys jar to AKKA_HOME/deploy) - 2. In another shell run 'java -jar ./dist/akka-0.6.jar' to start up Akka microkernel - 3. In the first shell run 'mvn scala:console -o' - 4. In the REPL you get execute: + To run the sample + + 1. Install the Redis network storage. Download it from [http://code.google.com/p/redis/]. + 2. Open up a shell and start up an instance of Redis. + 3. Fire up two shells. For each of them: + - Step down into to the root of the Akka distribution. + - Set 'export AKKA_HOME=. + - Run 'sbt console' to start up a REPL (interpreter). + 4. In the first REPL you get execute: - scala> import se.scalablesolutions.akka.sample.chat._ - - scala> Runner.run - 5. See the chat simulation run - 6. Run it again to see full speed after first initialization + - scala> ChatService.start + 5. In the first REPL you get execute: + - scala> import se.scalablesolutions.akka.sample.chat._ + - scala> Runner.run + 6. See the chat simulation run. + 7. Run it again to see full speed after first initialization. + ******************************************************************************/ /** @@ -42,10 +50,12 @@ case class ChatMessage(from: String, message: String) extends Event */ class ChatClient(val name: String) { import Actor.Sender.Self - def login = ChatService ! Login(name) - def logout = ChatService ! Logout(name) - def post(message: String) = ChatService ! ChatMessage(name, name + ": " + message) - def chatLog: ChatLog = (ChatService !! GetChatLog(name)).getOrElse(throw new Exception("Couldn't get the chat log from ChatServer")) + val chat = RemoteClient.actorFor("chat:service", "localhost", 9999) + + def login = chat ! Login(name) + def logout = chat ! Logout(name) + def post(message: String) = chat ! ChatMessage(name, name + ": " + message) + def chatLog: ChatLog = (chat !! GetChatLog(name)).getOrElse(throw new Exception("Couldn't get the chat log from ChatServer")) } /** @@ -182,16 +192,19 @@ object ChatService extends ChatServer with SessionManagement with ChatManagement with - RedisChatStorageFactory + RedisChatStorageFactory { + override def start: Actor = { + super.start + RemoteNode.start("localhost", 9999) + RemoteNode.register("chat:service", this) + this + } +} /** * Test runner emulating a chat session. */ object Runner { - // create a handle to the remote ChatService - ChatService.makeRemote("localhost", 9999) - ChatService.start - def run = { val client = new ChatClient("jonas") @@ -205,4 +218,4 @@ object Runner { client.logout } -} +} \ No newline at end of file From cfbc5854852194cb8fc62ca16a4c34e86fd9b4ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Bon=C3=A9r?= Date: Wed, 17 Mar 2010 08:17:18 -0700 Subject: [PATCH 04/11] Updated README with new running procedure --- akka-samples/akka-sample-chat/README | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/akka-samples/akka-sample-chat/README b/akka-samples/akka-sample-chat/README index d2049cd7c0..799da70c24 100644 --- a/akka-samples/akka-sample-chat/README +++ b/akka-samples/akka-sample-chat/README @@ -10,17 +10,20 @@ For details on how to set up Redis server have a look at http://code.google.com/ Then to run the sample: -1. Set ‘AKKA_HOME’ environment variable to the root of the Akka distribution. -2. Open up a shell and step into the Akka distribution root folder. -3. Build Akka by invoking ‘mvn install -Dmaven.test.skip=true’. This will also build the sample application and deploy it to the ‘$AKKA_HOME/deploy’ directory. -4. Run the microkernel - export AKKA_HOME=... - cd $AKKA_HOME - java -jar ./dist/akka-0.6.jar -5. Now start up a new shell and go down into the ‘./akka-samples/akka-sample-chat’ directory. -6. Invoke ‘mvn scala:console -o’. This will give you a Scala REPL (interpreter) with the chat application and all its dependency JARs on the classpath. -7. Simply paste in the whole code block with the ‘Runner’ object above and invoke ‘Runner.run’. This runs a simulated client session that will connect to the running server in the microkernel. -8. Invoke ‘Runner.run’ again and again… +1. Install the Redis network storage. Download it from [http://code.google.com/p/redis/]. +2. Open up a shell and start up an instance of Redis. +3. Fire up two shells. For each of them: + - Step down into to the root of the Akka distribution. + - Set 'export AKKA_HOME=. + - Run 'sbt console' to start up a REPL (interpreter). +4. In the first REPL you get execute: + - scala> import se.scalablesolutions.akka.sample.chat._ + - scala> ChatService.start +5. In the first REPL you get execute: + - scala> import se.scalablesolutions.akka.sample.chat._ + - scala> Runner.run +6. See the chat simulation run. +7. Run it again to see full speed after first initialization. Now you could test client reconnect by killing the running microkernel and start it up again. See the client reconnect take place in the REPL shell. From bf9bbd0dc133bd1bef5bd1a5369ff7f5b072f1c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Bon=C3=A9r?= Date: Wed, 17 Mar 2010 08:19:56 -0700 Subject: [PATCH 05/11] Updated how to run the sample docs. --- .../src/main/scala/ChatServer.scala | 38 ++++++++++++------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/akka-samples/akka-sample-chat/src/main/scala/ChatServer.scala b/akka-samples/akka-sample-chat/src/main/scala/ChatServer.scala index dcf8f74d6b..31d4e9d49f 100644 --- a/akka-samples/akka-sample-chat/src/main/scala/ChatServer.scala +++ b/akka-samples/akka-sample-chat/src/main/scala/ChatServer.scala @@ -16,22 +16,32 @@ import se.scalablesolutions.akka.config.OneForOneStrategy import se.scalablesolutions.akka.util.Logging /****************************************************************************** - To run the sample +Akka Chat Client/Server Sample Application - 1. Install the Redis network storage. Download it from [http://code.google.com/p/redis/]. - 2. Open up a shell and start up an instance of Redis. - 3. Fire up two shells. For each of them: - - Step down into to the root of the Akka distribution. - - Set 'export AKKA_HOME=. - - Run 'sbt console' to start up a REPL (interpreter). - 4. In the first REPL you get execute: +First we need to download, build and start up Redis: + +1. Download Redis from http://code.google.com/p/redis/downloads/list. +2. Step into the distribution. +3. Build: ‘make install’. +4. Run: ‘./redis-server’. +For details on how to set up Redis server have a look at http://code.google.com/p/redis/wiki/QuickStart. + +Then to run the sample: + +1. Fire up two shells. For each of them: + - Step down into to the root of the Akka distribution. + - Set 'export AKKA_HOME=. + - Run 'sbt console' to start up a REPL (interpreter). +2. In the first REPL you get execute: + - scala> import se.scalablesolutions.akka.sample.chat._ + - scala> ChatService.start +3. In the first REPL you get execute: - scala> import se.scalablesolutions.akka.sample.chat._ - - scala> ChatService.start - 5. In the first REPL you get execute: - - scala> import se.scalablesolutions.akka.sample.chat._ - - scala> Runner.run - 6. See the chat simulation run. - 7. Run it again to see full speed after first initialization. + - scala> Runner.run +4. See the chat simulation run. +5. Run it again to see full speed after first initialization. + +That’s it. Have fun. ******************************************************************************/ From ed116712a39380a319f7ced1a65cb921c1f26f58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Bon=C3=A9r?= Date: Wed, 17 Mar 2010 08:20:46 -0700 Subject: [PATCH 06/11] Fixed typo in docs. --- akka-samples/akka-sample-chat/README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/akka-samples/akka-sample-chat/README b/akka-samples/akka-sample-chat/README index 799da70c24..88720d8c55 100644 --- a/akka-samples/akka-sample-chat/README +++ b/akka-samples/akka-sample-chat/README @@ -25,7 +25,7 @@ Then to run the sample: 6. See the chat simulation run. 7. Run it again to see full speed after first initialization. -Now you could test client reconnect by killing the running microkernel and start it up again. See the client reconnect take place in the REPL shell. +Now you could test client reconnect by killing the console running the ChatService and start it up again. See the client reconnect take place in the REPL shell. That’s it. Have fun. From eb4e6242e3fdc955945288fc0f1d9061507a7b0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Bon=C3=A9r?= Date: Wed, 17 Mar 2010 17:43:49 +0100 Subject: [PATCH 07/11] Created an alias to TransactionalRef; Ref --- .../main/scala/stm/TransactionalState.scala | 20 +++++++++++++++++++ .../src/main/scala/ChatServer.scala | 7 ++++--- project/build/AkkaProject.scala | 4 ++-- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/akka-core/src/main/scala/stm/TransactionalState.scala b/akka-core/src/main/scala/stm/TransactionalState.scala index c74fde4ab0..4f35f1199e 100644 --- a/akka-core/src/main/scala/stm/TransactionalState.scala +++ b/akka-core/src/main/scala/stm/TransactionalState.scala @@ -53,6 +53,17 @@ trait Committable { } /** + * Alias to TransactionalRef. + * + * @author Jonas Bonér + */ +object Ref { + def apply[T]() = new Ref[T] +} + +/** + * Alias to Ref. + * * @author Jonas Bonér */ object TransactionalRef { @@ -65,8 +76,17 @@ object TransactionalRef { def apply[T]() = new TransactionalRef[T] } +/** + * Implements a transactional managed reference. + * Alias to TransactionalRef. + * + * @author Jonas Bonér + */ +class Ref[T] extends TransactionalRef[T] + /** * Implements a transactional managed reference. + * Alias to Ref. * * @author Jonas Bonér */ diff --git a/akka-samples/akka-sample-chat/src/main/scala/ChatServer.scala b/akka-samples/akka-sample-chat/src/main/scala/ChatServer.scala index dcf8f74d6b..9b85972958 100644 --- a/akka-samples/akka-sample-chat/src/main/scala/ChatServer.scala +++ b/akka-samples/akka-sample-chat/src/main/scala/ChatServer.scala @@ -87,8 +87,9 @@ trait ChatStorage extends Actor */ class RedisChatStorage extends ChatStorage { lifeCycle = Some(LifeCycle(Permanent)) - - private var chatLog = atomic { RedisStorage.getVector("akka.chat.log") } + val CHAT_LOG = "akka.chat.log" + + private var chatLog = atomic { RedisStorage.getVector(CHAT_LOG) } log.info("Redis-based chat storage is starting up...") @@ -106,7 +107,7 @@ class RedisChatStorage extends ChatStorage { reply(ChatLog(messageList)) } - override def postRestart(reason: Throwable) = chatLog = RedisStorage.getVector("akka.chat.log") + override def postRestart(reason: Throwable) = chatLog = RedisStorage.getVector(CHAT_LOG) } /** diff --git a/project/build/AkkaProject.scala b/project/build/AkkaProject.scala index 158f193494..cd46dbea5c 100644 --- a/project/build/AkkaProject.scala +++ b/project/build/AkkaProject.scala @@ -127,11 +127,11 @@ class AkkaParent(info: ProjectInfo) extends DefaultProject(info) { // ------------------------------------------------------------ // publishing override def managedStyle = ManagedStyle.Maven - val publishTo = Resolver.file("maven-local", new java.io.File((Path.userHome / ".m2" / "repository").toString)) + val publishTo = Resolver.file("maven-local", Path.userHome / ".m2" / "repository" asFile) // Credentials(Path.userHome / ".akka_publish_credentials", log) val sourceArtifact = Artifact(artifactID, "src", "jar", Some("sources"), Nil, None) -// val docsArtifact = Artifact(artifactID, "docs", "jar", Some("javadoc"), Nil, None) + //val docsArtifact = Artifact(artifactID, "docs", "jar", Some("javadoc"), Nil, None) override def packageDocsJar = defaultJarPath("-javadoc.jar") override def packageSrcJar= defaultJarPath("-sources.jar") From 592e4d3d1e47625937f99303edb142836a38e09f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Bon=C3=A9r?= Date: Wed, 17 Mar 2010 17:48:46 +0100 Subject: [PATCH 08/11] reformatted patterns code --- akka-patterns/src/main/scala/Patterns.scala | 33 ++++++++------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/akka-patterns/src/main/scala/Patterns.scala b/akka-patterns/src/main/scala/Patterns.scala index 02f2686ba7..3b7982148e 100644 --- a/akka-patterns/src/main/scala/Patterns.scala +++ b/akka-patterns/src/main/scala/Patterns.scala @@ -18,19 +18,17 @@ object Patterns { /** * Interceptor is a filter(x,y) where x.isDefinedAt is considered to be always true */ - def intercept[A, B](interceptor: (A) => Unit, interceptee: PF[A, B]): PF[A, B] = filter( - {case a if a.isInstanceOf[A] => interceptor(a)}, - interceptee - ) + def intercept[A, B](interceptor: (A) => Unit, interceptee: PF[A, B]): PF[A, B] = + filter({case a if a.isInstanceOf[A] => interceptor(a)}, interceptee) //FIXME 2.8, use default params with CyclicIterator def loadBalancerActor(actors: => InfiniteIterator[Actor]): Actor = new Actor with LoadBalancer { val seq = actors } - def dispatcherActor(routing: PF[Any, Actor], msgTransformer: (Any) => Any): Actor = new Actor with Dispatcher { + def dispatcherActor(routing: PF[Any, Actor], msgTransformer: (Any) => Any): Actor = + new Actor with Dispatcher { override def transform(msg: Any) = msgTransformer(msg) - def routes = routing } @@ -38,36 +36,29 @@ object Patterns { def routes = routing } - def loggerActor(actorToLog: Actor, logger: (Any) => Unit): Actor = dispatcherActor( - {case _ => actorToLog}, - logger - ) + def loggerActor(actorToLog: Actor, logger: (Any) => Unit): Actor = + dispatcherActor({case _ => actorToLog}, logger) } -trait Dispatcher { - self: Actor => +trait Dispatcher { self: Actor => protected def transform(msg: Any): Any = msg protected def routes: PartialFunction[Any, Actor] protected def dispatch: PartialFunction[Any, Unit] = { - case a if routes.isDefinedAt(a) => { - if (self.sender.isDefined) - routes(a) forward transform(a) - else - routes(a) send transform(a) - } + case a if routes.isDefinedAt(a) => + if (self.sender.isDefined) routes(a) forward transform(a) + else routes(a) send transform(a) } def receive = dispatch } -trait LoadBalancer extends Dispatcher { - self: Actor => +trait LoadBalancer extends Dispatcher { self: Actor => protected def seq: InfiniteIterator[Actor] - protected def routes = {case x if seq.hasNext => seq.next} + protected def routes = { case x if seq.hasNext => seq.next } } trait InfiniteIterator[T] extends Iterator[T] From 3010cd1aa24e85f86923c3584adefb608d1f8687 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Bon=C3=A9r?= Date: Wed, 17 Mar 2010 21:38:27 +0100 Subject: [PATCH 09/11] Refactored Serializer --- akka-core/src/main/scala/remote/Cluster.scala | 43 +++++++++--------- .../scala/remote/RemoteProtocolBuilder.scala | 14 +++--- .../main/scala/serialization/Serializer.scala | 44 +++++++++++-------- .../src/main/scala/Storage.scala | 2 +- 4 files changed, 54 insertions(+), 49 deletions(-) diff --git a/akka-core/src/main/scala/remote/Cluster.scala b/akka-core/src/main/scala/remote/Cluster.scala index 7156c999bc..4a1d6012a7 100644 --- a/akka-core/src/main/scala/remote/Cluster.scala +++ b/akka-core/src/main/scala/remote/Cluster.scala @@ -17,41 +17,42 @@ import scala.collection.immutable.{Map, HashMap} * @author Viktor Klang */ trait Cluster { + /** - * Specifies the cluster name - */ + * Specifies the cluster name + */ def name: String /** - * Adds the specified hostname + port as a local node - * This information will be propagated to other nodes in the cluster - * and will be available at the other nodes through lookup and foreach - */ + * Adds the specified hostname + port as a local node + * This information will be propagated to other nodes in the cluster + * and will be available at the other nodes through lookup and foreach + */ def registerLocalNode(hostname: String, port: Int): Unit /** - * Removes the specified hostname + port from the local node - * This information will be propagated to other nodes in the cluster - * and will no longer be available at the other nodes through lookup and foreach - */ + * Removes the specified hostname + port from the local node + * This information will be propagated to other nodes in the cluster + * and will no longer be available at the other nodes through lookup and foreach + */ def deregisterLocalNode(hostname: String, port: Int): Unit /** - * Sends the message to all Actors of the specified type on all other nodes in the cluster - */ + * Sends the message to all Actors of the specified type on all other nodes in the cluster + */ def relayMessage(to: Class[_ <: Actor], msg: AnyRef): Unit /** - * Traverses all known remote addresses avaiable at all other nodes in the cluster - * and applies the given PartialFunction on the first address that it's defined at - * The order of application is undefined and may vary - */ + * Traverses all known remote addresses avaiable at all other nodes in the cluster + * and applies the given PartialFunction on the first address that it's defined at + * The order of application is undefined and may vary + */ def lookup[T](pf: PartialFunction[RemoteAddress, T]): Option[T] /** - * Applies the specified function to all known remote addresses on al other nodes in the cluster - * The order of application is undefined and may vary - */ + * Applies the specified function to all known remote addresses on al other nodes in the cluster + * The order of application is undefined and may vary + */ def foreach(f: (RemoteAddress) => Unit): Unit } @@ -159,7 +160,7 @@ abstract class BasicClusterActor extends ClusterActor { case RegisterLocalNode(s) => { log debug ("RegisterLocalNode: %s", s) - local = Node(local.endpoints + s) + local = Node(s :: local.endpoints) broadcast(Papers(local.endpoints)) } @@ -242,7 +243,7 @@ object Cluster extends Cluster with Logging { "Can't start cluster since the 'akka.remote.cluster.actor' configuration option is not defined") val serializer = Class.forName(config.getString("akka.remote.cluster.serializer", DEFAULT_SERIALIZER_CLASS_NAME)).newInstance.asInstanceOf[Serializer] - serializer setClassLoader loader + serializer.classLoader = Some(loader) try { name map { fqn => diff --git a/akka-core/src/main/scala/remote/RemoteProtocolBuilder.scala b/akka-core/src/main/scala/remote/RemoteProtocolBuilder.scala index 287168140a..bfeec1c34e 100644 --- a/akka-core/src/main/scala/remote/RemoteProtocolBuilder.scala +++ b/akka-core/src/main/scala/remote/RemoteProtocolBuilder.scala @@ -18,19 +18,17 @@ object RemoteProtocolBuilder { private var SERIALIZER_PROTOBUF: Serializer.Protobuf = Serializer.Protobuf - def setClassLoader(classLoader: ClassLoader) = { - SERIALIZER_JAVA = new Serializer.Java - SERIALIZER_JAVA_JSON = new Serializer.JavaJSON - SERIALIZER_SCALA_JSON = new Serializer.ScalaJSON - SERIALIZER_JAVA.setClassLoader(classLoader) - SERIALIZER_JAVA_JSON.setClassLoader(classLoader) - SERIALIZER_SCALA_JSON.setClassLoader(classLoader) + def setClassLoader(cl: ClassLoader) = { + SERIALIZER_JAVA.classLoader = Some(cl) + SERIALIZER_JAVA_JSON.classLoader = Some(cl) + SERIALIZER_SCALA_JSON.classLoader = Some(cl) } def getMessage(request: RemoteRequest): Any = { request.getProtocol match { case SerializationProtocol.SBINARY => - val renderer = Class.forName(new String(request.getMessageManifest.toByteArray)).newInstance.asInstanceOf[SBinary[_ <: AnyRef]] + val renderer = Class.forName( + new String(request.getMessageManifest.toByteArray)).newInstance.asInstanceOf[SBinary[_ <: AnyRef]] renderer.fromBytes(request.getMessage.toByteArray) case SerializationProtocol.SCALA_JSON => val manifest = SERIALIZER_JAVA.in(request.getMessageManifest.toByteArray, None).asInstanceOf[String] diff --git a/akka-core/src/main/scala/serialization/Serializer.scala b/akka-core/src/main/scala/serialization/Serializer.scala index 1cc930a7eb..c878548711 100644 --- a/akka-core/src/main/scala/serialization/Serializer.scala +++ b/akka-core/src/main/scala/serialization/Serializer.scala @@ -18,13 +18,13 @@ import sjson.json.{Serializer => SJSONSerializer} * @author Jonas Bonér */ trait Serializer { - def deepClone(obj: AnyRef): AnyRef - def out(obj: AnyRef): Array[Byte] - def in(bytes: Array[Byte], clazz: Option[Class[_]]): AnyRef - - protected var classLoader: Option[ClassLoader] = None + var classLoader: Option[ClassLoader] = None - def setClassLoader(cl: ClassLoader) = classLoader = Some(cl) + def deepClone(obj: AnyRef): AnyRef + + def out(obj: AnyRef): Array[Byte] + + def in(bytes: Array[Byte], clazz: Option[Class[_]]): AnyRef } // For Java API @@ -55,7 +55,7 @@ object Serializer { * @author Jonas Bonér */ object Java extends Java - class Java extends Serializer { + trait Java extends Serializer { def deepClone(obj: AnyRef): AnyRef = in(out(obj), None) def out(obj: AnyRef): Array[Byte] = { @@ -67,8 +67,9 @@ object Serializer { } def in(bytes: Array[Byte], clazz: Option[Class[_]]): AnyRef = { - val in = if (classLoader.isDefined) new ClassLoaderObjectInputStream(classLoader.get, new ByteArrayInputStream(bytes)) - else new ObjectInputStream(new ByteArrayInputStream(bytes)) + val in = + if (classLoader.isDefined) new ClassLoaderObjectInputStream(classLoader.get, new ByteArrayInputStream(bytes)) + else new ObjectInputStream(new ByteArrayInputStream(bytes)) val obj = in.readObject in.close obj @@ -79,18 +80,21 @@ object Serializer { * @author Jonas Bonér */ object Protobuf extends Protobuf - class Protobuf extends Serializer { + trait Protobuf extends Serializer { def deepClone(obj: AnyRef): AnyRef = in(out(obj), Some(obj.getClass)) def out(obj: AnyRef): Array[Byte] = { - if (!obj.isInstanceOf[Message]) throw new IllegalArgumentException("Can't serialize a non-protobuf message using protobuf [" + obj + "]") + if (!obj.isInstanceOf[Message]) throw new IllegalArgumentException( + "Can't serialize a non-protobuf message using protobuf [" + obj + "]") obj.asInstanceOf[Message].toByteArray } def in(bytes: Array[Byte], clazz: Option[Class[_]]): AnyRef = { - if (!clazz.isDefined) throw new IllegalArgumentException("Need a protobuf message class to be able to serialize bytes using protobuf") + if (!clazz.isDefined) throw new IllegalArgumentException( + "Need a protobuf message class to be able to serialize bytes using protobuf") // TODO: should we cache this method lookup? - val message = clazz.get.getDeclaredMethod("getDefaultInstance", EMPTY_CLASS_ARRAY: _*).invoke(null, EMPTY_ANY_REF_ARRAY: _*).asInstanceOf[Message] + val message = clazz.get.getDeclaredMethod( + "getDefaultInstance", EMPTY_CLASS_ARRAY: _*).invoke(null, EMPTY_ANY_REF_ARRAY: _*).asInstanceOf[Message] message.toBuilder().mergeFrom(bytes).build } @@ -104,7 +108,7 @@ object Serializer { * @author Jonas Bonér */ object JavaJSON extends JavaJSON - class JavaJSON extends Serializer { + trait JavaJSON extends Serializer { private val mapper = new ObjectMapper def deepClone(obj: AnyRef): AnyRef = in(out(obj), Some(obj.getClass)) @@ -118,9 +122,11 @@ object Serializer { } def in(bytes: Array[Byte], clazz: Option[Class[_]]): AnyRef = { - if (!clazz.isDefined) throw new IllegalArgumentException("Can't deserialize JSON to instance if no class is provided") - val in = if (classLoader.isDefined) new ClassLoaderObjectInputStream(classLoader.get, new ByteArrayInputStream(bytes)) - else new ObjectInputStream(new ByteArrayInputStream(bytes)) + if (!clazz.isDefined) throw new IllegalArgumentException( + "Can't deserialize JSON to instance if no class is provided") + val in = + if (classLoader.isDefined) new ClassLoaderObjectInputStream(classLoader.get, new ByteArrayInputStream(bytes)) + else new ObjectInputStream(new ByteArrayInputStream(bytes)) val obj = mapper.readValue(in, clazz.get).asInstanceOf[AnyRef] in.close obj @@ -136,7 +142,7 @@ object Serializer { * @author Jonas Bonér */ object ScalaJSON extends ScalaJSON - class ScalaJSON extends Serializer { + trait ScalaJSON extends Serializer { def deepClone(obj: AnyRef): AnyRef = in(out(obj), None) def out(obj: AnyRef): Array[Byte] = SJSONSerializer.SJSON.out(obj) @@ -158,7 +164,7 @@ object Serializer { * @author Jonas Bonér */ object SBinary extends SBinary - class SBinary { + trait SBinary { import sbinary.DefaultProtocol._ def deepClone[T <: AnyRef](obj: T)(implicit w : Writes[T], r : Reads[T]): T = in[T](out[T](obj), None) diff --git a/akka-persistence/akka-persistence-common/src/main/scala/Storage.scala b/akka-persistence/akka-persistence-common/src/main/scala/Storage.scala index ff37dde82e..f21490a1be 100644 --- a/akka-persistence/akka-persistence-common/src/main/scala/Storage.scala +++ b/akka-persistence/akka-persistence-common/src/main/scala/Storage.scala @@ -302,7 +302,7 @@ trait PersistentRef[T] extends Transactional with Committable { trait PersistentQueue[A] extends scala.collection.mutable.Queue[A] with Transactional with Committable with Logging { - abstract case class QueueOp + sealed trait QueueOp case object ENQ extends QueueOp case object DEQ extends QueueOp From 02e6f5895a832091c41b46002dce94959f808210 Mon Sep 17 00:00:00 2001 From: Debasish Ghosh Date: Thu, 18 Mar 2010 10:51:22 +0530 Subject: [PATCH 10/11] added support for Redis based SortedSet persistence in Akka transactors --- .../src/main/scala/Storage.scala | 122 +++++++++ .../src/main/scala/StorageBackend.scala | 10 +- .../src/main/scala/RedisStorage.scala | 15 ++ .../src/main/scala/RedisStorageBackend.scala | 17 +- .../test/scala/RedisPersistentActorSpec.scala | 2 +- .../scala/RedisPersistentSortedSetSpec.scala | 237 ++++++++++++++++++ .../test/scala/RedisStorageBackendSpec.scala | 12 +- .../redis/redisclient/1.1/redisclient-1.1.jar | Bin 47464 -> 0 bytes .../redis/redisclient/1.1/redisclient-1.1.pom | 8 - project/build/AkkaProject.scala | 2 +- 10 files changed, 404 insertions(+), 21 deletions(-) create mode 100644 akka-persistence/akka-persistence-redis/src/test/scala/RedisPersistentSortedSetSpec.scala delete mode 100644 embedded-repo/com/redis/redisclient/1.1/redisclient-1.1.jar delete mode 100755 embedded-repo/com/redis/redisclient/1.1/redisclient-1.1.pom diff --git a/akka-persistence/akka-persistence-common/src/main/scala/Storage.scala b/akka-persistence/akka-persistence-common/src/main/scala/Storage.scala index f21490a1be..0f0eeac912 100644 --- a/akka-persistence/akka-persistence-common/src/main/scala/Storage.scala +++ b/akka-persistence/akka-persistence-common/src/main/scala/Storage.scala @@ -51,18 +51,24 @@ trait Storage { def newRef: PersistentRef[ElementType] def newQueue: PersistentQueue[ElementType] = // only implemented for redis throw new UnsupportedOperationException + def newSortedSet: PersistentSortedSet[ElementType] = // only implemented for redis + throw new UnsupportedOperationException def getMap(id: String): PersistentMap[ElementType, ElementType] def getVector(id: String): PersistentVector[ElementType] def getRef(id: String): PersistentRef[ElementType] def getQueue(id: String): PersistentQueue[ElementType] = // only implemented for redis throw new UnsupportedOperationException + def getSortedSet(id: String): PersistentSortedSet[ElementType] = // only implemented for redis + throw new UnsupportedOperationException def newMap(id: String): PersistentMap[ElementType, ElementType] def newVector(id: String): PersistentVector[ElementType] def newRef(id: String): PersistentRef[ElementType] def newQueue(id: String): PersistentQueue[ElementType] = // only implemented for redis throw new UnsupportedOperationException + def newSortedSet(id: String): PersistentSortedSet[ElementType] = // only implemented for redis + throw new UnsupportedOperationException } /** @@ -398,3 +404,119 @@ trait PersistentQueue[A] extends scala.collection.mutable.Queue[A] transaction.get.get.register(uuid, this) } } + +/** + * Implements a template for a concrete persistent transactional sorted set based storage. + *

+ * Sorting is done based on a zscore. But the computation of zscore has been kept + * outside the abstraction. + *

+ * zscore can be implemented in a variety of ways by the calling class: + *

+ * trait ZScorable {
+ *   def toZScore: Float
+ * }
+ *
+ * class Foo extends ZScorable {
+ *   //.. implemnetation
+ * }
+ * 
+ * Or we can also use views: + *
+ * class Foo {
+ *   //..
+ * }
+ * 
+ * implicit def Foo2Scorable(foo: Foo): ZScorable = new ZScorable {
+ *   def toZScore = {
+ *     //..
+ *   }
+ * }
+ * 
+ * + * and use foo.toZScore to compute the zscore and pass to the APIs. + * + * @author + */ +trait PersistentSortedSet[A] + extends Transactional + with Committable { + + protected val newElems = TransactionalState.newMap[A, Float] + protected val removedElems = TransactionalState.newVector[A] + + val storage: SortedSetStorageBackend[A] + + def commit = { + for ((element, score) <- newElems) storage.zadd(uuid, String.valueOf(score), element) + for (element <- removedElems) storage.zrem(uuid, element) + newElems.clear + removedElems.clear + } + + def +(elem: A, score: Float) = add(elem, score) + + def add(elem: A, score: Float) = { + register + newElems.put(elem, score) + } + + def -(elem: A) = remove(elem) + + def remove(elem: A) = { + register + removedElems.add(elem) + } + + private def inStorage(elem: A): Option[Float] = storage.zscore(uuid, elem) match { + case Some(s) => Some(s.toFloat) + case None => None + } + + def contains(elem: A): Boolean = { + if (newElems contains elem) true + else { + inStorage(elem) match { + case Some(f) => true + case None => false + } + } + } + + def size: Int = newElems.size + storage.zcard(uuid) - removedElems.size + + def zscore(elem: A): Float = { + if (newElems contains elem) newElems.get(elem).get + inStorage(elem) match { + case Some(f) => f + case None => + throw new Predef.NoSuchElementException(elem + " not present") + } + } + + implicit def order(x: (A, Float)) = new Ordered[(A, Float)] { + def compare(that: (A, Float)) = x._2 compare that._2 + } + + def zrange(start: Int, end: Int): List[(A, Float)] = { + // need to operate on the whole range + // get all from the underlying storage + val fromStore = storage.zrangeWithScore(uuid, 0, -1) + val ts = scala.collection.immutable.TreeSet(fromStore: _*) ++ newElems.toList + val l = ts.size + + // -1 means the last element, -2 means the second last + val s = if (start < 0) start + l else start + val e = + if (end < 0) end + l + else if (end >= l) (l - 1) + else end + // slice is open at the end, we need a closed end range + ts.elements.slice(s, e + 1).toList + } + + private def register = { + if (transaction.get.isEmpty) throw new NoTransactionInScopeException + transaction.get.get.register(uuid, this) + } +} diff --git a/akka-persistence/akka-persistence-common/src/main/scala/StorageBackend.scala b/akka-persistence/akka-persistence-common/src/main/scala/StorageBackend.scala index d909f0e4a4..ab0cfaf4d3 100644 --- a/akka-persistence/akka-persistence-common/src/main/scala/StorageBackend.scala +++ b/akka-persistence/akka-persistence-common/src/main/scala/StorageBackend.scala @@ -69,11 +69,15 @@ trait SortedSetStorageBackend[T] extends StorageBackend { // remove item from sorted set identified by name def zrem(name: String, item: T): Boolean - // cardinality of the set idnetified by name + // cardinality of the set identified by name def zcard(name: String): Int - def zscore(name: String, item: T): String + // zscore of the item from sorted set identified by name + def zscore(name: String, item: T): Option[Float] + // zrange from the sorted set identified by name def zrange(name: String, start: Int, end: Int): List[T] -} + // zrange with score from the sorted set identified by name + def zrangeWithScore(name: String, start: Int, end: Int): List[(T, Float)] +} diff --git a/akka-persistence/akka-persistence-redis/src/main/scala/RedisStorage.scala b/akka-persistence/akka-persistence-redis/src/main/scala/RedisStorage.scala index 1338a9f8d4..b8aada0572 100644 --- a/akka-persistence/akka-persistence-redis/src/main/scala/RedisStorage.scala +++ b/akka-persistence/akka-persistence-redis/src/main/scala/RedisStorage.scala @@ -15,16 +15,20 @@ object RedisStorage extends Storage { def newVector: PersistentVector[ElementType] = newVector(UUID.newUuid.toString) def newRef: PersistentRef[ElementType] = newRef(UUID.newUuid.toString) override def newQueue: PersistentQueue[ElementType] = newQueue(UUID.newUuid.toString) + override def newSortedSet: PersistentSortedSet[ElementType] = newSortedSet(UUID.newUuid.toString) def getMap(id: String): PersistentMap[ElementType, ElementType] = newMap(id) def getVector(id: String): PersistentVector[ElementType] = newVector(id) def getRef(id: String): PersistentRef[ElementType] = newRef(id) override def getQueue(id: String): PersistentQueue[ElementType] = newQueue(id) + override def getSortedSet(id: String): PersistentSortedSet[ElementType] = newSortedSet(id) def newMap(id: String): PersistentMap[ElementType, ElementType] = new RedisPersistentMap(id) def newVector(id: String): PersistentVector[ElementType] = new RedisPersistentVector(id) def newRef(id: String): PersistentRef[ElementType] = new RedisPersistentRef(id) override def newQueue(id: String): PersistentQueue[ElementType] = new RedisPersistentQueue(id) + override def newSortedSet(id: String): PersistentSortedSet[ElementType] = + new RedisPersistentSortedSet(id) } /** @@ -63,3 +67,14 @@ class RedisPersistentQueue(id: String) extends PersistentQueue[Array[Byte]] { val uuid = id val storage = RedisStorageBackend } + +/** + * Implements a persistent transactional sorted set based on the Redis + * storage. + * + * @author Debasish Ghosh + */ +class RedisPersistentSortedSet(id: String) extends PersistentSortedSet[Array[Byte]] { + val uuid = id + val storage = RedisStorageBackend +} diff --git a/akka-persistence/akka-persistence-redis/src/main/scala/RedisStorageBackend.scala b/akka-persistence/akka-persistence-redis/src/main/scala/RedisStorageBackend.scala index 8bca9c6af6..c48c84fa39 100644 --- a/akka-persistence/akka-persistence-redis/src/main/scala/RedisStorageBackend.scala +++ b/akka-persistence/akka-persistence-redis/src/main/scala/RedisStorageBackend.scala @@ -364,11 +364,10 @@ private [akka] object RedisStorageBackend extends } } - def zscore(name: String, item: Array[Byte]): String = withErrorHandling { + def zscore(name: String, item: Array[Byte]): Option[Float] = withErrorHandling { db.zscore(new String(encode(name.getBytes)), new String(item)) match { - case None => - throw new Predef.NoSuchElementException(new String(item) + " not present") - case Some(s) => s + case Some(s) => Some(s.toFloat) + case None => None } } @@ -380,6 +379,16 @@ private [akka] object RedisStorageBackend extends s.map(_.get.getBytes) } } + + def zrangeWithScore(name: String, start: Int, end: Int): List[(Array[Byte], Float)] = withErrorHandling { + db.zrangeWithScore( + new String(encode(name.getBytes)), start.toString, end.toString, RedisClient.ASC) match { + case None => + throw new Predef.NoSuchElementException(name + " not present") + case Some(l) => + l.map{ case (elem, score) => (elem.get.getBytes, score.get.toFloat) } + } + } def flushDB = withErrorHandling(db.flushDb) diff --git a/akka-persistence/akka-persistence-redis/src/test/scala/RedisPersistentActorSpec.scala b/akka-persistence/akka-persistence-redis/src/test/scala/RedisPersistentActorSpec.scala index 9405789bfd..41ee6fb909 100644 --- a/akka-persistence/akka-persistence-redis/src/test/scala/RedisPersistentActorSpec.scala +++ b/akka-persistence/akka-persistence-redis/src/test/scala/RedisPersistentActorSpec.scala @@ -87,7 +87,7 @@ class AccountActor extends Transactor { } @serializable class PersistentFailerActor extends Transactor { - //timeout = 5000 + // timeout = 5000 def receive = { case "Failure" => throw new RuntimeException("expected") diff --git a/akka-persistence/akka-persistence-redis/src/test/scala/RedisPersistentSortedSetSpec.scala b/akka-persistence/akka-persistence-redis/src/test/scala/RedisPersistentSortedSetSpec.scala new file mode 100644 index 0000000000..a2abb2cd40 --- /dev/null +++ b/akka-persistence/akka-persistence-redis/src/test/scala/RedisPersistentSortedSetSpec.scala @@ -0,0 +1,237 @@ +package se.scalablesolutions.akka.persistence.redis + +import org.scalatest.Spec +import org.scalatest.Assertions +import org.scalatest.matchers.ShouldMatchers +import org.scalatest.BeforeAndAfterAll +import org.scalatest.junit.JUnitRunner +import org.junit.runner.RunWith + +import se.scalablesolutions.akka.actor.{Actor, Transactor} + +/** + * A persistent actor based on Redis sortedset storage. + *

+ * Needs a running Redis server. + * @author Debasish Ghosh + */ + +trait ZScorable { + def zscore: Float +} + +case class Hacker(name: String, birth: String) extends ZScorable { + def zscore = birth.toFloat +} + +class SetThresholdViolationException extends RuntimeException + +// add hacker to the set +case class ADD(h: Hacker) + +// remove hacker from set +case class REMOVE(h: Hacker) + +// size of the set +case object SIZE + +// zscore of the hacker +case class SCORE(h: Hacker) + +// zrange +case class RANGE(start: Int, end: Int) + +// add and remove subject to the condition that there will be at least 3 hackers +case class MULTI(add: List[Hacker], rem: List[Hacker], failer: Actor) + +class SortedSetActor extends Transactor { + timeout = 100000 + private lazy val hackers = RedisStorage.newSortedSet + + def receive = { + case ADD(h) => + hackers.+(h.name.getBytes, h.zscore) + reply(true) + + case REMOVE(h) => + hackers.-(h.name.getBytes) + reply(true) + + case SIZE => + reply(hackers.size) + + case SCORE(h) => + reply(hackers.zscore(h.name.getBytes)) + + case RANGE(s, e) => + reply(hackers.zrange(s, e)) + + case MULTI(a, r, failer) => + a.foreach{ h: Hacker => + hackers.+(h.name.getBytes, h.zscore) + } + try { + r.foreach{ h => + if (hackers.size <= 3) + throw new SetThresholdViolationException + hackers.-(h.name.getBytes) + } + } catch { + case e: Exception => + failer !! "Failure" + } + reply((a.size, r.size)) + } +} + +import RedisStorageBackend._ + +@RunWith(classOf[JUnitRunner]) +class RedisPersistentSortedSetSpec extends + Spec with + ShouldMatchers with + BeforeAndAfterAll { + + override def beforeAll { + flushDB + println("** destroyed database") + } + + override def afterAll { + flushDB + println("** destroyed database") + } + + val h1 = Hacker("Alan kay", "1940") + val h2 = Hacker("Richard Stallman", "1953") + val h3 = Hacker("Yukihiro Matsumoto", "1965") + val h4 = Hacker("Claude Shannon", "1916") + val h5 = Hacker("Linus Torvalds", "1969") + val h6 = Hacker("Alan Turing", "1912") + + describe("Add and report cardinality of the set") { + val qa = new SortedSetActor + qa.start + + it("should enter 6 hackers") { + qa !! ADD(h1) + qa !! ADD(h2) + qa !! ADD(h3) + qa !! ADD(h4) + qa !! ADD(h5) + qa !! ADD(h6) + (qa !! SIZE).get.asInstanceOf[Int] should equal(6) + } + + it("should fetch correct scores for hackers") { + (qa !! SCORE(h1)).get.asInstanceOf[Float] should equal(1940.0f) + (qa !! SCORE(h5)).get.asInstanceOf[Float] should equal(1969.0f) + (qa !! SCORE(h6)).get.asInstanceOf[Float] should equal(1912.0f) + } + + it("should fetch proper range") { + (qa !! RANGE(0, 4)).get.asInstanceOf[List[_]].size should equal(5) + (qa !! RANGE(0, 6)).get.asInstanceOf[List[_]].size should equal(6) + } + + it("should remove and throw exception for removing non-existent hackers") { + qa !! REMOVE(h2) + (qa !! SIZE).get.asInstanceOf[Int] should equal(5) + qa !! REMOVE(h3) + (qa !! SIZE).get.asInstanceOf[Int] should equal(4) + val h7 = Hacker("Paul Snively", "1952") + try { + qa !! REMOVE(h7) + } + catch { + case e: Predef.NoSuchElementException => + e.getMessage should endWith("not present") + } + } + + it("should change score for entering the same hacker name with diff score") { + (qa !! SIZE).get.asInstanceOf[Int] should equal(4) + + // same name as h6 + val h7 = Hacker("Alan Turing", "1992") + qa !! ADD(h7) + + // size remains same + (qa !! SIZE).get.asInstanceOf[Int] should equal(4) + + // score updated + (qa !! SCORE(h7)).get.asInstanceOf[Float] should equal(1992.0f) + } + } + + describe("Transaction semantics") { + it("should rollback on exception") { + val qa = new SortedSetActor + qa.start + + val failer = new PersistentFailerActor + failer.start + + (qa !! SIZE).get.asInstanceOf[Int] should equal(0) + val add = List(h1, h2, h3, h4) + val rem = List(h2) + (qa !! MULTI(add, rem, failer)).get.asInstanceOf[Tuple2[Int, Int]] should equal((4,1)) + (qa !! SIZE).get.asInstanceOf[Int] should equal(3) + // size == 3 + + // add 2 more + val add1 = List(h5, h6) + + // remove 3 + val rem1 = List(h1, h3, h4) + try { + qa !! MULTI(add1, rem1, failer) + } catch { case e: Exception => {} + } + (qa !! SIZE).get.asInstanceOf[Int] should equal(3) + } + } + + describe("zrange") { + it ("should report proper range") { + val qa = new SortedSetActor + qa.start + qa !! ADD(h1) + qa !! ADD(h2) + qa !! ADD(h3) + qa !! ADD(h4) + qa !! ADD(h5) + qa !! ADD(h6) + (qa !! SIZE).get.asInstanceOf[Int] should equal(6) + val l = (qa !! RANGE(0, 6)).get.asInstanceOf[List[(Array[Byte], Float)]] + l.map { case (e, s) => (new String(e), s) }.head should equal(("Alan Turing", 1912.0f)) + val h7 = Hacker("Alan Turing", "1992") + qa !! ADD(h7) + (qa !! SIZE).get.asInstanceOf[Int] should equal(6) + val m = (qa !! RANGE(0, 6)).get.asInstanceOf[List[(Array[Byte], Float)]] + m.map { case (e, s) => (new String(e), s) }.head should equal(("Claude Shannon", 1916.0f)) + } + + it ("should report proper rge") { + val qa = new SortedSetActor + qa.start + qa !! ADD(h1) + qa !! ADD(h2) + qa !! ADD(h3) + qa !! ADD(h4) + qa !! ADD(h5) + qa !! ADD(h6) + (qa !! SIZE).get.asInstanceOf[Int] should equal(6) + (qa !! RANGE(0, 5)).get.asInstanceOf[List[_]].size should equal(6) + (qa !! RANGE(0, 6)).get.asInstanceOf[List[_]].size should equal(6) + (qa !! RANGE(0, 3)).get.asInstanceOf[List[_]].size should equal(4) + (qa !! RANGE(0, 1)).get.asInstanceOf[List[_]].size should equal(2) + (qa !! RANGE(0, 0)).get.asInstanceOf[List[_]].size should equal(1) + (qa !! RANGE(3, 1)).get.asInstanceOf[List[_]].size should equal(0) + (qa !! RANGE(0, -1)).get.asInstanceOf[List[_]].size should equal(6) + (qa !! RANGE(0, -2)).get.asInstanceOf[List[_]].size should equal(5) + (qa !! RANGE(0, -4)).get.asInstanceOf[List[_]].size should equal(3) + (qa !! RANGE(-4, -1)).get.asInstanceOf[List[_]].size should equal(4) + } + } +} diff --git a/akka-persistence/akka-persistence-redis/src/test/scala/RedisStorageBackendSpec.scala b/akka-persistence/akka-persistence-redis/src/test/scala/RedisStorageBackendSpec.scala index cfe704c6ba..44081a43c6 100644 --- a/akka-persistence/akka-persistence-redis/src/test/scala/RedisStorageBackendSpec.scala +++ b/akka-persistence/akka-persistence-redis/src/test/scala/RedisStorageBackendSpec.scala @@ -191,10 +191,10 @@ class RedisStorageBackendSpec extends zcard("hackers") should equal(6) - zscore("hackers", "alan turing".getBytes) should equal("1912") - zscore("hackers", "richard stallman".getBytes) should equal("1953") - zscore("hackers", "claude shannon".getBytes) should equal("1916") - zscore("hackers", "linus torvalds".getBytes) should equal("1969") + zscore("hackers", "alan turing".getBytes).get should equal(1912.0f) + zscore("hackers", "richard stallman".getBytes).get should equal(1953.0f) + zscore("hackers", "claude shannon".getBytes).get should equal(1916.0f) + zscore("hackers", "linus torvalds".getBytes).get should equal(1969.0f) val s: List[Array[Byte]] = zrange("hackers", 0, 2) s.size should equal(3) @@ -206,6 +206,10 @@ class RedisStorageBackendSpec extends val t: List[Array[Byte]] = zrange("hackers", 0, -1) t.size should equal(6) t.map(new String(_)) should equal(sorted) + + val u: List[(Array[Byte], Float)] = zrangeWithScore("hackers", 0, -1) + u.size should equal(6) + u.map{ case (e, s) => new String(e) } should equal(sorted) } } } diff --git a/embedded-repo/com/redis/redisclient/1.1/redisclient-1.1.jar b/embedded-repo/com/redis/redisclient/1.1/redisclient-1.1.jar deleted file mode 100644 index a269f15f7aaab12b04c9a2ba8fc4c6572b0f017f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 47464 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 Iyb8nv0Q<{W6aWAK diff --git a/embedded-repo/com/redis/redisclient/1.1/redisclient-1.1.pom b/embedded-repo/com/redis/redisclient/1.1/redisclient-1.1.pom deleted file mode 100755 index 16dd81402a..0000000000 --- a/embedded-repo/com/redis/redisclient/1.1/redisclient-1.1.pom +++ /dev/null @@ -1,8 +0,0 @@ - - - 4.0.0 - com.redis - redisclient - 1.1 - jar - diff --git a/project/build/AkkaProject.scala b/project/build/AkkaProject.scala index cd46dbea5c..783a8d010c 100644 --- a/project/build/AkkaProject.scala +++ b/project/build/AkkaProject.scala @@ -240,7 +240,7 @@ class AkkaParent(info: ProjectInfo) extends DefaultProject(info) { } class AkkaRedisProject(info: ProjectInfo) extends DefaultProject(info) { - val redis = "com.redis" % "redisclient" % "1.1" % "compile" + val redis = "com.redis" % "redisclient" % "1.2-SNAPSHOT" % "compile" override def testOptions = TestFilter((name: String) => name.endsWith("Test")) :: Nil lazy val dist = deployTask(info, distPath) dependsOn(`package`) describedAs("Deploying") } From d50bfe9d89971e6303bc2a44aa9cd23a5a481999 Mon Sep 17 00:00:00 2001 From: Debasish Ghosh Date: Thu, 18 Mar 2010 11:00:02 +0530 Subject: [PATCH 11/11] added new jar 1.2-SNAPSHOT for redisclient --- .../1.2-SNAPSHOT/redisclient-1.2-SNAPSHOT.jar | Bin 0 -> 45796 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 embedded-repo/com/redis/redisclient/1.2-SNAPSHOT/redisclient-1.2-SNAPSHOT.jar diff --git a/embedded-repo/com/redis/redisclient/1.2-SNAPSHOT/redisclient-1.2-SNAPSHOT.jar b/embedded-repo/com/redis/redisclient/1.2-SNAPSHOT/redisclient-1.2-SNAPSHOT.jar new file mode 100644 index 0000000000000000000000000000000000000000..88815a75d952c051b1282320cc463a5346d7050c GIT binary patch literal 45796 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 Kz+krw!~+2S^+byR literal 0 HcmV?d00001