1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *    http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package org.apache.spark.util
19
20import java.net.{URL, URLClassLoader}
21import java.util.Enumeration
22
23import scala.collection.JavaConverters._
24
25/**
26 * URL class loader that exposes the `addURL` and `getURLs` methods in URLClassLoader.
27 */
28private[spark] class MutableURLClassLoader(urls: Array[URL], parent: ClassLoader)
29  extends URLClassLoader(urls, parent) {
30
31  override def addURL(url: URL): Unit = {
32    super.addURL(url)
33  }
34
35  override def getURLs(): Array[URL] = {
36    super.getURLs()
37  }
38
39}
40
41/**
42 * A mutable class loader that gives preference to its own URLs over the parent class loader
43 * when loading classes and resources.
44 */
45private[spark] class ChildFirstURLClassLoader(urls: Array[URL], parent: ClassLoader)
46  extends MutableURLClassLoader(urls, null) {
47
48  private val parentClassLoader = new ParentClassLoader(parent)
49
50  override def loadClass(name: String, resolve: Boolean): Class[_] = {
51    try {
52      super.loadClass(name, resolve)
53    } catch {
54      case e: ClassNotFoundException =>
55        parentClassLoader.loadClass(name, resolve)
56    }
57  }
58
59  override def getResource(name: String): URL = {
60    val url = super.findResource(name)
61    val res = if (url != null) url else parentClassLoader.getResource(name)
62    res
63  }
64
65  override def getResources(name: String): Enumeration[URL] = {
66    val childUrls = super.findResources(name).asScala
67    val parentUrls = parentClassLoader.getResources(name).asScala
68    (childUrls ++ parentUrls).asJavaEnumeration
69  }
70
71  override def addURL(url: URL) {
72    super.addURL(url)
73  }
74
75}
76