/*
** j###t ########## #### ####
** j###t ########## #### ####
** j###T "###L J###"
** ######P' ########## #########
** ######k, ########## T######T
** ####~###L ####
** #### q###L ########## .#####
** #### \###L ########## #####"
**
** $Id$
**
** Class History
**
** Date Name Description
** ---------|------------|-----------------------------------------------
** 19Aug98 subtle start of recorded history
**
*/
package key;
import key.primitive.*;
import java.util.Hashtable;
import java.io.*;
/**
* A wrapper for a class, since we can't extend it.
*
* If class is made un-final, change KeyInputStream to use instanceof
* instead of o.getClass() == Type.class
*/
public final class Type
implements Symbol, Serializable, key.io.Replaceable
{
private static final long serialVersionUID = -3520340202727157134L;
private static Hashtable registeredTypeNames = new Hashtable();
private static Hashtable registeredTypeClasses = new Hashtable();
Class type;
String name;
String className;
public Type( Class c, String n )
{
type = c;
name = n;
className = null;
}
protected Type( String cn, String n )
{
className = cn;
name = n;
type = null;
}
private void writeObject( ObjectOutputStream oos ) throws IOException
{
if( className != null )
oos.writeObject( className );
else if( type != null )
oos.writeObject( type.getName() );
else
oos.writeObject( null );
}
private void readObject( ObjectInputStream ois ) throws IOException
{
try
{
className = (String) ois.readObject();
}
catch( ClassNotFoundException e )
{
throw new UnexpectedResult( e );
}
}
private final void resolve()
{
if( type == null && className != null )
{
try
{
type = Class.forName( className );
if( type == null )
Log.error( "key.Type: Class.forName( " + className + " ) returned null" );
else
{
className = null;
registeredTypeClasses.put( type, this );
}
}
catch( java.lang.ClassNotFoundException e )
{
Log.error( "key.Type", e );
throw new UnexpectedResult( e.toString() );
}
}
}
public String getName()
{
return( name );
}
public Object getKey()
{
return( name );
}
public final void setKey( Object key )
{
name = (String) key;
}
public final Object newInstance() throws InstantiationException,
IllegalAccessException
{
resolve();
return( type.newInstance() );
}
public final boolean isInterface()
{
resolve();
return( type.isInterface() );
}
public final Object clone() throws CloneNotSupportedException
{
throw new CloneNotSupportedException();
}
/**
* returns true if Class 'is' is the same as class 't', or is
* a specialised version of it (or implements interface t)
*/
public boolean isA( Type t )
{
resolve();
t.resolve();
if( t == null )
return( false );
return( isA( type, t.type ) );
}
/**
* returns true if Class 'is' is the same as class 't', or is
* a specialised version of it (or implements interface t)
*/
public static boolean isA( Class is, Class t )
{
return( t.isAssignableFrom( is ) );
/* -- JDK 1.0.2 recursive implementation
if( t == null || is==null )
return( false );
if( is == t )
return( true );
else
{
if( t.isInterface() )
{
Class[] interfaces = is.getInterfaces();
for( int i = 0; i < interfaces.length; i++ )
{
if( interfaces[i] == t )
return( true );
}
}
return( isA( is.getSuperclass(), t ) );
}
*/
}
/**
* One day, this will be able to accept things like:
* 'subtle:myRoom', because I've uploaded the appropriate
* class name. As it is, this only works for *registered*
* types. One day we'll support loading them from a
* players spot.
*/
public static Type forName( String s ) throws ClassNotFoundException
{
Type t = (Type) registeredTypeNames.get( s );
if( t != null )
return( t );
else
throw new ClassNotFoundException( s + " not found" );
}
public static Type typeOf( Object o )
{
return( typeFor( o.getClass() ) );
}
public static Type typeFor( Class c )
{
Type t = (Type) registeredTypeClasses.get( c );
if( t == null )
{
String cn = c.getName();
if( c.isArray() )
{
// it's an array: we could
// be more clever about how we
// determined the local name, but
// blah.
return( new Type( cn, cn ) );
}
t = (Type) registeredTypeNames.get( cn );
if( t == null )
{
t = newType( c, cn );
//Log.debug( "Type", "found new type '" + cn + "'" );
}
else
{
// manually resolve this type
t.type = c;
t.className = null;
}
}
return( t );
}
/**
* Never use newType when you mean forName(). It's possible
* we'll prevent newType being executed by non-priviledged
* people
*/
public static Type newType( String className, String localName )
{
boolean regnow = false;
Type t;
t = (Type) registeredTypeNames.get( className );
if( t != null )
{
t.name = localName;
registeredTypeNames.put( localName, t );
}
else
{
t = new Type( className, localName );
registeredTypeNames.put( localName, t );
registeredTypeNames.put( className, t );
}
return( t );
}
/**
* Never use newType when you mean forName(). It's possible
* we'll prevent newType being executed by non-priviledged
* people
*/
public static Type newType( Class c, String localName )
{
Type t = new Type( c, localName );
registeredTypeNames.put( localName, t );
registeredTypeNames.put( c.getName(), t );
registeredTypeClasses.put( c, t );
return( t );
}
public final Object getReplacement()
{
try
{
if( className != null )
return( Type.forName( className ) );
}
catch( Exception e )
{
Log.error( "while resolving a null Type", e );
}
return( null );
}
// a list of all the types that are needed by the program code
// keep in mind that if you use this in a static class, they
// may not have been initialised yet. I wrote some really nice
// code in the C++ version that forced initialisation in a certain
// order, but it appears I'm not good enough at Java yet. - subtle
public static final Type STRING = newType( "java.lang.String", "string" );
public static final Type INTEGER = newType( "java.lang.Integer", "integer" );
public static final Type INT = newType( Integer.TYPE, "int" );
public static final Type REFERENCE = newType( "key.Reference", "reference" );
public static final Type BOOLEAN = newType( "java.lang.Boolean", "boolean" );
public static final Type ATOM = newType( "key.Atom", "atom" );
public static final Type GENDER = newType( "key.primitive.Gender", "gender" );
public static final Type STORABLE = newType( "key.Storable", "storable" );
public static final Type COMMAND = newType( "key.Command", "command" );
public static final Type COMMANDLIST = newType( "key.CommandList", "commandList" );
public static final Type DATETIME = newType( "key.primitive.DateTime", "dateTime" );
public static final Type DURATION = newType( "key.primitive.Duration", "duration" );
public static final Type PASSWORD = newType( "key.primitive.Password", "password" );
public static final Type TIMESTATISTICS = newType( "key.TimeStatistics", "timeStatistics" );
public static final Type CONNECTIONSTATISTICS = newType( "key.ConnectionStatistics", "connectionStatistics" );
public static final Type CLAN = newType( "key.Clan", "clan" );
public static final Type FRIENDS = newType( "key.Friends", "friends" );
public static final Type ROOM = newType( "key.Room", "room" );
public static final Type PUBLICROOM = newType( "key.PublicRoom", "publicRoom" );
public static final Type EXIT = newType( "key.Exit", "exit" );
public static final Type MOVEMENT = newType( "key.effect.Movement", "movement" );
public static final Type BLOCKING = newType( "key.effect.Blocking", "blocking" );
public static final Type CONNECTION = newType( "key.effect.Connection", "connection" );
public static final Type SHOUT = newType( "key.effect.Shout", "shouts" );
//public static final Type OBJECT_DIRECT = newType( "key.effect.ObjectDirect", "objdirect" );
//public static final Type OBJECT_ROOM = newType( "key.effect.ObjectRoom", "objects" );
public static final Type CONTAINER = newType( "key.Container", "container" );
public static final Type INTERACTIVECONNECTION = newType( "key.InteractiveConnection", "interactiveConnection" );
public static final Type PLAYER = newType( "key.Player", "player" );
public static final Type PARAGRAPH = newType( "key.Paragraph", "paragraph" );
public static final Type LANDSCAPE = newType( "key.Landscape", "landscape" );
public static final Type LETTER = newType( "key.Letter", "letter" );
public static final Type MESSAGEBOX = newType( "key.MessageBox", "messageBox" );
public static final Type IMPLICATIONS = newType( "key.Implications", "implications" );
public static final Type GROUP = newType( "key.Group", "group" );
public static final Type DAEMON = newType( "key.Daemon", "daemon" );
public static final Type SCAPE = newType( "key.Scape", "scape" );
public static final Type RANK = newType( "key.Rank", "rank" );
public static final Type EMAILADDRESS = newType( "key.EmailAddress", "emailAddress" );
public static final Type WEBPAGE = newType( "key.Webpage", "webpage" );
public static final Type INFORMLIST = newType( "key.InformList", "informList" );
public static final Type SUBNET = newType( "key.Subnet", "subnet" );
public static final Type SHORTCUTCOLLECTION = newType( "key.collections.ShortcutCollection", "shortcutCollection" );
public static final Type NUMBEREDCOLLECTION = newType( "key.collections.NumberedCollection", "numberedCollection" );
public static final Type SITECOLLECTION = newType( "key.collections.SiteCollection", "siteCollection" );
public static final Type NETWORKCOLLECTION = newType( "key.collections.NetworkCollection", "networkCollection" );
public static final Type STRINGKEYCOLLECTION = newType( "key.collections.StringKeyCollection", "stringKeyCollection" );
public static final Type ALIASCOLLECTION = newType( "key.collections.AliasCollection", "aliasCollection" );
public static final Type SITE = newType( "key.Site", "site" );
public static final Type TARGETS = newType( "key.Targets", "targets" );
public static final Type TARGETABLE = newType( "key.Targetable", "targetable" );
public static final Type SCREEN = newType( "key.Screen", "screen" );
public static final Type STRINGSET = newType( "key.StringSet", "StringSet" );
public static final Type CONFIGURATION = newType( "key.config.Configuration", "configuration" );
public static final Type MEMO = newType( "key.Memo", "memo" );
public static final Type CLANACCEPT = newType( "key.commands.clan.Accept", "accept" );
public static final Type CLANADD = newType( "key.commands.clan.Add", "add" );
public static final Type CLANBASERANK = newType( "key.commands.clan.BaseRank", "baseRank" );
public static final Type CLANMOTD = newType( "key.commands.clan.ClanMotd", "ClanMOTD" );
public static final Type CLANDISSOLVE = newType( "key.commands.clan.Dissolve", "dissolve" );
public static final Type CLANEDITMOTD = newType( "key.commands.clan.EditMotd", "editMOTD" );
public static final Type CLANIMPLIES = newType( "key.commands.clan.Implies", "implies" );
public static final Type CLANMAKE = newType( "key.commands.clan.Make", "make" );
public static final Type CLANNOTIMPLIES = newType( "key.commands.clan.NotImplies", "notImplies" );
public static final Type CLANREFCLAN = newType( "key.commands.clan.RefClan", "refClan" );
public static final Type CLANREFCLANLAND = newType( "key.commands.clan.RefClanLand", "refClanLand" );
public static final Type CLANREFRANK = newType( "key.commands.clan.RefRank", "refRank" );
public static final Type CLANREVOKE = newType( "key.commands.clan.Revoke", "revoke" );
public static final Type CLANSETHALL = newType( "key.commands.clan.SetHall", "setHall" );
public static final Type CLANTAKE = newType( "key.commands.clan.Take", "take" );
public static final Type THING = newType( "key.Thing", "thing" );
public static final Type CHANNEL = newType( "key.Channel", "channel" );
//public static final Type STAFF_CHANNEL = newType( "key.StaffChannel", "staffChannel" );
//public static final Type ADMIN_CHANNEL = newType( "key.AdminChannel", "adminChannel" );
public static final Type COUNCIL = newType( "key.talker.forest.Council", "council" );
public static final Type ADVISOR = newType( "key.talker.forest.Advisor", "advisor" );
public static final Type ACTION = newType( "key.Action", "action" );
}