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 */ |