/* * Copyright (C) 2000 - 2012 TagServlet Ltd * * This file is part of Open BlueDragon (OpenBD) CFML Server Engine. * * OpenBD is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * Free Software Foundation,version 3. * * OpenBD 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenBD. If not, see http://www.gnu.org/licenses/ * * Additional permission under GNU GPL version 3 section 7 * * If you modify this Program, or any covered work, by linking or combining * it with any of the JARS listed in the README.txt (or a modified version of * (that library), containing parts covered by the terms of that JAR, the * licensors of this Program grant you additional permission to convey the * resulting work. * README.txt @ http://www.openbluedragon.org/license/README.txt * * http://openbd.org/ * $Id: PluginManager.java 2147 2012-07-02 01:57:34Z alan $ */ /* * Created on 03-Feb-2005, 22-Sep-2009 * * This is the main Plugin Manager class that is used as a bridge for managing * new plugins in the BlueDragon tree. * * To create a plugin, you must: * * - Implement the PlugIn interface, naming your class xyxPlugIn * - Optionally, package up your Plugin in a JAR file named: openbdplugin-xyz.jar * * It will be auto-discovered on startup */ package com.bluedragon.plugin; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.jar.JarEntry; import java.util.jar.JarInputStream; import com.naryx.tagfusion.cfm.engine.cfComponentData; import com.naryx.tagfusion.cfm.engine.cfData; import com.naryx.tagfusion.cfm.engine.cfEngine; import com.naryx.tagfusion.cfm.engine.cfSession; import com.naryx.tagfusion.cfm.engine.cfmBadFileException; import com.naryx.tagfusion.cfm.engine.cfmRunTimeException; import com.naryx.tagfusion.cfm.engine.engineListener; import com.naryx.tagfusion.cfm.tag.cfSCRIPT; import com.naryx.tagfusion.expression.compile.expressionEngine; import com.naryx.tagfusion.util.dummyServletRequest; import com.naryx.tagfusion.util.dummyServletResponse; import com.naryx.tagfusion.xmlConfig.xmlCFML; public class PluginManager implements PluginManagerInterface, RequestListener { private static PluginManagerInterface thisInst; private List<Plugin> listOfPlugins; private List<RequestListener> listOfRequestListeners; private Set<String> filesSet; private boolean bOverrideCore = true; public PluginManager(xmlCFML systemParameters) { thisInst = this; listOfPlugins = new ArrayList<Plugin>(); listOfRequestListeners = new ArrayList<RequestListener>(); filesSet = new HashSet<String>(); // Load in the standard plugins log("PlugInManager: Loading Standard Plugins" ); loadPlugIn("org.alanwilliamson.openbd.plugin.spreadsheet.SpreadSheetExtension", systemParameters); loadPlugIn("org.alanwilliamson.openbd.plugin.cfsmtp.SmtpExtension", systemParameters); loadPlugIn("org.aw20.plugin.login.LoginExtension", systemParameters); loadPlugIn("org.alanwilliamson.openbd.plugin.crontab.CronExtension", systemParameters); loadPlugIn("com.bluedragon.mongo.MongoExtension", systemParameters); loadPlugIn("org.alanwilliamson.openbd.plugin.salesforce.SalesForceExtension", systemParameters); loadPlugIn("com.bluedragon.vision.VisionExtension", systemParameters); loadPlugIn("com.bluedragon.profiler.ProfilerExtension", systemParameters); int standardCount = listOfPlugins.size(); log("PlugInManager: Standard Plugins=" + standardCount ); // Look at the flag if we can override the function bOverrideCore = systemParameters.getBoolean("server.system.pluginoverride", true); log("PluginManager: Auto Discovery [server.system.pluginoverride]=" + bOverrideCore ); // Look at the dynamic log("PluginManager: Auto Discovery (openbdplugin-XXXX.jar)"); try { ClassLoader systemLoader = ClassLoader.getSystemClassLoader(); URL[] urls = ((URLClassLoader)systemLoader).getURLs(); inspectPaths( urls, systemParameters ); } catch (Exception e) { log( "PluginManager.Exception: " + e.getMessage() ); } try { ClassLoader systemLoader = Thread.currentThread().getContextClassLoader(); URL[] urls = ((URLClassLoader)systemLoader).getURLs(); inspectPaths( urls, systemParameters ); } catch (Throwable e) { log( "PluginManager.Exception: " + e.getMessage() ); } String jarList = systemParameters.getString("server.system.pluginjarpath"); log("PluginManager: [server.system.pluginjarpath]=" + jarList ); if ( jarList != null && jarList.length() > 0 ){ String[] jars = jarList.split(","); for ( int x=0; x < jars.length; x++ ){ try{ if ( !jars[x].startsWith("file://") ) jars[x] = "file://" + jars[x]; inspectJAR( new URL( jars[x] ), systemParameters ); }catch(Exception e){ log( "PluginManager.Exception: " + e.getMessage() ); } } } // Finally look at the alternative lib path String altlibpath = cfEngine.getAltLibPath(); if ( altlibpath != null ){ try { File p = new File(altlibpath); inspectDIR( "", p, p.getPath(), systemParameters ); } catch (Exception e) { log( "PluginManager.Exception: " + e.getMessage() ); } } log("PlugInManager: Custom Plugins=" + (listOfPlugins.size()-standardCount) ); // We don't need this anymore filesSet = null; } private void inspectPaths( URL[] urls, xmlCFML systemParameters ) throws IOException{ for (int x = 0; x < urls.length; x++) { String fullName = urls[x].toString(); if (fullName.toLowerCase().indexOf("openbdplugin") != -1 && fullName.endsWith(".jar")) { inspectJAR( urls[x], systemParameters ); }else{ File file = new File(urls[x].getFile()); inspectDIR( "", file, file.getPath(), systemParameters ); } } } private void inspectDIR( String packageDir, File file, String topLevelDir, xmlCFML systemParameters) throws IOException { if ( filesSet.contains( file.getCanonicalFile().toString() ) ) return; else filesSet.add( file.getCanonicalFile().toString() ); if ( file.isFile() && file.getName().toLowerCase().endsWith("plugin.class") ){ String classF = file.getName(); classF = classF.substring(0, classF.lastIndexOf(".class") ); if ( packageDir.length() != 0 ) classF = packageDir + "." + classF; loadPlugIn( classF, systemParameters ); } else if ( file.isDirectory() ){ String curPath = file.getPath(); if ( !curPath.equals(topLevelDir) ){ if ( packageDir.length() == 0 ) packageDir = file.getName(); else packageDir = packageDir + "." + file.getName(); } String childFiles[] = file.list(); for ( int x=0; x < childFiles.length; x++ ){ inspectDIR( packageDir, new File( file, childFiles[x] ), topLevelDir, systemParameters ); } } } private void inspectJAR(URL jarFile, xmlCFML systemParameters) { if ( filesSet.contains( jarFile.toString() ) ) return; else filesSet.add( jarFile.toString() ); JarInputStream jarInputStream = null; try { jarInputStream = new JarInputStream(new FileInputStream( new File(jarFile.getFile()) ), false); JarEntry jarEntry = jarInputStream.getNextJarEntry(); while (jarEntry != null) { if ( (!jarEntry.isDirectory()) && jarEntry.getName().toLowerCase().endsWith("plugin.class") ) { String classF = jarEntry.getName(); classF = classF.substring(0, classF.lastIndexOf(".class") ); classF = classF.replace('/', '.'); loadPlugIn( classF, systemParameters ); } jarEntry = jarInputStream.getNextJarEntry(); } } catch (Throwable t) { if (!(t instanceof RuntimeException)) { throw new RuntimeException(t.toString(), t); } else { throw (RuntimeException) t; } } finally { org.aw20.io.StreamUtil.closeStream( jarInputStream ); } } public void loadPlugIn( String pluginClass, xmlCFML systemParameters ){ if ( "com.bluedragon.plugin.Plugin".equals(pluginClass) ) return; try{ Class<?> C = Class.forName( pluginClass ); Plugin plugin = (Plugin)C.newInstance(); plugin.pluginStart( this, systemParameters ); listOfPlugins.add( plugin ); log("PlugIn.Load.Installed: " + pluginClass + "; " + plugin.getPluginName() + "; Version=" + plugin.getPluginVersion() ); }catch(ClassCastException ce){ //ignore this because we may collide with other libraries/projects using xxxPlugin.java as their convention }catch(InstantiationException ce){ //ignore this because we may collide with other libraries/projects using xxxPlugin.java as their convention }catch(IllegalAccessException ce){ //ignore this because we may collide with other libraries/projects using xxxPlugin.java as their convention }catch(Throwable e){ log("PlugIn.Load.Failed: " + pluginClass + "; Error:" + e.getMessage() ); } } public void shutdown() { Iterator<Plugin> it = listOfPlugins.iterator(); while (it.hasNext()) it.next().pluginStop(this); } public void registerLangauge( String lang, String cfscriptClass ){ cfSCRIPT.registerLanguage(lang, cfscriptClass); } public void registerTag(String tagName, String tagClass) { cfEngine.thisInstance.TagChecker.addTag(tagName, tagClass); } public void registerFunction(String functionName, String functionClass) { if ( bOverrideCore ){ if ( expressionEngine.isFunction(functionName) ) log("PluginManager: Core Function Replaced; Name=" + functionName + "; Class=" + functionClass ); expressionEngine.addFunction(functionName, functionClass); }else if ( (!bOverrideCore && !expressionEngine.isFunction(functionName)) ) expressionEngine.addFunction(functionName, functionClass); } public void addEngineListener(engineListener _new) { cfEngine.registerEngineListener(_new); } public void removeEngineListener(engineListener _new) { cfEngine.registerEngineListener(_new); } public void startRequestStats() { cfEngine.thisInstance.startRequestStats(); } public void stopRequestStats() { cfEngine.thisInstance.stopRequestStats(); } public long getStatsTotalRequests() { if (cfEngine.thisInstance.avgTracker != null) return cfEngine.thisInstance.avgTracker.getCount(); else return -1; } public long getStatsAverageRequestTimeMS() { if (cfEngine.thisInstance.avgTracker != null) return cfEngine.thisInstance.avgTracker.getAverage(); else return -1; } public long getStatsShortestRequestTimeMS() { if (cfEngine.thisInstance.avgTracker != null) return cfEngine.thisInstance.avgTracker.getMin(); else return -1; } public long getStatsLongestRequestTimeMS() { if (cfEngine.thisInstance.avgTracker != null) return cfEngine.thisInstance.avgTracker.getMax(); else return -1; } public long getStatsActiveRequests() { if (cfEngine.thisInstance.avgTracker != null) return cfEngine.thisInstance.avgTracker.getActiveCount(); else return -1; } public void log(String log) { cfEngine.log(log); } public void addRequestListener(RequestListener _new) { listOfRequestListeners.remove(_new); listOfRequestListeners.add(_new); if (listOfRequestListeners.size() > 0) { cfEngine.thisInstance.registerRequestListener(this); } } public void removeRequestListener(RequestListener _new) { listOfRequestListeners.remove(_new); if (listOfRequestListeners.size() == 0) { cfEngine.thisInstance.removeRequestListener(); } } public void requestBadFileException(cfmBadFileException bfException, cfSession session) { Iterator<RequestListener> it = listOfRequestListeners.iterator(); while (it.hasNext()) it.next().requestBadFileException(bfException, session); } public void requestEnd(cfSession session) { Iterator<RequestListener> it = listOfRequestListeners.iterator(); while (it.hasNext()) it.next().requestEnd(session); } public void requestRuntimeException(cfmRunTimeException cfException, cfSession session) { Iterator<RequestListener> it = listOfRequestListeners.iterator(); while (it.hasNext()) it.next().requestRuntimeException(cfException, session); } public void requestStart(cfSession session) { Iterator<RequestListener> it = listOfRequestListeners.iterator(); while (it.hasNext()) it.next().requestStart(session); } public static PluginManagerInterface getPlugInManager() { return thisInst; } public ObjectCFC createCFC(cfSession session, cfData cfcObject) throws Exception { if (cfcObject.getDataType() == cfData.CFCOMPONENTOBJECTDATA) return new ObjectCFCImpl((cfComponentData) cfcObject); else return createCFC(session, cfcObject.getString()); } public ObjectCFC createCFC(cfSession session, String cfcName) throws Exception { return new ObjectCFCImpl(new cfComponentData(session, cfcName)); } public cfSession createBlankSession() { return new cfSession(new dummyServletRequest(cfEngine.thisServletContext.getRealPath("/")), new dummyServletResponse(), cfEngine.thisServletContext); } }