diff options
-rw-r--r-- | src/library/scala/sys/BooleanProp.scala | 40 | ||||
-rw-r--r-- | src/library/scala/sys/Prop.scala | 8 | ||||
-rw-r--r-- | src/library/scala/sys/PropImpl.scala | 31 | ||||
-rw-r--r-- | src/library/scala/sys/SystemProperties.scala | 29 | ||||
-rw-r--r-- | src/partest/scala/tools/partest/SecurityTest.scala | 32 | ||||
-rw-r--r-- | test/files/run/applet-prop.scala | 40 | ||||
-rw-r--r-- | test/files/run/sysprops.scala | 2 | ||||
-rw-r--r-- | test/files/specialized/test.scala | 11 |
8 files changed, 146 insertions, 47 deletions
diff --git a/src/library/scala/sys/BooleanProp.scala b/src/library/scala/sys/BooleanProp.scala index 0f04d1f45e..e598d81307 100644 --- a/src/library/scala/sys/BooleanProp.scala +++ b/src/library/scala/sys/BooleanProp.scala @@ -11,9 +11,8 @@ package scala.sys /** A few additional conveniences for Boolean properties. */ trait BooleanProp extends Prop[Boolean] { - /** The default implementation of `value` adheres to java's definition - * of truth, which means it is true only if there is a value in the map and - * that value, once converted to all lower case, is equal to "true". + /** The semantics of value are determined at Prop creation. See methods + * `valueIsTrue` and `keyExists` in object BooleanProp for examples. * * @return true if the current String is considered true, false otherwise */ @@ -30,5 +29,40 @@ trait BooleanProp extends Prop[Boolean] { } object BooleanProp { + private[sys] + class BooleanPropImpl(key: String, valueFn: String => Boolean) extends PropImpl(key, valueFn) with BooleanProp { + def enable() = this set "true" + def disable() = this.clear() + def toggle() = if (value) disable() else enable() + } + private[sys] + class ConstantImpl(val key: String, val value: Boolean) extends BooleanProp { + val isSet = value + def set(newValue: String) = "" + value + def get: String = "" + value + val clear, enable, disable, toggle = () + protected def zero = false + } + + /** The java definition of property truth is that the key be in the map and + * the value be equal to the String "true", case insensitively. This method + * creates a BooleanProp instance which adheres to that definition. + * + * @return A BooleanProp which acts like java's Boolean.getBoolean + */ + def valueIsTrue[T](key: String): BooleanProp = new BooleanPropImpl(key, _.toLowerCase == "true") + + /** As an alternative, this method creates a BooleanProp which is true + * if the key exists in the map. This way -Dfoo.bar is enough to be + * considered true. + * + * @return A BooleanProp with a liberal truth policy + */ + def keyExists[T](key: String): BooleanProp = new BooleanPropImpl(key, _ => true) + + /** A constant true or false property which ignores all method calls. + */ + def constant(key: String, isOn: Boolean): BooleanProp = new ConstantImpl(key, isOn) + implicit def booleanPropAsBoolean(b: BooleanProp): Boolean = b.value } diff --git a/src/library/scala/sys/Prop.scala b/src/library/scala/sys/Prop.scala index 1ac63ebc71..e3cbd4e515 100644 --- a/src/library/scala/sys/Prop.scala +++ b/src/library/scala/sys/Prop.scala @@ -18,7 +18,7 @@ package scala.sys * @version 2.9 * @since 2.9 */ -trait Prop[T] { +trait Prop[+T] { /** The full name of the property, e.g. "java.awt.headless". */ def key: String @@ -60,21 +60,19 @@ trait Prop[T] { protected def zero: T } -object Prop extends PropCompanion { +object Prop { /** A creator of property instances. For any type `T`, if an implicit * parameter of type Creator[T] is in scope, a Prop[T] can be created * via this object's apply method. */ - trait Creator[T] { + trait Creator[+T] { /** Creates a Prop[T] of this type based on the given key. */ def apply(key: String): Prop[T] } - implicit object BooleanProp extends BooleanCreatorImpl implicit object StringProp extends CreatorImpl[String](s => s) implicit object IntProp extends CreatorImpl[Int](_.toInt) implicit object DoubleProp extends CreatorImpl[Double](_.toDouble) - def bool[T](key: String): BooleanProp = BooleanProp(key) def apply[T: Creator](key: String): Prop[T] = implicitly[Creator[T]] apply key } diff --git a/src/library/scala/sys/PropImpl.scala b/src/library/scala/sys/PropImpl.scala index 02f00f682b..55073c35d3 100644 --- a/src/library/scala/sys/PropImpl.scala +++ b/src/library/scala/sys/PropImpl.scala @@ -12,7 +12,7 @@ import scala.collection.mutable /** The internal implementation of scala.sys.Prop. */ -private[sys] class PropImpl[T](val key: String, valueFn: String => T) extends Prop[T] { +private[sys] class PropImpl[+T](val key: String, valueFn: String => T) extends Prop[T] { def value: T = if (isSet) valueFn(get) else zero def isSet = underlying contains key def set(newValue: String): String = { @@ -21,10 +21,10 @@ private[sys] class PropImpl[T](val key: String, valueFn: String => T) extends Pr old } def get: String = - if (isSet) underlying(key) + if (isSet) underlying.getOrElse(key, "") else "" - def clear() = underlying -= key + def clear(): Unit = underlying -= key /** The underlying property map, in our case always sys.props */ protected def underlying: mutable.Map[String, String] = scala.sys.props @@ -33,26 +33,7 @@ private[sys] class PropImpl[T](val key: String, valueFn: String => T) extends Pr override def toString = "%s (%s)".format(key, getString) } -trait PropCompanion { - self: Prop.type => - - private[sys] class BooleanPropImpl(key: String, valueFn: String => Boolean) extends PropImpl[Boolean](key, valueFn) with BooleanProp { - def enable() = this set "true" - def disable() = this.clear() - def toggle() = if (value) disable() else enable() - } - private[sys] abstract class CreatorImpl[T](f: String => T) extends Creator[T] { - def apply(key: String): Prop[T] = new PropImpl[T](key, f) - } - /** Implicit objects for the standard types. Custom ones can also be - * created by implementing Creator[T]. - */ - private[sys] trait BooleanCreatorImpl extends Creator[Boolean] { - self: BooleanProp.type => - - /** As implemented in java.lang.Boolean.getBoolean. */ - private def javaStyleTruth(s: String) = s.toLowerCase == "true" - - def apply(key: String): BooleanProp = new BooleanPropImpl(key, javaStyleTruth) - } +private[sys] abstract class CreatorImpl[+T](f: String => T) extends Prop.Creator[T] { + def apply(key: String): Prop[T] = new PropImpl[T](key, f) } + diff --git a/src/library/scala/sys/SystemProperties.scala b/src/library/scala/sys/SystemProperties.scala index de3f9598f0..7c6286516b 100644 --- a/src/library/scala/sys/SystemProperties.scala +++ b/src/library/scala/sys/SystemProperties.scala @@ -10,11 +10,14 @@ package scala.sys import scala.collection.mutable import scala.collection.JavaConverters._ +import java.security.AccessControlException /** A bidirectional map wrapping the java System properties. * Changes to System properties will be immediately visible in the map, * and modifications made to the map will be immediately applied to the - * System properties. + * System properties. If a security manager is in place which prevents + * the properties from being read or written, the AccessControlException + * will be caught and discarded. * * @author Paul Phillips * @version 2.9 @@ -23,11 +26,19 @@ import scala.collection.JavaConverters._ class SystemProperties extends mutable.Map[String, String] { override def empty = new SystemProperties override def default(key: String): String = null - def iterator: Iterator[(String, String)] = System.getProperties().asScala.iterator - def get(key: String) = Option(System.getProperty(key)) - def -= (key: String): this.type = { System.clearProperty(key) ; this } - def += (kv: (String, String)): this.type = { System.setProperty(kv._1, kv._2) ; this } + def iterator: Iterator[(String, String)] = + wrapAccess(System.getProperties().asScala.iterator) getOrElse Iterator.empty + def get(key: String) = + wrapAccess(Option(System.getProperty(key))) flatMap (x => x) + override def contains(key: String) = + wrapAccess(super.contains(key)) exists (x => x) + + def -= (key: String): this.type = { wrapAccess(System.clearProperty(key)) ; this } + def += (kv: (String, String)): this.type = { wrapAccess(System.setProperty(kv._1, kv._2)) ; this } + + def wrapAccess[T](body: => T): Option[T] = + try Some(body) catch { case _: AccessControlException => None } } /** The values in SystemProperties can be used to access and manipulate @@ -40,8 +51,12 @@ object SystemProperties { implicit def systemPropertiesToCompanion(p: SystemProperties): SystemProperties.type = this private lazy val propertyHelp = mutable.Map[String, String]() private def bool(key: String, helpText: String) = { - try Prop.bool(key) - finally propertyHelp(key) = helpText + val prop = ( + if (key startsWith "java.") BooleanProp.valueIsTrue(key) + else BooleanProp.keyExists(key) + ) + propertyHelp(key) = helpText + prop } def help(key: String) = propertyHelp.getOrElse(key, "") diff --git a/src/partest/scala/tools/partest/SecurityTest.scala b/src/partest/scala/tools/partest/SecurityTest.scala new file mode 100644 index 0000000000..54aad5a625 --- /dev/null +++ b/src/partest/scala/tools/partest/SecurityTest.scala @@ -0,0 +1,32 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Paul Phillips + */ + +package scala.tools.partest + +import java.security._ +import java.util._ + +abstract class SecurityTest extends App { + def throwIt(x: Any) = throw new AccessControlException("" + x) + + def readPerm(p: PropertyPermission) = p.getActions contains "read" + def writePerm(p: PropertyPermission) = p.getActions contains "write" + def propertyCheck(p: PropertyPermission): Unit = throwIt(p) + + def check(perm: Permission): Unit = perm match { + case p: PropertyPermission => propertyCheck(p) + case _ => () + } + + lazy val sm = new SecurityManager { + // these two are the choke points for all permissions checks + override def checkPermission(perm: Permission): Unit = check(perm) + override def checkPermission(perm: Permission, context: Object): Unit = check(perm) + } + def securityOn(): Boolean = { + try { System.setSecurityManager(sm) ; true } + catch { case _: SecurityException => false } + } +} diff --git a/test/files/run/applet-prop.scala b/test/files/run/applet-prop.scala new file mode 100644 index 0000000000..fb112bf7d5 --- /dev/null +++ b/test/files/run/applet-prop.scala @@ -0,0 +1,40 @@ +import scala.tools.partest._ +import java.util.PropertyPermission +import java.security.AccessControlException + +class S extends javax.swing.JApplet { + scala.collection.Traversable +} + +object Test extends SecurityTest { + val s = new S + // lazy val TestKey = sys.SystemProperties.noTraceSupression.key + // def hitPerm() = new Throwable with scala.util.control.ControlThrowable { } + // + // var throwing = false + // override def propertyCheck(p: PropertyPermission): Unit = { + // if (p.getName == TestKey) { + // println("I see " + p.getName) + // if (throwing) + // throwIt(p) + // } + // } + // + // hitPerm() + // securityOn() + // hitPerm() + // + // throwing = true + // + // val caught = + // try { hitPerm() ; false } + // catch { case _: AccessControlException => true } + // + // assert(caught, "Should have incurred exception.") + // throwing = false + // hitPerm() + // + // val xs = new Traversable[Int] { def foreach[U](f: Int => U) = 1 to 3 foreach f } + // xs foreach println +} + diff --git a/test/files/run/sysprops.scala b/test/files/run/sysprops.scala index d3df22d634..bdad677221 100644 --- a/test/files/run/sysprops.scala +++ b/test/files/run/sysprops.scala @@ -5,7 +5,7 @@ object Test { val key = "ding.dong.doobie" def bool() = { - val prop = Prop.bool(key) + val prop = BooleanProp.valueIsTrue(key) assert(prop.key == key) prop.clear() diff --git a/test/files/specialized/test.scala b/test/files/specialized/test.scala index 54ef28d68a..bccc6f0f93 100644 --- a/test/files/specialized/test.scala +++ b/test/files/specialized/test.scala @@ -1,10 +1,9 @@ - - - object Test { - + // not sure exactly what this is enforcing, but it was failing on + // me due to some early boxing happening with the check for a + // stack trace suppression system property, so I boosted the count. def main(args: Array[String]) { - assert(runtime.BoxesRunTime.booleanBoxCount == 0) + assert(runtime.BoxesRunTime.booleanBoxCount < 10, + "Expected no more than 10 boolean boxings, found " + runtime.BoxesRunTime.booleanBoxCount) } - } |