forked from ACINQ/eclair
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPlugin.scala
67 lines (53 loc) · 2.18 KB
/
Plugin.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
/*
* Copyright 2019 ACINQ SAS
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package fr.acinq.eclair
import java.io.File
import java.net.{JarURLConnection, URL, URLClassLoader}
import akka.http.scaladsl.server.Route
import fr.acinq.eclair.api.directives.EclairDirectives
import grizzled.slf4j.Logging
import scala.util.{Failure, Success, Try}
trait Plugin {
def params: PluginParams
def onSetup(setup: Setup): Unit
def onKit(kit: Kit): Unit
}
trait RouteProvider {
def route(directives: EclairDirectives): Route
}
object Plugin extends Logging {
/**
* The files passed to this function must be jars containing a manifest entry for "Main-Class" with the
* FQDN of the entry point of the plugin. The entry point is the implementation of the interface "fr.acinq.eclair.Plugin"
* @param jars
* @return
*/
def loadPlugins(jars: Seq[File]): Seq[Plugin] = {
val urls = jars.flatMap(openJar)
val loader = new URLClassLoader(urls.map(_.getJarFileURL).toArray, ClassLoader.getSystemClassLoader)
val pluginClasses = urls
.flatMap(j => Option(j.getMainAttributes.getValue("Main-Class")))
.flatMap(classFQDN => Try[Class[_]](loader.loadClass(classFQDN)).toOption)
.flatMap(c => Try(c.getDeclaredConstructor().newInstance().asInstanceOf[Plugin]).toOption)
logger.info(s"loading ${pluginClasses.size} plugins")
pluginClasses
}
def openJar(jar: File): Option[JarURLConnection] =
Try(new URL(s"jar:file:${jar.getCanonicalPath}!/").openConnection().asInstanceOf[JarURLConnection]) match {
case Success(url) => Some(url)
case Failure(t) => logger.error(s"unable to load plugin file:${jar.getAbsolutePath} ", t); None
}
}