updates Scala examples, added detach plugin
git-svn-id: http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk@23531 5e8d7ff9-d8ef-0310-90f0-a4852d11357a
This commit is contained in:
parent
00da152c72
commit
b192503851
|
@ -0,0 +1,186 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<project name="sabbus" default="build">
|
||||||
|
|
||||||
|
<description>
|
||||||
|
SuperSabbus for Scala detach plugin.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<echo level="info" message="Running SABBUS for ${ant.project.name}..."/>
|
||||||
|
|
||||||
|
<!-- ===========================================================================
|
||||||
|
END-USER TARGETS
|
||||||
|
============================================================================ -->
|
||||||
|
|
||||||
|
<target name="build" depends="pack.done"
|
||||||
|
description="Builds the Scala detach plugin."/>
|
||||||
|
|
||||||
|
<target name="clean" depends="quick.clean">
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="all.clean" depends="quick.clean, pack.clean">
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<!-- ===========================================================================
|
||||||
|
PROPERTIES
|
||||||
|
============================================================================ -->
|
||||||
|
|
||||||
|
<property environment="env"/>
|
||||||
|
<!-- Prevents system classpath from being used -->
|
||||||
|
<property name="build.sysclasspath" value="ignore"/>
|
||||||
|
|
||||||
|
<!-- Defines the repository layout -->
|
||||||
|
<property name="lib.dir" value="${basedir}/lib"/>
|
||||||
|
<property name="src.dir" value="${basedir}/src"/>
|
||||||
|
<property name="partest.dir" value="${basedir}/test"/>
|
||||||
|
|
||||||
|
<!-- Loads custom properties definitions -->
|
||||||
|
<property file="${basedir}/build.properties"/>
|
||||||
|
|
||||||
|
<!-- Sets location of build folders -->
|
||||||
|
<property name="build.dir" value="${basedir}/build"/>
|
||||||
|
<property name="build-quick.dir" value="${build.dir}/quick"/>
|
||||||
|
<property name="build-pack.dir" value="${build.dir}/pack"/>
|
||||||
|
|
||||||
|
<!-- if ANT_OPTS is already set by the environment, it will be unaltered,
|
||||||
|
but if it is unset it will take this default value. -->
|
||||||
|
<property name="env.ANT_OPTS" value="-Xms1024M -Xmx1024M -Xss1M -XX:MaxPermSize=128M -XX:+UseParallelGC" />
|
||||||
|
|
||||||
|
<property
|
||||||
|
name="scalacfork.jvmargs"
|
||||||
|
value="${env.ANT_OPTS}"/>
|
||||||
|
|
||||||
|
<property name="scalac.args.quick" value="-deprecation"/>
|
||||||
|
<property name="scalac.args.optimise" value=""/>
|
||||||
|
|
||||||
|
<!-- Setting-up Ant contrib tasks -->
|
||||||
|
<taskdef resource="net/sf/antcontrib/antlib.xml" classpath="${lib.dir}/ant/ant-contrib.jar"/>
|
||||||
|
|
||||||
|
<!-- ===========================================================================
|
||||||
|
QUICK BUILD (QUICK)
|
||||||
|
============================================================================ -->
|
||||||
|
|
||||||
|
<target name="quick.clean">
|
||||||
|
<delete includeemptydirs="yes" quiet="yes" failonerror="no">
|
||||||
|
<fileset dir="${build-quick.dir}/classes/detach-library"/>
|
||||||
|
<fileset dir="${build-quick.dir}/classes/detach-plugin"/>
|
||||||
|
</delete>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="quick.done">
|
||||||
|
<stopwatch name="quick.done.timer"/>
|
||||||
|
<path id="quick.classpath">
|
||||||
|
<pathelement location="${build-quick.dir}/classes/library"/>
|
||||||
|
<pathelement location="${build-quick.dir}/classes/compiler"/>
|
||||||
|
<pathelement location="${lib.dir}/fjbg.jar"/>
|
||||||
|
<pathelement location="${lib.dir}/msil.jar"/>
|
||||||
|
<pathelement location="${lib.dir}/forkjoin.jar"/>
|
||||||
|
<pathelement location="${ant.home}/lib/ant.jar"/>
|
||||||
|
</path>
|
||||||
|
<taskdef
|
||||||
|
resource="scala/tools/ant/sabbus/antlib.xml"
|
||||||
|
classpathref="quick.classpath"
|
||||||
|
/>
|
||||||
|
<mkdir dir="${build-quick.dir}/classes/detach-plugin"/>
|
||||||
|
<scalacfork
|
||||||
|
destdir="${build-quick.dir}/classes/detach-plugin"
|
||||||
|
compilerpathref="quick.classpath"
|
||||||
|
params="${scalac.args.quick}"
|
||||||
|
srcdir="${src.dir}/detach/plugin"
|
||||||
|
jvmargs="${scalacfork.jvmargs}">
|
||||||
|
<include name="**/*.scala"/>
|
||||||
|
<compilationpath>
|
||||||
|
<pathelement location="${build-quick.dir}/classes/library"/>
|
||||||
|
<pathelement location="${build-quick.dir}/classes/compiler"/>
|
||||||
|
<pathelement location="${build-quick.dir}/classes/detach-plugin"/>
|
||||||
|
<pathelement location="${lib.dir}/forkjoin.jar"/>
|
||||||
|
</compilationpath>
|
||||||
|
</scalacfork>
|
||||||
|
<copy
|
||||||
|
file="${src.dir}/detach/plugin/scalac-plugin.xml"
|
||||||
|
todir="${build-quick.dir}/classes/detach-plugin"
|
||||||
|
/>
|
||||||
|
<mkdir dir="${build-quick.dir}/classes/detach-library"/>
|
||||||
|
<scalacfork
|
||||||
|
destdir="${build-quick.dir}/classes/detach-library"
|
||||||
|
compilerpathref="quick.classpath"
|
||||||
|
params="${scalac.args.quick}"
|
||||||
|
srcdir="${src.dir}/detach/library"
|
||||||
|
jvmargs="${scalacfork.jvmargs}">
|
||||||
|
<include name="**/*.scala"/>
|
||||||
|
<compilationpath>
|
||||||
|
<pathelement location="${build-quick.dir}/classes/library"/>
|
||||||
|
<pathelement location="${lib.dir}/forkjoin.jar"/>
|
||||||
|
</compilationpath>
|
||||||
|
</scalacfork>
|
||||||
|
<touch file="${build-quick.dir}/plugins.complete" verbose="no"/>
|
||||||
|
<stopwatch name="quick.done.timer" action="total"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<!-- ===========================================================================
|
||||||
|
PACKED QUICK BUILD (PACK)
|
||||||
|
============================================================================ -->
|
||||||
|
|
||||||
|
<target name="pack.start" depends="quick.done"/>
|
||||||
|
|
||||||
|
<target name="pack.pre-lib" depends="pack.start">
|
||||||
|
<uptodate
|
||||||
|
property="pack.lib.available"
|
||||||
|
targetfile="${build-pack.dir}/lib/scala-detach.jar"
|
||||||
|
srcfile="${build-quick.dir}/plugins.complete"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="pack.lib" depends="pack.pre-lib" unless="pack.lib.available">
|
||||||
|
<mkdir dir="${build-pack.dir}/misc/scala-devel/plugins"/>
|
||||||
|
<jar destfile="${build-pack.dir}/misc/scala-devel/plugins/detach.jar">
|
||||||
|
<fileset dir="${build-quick.dir}/classes/detach-plugin"/>
|
||||||
|
</jar>
|
||||||
|
<mkdir dir="${build-pack.dir}/lib"/>
|
||||||
|
<jar destfile="${build-pack.dir}/lib/scala-detach.jar">
|
||||||
|
<fileset dir="${build-quick.dir}/classes/detach-library">
|
||||||
|
<include name="scala/**"/>
|
||||||
|
</fileset>
|
||||||
|
</jar>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="pack.done" depends="pack.lib">
|
||||||
|
<path id="pack.classpath">
|
||||||
|
<pathelement location="${build-pack.dir}/lib/scala-library.jar"/>
|
||||||
|
<pathelement location="${build-pack.dir}/lib/scala-compiler.jar"/>
|
||||||
|
<pathelement location="${build-pack.dir}/lib/scala-detach.jar"/>
|
||||||
|
<pathelement location="${build-pack.dir}/lib/scala-partest.jar"/>
|
||||||
|
<pathelement location="${build-pack.dir}/lib/scalap.jar"/>
|
||||||
|
<pathelement location="${ant.home}/lib/ant.jar"/>
|
||||||
|
<pathelement location="${lib.dir}/jline.jar"/>
|
||||||
|
</path>
|
||||||
|
<taskdef resource="scala/tools/ant/antlib.xml" classpathref="pack.classpath"/>
|
||||||
|
<taskdef resource="scala/tools/partest/antlib.xml" classpathref="pack.classpath"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="pack.clean">
|
||||||
|
<delete includeemptydirs="yes" quiet="yes" failonerror="no">
|
||||||
|
<fileset dir="${build-pack.dir}/lib" includes="scala-detach.jar"/>
|
||||||
|
<fileset dir="${build-pack.dir}/misc/scala-devel/plugins" includes="detach.jar"/>
|
||||||
|
</delete>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<!-- ===========================================================================
|
||||||
|
TEST SUITE
|
||||||
|
============================================================================ -->
|
||||||
|
|
||||||
|
<target name="test.suite" depends="pack.done">
|
||||||
|
<property name="partest.srcdir" value="files" />
|
||||||
|
<partest showlog="yes" erroronfailed="yes" javacmd="${java.home}/bin/java"
|
||||||
|
timeout="2400000"
|
||||||
|
srcdir="${partest.srcdir}"
|
||||||
|
scalacopts="${scalac.args.optimise} -Xpluginsdir ${build-pack.dir}/misc/scala-devel/plugins -Xplugin-require:detach -P:detach:enable">
|
||||||
|
<compilationpath>
|
||||||
|
<path refid="pack.classpath"/>
|
||||||
|
<fileset dir="${partest.dir}/files/lib" includes="*.jar" />
|
||||||
|
</compilationpath>
|
||||||
|
<negtests dir="${partest.dir}/${partest.srcdir}/detach-neg" includes="*.scala"/>
|
||||||
|
<runtests dir="${partest.dir}/${partest.srcdir}/detach-run" includes="*.scala"/>
|
||||||
|
</partest>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
</project>
|
|
@ -30,6 +30,8 @@ PROPERTIES
|
||||||
<property name="scala.comp.jar" value="${lib.dir}/scala-compiler.jar"/>
|
<property name="scala.comp.jar" value="${lib.dir}/scala-compiler.jar"/>
|
||||||
<property name="fjbg.name" value="fjbg.jar"/>
|
<property name="fjbg.name" value="fjbg.jar"/>
|
||||||
<property name="fjbg.jar" value="${lib.dir}/${fjbg.name}"/>
|
<property name="fjbg.jar" value="${lib.dir}/${fjbg.name}"/>
|
||||||
|
<property name="msil.name" value="msil.jar"/>
|
||||||
|
<property name="msil.jar" value="${lib.dir}/${msil.name}"/>
|
||||||
<property name="ant.jar" value="${ant.home}/lib/ant.jar"/>
|
<property name="ant.jar" value="${ant.home}/lib/ant.jar"/>
|
||||||
<property name="ant-contrib.jar" value="${lib.dir}/ant/ant-contrib.jar"/>
|
<property name="ant-contrib.jar" value="${lib.dir}/ant/ant-contrib.jar"/>
|
||||||
<!-- -->
|
<!-- -->
|
||||||
|
@ -61,7 +63,7 @@ INITIALISATION
|
||||||
classpath="${scala.lib.jar}"
|
classpath="${scala.lib.jar}"
|
||||||
/>
|
/>
|
||||||
<available
|
<available
|
||||||
classname="scala.List"
|
classname="scala.collection.immutable.List"
|
||||||
classpath="${scala.lib.jar}"
|
classpath="${scala.lib.jar}"
|
||||||
/>
|
/>
|
||||||
<available
|
<available
|
||||||
|
@ -88,6 +90,15 @@ INITIALISATION
|
||||||
/>
|
/>
|
||||||
</not></condition>
|
</not></condition>
|
||||||
</fail>
|
</fail>
|
||||||
|
<echo level="verbose" message="msil.jar=${msil.jar}"/>
|
||||||
|
<fail message="MSIL library in '${lib.dir}/' is not available">
|
||||||
|
<condition><not>
|
||||||
|
<available
|
||||||
|
classname="ch.epfl.lamp.compiler.msil.MemberInfo"
|
||||||
|
classpath="${msil.jar}"
|
||||||
|
/>
|
||||||
|
</not></condition>
|
||||||
|
</fail>
|
||||||
<echo level="verbose" message="ant.jar=${ant.jar}"/>
|
<echo level="verbose" message="ant.jar=${ant.jar}"/>
|
||||||
<echo level="verbose" message="ant-contrib.jar=${ant-contrib.jar}"/>
|
<echo level="verbose" message="ant-contrib.jar=${ant-contrib.jar}"/>
|
||||||
<fail message="Additional Ant tasks in '${lib.dir}/' is not available">
|
<fail message="Additional Ant tasks in '${lib.dir}/' is not available">
|
||||||
|
@ -101,6 +112,7 @@ INITIALISATION
|
||||||
<!-- Creating class-pathes -->
|
<!-- Creating class-pathes -->
|
||||||
<path id="common.classpath">
|
<path id="common.classpath">
|
||||||
<pathelement location="${fjbg.jar}"/>
|
<pathelement location="${fjbg.jar}"/>
|
||||||
|
<pathelement location="${msil.jar}"/>
|
||||||
</path>
|
</path>
|
||||||
<path id="scala.classpath">
|
<path id="scala.classpath">
|
||||||
<pathelement location="${scala.lib.jar}"/>
|
<pathelement location="${scala.lib.jar}"/>
|
||||||
|
@ -202,7 +214,7 @@ BUILD
|
||||||
<for list="${list}" param="file">
|
<for list="${list}" param="file">
|
||||||
<sequential>
|
<sequential>
|
||||||
<scalac srcdir="${src.dir}"
|
<scalac srcdir="${src.dir}"
|
||||||
destdir="${build.dir}">
|
destdir="${build.dir}" deprecation="true">
|
||||||
<classpath>
|
<classpath>
|
||||||
<pathelement location="${scala.lib.jar}"/>
|
<pathelement location="${scala.lib.jar}"/>
|
||||||
<pathelement location="${build.dir}"/>
|
<pathelement location="${build.dir}"/>
|
||||||
|
|
|
@ -4,19 +4,19 @@ object boundedbuffer {
|
||||||
|
|
||||||
import concurrent.ops._
|
import concurrent.ops._
|
||||||
|
|
||||||
class BoundedBuffer[a](N: Int) {
|
class BoundedBuffer[A](N: Int)(implicit m: ClassManifest[A]) {
|
||||||
var in, out, n = 0
|
var in, out, n = 0
|
||||||
val elems = new Array[a](N)
|
val elems = new Array[A](N)
|
||||||
|
|
||||||
def await(cond: => Boolean) = while (!cond) { wait() }
|
def await(cond: => Boolean) = while (!cond) { wait() }
|
||||||
|
|
||||||
def put(x: a) = synchronized {
|
def put(x: A) = synchronized {
|
||||||
await (n < N)
|
await (n < N)
|
||||||
elems(in) = x; in = (in + 1) % N; n += 1
|
elems(in) = x; in = (in + 1) % N; n += 1
|
||||||
if (n == 1) notifyAll()
|
if (n == 1) notifyAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
def get: a = synchronized {
|
def get: A = synchronized {
|
||||||
await (n != 0)
|
await (n != 0)
|
||||||
val x = elems(out); out = (out + 1) % N ; n -= 1
|
val x = elems(out); out = (out + 1) % N ; n -= 1
|
||||||
if (n == N - 1) notifyAll()
|
if (n == N - 1) notifyAll()
|
||||||
|
|
|
@ -3,10 +3,10 @@ package examples
|
||||||
object gadts extends Application {
|
object gadts extends Application {
|
||||||
|
|
||||||
abstract class Term[T]
|
abstract class Term[T]
|
||||||
case class Lit(x: int) extends Term[int]
|
case class Lit(x: Int) extends Term[Int]
|
||||||
case class Succ(t: Term[int]) extends Term[int]
|
case class Succ(t: Term[Int]) extends Term[Int]
|
||||||
case class IsZero(t: Term[int]) extends Term[boolean]
|
case class IsZero(t: Term[Int]) extends Term[Boolean]
|
||||||
case class If[T](c: Term[boolean],
|
case class If[T](c: Term[Boolean],
|
||||||
t1: Term[T],
|
t1: Term[T],
|
||||||
t2: Term[T]) extends Term[T]
|
t2: Term[T]) extends Term[T]
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ object gadts extends Application {
|
||||||
case IsZero(u) => eval(u) == 0
|
case IsZero(u) => eval(u) == 0
|
||||||
case If(c, u1, u2) => eval(if (eval(c)) u1 else u2)
|
case If(c, u1, u2) => eval(if (eval(c)) u1 else u2)
|
||||||
}
|
}
|
||||||
Console.println(
|
println(
|
||||||
eval(If(IsZero(Lit(1)), Lit(41), Succ(Lit(41)))))
|
eval(If(IsZero(Lit(1)), Lit(41), Succ(Lit(41)))))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,10 +10,10 @@ object iterators {
|
||||||
}
|
}
|
||||||
|
|
||||||
def printArray(xs: Array[Double]) =
|
def printArray(xs: Array[Double]) =
|
||||||
Iterator.fromArray(xs) foreach { x => println(x) }
|
xs.iterator foreach { x => println(x) }
|
||||||
|
|
||||||
def findGreater(xs: Array[Double], limit: Double) =
|
def findGreater(xs: Array[Double], limit: Double) =
|
||||||
Iterator.fromArray(xs)
|
xs.iterator
|
||||||
.zip(Iterator.from(0))
|
.zip(Iterator.from(0))
|
||||||
.filter{case Pair(x, i) => x > limit }
|
.filter{case Pair(x, i) => x > limit }
|
||||||
.map{case Pair(x, i) => i}
|
.map{case Pair(x, i) => i}
|
||||||
|
|
|
@ -112,7 +112,6 @@ trait ScalaSettings extends AbsScalaSettings with StandardScalaSettings {
|
||||||
val noCompletion = BooleanSetting ("-Yno-completion", "Disable tab-completion in the REPL")
|
val noCompletion = BooleanSetting ("-Yno-completion", "Disable tab-completion in the REPL")
|
||||||
val Xdce = BooleanSetting ("-Ydead-code", "Perform dead code elimination")
|
val Xdce = BooleanSetting ("-Ydead-code", "Perform dead code elimination")
|
||||||
val debug = BooleanSetting ("-Ydebug", "Output debugging messages")
|
val debug = BooleanSetting ("-Ydebug", "Output debugging messages")
|
||||||
val Xdetach = BooleanSetting ("-Ydetach", "Perform detaching of remote closures")
|
|
||||||
// val doc = BooleanSetting ("-Ydoc", "Generate documentation")
|
// val doc = BooleanSetting ("-Ydoc", "Generate documentation")
|
||||||
val inline = BooleanSetting ("-Yinline", "Perform inlining when possible")
|
val inline = BooleanSetting ("-Yinline", "Perform inlining when possible")
|
||||||
val Xlinearizer = ChoiceSetting ("-Ylinearizer", "Linearizer to use", List("normal", "dfs", "rpo", "dump"), "rpo") .
|
val Xlinearizer = ChoiceSetting ("-Ylinearizer", "Linearizer to use", List("normal", "dfs", "rpo", "dump"), "rpo") .
|
||||||
|
|
|
@ -0,0 +1,192 @@
|
||||||
|
/* __ *\
|
||||||
|
** ________ ___ / / ___ Scala API **
|
||||||
|
** / __/ __// _ | / / / _ | (c) 2007-2010, LAMP/EPFL **
|
||||||
|
** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
|
||||||
|
** /____/\___/_/ |_/____/_/ | | **
|
||||||
|
** |/ **
|
||||||
|
\* */
|
||||||
|
|
||||||
|
// $Id: Channel.scala 18365 2009-07-21 11:00:42Z michelou $
|
||||||
|
|
||||||
|
package scala.remoting
|
||||||
|
|
||||||
|
import java.io._
|
||||||
|
import java.net._
|
||||||
|
import java.rmi.server.RMIClassLoader
|
||||||
|
|
||||||
|
/** <p>
|
||||||
|
* The class <code>Channel</code> implements (basic) typed channels
|
||||||
|
* which use <a href="http://java.sun.com/docs/books/tutorial/networking/sockets/"
|
||||||
|
* target="_top"/>Java socket</a> communication and Scala type manifests to
|
||||||
|
* provide type-safe send/receive operations between a localhost and another
|
||||||
|
* remote machine by specifying some <code>host</code> and <code>port</code>.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Stephane Micheloud
|
||||||
|
* @version 1.1
|
||||||
|
*/
|
||||||
|
class Channel protected (socket: Socket) {
|
||||||
|
|
||||||
|
// Create a socket without a timeout
|
||||||
|
def this(host: String, port: Int) = this(new Socket(host, port))
|
||||||
|
|
||||||
|
// // Create a socket with a timeout
|
||||||
|
// val sockaddr: SocketAddress = new InetSocketAddress(addr, port)
|
||||||
|
// val socket = new Socket()
|
||||||
|
// // If the timeout occurs, SocketTimeoutException is thrown.
|
||||||
|
// socket.connect(sockaddr, 2000) // 2 seconds
|
||||||
|
|
||||||
|
/** Returns the local address of this channel. */
|
||||||
|
val host = socket.getInetAddress.getHostAddress
|
||||||
|
|
||||||
|
/** Returns the port on which this channel is listening. */
|
||||||
|
val port = socket.getLocalPort
|
||||||
|
|
||||||
|
private var cl: ClassLoader =
|
||||||
|
try {
|
||||||
|
// requires permission in Java policy file
|
||||||
|
val codebase = System.getProperty("java.rmi.server.codebase")
|
||||||
|
if (codebase != null) info("codebase="+codebase)
|
||||||
|
RMIClassLoader.getClassLoader(codebase)
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
case e: Exception =>
|
||||||
|
error("Class loader undefined: " + e.getMessage)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
def classLoader: ClassLoader = cl
|
||||||
|
def classLoader_=(x: ClassLoader) { cl = x }
|
||||||
|
|
||||||
|
info(""+this)
|
||||||
|
|
||||||
|
private class CustomObjectInputStream(in: InputStream)
|
||||||
|
extends ObjectInputStream(in) {
|
||||||
|
override def resolveClass(desc: ObjectStreamClass): Class[_] =
|
||||||
|
if (cl eq null)
|
||||||
|
super.resolveClass(desc)
|
||||||
|
else
|
||||||
|
try {
|
||||||
|
info("resolve class "+desc.getName)
|
||||||
|
cl loadClass desc.getName
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
case e: ClassNotFoundException =>
|
||||||
|
super.resolveClass(desc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
// lazy modifier is required!
|
||||||
|
private lazy val in =
|
||||||
|
try {
|
||||||
|
new CustomObjectInputStream(socket.getInputStream)
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
case e: IOException =>
|
||||||
|
error("Input stream undefined: "+e.getMessage+" ("+this+")")
|
||||||
|
null
|
||||||
|
}
|
||||||
|
private lazy val out =
|
||||||
|
try {
|
||||||
|
new ObjectOutputStream(socket.getOutputStream)
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
case e: IOException =>
|
||||||
|
error("Output stream undefined: "+e.getMessage+" ("+this+")")
|
||||||
|
null
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
/** <code>receive<primtype></code> methods may throw an
|
||||||
|
* <code>IOException</code>.
|
||||||
|
*/
|
||||||
|
def receiveUnit = receive[Unit]
|
||||||
|
def receiveBoolean = receive[Boolean]
|
||||||
|
def receiveByte = receive[Byte]
|
||||||
|
def receiveChar = receive[Char]
|
||||||
|
def receiveShort = receive[Short]
|
||||||
|
def receiveInt = receive[Int]
|
||||||
|
def receiveLong = receive[Long]
|
||||||
|
def receiveFloat = receive[Float]
|
||||||
|
def receiveDouble = receive[Double]
|
||||||
|
def receiveString = receive[String]
|
||||||
|
|
||||||
|
/** <code>receive</code> method may throw either an
|
||||||
|
* <code>ClassNotFoundException</code> or an <code>IOException</code>.
|
||||||
|
*
|
||||||
|
* @throw <code>ChannelException</code> if received value has not
|
||||||
|
* the expected type.
|
||||||
|
*/
|
||||||
|
@throws(classOf[ChannelException])
|
||||||
|
def receive[T](implicit expected: reflect.Manifest[T]): T = {
|
||||||
|
val in = new CustomObjectInputStream(socket.getInputStream)
|
||||||
|
val found = in.readObject().asInstanceOf[reflect.Manifest[_]]
|
||||||
|
info("receive: found="+found+", expected="+expected)
|
||||||
|
import scala.reflect.Manifest
|
||||||
|
val x = found match {
|
||||||
|
case Manifest.Unit => ()
|
||||||
|
case Manifest.Boolean => in.readBoolean()
|
||||||
|
case Manifest.Byte => in.readByte()
|
||||||
|
case Manifest.Char => in.readChar()
|
||||||
|
case Manifest.Short => in.readShort()
|
||||||
|
case Manifest.Int => in.readInt()
|
||||||
|
case Manifest.Long => in.readLong()
|
||||||
|
case Manifest.Float => in.readFloat()
|
||||||
|
case Manifest.Double => in.readDouble()
|
||||||
|
case _ => in.readObject()
|
||||||
|
}
|
||||||
|
val res = if (found <:< expected)
|
||||||
|
x.asInstanceOf[T]
|
||||||
|
else
|
||||||
|
throw new ChannelException(
|
||||||
|
"\n\tfound \""+found+"\"\n\texpected \""+expected+"\"")
|
||||||
|
info("received "+res+" (available="+in.available+")")
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
/** <code>?</code> method may throw either an
|
||||||
|
* <code>ClassNotFoundException</code> or an <code>IOException</code>.
|
||||||
|
*/
|
||||||
|
def ?[T](implicit m: reflect.Manifest[T]): T = receive[T](m)
|
||||||
|
|
||||||
|
/** <code>send</code> method may throw an <code>IOException</code>.
|
||||||
|
*/
|
||||||
|
def send[T](x: T)(implicit m: reflect.Manifest[T]) {
|
||||||
|
val out = new ObjectOutputStream(socket.getOutputStream)
|
||||||
|
out writeObject m
|
||||||
|
x match {
|
||||||
|
case x: Unit => // nop
|
||||||
|
case x: Boolean => out writeBoolean x
|
||||||
|
case x: Byte => out writeByte x
|
||||||
|
case x: Char => out writeChar x
|
||||||
|
case x: Short => out writeShort x
|
||||||
|
case x: Int => out writeInt x
|
||||||
|
case x: Long => out writeLong x
|
||||||
|
case x: Float => out writeFloat x
|
||||||
|
case x: Double => out writeDouble x
|
||||||
|
case x => out writeObject x
|
||||||
|
}
|
||||||
|
out.flush()
|
||||||
|
info("sent "+x)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** <code>!</code> method may throw an <code>IOException</code>.
|
||||||
|
*/
|
||||||
|
def ![T](x: T)(implicit m: reflect.Manifest[T]) { send(x)(m) }
|
||||||
|
|
||||||
|
def close() {
|
||||||
|
try { socket.close() }
|
||||||
|
catch { case e: IOException => }
|
||||||
|
info(this+" closed")
|
||||||
|
}
|
||||||
|
|
||||||
|
override def toString: String = socket.toString
|
||||||
|
|
||||||
|
private def info(msg: String) {
|
||||||
|
runtime.remoting.Debug.info("[Channel] "+msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** <code>ChannelException</code> may be thrown by the operation
|
||||||
|
* <code>receive</code> when the received data has not the expected type.
|
||||||
|
*/
|
||||||
|
case class ChannelException(msg: String) extends IOException(msg)
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
/* __ *\
|
||||||
|
** ________ ___ / / ___ Scala API **
|
||||||
|
** / __/ __// _ | / / / _ | (c) 2007-2009, LAMP/EPFL **
|
||||||
|
** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
|
||||||
|
** /____/\___/_/ |_/____/_/ | | **
|
||||||
|
** |/ **
|
||||||
|
\* */
|
||||||
|
|
||||||
|
// $Id: Debug.scala 17412 2009-03-31 10:08:25Z michelou $
|
||||||
|
|
||||||
|
package scala.remoting
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Stephane Micheloud
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
|
object Debug extends runtime.remoting.Debug {
|
||||||
|
private val f = new java.text.SimpleDateFormat("HH:mm:ss")
|
||||||
|
private val c = new java.util.GregorianCalendar
|
||||||
|
|
||||||
|
def getTime: String = f format c.getTime
|
||||||
|
|
||||||
|
def getLocation(obj: AnyRef): String = {
|
||||||
|
val s = obj.getClass().getClassLoader().toString()
|
||||||
|
s.substring(s.indexOf('['))
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
/* __ *\
|
||||||
|
** ________ ___ / / ___ Scala API **
|
||||||
|
** / __/ __// _ | / / / _ | (c) 2007-2010, LAMP/EPFL **
|
||||||
|
** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
|
||||||
|
** /____/\___/_/ |_/____/_/ | | **
|
||||||
|
** |/ **
|
||||||
|
\* */
|
||||||
|
|
||||||
|
// $Id: ServerChannel.scala 18365 2009-07-21 11:00:42Z michelou $
|
||||||
|
|
||||||
|
package scala.remoting
|
||||||
|
|
||||||
|
import java.net.{ServerSocket, Socket}
|
||||||
|
|
||||||
|
/** <p>
|
||||||
|
* Creates a server channel and binds its associated socket to the
|
||||||
|
* specified port number.<br/>
|
||||||
|
* Example:
|
||||||
|
* </p><pre>
|
||||||
|
* <b>class</b> ComputeChannel(s: Socket) <b>extends</b> Channel(s) {
|
||||||
|
* <b>def</b> receiveFunc = receive[Int => Int]
|
||||||
|
* }
|
||||||
|
* <b>class</b> ComputeServer(p: Int)
|
||||||
|
* <b>extends</b> AbstractServerChannel[ComputeChannel](p) {
|
||||||
|
* <b>def</b> newChannel(s: Socket) = <b>new</b> ComputeChannel(s)
|
||||||
|
* }</pre>
|
||||||
|
*
|
||||||
|
* @author Stephane Micheloud
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
|
class ServerChannel(p: Int) extends AbstractServerChannel[Channel](p) {
|
||||||
|
def newChannel(s: Socket) = new Channel(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class AbstractServerChannel[T <: Channel](_port: Int) {
|
||||||
|
|
||||||
|
/** Creates an input channel and binds its associated socket to any
|
||||||
|
* free port.
|
||||||
|
*/
|
||||||
|
def this() = this(0)
|
||||||
|
|
||||||
|
// The maximum queue length for incoming requests to connect is set to 50.
|
||||||
|
private val serverSocket = new ServerSocket(_port)
|
||||||
|
|
||||||
|
/** Returns the local address of this channel. */
|
||||||
|
val host = serverSocket.getInetAddress.getHostAddress
|
||||||
|
|
||||||
|
/** Returns the port on which this channel is listening. */
|
||||||
|
val port = serverSocket.getLocalPort
|
||||||
|
info("Listening on port "+port)
|
||||||
|
|
||||||
|
protected def newChannel(socket: Socket): T
|
||||||
|
|
||||||
|
def accept: T = {
|
||||||
|
System.gc() // required!
|
||||||
|
newChannel(serverSocket.accept)
|
||||||
|
}
|
||||||
|
|
||||||
|
def close() {
|
||||||
|
try { serverSocket.close() }
|
||||||
|
catch { case e: java.io.IOException => }
|
||||||
|
info("Server socket "+host+":"+port+" closed")
|
||||||
|
}
|
||||||
|
|
||||||
|
protected def info(msg: String) {
|
||||||
|
runtime.remoting.Debug.info("[ServerChannel] "+msg)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
/* __ *\
|
||||||
|
** ________ ___ / / ___ Scala API **
|
||||||
|
** / __/ __// _ | / / / _ | (c) 2002-2009, LAMP/EPFL **
|
||||||
|
** __\ \/ /__/ __ |/ /__/ __ | http://www.scala-lang.org/ **
|
||||||
|
** /____/\___/_/ |_/____/_/ | | **
|
||||||
|
** |/ **
|
||||||
|
\* */
|
||||||
|
|
||||||
|
// $Id: detach.scala 16901 2009-01-13 15:37:05Z michelou $
|
||||||
|
|
||||||
|
package scala.remoting
|
||||||
|
|
||||||
|
|
||||||
|
/** The <code>detach</code> object is a <em>marker object</em> which informs
|
||||||
|
* the Scala compiler that arguments whose type is a function type are
|
||||||
|
* eligible for remote closure generation.
|
||||||
|
*
|
||||||
|
* @author Stephane Micheloud
|
||||||
|
* @version 1.0, 13/07/2005
|
||||||
|
*/
|
||||||
|
object detach {
|
||||||
|
|
||||||
|
def apply[R](f: Function0[R]): Function0[R] = f
|
||||||
|
def apply[T0, R](f: Function1[T0, R]): Function1[T0, R] = f
|
||||||
|
def apply[T0, T1, R](f: Function2[T0, T1, R]): Function2[T0, T1, R] = f
|
||||||
|
def apply[T0, T1, T2, R](f: Function3[T0, T1, T2, R]): Function3[T0, T1, T2, R] = f
|
||||||
|
def apply[T0, T1, T2, T3, R](f: Function4[T0, T1, T2, T3, R]): Function4[T0, T1, T2, T3, R] = f
|
||||||
|
def apply[T0, T1, T2, T3, T4, R](f: Function5[T0, T1, T2, T3, T4, R]): Function5[T0, T1, T2, T3, T4, R] = f
|
||||||
|
def apply[T0, T1, T2, T3, T4, T5, R](f: Function6[T0, T1, T2, T3, T4, T5, R]): Function6[T0, T1, T2, T3, T4, T5, R] = f
|
||||||
|
def apply[T0, T1, T2, T3, T4, T5, T6, R](f: Function7[T0, T1, T2, T3, T4, T5, T6, R]): Function7[T0, T1, T2, T3, T4, T5, T6, R] = f
|
||||||
|
def apply[T0, T1, T2, T3, T4, T5, T6, T7, R](f: Function8[T0, T1, T2, T3, T4, T5, T6, T7, R]): Function8[T0, T1, T2, T3, T4, T5, T6, T7, R] = f
|
||||||
|
def apply[T0, T1, T2, T3, T4, T5, T6, T7, T8, R](f: Function9[T0, T1, T2, T3, T4, T5, T6, T7, T8, R]): Function9[T0, T1, T2, T3, T4, T5, T6, T7, T8, R] = f
|
||||||
|
|
||||||
|
// since 2.7.0
|
||||||
|
def apply[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, R](f: Function10[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, R]): Function10[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, R] = f
|
||||||
|
def apply[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, R](f: Function11[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, R]): Function11[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, R] = f
|
||||||
|
def apply[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, R](f: Function12[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, R]): Function12[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, R] = f
|
||||||
|
def apply[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, R](f: Function13[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, R]): Function13[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, R] = f
|
||||||
|
def apply[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, R](f: Function14[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, R]): Function14[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, R] = f
|
||||||
|
def apply[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, R](f: Function15[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, R]): Function15[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, R] = f
|
||||||
|
def apply[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, R](f: Function16[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, R]): Function16[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, R] = f
|
||||||
|
def apply[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, R](f: Function17[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, R]): Function17[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, R] = f
|
||||||
|
def apply[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, R](f: Function18[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, R]): Function18[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, R] = f
|
||||||
|
def apply[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, R](f: Function19[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, R]): Function19[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, R] = f
|
||||||
|
def apply[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, R](f: Function20[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, R]): Function20[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, R] = f
|
||||||
|
def apply[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, R](f: Function21[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, R]): Function21[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, R] = f
|
||||||
|
def apply[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, R](f: Function22[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, R]): Function22[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, R] = f
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,182 @@
|
||||||
|
/* __ *\
|
||||||
|
** ________ ___ / / ___ Scala API **
|
||||||
|
** / __/ __// _ | / / / _ | (c) 2002-2009, LAMP/EPFL **
|
||||||
|
** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
|
||||||
|
** /____/\___/_/ |_/____/_/ | | **
|
||||||
|
** |/ **
|
||||||
|
\* */
|
||||||
|
|
||||||
|
// $Id: RemoteRef.scala 18365 2009-07-21 11:00:42Z michelou $
|
||||||
|
|
||||||
|
package scala.runtime
|
||||||
|
|
||||||
|
import java.net.{InetAddress, MalformedURLException}
|
||||||
|
import java.rmi.{NoSuchObjectException, NotBoundException, Remote}
|
||||||
|
import java.rmi.registry.{LocateRegistry, Registry}
|
||||||
|
import java.rmi.server.{ExportException, RemoteObject, UnicastRemoteObject}
|
||||||
|
|
||||||
|
import scala.runtime.remoting.{Debug, RemoteGC}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Stephane Micheloud
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
|
object RemoteRef { /*extends Thread {
|
||||||
|
start()
|
||||||
|
|
||||||
|
private class QuitException extends Exception
|
||||||
|
private var isTerminated = false
|
||||||
|
|
||||||
|
// keeps track of live remote objects
|
||||||
|
val remoteGC = new RemoteGC
|
||||||
|
|
||||||
|
override def run() {
|
||||||
|
info("started thread")
|
||||||
|
try {
|
||||||
|
while (!isTerminated) {
|
||||||
|
this.synchronized {
|
||||||
|
try {
|
||||||
|
wait(200)
|
||||||
|
} catch {
|
||||||
|
case _: InterruptedException =>
|
||||||
|
if (isTerminated) throw new QuitException
|
||||||
|
}
|
||||||
|
remoteGC.gc()
|
||||||
|
if (remoteGC.allClosed)
|
||||||
|
throw new QuitException
|
||||||
|
} // synchronized
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
case _: QuitException =>
|
||||||
|
// allow thread to exit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
try {
|
||||||
|
val prop = System.getProperty("sun.rmi.dgc.server.gcInterval")
|
||||||
|
if (prop eq null)
|
||||||
|
System.setProperty("sun.rmi.dgc.server.gcInterval", "10000")
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
case e =>
|
||||||
|
error(e.getMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val host =
|
||||||
|
try {
|
||||||
|
val prop = System.getProperty("java.rmi.server.hostname")
|
||||||
|
if (prop ne null) prop else InetAddress.getLocalHost.getHostAddress
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
case e =>
|
||||||
|
warning(e.getMessage)
|
||||||
|
InetAddress.getLocalHost.getHostAddress
|
||||||
|
}
|
||||||
|
|
||||||
|
private val port =
|
||||||
|
try {
|
||||||
|
val prop = System.getProperty("scala.remoting.port")
|
||||||
|
if (prop ne null) prop.toInt else Registry.REGISTRY_PORT
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
case e =>
|
||||||
|
warning(e.getMessage)
|
||||||
|
Registry.REGISTRY_PORT // default port
|
||||||
|
}
|
||||||
|
|
||||||
|
private val registry =
|
||||||
|
try {
|
||||||
|
LocateRegistry.createRegistry(port)
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
case e =>
|
||||||
|
warning(e.getMessage)
|
||||||
|
LocateRegistry.getRegistry(host, port)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val prefix = "//"+host+":"+port+"/"
|
||||||
|
printDebugInfos
|
||||||
|
|
||||||
|
// Variant 1: rebind/unbind
|
||||||
|
def bind(name: String, x: Remote): Remote =
|
||||||
|
try {
|
||||||
|
registry.rebind(prefix+name, x)
|
||||||
|
info("\""+prefix+name+"\" bound")
|
||||||
|
val stub = RemoteObject.toStub(x)
|
||||||
|
//remoteGC.newRef(stub)
|
||||||
|
stub
|
||||||
|
} catch {
|
||||||
|
case e: MalformedURLException =>
|
||||||
|
error(e.getMessage); null
|
||||||
|
case e: ExportException =>
|
||||||
|
info(""+e); null
|
||||||
|
case e: Exception => // AlreadyBoundException, etc..
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
|
||||||
|
def unbind(name: String) =
|
||||||
|
try {
|
||||||
|
registry.unbind(prefix+name)
|
||||||
|
info("\""+name+"\" unbound")
|
||||||
|
} catch {
|
||||||
|
case e: java.io.EOFException =>
|
||||||
|
warning(e.getMessage)
|
||||||
|
case e: NotBoundException =>
|
||||||
|
warning(e.getMessage+" already unbound")
|
||||||
|
case e: MalformedURLException =>
|
||||||
|
error(e.getMessage)
|
||||||
|
case e: Exception =>
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
// Variant 2: un-/exportObject
|
||||||
|
def bind(name: String, x: Remote): Remote =
|
||||||
|
try {
|
||||||
|
val ex = UnicastRemoteObject.exportObject(x)
|
||||||
|
registry.rebind(prefix+name, ex)
|
||||||
|
info("\""+prefix+name+"\" bound")
|
||||||
|
//val stub = RemoteObject.toStub(ex)
|
||||||
|
//remoteGC.newRef(ex)
|
||||||
|
ex //stub
|
||||||
|
} catch {
|
||||||
|
case e: MalformedURLException =>
|
||||||
|
error(e.getMessage); null
|
||||||
|
case e: ExportException =>
|
||||||
|
info(""+e); null
|
||||||
|
case e: Exception => // AlreadyBoundException, etc..
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
|
||||||
|
def unbind(x: Remote) {
|
||||||
|
try {
|
||||||
|
UnicastRemoteObject.unexportObject(x, false)
|
||||||
|
info("\""+x+"\" unbound")
|
||||||
|
} catch {
|
||||||
|
case e: java.io.EOFException =>
|
||||||
|
warning(e.getMessage)
|
||||||
|
case e: NotBoundException =>
|
||||||
|
warning(e.getMessage+" already unbound")
|
||||||
|
case e: MalformedURLException =>
|
||||||
|
error(e.getMessage)
|
||||||
|
case e: Exception =>
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
private def info(msg: String) { Debug.info("[RemoteRef] "+msg) }
|
||||||
|
private def warning(msg: String) { Debug.warning("[RemoteRef] "+msg) }
|
||||||
|
private def error(msg: String) { Debug.error("[RemoteRef] "+msg) }
|
||||||
|
|
||||||
|
private def printDebugInfos {
|
||||||
|
def property(name: String): String =
|
||||||
|
name+"="+(
|
||||||
|
try { System.getProperty(name, "") }
|
||||||
|
catch { case e => warning(e.getMessage); "?" })
|
||||||
|
info(property("java.rmi.server.hostname"))
|
||||||
|
info(property("sun.rmi.dgc.server.gcInterval"))
|
||||||
|
info("registry="+registry)
|
||||||
|
info("prefix="+prefix)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
/* __ *\
|
||||||
|
** ________ ___ / / ___ Scala API **
|
||||||
|
** / __/ __// _ | / / / _ | (c) 2007-2009, LAMP/EPFL **
|
||||||
|
** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
|
||||||
|
** /____/\___/_/ |_/____/_/ | | **
|
||||||
|
** |/ **
|
||||||
|
\* */
|
||||||
|
|
||||||
|
// $Id: Debug.scala 17777 2009-05-19 18:16:25Z michelou $
|
||||||
|
|
||||||
|
package scala.runtime.remoting
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Stephane Micheloud
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
|
object Debug extends Debug {
|
||||||
|
override def info (msg: String) { if (lib) super.info(msg) }
|
||||||
|
override def verbose(msg: String) { if (lib) super.verbose(msg) }
|
||||||
|
override def warning(msg: String) { if (lib) super.warning(msg) }
|
||||||
|
override def error (msg: String) { if (lib) super.error(msg) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Stephane Micheloud
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
|
class Debug(tag: String) {
|
||||||
|
|
||||||
|
def this() = this("")
|
||||||
|
|
||||||
|
object Level extends Enumeration {
|
||||||
|
type Level = Value
|
||||||
|
val SILENT, ERROR, WARNING, VERBOSE, INFO = Value
|
||||||
|
}
|
||||||
|
|
||||||
|
private val level0 =
|
||||||
|
try {
|
||||||
|
val prop = System.getProperty("scala.remoting.logLevel")
|
||||||
|
if (prop ne null) prop.toLowerCase else ""
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
case e =>
|
||||||
|
Console.err.println(e.getMessage)
|
||||||
|
""
|
||||||
|
}
|
||||||
|
|
||||||
|
import Level._
|
||||||
|
protected var (lev, lib) = {
|
||||||
|
val p = java.util.regex.Pattern.compile("(error|warning|verbose|info)(\\,lib)?(.*)")
|
||||||
|
val m = p matcher level0
|
||||||
|
val (s, b) =
|
||||||
|
if (m.matches) (m.group(1), m.group(2) ne null)
|
||||||
|
else ("", false)
|
||||||
|
s match {
|
||||||
|
case "error" => (ERROR , b)
|
||||||
|
case "warning" => (WARNING, b)
|
||||||
|
case "verbose" => (VERBOSE, b)
|
||||||
|
case "info" => (INFO , b)
|
||||||
|
case _ => (SILENT , false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def level = lev
|
||||||
|
def level_= (lev: Level) = { this.lev = lev }
|
||||||
|
|
||||||
|
private val tag0: String =
|
||||||
|
if (tag != null & tag.length > 0) tag+" " else ""
|
||||||
|
|
||||||
|
def info(msg: String) {
|
||||||
|
if (lev >= INFO) Console.println(tag0 + "(info): " + msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
def verbose(msg: String) {
|
||||||
|
if (lev >= VERBOSE) Console.println(tag0 + "(verb): " + msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
def warning(msg: String) {
|
||||||
|
if (lev >= WARNING) Console.err.println(tag0 + "(warn): " + msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
def error(msg: String) {
|
||||||
|
if (lev >= ERROR) Console.err.println(tag0 + "(erro): " + msg)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,192 @@
|
||||||
|
/* __ *\
|
||||||
|
** ________ ___ / / ___ Scala API **
|
||||||
|
** / __/ __// _ | / / / _ | (c) 2002-2008, LAMP/EPFL **
|
||||||
|
** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
|
||||||
|
** /____/\___/_/ |_/____/_/ | | **
|
||||||
|
** |/ **
|
||||||
|
\* */
|
||||||
|
|
||||||
|
// $Id: RegistryDelegate.scala 18234 2009-07-07 13:21:57Z michelou $
|
||||||
|
|
||||||
|
package scala.runtime.remoting
|
||||||
|
|
||||||
|
import java.rmi.{RMISecurityManager, Remote, RemoteException}
|
||||||
|
import java.rmi.registry.{LocateRegistry, Registry}
|
||||||
|
import java.rmi.server.UnicastRemoteObject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* This class implements the registry delegate concept
|
||||||
|
* (see http://www.genady.net/rmi/v20/docs/delegate/RegistryDelegate.html)
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* In order to enforce some level of security, the standard RMI registry
|
||||||
|
* implementation (e.g. <code>rmiregistry.exe</code>) only allows processes
|
||||||
|
* on the same host to register objects in the registry (think of a bank
|
||||||
|
* running a registry on one of its servers, and doesn't want anybody
|
||||||
|
* modifying it). So, by design, if a process tries to
|
||||||
|
* <code>bind(String, Remote)</code> an object to a remote registry,
|
||||||
|
* an exception will be thrown.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* However, the design of a distributed system may require remote clients to
|
||||||
|
* register themselves in a central registry. If such system is deployed in a
|
||||||
|
* controlled and trusted environment (e.g., a firewalled intranet with tight
|
||||||
|
* access control), the security risk may be acceptable.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* The simplest technical solution to the remote registration problem is to
|
||||||
|
* have a registry delegate. A registry delegate is an object that serves as
|
||||||
|
* a proxy for the real registry. The delegate itself usually appears in the
|
||||||
|
* registry under a well known name. It implements the Registry interface and
|
||||||
|
* simply delegates all method calls to the appropriate methods of the real
|
||||||
|
* registry. The delegate is allowed to perform bind and unbind operations
|
||||||
|
* because it is running on the same host as the registry.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* The common scenario for starting a registry and creating the delegate is
|
||||||
|
* starting a class with the following <code>main(Array[String])</code> method:
|
||||||
|
* </p>
|
||||||
|
* <pre>
|
||||||
|
* @throws(classOf[AccessException], classOf[RemoteException], classOf[AlreadyBoundException])
|
||||||
|
* <b>object</b> namingService {
|
||||||
|
* <b>def</b> main(args: Array[String]) {
|
||||||
|
* <b>if</b> (System.getSecurityManager() == <b>null</b>)
|
||||||
|
* System.setSecurityManager(<b>new</b> RMISecurityManager())
|
||||||
|
*
|
||||||
|
* <b>val</b> registry = LocateRegistry.createRegistry(REGISTRY_PORT)
|
||||||
|
* registry.bind(DELEGATE_NAME, <b>new</b> RegistryDelegate());
|
||||||
|
*
|
||||||
|
* do {
|
||||||
|
* <b>try</b> {
|
||||||
|
* Thread.sleep(Long.MAX_VALUE)
|
||||||
|
* } <b>catch</b> {
|
||||||
|
* <b>case</b> e: InterruptedException => // do nothing
|
||||||
|
* <b>case</b> e: Throwable => e.printStackTrace(); System.exit(1)
|
||||||
|
* }
|
||||||
|
* } while (<b>true</b>)
|
||||||
|
* }
|
||||||
|
* }</pre>
|
||||||
|
* <p>
|
||||||
|
* The common usage scenario looks something like:
|
||||||
|
* </p><pre>
|
||||||
|
* Registry remoteRegistry = LocateRegistry.getRegistry("remotehost.mycompany.com");
|
||||||
|
* Registry delegate = (Registry) remoteRegistry.lookup(DELEGATE_NAME);
|
||||||
|
* delegate.bind("someName", <b>new</b> SomeRemoteObject());</pre>
|
||||||
|
* <p>
|
||||||
|
* The <code>getRegistryDelegate(String)</code> method is a helper method
|
||||||
|
* that fetches the registry delegate for you.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* The <code>main(Array[String])</code> method of this class will create a
|
||||||
|
* local registry on the default port, create a registry delegate and bind
|
||||||
|
* it under the well known name that you chose in the wizard
|
||||||
|
* (<code>DELEGATE_NAME</code>).
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Genady Beryozkin, rmi-info@genady.net
|
||||||
|
*/
|
||||||
|
|
||||||
|
object RMIDelegate {
|
||||||
|
/** The name under which the delegate appears in the registry. */
|
||||||
|
val DELEGATE_NAME = "foo"
|
||||||
|
|
||||||
|
/** This method retrieves the registry delegate from a registry that is
|
||||||
|
* running on a remote host.
|
||||||
|
*/
|
||||||
|
@throws(classOf[RemoteException])
|
||||||
|
def getRegistryDelegate(remoteHost: String): Registry =
|
||||||
|
getRegistryDelegate(remoteHost, Registry.REGISTRY_PORT)
|
||||||
|
|
||||||
|
/** This method retrieves the registry delegate from a registry that is
|
||||||
|
* running on a remote host.
|
||||||
|
*/
|
||||||
|
@throws(classOf[RemoteException])
|
||||||
|
def getRegistryDelegate(remoteHost: String, remotePort: Int): Registry = {
|
||||||
|
val registry = LocateRegistry.getRegistry(remoteHost, remotePort)
|
||||||
|
(registry lookup DELEGATE_NAME).asInstanceOf[Registry]
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A simple way to run a registry and bind a registry delegate. */
|
||||||
|
@throws(classOf[RemoteException])
|
||||||
|
def main(args: Array[String]) {
|
||||||
|
var port = Registry.REGISTRY_PORT
|
||||||
|
|
||||||
|
if (args.length > 0) {
|
||||||
|
if (args(0) equals "-help") {
|
||||||
|
println("Usage: rmidelegate <options> <port>")
|
||||||
|
exit(0)
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
port = args(0).toInt
|
||||||
|
} catch {
|
||||||
|
case e: NumberFormatException =>
|
||||||
|
println("Usage: rmidelegate <options> <port>")
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
val opts = args filter (_ startsWith "-J-D")
|
||||||
|
for (opt <- opts) {
|
||||||
|
val x = opt.substring(4) split "="
|
||||||
|
if (x.length == 2) System.setProperty(x(0), x(1))
|
||||||
|
else System.setProperty(x(0), "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (System.getSecurityManager() == null)
|
||||||
|
System.setSecurityManager(new RMISecurityManager() {
|
||||||
|
override def checkPermission(p: java.security.Permission) {}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
val registry = LocateRegistry.createRegistry(port)
|
||||||
|
registry.bind(DELEGATE_NAME, new RegistryDelegate())
|
||||||
|
|
||||||
|
do {
|
||||||
|
try {
|
||||||
|
Thread.sleep(Long.MaxValue)
|
||||||
|
} catch {
|
||||||
|
case e: InterruptedException =>
|
||||||
|
// do nothing
|
||||||
|
case e: Throwable =>
|
||||||
|
e.printStackTrace()
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
} while (true)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Create a delegate for a user provided registry instance. The registry is
|
||||||
|
* assumed to be a local registry, as there is no point in creating a delegate
|
||||||
|
* for a remote registry.
|
||||||
|
*/
|
||||||
|
class RegistryDelegate(reg: Registry) extends UnicastRemoteObject with Registry {
|
||||||
|
/** The local registry */
|
||||||
|
private val localRegistry: Registry = reg
|
||||||
|
|
||||||
|
/** Create a delegate for a local registry that is bound to the default
|
||||||
|
* local port (1099).
|
||||||
|
*/
|
||||||
|
def this() = this(LocateRegistry.getRegistry())
|
||||||
|
|
||||||
|
/** Create a delegate for a local registry that is bound to a user
|
||||||
|
* specified port.
|
||||||
|
*/
|
||||||
|
def this(port: Int) = this(LocateRegistry.getRegistry(port))
|
||||||
|
|
||||||
|
@throws(classOf[RemoteException])
|
||||||
|
def bind(name: String, obj: Remote) { localRegistry.bind(name, obj) }
|
||||||
|
|
||||||
|
@throws(classOf[RemoteException])
|
||||||
|
def list(): Array[String] = localRegistry.list()
|
||||||
|
|
||||||
|
@throws(classOf[RemoteException])
|
||||||
|
def lookup(name: String): Remote = localRegistry.lookup(name)
|
||||||
|
|
||||||
|
@throws(classOf[RemoteException])
|
||||||
|
def rebind(name: String, obj: Remote) { localRegistry.rebind(name, obj) }
|
||||||
|
|
||||||
|
@throws(classOf[RemoteException])
|
||||||
|
def unbind(name: String) { localRegistry.unbind(name) }
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
/* __ *\
|
||||||
|
** ________ ___ / / ___ Scala API **
|
||||||
|
** / __/ __// _ | / / / _ | (c) 2002-2009, LAMP/EPFL **
|
||||||
|
** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
|
||||||
|
** /____/\___/_/ |_/____/_/ | | **
|
||||||
|
** |/ **
|
||||||
|
\* */
|
||||||
|
|
||||||
|
// $Id: RemoteBooleanRef.scala 18398 2009-07-28 14:26:36Z michelou $
|
||||||
|
|
||||||
|
package scala.runtime.remoting
|
||||||
|
|
||||||
|
import java.rmi.server.{UnicastRemoteObject, Unreferenced}
|
||||||
|
import scala.runtime.{BooleanRef, RemoteRef}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The trait Remote<code>RemoteBooleanRef</code> provides a remote interface
|
||||||
|
* for manipulating boolean references.
|
||||||
|
*
|
||||||
|
* @author Stephane Micheloud
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
|
@remote
|
||||||
|
trait RemoteBooleanRef {
|
||||||
|
def elem_=(value: Boolean)
|
||||||
|
def elem: Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The class <code>RemoteBooleanRefImpl</code> implements a remote (global)
|
||||||
|
* boolean reference by inheriting from the class
|
||||||
|
* <code>UnicastRemoteObject</code>.
|
||||||
|
*
|
||||||
|
* In particular, it forwards method invocations to the <code>elem</code>
|
||||||
|
* accessors of class <code>runtime.BooleanRef</code> and implements the
|
||||||
|
* <code>java.rmi.server.Unreferenced</code> interface to automatically
|
||||||
|
* remove the no more referenced binding from the registry.
|
||||||
|
*
|
||||||
|
* @author Stephane Micheloud
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
|
class RemoteBooleanRefImpl(name: String, x: BooleanRef)
|
||||||
|
extends UnicastRemoteObject with RemoteBooleanRef with Unreferenced {
|
||||||
|
def elem_=(value: Boolean) { x.elem = value }
|
||||||
|
def elem: Boolean = x.elem
|
||||||
|
override def toString() = x.elem.toString
|
||||||
|
def unreferenced() {
|
||||||
|
Debug.info("[RemoteBooleanRefImpl] unreferenced: "+this)
|
||||||
|
RemoteRef.unbind(name)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
/* __ *\
|
||||||
|
** ________ ___ / / ___ Scala API **
|
||||||
|
** / __/ __// _ | / / / _ | (c) 2002-2009, LAMP/EPFL **
|
||||||
|
** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
|
||||||
|
** /____/\___/_/ |_/____/_/ | | **
|
||||||
|
** |/ **
|
||||||
|
\* */
|
||||||
|
|
||||||
|
// $Id: RemoteByteRef.scala 18398 2009-07-28 14:26:36Z michelou $
|
||||||
|
|
||||||
|
package scala.runtime.remoting
|
||||||
|
|
||||||
|
import java.rmi.server.{UnicastRemoteObject, Unreferenced}
|
||||||
|
import scala.runtime.{ByteRef, RemoteRef}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The trait Remote<code>RemoteByteRef</code> provides a remote interface
|
||||||
|
* for manipulating byte references.
|
||||||
|
*
|
||||||
|
* @author Stephane Micheloud
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
|
@remote
|
||||||
|
trait RemoteByteRef {
|
||||||
|
def elem_=(value: Byte)
|
||||||
|
def elem: Byte
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The class <code>RemoteByteRefImpl</code> implements a remote (global)
|
||||||
|
* byte reference by inheriting from the class
|
||||||
|
* <code>UnicastRemoteObject</code>.
|
||||||
|
*
|
||||||
|
* In particular, it forwards method invocations to the <code>elem</code>
|
||||||
|
* accessors of class <code>runtime.ByteRef</code> and implements the
|
||||||
|
* <code>java.rmi.server.Unreferenced</code> interface to automatically
|
||||||
|
* remove the no more referenced binding from the registry.
|
||||||
|
*
|
||||||
|
* @author Stephane Micheloud
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
|
class RemoteByteRefImpl(name: String, x: ByteRef)
|
||||||
|
extends UnicastRemoteObject with RemoteByteRef with Unreferenced {
|
||||||
|
def elem_=(value: Byte) { x.elem = value }
|
||||||
|
def elem: Byte = x.elem
|
||||||
|
override def toString() = x.elem.toString
|
||||||
|
def unreferenced() {
|
||||||
|
Debug.info("[RemoteByteRefImpl] unreferenced: "+this)
|
||||||
|
RemoteRef.unbind(name)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
/* __ *\
|
||||||
|
** ________ ___ / / ___ Scala API **
|
||||||
|
** / __/ __// _ | / / / _ | (c) 2002-2008, LAMP/EPFL **
|
||||||
|
** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
|
||||||
|
** /____/\___/_/ |_/____/_/ | | **
|
||||||
|
** |/ **
|
||||||
|
\* */
|
||||||
|
|
||||||
|
// $Id: RemoteCharRef.scala 18398 2009-07-28 14:26:36Z michelou $
|
||||||
|
|
||||||
|
package scala.runtime.remoting
|
||||||
|
|
||||||
|
import java.rmi.server.{UnicastRemoteObject, Unreferenced}
|
||||||
|
import scala.runtime.{CharRef, RemoteRef}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The trait Remote<code>RemoteCharRef</code> provides a remote interface
|
||||||
|
* for manipulating character references.
|
||||||
|
*
|
||||||
|
* @author Stephane Micheloud
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
|
@remote
|
||||||
|
trait RemoteCharRef {
|
||||||
|
def elem_=(value: Char)
|
||||||
|
def elem: Char
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The class <code>RemoteCharRefImpl</code> implements a remote (global)
|
||||||
|
* character reference by inheriting from the class
|
||||||
|
* <code>UnicastRemoteObject</code>.
|
||||||
|
*
|
||||||
|
* In particular, it forwards method invocations to the <code>elem</code>
|
||||||
|
* accessors of class <code>runtime.CharRef</code> and implements the
|
||||||
|
* <code>java.rmi.server.Unreferenced</code> interface to automatically
|
||||||
|
* remove the no more referenced binding from the registry.
|
||||||
|
*
|
||||||
|
* @author Stephane Micheloud
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
|
class RemoteCharRefImpl(name: String, x: CharRef)
|
||||||
|
extends UnicastRemoteObject with RemoteCharRef with Unreferenced {
|
||||||
|
def elem_=(value: Char) { x.elem = value }
|
||||||
|
def elem: Char = x.elem
|
||||||
|
override def toString() = x.elem.toString
|
||||||
|
def unreferenced() {
|
||||||
|
Debug.info("[RemoteCharRefImpl] unreferenced: "+this)
|
||||||
|
RemoteRef.unbind(name)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
/* __ *\
|
||||||
|
** ________ ___ / / ___ Scala API **
|
||||||
|
** / __/ __// _ | / / / _ | (c) 2002-2009, LAMP/EPFL **
|
||||||
|
** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
|
||||||
|
** /____/\___/_/ |_/____/_/ | | **
|
||||||
|
** |/ **
|
||||||
|
\* */
|
||||||
|
|
||||||
|
// $Id: RemoteDoubleRef.scala 18398 2009-07-28 14:26:36Z michelou $
|
||||||
|
|
||||||
|
package scala.runtime.remoting
|
||||||
|
|
||||||
|
import java.rmi.server.{UnicastRemoteObject, Unreferenced}
|
||||||
|
import scala.runtime.{DoubleRef, RemoteRef}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The trait Remote<code>RemoteDoubleRef</code> provides..
|
||||||
|
*
|
||||||
|
* @author Stephane Micheloud
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
|
@remote
|
||||||
|
trait RemoteDoubleRef {
|
||||||
|
def elem_=(value: Double)
|
||||||
|
def elem: Double
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The class <code>RemoteDoubleRefImpl</code> implements a remote (global)
|
||||||
|
* double reference by inheriting from the class
|
||||||
|
* <code>UnicastRemoteObject</code>.
|
||||||
|
*
|
||||||
|
* In particular, it forwards method invocations to the <code>elem</code>
|
||||||
|
* accessors of class <code>runtime.DoubleRef</code> and implements the
|
||||||
|
* <code>java.rmi.server.Unreferenced</code> interface to automatically
|
||||||
|
* remove the no more referenced binding from the registry.
|
||||||
|
*
|
||||||
|
* @author Stephane Micheloud
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
|
class RemoteDoubleRefImpl(name: String, x: DoubleRef)
|
||||||
|
extends UnicastRemoteObject with RemoteDoubleRef with Unreferenced {
|
||||||
|
def elem_=(value: Double) { x.elem = value }
|
||||||
|
def elem: Double = x.elem
|
||||||
|
override def toString() = x.elem.toString
|
||||||
|
def unreferenced() {
|
||||||
|
Debug.info("[RemoteDoubleRefImpl] unreferenced: "+this)
|
||||||
|
RemoteRef.unbind(name)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
/* __ *\
|
||||||
|
** ________ ___ / / ___ Scala API **
|
||||||
|
** / __/ __// _ | / / / _ | (c) 2002-2009, LAMP/EPFL **
|
||||||
|
** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
|
||||||
|
** /____/\___/_/ |_/____/_/ | | **
|
||||||
|
** |/ **
|
||||||
|
\* */
|
||||||
|
|
||||||
|
// $Id: RemoteFloatRef.scala 18398 2009-07-28 14:26:36Z michelou $
|
||||||
|
|
||||||
|
package scala.runtime.remoting
|
||||||
|
|
||||||
|
import java.rmi.server.{UnicastRemoteObject, Unreferenced}
|
||||||
|
import scala.runtime.{FloatRef, RemoteRef}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The trait Remote<code>RemoteFloatRef</code> provides a remote interface
|
||||||
|
* for manipulating float references.
|
||||||
|
*
|
||||||
|
* @author Stephane Micheloud
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
|
@remote
|
||||||
|
trait RemoteFloatRef {
|
||||||
|
def elem_=(value: Float)
|
||||||
|
def elem: Float
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The class <code>RemoteFloatRefImpl</code> implements a remote (global)
|
||||||
|
* float reference by inheriting from the class
|
||||||
|
* <code>UnicastRemoteObject</code>.
|
||||||
|
*
|
||||||
|
* In particular, it forwards method invocations to the <code>elem</code>
|
||||||
|
* accessors of class <code>runtime.FloatRef</code> and implements the
|
||||||
|
* <code>java.rmi.server.Unreferenced</code> interface.
|
||||||
|
*
|
||||||
|
* @author Stephane Micheloud
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
|
class RemoteFloatRefImpl(name: String, x: FloatRef)
|
||||||
|
extends UnicastRemoteObject with RemoteFloatRef with Unreferenced {
|
||||||
|
def elem_=(value: Float) { x.elem = value }
|
||||||
|
def elem: Float = x.elem
|
||||||
|
override def toString() = x.elem.toString
|
||||||
|
def unreferenced() {
|
||||||
|
Debug.info("[RemoteIntFloatImpl] unreferenced: "+this)
|
||||||
|
RemoteRef.unbind(name)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
/* __ *\
|
||||||
|
** ________ ___ / / ___ Scala API **
|
||||||
|
** / __/ __// _ | / / / _ | (c) 2002-2009, LAMP/EPFL **
|
||||||
|
** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
|
||||||
|
** /____/\___/_/ |_/____/_/ | | **
|
||||||
|
** |/ **
|
||||||
|
\* */
|
||||||
|
|
||||||
|
// $Id: RemoteGC.scala 17547 2009-04-21 13:56:28Z michelou $
|
||||||
|
|
||||||
|
package scala.runtime.remoting
|
||||||
|
|
||||||
|
import java.lang.ref.{Reference, WeakReference, ReferenceQueue}
|
||||||
|
import java.rmi.{NoSuchObjectException, Remote}
|
||||||
|
import java.rmi.server.UnicastRemoteObject
|
||||||
|
|
||||||
|
import scala.collection.mutable.HashSet
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Stephane Micheloud
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
|
// Adapted from scala.actors.ActorGC
|
||||||
|
private [runtime] class RemoteGC {
|
||||||
|
|
||||||
|
private val refQueue = new ReferenceQueue[Remote]
|
||||||
|
private val refSet = new HashSet[Reference[T] forSome { type T <: Remote }]
|
||||||
|
|
||||||
|
private var liveRefs = 0
|
||||||
|
|
||||||
|
def newRef(a: Remote) = synchronized {
|
||||||
|
refSet += new WeakReference(a, refQueue)
|
||||||
|
liveRefs += 1
|
||||||
|
info("added object reference \""+a+"\" ("+liveRefs+")")
|
||||||
|
}
|
||||||
|
|
||||||
|
def gc() = synchronized {
|
||||||
|
info("GC called ("+liveRefs+")")
|
||||||
|
// check for unreachable object references
|
||||||
|
def drain() {
|
||||||
|
val wr = refQueue.poll
|
||||||
|
if (wr != null) {
|
||||||
|
val msg = try {
|
||||||
|
UnicastRemoteObject.unexportObject(wr.get, true/*force*/)
|
||||||
|
"removed object reference"
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
case e: NoSuchObjectException =>
|
||||||
|
"object already unbound"
|
||||||
|
}
|
||||||
|
info(msg+" ("+liveRefs+")")
|
||||||
|
liveRefs -= 1
|
||||||
|
refSet -= wr
|
||||||
|
// continue draining
|
||||||
|
drain()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
drain()
|
||||||
|
}
|
||||||
|
|
||||||
|
def allClosed: Boolean = synchronized {
|
||||||
|
liveRefs <= 0
|
||||||
|
}
|
||||||
|
|
||||||
|
private def info(msg: String) { Debug.info("[RemoteGC] "+msg) }
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
/* __ *\
|
||||||
|
** ________ ___ / / ___ Scala API **
|
||||||
|
** / __/ __// _ | / / / _ | (c) 2002-2009, LAMP/EPFL **
|
||||||
|
** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
|
||||||
|
** /____/\___/_/ |_/____/_/ | | **
|
||||||
|
** |/ **
|
||||||
|
\* */
|
||||||
|
|
||||||
|
// $Id: RemoteIntRef.scala 18398 2009-07-28 14:26:36Z michelou $
|
||||||
|
|
||||||
|
package scala.runtime.remoting
|
||||||
|
|
||||||
|
import java.rmi.server.{UnicastRemoteObject, Unreferenced}
|
||||||
|
import scala.runtime.{IntRef, RemoteRef}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The trait Remote<code>RemoteIntRef</code> provides a remote interface
|
||||||
|
* for manipulating integer references.
|
||||||
|
*
|
||||||
|
* @author Stephane Micheloud
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
|
@remote
|
||||||
|
trait RemoteIntRef {
|
||||||
|
def elem_=(value: Int)
|
||||||
|
def elem: Int
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The class <code>RemoteIntRefImpl</code> implements a remote (global)
|
||||||
|
* integer reference by inheriting from the class
|
||||||
|
* <code>UnicastRemoteObject</code>.
|
||||||
|
*
|
||||||
|
* In particular, it forwards method invocations to the <code>elem</code>
|
||||||
|
* accessors of class <code>runtime.IntRef</code> and implements the
|
||||||
|
* <code>java.rmi.server.Unreferenced</code> interface to automatically
|
||||||
|
* remove the no more referenced binding from the registry.
|
||||||
|
*
|
||||||
|
* @author Stephane Micheloud
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
|
class RemoteIntRefImpl(name: String, x: IntRef)
|
||||||
|
extends UnicastRemoteObject with RemoteIntRef with Unreferenced {
|
||||||
|
def elem_=(value: Int) { x.elem = value }
|
||||||
|
def elem: Int = x.elem
|
||||||
|
override def toString() = x.elem.toString
|
||||||
|
def unreferenced() {
|
||||||
|
Debug.info("[RemoteIntRefImpl] unreferenced: "+this)
|
||||||
|
RemoteRef.unbind(name)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
/* __ *\
|
||||||
|
** ________ ___ / / ___ Scala API **
|
||||||
|
** / __/ __// _ | / / / _ | (c) 2002-2009, LAMP/EPFL **
|
||||||
|
** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
|
||||||
|
** /____/\___/_/ |_/____/_/ | | **
|
||||||
|
** |/ **
|
||||||
|
\* */
|
||||||
|
|
||||||
|
// $Id: RemoteLongRef.scala 18398 2009-07-28 14:26:36Z michelou $
|
||||||
|
|
||||||
|
package scala.runtime.remoting
|
||||||
|
|
||||||
|
import java.rmi.server.{UnicastRemoteObject, Unreferenced}
|
||||||
|
import scala.runtime.{LongRef, RemoteRef}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The trait Remote<code>RemoteLongRef</code> provides a remote interface
|
||||||
|
* for manipulating long integer references.
|
||||||
|
*
|
||||||
|
* @author Stephane Micheloud
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
|
@remote
|
||||||
|
trait RemoteLongRef {
|
||||||
|
def elem_=(value: Long)
|
||||||
|
def elem: Long
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The class <code>RemoteLongRefImpl</code> implements a remote (global)
|
||||||
|
* long integer reference by inheriting from the class
|
||||||
|
* <code>UnicastRemoteObject</code>.
|
||||||
|
*
|
||||||
|
* In particular, it forwards method invocations to the <code>elem</code>
|
||||||
|
* accessors of class <code>runtime.LongRef</code> and implements the
|
||||||
|
* <code>java.rmi.server.Unreferenced</code> interface to automatically
|
||||||
|
* remove the no more referenced binding from the registry.
|
||||||
|
*
|
||||||
|
* @author Stephane Micheloud
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
|
class RemoteLongRefImpl(name: String, x: LongRef)
|
||||||
|
extends UnicastRemoteObject with RemoteLongRef with Unreferenced {
|
||||||
|
def elem_=(value: Long) { x.elem = value }
|
||||||
|
def elem: Long = x.elem
|
||||||
|
override def toString() = x.elem.toString
|
||||||
|
def unreferenced() {
|
||||||
|
Debug.info("[RemoteLongRefImpl] unreferenced: "+this)
|
||||||
|
RemoteRef.unbind(name)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
/* __ *\
|
||||||
|
** ________ ___ / / ___ Scala API **
|
||||||
|
** / __/ __// _ | / / / _ | (c) 2002-2009, LAMP/EPFL **
|
||||||
|
** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
|
||||||
|
** /____/\___/_/ |_/____/_/ | | **
|
||||||
|
** |/ **
|
||||||
|
\* */
|
||||||
|
|
||||||
|
// $Id: RemoteObjectRef.scala 18398 2009-07-28 14:26:36Z michelou $
|
||||||
|
|
||||||
|
package scala.runtime.remoting
|
||||||
|
|
||||||
|
import java.rmi.server.{UnicastRemoteObject, Unreferenced}
|
||||||
|
import scala.runtime.{ObjectRef, RemoteRef}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The trait Remote<code>RemoteObjectRef</code> provides a remote interface
|
||||||
|
* for manipulating object references.
|
||||||
|
*
|
||||||
|
* @author Stephane Micheloud
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
|
@remote
|
||||||
|
trait RemoteObjectRef {
|
||||||
|
def elem_=(value: AnyRef)
|
||||||
|
def elem: AnyRef
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The class <code>RemoteObjectRefImpl</code> implements a remote (global)
|
||||||
|
* object reference by inheriting from the class
|
||||||
|
* <code>UnicastRemoteObject</code>.
|
||||||
|
*
|
||||||
|
* In particular, it forwards method invocations to the <code>elem</code>
|
||||||
|
* accessors of class <code>runtime.ObjectRef</code> and implements the
|
||||||
|
* <code>java.rmi.server.Unreferenced</code> interface to automatically
|
||||||
|
* remove the no more referenced binding from the registry.
|
||||||
|
*
|
||||||
|
* @author Stephane Micheloud
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
|
class RemoteObjectRefImpl(name: String, x: ObjectRef)
|
||||||
|
extends UnicastRemoteObject with RemoteObjectRef with Unreferenced {
|
||||||
|
def elem_=(value: AnyRef) { x.elem = value }
|
||||||
|
def elem: AnyRef = x.elem
|
||||||
|
override def toString() = x.elem.toString
|
||||||
|
def unreferenced() {
|
||||||
|
Debug.info("[RemoteObjectRefImpl] unreferenced: "+this)
|
||||||
|
RemoteRef.unbind(name)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
/* __ *\
|
||||||
|
** ________ ___ / / ___ Scala API **
|
||||||
|
** / __/ __// _ | / / / _ | (c) 2002-2009, LAMP/EPFL **
|
||||||
|
** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
|
||||||
|
** /____/\___/_/ |_/____/_/ | | **
|
||||||
|
** |/ **
|
||||||
|
\* */
|
||||||
|
|
||||||
|
// $Id: RemoteShortRef.scala 18398 2009-07-28 14:26:36Z michelou $
|
||||||
|
|
||||||
|
package scala.runtime.remoting
|
||||||
|
|
||||||
|
import java.rmi.server.{UnicastRemoteObject, Unreferenced}
|
||||||
|
import scala.runtime.{ShortRef, RemoteRef}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The trait Remote<code>RemoteShortRef</code> provides a remote interface
|
||||||
|
* for manipulating short integer references.
|
||||||
|
*
|
||||||
|
* @author Stephane Micheloud
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
|
@remote
|
||||||
|
trait RemoteShortRef {
|
||||||
|
def elem_=(value: Short)
|
||||||
|
def elem: Short
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The class <code>RemoteShortRefImpl</code> implements a remote (global)
|
||||||
|
* short integer reference by inheriting from the class
|
||||||
|
* <code>UnicastRemoteObject</code>.
|
||||||
|
*
|
||||||
|
* In particular, it forwards method invocations to the <code>elem</code>
|
||||||
|
* accessors of class <code>runtime.ShortRef</code> and implements the
|
||||||
|
* <code>java.rmi.server.Unreferenced</code> interface.
|
||||||
|
*
|
||||||
|
* @author Stephane Micheloud
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
|
class RemoteShortRefImpl(name: String, x: ShortRef)
|
||||||
|
extends UnicastRemoteObject with RemoteShortRef with Unreferenced {
|
||||||
|
def elem_=(value: Short) { x.elem = value }
|
||||||
|
def elem: Short = x.elem
|
||||||
|
override def toString() = x.elem.toString
|
||||||
|
def unreferenced() {
|
||||||
|
Debug.info("[RemoteShortRefImpl] unreferenced: "+this)
|
||||||
|
RemoteRef.unbind(name)
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,41 @@
|
||||||
|
/* NSC -- new Scala compiler
|
||||||
|
* Copyright 2005-2010 LAMP/EPFL
|
||||||
|
* @author Stephane Micheloud
|
||||||
|
*/
|
||||||
|
|
||||||
|
package scala.tools.detach
|
||||||
|
|
||||||
|
import scala.tools.nsc.{Global, Phase}
|
||||||
|
import scala.tools.nsc.plugins.{Plugin, PluginComponent}
|
||||||
|
|
||||||
|
class DetachPlugin(val global: Global) extends Plugin {
|
||||||
|
import global._
|
||||||
|
|
||||||
|
val name = "detach"
|
||||||
|
val description = "Perform detaching of remote closures"
|
||||||
|
|
||||||
|
object detach extends {
|
||||||
|
val global = DetachPlugin.this.global
|
||||||
|
val runsAfter = List("lambdalift")
|
||||||
|
override val runsBefore = List("constructors")
|
||||||
|
} with Detach
|
||||||
|
|
||||||
|
val components = List[PluginComponent](detach)
|
||||||
|
|
||||||
|
def setEnabled(flag: Boolean) { detach.isEnabled = flag }
|
||||||
|
|
||||||
|
override def processOptions(options: List[String], error: String => Unit) = {
|
||||||
|
var enabled = false
|
||||||
|
for (option <- options) {
|
||||||
|
if (option == "enable") {
|
||||||
|
enabled = true
|
||||||
|
} else {
|
||||||
|
error("Option not understood: "+option)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setEnabled(enabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
override val optionsHelp: Option[String] =
|
||||||
|
Some(" -P:detach:enable Enable detaching of remote closures")
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
<plugin>
|
||||||
|
<name>detach</name>
|
||||||
|
<classname>scala.tools.detach.DetachPlugin</classname>
|
||||||
|
</plugin>
|
|
@ -0,0 +1,4 @@
|
||||||
|
det_bar.scala:7: error: detach inapplicable for method bar
|
||||||
|
detach(bar)
|
||||||
|
^
|
||||||
|
one error found
|
|
@ -0,0 +1,13 @@
|
||||||
|
import scala.remoting._
|
||||||
|
class A(y: Int) {
|
||||||
|
var z = 2
|
||||||
|
var bar = (x: Int) => x + y + z
|
||||||
|
def foo(x: Int): Int = x + y + z
|
||||||
|
bar = (x: Int) => x * y
|
||||||
|
detach(bar)
|
||||||
|
}
|
||||||
|
|
||||||
|
object test extends Application {
|
||||||
|
val a = new A(1)
|
||||||
|
println(a.bar(2))
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
Server.main 8889
|
||||||
|
Client.main 127.0.0.1 8889
|
||||||
|
yInstVal = 10
|
||||||
|
zLocVal = 1000
|
||||||
|
result received: 11111
|
|
@ -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 _ => }
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
*/
|
|
@ -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"
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
-Xpluginsdir ../../../../build/pack/misc/scala-devel/plugins -Xplugin-require:detach -P:detach:enable
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
//};
|
|
@ -0,0 +1,5 @@
|
||||||
|
Server.main 8889
|
||||||
|
> Client.main 127.0.0.1 8889
|
||||||
|
yInstVal = 10
|
||||||
|
zLocVal = 1000
|
||||||
|
result received: 11111
|
|
@ -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 _ => }
|
||||||
|
}
|
||||||
|
}
|
|
@ -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()
|
||||||
|
}
}
|
|
@ -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"
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
-Xpluginsdir ../../../../build/pack/misc/scala-devel/plugins -Xplugin-require:detach -P:detach:enable
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
//};
|
Loading…
Reference in New Issue