/* ** 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() ); } }