1 /* 2 * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.xml.internal.org.jvnet.mimepull; 27 28 import java.io.File; 29 import java.io.IOException; 30 import java.io.RandomAccessFile; 31 import java.lang.ref.ReferenceQueue; 32 import java.lang.ref.WeakReference; 33 import java.util.ArrayList; 34 import java.util.List; 35 import java.util.concurrent.Executor; 36 import java.util.logging.Level; 37 import java.util.logging.Logger; 38 39 /** 40 * Removing files based on this 41 * <a href="http://java.sun.com/developer/technicalArticles/javase/finalization/">article</a> 42 * 43 * @author Jitendra Kotamraju 44 */ 45 final class WeakDataFile extends WeakReference<DataFile> { 46 47 private static final Logger LOGGER = Logger.getLogger(WeakDataFile.class.getName()); 48 //private static final int MAX_ITERATIONS = 2; 49 private static ReferenceQueue<DataFile> refQueue = new ReferenceQueue<DataFile>(); 50 private static List<WeakDataFile> refList = new ArrayList<WeakDataFile>(); 51 private final File file; 52 private final RandomAccessFile raf; 53 private static boolean hasCleanUpExecutor = false; 54 static { 55 CleanUpExecutorFactory executorFactory = CleanUpExecutorFactory.newInstance(); 56 if (executorFactory!=null) { 57 if (LOGGER.isLoggable(Level.FINE)) { 58 LOGGER.log(Level.FINE, "Initializing clean up executor for MIMEPULL: {0}", executorFactory.getClass().getName()); 59 } 60 Executor executor = executorFactory.getExecutor(); 61 executor.execute(new Runnable() { 62 @Override 63 public void run() { 64 WeakDataFile weak; 65 while (true) { 66 try { 67 weak = (WeakDataFile) refQueue.remove(); 68 if (LOGGER.isLoggable(Level.FINE)) { 69 LOGGER.log(Level.FINE, "Cleaning file = {0} from reference queue.", weak.file); 70 } 71 weak.close(); 72 } catch (InterruptedException e) { 73 } 74 } 75 } 76 }); 77 hasCleanUpExecutor = true; 78 } 79 } 80 81 WeakDataFile(DataFile df, File file) { 82 super(df, refQueue); 83 refList.add(this); 84 this.file = file; 85 try { 86 raf = new RandomAccessFile(file, "rw"); 87 } catch(IOException ioe) { 88 throw new MIMEParsingException(ioe); 89 } 90 if (!hasCleanUpExecutor) { 91 drainRefQueueBounded(); 92 } 93 } 94 95 synchronized void read(long pointer, byte[] buf, int offset, int length ) { 96 try { 97 raf.seek(pointer); 98 raf.readFully(buf, offset, length); 99 } catch(IOException ioe) { 100 throw new MIMEParsingException(ioe); 101 } 102 } 103 104 synchronized long writeTo(long pointer, byte[] data, int offset, int length) { 105 try { 106 raf.seek(pointer); 107 raf.write(data, offset, length); 108 return raf.getFilePointer(); // Update pointer for next write 109 } catch(IOException ioe) { 110 throw new MIMEParsingException(ioe); 111 } 112 } 113 114 void close() { 115 if (LOGGER.isLoggable(Level.FINE)) { 116 LOGGER.log(Level.FINE, "Deleting file = {0}", file.getName()); 117 } 118 refList.remove(this); 119 try { 120 raf.close(); 121 boolean deleted = file.delete(); 122 if (!deleted) { 123 if (LOGGER.isLoggable(Level.INFO)) { 124 LOGGER.log(Level.INFO, "File {0} was not deleted", file.getAbsolutePath()); 125 } 126 } 127 } catch(IOException ioe) { 128 throw new MIMEParsingException(ioe); 129 } 130 } 131 132 void renameTo(File f) { 133 if (LOGGER.isLoggable(Level.FINE)) { 134 LOGGER.log(Level.FINE, "Moving file={0} to={1}", new Object[]{file, f}); 135 } 136 refList.remove(this); 137 try { 138 raf.close(); 139 boolean renamed = file.renameTo(f); 140 if (!renamed) { 141 if (LOGGER.isLoggable(Level.INFO)) { 142 LOGGER.log(Level.INFO, "File {0} was not moved to {1}", new Object[] {file.getAbsolutePath(), f.getAbsolutePath()}); 143 } 144 } 145 } catch(IOException ioe) { 146 throw new MIMEParsingException(ioe); 147 } 148 149 } 150 151 static void drainRefQueueBounded() { 152 WeakDataFile weak; 153 while (( weak = (WeakDataFile) refQueue.poll()) != null ) { 154 if (LOGGER.isLoggable(Level.FINE)) { 155 LOGGER.log(Level.FINE, "Cleaning file = {0} from reference queue.", weak.file); 156 } 157 weak.close(); 158 } 159 } 160 }