summaryrefslogtreecommitdiff
path: root/examples/scala-js/sbt-plugin/src/main/scala/scala/scalajs/sbtplugin/env/phantomjs/PhantomJettyClassLoader.scala
diff options
context:
space:
mode:
Diffstat (limited to 'examples/scala-js/sbt-plugin/src/main/scala/scala/scalajs/sbtplugin/env/phantomjs/PhantomJettyClassLoader.scala')
-rw-r--r--examples/scala-js/sbt-plugin/src/main/scala/scala/scalajs/sbtplugin/env/phantomjs/PhantomJettyClassLoader.scala63
1 files changed, 63 insertions, 0 deletions
diff --git a/examples/scala-js/sbt-plugin/src/main/scala/scala/scalajs/sbtplugin/env/phantomjs/PhantomJettyClassLoader.scala b/examples/scala-js/sbt-plugin/src/main/scala/scala/scalajs/sbtplugin/env/phantomjs/PhantomJettyClassLoader.scala
new file mode 100644
index 0000000..02c229b
--- /dev/null
+++ b/examples/scala-js/sbt-plugin/src/main/scala/scala/scalajs/sbtplugin/env/phantomjs/PhantomJettyClassLoader.scala
@@ -0,0 +1,63 @@
+package scala.scalajs.sbtplugin.env.phantomjs
+
+import scala.scalajs.tools.io.IO
+
+/** A special [[ClassLoader]] to load the Jetty 8 dependency of [[PhantomJSEnv]]
+ * in a private space.
+ *
+ * It loads everything that belongs to [[JettyWebsocketManager]] itself (while
+ * retrieving the requested class file from its parent.
+ * For all other classes, it first tries to load them from [[jettyLoader]],
+ * which should only contain the Jetty 8 classpath.
+ * If this fails, it delegates to its parent.
+ *
+ * The rationale is, that [[JettyWebsocketManager]] and its dependees can use
+ * the classes on the Jetty 8 classpath, while they remain hidden from the rest
+ * of the Java world. This allows to load another version of Jetty in the same
+ * JVM for the rest of the project.
+ */
+private[sbtplugin] class PhantomJettyClassLoader(jettyLoader: ClassLoader,
+ parent: ClassLoader) extends ClassLoader(parent) {
+
+ def this(loader: ClassLoader) =
+ this(loader, ClassLoader.getSystemClassLoader())
+
+ /** Classes needed to bridge private jetty classpath and public PhantomJS
+ * Basically everything defined in JettyWebsocketManager.
+ */
+ private val bridgeClasses = Set(
+ "scala.scalajs.sbtplugin.env.phantomjs.JettyWebsocketManager",
+ "scala.scalajs.sbtplugin.env.phantomjs.JettyWebsocketManager$WSLogger",
+ "scala.scalajs.sbtplugin.env.phantomjs.JettyWebsocketManager$ComWebSocketListener",
+ "scala.scalajs.sbtplugin.env.phantomjs.JettyWebsocketManager$$anon$1",
+ "scala.scalajs.sbtplugin.env.phantomjs.JettyWebsocketManager$$anon$2"
+ )
+
+ override protected def loadClass(name: String, resolve: Boolean): Class[_] = {
+ if (bridgeClasses.contains(name)) {
+ // Load bridgeClasses manually since they must be associated to this
+ // class loader, rather than the parent class loader in order to find the
+ // jetty classes
+
+ // First check if we have loaded it already
+ Option(findLoadedClass(name)) getOrElse {
+ val wsManager =
+ parent.getResourceAsStream(name.replace('.', '/') + ".class")
+
+ if (wsManager == null) {
+ throw new ClassNotFoundException(name)
+ } else {
+ val buf = IO.readInputStreamToByteArray(wsManager)
+ defineClass(name, buf, 0, buf.length)
+ }
+ }
+ } else {
+ try {
+ jettyLoader.loadClass(name)
+ } catch {
+ case _: ClassNotFoundException =>
+ super.loadClass(name, resolve)
+ }
+ }
+ }
+}