/** * A component of a library for * GENESIS * Copyright (C) 2008 * Andy Turner, * University of Leeds. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ package uk.ac.leeds.ccg.andyt.projects.genesis.utilities; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; /** * An abstract class to be extended by classes that are required to * handle runtime errors such as java.lang.OutOfMemroyError. * * @author Andy Turner * @version 1.0.0, 2008-10-10 */ public abstract class ErrorHandler implements Serializable { private static final long serialVersionUID = 1L; /** * Directory for swapping data to. */ private File directory; /** * A HashMap storing class.getName() as keys and * the numbers of caches swapped of that class as values. */ private HashMap numberOfCachesSwappedAsFilesHashMap; /** * Reserve memory. This is to be cleared when dealing with OutOfMemoryErrors. */ private transient int[] memoryReserve; //public transient int[] memoryReserve; /** * Initialises this.memoryReserve as an int[] of length size. * @param size The length that this.memoryReserve is initialised as. */ public final void initMemoryReserve( int size ) { //log( "initMemoryReserve( " + size + " )" ); this.memoryReserve = new int[ size ]; Arrays.fill( this.memoryReserve, Integer.MIN_VALUE ); System.gc(); } /** * Initialises memoryReserve as an array of size 3000000. * Enough memory is needed for swapping data to this.directory */ public final void initMemoryReserve() { initMemoryReserve( 3000000 ); } /** * Clears memoryReserve by setting it to null and calling the garbage * collector. */ public final void clearMemoryReserve() { //System.gc(); //log(Runtime.getRuntime().freeMemory()); this.memoryReserve = null; System.gc(); //log(Runtime.getRuntime().freeMemory()); } /** * If aHashSetSerializable.isEmpty() this does nothing and returns null. * Otherwise aHashSetSerializable is swapped to a File * which is returned. */ protected File swapToFile( HashSet _HashSet ) { //throws IOException { if ( _HashSet.isEmpty() ) { return null; } else { String type = _HashSet.getClass().getName(); if ( true ) { Iterator aHashSetSerializableIterator = _HashSet.iterator(); type += aHashSetSerializableIterator.next().getClass().getName(); } int numberOfCachesSwappedAsFiles = ( Integer ) this.numberOfCachesSwappedAsFilesHashMap.get( type ); numberOfCachesSwappedAsFiles ++; this.numberOfCachesSwappedAsFilesHashMap.put( type, numberOfCachesSwappedAsFiles ); File aFile = FileCreator.createNewFile( this.directory, type + Integer.toString( numberOfCachesSwappedAsFiles ) ); try { ObjectOutputStream aObjectOutputStream = new ObjectOutputStream( new BufferedOutputStream( new FileOutputStream( aFile ) ) ); aObjectOutputStream.writeObject( _HashSet ); aObjectOutputStream.flush(); aObjectOutputStream.close(); } catch ( IOException aIOException ) { aIOException.printStackTrace(); //throw ioe0; } return aFile; } } /** * If aHashMap.isEmpty() this does nothing and returns null. * Otherwise aHashMap is swapped to a File * which is returned. */ protected File swapToFile( HashMap aHashMap ) { //throws IOException { if ( aHashMap.isEmpty() ) { return null; } else { String type = aHashMap.getClass().getName(); if ( true ) { Iterator aHashMapKeySetIterator = aHashMap.keySet().iterator(); type += aHashMapKeySetIterator.next().getClass().getName(); Iterator aHashMapValuesIterator = aHashMap.values().iterator(); type += aHashMapValuesIterator.next().getClass().getName(); } int numberOfCachesSwappedAsFiles = ( Integer ) this.numberOfCachesSwappedAsFilesHashMap.get( type ); numberOfCachesSwappedAsFiles ++; this.numberOfCachesSwappedAsFilesHashMap.put( type, numberOfCachesSwappedAsFiles ); File aFile = FileCreator.createNewFile( this.directory, type + Integer.toString( numberOfCachesSwappedAsFiles ) ); try { ObjectOutputStream aObjectOutputStream = new ObjectOutputStream( new BufferedOutputStream( new FileOutputStream( aFile ) ) ); aObjectOutputStream.writeObject( aHashMap ); aObjectOutputStream.flush(); aObjectOutputStream.close(); } catch ( IOException aIOException ) { aIOException.printStackTrace(); //throw ioe0; } return aFile; } } /** * A method to write this instance to Files located in this.directory. * @param handleOutOfMemoryError * If true then OutOfMemoryErrors are caught, swap operations are initiated, * then the method is re-called. * If false then OutOfMemoryErrors are caught and thrown. */ public final File writeToFile( boolean handleOutOfMemoryError ) throws IOException { try { return writeToFile(); } catch ( OutOfMemoryError oome0 ) { if ( handleOutOfMemoryError ) { return writeToFile( handleOutOfMemoryError ); } else { throw oome0; } } } /** * A method to write this instance to a File located in the directory returned by * getDirectory(). */ protected File writeToFile() throws IOException { // Write out this. String filename = this.getClass().getName(); File file = new File( getDirectory(), filename + ".thisFile" ); //System.out.println("Writing out to " + file.toURL().toString() ); ObjectOutputStream aObjectOutputStream = new ObjectOutputStream( new BufferedOutputStream( new FileOutputStream( file ) ) ); aObjectOutputStream.writeObject( this ); aObjectOutputStream.flush(); aObjectOutputStream.close(); return file; } /** * A method to write this instance to a File located in the directory returned by * getDirectory(). * @param objectToWrite The object to be written */ protected void writeToFile( Object objectToWrite, File aFileToWriteTo ) throws IOException { ObjectOutputStream aObjectOutputStream = new ObjectOutputStream( new BufferedOutputStream( new FileOutputStream( aFileToWriteTo ) ) ); aObjectOutputStream.writeObject( objectToWrite ); aObjectOutputStream.flush(); aObjectOutputStream.close(); } /** * Loads an Object from aFile File. * @param aFile The File from which the ObjectObjectnullObject from aObjectInputStream ObjectInputStream. * @param aObjectInputStream The ObjectInputStream from which the ObjectObjectnullthis.directory */ public final File getDirectory() { return this.directory; } /** * Sets this.directory to directory. * N.B. No checks are done on directory to ensure it is viable for use. */ protected final void setDirectory( File directory ) { this.directory = directory; } /** * @return this.memoryReserve */ protected final int[] getMemoryReserve() { return this.memoryReserve; } /** * Sets this.memoryReserve to memoryReserve. */ protected final void setMemoryReserve( int[] memoryReserve ) { this.memoryReserve = memoryReserve; } /** * @return this.numberOfCachesSwappedAsFilesHashMap */ protected final HashMap getNumberOfCachesSwappedAsFilesHashMap() { return this.numberOfCachesSwappedAsFilesHashMap; } /** * Sets this.numberOfCachesSwappedAsFilesHashMap to numberOfCachesSwappedAsFilesHashMap. */ protected final void setNumberOfCachesSwappedAsFilesHashMap( HashMap numberOfCachesSwappedAsFilesHashMap ) { this.numberOfCachesSwappedAsFilesHashMap = numberOfCachesSwappedAsFilesHashMap; } }