/*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program 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
* this program. If not, see .
*/
package com.l2jserver.gameserver.util;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jserver.Config;
/**
* extension loader for l2j
* @author galun
* @version $Id: DynamicExtension.java,v 1.3 2006/05/14 17:19:39 galun Exp $
*/
public class DynamicExtension
{
private static Logger _log = Logger.getLogger(DynamicExtension.class.getCanonicalName());
private JarClassLoader _classLoader;
private Properties _prop;
private ConcurrentHashMap _loadedExtensions;
private ConcurrentHashMap _getters;
private ConcurrentHashMap _setters;
/**
* create an instance of DynamicExtension
* this will be done by GameServer according to the altsettings.properties
*
*/
private DynamicExtension()
{
_getters = new ConcurrentHashMap();
_setters = new ConcurrentHashMap();
initExtensions();
}
/**
* get the singleton of DynamicInstance
* @return the singleton instance
*/
public static DynamicExtension getInstance()
{
return SingletonHolder._instance;
}
/**
* get an extension object by class name
* @param className he class name as defined in the extension properties
* @return the object or null if not found
*/
public Object getExtension(String className)
{
return _loadedExtensions.get(className);
}
/**
* initialize all configured extensions
*
*/
public String initExtensions()
{
_prop = new Properties();
String res = "";
_loadedExtensions = new ConcurrentHashMap();
try
{
_prop.load(new FileInputStream(Config.EXTENSIONS_CONFIG_FILE));
}
catch (FileNotFoundException ex)
{
_log.info(ex.getMessage() + ": no extensions to load");
}
catch (Exception ex)
{
_log.log(Level.WARNING, "could not load properties", ex);
}
_classLoader = new JarClassLoader();
for (Object o : _prop.keySet())
{
String k = (String) o;
if (k.endsWith("Class"))
{
res += initExtension(_prop.getProperty(k)) + "\n";
}
}
return res;
}
/**
* init a named extension
* @param name the class name and optionally a jar file name delimited with a '@' if the jar file is not
* in the class path
*/
public String initExtension(String name)
{
String className = name;
String[] p = name.split("@");
String res = name + " loaded";
if (p.length > 1)
{
_classLoader.addJarFile(p[1]);
className = p[0];
}
if (_loadedExtensions.containsKey(className))
return "already loaded";
try
{
Class> extension = Class.forName(className, true, _classLoader);
Object obj = extension.newInstance();
extension.getMethod("init", new Class[0]).invoke(obj, new Object[0]);
_log.info("Extension " + className + " loaded.");
_loadedExtensions.put(className, obj);
}
catch (Exception ex)
{
_log.log(Level.WARNING, name, ex);
res = ex.toString();
}
return res;
}
/**
* create a new class loader which resets the cache (jar files and loaded classes)
* on next class loading request it will read the jar again
*/
protected void clearCache()
{
_classLoader = new JarClassLoader();
}
/**
* call unloadExtension() for all known extensions
*
*/
public String unloadExtensions()
{
String res = "";
for (String e : _loadedExtensions.keySet())
res += unloadExtension(e) + "\n";
return res;
}
/**
* get all loaded extensions
* @return a String array with the class names
*/
public String[] getExtensions()
{
String[] l = new String[_loadedExtensions.size()];
_loadedExtensions.keySet().toArray(l);
return l;
}
/**
* unload a named extension
* @param name the class name and optionally a jar file name delimited with a '@'
*/
public String unloadExtension(String name)
{
String className = name;
String[] p = name.split("@");
if (p.length > 1)
{
_classLoader.addJarFile(p[1]);
className = p[0];
}
String res = className + " unloaded";
try
{
Object obj = _loadedExtensions.get(className);
Class> extension = obj.getClass();
_loadedExtensions.remove(className);
extension.getMethod("unload", new Class[0]).invoke(obj, new Object[0]);
_log.info("Extension " + className + " unloaded.");
}
catch (Exception ex)
{
_log.log(Level.WARNING, "could not unload " + className, ex);
res = ex.toString();
}
return res;
}
/**
* unloads all extensions, resets the cache and initializes all configured extensions
*
*/
public void reload()
{
unloadExtensions();
clearCache();
initExtensions();
}
/**
* unloads a named extension, resets the cache and initializes the extension
* @param name the class name and optionally a jar file name delimited with a '@' if the jar file is not
* in the class path
*/
public void reload(String name)
{
unloadExtension(name);
clearCache();
initExtension(name);
}
/**
* register a getter function given a (hopefully) unique name
* @param name the name of the function
* @param function the ExtensionFunction implementation
*/
public void addGetter(String name, ExtensionFunction function)
{
_getters.put(name, function);
}
/**
* deregister a getter function
* @param name the name used for registering
*/
public void removeGetter(String name)
{
_getters.remove(name);
}
/**
* call a getter function registered with DynamicExtension
* @param name the function name
* @param arg a function argument
* @return an object from the extension
*/
public Object get(String name, String arg)
{
ExtensionFunction func = _getters.get(name);
if (func != null)
return func.get(arg);
return "";
}
/**
* register a setter function given a (hopefully) unique name
* @param name the name of the function
* @param function the ExtensionFunction implementation
*/
public void addSetter(String name, ExtensionFunction function)
{
_setters.put(name, function);
}
/**
* deregister a setter function
* @param name the name used for registering
*/
public void removeSetter(String name)
{
_setters.remove(name);
}
/**
* call a setter function registered with DynamicExtension
* @param name the function name
* @param arg a function argument
* @param obj an object to set
*/
public void set(String name, String arg, Object obj)
{
ExtensionFunction func = _setters.get(name);
if (func != null)
func.set(arg, obj);
}
public JarClassLoader getClassLoader()
{
return _classLoader;
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final DynamicExtension _instance = new DynamicExtension();
}
}