summaryrefslogtreecommitdiff
path: root/test/files/detach-run
diff options
context:
space:
mode:
authormichelou <michelou@epfl.ch>2010-11-17 12:26:13 +0000
committermichelou <michelou@epfl.ch>2010-11-17 12:26:13 +0000
commitc09f6173e96ec741c9b38edfee969ae8c6b74d4e (patch)
tree1f06579f72afa12092acd0b5bbb7c678291cf619 /test/files/detach-run
parent363a1456f671323b35dcacf2c8b8eb39180b8a53 (diff)
downloadscala-c09f6173e96ec741c9b38edfee969ae8c6b74d4e.tar.gz
scala-c09f6173e96ec741c9b38edfee969ae8c6b74d4e.tar.bz2
scala-c09f6173e96ec741c9b38edfee969ae8c6b74d4e.zip
updates Scala examples, added detach plugin
Diffstat (limited to 'test/files/detach-run')
-rw-r--r--test/files/detach-run/actor-run.check5
-rw-r--r--test/files/detach-run/actor/Client.scala50
-rw-r--r--test/files/detach-run/actor/Server.scala24
-rw-r--r--test/files/detach-run/actor/ServerClassLoader.scala154
-rw-r--r--test/files/detach-run/actor/ServerConsole.scala71
-rw-r--r--test/files/detach-run/actor/actor.flags1
-rw-r--r--test/files/detach-run/actor/actor.scala140
-rw-r--r--test/files/detach-run/actor/java.policy25
-rw-r--r--test/files/detach-run/basic-run.check5
-rw-r--r--test/files/detach-run/basic/Client.scala44
-rw-r--r--test/files/detach-run/basic/Server.scala17
-rw-r--r--test/files/detach-run/basic/ServerConsole.scala80
-rw-r--r--test/files/detach-run/basic/basic.flags1
-rw-r--r--test/files/detach-run/basic/basic.scala153
-rw-r--r--test/files/detach-run/basic/java.policy26
15 files changed, 796 insertions, 0 deletions
diff --git a/test/files/detach-run/actor-run.check b/test/files/detach-run/actor-run.check
new file mode 100644
index 0000000000..9448ddd5fe
--- /dev/null
+++ b/test/files/detach-run/actor-run.check
@@ -0,0 +1,5 @@
+Server.main 8889
+Client.main 127.0.0.1 8889
+yInstVal = 10
+zLocVal = 1000
+result received: 11111
diff --git a/test/files/detach-run/actor/Client.scala b/test/files/detach-run/actor/Client.scala
new file mode 100644
index 0000000000..af1c26ee1b
--- /dev/null
+++ b/test/files/detach-run/actor/Client.scala
@@ -0,0 +1,50 @@
+import scala.actors.Actor._, ClientHelper._
+import scala.actors.remote._, RemoteActor._
+import scala.remoting._, Debug._
+
+object Foo {
+ def trace(msg: String) { info("[Foo.trace] "+msg)}
+}
+object Client {
+ val yInstVal: Int = 10
+ var yInstVar: Int = 99
+ object Bar {
+ def trace(msg: String) { info("[Bar.trace] "+msg) }
+ }
+ def main(args: Array[String]) {
+ init(args)
+ actor {
+ val server = select(Node(host, port), 'Server)
+ val zLocVal: Int = 1000
+ var zLocVar: Int = 9998
+ server ! detach(
+ (x: Int) => {
+ println("yInstVal = "+yInstVal)
+ this.trace("yInstVar = "+yInstVar)
+ Bar.trace("zLocVal = "+zLocVal)
+ Foo.trace("zLocVar = "+zLocVar)
+ zLocVar += 2
+ System.out.println("zLocVal = "+zLocVal)
+ Debug.info("zLocVar = "+zLocVar)
+ x + yInstVal + yInstVar + zLocVal + zLocVar
+ })
+ react {
+ case result: Int =>
+ println("result received: " + result)
+ Predef.exit(0)
+ }
+ }
+ }
+ private def trace(msg: String) { info("[Client.trace] "+msg) }
+}
+
+object ClientHelper {
+ private var _host = "127.0.0.1"
+ private var _port = 8888
+ def host = _host
+ def port = _port
+ def init(args: Array[String]) {
+ try { _host = args(0) } catch { case _ => }
+ try { _port = args(1).toInt } catch { case _ => }
+ }
+}
diff --git a/test/files/detach-run/actor/Server.scala b/test/files/detach-run/actor/Server.scala
new file mode 100644
index 0000000000..84df6f5d81
--- /dev/null
+++ b/test/files/detach-run/actor/Server.scala
@@ -0,0 +1,24 @@
+import scala.actors._, Actor._
+import scala.actors.remote._, RemoteActor._
+import scala.reflect.Manifest
+
+object Server extends ServerConsole {
+ private def computation(f: Int => Int): Int = {
+ //some time-consuming task
+ f(2)
+ }
+ def main(args: Array[String]) {
+ actor {
+ classLoader = serverClassLoader
+ alive(args(0).toInt)
+ register('Server, self)
+ loopWhile(isRunning) {
+ react {
+ case f: (Int => Int) =>
+ val result = computation(f)
+ sender ! result
+ }
+ }
+ }
+ }
+}
diff --git a/test/files/detach-run/actor/ServerClassLoader.scala b/test/files/detach-run/actor/ServerClassLoader.scala
new file mode 100644
index 0000000000..3f5d96a1a1
--- /dev/null
+++ b/test/files/detach-run/actor/ServerClassLoader.scala
@@ -0,0 +1,154 @@
+import java.io._
+import java.net.{JarURLConnection, URL, URLClassLoader}
+
+import scala.remoting.Debug
+
+ private class ServerObjectInputStream(in: InputStream, cl: ClassLoader)
+ extends ObjectInputStream(in) {
+ override def resolveClass(cd: ObjectStreamClass): Class[_] = {
+ println("[ServerObjectInputStream] resolveClass "+cd.getName)
+ try {
+ Debug.info("load class "+cd.getName+" from "+cl)
+ val c = cl.loadClass(cd.getName)
+ Debug.info("loaded class "+c.getName)
+ c
+ } catch {
+ case cnf: ClassNotFoundException =>
+ Debug.info("resolve class (this) "+cd.getName)
+ val c = super.resolveClass(cd)
+ Debug.info("resolve class (super) "+c.getName)
+ c
+ }
+ }
+ override def resolveProxyClass(interfaces: Array[String]): Class[_] = {
+ println("[ServerObjectInputStream] resolveProxyClass "+interfaces.toList)
+ try {
+ val c = cl.loadClass(interfaces.last)
+ Debug.info("loaded class "+c.getName)
+ c
+ } catch {
+ case cnf: ClassNotFoundException =>
+ Debug.info("resolve proxy class (this) "+interfaces.last)
+ val c = super.resolveProxyClass(interfaces)
+ Debug.info("resolve proxy class (super) "+c.getName)
+ c
+ }
+ }
+ }
+/*
+ // VARIANT 1
+ class ServerClassLoader extends URLClassLoader(urls) {
+ import scala.reflect.Manifest
+ def load[A](a: Array[Byte])(implicit expected: Manifest[A]): A = {
+ val in = new ServerObjectInputStream(new ByteArrayInputStream(a), this)
+ val found = in.readObject.asInstanceOf[Manifest[_]]
+ if (! (found <:< expected))
+ throw new ClassCastException("type mismatch;"+
+ "\n found : "+found+
+ "\n required: "+expected)
+ val o = in.readObject.asInstanceOf[A]
+ in.close()
+ o
+ }
+ override def findClass(name: String): Class[_] = {
+ println("[ServerClassLoader] findClass "+name)
+ val b = loadClassData(name)
+ if (b != null) defineClass(name, b, 0, b.length)
+ else super.findClass(name)
+ }
+ private def loadClassData(name: String): Array[Byte] = {
+ println("[ServerClassLoader] loadClassData "+name)
+ null
+ }
+ }
+ val serverClassLoader = new ServerClassLoader
+*/
+
+/*
+ class ServerClassLoader(parent: ClassLoader) extends URLClassLoader(urls, parent) {
+ import scala.reflect.Manifest
+ def load[A](a: Array[Byte])(implicit expected: Manifest[A]): A = {
+ val in = new ServerObjectInputStream(new ByteArrayInputStream(a), this)
+ val found = in.readObject.asInstanceOf[Manifest[_]]
+ if (! (found <:< expected))
+ throw new ClassCastException("type mismatch;"+
+ "\n found : "+found+
+ "\n required: "+expected)
+ val o = in.readObject.asInstanceOf[A]
+ in.close()
+ o
+ }
+ override def findClass(name: String): Class[_] = {
+ println("[ServerClassLoader] findClass "+name)
+ val b = loadClassData(name)
+ if (b != null) defineClass(name, b, 0, b.length)
+ else super.findClass(name)
+ }
+ private def loadClassData(name: String): Array[Byte] = {
+ println("[ServerClassLoader] loadClassData "+name)
+ null
+ }
+ }
+*/
+class ServerClassLoader(urls: Array[URL], parent: ClassLoader)
+extends URLClassLoader(urls, parent) {
+
+ private val cache = new collection.mutable.HashMap[String, Class[_]]
+
+ for (url <- urls) {
+ val jarurl = new URL("jar:"+url+"!/")
+ val con = jarurl.openConnection().asInstanceOf[JarURLConnection]
+ val jar = con.getJarFile
+ val e = jar.entries
+ while (e.hasMoreElements) {
+ val ze = e.nextElement
+ val path = ze.getName
+ if (path endsWith ".class") {
+ val size = ze.getSize
+ val name = path.replace("/", ".").substring(0, path.length - 6)
+ cache += name -> this.loadClass(name)
+ println("[ServerClassLoader] added "+name+" ("+size+")")
+ }
+ }; //jar.close()
+ }
+
+ override def findClass(name: String): Class[_] = {
+ println("[ServerClassLoader] findClass: name="+name)
+ cache get name match {
+ case Some(cl) =>
+ println(name+" cached"); cl
+ case None =>
+ println(name+" not cached"); super.findClass(name)
+ }
+ }
+
+}
+
+/*
+try {
+ JarFile jarFile = new JarFile(srcPath);
+ Enumeration<JarEntry> entries = jarFile.entries();
+ String url = "file:" + srcPath;
+ System.out.println(url);
+ URLClassLoader classLoader = new URLClassLoader(
+ new URL[] { new URL(url) });
+ while (entries.hasMoreElements()) {
+ JarEntry jarEntry = (JarEntry) entries
+ .nextElement();
+ String classPath = jarEntry.getName();
+ if (classPath.endsWith(".class")) {
+ String className = classPath.replace("/", ".")
+ .substring(0, classPath.length() - 6);
+ try {
+ Class clazz = classLoader
+ .loadClass(className);
+ //Et là, tu fais ce que tu vexu avec la classe
+ } catch (ClassNotFoundException e1) {
+ e1.printStackTrace();
+ }
+ }
+ }
+} catch (IOException e1) {
+ e1.printStackTrace();
+}
+*/
diff --git a/test/files/detach-run/actor/ServerConsole.scala b/test/files/detach-run/actor/ServerConsole.scala
new file mode 100644
index 0000000000..f68274e927
--- /dev/null
+++ b/test/files/detach-run/actor/ServerConsole.scala
@@ -0,0 +1,71 @@
+import java.io._
+
+import scala.compat.Platform.currentTime
+import scala.remoting.Debug, Debug._
+
+trait ServerConsole extends Thread {
+ private val startTime = currentTime
+ actors.Debug.level = // e.g. 3 // info+warning+error
+ try { System.getProperty("scala.actors.logLevel", "0").toInt }
+ catch { case e => 0 }
+
+ start()
+
+ val serverClassLoader = {
+ import java.rmi.server.RMIClassLoader
+ val codebase = System.getProperty("java.rmi.server.codebase")
+ info("[ServerConsole] codebase="+codebase)
+ RMIClassLoader.getClassLoader(codebase)
+ }
+
+ private var isTerminated = false
+
+ def terminate() { isTerminated = false }
+
+ def isRunning = !isTerminated
+
+ override def run() {
+ val in = new BufferedReader(new InputStreamReader(System.in))
+ var quit = false
+ while (!quit) {
+ val args = getArgs(in)
+ if (args contains "quit")
+ quit = true
+ if (args contains "cls") {
+ println(ERASE_SCREEN)
+ println(CURSOR_HOME)
+ }
+ if (args contains "warning")
+ Debug.level = Level.WARNING
+ if (args contains "info")
+ Debug.level = Level.INFO
+ if (args contains "silent")
+ Debug.level = Level.SILENT
+ }
+ terminate()
+ println("Server exited ("+mkTimeString(currentTime - startTime)+")")
+ exit(0)
+ }
+
+ protected def trace(msg: String) {
+ Debug.info("[ServerConsole.trace] "+msg)
+ }
+
+ private def getArgs(in: BufferedReader): List[String] = {
+ val input = try { in.readLine() } catch { case _ => null }
+ if (input != null) (input.trim split "\\s+").toList else Nil
+ }
+
+ private def mkTimeString(time: Long): String = {
+ def twoDigits(i: Long) = (if (i < 10) "0" else "")+i
+ val sec = time / 1000
+ val min = sec / 60
+ val h = min / 60
+ twoDigits(h) +":"+
+ twoDigits(min - h * 60)+":"+
+ twoDigits(sec - min * 60)
+ }
+
+ private val ERASE_SCREEN = "\033[2J"
+ private val CURSOR_HOME = "\033[H"
+}
diff --git a/test/files/detach-run/actor/actor.flags b/test/files/detach-run/actor/actor.flags
new file mode 100644
index 0000000000..55eed8bbcd
--- /dev/null
+++ b/test/files/detach-run/actor/actor.flags
@@ -0,0 +1 @@
+-Xpluginsdir ../../../../build/pack/misc/scala-devel/plugins -Xplugin-require:detach -P:detach:enable
diff --git a/test/files/detach-run/actor/actor.scala b/test/files/detach-run/actor/actor.scala
new file mode 100644
index 0000000000..0cf55462f6
--- /dev/null
+++ b/test/files/detach-run/actor/actor.scala
@@ -0,0 +1,140 @@
+object Test {
+
+ val actors_logLevel = "0"
+ // = "3" // info+warning+error
+ val logLevel = "silent"
+ // = "info" // debug user code only
+ // = "info,lib" // debug user & library code
+
+ // we assume an Apache server is running locally for deployment
+ private val sep = java.io.File.separator
+ val docPath = System.getProperty("user.home")+sep+"public_html"
+ val docRoot = "http://127.0.0.1/~"+System.getProperty("user.name")
+
+ val host = "127.0.0.1"
+ val port = 8889
+
+ def main(args: Array[String]) {
+ setenv()
+ println("Server.main "+port)
+ Server.main(Array(port.toString))
+ println("Client.main "+host+" "+port)
+ Client.main(Array(host, port.toString))
+ Server.terminate()
+ }
+
+ private def setenv() {
+ import java.io._, java.util.jar._
+
+ val policyTmpl =
+ System.getProperty("partest.cwd")+sep+"actor"+sep+"java.policy"
+ val outPath = System.getProperty("partest.output")
+ val libPath = System.getProperty("partest.lib")
+ val policyFile = outPath+sep+"java.policy"
+ val codebaseDir = outPath+sep+"-"
+
+ assert((new java.io.File(docPath)).isDirectory,
+ "Root directory \""+docPath+"\" not found")
+ val deployJar = docPath+sep+"actor_deploy.jar"
+ val deployUrl = docRoot+"/actor_deploy.jar"
+
+ // Java properties for server & client
+ System.setProperty("scala.actors.logLevel", actors_logLevel)
+ System.setProperty("scala.remoting.logLevel", logLevel)
+ System.setProperty("java.security.manager", "")
+ System.setProperty("java.security.policy", policyFile)
+ // Java properties for server only
+ System.setProperty("java.rmi.server.codebase", deployUrl)
+ System.setProperty("java.rmi.server.hostname", host)
+ System.setProperty("java.rmi.server.useCodebaseOnly", "true")
+
+ val classNames = List(
+ "$anonfun$main$1$proxy",
+ "$anonfun$main$1$proxyImpl_Stub",
+ "Bar$proxy",
+ "Bar$proxyImpl_Stub",
+ "Client$$anonfun$main$1$$anonfun$apply$1$detach",
+ "Client$proxy",
+ "Client$proxyImpl_Stub",
+ "Foo$proxy",
+ "Foo$proxyImpl_Stub")
+
+ val proxyImplNames =
+ for (n <- classNames; i = n lastIndexOf "_Stub"; if i > 0)
+ yield n.substring(0, i)
+
+ generatePolicyFile()
+ generateRmiStubs(proxyImplNames)
+ generateJarFile(classNames)
+
+ def generatePolicyFile() {
+ val in = new BufferedReader(new FileReader(policyTmpl))
+ val out = new PrintWriter(new BufferedWriter(new FileWriter(policyFile)))
+ var line = in.readLine()
+ while (line != null) {
+ val line1 = line.replaceAll("@PROJECT_LIB_BASE@", codebaseDir)
+ out.println(line1)
+ line = in.readLine()
+ }
+ in.close()
+ out.close()
+ }
+ def exec(command: String) {
+ val proc = Runtime.getRuntime exec command
+ proc.waitFor()
+ val out = new BufferedReader(new InputStreamReader(proc.getInputStream))
+ var line = out.readLine()
+ while (line != null) {
+ println(line)
+ line = out.readLine()
+ }
+ out.close()
+ val err = new BufferedReader(new InputStreamReader(proc.getErrorStream))
+ line = err.readLine()
+ while (line != null) {
+ println(line)
+ line = err.readLine()
+ }
+ err.close()
+ }
+
+ def ls(path: String) { exec("ls -al "+path) }
+ def rmic(options: List[String], classNames: List[String]) {
+ val javaHome = scala.util.Properties.javaHome
+ val jdkHome =
+ if (javaHome endsWith "jre") javaHome.substring(0, javaHome.length-4)
+ else javaHome
+ val rmicExt = if (scala.util.Properties.isWin) ".exe" else ""
+ val rmicCmd = jdkHome+sep+"bin"+sep+"rmic"+rmicExt
+ val cmdLine = rmicCmd+options.mkString(" ", " ", "")+
+ classNames.mkString(" "," ","")
+ // println(cmdLine)
+ exec(cmdLine)
+ }
+ def generateRmiStubs(classNames: List[String]) {
+ val options = List(
+ "-v1.2",
+ "-classpath "+libPath+File.pathSeparator+outPath,
+ "-d "+outPath)
+ rmic(options, classNames)
+ //ls(outPath)
+ }
+ def generateJarFile(classNames: List[String]) {
+ val out = new JarOutputStream(new FileOutputStream(deployJar))
+ classNames foreach (name => {
+ val className = name+".class"
+ out putNextEntry new JarEntry(className)
+ val in = new FileInputStream(outPath+sep+className)
+ val buf = new Array[Byte](256)
+ var len = in read buf
+ while (len != -1) {
+ out.write(buf, 0, len)
+ len = in read buf
+ }
+ in.close()
+ })
+ out.close()
+ }
+ }
+}
+
diff --git a/test/files/detach-run/actor/java.policy b/test/files/detach-run/actor/java.policy
new file mode 100644
index 0000000000..4beb2ca26b
--- /dev/null
+++ b/test/files/detach-run/actor/java.policy
@@ -0,0 +1,25 @@
+// See http://java.sun.com/javase/6/docs/technotes/guides/security/permissions.html
+// See http://mindprod.com/jgloss/policyfile.html
+// The policy expands ${/} to the correct path or folder delimiter on your host platform.
+
+// Actions available with SocketPermission: accept, connect, listen, resolve
+// 1) The "resolve" action is implied when any of the other actions are present.
+// 2) The "listen" action is only meaningful when used with "localhost".
+
+grant {
+ permission java.net.SocketPermission "*:80", "connect,accept,listen";
+ permission java.net.SocketPermission "*:1024-", "connect,accept,listen";
+ permission java.util.PropertyPermission "scala.remoting.logLevel", "read";
+ permission java.util.PropertyPermission "scala.remoting.port", "read";
+};
+
+grant codeBase "@PROJECT_LIB_BASE@" {
+ permission java.lang.RuntimePermission "getClassLoader";
+ permission java.util.PropertyPermission "java.rmi.server.codebase", "read";
+ permission java.util.PropertyPermission "java.rmi.server.hostname", "read";
+ permission java.util.PropertyPermission "sun.rmi.dgc.server.gcInterval", "read,write";
+};
+
+//grant {
+// permission java.security.AllPermission;
+//};
diff --git a/test/files/detach-run/basic-run.check b/test/files/detach-run/basic-run.check
new file mode 100644
index 0000000000..6463d97497
--- /dev/null
+++ b/test/files/detach-run/basic-run.check
@@ -0,0 +1,5 @@
+Server.main 8889
+> Client.main 127.0.0.1 8889
+yInstVal = 10
+zLocVal = 1000
+result received: 11111
diff --git a/test/files/detach-run/basic/Client.scala b/test/files/detach-run/basic/Client.scala
new file mode 100644
index 0000000000..d3f159fd40
--- /dev/null
+++ b/test/files/detach-run/basic/Client.scala
@@ -0,0 +1,44 @@
+import java.net._, Thread._, ClientHelper._
+import scala.remoting._, Debug._
+
+object Foo {
+ def trace(s: String) { info("[Foo.trace] "+s)}
+}
+object Client {
+ val yInstVal: Int = 10
+ var yInstVar: Int = 99
+ object Bar {
+ def trace(s: String) { info("[Bar.trace] "+s) }
+ }
+ def main(args: Array[String]) {
+ init(args)
+ val server = new Channel(host, port)
+ val zLocVal: Int = 1000
+ var zLocVar: Int = 9998
+ server ! detach(
+ (x: Int) => {
+ println("yInstVal = "+yInstVal)
+ this.trace("yInstVar = "+yInstVar)
+ Bar.trace("zLocVal = "+zLocVal)
+ Foo.trace("zLocVar = "+zLocVar)
+ zLocVar += 2
+ System.out.println("zLocVal = "+zLocVal)
+ Debug.info("zLocVar = "+zLocVar)
+ x + yInstVal + yInstVar + zLocVal + zLocVar
+ })
+ val result = server.receiveInt
+ println("result received: " + result)
+ }
+ private def trace(s: String) { info("[Client.trace] "+s) }
+}
+
+object ClientHelper {
+ private var _host = "127.0.0.1"
+ private var _port = 8888
+ def host = _host
+ def port = _port
+ def init(args: Array[String]) {
+ try { _host = args(0) } catch { case _ => }
+ try { _port = args(1).toInt } catch { case _ => }
+ }
+}
diff --git a/test/files/detach-run/basic/Server.scala b/test/files/detach-run/basic/Server.scala
new file mode 100644
index 0000000000..601eea3c58
--- /dev/null
+++ b/test/files/detach-run/basic/Server.scala
@@ -0,0 +1,17 @@
+import scala.remoting.ServerChannel
+
+object Server extends ServerConsole {
+ private def computation(f: Int => Int): Int = {
+ //some time-consuming task
+ f(2)
+ }
+ def main(args: Array[String]) {
+ val server = new ServerChannel(args(0).toInt)
+ loop {
+ val client = server.accept
+ val f = client.receive[Int => Int]
+ val result = computation(f)
+ client ! result
+ }
+ server.close()
+ } }
diff --git a/test/files/detach-run/basic/ServerConsole.scala b/test/files/detach-run/basic/ServerConsole.scala
new file mode 100644
index 0000000000..bc96bfa329
--- /dev/null
+++ b/test/files/detach-run/basic/ServerConsole.scala
@@ -0,0 +1,80 @@
+import java.io._
+
+import scala.compat.Platform.currentTime
+import scala.remoting.Debug, Debug._
+
+trait ServerConsole extends Thread {
+ private val startTime = currentTime
+
+ start()
+
+ private var isTerminated = false
+
+ def terminate() { isTerminated = true }
+
+ protected def loop(block: => Unit) {
+ while (!isTerminated) {
+ try {
+ block
+ }
+ catch {
+ case e: ObjectStreamException =>
+ trace("Object stream error ("+e.getMessage+")")
+ case e: EOFException =>
+ trace("Connection lost")
+ case e: ClassNotFoundException =>
+ trace("Class not found")
+ case e =>
+ trace("Server error: "+e)
+ }
+ }
+ }
+
+ override def run() {
+ import java.io._
+ val in = new BufferedReader(new InputStreamReader(System.in))
+ var quit = false
+ while (!quit) {
+ val args = getArgs(in)
+ if (args contains "quit")
+ quit = true
+ if (args contains "cls") {
+ println(ERASE_SCREEN)
+ println(CURSOR_HOME)
+ }
+ if (args contains "warning")
+ Debug.level = Level.WARNING
+ if (args contains "info")
+ Debug.level = Level.INFO
+ if (args contains "silent")
+ Debug.level = Level.SILENT
+ }
+ terminate()
+ println("Server exited ("+mkTimeString(currentTime - startTime)+")")
+ exit(0)
+
+ }
+
+ protected def trace(msg: String) {
+ Debug.info("[ServerConsole.trace] "+msg)
+ }
+
+ private def getArgs(in: BufferedReader): List[String] = {
+ print("> ")
+ val input = try { in.readLine() } catch { case _ => null }
+ if (input != null) (input.trim split "\\s+").toList else Nil
+ }
+
+ private def mkTimeString(time: Long): String = {
+ def twoDigits(i: Long) = (if (i < 10) "0" else "")+i
+ val sec = time / 1000
+ val min = sec / 60
+ val h = min / 60
+ twoDigits(h) +":"+
+ twoDigits(min - h * 60)+":"+
+ twoDigits(sec - min * 60)
+ }
+
+ private val ERASE_SCREEN = "\033[2J"
+ private val CURSOR_HOME = "\033[H"
+}
diff --git a/test/files/detach-run/basic/basic.flags b/test/files/detach-run/basic/basic.flags
new file mode 100644
index 0000000000..55eed8bbcd
--- /dev/null
+++ b/test/files/detach-run/basic/basic.flags
@@ -0,0 +1 @@
+-Xpluginsdir ../../../../build/pack/misc/scala-devel/plugins -Xplugin-require:detach -P:detach:enable
diff --git a/test/files/detach-run/basic/basic.scala b/test/files/detach-run/basic/basic.scala
new file mode 100644
index 0000000000..c8a1046d44
--- /dev/null
+++ b/test/files/detach-run/basic/basic.scala
@@ -0,0 +1,153 @@
+object Test {
+
+ val host = "127.0.0.1"
+ val port = 8889
+ val logLevel = "silent"
+ // = "info" // debug user code only
+ // = "info,lib" // debug user & library code
+
+ // we assume an Apache server is running locally for deployment
+ private val sep = java.io.File.separator
+ val docPath = System.getProperty("user.home")+sep+"public_html"
+ val docRoot = "http://127.0.0.1/~"+System.getProperty("user.name")
+
+ private var server = new ServerThread(port)
+ private var client = new ClientThread(host, port)
+
+ def main(args: Array[String]) {
+ setenv()
+ server.start()
+ Thread.sleep(1000)
+ client.start()
+ server.join()
+ client.join()
+ System.exit(0)
+ }
+
+ private class ServerThread(port: Int) extends Thread {
+ override def run() {
+ println("Server.main "+port)
+ Server.main(Array(port.toString))
+ }
+ }
+
+ private class ClientThread(host: String, port: Int) extends Thread {
+ override def run() {
+ println("Client.main "+host+" "+port)
+ Client.main(Array(host, port.toString))
+ Server.terminate()
+ }
+ }
+
+ private def setenv() {
+ import java.io._, java.util.jar._
+
+ val policyTmpl =
+ System.getProperty("partest.cwd")+sep+"basic"+sep+"java.policy"
+ val outPath = System.getProperty("partest.output")
+ val libPath = System.getProperty("partest.lib")
+ val policyFile = outPath+sep+"java.policy"
+ val codebaseDir = outPath+sep+"-"
+
+ assert((new java.io.File(docPath)).isDirectory,
+ "Root directory \""+docPath+"\" not found")
+ val deployJar = docPath+sep+"basic_deploy.jar"
+ val deployUrl = docRoot+"/basic_deploy.jar"
+
+ // Java properties for server & client
+ System.setProperty("scala.remoting.logLevel", logLevel)
+ System.setProperty("java.security.manager", "")
+ System.setProperty("java.security.policy", policyFile)
+ // Java properties for server only
+ System.setProperty("java.rmi.server.codebase", deployUrl)
+ System.setProperty("java.rmi.server.hostname", host)
+ System.setProperty("java.rmi.server.useCodebaseOnly", "true")
+
+ val classNames = List(
+ "Bar$proxy",
+ "Bar$proxyImpl_Stub",
+ "Client$$anonfun$main$1$detach",
+ "Client$proxy",
+ "Client$proxyImpl_Stub",
+ "Foo$proxy",
+ "Foo$proxyImpl_Stub")
+
+ val proxyImplNames =
+ for (n <- classNames; i = n lastIndexOf "_Stub"; if i > 0)
+ yield n.substring(0, i)
+
+ generatePolicyFile()
+ generateRmiStubs(proxyImplNames)
+ generateJarFile(classNames)
+
+ def generatePolicyFile() {
+ val in = new BufferedReader(new FileReader(policyTmpl))
+ val out = new PrintWriter(new BufferedWriter(new FileWriter(policyFile)))
+ var line = in.readLine()
+ while (line != null) {
+ val line1 = line.replaceAll("@PROJECT_LIB_BASE@", codebaseDir)
+ out.println(line1)
+ line = in.readLine()
+ }
+ in.close()
+ out.close()
+ }
+ def exec(command: String) {
+ val proc = Runtime.getRuntime exec command
+ proc.waitFor()
+ val out = new BufferedReader(new InputStreamReader(proc.getInputStream))
+ var line = out.readLine()
+ while (line != null) {
+ println(line)
+ line = out.readLine()
+ }
+ out.close()
+ val err = new BufferedReader(new InputStreamReader(proc.getErrorStream))
+ line = err.readLine()
+ while (line != null) {
+ println(line)
+ line = err.readLine()
+ }
+ err.close()
+ }
+
+ def ls(path: String) { exec("ls -al "+path) }
+ def rmic(options: List[String], classNames: List[String]) {
+ val javaHome = scala.util.Properties.javaHome
+ val jdkHome =
+ if (javaHome endsWith "jre") javaHome.substring(0, javaHome.length-4)
+ else javaHome
+ val rmicExt = if (scala.util.Properties.isWin) ".exe" else ""
+ val rmicCmd = jdkHome+sep+"bin"+sep+"rmic"+rmicExt
+ val cmdLine = rmicCmd+options.mkString(" ", " ", "")+
+ classNames.mkString(" "," ","")
+ // println(cmdLine)
+ exec(cmdLine)
+ }
+ def generateRmiStubs(classNames: List[String]) {
+ val options = List(
+ "-v1.2",
+ "-classpath "+libPath+File.pathSeparator+outPath,
+ "-d "+outPath)
+ rmic(options, classNames)
+ // ls(outPath)
+ }
+ def generateJarFile(classNames: List[String]) {
+ val out = new JarOutputStream(new FileOutputStream(deployJar))
+ classNames foreach (name => {
+ val className = name+".class"
+ out putNextEntry new JarEntry(className)
+ val in = new FileInputStream(outPath+sep+className)
+ val buf = new Array[Byte](256)
+ var len = in read buf
+ while (len != -1) {
+ out.write(buf, 0, len)
+ len = in read buf
+ }
+ in.close()
+ })
+ out.close()
+ }
+ }
+}
+
diff --git a/test/files/detach-run/basic/java.policy b/test/files/detach-run/basic/java.policy
new file mode 100644
index 0000000000..92c1045c3d
--- /dev/null
+++ b/test/files/detach-run/basic/java.policy
@@ -0,0 +1,26 @@
+// See http://java.sun.com/javase/6/docs/technotes/guides/security/permissions.html
+// See http://mindprod.com/jgloss/policyfile.html
+// The policy expands ${/} to the correct path or folder delimiter on your host platform.
+
+// Actions available with SocketPermission: accept, connect, listen, resolve
+// 1) The "resolve" action is implied when any of the other actions are present.
+// 2) The "listen" action is only meaningful when used with "localhost".
+
+grant {
+ permission java.net.SocketPermission "*:80", "connect,accept,listen";
+ permission java.net.SocketPermission "*:1024-", "connect,accept,listen";
+ permission java.util.PropertyPermission "scala.remoting.logLevel", "read";
+ permission java.util.PropertyPermission "scala.remoting.port", "read";
+};
+
+grant codeBase "@PROJECT_LIB_BASE@" {
+ permission java.lang.RuntimePermission "getClassLoader";
+ permission java.lang.RuntimePermission "createClassLoader";
+ permission java.util.PropertyPermission "java.rmi.server.codebase", "read";
+ permission java.util.PropertyPermission "java.rmi.server.hostname", "read";
+ permission java.util.PropertyPermission "sun.rmi.dgc.server.gcInterval", "read,write";
+};
+
+//grant {
+// permission java.security.AllPermission;
+//};