src/Pure/System/isabelle_system.scala
changeset 75702 97e8f4c938bf
parent 75697 21c1f82e7f5d
child 76144 35a279a2d246
equal deleted inserted replaced
75701:84990c95712d 75702:97e8f4c938bf
    10 import java.util.{Map => JMap, HashMap}
    10 import java.util.{Map => JMap, HashMap}
    11 import java.io.{File => JFile, IOException}
    11 import java.io.{File => JFile, IOException}
    12 import java.nio.file.{Path => JPath, Files, SimpleFileVisitor, FileVisitResult,
    12 import java.nio.file.{Path => JPath, Files, SimpleFileVisitor, FileVisitResult,
    13   StandardCopyOption, FileSystemException}
    13   StandardCopyOption, FileSystemException}
    14 import java.nio.file.attribute.BasicFileAttributes
    14 import java.nio.file.attribute.BasicFileAttributes
    15 import java.net.URLClassLoader
       
    16 
       
    17 import scala.jdk.CollectionConverters._
       
    18 
    15 
    19 
    16 
    20 object Isabelle_System {
    17 object Isabelle_System {
    21   /* settings environment */
    18   /* settings environment */
    22 
    19 
    38       error("Undefined Isabelle environment variable: " + quote(name))
    35       error("Undefined Isabelle environment variable: " + quote(name))
    39 
    36 
    40 
    37 
    41   /* services */
    38   /* services */
    42 
    39 
    43   abstract class Service
    40   type Service = Classpath.Service
    44 
    41 
    45   @volatile private var _services: Option[List[Class[Service]]] = None
    42   @volatile private var _classpath: Option[Classpath] = None
    46 
    43 
    47   def services(): List[Class[Service]] = {
    44   def classpath(): Classpath = {
    48     if (_services.isEmpty) init()  // unsynchronized check
    45     if (_classpath.isEmpty) init()  // unsynchronized check
    49     _services.get
    46     _classpath.get
    50   }
    47   }
    51 
    48 
    52   def make_services[C](c: Class[C], more_services: List[Class[Service]] = Nil): List[C] =
    49   def make_services[C](c: Class[C]): List[C] = classpath().make_services(c)
    53     for { c1 <- services() ::: more_services if Library.is_subclass(c1, c) }
    50 
    54       yield c1.getDeclaredConstructor().newInstance().asInstanceOf[C]
    51 
    55 
    52   /* init settings + classpath */
    56   class Tmp_Loader private[Isabelle_System](tmp_jars: List[JFile], parent: ClassLoader)
       
    57     extends URLClassLoader(tmp_jars.map(_.toURI.toURL).toArray, parent) {
       
    58       override def finalize(): Unit = {
       
    59         for (tmp_jar <- tmp_jars) {
       
    60           try { tmp_jar.delete() }
       
    61           catch { case _: Throwable => }
       
    62         }
       
    63       }
       
    64     }
       
    65 
       
    66   def make_classloader(jars: List[File.Content_Bytes]): (List[JFile], ClassLoader) =
       
    67   {
       
    68     val default_classloader = Isabelle_System.getClass.getClassLoader
       
    69     if (jars.isEmpty) (Nil, default_classloader)
       
    70     else {
       
    71       val tmp_jars =
       
    72         for (jar <- jars) yield {
       
    73           val tmp_jar = tmp_file("jar", ext = "jar")
       
    74           Bytes.write(tmp_jar, jar.content)
       
    75           tmp_jar
       
    76         }
       
    77       (tmp_jars, new Tmp_Loader(tmp_jars, default_classloader))
       
    78     }
       
    79   }
       
    80 
       
    81 
       
    82   /* init settings + services */
       
    83 
       
    84   private def init_services(
       
    85     where: String, names: List[String], classloader: ClassLoader
       
    86   ): List[Class[Service]] = {
       
    87     for (name <- names) yield {
       
    88       def err(msg: String): Nothing =
       
    89         error("Bad Isabelle/Scala service " + quote(name) + " in " + where + "\n" + msg)
       
    90       try { Class.forName(name, true, classloader).asInstanceOf[Class[Service]] }
       
    91       catch {
       
    92         case _: ClassNotFoundException => err("Class not found")
       
    93         case exn: Throwable => err(Exn.message(exn))
       
    94       }
       
    95     }
       
    96   }
       
    97 
       
    98   def init_services_env(classloader: ClassLoader): List[Class[Service]] =
       
    99   {
       
   100     val variable = "ISABELLE_SCALA_SERVICES"
       
   101     init_services(quote(variable), space_explode(':', getenv_strict(variable)), classloader)
       
   102   }
       
   103 
       
   104   def init_services_jar(jar: Path, classloader: ClassLoader): List[Class[Service]] =
       
   105     init_services(jar.toString,
       
   106       isabelle.setup.Build.get_services(jar.java_path).asScala.toList, classloader)
       
   107 
    53 
   108   def init(isabelle_root: String = "", cygwin_root: String = ""): Unit = {
    54   def init(isabelle_root: String = "", cygwin_root: String = ""): Unit = {
   109     isabelle.setup.Environment.init(isabelle_root, cygwin_root)
    55     isabelle.setup.Environment.init(isabelle_root, cygwin_root)
   110     val (_, classloader) = make_classloader(Nil)
       
   111     synchronized {
    56     synchronized {
   112       if (_services.isEmpty) {
    57       if (_classpath.isEmpty) _classpath = Some(Classpath())
   113         _services =
       
   114           Some(init_services_env(classloader) :::
       
   115             Scala.get_classpath().flatMap(init_services_jar(_, classloader)))
       
   116       }
       
   117     }
    58     }
   118   }
    59   }
   119 
    60 
   120 
    61 
   121   /* getetc -- static distribution parameters */
    62   /* getetc -- static distribution parameters */