123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447 |
- /*
- Copyright (c) 2012 James Ahlborn
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
- package com.healthmarketscience.jackcess;
-
- import java.io.File;
- import java.io.IOException;
- import java.nio.channels.FileChannel;
- import java.nio.charset.Charset;
- import java.nio.file.Path;
- import java.text.SimpleDateFormat;
- import java.util.Calendar;
- import java.util.Date;
- import java.util.GregorianCalendar;
- import java.util.HashMap;
- import java.util.Map;
- import java.util.TimeZone;
-
- import com.healthmarketscience.jackcess.impl.CodecProvider;
- import com.healthmarketscience.jackcess.impl.DatabaseImpl;
- import com.healthmarketscience.jackcess.impl.PropertyMapImpl;
- import com.healthmarketscience.jackcess.util.MemFileChannel;
-
- /**
- * Builder style class for opening/creating a {@link Database}.
- * <p>
- * Simple example usage:
- * <pre>
- * Database db = DatabaseBuilder.open(new File("test.mdb"));
- * </pre>
- * <p>
- * Advanced example usage:
- * <pre>
- * Database db = new DatabaseBuilder(new File("test.mdb"))
- * .setReadOnly(true)
- * .open();
- * </pre>
- *
- * @author James Ahlborn
- * @usage _general_class_
- */
- public class DatabaseBuilder
- {
- /** the file name of the mdb to open/create */
- private Path _mdbFile;
- /** whether or not to open existing mdb read-only */
- private boolean _readOnly;
- /** whether or not to auto-sync writes to the filesystem */
- private boolean _autoSync = Database.DEFAULT_AUTO_SYNC;
- /** optional charset for mdbs with unspecified charsets */
- private Charset _charset;
- /** optional timezone override for interpreting dates */
- private TimeZone _timeZone;
- /** optional CodecProvider for handling encoded mdbs */
- private CodecProvider _codecProvider;
- /** FileFormat to use when creating a new mdb */
- private Database.FileFormat _fileFormat;
- /** optional pre-opened FileChannel, will _not_ be closed by Database
- close */
- private FileChannel _channel;
- /** database properties (if any) */
- private Map<String,PropertyMap.Property> _dbProps;
- /** database summary properties (if any) */
- private Map<String,PropertyMap.Property> _summaryProps;
- /** database user-defined (if any) */
- private Map<String,PropertyMap.Property> _userProps;
-
-
- public DatabaseBuilder() {
- this((Path)null);
- }
-
- public DatabaseBuilder(File mdbFile) {
- this(toPath(mdbFile));
- }
-
- public DatabaseBuilder(Path mdbFile) {
- _mdbFile = mdbFile;
- }
-
- /**
- * File containing an existing database for {@link #open} or target file for
- * new database for {@link #create} (in which case, <b>tf this file already
- * exists, it will be overwritten.</b>)
- * @usage _general_method_
- */
- public DatabaseBuilder setFile(File mdbFile) {
- return setPath(toPath(mdbFile));
- }
-
- /**
- * File containing an existing database for {@link #open} or target file for
- * new database for {@link #create} (in which case, <b>tf this file already
- * exists, it will be overwritten.</b>)
- * @usage _general_method_
- */
- public DatabaseBuilder setPath(Path mdbFile) {
- _mdbFile = mdbFile;
- return this;
- }
-
- /**
- * Sets flag which, iff {@code true}, will force opening file in
- * read-only mode ({@link #open} only).
- * @usage _general_method_
- */
- public DatabaseBuilder setReadOnly(boolean readOnly) {
- _readOnly = readOnly;
- return this;
- }
-
- /**
- * Sets whether or not to enable auto-syncing on write. if {@code true},
- * write operations will be immediately flushed to disk upon completion.
- * This leaves the database in a (fairly) consistent state on each write,
- * but can be very inefficient for many updates. if {@code false}, flushing
- * to disk happens at the jvm's leisure, which can be much faster, but may
- * leave the database in an inconsistent state if failures are encountered
- * during writing. Writes may be flushed at any time using {@link
- * Database#flush}.
- * @usage _intermediate_method_
- */
- public DatabaseBuilder setAutoSync(boolean autoSync) {
- _autoSync = autoSync;
- return this;
- }
-
- /**
- * Sets the Charset to use, if {@code null}, uses default.
- * @usage _intermediate_method_
- */
- public DatabaseBuilder setCharset(Charset charset) {
- _charset = charset;
- return this;
- }
-
- /**
- * Sets the TimeZone to use for interpreting dates, if {@code null}, uses
- * default
- * @usage _intermediate_method_
- */
- public DatabaseBuilder setTimeZone(TimeZone timeZone) {
- _timeZone = timeZone;
- return this;
- }
-
- /**
- * Sets the CodecProvider for handling page encoding/decoding, may be
- * {@code null} if no special encoding is necessary
- * @usage _intermediate_method_
- */
- public DatabaseBuilder setCodecProvider(CodecProvider codecProvider) {
- _codecProvider = codecProvider;
- return this;
- }
-
- /**
- * Sets the version of new database ({@link #create} only).
- * @usage _general_method_
- */
- public DatabaseBuilder setFileFormat(Database.FileFormat fileFormat) {
- _fileFormat = fileFormat;
- return this;
- }
-
- /**
- * Sets a pre-opened FileChannel. if provided explicitly, <i>it will not be
- * closed by the Database instance</i>. This allows ultimate control of
- * where the mdb file exists (which may not be on disk, e.g.
- * {@link MemFileChannel}). If provided, the File parameter will be
- * available from {@link Database#getFile}, but otherwise ignored.
- * @usage _advanced_method_
- */
- public DatabaseBuilder setChannel(FileChannel channel) {
- _channel = channel;
- return this;
- }
-
- /**
- * Sets the database property with the given name to the given value.
- * Attempts to determine the type of the property (see
- * {@link PropertyMap#put(String,Object)} for details on determining the
- * property type).
- */
- public DatabaseBuilder putDatabaseProperty(String name, Object value) {
- return putDatabaseProperty(name, null, value);
- }
-
- /**
- * Sets the database property with the given name and type to the given
- * value.
- */
- public DatabaseBuilder putDatabaseProperty(String name, DataType type,
- Object value) {
- _dbProps = putProperty(_dbProps, name, type, value);
- return this;
- }
-
- /**
- * Sets the summary database property with the given name to the given
- * value. Attempts to determine the type of the property (see
- * {@link PropertyMap#put(String,Object)} for details on determining the
- * property type).
- */
- public DatabaseBuilder putSummaryProperty(String name, Object value) {
- return putSummaryProperty(name, null, value);
- }
-
- /**
- * Sets the summary database property with the given name and type to
- * the given value.
- */
- public DatabaseBuilder putSummaryProperty(String name, DataType type,
- Object value) {
- _summaryProps = putProperty(_summaryProps, name, type, value);
- return this;
- }
-
- /**
- * Sets the user-defined database property with the given name to the given
- * value. Attempts to determine the type of the property (see
- * {@link PropertyMap#put(String,Object)} for details on determining the
- * property type).
- */
- public DatabaseBuilder putUserDefinedProperty(String name, Object value) {
- return putUserDefinedProperty(name, null, value);
- }
-
- /**
- * Sets the user-defined database property with the given name and type to
- * the given value.
- */
- public DatabaseBuilder putUserDefinedProperty(String name, DataType type,
- Object value) {
- _userProps = putProperty(_userProps, name, type, value);
- return this;
- }
-
- private static Map<String,PropertyMap.Property> putProperty(
- Map<String,PropertyMap.Property> props, String name, DataType type,
- Object value)
- {
- if(props == null) {
- props = new HashMap<String,PropertyMap.Property>();
- }
- props.put(name, PropertyMapImpl.createProperty(name, type, value));
- return props;
- }
-
- /**
- * Opens an existingnew Database using the configured information.
- */
- public Database open() throws IOException {
- return DatabaseImpl.open(_mdbFile, _readOnly, _channel, _autoSync, _charset,
- _timeZone, _codecProvider);
- }
-
- /**
- * Creates a new Database using the configured information.
- */
- public Database create() throws IOException {
- Database db = DatabaseImpl.create(_fileFormat, _mdbFile, _channel, _autoSync,
- _charset, _timeZone);
- if(_dbProps != null) {
- PropertyMap props = db.getDatabaseProperties();
- props.putAll(_dbProps.values());
- props.save();
- }
- if(_summaryProps != null) {
- PropertyMap props = db.getSummaryProperties();
- props.putAll(_summaryProps.values());
- props.save();
- }
- if(_userProps != null) {
- PropertyMap props = db.getUserDefinedProperties();
- props.putAll(_userProps.values());
- props.save();
- }
- return db;
- }
-
- /**
- * Open an existing Database. If the existing file is not writeable, the
- * file will be opened read-only. Auto-syncing is enabled for the returned
- * Database.
- *
- * @param mdbFile File containing the database
- *
- * @see DatabaseBuilder for more flexible Database opening
- * @usage _general_method_
- */
- public static Database open(File mdbFile) throws IOException {
- return new DatabaseBuilder(mdbFile).open();
- }
-
- /**
- * Open an existing Database. If the existing file is not writeable, the
- * file will be opened read-only. Auto-syncing is enabled for the returned
- * Database.
- *
- * @param mdbFile File containing the database
- *
- * @see DatabaseBuilder for more flexible Database opening
- * @usage _general_method_
- */
- public static Database open(Path mdbFile) throws IOException {
- return new DatabaseBuilder(mdbFile).open();
- }
-
- /**
- * Create a new Database for the given fileFormat
- *
- * @param fileFormat version of new database.
- * @param mdbFile Location to write the new database to. <b>If this file
- * already exists, it will be overwritten.</b>
- *
- * @see DatabaseBuilder for more flexible Database creation
- * @usage _general_method_
- */
- public static Database create(Database.FileFormat fileFormat, File mdbFile)
- throws IOException
- {
- return new DatabaseBuilder(mdbFile).setFileFormat(fileFormat).create();
- }
-
- /**
- * Returns a SimpleDateFormat for the given format string which is
- * configured with a compatible Calendar instance (see
- * {@link #toCompatibleCalendar}).
- */
- public static SimpleDateFormat createDateFormat(String formatStr) {
- SimpleDateFormat sdf = new SimpleDateFormat(formatStr);
- toCompatibleCalendar(sdf.getCalendar());
- return sdf;
- }
-
- /**
- * Ensures that the given {@link Calendar} is configured to be compatible
- * with how Access handles dates. Specifically, alters the gregorian change
- * (the java default gregorian change switches to julian dates for dates pre
- * 1582-10-15, whereas Access uses <a href="https://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar">proleptic gregorian dates</a>).
- */
- public static Calendar toCompatibleCalendar(Calendar cal) {
- if(cal instanceof GregorianCalendar) {
- ((GregorianCalendar)cal).setGregorianChange(new Date(Long.MIN_VALUE));
- }
- return cal;
- }
-
- /**
- * Convenience method for constructing a DatabaseBuilder.
- */
- public static DatabaseBuilder newDatabase() {
- return new DatabaseBuilder();
- }
-
- /**
- * Convenience method for constructing a DatabaseBuilder.
- */
- public static DatabaseBuilder newDatabase(Path path) {
- return new DatabaseBuilder(path);
- }
-
- /**
- * Convenience method for constructing a DatabaseBuilder.
- */
- public static DatabaseBuilder newDatabase(File file) {
- return new DatabaseBuilder(file);
- }
-
- /**
- * Convenience method for constructing a TableBuilder.
- */
- public static TableBuilder newTable(String name) {
- return new TableBuilder(name);
- }
-
- /**
- * Convenience method for constructing a TableBuilder.
- */
- public static TableBuilder newTable(String name, boolean escapeIdentifiers) {
- return new TableBuilder(name, escapeIdentifiers);
- }
-
- /**
- * Convenience method for constructing a ColumnBuilder.
- */
- public static ColumnBuilder newColumn(String name) {
- return new ColumnBuilder(name);
- }
-
- /**
- * Convenience method for constructing a TableBuilder.
- */
- public static ColumnBuilder newColumn(String name, DataType type) {
- return new ColumnBuilder(name, type);
- }
-
- /**
- * Convenience method for constructing an IndexBuilder.
- */
- public static IndexBuilder newIndex(String name) {
- return new IndexBuilder(name);
- }
-
- /**
- * Convenience method for constructing a primary key IndexBuilder.
- */
- public static IndexBuilder newPrimaryKey(String... colNames) {
- return new IndexBuilder(IndexBuilder.PRIMARY_KEY_NAME)
- .addColumns(colNames)
- .setPrimaryKey();
- }
-
- /**
- * Convenience method for constructing a RelationshipBuilder.
- */
- public static RelationshipBuilder newRelationship(
- String fromTable, String toTable) {
- return new RelationshipBuilder(fromTable, toTable);
- }
-
- /**
- * Convenience method for constructing a RelationshipBuilder.
- */
- public static RelationshipBuilder newRelationship(
- Table fromTable, Table toTable) {
- return new RelationshipBuilder(fromTable, toTable);
- }
-
- private static Path toPath(File file) {
- return ((file != null) ? file.toPath() : null);
- }
- }
|