author | wenzelm |
Sun, 18 Feb 2024 12:33:43 +0100 | |
changeset 79659 | a4118f530263 |
parent 76527 | 63f9ffa1625f |
child 80300 | 152d6c58adb3 |
permissions | -rw-r--r-- |
75702 | 1 |
/* Title: Pure/System/classpath.scala |
2 |
Author: Makarius |
|
3 |
||
4 |
Java classpath and Scala services. |
|
5 |
*/ |
|
6 |
||
7 |
package isabelle |
|
8 |
||
9 |
||
10 |
import java.io.{File => JFile} |
|
11 |
import java.nio.file.Files |
|
12 |
import java.net.URLClassLoader |
|
13 |
||
14 |
import scala.jdk.CollectionConverters._ |
|
15 |
||
16 |
||
17 |
object Classpath { |
|
18 |
abstract class Service |
|
19 |
type Service_Class = Class[Service] |
|
20 |
||
21 |
def apply( |
|
22 |
jar_files: List[JFile] = Nil, |
|
75825 | 23 |
jar_contents: List[File.Content] = Nil): Classpath = |
75702 | 24 |
{ |
25 |
val jar_files0 = |
|
26 |
for { |
|
27 |
s <- space_explode(JFile.pathSeparatorChar, System.getProperty("java.class.path", "")) |
|
28 |
if s.nonEmpty |
|
75703 | 29 |
} yield File.absolute(new JFile(s)) |
75702 | 30 |
|
31 |
val jar_files1 = |
|
76527 | 32 |
jar_files.flatMap(start => |
33 |
File.find_files(start, file => File.is_jar(file.getName)).sortBy(_.getName)) |
|
75702 | 34 |
.map(File.absolute) |
35 |
||
36 |
val tmp_jars = |
|
37 |
for (jar <- jar_contents) yield { |
|
38 |
val tmp_jar = Files.createTempFile("jar", "jar").toFile |
|
39 |
tmp_jar.deleteOnExit() |
|
40 |
Bytes.write(tmp_jar, jar.content) |
|
41 |
tmp_jar |
|
42 |
} |
|
43 |
new Classpath(jar_files0 ::: jar_files1, tmp_jars) |
|
44 |
} |
|
45 |
} |
|
46 |
||
47 |
class Classpath private(static_jars: List[JFile], dynamic_jars: List[JFile]) { |
|
48 |
def jars: List[JFile] = static_jars ::: dynamic_jars |
|
49 |
override def toString: String = jars.mkString("Classpath(", ", ", ")") |
|
50 |
||
51 |
def platform_path: String = jars.map(_.getPath).mkString(JFile.pathSeparator) |
|
52 |
||
75704 | 53 |
val class_loader: ClassLoader = |
75702 | 54 |
{ |
75704 | 55 |
val this_class_loader = this.getClass.getClassLoader |
56 |
if (dynamic_jars.isEmpty) this_class_loader |
|
75702 | 57 |
else { |
79659
a4118f530263
clarified signature: avoid ill-defined type java.net.URL;
wenzelm
parents:
76527
diff
changeset
|
58 |
val dynamic_jars_url = dynamic_jars.map(file => File.url(file).java_url) |
a4118f530263
clarified signature: avoid ill-defined type java.net.URL;
wenzelm
parents:
76527
diff
changeset
|
59 |
new URLClassLoader(dynamic_jars_url.toArray, this_class_loader) { |
75702 | 60 |
override def finalize(): Unit = { |
61 |
for (jar <- dynamic_jars) { |
|
62 |
try { jar.delete() } |
|
63 |
catch { case _: Throwable => } |
|
64 |
} |
|
65 |
} |
|
66 |
} |
|
67 |
} |
|
68 |
} |
|
69 |
||
70 |
private def init_services(where: String, names: List[String]): List[Classpath.Service_Class] = { |
|
71 |
for (name <- names) yield { |
|
72 |
def err(msg: String): Nothing = |
|
73 |
error("Bad Isabelle/Scala service " + quote(name) + " in " + where + "\n" + msg) |
|
75704 | 74 |
try { Class.forName(name, true, class_loader).asInstanceOf[Classpath.Service_Class] } |
75702 | 75 |
catch { |
76 |
case _: ClassNotFoundException => err("Class not found") |
|
77 |
case exn: Throwable => err(Exn.message(exn)) |
|
78 |
} |
|
79 |
} |
|
80 |
} |
|
81 |
||
82 |
val services: List[Classpath.Service_Class] = |
|
83 |
{ |
|
84 |
val variable = "ISABELLE_SCALA_SERVICES" |
|
85 |
val services_env = |
|
86 |
init_services(quote(variable), space_explode(':', Isabelle_System.getenv_strict(variable))) |
|
87 |
val services_jars = |
|
88 |
jars.flatMap(jar => |
|
89 |
init_services(File.standard_path(jar), |
|
90 |
isabelle.setup.Build.get_services(jar.toPath).asScala.toList)) |
|
91 |
services_env ::: services_jars |
|
92 |
} |
|
93 |
||
94 |
def make_services[C](c: Class[C]): List[C] = |
|
95 |
for { c1 <- services if Library.is_subclass(c1, c) } |
|
96 |
yield c1.getDeclaredConstructor().newInstance().asInstanceOf[C] |
|
97 |
} |