1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.util;
19
20 import java.io.File;
21 import java.io.IOException;
22 import java.net.MalformedURLException;
23 import java.net.URL;
24 import java.net.URLClassLoader;
25 import java.util.HashMap;
26
27 import org.apache.commons.logging.Log;
28 import org.apache.commons.logging.LogFactory;
29 import org.apache.hadoop.classification.InterfaceAudience;
30 import org.apache.hadoop.conf.Configuration;
31 import org.apache.hadoop.fs.FileStatus;
32 import org.apache.hadoop.fs.FileSystem;
33 import org.apache.hadoop.fs.Path;
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52 @InterfaceAudience.Private
53 public class DynamicClassLoader extends URLClassLoader {
54 private static final Log LOG =
55 LogFactory.getLog(DynamicClassLoader.class);
56
57
58 private static final String DYNAMIC_JARS_DIR = File.separator
59 + "dynamic" + File.separator + "jars" + File.separator;
60
61
62
63
64 private final ClassLoader parent;
65
66 private File localDir;
67
68
69 private FileSystem remoteDirFs;
70 private Path remoteDir;
71
72
73 private HashMap<String, Long> jarModifiedTime;
74
75
76
77
78
79
80
81
82 public DynamicClassLoader(
83 final Configuration conf, final ClassLoader parent) {
84 super(new URL[]{}, parent);
85 this.parent = parent;
86
87 jarModifiedTime = new HashMap<String, Long>();
88 String localDirPath = conf.get("hbase.local.dir") + DYNAMIC_JARS_DIR;
89 localDir = new File(localDirPath);
90 if (!localDir.mkdirs() && !localDir.isDirectory()) {
91 throw new RuntimeException("Failed to create local dir " + localDir.getPath()
92 + ", DynamicClassLoader failed to init");
93 }
94
95 String remotePath = conf.get("hbase.dynamic.jars.dir");
96 if (remotePath == null || remotePath.equals(localDirPath)) {
97 remoteDir = null;
98 } else {
99 remoteDir = new Path(remotePath);
100 try {
101 remoteDirFs = remoteDir.getFileSystem(conf);
102 } catch (IOException ioe) {
103 LOG.warn("Failed to identify the fs of dir "
104 + remoteDir + ", ignored", ioe);
105 remoteDir = null;
106 }
107 }
108 }
109
110 @Override
111 public Class<?> loadClass(String name)
112 throws ClassNotFoundException {
113 try {
114 return parent.loadClass(name);
115 } catch (ClassNotFoundException e) {
116 if (LOG.isDebugEnabled()) {
117 LOG.debug("Class " + name + " not found - using dynamical class loader");
118 }
119
120
121 Class<?> clasz = findLoadedClass(name);
122 if (clasz != null) {
123 if (LOG.isDebugEnabled()) {
124 LOG.debug("Class " + name + " already loaded");
125 }
126 }
127 else {
128 try {
129 if (LOG.isDebugEnabled()) {
130 LOG.debug("Finding class: " + name);
131 }
132 clasz = findClass(name);
133 } catch (ClassNotFoundException cnfe) {
134
135 if (LOG.isDebugEnabled()) {
136 LOG.debug("Loading new jar files, if any");
137 }
138 loadNewJars();
139
140 if (LOG.isDebugEnabled()) {
141 LOG.debug("Finding class again: " + name);
142 }
143 clasz = findClass(name);
144 }
145 }
146 return clasz;
147 }
148 }
149
150 private synchronized void loadNewJars() {
151
152 for (File file: localDir.listFiles()) {
153 String fileName = file.getName();
154 if (jarModifiedTime.containsKey(fileName)) {
155 continue;
156 }
157 if (file.isFile() && fileName.endsWith(".jar")) {
158 jarModifiedTime.put(fileName, Long.valueOf(file.lastModified()));
159 try {
160 URL url = file.toURI().toURL();
161 addURL(url);
162 } catch (MalformedURLException mue) {
163
164 LOG.warn("Failed to load new jar " + fileName, mue);
165 }
166 }
167 }
168
169
170 FileStatus[] statuses = null;
171 if (remoteDir != null) {
172 try {
173 statuses = remoteDirFs.listStatus(remoteDir);
174 } catch (IOException ioe) {
175 LOG.warn("Failed to check remote dir status " + remoteDir, ioe);
176 }
177 }
178 if (statuses == null || statuses.length == 0) {
179 return;
180 }
181
182 for (FileStatus status: statuses) {
183 if (status.isDir()) continue;
184 Path path = status.getPath();
185 String fileName = path.getName();
186 if (!fileName.endsWith(".jar")) {
187 if (LOG.isDebugEnabled()) {
188 LOG.debug("Ignored non-jar file " + fileName);
189 }
190 continue;
191 }
192 Long cachedLastModificationTime = jarModifiedTime.get(fileName);
193 if (cachedLastModificationTime != null) {
194 long lastModified = status.getModificationTime();
195 if (lastModified < cachedLastModificationTime.longValue()) {
196
197
198
199
200
201
202
203 continue;
204 }
205 }
206 try {
207
208 File dst = new File(localDir, fileName);
209 remoteDirFs.copyToLocalFile(path, new Path(dst.getPath()));
210 jarModifiedTime.put(fileName, Long.valueOf(dst.lastModified()));
211 URL url = dst.toURI().toURL();
212 addURL(url);
213 } catch (IOException ioe) {
214 LOG.warn("Failed to load new jar " + fileName, ioe);
215 }
216 }
217 }
218 }