Essentials/EssentialsUpdate/src/f00f/net/irc/martyr/commands/AbstractInCommand.java

175 lines
4.9 KiB
Java

package f00f.net.irc.martyr.commands;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.StringTokenizer;
import f00f.net.irc.martyr.CommandRegister;
import f00f.net.irc.martyr.InCommand;
import f00f.net.irc.martyr.State;
import f00f.net.irc.martyr.clientstate.ClientState;
/**
* Defines a generic command. Most commands will simply have to
* override the getIrcIdentifier method and implement the parse and
* render methods using convenience methods.
*/
public abstract class AbstractInCommand implements InCommand
{
protected Map<String,String> attributes = new HashMap<String,String>();
protected AbstractInCommand()
{
}
protected AbstractInCommand( String[] attributeNames )
{
for (String attributeName : attributeNames) {
attributes.put(attributeName, null);
}
}
public String getAttribute( String key )
{
return attributes.get( key );
}
public Iterator getAttributeKeys()
{
return Collections.unmodifiableSet( attributes.keySet() ).iterator();
}
protected void setAttribute( String key, String value )
{
attributes.put( key, value );
}
private String sourceString;
/**
* Some commands, when received by the server, can only occur in one
* state. Thus, when this command is received, the protocol should
* assume that it is that state. A command can use the 'unknown'
* state to indicate it can be received in any state (for example,
* ping). Most commands will occur in the REGISTERED state, so for a
* few exeptions, commands can leave this alone.
*/
public State getState()
{
return State.REGISTERED;
}
/**
* Every command should know how to register itself (or not) with the
* command parsing engine. If a command is available under mutiple
* identifiers, then this method can be overridden and the addCommand
* method can be called multiple times.
*/
public void selfRegister( CommandRegister commandRegister )
{
commandRegister.addCommand( getIrcIdentifier(), this );
}
/**
* Parses a string and produces a formed command object, if it can.
* Should return null if it cannot form the command object.
*/
public abstract InCommand parse( String prefix, String identifier, String params );
/**
* By default, commands do not update the client state.
*/
public boolean updateClientState( ClientState state )
{
return false;
}
/**
* Utility method to make parsing easy. Provides parameter n, where
* n=0 is the first parameter. Parses out the : and considers
* anything after a : to be one string, the final parameter.
*
* If the index doesn't exist, returns null. Should it throw
* IndexOutOfBoundsException? No, some commands may have optional
* fields.
*
* @param params String with parameters in it
* @param num Position number of parameter to be requested
* @return Parameter specified by id in params string
*/
public String getParameter( String params, int num )
{
int colonIndex = params.indexOf( " :" );
colonIndex++; // Skip the space, we just needed it to be sure it's really a "rest of line" colon
String textParam = null;
String spaceParams;
if( colonIndex < 0 )
{
spaceParams = params;
}
else if( colonIndex == 0 )
{
if( num == 0 )
return params.substring( 1, params.length() );
else
return null;
// throw exception?
}
else
{
// colon index > 0, so we have at least one parameter before
// the final parameter.
spaceParams = params.substring( 0, colonIndex ).trim();
textParam = params.substring( colonIndex + 1, params.length() );
}
StringTokenizer tokens = new StringTokenizer( spaceParams, " " );
while( tokens.hasMoreTokens() && num > 0 )
{
// strip off tokensi
--num;
tokens.nextToken();
}
if( num == 0 && tokens.hasMoreTokens() )
return tokens.nextToken();
if( num == 0 && !tokens.hasMoreTokens() )
return textParam;
return null;
// throw exception?
}
public int getIntParameter( String params, int paramnum, int defaultNum )
{
try
{
return Integer.parseInt( getParameter( params, paramnum ) );
}
catch( NumberFormatException nfe )
{
return defaultNum;
}
}
public void setSourceString( String source )
{
this.sourceString = source;
}
public String getSourceString()
{
return sourceString;
}
}