Quem já trabalhou com RMI em Java sabe que hoje em dia é um processo altamente burocrático. Muitos desistem quando seguem um tutorial passo-a-passo e no final não funciona. Eu já havia feito programas que usavam RMI nos primórdios do Java e já achava, por um lado difícil de implementar, por outro lado, mais simples que a alternativa da época que era Corba. Quando precisei usar novamente, há uns dois anos atrás, descobri que estava ainda mais complicado. Quem quiser se aventurar, pode ler o Tutorial sobre RMI da Sun.
Dentre as burocracias, temos que rodar o rmiregistry para ser o registro de objetos distribuídos ou criar um programaticamente. Depois, temos que criar um stub dinamicamente, usar este stub para fazer o bind no registro, criar um SecurityManager, configurar um arquivo policy, criar uma interface e implementá-la, fazer lookup no cliente, parâmetros na execução, etc…
Seguindo a descoberta de Scala, passei pela seção de Actors e achei muito interessante, porém, a implementação que vi era local. Pensei então: Se eu fosse projetar em Scala uma solução de comunicação remota, iria usar o modelo de Actors para tal. Será que não pensaram assim ? Sim ! Exatamente ! E a burocracia ? Menor que essa, só adivinhando !
Para transformar a comunicação local dos Actors em remota, basta apenas colocar a porta TCP a ser usada pelo servidor, registrar-se e no cliente, fazer o lookup. Pronto ! Vejamos um hello world remoto:
Servidor:
package scalademo
import scala.actors.Actor._
import scala.actors.remote.RemoteActor._
object ServerActor {
def main(args: Array[String]) {
actor {
alive(5000)
register('Server, self)
println("Server running..." )
loop {
react {
case text => sender ! "Message |"
+ text + "| was received ok"
}
}
}
}
}
Cliente:
package scalademo
import scala.actors.Actor._
import scala.actors.remote._
import scala.actors.remote.RemoteActor._
object ClientActor {
def main(args: Array[String]) {
actor {
val server = select(Node("localhost", 5000), 'Server)
println("Sending hello..." )
server ! "Hello"
receive {
case text => println(text)
}
}
}
}
Caso queiram ver um exemplo mais completo, recomendo este artigo. Para simplificar, usei objetos da classe String como transporte. Em uma aplicação mais completa, é conveniente usarmos case classes.
Assim como em Java, evito usar um repositório público de classes via HTTP para o classloader. A complicação adicional, que está presente em ambas linguagens, só se justifica quando o lado servidor pode receber objetos de classes não previstas originalmente. Normalmente as aplicações são fechadas, isto é, todas as classes já são conhecidas. Assim, é somente uma questão de empacotar as classes necessárias nos jars do servidor e do cliente.
Abaixo a burocracia ! Escalabilidade é fazer o simples fácil, e o complicado possível.
Alexei Barbosa de Aguiar
