/*
** j###t ########## #### ####
** j###t ########## #### ####
** j###T "###L J###"
** ######P' ########## #########
** ######k, ########## T######T
** ####~###L ####
** #### q###L ########## .#####
** #### \###L ########## #####"
**
** $Id$
**
** Class History
**
** Date Name Description
** ---------|------------|-----------------------------------------------
** 07Sep98 subtle created
**
*/
package key;
import key.io.KeyOutputStream;
import key.io.KeyInputStream;
import java.net.*;
import java.io.*;
import java.util.*;
import java.lang.*;
import java.lang.reflect.*;
public final class Factory
{
public static void storeObject( Object object, File to )
{
storeObject( object, to, false );
}
public static Object loadObject( File from )
{
ObjectInputStream ds = null;
Object result = null;
InputStream fis = null;
try
{
fis = new FileInputStream( from );
if( Main.COMPRESS_DISK_FILES )
fis = new java.util.zip.GZIPInputStream( fis );
ds = new KeyInputStream( fis );
}
catch( IOException e )
{
Log.error( "while loading file '" + from.getPath() + "'", e );
return( null );
}
try
{
result = ds.readObject();
}
catch( java.io.InvalidClassException e )
{
if( Key.isRunning() )
Log.error( "while loading file '" + from.getPath() + "'", e );
else
{
e.printStackTrace();
Log.fatal( "Key", e.toString() + " while loading from file '" + from.getPath() + "'" );
}
}
catch( ClassNotFoundException e )
{
Log.error( "while loading from file '" + from.getName() + "'", e );
return( null );
}
catch( IOException e )
{
Log.error( "while loading from file '" + from.getName() + "'", e );
return( null );
}
finally
{
try
{
ds.close();
fis.close();
}
catch( IOException except )
{
}
}
// this is done by the Factory on construction, but
// here on load, obviously
if( result instanceof Atom )
Factory.incrementImplicitReferenceCounts( (Atom) result );
return( result );
}
public static void storeObject( Object object, File to, boolean distinct )
{
File temp = null;
try
{
temp = new File( to.getPath() + tempFileExtension );
{
// streamed code (is RandomAccessFile faster?)
OutputStream fos = new FileOutputStream( temp );
if( Main.COMPRESS_DISK_FILES )
fos = new java.util.zip.GZIPOutputStream( fos );
KeyOutputStream oos = new KeyOutputStream( fos );
if( distinct )
oos.doSwapping();
oos.writeObject( object );
oos.close();
fos.close();
}
to.delete();
temp.renameTo( to );
}
catch( IOException e )
{
if( temp != null )
temp.delete();
throw new UnexpectedResult( e.toString() + " while trying to saveObject to file '" + to.getName() + "'" );
}
}
public static Atom makeAtom( Class cl, Object key )
{
Atom a;
a = createAtom( cl );
a.setKey( key );
a.constructed();
return( a );
}
public static Atom makeAtom( Class cl )
{
Atom a;
a = createAtom( cl );
a.constructed();
return( a );
}
private static Atom createAtom( Class cl )
{
Atom a;
try
{
a = (Atom) cl.newInstance();
}
catch( Exception e )
{
e.printStackTrace( System.out );
throw new UnexpectedResult( e );
}
postCreateProcess( a );
return( a );
}
public static void postCreateProcess( Atom a )
{
processFields( a.getClass(), a, CONSTRUCTER );
}
public static void decrementImplicitReferenceCounts( Atom a )
{
processFields( a.getClass(), a, DECREMENTER );
}
public static void incrementImplicitReferenceCounts( Atom a )
{
processFields( a.getClass(), a, INCREMENTER );
}
public static void distinctSyncFields( Atom a )
{
processFields( a.getClass(), a, DISTINCT_SYNCER );
}
public static void nonTemporaryFields( Atom a )
{
processFields( a.getClass(), a, NON_TEMPORARY );
}
public static void partDeleteFields( Atom a )
{
processFields( a.getClass(), a, PART_DELETER );
}
/**
* Makes sure that the owner of this atom also
* owns all of this atom's final atomic fields.
*/
public static void syncOwnerFields( Atom a )
{
processFields( a.getClass(), a, SYNC_OWNER );
}
public static void syncOwnerRecursiveFields( Atom a )
{
processFields( a.getClass(), a, SYNC_OWNER_R );
}
private final static void processFields( Class start, Atom parent, FieldScanner fs )
throws SecurityException
{
{
Field[] fields;
fields = start.getDeclaredFields();
for( int i = 0; i < fields.length; i++ )
{
Field f = fields[i];
if( Atom.class.isAssignableFrom( f.getType() ) )
{
// this is an atom
try
{
int mod = f.getModifiers();
if( !Modifier.isTransient( mod ) && !Modifier.isStatic( mod ) )
{
// The field must be final, then, since if
// re-assignments are made we would have to update
// reference counts here, there, and everywhere, and
// that can't be guaranteed.
if( !Modifier.isFinal( mod ) )
{
// replace with exception
System.err.println( "ERROR: Atomic Field " + f.toString() + " is not final or transient." );
}
Atom sub = (Atom) f.get( parent );
if( sub == null )
{
// TODO: replace with exception
Log.error( "WARNING: Atomic Field " + f.toString() + " has a value of null, which isn't useful" );
continue;
}
fs.processField( f, parent, sub );
}
}
catch( Exception e )
{
Log.error( "Factory", e );
throw new UnexpectedResult( e ); // this line temporary
}
}
}
}
{
Class root;
root = start.getSuperclass();
if( root != Atom.class && root != null )
{
processFields( root, parent, fs );
}
}
}
public static final OnConstruct CONSTRUCTER = new OnConstruct();
public static final DecrementImplicitRefs DECREMENTER = new DecrementImplicitRefs();
public static final IncrementImplicitRefs INCREMENTER = new IncrementImplicitRefs();
public static final DistinctSyncer DISTINCT_SYNCER = new DistinctSyncer();
public static final NonTemporary NON_TEMPORARY = new NonTemporary();
public static final PartDeleter PART_DELETER = new PartDeleter();
public static final SyncOwner SYNC_OWNER = new SyncOwner();
public static final SyncOwnerRecursive SYNC_OWNER_R = new SyncOwnerRecursive();
public static final String tempFileExtension = ".tmp";
}
interface FieldScanner
{
public void processField( Field f, Atom parent, Atom sub );
}
class OnConstruct implements FieldScanner
{
public void processField( Field f, Atom parent, Atom sub )
{
sub.owner = parent.owner;
sub.setKey( f.getName() );
sub.setParent( parent, AtomicElement.PARENT_TYPE );
sub.addReference( parent );
}
}
class DecrementImplicitRefs implements FieldScanner
{
public void processField( Field f, Atom parent, Atom sub )
{
sub.removeReference( parent );
}
}
/**
* the opposite of decrementImplicitRefs, but not to be used for
* creation, only for loading. Typically called from Key.loadObject
*/
class IncrementImplicitRefs implements FieldScanner
{
public void processField( Field f, Atom parent, Atom sub )
{
sub.addReference( parent );
}
}
class DistinctSyncer implements FieldScanner
{
public void processField( Field f, Atom parent, Atom sub )
{
Registry.instance.syncDistinct( sub.index, sub.timestamp );
}
}
class NonTemporary implements FieldScanner
{
public void processField( Field f, Atom parent, Atom sub )
{
sub.stopBeingTemporary();
}
}
class PartDeleter implements FieldScanner
{
public void processField( Field f, Atom parent, Atom sub )
{
Registry.instance.delete( sub );
}
}
class SyncOwner implements FieldScanner
{
public void processField( Field f, Atom parent, Atom sub )
{
sub.setOwner( parent.getOwner() );
}
}
class SyncOwnerRecursive implements FieldScanner
{
public void processField( Field f, Atom parent, Atom sub )
{
sub.setRecursiveOwner( parent.getOwner() );
}
}