blob: 61f8134f56eb13723902cc5b48b252ef2efa035c [file] [log] [blame]
/*
* 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.
*/
package org.apache.synapse.transport.utils.sslcert.adaptor;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.InputStream;
import java.util.Hashtable;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
/**
* The ParentLastClassLoader is needed because the OCSP/CRL feature for synapse uses a dependency
* jar from bouncyCastle version bcprov-jdk16-1.46.jar. Apache Rampart which is a synapse
* dependency for WS-Security also uses an older version of a bouncyCastle jar. The JVM loads the
* older version thus making OCSP/CRL feature fail to function. This is known as Jar Hell in java
* community. As a workaround, a Parent Last Class Loader is used to load the classes used by
* OCSP/CRL feature from the relevant jar files. The default class loader hierarchy in Java is
* Parent First. This custom ParentLastClassLoader overrides the default behaviour. If
* ParentLastClassLoader could not load a class it will delegate the job to the parent, the system
* class loader.
*/
public class ParentLastClassLoader extends ClassLoader {
//used to cache already defined classes
private static final Hashtable<String,Class> classes = new Hashtable<String,Class>();
private File[] jarFiles; // Jar files
public ParentLastClassLoader(ClassLoader parent) {
super(parent);
String libDir = System.getProperty("synapse.bcprov.lib");
if (libDir == null) {
libDir = "lib";
}
File dir = new File(libDir);
jarFiles = dir.listFiles(new FileFilter() {
public boolean accept(File f) {
return f.getName().startsWith("synapse-nhttp-transport") ||
f.getName().equals("bcprov-jdk15on-1.49.jar");
}
});
}
@Override
public Class<?> findClass(String name) throws ClassNotFoundException {
throw new ClassNotFoundException();
}
@Override
protected synchronized Class<?> loadClass(String className,
boolean resolve) throws ClassNotFoundException {
try {
byte classByte[];
Class result;
//checks in cached classes
result = classes.get(className);
if (result != null) {
return result;
}
for (File jarFile : jarFiles) {
try {
JarFile jar = new JarFile(jarFile);
JarEntry entry = jar.getJarEntry(className.replace(".", "/") + ".class");
InputStream is = jar.getInputStream(entry);
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
int nextValue = is.read();
while (-1 != nextValue) {
byteStream.write(nextValue);
nextValue = is.read();
}
classByte = byteStream.toByteArray();
result = defineClass(className, classByte, 0, classByte.length, null);
classes.put(className, result);
break;
} catch (Exception ignored) {}
}
if (result != null) {
return result;
} else {
throw new ClassNotFoundException("Not found " + className);
}
} catch (ClassNotFoundException e) {
// didn't find it, try the parent
return super.loadClass(className, resolve);
}
}
}