| package org.apache.cassandra.triggers; |
| /* |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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. |
| * |
| */ |
| |
| |
| import java.io.File; |
| import java.io.FilenameFilter; |
| import java.io.IOError; |
| import java.io.IOException; |
| import java.net.URL; |
| import java.net.URLClassLoader; |
| import java.util.Map; |
| import java.util.concurrent.ConcurrentHashMap; |
| |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import com.google.common.io.Files; |
| |
| /** |
| * Custom class loader will load the classes from the class path, CCL will load |
| * the classes from the the URL first, if it cannot find the required class it |
| * will let the parent class loader do the its job. |
| * |
| * Note: If the CCL is GC'ed then the associated classes will be unloaded. |
| */ |
| public class CustomClassLoader extends URLClassLoader |
| { |
| private static final Logger logger = LoggerFactory.getLogger(CustomClassLoader.class); |
| private final Map<String, Class<?>> cache = new ConcurrentHashMap<String, Class<?>>(); |
| private final ClassLoader parent; |
| |
| public CustomClassLoader(ClassLoader parent) |
| { |
| super(new URL[] {}, parent); |
| assert parent != null; |
| this.parent = getParent(); |
| } |
| |
| public CustomClassLoader(ClassLoader parent, File classPathDir) |
| { |
| super(new URL[] {}, parent); |
| assert parent != null; |
| this.parent = getParent(); |
| addClassPath(classPathDir); |
| } |
| |
| public void addClassPath(File dir) |
| { |
| if (dir == null || !dir.exists()) |
| return; |
| FilenameFilter filter = new FilenameFilter() |
| { |
| public boolean accept(File dir, String name) |
| { |
| return name.endsWith(".jar"); |
| } |
| }; |
| for (File inputJar : dir.listFiles(filter)) |
| { |
| File lib = new File(System.getProperty("java.io.tmpdir"), "lib"); |
| if (!lib.exists()) |
| { |
| lib.mkdir(); |
| lib.deleteOnExit(); |
| } |
| try |
| { |
| File out = File.createTempFile("cassandra-", ".jar", lib); |
| out.deleteOnExit(); |
| logger.info("Loading new jar {}", inputJar.getAbsolutePath()); |
| Files.copy(inputJar, out); |
| addURL(out.toURI().toURL()); |
| } |
| catch (IOException ex) |
| { |
| throw new IOError(ex); |
| } |
| } |
| } |
| |
| @Override |
| public Class<?> loadClass(String name) throws ClassNotFoundException |
| { |
| Class<?> clazz = cache.get(name); |
| if (clazz == null) |
| return loadClassInternal(name); |
| return clazz; |
| } |
| |
| public synchronized Class<?> loadClassInternal(String name) throws ClassNotFoundException |
| { |
| try |
| { |
| return parent.loadClass(name); |
| } |
| catch (ClassNotFoundException ex) |
| { |
| logger.trace("Class not found using parent class loader,", ex); |
| // Don't throw the exception here, try triggers directory. |
| } |
| Class<?> clazz = this.findClass(name); |
| cache.put(name, clazz); |
| return clazz; |
| } |
| } |