import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Writer;

public class WriterMain {

	public static void main(String[] args) throws IOException {
		File f = new File("temp");
		f.deleteOnExit();
		FileOutputStream fos = new FileOutputStream(f);
		PrintWriter writer = new PrintWriter(fos);
		
		fos.close();
		writer.write("bla");
	}
	
	static aspect WriterChecker {
		
		/*
		 * This aspect checks if a writer is created for an output stream,
		 * neither the stream nor the writer were closed when writing to either of the two.   
		 */
		
		pointcut createWriter(OutputStream os):
			call(Writer+.new(OutputStream+,..)) && args(os,..);
		
		tracematch(Writer w, OutputStream os) {
			
			sym create after returning(w): createWriter(os);
			
			sym closeW before: call(* close()) && target(w);
			sym closeO before: call(* close()) && target(os);
			
			sym writeW before: (call(* write(..)) || call(* print*(..))) && target(w);
			sym writeO before: call(* write(..)) && target(os);
			
			create (closeW|closeO) (writeW|writeO) {
				throw new IllegalStateException("Attempting to write to closed stream/writer.");
			}
		}

	}
}
