/* * Copyright 2013 The Solmix Project * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.gnu.org/licenses/ * or see the FSF site: http://www.fsf.org. */ package org.solmix.runtime.extension; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.solmix.runtime.Container; /** * * @author solmix.f@gmail.com * @version $Id$ 2014年7月27日 */ public class ExtensionInfo { private static final Logger LOG = LoggerFactory.getLogger(ExtensionInfo.class); protected String className; protected ClassLoader classloader; protected Class<?> clazz; protected Class<?> intf; protected String interfaceName; protected boolean deferred; protected Collection<String> namespaces = new ArrayList<String>(); protected Object args[]; protected volatile Object obj; protected boolean optional; protected boolean notFound; /** * @param e */ public ExtensionInfo(ExtensionInfo 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; } /** * @param loader */ public ExtensionInfo(ClassLoader loader) { classloader = loader; } /** * */ public ExtensionInfo() { } /** * @param class1 */ public ExtensionInfo(Class<?> clazz) { this.clazz = clazz; className = clazz.getName(); classloader = clazz.getClassLoader(); } /** * @return */ public String getName() { /* return StringUtils.isEmpty(interfaceName) ? className : interfaceName;*/ return className; } /** * @return */ public ExtensionInfo cloneNoObject() { ExtensionInfo ext = new ExtensionInfo(this); ext.obj = null; ext.clazz = null; ext.intf = null; return ext; } public String getClassname() { return className; } public void setClassname(String i) { _setClassname(i); } private 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; } @Override public String toString() { StringBuilder buf = new StringBuilder(); buf.append("class: "); buf.append(className); buf.append(", interface: "); buf.append(interfaceName); buf.append(", interface: "); buf.append(interfaceName); 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(); } /** * @return */ public Object getLoadedObject() { return obj; } /** * @param loader * @return */ public Class<?> loadInterface(ClassLoader loader) { if (intf != null || notFound) { return intf; } intf = tryClass(interfaceName,loader); return intf; } 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) { if (origEx != null) { ex = origEx; } throw new ExtensionException( ex); } } } return null; } /** * @param loader * @return */ public Class<?> getClassObject(ClassLoader loader) { if (notFound) { return null; } if (clazz == null) { clazz = tryClass(className, loader); } return clazz; } /** * @param loader * @param container * @return */ public Object load(ClassLoader loader, Container container) { if (obj != null) { return obj; } Class<?> cls = getClassObject(loader); try { if (notFound) { return null; } try { //if there is a container constructor, use it. if (container != null && args == null) { Constructor<?> con = cls.getConstructor(Container.class); obj = con.newInstance(container); return obj; } else if (container != null && args != null) { Constructor<?> con; boolean noc = false; try { con = cls.getConstructor(Container.class, Object[].class); } catch (Exception ex) { con = cls.getConstructor(Object[].class); noc = true; } if (noc) { obj = con.newInstance(args); } else { obj = con.newInstance(container, 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("PROBLEM_CREATING_EXTENSION_CLASS", ex.getCause()); } catch (InstantiationException ex) { throw new ExtensionException("PROBLEM_CREATING_EXTENSION_CLASS", ex); } catch (SecurityException ex) { throw new ExtensionException("PROBLEM_CREATING_EXTENSION_CLASS", ex); } catch (NoSuchMethodException e) { //ignore } obj = cls.getConstructor().newInstance(); } catch (ExtensionException ex) { notFound = true; if (!optional) { throw ex; } else { LOG.info("Could not load optional extension " + getName(), ex); } } catch (InvocationTargetException ex) { notFound = true; if (!optional) { throw new ExtensionException("PROBLEM_CREATING_EXTENSION_CLASS",ex.getCause()); } else { LOG.info( "Could not load optional extension " + getName(), ex); } } catch (NoSuchMethodException ex) { notFound = true; List<Object> a = new ArrayList<Object>(); if (container != null) { a.add(container); } if (args != null) { a.add(args); } if (!optional) { throw new ExtensionException("PROBLEM_FINDING_CONSTRUCTOR", ex); } else { LOG.info("Could not load optional extension " + getName(), ex); } } catch (Throwable e) { notFound = true; if (!optional) { throw new ExtensionException("PROBLEM_CREATING_EXTENSION_CLASS", e); } else { LOG.info( "Could not load optional extension " + getName(), e); } } return obj; } public void setOptional(boolean b) { optional = b; } public boolean isOptional() { return optional; } }