clarified management of services: static declarations vs. dynamic instances (e.g. relevant for stateful Session.Protocol_Handler, notably Scala.Handler and session "System");
authorwenzelm
Sun, 16 Aug 2020 11:57:15 +0200
changeset 72159 40b5ee5889d2
parent 72158 cafe00f2161e
child 72160 bb5c1992b442
child 72164 b7c54ff7f2dd
clarified management of services: static declarations vs. dynamic instances (e.g. relevant for stateful Session.Protocol_Handler, notably Scala.Handler and session "System");
src/Pure/PIDE/session.scala
src/Pure/System/isabelle_system.scala
src/Pure/System/isabelle_tool.scala
src/Pure/System/scala.scala
src/Pure/Thy/file_format.scala
--- a/src/Pure/PIDE/session.scala	Sat Aug 15 13:51:55 2020 +0200
+++ b/src/Pure/PIDE/session.scala	Sun Aug 16 11:57:15 2020 +0200
@@ -543,11 +543,8 @@
               prover.get.options(file_formats.prover_options(session_options))
               prover.get.init_session(resources)
 
-              Isabelle_System.services.foreach(
-                {
-                  case handler: Session.Protocol_Handler => init_protocol_handler(handler)
-                  case _ =>
-                })
+              Isabelle_System.make_services(classOf[Session.Protocol_Handler])
+                .foreach(init_protocol_handler)
 
               phase = Session.Ready
               debugger.ready()
--- a/src/Pure/System/isabelle_system.scala	Sat Aug 15 13:51:55 2020 +0200
+++ b/src/Pure/System/isabelle_system.scala	Sun Aug 16 11:57:15 2020 +0200
@@ -12,7 +12,7 @@
 import java.nio.file.{Path => JPath, Files, SimpleFileVisitor, FileVisitResult}
 import java.nio.file.attribute.BasicFileAttributes
 
-import scala.collection.mutable
+import scala.annotation.tailrec
 
 
 object Isabelle_System
@@ -49,7 +49,7 @@
   abstract class Service
 
   @volatile private var _settings: Option[Map[String, String]] = None
-  @volatile private var _services: Option[List[Service]] = None
+  @volatile private var _services: Option[List[Class[Service]]] = None
 
   def settings(): Map[String, String] =
   {
@@ -57,12 +57,26 @@
     _settings.get
   }
 
-  def services(): List[Service] =
+  def services(): List[Class[Service]] =
   {
     if (_services.isEmpty) init()  // unsynchronized check
     _services.get
   }
 
+  def make_services[C](c: Class[C]): List[C] =
+  {
+    @tailrec def is_subclass(c1: Class[_]): Boolean =
+    {
+      c1 == c ||
+      {
+        val c2 = c1.getSuperclass
+        c2 != null && is_subclass(c2)
+      }
+    }
+    for { c1 <- services() if is_subclass(c1) }
+      yield c1.getDeclaredConstructor().newInstance().asInstanceOf[C]
+  }
+
   def init(isabelle_root: String = "", cygwin_root: String = ""): Unit = synchronized
   {
     if (_settings.isEmpty || _services.isEmpty) {
@@ -141,10 +155,7 @@
         yield {
           def err(msg: String): Nothing =
             error("Bad entry " + quote(name) + " in " + variable + "\n" + msg)
-          try {
-            Class.forName(name).asInstanceOf[Class[Service]]
-              .getDeclaredConstructor().newInstance()
-          }
+          try { Class.forName(name).asInstanceOf[Class[Service]] }
           catch {
             case _: ClassNotFoundException => err("Class not found")
             case exn: Throwable => err(Exn.message(exn))
--- a/src/Pure/System/isabelle_tool.scala	Sat Aug 15 13:51:55 2020 +0200
+++ b/src/Pure/System/isabelle_tool.scala	Sun Aug 16 11:57:15 2020 +0200
@@ -98,7 +98,7 @@
   /* internal tools */
 
   private lazy val internal_tools: List[Isabelle_Tool] =
-    Isabelle_System.services.collect { case c: Isabelle_Scala_Tools => c.tools.toList }.flatten
+    Isabelle_System.make_services(classOf[Isabelle_Scala_Tools]).flatMap(_.tools)
 
   private def list_internal(): List[(String, String)] =
     for (tool <- internal_tools.toList)
--- a/src/Pure/System/scala.scala	Sat Aug 15 13:51:55 2020 +0200
+++ b/src/Pure/System/scala.scala	Sun Aug 16 11:57:15 2020 +0200
@@ -117,7 +117,7 @@
   }
 
   lazy val functions: List[Fun] =
-    Isabelle_System.services.collect { case c: Isabelle_Scala_Functions => c.functions.toList }.flatten
+    Isabelle_System.make_services(classOf[Isabelle_Scala_Functions]).flatMap(_.functions)
 
 
   /* invoke function */
--- a/src/Pure/Thy/file_format.scala	Sat Aug 15 13:51:55 2020 +0200
+++ b/src/Pure/Thy/file_format.scala	Sun Aug 16 11:57:15 2020 +0200
@@ -15,7 +15,7 @@
   /* registry */
 
   lazy val registry: Registry =
-    new Registry(Isabelle_System.services.collect { case c: File_Format => c })
+    new Registry(Isabelle_System.make_services(classOf[File_Format]))
 
   final class Registry private [File_Format](file_formats: List[File_Format])
   {
@@ -53,7 +53,7 @@
   object No_Agent extends Agent
 }
 
-trait File_Format extends Isabelle_System.Service
+abstract class File_Format extends Isabelle_System.Service
 {
   def format_name: String
   override def toString: String = "File_Format(" + format_name + ")"