2010-12-14 18:22:46 +01:00
/* *
* Copyright ( C ) 2009 - 2010 Scalable Solutions AB < http : //scalablesolutions.se>
*/
package akka.remoteinterface
import akka.japi.Creator
2010-12-15 17:52:31 +01:00
import akka.actor._
2011-05-24 19:04:25 +02:00
import DeploymentConfig._
2010-12-15 17:52:31 +01:00
import akka.util._
2011-05-23 11:31:01 +02:00
import akka.dispatch.Promise
2011-05-16 09:47:23 +02:00
import akka.serialization._
2010-12-29 16:08:43 +01:00
import akka.AkkaException
2011-03-24 12:48:40 +01:00
import scala.reflect.BeanProperty
import java.net.InetSocketAddress
import java.util.concurrent.ConcurrentHashMap
2011-05-18 17:25:30 +02:00
import java.io. { PrintWriter , PrintStream }
2011-05-03 16:26:30 +02:00
import java.lang.reflect.InvocationTargetException
2010-12-15 17:52:31 +01:00
2011-02-28 22:54:32 +01:00
trait RemoteModule {
2011-03-31 15:55:30 +02:00
val UUID_PREFIX = "uuid:" . intern
2010-12-21 14:36:47 +01:00
2010-12-15 17:52:31 +01:00
def optimizeLocalScoped_? ( ) : Boolean //Apply optimizations for remote operations in local scope
2011-05-18 17:25:30 +02:00
protected [ akka ] def notifyListeners ( message : ⇒ Any ) : Unit
2010-12-17 16:09:21 +01:00
2011-05-24 19:04:25 +02:00
private [ akka ] def actors : ConcurrentHashMap [ String , ActorRef ] // FIXME need to invalidate this cache on replication
private [ akka ] def actorsByUuid : ConcurrentHashMap [ String , ActorRef ] // FIXME remove actorsByUuid map?
private [ akka ] def actorsFactories : ConcurrentHashMap [ String , ( ) ⇒ ActorRef ] // FIXME what to do wit actorsFactories map?
2010-12-21 14:36:47 +01:00
2011-05-25 16:18:35 +02:00
private [ akka ] def findActorByAddress ( address : String ) : ActorRef = actors . get ( address )
private [ akka ] def findActorByUuid ( uuid : String ) : ActorRef = actorsByUuid . get ( uuid )
private [ akka ] def findActorFactory ( address : String ) : ( ) ⇒ ActorRef = actorsFactories . get ( address )
private [ akka ] def findActorByAddressOrUuid ( address : String , uuid : String ) : ActorRef = {
var actorRefOrNull = if ( address . startsWith ( UUID_PREFIX ) ) findActorByUuid ( address . substring ( UUID_PREFIX . length ) )
else findActorByAddress ( address )
if ( actorRefOrNull eq null ) actorRefOrNull = findActorByUuid ( uuid )
actorRefOrNull
}
/*
2011-05-24 19:04:25 +02:00
private [ akka ] def findActorByAddress ( address : String ) : ActorRef = {
val cachedActorRef = actors . get ( address )
if ( cachedActorRef ne null ) cachedActorRef
else {
val actorRef =
Deployer . lookupDeploymentFor ( address ) match {
case Some ( Deploy ( _ , router , _ , Clustered ( home , _ , _ ) ) ) ⇒
2010-12-21 14:36:47 +01:00
2011-05-24 19:04:25 +02:00
if ( DeploymentConfig . isHomeNode ( home ) ) { // on home node
Actor . registry . actorFor ( address ) match { // try to look up in actor registry
case Some ( actorRef ) ⇒ // in registry -> DONE
actorRef
case None ⇒ // not in registry -> check out as 'ref' from cluster (which puts it in actor registry for next time around)
Actor . cluster . ref ( address , DeploymentConfig . routerTypeFor ( router ) )
}
} else throw new IllegalActorStateException ( "Trying to look up remote actor on non-home node. FIXME: fix this behavior" )
case Some ( Deploy ( _ , _ , _ , Local ) ) ⇒
Actor . registry . actorFor ( address ) . getOrElse ( throw new IllegalActorStateException ( "Could not lookup locally deployed actor in actor registry" ) )
case _ ⇒
actors . get ( address ) // FIXME do we need to fall back to local here? If it is not clustered then it should not be a remote actor in the first place. Throw exception.
}
actors . put ( address , actorRef ) // cache it for next time around
actorRef
}
}
2010-12-21 14:36:47 +01:00
2011-05-18 17:25:30 +02:00
private [ akka ] def findActorByUuid ( uuid : String ) : ActorRef = actorsByUuid . get ( uuid )
2010-12-21 14:36:47 +01:00
2011-05-18 17:25:30 +02:00
private [ akka ] def findActorFactory ( address : String ) : ( ) ⇒ ActorRef = actorsFactories . get ( address )
2010-12-21 14:36:47 +01:00
2011-05-18 17:25:30 +02:00
private [ akka ] def findActorByAddressOrUuid ( address : String , uuid : String ) : ActorRef = {
2011-05-24 19:04:25 +02:00
// find by address
var actorRefOrNull =
if ( address . startsWith ( UUID_PREFIX ) ) findActorByUuid ( address . substring ( UUID_PREFIX . length ) ) // FIXME remove lookup by UUID? probably
else findActorByAddress ( address )
// find by uuid
2010-12-21 14:36:47 +01:00
if ( actorRefOrNull eq null ) actorRefOrNull = findActorByUuid ( uuid )
actorRefOrNull
}
2011-05-25 16:18:35 +02:00
*/
2010-12-15 17:52:31 +01:00
}
2010-12-29 16:08:43 +01:00
/* *
* Life - cycle events for RemoteClient .
*/
2011-01-05 17:03:40 +01:00
sealed trait RemoteClientLifeCycleEvent
2010-12-29 16:08:43 +01:00
case class RemoteClientError (
2010-12-30 14:59:00 +01:00
@BeanProperty cause : Throwable ,
2011-01-05 17:03:40 +01:00
@BeanProperty client : RemoteClientModule ,
@BeanProperty remoteAddress : InetSocketAddress ) extends RemoteClientLifeCycleEvent
2010-12-29 16:08:43 +01:00
case class RemoteClientDisconnected (
2011-01-05 17:03:40 +01:00
@BeanProperty client : RemoteClientModule ,
@BeanProperty remoteAddress : InetSocketAddress ) extends RemoteClientLifeCycleEvent
2010-12-29 16:08:43 +01:00
case class RemoteClientConnected (
2011-01-05 17:03:40 +01:00
@BeanProperty client : RemoteClientModule ,
@BeanProperty remoteAddress : InetSocketAddress ) extends RemoteClientLifeCycleEvent
2010-12-29 16:08:43 +01:00
case class RemoteClientStarted (
2011-01-05 17:03:40 +01:00
@BeanProperty client : RemoteClientModule ,
@BeanProperty remoteAddress : InetSocketAddress ) extends RemoteClientLifeCycleEvent
2010-12-29 16:08:43 +01:00
case class RemoteClientShutdown (
2011-01-05 17:03:40 +01:00
@BeanProperty client : RemoteClientModule ,
@BeanProperty remoteAddress : InetSocketAddress ) extends RemoteClientLifeCycleEvent
2010-12-30 14:59:00 +01:00
case class RemoteClientWriteFailed (
@BeanProperty request : AnyRef ,
@BeanProperty cause : Throwable ,
2011-01-05 17:03:40 +01:00
@BeanProperty client : RemoteClientModule ,
@BeanProperty remoteAddress : InetSocketAddress ) extends RemoteClientLifeCycleEvent
2010-12-29 16:08:43 +01:00
/* *
* Life - cycle events for RemoteServer .
*/
2011-01-05 17:03:40 +01:00
sealed trait RemoteServerLifeCycleEvent
2010-12-29 16:08:43 +01:00
case class RemoteServerStarted (
@BeanProperty val server : RemoteServerModule ) extends RemoteServerLifeCycleEvent
case class RemoteServerShutdown (
@BeanProperty val server : RemoteServerModule ) extends RemoteServerLifeCycleEvent
case class RemoteServerError (
@BeanProperty val cause : Throwable ,
@BeanProperty val server : RemoteServerModule ) extends RemoteServerLifeCycleEvent
case class RemoteServerClientConnected (
@BeanProperty val server : RemoteServerModule ,
@BeanProperty val clientAddress : Option [ InetSocketAddress ] ) extends RemoteServerLifeCycleEvent
case class RemoteServerClientDisconnected (
@BeanProperty val server : RemoteServerModule ,
@BeanProperty val clientAddress : Option [ InetSocketAddress ] ) extends RemoteServerLifeCycleEvent
case class RemoteServerClientClosed (
@BeanProperty val server : RemoteServerModule ,
@BeanProperty val clientAddress : Option [ InetSocketAddress ] ) extends RemoteServerLifeCycleEvent
2011-01-03 14:44:15 +01:00
case class RemoteServerWriteFailed (
@BeanProperty request : AnyRef ,
@BeanProperty cause : Throwable ,
2011-01-05 17:03:40 +01:00
@BeanProperty server : RemoteServerModule ,
@BeanProperty clientAddress : Option [ InetSocketAddress ] ) extends RemoteServerLifeCycleEvent
2010-12-29 16:08:43 +01:00
/* *
* Thrown for example when trying to send a message using a RemoteClient that is either not started or shut down .
*/
2011-03-24 16:23:37 +01:00
class RemoteClientException private [ akka ] (
message : String ,
@BeanProperty val client : RemoteClientModule ,
2011-04-29 17:15:00 +02:00
val remoteAddress : InetSocketAddress , cause : Throwable = null ) extends AkkaException ( message , cause )
2010-12-29 16:08:43 +01:00
/* *
2011-03-31 15:55:30 +02:00
* Thrown when the remote server actor dispatching fails for some reason .
*/
class RemoteServerException private [ akka ] ( message : String ) extends AkkaException ( message )
/* *
* Thrown when a remote exception sent over the wire cannot be loaded and instantiated
2010-12-29 16:08:43 +01:00
*/
2011-03-25 16:25:36 +01:00
case class CannotInstantiateRemoteExceptionDueToRemoteProtocolParsingErrorException private [ akka ] ( cause : Throwable , originalClassName : String , originalMessage : String )
2011-03-24 16:23:37 +01:00
extends AkkaException ( "\nParsingError[%s]\nOriginalException[%s]\nOriginalMessage[%s]"
2011-05-18 17:25:30 +02:00
. format ( cause . toString , originalClassName , originalMessage ) ) {
override def printStackTrace = cause . printStackTrace
2011-03-24 16:23:37 +01:00
override def printStackTrace ( printStream : PrintStream ) = cause . printStackTrace ( printStream )
override def printStackTrace ( printWriter : PrintWriter ) = cause . printStackTrace ( printWriter )
}
2010-12-15 17:52:31 +01:00
abstract class RemoteSupport extends ListenerManagement with RemoteServerModule with RemoteClientModule {
2011-03-24 12:48:40 +01:00
2011-05-03 21:04:45 +02:00
val eventHandler : ActorRef = {
2011-05-16 09:47:23 +02:00
implicit object format extends StatelessActorFormat [ RemoteEventHandler ]
val clazz = classOf [ RemoteEventHandler ]
val handler = Actor . actorOf ( clazz , clazz . getName ) . start ( )
2011-03-24 12:48:40 +01:00
// add the remote client and server listener that pipes the events to the event handler system
addListener ( handler )
handler
}
2011-04-29 10:20:16 +02:00
def shutdown ( ) {
2011-04-12 10:53:56 +02:00
eventHandler . stop ( )
2011-03-24 12:48:40 +01:00
removeListener ( eventHandler )
2011-05-03 21:04:45 +02:00
this . shutdownClientModule ( )
this . shutdownServerModule ( )
2010-12-17 16:09:21 +01:00
clear
2010-12-15 17:52:31 +01:00
}
2010-12-22 10:10:04 +01:00
2010-12-15 17:52:31 +01:00
protected override def manageLifeCycleOfListeners = false
2011-05-18 17:25:30 +02:00
protected [ akka ] override def notifyListeners ( message : ⇒ Any ) : Unit = super . notifyListeners ( message )
2010-12-17 16:09:21 +01:00
2011-05-18 17:25:30 +02:00
private [ akka ] val actors = new ConcurrentHashMap [ String , ActorRef ]
private [ akka ] val actorsByUuid = new ConcurrentHashMap [ String , ActorRef ]
private [ akka ] val actorsFactories = new ConcurrentHashMap [ String , ( ) ⇒ ActorRef ]
2010-12-17 16:09:21 +01:00
def clear {
2011-03-08 11:46:03 +01:00
actors . clear
actorsByUuid . clear
2011-03-07 21:54:00 +01:00
actorsFactories . clear
2010-12-17 16:09:21 +01:00
}
2010-12-15 17:52:31 +01:00
}
2010-12-14 18:22:46 +01:00
/* *
2011-01-04 13:24:28 +01:00
* This is the interface for the RemoteServer functionality , it 's used in Actor . remote
2010-12-14 18:22:46 +01:00
*/
2010-12-15 17:52:31 +01:00
trait RemoteServerModule extends RemoteModule {
2010-12-14 18:22:46 +01:00
protected val guard = new ReentrantGuard
/* *
* Signals whether the server is up and running or not
*/
def isRunning : Boolean
/* *
* Gets the name of the server instance
*/
def name : String
/* *
2010-12-21 14:36:47 +01:00
* Gets the address of the server instance
2010-12-14 18:22:46 +01:00
*/
2010-12-21 14:36:47 +01:00
def address : InetSocketAddress
2010-12-14 18:22:46 +01:00
/* *
* Starts the server up
*/
2011-01-05 16:36:50 +01:00
def start ( ) : RemoteServerModule =
2011-04-08 15:29:14 +02:00
start ( ReflectiveAccess . RemoteModule . configDefaultAddress . getAddress . getHostAddress ,
2011-05-18 17:25:30 +02:00
ReflectiveAccess . RemoteModule . configDefaultAddress . getPort ,
None )
2011-01-05 16:36:50 +01:00
/* *
* Starts the server up
*/
def start ( loader : ClassLoader ) : RemoteServerModule =
2011-04-08 15:29:14 +02:00
start ( ReflectiveAccess . RemoteModule . configDefaultAddress . getAddress . getHostAddress ,
2011-05-18 17:25:30 +02:00
ReflectiveAccess . RemoteModule . configDefaultAddress . getPort ,
Option ( loader ) )
2011-01-05 16:36:50 +01:00
/* *
* Starts the server up
*/
2011-01-05 17:03:40 +01:00
def start ( host : String , port : Int ) : RemoteServerModule =
2011-05-18 17:25:30 +02:00
start ( host , port , None )
2011-01-05 17:03:40 +01:00
/* *
* Starts the server up
*/
def start ( host : String , port : Int , loader : ClassLoader ) : RemoteServerModule =
2011-05-18 17:25:30 +02:00
start ( host , port , Option ( loader ) )
2011-01-05 17:03:40 +01:00
/* *
* Starts the server up
*/
def start ( host : String , port : Int , loader : Option [ ClassLoader ] ) : RemoteServerModule
2010-12-14 18:22:46 +01:00
/* *
* Shuts the server down
*/
2011-01-05 16:36:50 +01:00
def shutdownServerModule ( ) : Unit
2010-12-14 18:22:46 +01:00
/* *
* Register Remote Actor by the Actor 's 'id' field . It starts the Actor if it is not started already .
*/
2011-04-08 21:16:05 +02:00
def register ( actorRef : ActorRef ) : Unit = register ( actorRef . address , actorRef )
2010-12-14 18:22:46 +01:00
/* *
* Register Remote Actor by the Actor 's uuid field . It starts the Actor if it is not started already .
*/
def registerByUuid ( actorRef : ActorRef ) : Unit
/* *
2011-04-29 17:09:22 +02:00
* Register Remote Actor by a specific 'id' passed as argument . The actor is registered by UUID rather than ID
* when prefixing the handle with the “ uuid : ” protocol .
2010-12-14 18:22:46 +01:00
* < p />
* NOTE : If you use this method to register your remote actor then you must unregister the actor by this ID yourself .
*/
2011-04-08 21:16:05 +02:00
def register ( address : String , actorRef : ActorRef ) : Unit
2010-12-14 18:22:46 +01:00
/* *
* Register Remote Session Actor by a specific 'id' passed as argument .
* < p />
* NOTE : If you use this method to register your remote actor then you must unregister the actor by this ID yourself .
*/
2011-05-18 17:25:30 +02:00
def registerPerSession ( address : String , factory : ⇒ ActorRef ) : Unit
2010-12-14 18:22:46 +01:00
/* *
* Register Remote Session Actor by a specific 'id' passed as argument .
* < p />
* NOTE : If you use this method to register your remote actor then you must unregister the actor by this ID yourself .
* Java API
*/
2011-04-08 21:16:05 +02:00
def registerPerSession ( address : String , factory : Creator [ ActorRef ] ) : Unit = registerPerSession ( address , factory . create )
2010-12-14 18:22:46 +01:00
/* *
* Unregister Remote Actor that is registered using its 'id' field ( not custom ID ) .
*/
def unregister ( actorRef : ActorRef ) : Unit
/* *
* Unregister Remote Actor by specific 'id' .
* < p />
* NOTE : You need to call this method if you have registered an actor by a custom ID .
*/
2011-04-08 21:16:05 +02:00
def unregister ( address : String ) : Unit
2010-12-14 18:22:46 +01:00
/* *
* Unregister Remote Actor by specific 'id' .
* < p />
* NOTE : You need to call this method if you have registered an actor by a custom ID .
*/
2011-04-08 21:16:05 +02:00
def unregisterPerSession ( address : String ) : Unit
2010-12-15 17:52:31 +01:00
}
2011-05-18 17:25:30 +02:00
trait RemoteClientModule extends RemoteModule { self : RemoteModule ⇒
2010-12-15 17:52:31 +01:00
2011-04-29 15:47:56 +02:00
def actorFor ( address : String , hostname : String , port : Int ) : ActorRef =
actorFor ( address , Actor . TIMEOUT , hostname , port , None )
2010-12-15 17:52:31 +01:00
2011-04-29 15:47:56 +02:00
def actorFor ( address : String , hostname : String , port : Int , loader : ClassLoader ) : ActorRef =
actorFor ( address , Actor . TIMEOUT , hostname , port , Some ( loader ) )
2010-12-15 17:52:31 +01:00
2011-04-29 15:47:56 +02:00
def actorFor ( address : String , timeout : Long , hostname : String , port : Int ) : ActorRef =
actorFor ( address , timeout , hostname , port , None )
2010-12-15 17:52:31 +01:00
2011-04-29 15:47:56 +02:00
def actorFor ( address : String , timeout : Long , hostname : String , port : Int , loader : ClassLoader ) : ActorRef =
actorFor ( address , timeout , hostname , port , Some ( loader ) )
2010-12-15 17:52:31 +01:00
2010-12-29 17:59:38 +01:00
/* *
* Clean - up all open connections .
*/
2011-01-05 16:36:50 +01:00
def shutdownClientModule ( ) : Unit
2010-12-29 17:59:38 +01:00
/* *
* Shuts down a specific client connected to the supplied remote address returns true if successful
*/
def shutdownClientConnection ( address : InetSocketAddress ) : Boolean
/* *
* Restarts a specific client connected to the supplied remote address , but only if the client is not shut down
*/
def restartClientConnection ( address : InetSocketAddress ) : Boolean
/* * Methods that needs to be implemented by a transport * */
2010-12-15 17:52:31 +01:00
2011-04-29 15:47:56 +02:00
protected [ akka ] def actorFor ( address : String , timeout : Long , hostname : String , port : Int , loader : Option [ ClassLoader ] ) : ActorRef
2010-12-15 17:52:31 +01:00
2010-12-29 17:59:38 +01:00
protected [ akka ] def send [ T ] ( message : Any ,
senderOption : Option [ ActorRef ] ,
2011-05-23 11:31:01 +02:00
senderFuture : Option [ Promise [ T ] ] ,
2011-04-18 13:18:47 +02:00
remoteAddress : InetSocketAddress ,
2010-12-29 17:59:38 +01:00
timeout : Long ,
isOneWay : Boolean ,
actorRef : ActorRef ,
2011-05-23 11:31:01 +02:00
loader : Option [ ClassLoader ] ) : Option [ Promise [ T ] ]
2011-04-01 14:29:26 +02:00
}