/* * Copyright 2009-2012 by KNURT Systeme (http://www.knurt.de) * * Licensed under the Creative Commons License Attribution-NonCommercial-ShareAlike 3.0 Unported; * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://creativecommons.org/licenses/by-nc-sa/3.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 de.knurt.fam.plugin; import java.io.File; import java.io.IOException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarFile; import org.apache.commons.digester.plugins.PluginConfigurationException; import de.knurt.fam.connector.FamConnector; import de.knurt.fam.core.aspects.logging.FamLog; /** * resolve loading plugins and support interfaces to set specific behaviour. * * @author Daniel Oltmanns <info@knurt.de> * @since 1.3.0 (10/09/2010) */ public class DefaultPluginResolver implements PluginResolver { private RegisterSubmission registerSubmission = null; private List<Plugin> plugins = new ArrayList<Plugin>(); public List<Plugin> getPlugins() { return plugins; } /** {@inheritDoc} */ @Override public RegisterSubmission getRegisterSubmission() { return this.registerSubmission; } private boolean implementz(Class<?> clazz, Class<?> interfaze) { return this.implementz(clazz, interfaze.getName()); } private boolean implementz(Class<?> clazz, String interfaceName) { boolean result = false; Class<?>[] interfaces = clazz.getInterfaces(); for (Class<?> interfaze : interfaces) { if (interfaze.getName().equals(interfaceName)) { result = true; break; } } return result; } private boolean isPlugin(Class<?> cl) { return this.implementz(cl, Plugin.class); } /** {@inheritDoc} */ @Override protected void finalize() throws Throwable { for (Plugin plugin : this.plugins) { plugin.stop(); } } /** one and only instance of DefaultPluginResolver */ private volatile static DefaultPluginResolver me; /** construct DefaultPluginResolver */ private DefaultPluginResolver() { this.initPlugins(); } private void initPlugins() { File pluginDirectory = new File(FamConnector.me().getPluginDirectory()); if (pluginDirectory.exists() && pluginDirectory.isDirectory() && pluginDirectory.canRead()) { File[] files = pluginDirectory.listFiles(); ClassLoader currentThreadClassLoader = Thread.currentThread().getContextClassLoader(); for (File file : files) { if (file.isFile() && file.getName().toLowerCase().endsWith("jar")) { JarFile jar = null; try { jar = new JarFile(file.getAbsoluteFile().toString()); Enumeration<JarEntry> jarEntries = jar.entries(); while (jarEntries.hasMoreElements()) { JarEntry entry = jarEntries.nextElement(); if (entry.getName().toLowerCase().endsWith("class")) { String className = entry.getName().replaceAll("/", ".").replaceAll("\\.class$", ""); // @SuppressWarnings("resource") // classLoader must not be closed, getting an "IllegalStateException: zip file closed" otherwise URLClassLoader classLoader = new URLClassLoader(new URL[] { file.toURI().toURL() }, currentThreadClassLoader); Class<?> cl = classLoader.loadClass(className); if (this.isPlugin(cl)) { Plugin plugin = (Plugin) cl.newInstance(); this.plugins.add(plugin); } } } } catch (IllegalAccessException e) { e.printStackTrace(); FamLog.logException(this.getClass(), e, "failed to load plugin", 201010091426l); } catch (InstantiationException e) { e.printStackTrace(); FamLog.logException(this.getClass(), e, "failed to load plugin", 201010091424l); } catch (ClassNotFoundException e) { e.printStackTrace(); FamLog.logException(this.getClass(), e, "failed to load plugin", 201010091425l); } catch (IOException e) { e.printStackTrace(); FamLog.logException(this.getClass(), e, "failed to load plugin", 201010091351l); } finally { try { jar.close(); } catch (Exception e) { } } } } for (Plugin plugin : this.plugins) { boolean found = false; if (this.implementz(plugin.getClass(), RegisterSubmission.class)) { if (found == true) { throw new PluginConfigurationException("Found more than one RegisterSubmission classes"); // TODO #19 supply a solution Ticket } this.registerSubmission = (RegisterSubmission) plugin; found = true; } } for (Plugin plugin : this.plugins) { plugin.start(); } } // search plugin if (this.registerSubmission == null) { this.registerSubmission = new DefaultRegisterSubmission(); } } /** * return the one and only instance of DefaultPluginResolver * * @return the one and only instance of DefaultPluginResolver */ public static DefaultPluginResolver getInstance() { if (me == null) { // ↖ no instance so far synchronized (DefaultPluginResolver.class) { if (me == null) { // ↖ still no instance so far // ↓ the one and only me me = new DefaultPluginResolver(); } } } return me; } /** * short for {@link #getInstance()} * * @return the one and only instance of DefaultPluginResolver */ public static DefaultPluginResolver me() { return getInstance(); } /** * init plugins as far as it is not initialized by now */ public static void init() { getInstance(); } }