blob: 03f0dc6192c06be5ab72bb7303177f4fe3a5a9a1 [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.cxf.bus.extension;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.cxf.Bus;
import org.apache.cxf.common.i18n.Message;
import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.common.util.StringUtils;
public class Extension {
protected static final Logger LOG = LogUtils.getL7dLogger(Extension.class);
private static final String PROBLEM_CREATING_EXTENSION_CLASS = "PROBLEM_CREATING_EXTENSION_CLASS";
protected String className;
protected ClassLoader classloader;
protected volatile Class<?> clazz;
protected volatile Class<?> intf;
protected String interfaceName;
protected boolean deferred;
protected Collection<String> namespaces = new ArrayList<>();
protected Object[] args;
protected volatile Object obj;
protected boolean optional;
protected boolean notFound;
public Extension() {
}
public Extension(Class<?> cls, Class<?> inf) {
clazz = cls;
intf = inf;
interfaceName = inf.getName();
className = cls.getName();
classloader = cls.getClassLoader();
}
public Extension(Class<?> cls) {
clazz = cls;
className = cls.getName();
classloader = cls.getClassLoader();
}
public Extension(ClassLoader loader) {
classloader = loader;
}
public Extension(Extension ext) {
className = ext.className;
interfaceName = ext.interfaceName;
deferred = ext.deferred;
namespaces = ext.namespaces;
obj = ext.obj;
clazz = ext.clazz;
intf = ext.intf;
classloader = ext.classloader;
args = ext.args;
optional = ext.optional;
}
public void setOptional(boolean b) {
optional = b;
}
public boolean isOptional() {
return optional;
}
public String getName() {
return StringUtils.isEmpty(interfaceName) ? className : interfaceName;
}
public Object getLoadedObject() {
return obj;
}
public Extension cloneNoObject() {
Extension ext = new Extension(this);
ext.obj = null;
ext.clazz = null;
ext.intf = null;
return ext;
}
public String toString() {
StringBuilder buf = new StringBuilder(128);
buf.append("class: ");
buf.append(className);
buf.append(", interface: ");
buf.append(interfaceName);
buf.append(", deferred: ");
buf.append(deferred ? "true" : "false");
buf.append(", namespaces: (");
int n = 0;
for (String ns : namespaces) {
if (n > 0) {
buf.append(", ");
}
buf.append(ns);
n++;
}
buf.append(')');
return buf.toString();
}
public String getClassname() {
return className;
}
public void setClassname(String i) {
clazz = null;
notFound = false;
className = i;
}
public String getInterfaceName() {
return interfaceName;
}
public void setInterfaceName(String i) {
interfaceName = i;
notFound = false;
}
public boolean isDeferred() {
return deferred;
}
public void setDeferred(boolean d) {
deferred = d;
}
public Collection<String> getNamespaces() {
return namespaces;
}
public void setArgs(Object[] a) {
args = a;
}
protected Class<?> tryClass(String name, ClassLoader cl) {
Throwable origEx = null;
if (classloader != null) {
try {
return classloader.loadClass(name);
} catch (Throwable nex) {
//ignore, fall into the stuff below
//save the exception though as this is likely the important one
origEx = nex;
}
}
try {
return cl.loadClass(name);
} catch (Throwable ex) {
try {
// using the extension classloader as a fallback
return this.getClass().getClassLoader().loadClass(name);
} catch (Throwable nex) {
notFound = true;
if (!optional) {
throw new ExtensionException(new Message("PROBLEM_LOADING_EXTENSION_CLASS", LOG, name),
origEx != null ? origEx : ex);
}
}
}
return null;
}
public Class<?> getClassObject(ClassLoader cl) {
if (notFound) {
return null;
}
if (clazz != null) {
return clazz;
}
synchronized (this) {
if (clazz == null) {
clazz = tryClass(className, cl);
}
}
return clazz;
}
public Object load(ClassLoader cl, Bus b) {
if (obj != null) {
return obj;
}
Class<?> cls = getClassObject(cl);
try {
if (notFound) {
return null;
}
try {
//if there is a Bus constructor, use it.
if (b != null && args == null) {
Constructor<?> con = cls.getConstructor(Bus.class);
obj = con.newInstance(b);
return obj;
} else if (b != null && args != null) {
try {
obj = cls.getConstructor(Bus.class, Object[].class).newInstance(b, args);
} catch (NoSuchMethodException ex) { // no bus
obj = cls.getConstructor(Object[].class).newInstance(args);
}
return obj;
} else if (args != null) {
Constructor<?> con = cls.getConstructor(Object[].class);
obj = con.newInstance(args);
return obj;
}
} catch (InvocationTargetException ex) {
throw new ExtensionException(new Message(PROBLEM_CREATING_EXTENSION_CLASS, LOG, cls.getName()),
ex.getCause());
} catch (InstantiationException | SecurityException ex) {
throw new ExtensionException(new Message(PROBLEM_CREATING_EXTENSION_CLASS, LOG, cls.getName()), ex);
} catch (NoSuchMethodException e) {
//ignore
}
obj = cls.getConstructor().newInstance();
} catch (ExtensionException ex) {
notFound = true;
if (!optional) {
throw ex;
}
LOG.log(Level.FINE, "Could not load optional extension " + getName(), ex);
} catch (InvocationTargetException ex) {
notFound = true;
if (!optional) {
throw new ExtensionException(new Message(PROBLEM_CREATING_EXTENSION_CLASS, LOG, cls.getName()),
ex.getCause());
}
LOG.log(Level.FINE, "Could not load optional extension " + getName(), ex);
} catch (NoSuchMethodException ex) {
notFound = true;
List<Object> a = new ArrayList<>();
if (b != null) {
a.add(b);
}
if (args != null) {
a.add(args);
}
if (!optional) {
throw new ExtensionException(new Message("PROBLEM_FINDING_CONSTRUCTOR", LOG,
cls.getName(), a), ex);
}
LOG.log(Level.FINE, "Could not load optional extension " + getName(), ex);
} catch (Throwable e) {
notFound = true;
if (!optional) {
throw new ExtensionException(new Message(PROBLEM_CREATING_EXTENSION_CLASS, LOG, cls.getName()), e);
}
LOG.log(Level.FINE, "Could not load optional extension " + getName(), e);
}
return obj;
}
public Class<?> loadInterface(ClassLoader cl) {
if (intf != null || notFound) {
return intf;
}
synchronized (this) {
if (intf == null) {
intf = tryClass(interfaceName, cl);
}
}
return intf;
}
}