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 =
|
|
32 |
jar_files.flatMap(start => File.find_files(start, _.getName.endsWith(".jar")))
|
|
33 |
.map(File.absolute)
|
|
34 |
|
|
35 |
val tmp_jars =
|
|
36 |
for (jar <- jar_contents) yield {
|
|
37 |
val tmp_jar = Files.createTempFile("jar", "jar").toFile
|
|
38 |
tmp_jar.deleteOnExit()
|
|
39 |
Bytes.write(tmp_jar, jar.content)
|
|
40 |
tmp_jar
|
|
41 |
}
|
|
42 |
new Classpath(jar_files0 ::: jar_files1, tmp_jars)
|
|
43 |
}
|
|
44 |
}
|
|
45 |
|
|
46 |
class Classpath private(static_jars: List[JFile], dynamic_jars: List[JFile]) {
|
|
47 |
def jars: List[JFile] = static_jars ::: dynamic_jars
|
|
48 |
override def toString: String = jars.mkString("Classpath(", ", ", ")")
|
|
49 |
|
|
50 |
def platform_path: String = jars.map(_.getPath).mkString(JFile.pathSeparator)
|
|
51 |
|
75704
|
52 |
val class_loader: ClassLoader =
|
75702
|
53 |
{
|
75704
|
54 |
val this_class_loader = this.getClass.getClassLoader
|
|
55 |
if (dynamic_jars.isEmpty) this_class_loader
|
75702
|
56 |
else {
|
75704
|
57 |
new URLClassLoader(dynamic_jars.map(File.url).toArray, this_class_loader) {
|
75702
|
58 |
override def finalize(): Unit = {
|
|
59 |
for (jar <- dynamic_jars) {
|
|
60 |
try { jar.delete() }
|
|
61 |
catch { case _: Throwable => }
|
|
62 |
}
|
|
63 |
}
|
|
64 |
}
|
|
65 |
}
|
|
66 |
}
|
|
67 |
|
|
68 |
private def init_services(where: String, names: List[String]): List[Classpath.Service_Class] = {
|
|
69 |
for (name <- names) yield {
|
|
70 |
def err(msg: String): Nothing =
|
|
71 |
error("Bad Isabelle/Scala service " + quote(name) + " in " + where + "\n" + msg)
|
75704
|
72 |
try { Class.forName(name, true, class_loader).asInstanceOf[Classpath.Service_Class] }
|
75702
|
73 |
catch {
|
|
74 |
case _: ClassNotFoundException => err("Class not found")
|
|
75 |
case exn: Throwable => err(Exn.message(exn))
|
|
76 |
}
|
|
77 |
}
|
|
78 |
}
|
|
79 |
|
|
80 |
val services: List[Classpath.Service_Class] =
|
|
81 |
{
|
|
82 |
val variable = "ISABELLE_SCALA_SERVICES"
|
|
83 |
val services_env =
|
|
84 |
init_services(quote(variable), space_explode(':', Isabelle_System.getenv_strict(variable)))
|
|
85 |
val services_jars =
|
|
86 |
jars.flatMap(jar =>
|
|
87 |
init_services(File.standard_path(jar),
|
|
88 |
isabelle.setup.Build.get_services(jar.toPath).asScala.toList))
|
|
89 |
services_env ::: services_jars
|
|
90 |
}
|
|
91 |
|
|
92 |
def make_services[C](c: Class[C]): List[C] =
|
|
93 |
for { c1 <- services if Library.is_subclass(c1, c) }
|
|
94 |
yield c1.getDeclaredConstructor().newInstance().asInstanceOf[C]
|
|
95 |
}
|