/** * Copyright (C) 2009-2010 Typesafe Inc. */ package akka.remote import akka.japi.Creator import akka.actor._ import DeploymentConfig._ import akka.util._ import akka.dispatch.Promise import akka.serialization._ import akka.{ AkkaException, AkkaApplication } import scala.reflect.BeanProperty import java.net.InetSocketAddress import java.util.concurrent.ConcurrentHashMap import java.io.{ PrintWriter, PrintStream } import java.lang.reflect.InvocationTargetException class RemoteException(message: String) extends AkkaException(message) trait RemoteModule { protected[akka] def notifyListeners(message: ⇒ Any): Unit } /** * Remote life-cycle events. */ sealed trait RemoteLifeCycleEvent /** * Life-cycle events for RemoteClient. */ trait RemoteClientLifeCycleEvent extends RemoteLifeCycleEvent { def remoteAddress: InetSocketAddress } case class RemoteClientError( @BeanProperty cause: Throwable, @BeanProperty client: RemoteClientModule, @BeanProperty remoteAddress: InetSocketAddress) extends RemoteClientLifeCycleEvent case class RemoteClientDisconnected( @BeanProperty client: RemoteClientModule, @BeanProperty remoteAddress: InetSocketAddress) extends RemoteClientLifeCycleEvent case class RemoteClientConnected( @BeanProperty client: RemoteClientModule, @BeanProperty remoteAddress: InetSocketAddress) extends RemoteClientLifeCycleEvent case class RemoteClientStarted( @BeanProperty client: RemoteClientModule, @BeanProperty remoteAddress: InetSocketAddress) extends RemoteClientLifeCycleEvent case class RemoteClientShutdown( @BeanProperty client: RemoteClientModule, @BeanProperty remoteAddress: InetSocketAddress) extends RemoteClientLifeCycleEvent case class RemoteClientWriteFailed( @BeanProperty request: AnyRef, @BeanProperty cause: Throwable, @BeanProperty client: RemoteClientModule, @BeanProperty remoteAddress: InetSocketAddress) extends RemoteClientLifeCycleEvent /** * Life-cycle events for RemoteServer. */ trait RemoteServerLifeCycleEvent extends RemoteLifeCycleEvent 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 case class RemoteServerWriteFailed( @BeanProperty request: AnyRef, @BeanProperty cause: Throwable, @BeanProperty server: RemoteServerModule, @BeanProperty clientAddress: Option[InetSocketAddress]) extends RemoteServerLifeCycleEvent /** * Thrown for example when trying to send a message using a RemoteClient that is either not started or shut down. */ class RemoteClientException private[akka] ( message: String, @BeanProperty val client: RemoteClientModule, val remoteAddress: InetSocketAddress, cause: Throwable = null) extends AkkaException(message, cause) /** * 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 */ case class CannotInstantiateRemoteExceptionDueToRemoteProtocolParsingErrorException private[akka] (cause: Throwable, originalClassName: String, originalMessage: String) extends AkkaException("\nParsingError[%s]\nOriginalException[%s]\nOriginalMessage[%s]" .format(cause.toString, originalClassName, originalMessage)) { override def printStackTrace = cause.printStackTrace override def printStackTrace(printStream: PrintStream) = cause.printStackTrace(printStream) override def printStackTrace(printWriter: PrintWriter) = cause.printStackTrace(printWriter) } abstract class RemoteSupport(val app: AkkaApplication) extends RemoteServerModule with RemoteClientModule { def shutdown() { this.shutdownClientModule() this.shutdownServerModule() } protected[akka] override def notifyListeners(message: ⇒ Any): Unit = app.eventHandler.notify(message) } /** * This is the interface for the RemoteServer functionality, it's used in Actor.remote */ trait RemoteServerModule extends RemoteModule { this: RemoteSupport ⇒ /** * Signals whether the server is up and running or not */ def isRunning: Boolean /** * Gets the name of the server instance */ def name: String /** * Starts the server up */ def start(host: String, port: Int, loader: Option[ClassLoader]): RemoteServerModule /** * Shuts the server down */ def shutdownServerModule(): Unit } trait RemoteClientModule extends RemoteModule { self: RemoteSupport ⇒ /** * Clean-up all open connections. */ def shutdownClientModule(): Unit /** * 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 **/ protected[akka] def send(message: Any, senderOption: Option[ActorRef], remoteAddress: InetSocketAddress, recipient: ActorRef, loader: Option[ClassLoader]): Unit }