/**
* This source file is part of WZ Hybrid Bots
* For the latest information, see http://sourceforge.net/projects/wzhybridbots
*
* Copyright (c) 2006 - WzCtf
* For more information about WzCtf, see http://www.wzctf.net
* Also see the license in license.txt
*/
package plugins.PluginManager.tools.command;
/** The imported classes/interfaces */
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import hybrid.core.consts.MessageTypes;
import frontend.alphaspawn.ASConnection;
import frontend.alphaspawn.PluginAdapter;
import frontend.alphaspawn.PluginManager;
import frontend.alphaspawn.tools.command.Command;
import wzhybridbots.consts.AccessLevel;
import wzhybridbots.security.BotOperator;
import wzhybridbots.security.BotOperatorSet;
/**
* Plugin command used to list/load/unload/reload plugins at runtime.
*
* @author Witlospock
* @version 1.0
*/
public class Plugin extends Command {
/** The plugin manager that load/unload plugins */
protected PluginManager objPluginMgr = null;
/** A connection object used to track and handle commands */
protected ASConnection objConnection = null;
/** A set of the bot operators and their access level */
protected BotOperatorSet objBotOperators = null;
/** A regex pattern for the arguments of the command */
protected Pattern objPattern = null;
/**
* The class constructor. Initialize the command object.
*
* @param conn A fully functionnal connection object.
* @param plugins The plugin manager that load/unload plugins.
* @param objBotOperators The set of bot operators and their access level.
*/
public Plugin ( ASConnection conn,
PluginManager plugins,
BotOperatorSet ops ) {
// Initialize the class
super( "!plugin -lur<pluginName>", "List/Load/Unload/Reload a plugin" );
// Checks for valid parameters
if ( conn == null ) { throw new NullPointerException(); }
if ( plugins == null ) { throw new NullPointerException(); }
if ( ops == null ) { throw new NullPointerException(); }
// Sets the fields
this.objConnection = conn;
this.objPluginMgr = plugins;
this.objBotOperators = ops;
// Sets the pattern
// Here is the pattern we want to match
// !plugin -<option><pluginName>
//
// where
// <option>
// l Load
// u Unload
// r Reload
// <pluginName>
// The name of the plugin
//
// ex:
// !plugin -lPluginManager
// !plugin -uPluginManager
// !plugin -rPluginManager
// !plugin -lPluginManager -uLagCheck -rSomeOtherPlugin
////////////////////////////////////////////////////////////
this.objPattern = Pattern.compile( "(?:\\s*(-[lur]\\w*))" );
}
/**
* Returns true if the player has sufficient access level,
* false otherwise.
*
* @param playerName The name of the player to check access.
*
* @return see above.
*/
public boolean checkAccess ( String playerName ) {
boolean hasAccess = false;
// Check if the player has SysOp access
BotOperator operator = new BotOperator( playerName );
if ( this.objBotOperators.contains( operator ) ) {
// The operator is register... let check his access level
operator = this.objBotOperators.get( operator );
// This isn't suppose to happen often, but still...
if ( operator != null ) {
hasAccess = operator.getAccessLevel() >= AccessLevel.SYSOP;
}
}
return hasAccess;
}
/**
* Returns a bit field representing the command type this command can be fired from.
*
* @return see above.
*/
public int getMessageTypes () {
return (1 << MessageTypes.Private) | (1 << MessageTypes.Public);
}
/**
* Called when a player with the proper access level execute a command
* that belongs to this Command object.
*
* @param playerName The name of the player executing the command.
* @param command The command to be execute.
* @param args Additionnal arguments beside the command .
*/
public void handleCommand( String playerName, String command, String args ) {
if ( args == null || args.trim().length() <= 0 ) {
// The operator want to get a list of all plugins
listPlugin( playerName );
}
else {
// The operator has specified some parameters
Matcher matcher = this.objPattern.matcher( args );
// Checks if the matcher found something
if ( matcher.find() ) {
do {
// The argument are in the right format
String match = matcher.group( 1 );
if ( match.length() > 2 ) {
// There is a plugin's name
// Retrieve the plugin's name
String pluginName = match.substring( 2 );
// Check the type of command (l,u,r)
switch ( match.charAt( 1 ) ) {
// Load
///////////////////////////////
case 'l':
// Load the plugin
if ( loadPlugin( pluginName ) ) {
// Plugin has been loaded & registered
// Display a message to the player
this.objConnection.sendPrivateMessage( playerName, "The plugin '" + pluginName + "' has been loaded successfully." );
}
else {
// Plugin failed to load and/or register
// Display a message to the player
this.objConnection.sendPrivateMessage( playerName, "The plugin '" + pluginName + "' failed to load." );
}
break;
// Unload
///////////////////////////////
case 'u':
// Unload the plugin
if ( unloadPlugin( pluginName ) ) {
// The plugin has been unloaded
// Display a message to the player
this.objConnection.sendPrivateMessage( playerName, "The plugin '" + pluginName + "' has been unloaded successfully." );
}
else {
// Unable to find or unload the plugin
// Display a message to the player
this.objConnection.sendPrivateMessage( playerName, "The plugin '" + pluginName + "' doesn't exist or didn't unload." );
}
break;
// Reload
///////////////////////////////
case 'r':
// Reload the plugin
if ( reloadPlugin( pluginName ) ) {
// The plugin has been reloaded
// Display a message to the player
this.objConnection.sendPrivateMessage( playerName, "The plugin '" + pluginName + "' has been reloaded successfully." );
}
else {
// Unable to reload the plugin
this.objConnection.sendPrivateMessage( playerName, "The plugin '" + pluginName + "' failed to reload." );
}
break;
// What command is this ?!?
///////////////////////////////
default:
this.objConnection.sendPrivateMessage( playerName, "The '-" + match.charAt( 1 ) + "' command's option doesn't exist." );
break;
}
}
else {
// Where is the plugin's name ?!?
this.objConnection.sendPrivateMessage( playerName, "The plugin's name is missing for the '" + match + "' command's option." );
}
} while ( matcher.find() ) ;
}
else {
// The pattern didn't match
// Display an error message
this.objConnection.sendPrivateMessage( playerName, "Unknown argument '" + args + "' for command '" + command + "'." );
}
}
}
/**
* Called when a player with insufficient permission want to execute
* a command that belongs to this Command object.
*
* @param playerName The name of the player executing the command.
* @param command The command to be execute.
* @param args Additionnal arguments beside the command.
*/
public void ignoreCommand( String playerName, String command, String args ) {
}
/**
* Loads the specified plugin.
*
* @param pluginName The plugin to load.
* @return true if the plugin has been loaded successfully, false otherwise.
* If it was already loaded, true is return.
*/
protected boolean loadPlugin ( String pluginName ) {
// Load & register the plugin
PluginAdapter plugin = null;
try {
plugin = this.objPluginMgr.loadPlugin( pluginName );
}
catch ( Exception e ) {
// We caught an exception... the plugin shouldn't exist
// or the parameter pass had a very bad name
plugin = null;
}
return plugin != null;
}
/**
* Unloads the specified plugin.
*
* @param pluginName The plugin to unload.
* @return true if the plugin has been unloaded successfully, false otherwise.
* If it wasn't found, false is return.
*/
protected boolean unloadPlugin ( String pluginName ) {
// Iterate through the plugin list and find the right plugin
PluginAdapter pluginToRemove = null;
for ( int i = this.objPluginMgr.getPluginCount() - 1 ; i >= 0 && pluginToRemove == null ; i-- ) {
PluginAdapter plugin = this.objPluginMgr.getPlugin( i );
// Checks if we get a valid plugin
if ( plugin != null ) {
// The plugin is valid.
// Checks if this is the one we are look for.
if ( plugin.getName().equals( pluginName ) ) {
// This is the plugin to unload
pluginToRemove = plugin;
}
}
}
// Checks if we have found the plugin to unload
if ( pluginToRemove != null ) {
// We found our plugin
// Unload it
return this.objPluginMgr.removePlugin( pluginToRemove );
}
return false;
}
/**
* Reloads a specified plugin.
*
* @param pluginName The plugin to reload.
* @return true is the plugin has been reloaded successfully, false otherwise.
*/
protected boolean reloadPlugin ( String pluginName ) {
boolean reloaded = false;
// Try to unload the plugin
if ( unloadPlugin( pluginName ) ) {
// The plugin was unloaded successfully
// Try to load the plugin
if ( loadPlugin( pluginName ) ) {
// The plugin was loaded successfully
reloaded = true;
}
else {
// Unable to load the plugin back
}
}
else {
// The plugin didn't unload or doesn't exists
}
return reloaded;
}
/**
* Displays to the specified player the list of all loaded/unloaded plugins.
*
* @param playerName The player that wants to get the list of plugins.
*/
protected void listPlugin ( String playerName ) {
// Create a container for the package's name
SortedMap listPkg = new TreeMap();
// Variables use for display purpose
int longestName = 0;
// Retrieve the list of all available plugins
/////////////////////////////////////////////
// Checks the list of all available plugins
PluginEnumerator pe = PluginEnumerator.getInstance();
for ( Iterator iter = pe.iterator() ; iter.hasNext() ; ) {
String pluginName = (String)iter.next();
// Memorize the plugin's name
if ( pluginName != null &&
pluginName.length() > 0 ) {
listPkg.put( pluginName, new Boolean( false ) );
if ( pluginName.length() > longestName ) {
longestName = pluginName.length();
}
}
}
// Second, get the list of loaded plugins
// Iterate through the list and mark these plugins has loaded
for ( Iterator iter = this.objPluginMgr.getPlugins().iterator() ; iter.hasNext() ; ) {
PluginAdapter plugin = (PluginAdapter)iter.next();
String pluginName = plugin.getName();
// Checks if the plugin is in the list
if ( listPkg.containsKey( pluginName ) ) {
// The plugin is in the list
// Remove the old occurence and insert a new one and
// mark it as loaded
listPkg.remove( pluginName );
}
// Insert the plugin in the list and mark it as loaded
listPkg.put( pluginName, new Boolean( true ) );
if ( pluginName.length() > longestName ) {
longestName = pluginName.length();
}
}
// Display the list of plugins
/////////////////////////////////////////////
if ( !listPkg.isEmpty() ) {
// The are some plugins
String spaces = " ";
String loaded = "Loaded";
String unloaded = "Unloaded";
for ( Iterator iter = listPkg.entrySet().iterator() ; iter.hasNext() ; ) {
Map.Entry entry = (Map.Entry)iter.next();
// Format the output string
StringBuffer output = new StringBuffer( (String)entry.getKey() );
// Fill the output with some space
for ( int i = output.length() ; i < longestName ; i++ ) {
output.append( ' ' );
}
output.append( spaces );
// Checks if the plugin is loaded or unloaded
if ( ( (Boolean)entry.getValue() ).booleanValue() ) {
// The plugin is loaded
output.append( loaded ).append( spaces );
// Put some spaces
for ( int i = 0 ; i < unloaded.length() ; i++ ) {
output.append( ' ' );
}
}
else {
// The plugin is unloaded
// Put some spaces
for ( int i = 0 ; i < loaded.length() ; i++ ) {
output.append( ' ' );
}
output.append( spaces ).append( unloaded );
}
// Display the line to the player
this.objConnection.sendPrivateMessage( playerName, output.toString() );
}
}
else {
// No plugins found
this.objConnection.sendPrivateMessage( playerName, "No plugin found" );
}
}
/**
* Internal class that enumerates all plugins that can be
* loaded by the bot.
*
* @author Witlospock
* @version 1.0
*/
private static class PluginEnumerator {
/** The only possible instance of this class */
private static PluginEnumerator singleton = null;
/** List that contains the plugins name */
private List pluginList = new ArrayList();
/**
* Default class constructor.
*/
private PluginEnumerator () {
// Fill the list of plugins
initPluginList();
}
private void initPluginList () {
// FIXME The class isn't able to enumerate the plugins package
// Maybe it would work if the CLASSPATH environment variable had the plugins folder
// Get the list of packages
Package plugins[] = Package.getPackages();
for ( int i = 0 ; i < plugins.length ; i++ ) {
if ( plugins[i] == null ) { continue; }
String pluginName = plugins[i].getName();
// Memorize the plugin's name
if ( pluginName != null &&
pluginName.length() > 0 &&
pluginName.startsWith( "plugins" ) ) {
// TODO Truncate the string to keep only the plugin's name
this.pluginList.add( pluginName );
}
}
}
/**
* Returns the instance of this class.
*
* @return see above.
*/
public static PluginEnumerator getInstance () {
// Returns the only instance of the PluginEnumerator class.
if ( PluginEnumerator.singleton == null ) {
PluginEnumerator.singleton = new PluginEnumerator();
}
return PluginEnumerator.singleton;
}
/**
* Returns an iterator on the list of plugins found.
*
* @return see above.
*/
public Iterator iterator () {
// Return an iterator on the package list
return this.pluginList.iterator();
}
}
}