package ecologylab.io;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.security.AccessController;
import java.security.PrivilegedAction;
import ecologylab.generic.Debug;
/**
* Utility class for managing memory mapped buffers.
*
* @author wolf
*/
public class NIOTools extends Debug
{
/**
* The logger for reporting io problems
*/
private static boolean warned;
/**
* Really closes a MappedByteBuffer without the need to wait for garbage collection. Any problems
* with closing a buffer on Windows (the problem child in this case) will be logged as SEVERE to
* the logger of the package name. To force logging of errors, set the System property
* "org.geotools.io.debugBuffer" to "true".
*
* @param buffer
* See MappedByteBuffer
* @return true if the operation was successful, false otherwise.
*/
public static boolean clean(final java.nio.ByteBuffer buffer)
{
if (buffer == null || !buffer.isDirect())
return false;
Boolean b = (Boolean) AccessController.doPrivileged(new PrivilegedAction()
{
@Override
public Object run()
{
Boolean success = Boolean.FALSE;
try
{
Method getCleanerMethod = buffer.getClass().getMethod("cleaner", null);
getCleanerMethod.setAccessible(true);
Object cleaner = getCleanerMethod.invoke(buffer, null);
Method clean = cleaner.getClass().getMethod("clean", null);
clean.invoke(cleaner, null);
success = Boolean.TRUE;
}
catch (Exception e)
{
if (!warned)
log(e, buffer);
}
return success;
}
});
return b.booleanValue();
}
private static void log(Exception e, java.nio.ByteBuffer buffer)
{
warned = true;
String message = "NIOTools: Error attempting to close a mapped byte buffer : "
+ buffer.getClass().getName();
message += "\n JVM : " + System.getProperty("java.version") + " "
+ System.getProperty("java.vendor");
Debug.println(message);
}
public static boolean writeMemoryMapped(File file, StringBuilder buffy)
{
boolean ok = true;
RandomAccessFile rFile = null;
MappedByteBuffer mMapBuffer = null;
try
{
rFile = new RandomAccessFile(file, "rw");
FileChannel fileChannel = rFile.getChannel();
int length = buffy.length();
mMapBuffer = fileChannel.map(FileChannel.MapMode.PRIVATE, 0, length);
fileChannel.close();
// TODO could write XmlTools.xmlHeader() here
for (int i = 0; i < length; i++)
mMapBuffer.put((byte) buffy.charAt(i));
rFile.close();
clean(mMapBuffer);
}
catch (IOException e)
{
e.printStackTrace();
ok = false;
}
/*
* finally { try { if (rFile != null) rFile.close(); } catch (IOException e) {
* e.printStackTrace(); } if (mMapBuffer != null) clean(mMapBuffer); }
*/
return ok;
}
static final int BUFFER_SIZE = 1024;
static final ByteBuffer byteBuffer = ByteBuffer.allocateDirect(BUFFER_SIZE);
public static boolean writeFile(File file, StringBuilder buffy)
{
boolean ok = true;
FileOutputStream oStream = null;
try
{
oStream = new FileOutputStream(file);
FileChannel fileChannel = oStream.getChannel();
int length = buffy.length();
// TODO could write XmlTools.xmlHeader() here
int buffyIndex = 0;
for (buffyIndex = 0; buffyIndex < length; buffyIndex += BUFFER_SIZE)
{
writeABuffer(fileChannel, buffy, buffyIndex, BUFFER_SIZE);
// TODO -- deal with how this will drop bytes at the end
}
if (buffyIndex > length)
{
buffyIndex -= BUFFER_SIZE;
int lastCount = length - buffyIndex;
// writeABuffer(fileChannel, buffy, buffyIndex, lastCount);
}
fileChannel.close();
}
catch (IOException e)
{
e.printStackTrace();
ok = false;
}
return ok;
}
private static void writeABuffer(FileChannel fileChannel, StringBuilder buffy, int index,
int length) throws IOException
{
for (int i = 0; i < length; i++)
byteBuffer.put((byte) buffy.charAt(index));
fileChannel.write(byteBuffer);
byteBuffer.clear();
}
}