import java.io.FileNotFoundException;
import java.io.Flushable;
import java.io.IOException;
+import java.io.InputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
+import java.nio.channels.ReadableByteChannel;
import java.nio.charset.Charset;
import java.sql.ResultSet;
import java.sql.SQLException;
but leaves more chance of a useable database in the face of failures. */
public static final boolean DEFAULT_AUTO_SYNC = true;
- /** system property which can be used to make big index support the
- default. */
+ /** the default value for the resource path used to load classpath
+ resources. */
+ public static final String DEFAULT_RESOURCE_PATH =
+ "com/healthmarketscience/jackcess/";
+
+ /** (boolean) system property which can be used to disable the default big
+ index support. */
public static final String USE_BIG_INDEX_PROPERTY =
"com.healthmarketscience.jackcess.bigIndex";
public static final String CHARSET_PROPERTY_PREFIX =
"com.healthmarketscience.jackcess.charset.";
+ /** system property which can be used to set the path from which classpath
+ resources are loaded (must end with a "/" if non-empty). Default value
+ is {@link #DEFAULT_RESOURCE_PATH} if unspecified. */
+ public static final String RESOURCE_PATH_PROPERTY =
+ "com.healthmarketscience.jackcess.resourcePath";
+
+ /** (boolean) system property which can be used to indicate that the current
+ vm has a poor nio implementation (specifically for
+ FileChannel.transferFrom) */
+ public static final String BROKEN_NIO_PROPERTY =
+ "com.healthmarketscience.jackcess.brokenNio";
+
/** default error handler used if none provided (just rethrows exception) */
public static final ErrorHandler DEFAULT_ERROR_HANDLER = new ErrorHandler() {
public Object handleRowError(Column column,
throw (RuntimeException)error;
}
};
+
+ /** the resource path to be used when loading classpath resources */
+ static final String RESOURCE_PATH =
+ System.getProperty(RESOURCE_PATH_PROPERTY, DEFAULT_RESOURCE_PATH);
+
+ /** whether or not this jvm has "broken" nio support */
+ static final boolean BROKEN_NIO = Boolean.TRUE.toString().equalsIgnoreCase(
+ System.getProperty(BROKEN_NIO_PROPERTY));
/** System catalog always lives on page 2 */
private static final int PAGE_SYSTEM_CATALOG = 2;
private static final String CAT_COL_FLAGS = "Flags";
/** System catalog column name of the properties column */
private static final String CAT_COL_PROPS = "LvProp";
+
+ /** the maximum size of any of the included "empty db" resources */
+ private static final long MAX_EMPTYDB_SIZE = 320000L;
public static enum FileFormat {
V1997(null, JetFormat.VERSION_3),
- V2000("com/healthmarketscience/jackcess/empty.mdb", JetFormat.VERSION_4),
- V2003("com/healthmarketscience/jackcess/empty2003.mdb", JetFormat.VERSION_4),
- V2007("com/healthmarketscience/jackcess/empty2007.accdb", JetFormat.VERSION_5, ".accdb"),
+ V2000(RESOURCE_PATH + "empty.mdb", JetFormat.VERSION_4),
+ V2003(RESOURCE_PATH + "empty2003.mdb", JetFormat.VERSION_4),
+ V2007(RESOURCE_PATH + "empty2007.accdb", JetFormat.VERSION_5, ".accdb"),
MSISAM(null, JetFormat.VERSION_MSISAM, ".mny");
private final String _emptyFile;
FileChannel channel = openChannel(mdbFile, false);
channel.truncate(0);
- channel.transferFrom(Channels.newChannel(
- Thread.currentThread().getContextClassLoader().getResourceAsStream(
- fileFormat._emptyFile)), 0, Integer.MAX_VALUE);
+ transferFrom(channel, Thread.currentThread().getContextClassLoader()
+ .getResourceAsStream(fileFormat._emptyFile));
return new Database(channel, autoSync, fileFormat, charset, timeZone,
null);
}
return format.CHARSET;
}
+ /**
+ * Copies the given InputStream to the given channel using the most
+ * efficient means possible.
+ */
+ private static void transferFrom(FileChannel channel, InputStream in)
+ throws IOException
+ {
+ ReadableByteChannel readChannel = Channels.newChannel(in);
+ if(!BROKEN_NIO) {
+ // sane implementation
+ channel.transferFrom(readChannel, 0, MAX_EMPTYDB_SIZE);
+ } else {
+ // do things the hard way for broken vms
+ ByteBuffer bb = ByteBuffer.allocate(8096);
+ while(readChannel.read(bb) >= 0) {
+ bb.flip();
+ channel.write(bb);
+ bb.clear();
+ }
+ }
+ }
+
/**
* Utility class for storing table page number and actual name.
*/
}
}
+ /** the JetFormat constants for the Jet database version "3" */
+ public static final JetFormat VERSION_3 = new Jet3Format();
+ /** the JetFormat constants for the Jet database version "4" */
+ public static final JetFormat VERSION_4 = new Jet4Format();
+ /** the JetFormat constants for the MSISAM database */
+ public static final JetFormat VERSION_MSISAM = new MSISAMFormat();
+ /** the JetFormat constants for the Jet database version "5" */
+ public static final JetFormat VERSION_5 = new Jet5Format();
+
//These constants are populated by this class's constructor. They can't be
//populated by the subclass's constructor because they are final, and Java
//doesn't allow this; hence all the abstract defineXXX() methods.
public final Charset CHARSET;
- public static final JetFormat VERSION_3 = new Jet3Format();
- public static final JetFormat VERSION_4 = new Jet4Format();
- public static final JetFormat VERSION_MSISAM = new MSISAMFormat();
- public static final JetFormat VERSION_5 = new Jet5Format();
-
/**
* @param channel the database file.
* @return The Jet Format represented in the passed-in file
<faq id="linux">
<question>Does this work on Linux/Unix?</question>
<answer>
- <p>Yep, Jackcess is pure Java. It will work on any
- Java Virtual Machine (1.4+).</p>
+ <p>Yep, Jackcess is pure Java. It will work on any Java Virtual
+ Machine (1.5+).</p>
</answer>
</faq>
</answer>
</faq>
+ <faq id="android">
+ <question>Why do I get an OutOfMemoryError or NullPointerException when
+ creating a new database on the Android platform?</question>
+ <answer>
+ <p>
+ There are 2 issues which need to be dealt with when using Jackcess
+ on the Android platform. The first is that non-class resources need
+ to be in a special location. The second is that the nio
+ implementation has some "weaknesses".
+ </p>
+ <p>
+ The following steps will make Jackcess compatible with the Android
+ platform.
+ <ul>
+ <li>Set the system property "com.healthmarketscience.jackcess.brokenNio=true"</li>
+ <li>Set the system property "com.healthmarketscience.jackcess.resourcePath=/res/raw/"</li>
+ <li>Copy the *.txt, *.mdb, and *.accdb files from the
+ "com/healthmarketscience/jackcess/" directory in the Jackcess
+ jar to the "/res/raw" Android application directory.</li>
+ <li>Before executing any Jackcess code, set the current Thread's
+ context classloader,
+ e.g. "Thread.currentThread().setContextClassLoader(Database.class.getClassLoader())".</li>
+ </ul>
+ </p>
+ </answer>
+ </faq>
+
<faq id="hms">
<question>Who is Health Market Science?</question>
<answer>
Using proprietary matching and consolidation software,
HMS scientifically manufactures the most comprehensive
and accurate healthcare data sets in the market today.
- <a href="http://www.healthmarketscience.com/company/careers.html">We're hiring!</a>
- HMS is always looking for talented individuals.
</p>
</answer>
</faq>