Remote and Dynamic class loading in Scala

  One machine which acts as a server
-------------------------------------------
  1 
  2 package portnode
  3 
  4 import java.io.IOException
  5 import scala.actors.Actor
  6 import scala.actors.Actor._
  7 import scala.actors.Exit
  8 import scala.actors.remote.RemoteActor
  9 import scala.actors.remote.RemoteActor._
 10 
 11 class MyClassLoader(maxclasssize: Int) extends java.lang.ClassLoader {
 12 
 13   var storage: Map[String, Array[Byte]] = Map[String, Array[Byte]]()
 14 
 15   def unloadClass(classname: String): Boolean = {
 16     if(!storage.contains(classname))
 17       return false
 18     else
 19       storage -= classname
 20     true
 21   }
 22 
 23   def storeClass(databytes: Array[Byte], classname: String): Boolean = {
 24     if(storage.contains(classname))
 25       return false
 26 
 27     // This is a extra security to prevent overloding of class with excess data
 28     if(databytes.length > maxclasssize)
 29       return false
 30       
 31     storage += (classname -> databytes)
 32     return true
 33   }
 34 
 35   override def loadClass(name: String, resolve: Boolean): Class[_] =  {
 36 
 37     var c: Class[_] = findLoadedClass (name);
 38     if (c == null) {
 39       try {
 40         c = findSystemClass (name);
 41       } catch {
 42         case e: Exception =>
 43       }
 44     }
 45 
 46     if (c == null) {
 47       
 48       if(!storage.contains(name))
 49         throw new ClassNotFoundException(name)
 50 
 51       try {
 52         val databytes = storage(name)
 53         c = defineClass (name, databytes, 0, databytes.length);
 54         if (c == null) throw new ClassNotFoundException (name);
 55       } catch {
 56         case e: IOException=> throw new ClassNotFoundException(name)
 57       }
 58     }
 59     if (resolve) resolveClass (c);
 60     return c;
 61   }
 62 
 63 }
 64 
 65 class Port(name: String, portnum: Int, classloader: MyClassLoader) extends Actor {
 66   trapExit = true;  
 67   
 68   def act() {
 69     RemoteActor.classLoader = classloader
 70     alive(portnum)
 71     register(Symbol(name), this)
 72 
 73     while(true){
 74       receive { 
 75         case Exit(from: Actor, exc: Exception) => println("Excpetion received"); exit()
 76         case data_name: (Array[Byte], String) => {
 77               val (data, name) = data_name              
 78               if(classloader.storeClass(data, name))
 79                 println("Class [" + name + "] data received")
 80               else
 81                 println("Store failed!")
 82 
 83               val remote = classloader.loadClass(name, true)
 84               val allconstructors = remote.getDeclaredConstructors()
 85               allconstructors.sortWith((x,y) => x.getParameterTypes.length < y.getParameterTypes.length)
 86 
 87               val ref = allconstructors(0).newInstance("vasanth")
 88 
 89               val methods = remote.getMethods()
 90               val method = methods.filter(p => p.getName.equals("getName"))
 91               if(method.isEmpty == false){
 92                 val result = method(0).invoke(ref)
 93                 println("Successfully an object created! and obtained the result: " + result)
 94               } else {
 95                 println("No method named getName to invoke")
 96               }
 97 
 98               
 99         }
100         case _                                => println("Unknown message!")
101       }
102     }
103   }
104 }
105 
106 object Main {
107 
108   /**
109    * @param args the command line arguments
110    */
111   def main(args: Array[String]): Unit = {
112     println("Starting at port 5555...")
113     val myclassloader = new MyClassLoader(1024*128)
114     val port = new Port("remotefirst", 5555, myclassloader)
115     port.start()
116   }
117 
118 }

Second machine which acts like a client
----------------------------------------------------------

package tmpscala

import scala.actors.remote.Node
import scala.actors.remote.RemoteActor
import scala.concurrent.ops._;
import java.io.InputStream
import scala.actors.Actor
import scala.actors.Actor._

class custom(name: String) extends java.io.Serializable {
  val cutomname = name;

  def custom() = {

  }

  def getName(): String = {
    cutomname
  }
}

class simple extends java.io.Serializable {
  var name = "nodefault"

  def simple() = {
    name = "default"
  }

  def getName(): String = {
    name
  }
}

class sender(sendto: Actor) {

  def getClassAsBytes(name: String): Array[Byte] = {
    println("Reading class:" + name)
    val is: InputStream = ClassLoader.getSystemClassLoader().getResourceAsStream(name);
    if(is == null){
      println("Failed loading :" + name)
      return null
    } else {
      var al: List[Byte] = List[Byte]();
      var ch: Int = is.read()

      while(ch >= 0){        
        val c = ch.byteValue();
        al = c :: al
        ch = is.read()
      }

      return al.reverse.toArray[Byte]
    }
  }

  def sendcustom(msg: String, name: String) = {
    val remoteobject = RemoteActor.select(Node("192.168.56.101", 5555), Symbol(name))
    println("Sending custom message")

    //val tst: Array[Byte] = new Array[Byte](3)
    //remoteobject ! tst
    val classname = "tmpscala/custom.class"
    remoteobject ! (getClassAsBytes(classname), "tmpscala.custom")
    //remoteobject ! msg
  }

  def send(msg: String) = {
    sendto ! msg
  }
}

class receiver(name :String) {
  var receiver: Actor = actor {
    RemoteActor.alive(5555)
    RemoteActor.register(Symbol(name), self)

    var exitrequest = false
    loopWhile(exitrequest != true) {
      receive {
        case str: String => println("Received :(" + name + ")" + str)
        case bool: Boolean => {
            if(mailboxSize != 0){
              self ! true
            }
            println("Exit msg got... Quitting..."); exitrequest = true
          }
        case _ => println("Received");
      }
    }
  }
}

object Main {

  /**
   * @param args the command line arguments
   */
  def main(args: Array[String]): Unit = {
//    for(i <- 1 to 10000){
//      spawn {
//        val id = i
//        Thread.sleep(1000)
//        println("Hello, world! [" + i +"]")
//      }
//    }
    val is: InputStream = ClassLoader.getSystemClassLoader().getResourceAsStream("custom")

    val rec = new receiver("first")
    val rec2 = new receiver("second")
    var sen = new sender(rec.receiver)

    for(j<- 1 to 2){
      spawn{
        sen.sendcustom("Iteration :" + j, "remotefirst")
        sen.sendcustom("Iteration :" + j, "second")
      }
    }

    //rec.receiver ! true
  }

}

About this entry