2010-12-14 18:22:46 +01:00
|
|
|
/**
|
2011-07-14 16:03:08 +02:00
|
|
|
* Copyright (C) 2009-2010 Typesafe Inc. <http://www.typesafe.com>
|
2010-12-14 18:22:46 +01:00
|
|
|
*/
|
|
|
|
|
|
2011-09-20 21:44:50 +02:00
|
|
|
package akka.remote
|
2010-12-14 18:22:46 +01:00
|
|
|
|
2010-12-15 17:52:31 +01:00
|
|
|
import akka.actor._
|
2011-11-10 20:08:00 +01:00
|
|
|
import akka.AkkaException
|
2011-03-24 12:48:40 +01:00
|
|
|
import scala.reflect.BeanProperty
|
2011-11-10 17:39:04 +01:00
|
|
|
import java.io.{ PrintWriter, PrintStream }
|
2011-03-24 12:48:40 +01:00
|
|
|
import java.net.InetSocketAddress
|
2011-11-29 16:32:50 +01:00
|
|
|
import java.net.URI
|
|
|
|
|
import java.net.URISyntaxException
|
|
|
|
|
import java.net.InetAddress
|
2011-11-29 21:52:18 +01:00
|
|
|
import java.net.UnknownHostException
|
2011-11-10 17:39:04 +01:00
|
|
|
|
|
|
|
|
object RemoteAddress {
|
2011-11-29 21:52:18 +01:00
|
|
|
def apply(system: String, host: String, port: Int): RemoteAddress = {
|
|
|
|
|
// TODO check whether we should not rather bail out early
|
|
|
|
|
val ip = try InetAddress.getByName(host) catch { case _: UnknownHostException ⇒ null }
|
2011-11-29 16:32:50 +01:00
|
|
|
new RemoteAddress(system, host, ip, port)
|
2011-11-10 17:39:04 +01:00
|
|
|
}
|
|
|
|
|
|
2011-11-29 21:52:18 +01:00
|
|
|
val RE = """(?:(\w+)@)?(\w+):(\d+)""".r
|
|
|
|
|
object Int {
|
|
|
|
|
def unapply(s: String) = Some(Integer.parseInt(s))
|
|
|
|
|
}
|
|
|
|
|
def apply(stringRep: String, defaultSystem: String): RemoteAddress = stringRep match {
|
|
|
|
|
case RE(sys, host, Int(port)) ⇒ apply(if (sys != null) sys else defaultSystem, host, port)
|
|
|
|
|
case _ ⇒ throw new IllegalArgumentException(stringRep + " is not a valid remote address [system@host:port]")
|
2011-11-25 12:02:25 +01:00
|
|
|
}
|
2011-12-09 20:19:59 +01:00
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
object RemoteAddressExtractor {
|
|
|
|
|
def unapply(s: String): Option[RemoteAddress] = {
|
|
|
|
|
try {
|
|
|
|
|
val uri = new URI("akka://" + s)
|
|
|
|
|
if (uri.getScheme != "akka" || uri.getUserInfo == null || uri.getHost == null || uri.getPort == -1) None
|
|
|
|
|
else Some(RemoteAddress(uri.getUserInfo, uri.getHost, uri.getPort))
|
|
|
|
|
} catch {
|
|
|
|
|
case _: URISyntaxException ⇒ None
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-11-10 17:39:04 +01:00
|
|
|
}
|
|
|
|
|
|
2011-11-29 16:32:50 +01:00
|
|
|
case class RemoteAddress(system: String, host: String, ip: InetAddress, port: Int) extends Address {
|
2011-11-24 16:58:23 +01:00
|
|
|
def protocol = "akka"
|
2011-11-10 18:41:51 +01:00
|
|
|
@transient
|
2011-11-29 16:32:50 +01:00
|
|
|
lazy val hostPort = system + "@" + host + ":" + port
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
object RemoteActorPath {
|
|
|
|
|
def unapply(addr: String): Option[(RemoteAddress, Iterable[String])] = {
|
|
|
|
|
try {
|
|
|
|
|
val uri = new URI(addr)
|
2011-12-05 17:31:54 +01:00
|
|
|
if (uri.getScheme != "akka" || uri.getUserInfo == null || uri.getHost == null || uri.getPort == -1 || uri.getPath == null) None
|
|
|
|
|
else Some(RemoteAddress(uri.getUserInfo, uri.getHost, uri.getPort), ActorPath.split(uri.getPath).drop(1))
|
2011-11-29 16:32:50 +01:00
|
|
|
} catch {
|
|
|
|
|
case _: URISyntaxException ⇒ None
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-11-10 17:39:04 +01:00
|
|
|
}
|
2010-12-15 17:52:31 +01:00
|
|
|
|
2011-09-15 10:20:18 +02:00
|
|
|
class RemoteException(message: String) extends AkkaException(message)
|
|
|
|
|
|
2011-02-28 22:54:32 +01:00
|
|
|
trait RemoteModule {
|
2011-10-27 12:23:01 +02:00
|
|
|
protected[akka] def notifyListeners(message: RemoteLifeCycleEvent): Unit
|
2010-12-15 17:52:31 +01:00
|
|
|
}
|
|
|
|
|
|
2011-08-29 11:44:33 +02:00
|
|
|
/**
|
|
|
|
|
* Remote life-cycle events.
|
|
|
|
|
*/
|
|
|
|
|
sealed trait RemoteLifeCycleEvent
|
|
|
|
|
|
2010-12-29 16:08:43 +01:00
|
|
|
/**
|
|
|
|
|
* Life-cycle events for RemoteClient.
|
|
|
|
|
*/
|
2011-08-29 11:44:33 +02:00
|
|
|
trait RemoteClientLifeCycleEvent extends RemoteLifeCycleEvent {
|
2011-11-10 17:39:04 +01:00
|
|
|
def remoteAddress: RemoteAddress
|
2011-08-29 11:44:33 +02:00
|
|
|
}
|
|
|
|
|
|
2010-12-29 16:08:43 +01:00
|
|
|
case class RemoteClientError(
|
2010-12-30 14:59:00 +01:00
|
|
|
@BeanProperty cause: Throwable,
|
2011-11-10 12:23:39 +01:00
|
|
|
@BeanProperty remote: RemoteSupport,
|
2011-11-10 17:39:04 +01:00
|
|
|
@BeanProperty remoteAddress: RemoteAddress) extends RemoteClientLifeCycleEvent
|
2011-09-08 19:45:16 +02:00
|
|
|
|
2010-12-29 16:08:43 +01:00
|
|
|
case class RemoteClientDisconnected(
|
2011-11-10 12:23:39 +01:00
|
|
|
@BeanProperty remote: RemoteSupport,
|
2011-11-10 17:39:04 +01:00
|
|
|
@BeanProperty remoteAddress: RemoteAddress) extends RemoteClientLifeCycleEvent
|
2011-09-08 19:45:16 +02:00
|
|
|
|
2010-12-29 16:08:43 +01:00
|
|
|
case class RemoteClientConnected(
|
2011-11-10 12:23:39 +01:00
|
|
|
@BeanProperty remote: RemoteSupport,
|
2011-11-10 17:39:04 +01:00
|
|
|
@BeanProperty remoteAddress: RemoteAddress) extends RemoteClientLifeCycleEvent
|
2011-09-08 19:45:16 +02:00
|
|
|
|
2010-12-29 16:08:43 +01:00
|
|
|
case class RemoteClientStarted(
|
2011-11-10 12:23:39 +01:00
|
|
|
@BeanProperty remote: RemoteSupport,
|
2011-11-10 17:39:04 +01:00
|
|
|
@BeanProperty remoteAddress: RemoteAddress) extends RemoteClientLifeCycleEvent
|
2011-09-08 19:45:16 +02:00
|
|
|
|
2010-12-29 16:08:43 +01:00
|
|
|
case class RemoteClientShutdown(
|
2011-11-10 12:23:39 +01:00
|
|
|
@BeanProperty remote: RemoteSupport,
|
2011-11-10 17:39:04 +01:00
|
|
|
@BeanProperty remoteAddress: RemoteAddress) extends RemoteClientLifeCycleEvent
|
2011-09-08 19:45:16 +02:00
|
|
|
|
2010-12-30 14:59:00 +01:00
|
|
|
case class RemoteClientWriteFailed(
|
|
|
|
|
@BeanProperty request: AnyRef,
|
|
|
|
|
@BeanProperty cause: Throwable,
|
2011-11-10 12:23:39 +01:00
|
|
|
@BeanProperty remote: RemoteSupport,
|
2011-11-10 17:39:04 +01:00
|
|
|
@BeanProperty remoteAddress: RemoteAddress) extends RemoteClientLifeCycleEvent
|
2010-12-29 16:08:43 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Life-cycle events for RemoteServer.
|
|
|
|
|
*/
|
2011-08-29 11:44:33 +02:00
|
|
|
trait RemoteServerLifeCycleEvent extends RemoteLifeCycleEvent
|
|
|
|
|
|
2010-12-29 16:08:43 +01:00
|
|
|
case class RemoteServerStarted(
|
2011-11-10 12:23:39 +01:00
|
|
|
@BeanProperty remote: RemoteSupport) extends RemoteServerLifeCycleEvent
|
2010-12-29 16:08:43 +01:00
|
|
|
case class RemoteServerShutdown(
|
2011-11-10 12:23:39 +01:00
|
|
|
@BeanProperty remote: RemoteSupport) extends RemoteServerLifeCycleEvent
|
2010-12-29 16:08:43 +01:00
|
|
|
case class RemoteServerError(
|
|
|
|
|
@BeanProperty val cause: Throwable,
|
2011-11-10 12:23:39 +01:00
|
|
|
@BeanProperty remote: RemoteSupport) extends RemoteServerLifeCycleEvent
|
2010-12-29 16:08:43 +01:00
|
|
|
case class RemoteServerClientConnected(
|
2011-11-10 12:23:39 +01:00
|
|
|
@BeanProperty remote: RemoteSupport,
|
2011-11-10 17:39:04 +01:00
|
|
|
@BeanProperty val clientAddress: Option[RemoteAddress]) extends RemoteServerLifeCycleEvent
|
2010-12-29 16:08:43 +01:00
|
|
|
case class RemoteServerClientDisconnected(
|
2011-11-10 12:23:39 +01:00
|
|
|
@BeanProperty remote: RemoteSupport,
|
2011-11-10 17:39:04 +01:00
|
|
|
@BeanProperty val clientAddress: Option[RemoteAddress]) extends RemoteServerLifeCycleEvent
|
2010-12-29 16:08:43 +01:00
|
|
|
case class RemoteServerClientClosed(
|
2011-11-10 12:23:39 +01:00
|
|
|
@BeanProperty remote: RemoteSupport,
|
2011-11-10 17:39:04 +01:00
|
|
|
@BeanProperty val clientAddress: Option[RemoteAddress]) extends RemoteServerLifeCycleEvent
|
2011-01-03 14:44:15 +01:00
|
|
|
case class RemoteServerWriteFailed(
|
|
|
|
|
@BeanProperty request: AnyRef,
|
|
|
|
|
@BeanProperty cause: Throwable,
|
2011-11-10 12:23:39 +01:00
|
|
|
@BeanProperty server: RemoteSupport,
|
2011-11-10 17:39:04 +01:00
|
|
|
@BeanProperty remoteAddress: Option[RemoteAddress]) 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,
|
2011-11-10 12:23:39 +01:00
|
|
|
@BeanProperty val client: RemoteSupport,
|
2011-11-10 17:39:04 +01:00
|
|
|
val remoteAddress: RemoteAddress, 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
|
|
|
|
2011-11-17 12:36:35 +01:00
|
|
|
abstract class RemoteSupport(val system: ActorSystem) {
|
2010-12-14 18:22:46 +01:00
|
|
|
/**
|
2011-11-10 12:23:39 +01:00
|
|
|
* Shuts down the remoting
|
2010-12-14 18:22:46 +01:00
|
|
|
*/
|
2011-11-10 12:23:39 +01:00
|
|
|
def shutdown(): Unit
|
2010-12-14 18:22:46 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Gets the name of the server instance
|
|
|
|
|
*/
|
|
|
|
|
def name: String
|
|
|
|
|
|
2011-01-05 17:03:40 +01:00
|
|
|
/**
|
2011-11-10 12:23:39 +01:00
|
|
|
* Starts up the remoting
|
2011-01-05 17:03:40 +01:00
|
|
|
*/
|
2011-11-10 12:23:39 +01:00
|
|
|
def start(loader: Option[ClassLoader]): Unit
|
2010-12-29 17:59:38 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Shuts down a specific client connected to the supplied remote address returns true if successful
|
|
|
|
|
*/
|
2011-11-10 17:39:04 +01:00
|
|
|
def shutdownClientConnection(address: RemoteAddress): Boolean
|
2010-12-29 17:59:38 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Restarts a specific client connected to the supplied remote address, but only if the client is not shut down
|
|
|
|
|
*/
|
2011-11-10 17:39:04 +01:00
|
|
|
def restartClientConnection(address: RemoteAddress): Boolean
|
2010-12-29 17:59:38 +01:00
|
|
|
|
|
|
|
|
/** Methods that needs to be implemented by a transport **/
|
2010-12-15 17:52:31 +01:00
|
|
|
|
2011-11-03 18:33:57 +01:00
|
|
|
protected[akka] def send(message: Any,
|
|
|
|
|
senderOption: Option[ActorRef],
|
2011-12-07 16:29:12 +01:00
|
|
|
recipient: RemoteActorRef,
|
2011-11-03 18:33:57 +01:00
|
|
|
loader: Option[ClassLoader]): Unit
|
2011-11-10 12:23:39 +01:00
|
|
|
|
2011-11-17 12:36:35 +01:00
|
|
|
protected[akka] def notifyListeners(message: RemoteLifeCycleEvent): Unit = system.eventStream.publish(message)
|
2011-11-10 12:23:39 +01:00
|
|
|
|
|
|
|
|
override def toString = name
|
2011-04-01 14:29:26 +02:00
|
|
|
}
|