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
You’re currently reading “Remote and Dynamic class loading in Scala,” an entry on Coffee Time Code
- Published:
- July 24, 2010 / 10:58 pm
- Category:
- program
- Tags:
No comments yet
Jump to comment form | comment rss [?] | trackback uri [?]