View Javadoc
1   /*
2   Copyright (c) 2013 James Ahlborn
3   
4   Licensed under the Apache License, Version 2.0 (the "License");
5   you may not use this file except in compliance with the License.
6   You may obtain a copy of the License at
7   
8       http://www.apache.org/licenses/LICENSE-2.0
9   
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15  */
16  
17  package com.healthmarketscience.jackcess;
18  
19  import java.io.Closeable;
20  import java.io.File;
21  import java.io.Flushable;
22  import java.io.IOException;
23  import java.nio.charset.Charset;
24  import java.util.ConcurrentModificationException;
25  import java.util.Iterator;
26  import java.util.List;
27  import java.util.Map;
28  import java.util.Set;
29  import java.util.TimeZone;
30  
31  import com.healthmarketscience.jackcess.query.Query;
32  import com.healthmarketscience.jackcess.impl.DatabaseImpl;
33  import com.healthmarketscience.jackcess.util.ColumnValidatorFactory;
34  import com.healthmarketscience.jackcess.util.ErrorHandler;
35  import com.healthmarketscience.jackcess.util.LinkResolver;
36  import com.healthmarketscience.jackcess.util.TableIterableBuilder;
37  
38  /**
39   * An Access database instance.  A new instance can be instantiated by opening
40   * an existing database file ({@link DatabaseBuilder#open(File)}) or creating
41   * a new database file ({@link DatabaseBuilder#create(Database.FileFormat,File)}) (for
42   * more advanced opening/creating use {@link DatabaseBuilder}).  Once a
43   * Database has been opened, you can interact with the data via the relevant
44   * {@link Table}.  When a Database instance is no longer useful, it should
45   * <b>always</b> be closed ({@link #close}) to avoid corruption.
46   * <p/>
47   * Database instances (and all the related objects) are <i>not</i>
48   * thread-safe.  However, separate Database instances (and their respective
49   * objects) can be used by separate threads without a problem.
50   * <p/>
51   * Database instances do not implement any "transactional" support, and
52   * therefore concurrent editing of the same database file by multiple Database
53   * instances (or with outside programs such as MS Access) <i>will generally
54   * result in database file corruption</i>.
55   *
56   * @author James Ahlborn
57   * @usage _general_class_
58   */
59  public interface Database extends Iterable<Table>, Closeable, Flushable
60  {
61    /** default value for the auto-sync value ({@code true}).  this is slower,
62     *  but leaves more chance of a useable database in the face of failures.
63     * @usage _general_field_
64     */
65    public static final boolean DEFAULT_AUTO_SYNC = true;
66  
67    /**
68     * the default sort order for table columns.
69     * @usage _intermediate_field_
70     */
71    public static final Table.ColumnOrder DEFAULT_COLUMN_ORDER = 
72      Table.ColumnOrder.DATA;
73  
74    /** system property which can be used to set the default TimeZone used for
75     *  date calculations.
76     * @usage _general_field_
77     */
78    public static final String TIMEZONE_PROPERTY =
79      "com.healthmarketscience.jackcess.timeZone";
80  
81    /** system property prefix which can be used to set the default Charset
82     *  used for text data (full property includes the JetFormat version).
83     * @usage _general_field_
84     */
85    public static final String CHARSET_PROPERTY_PREFIX =
86      "com.healthmarketscience.jackcess.charset.";
87  
88    /** system property which can be used to set the path from which classpath
89     *  resources are loaded (must end with a "/" if non-empty).  Default value
90     *  is {@value com.healthmarketscience.jackcess.impl.DatabaseImpl#DEFAULT_RESOURCE_PATH}
91     *  if unspecified.
92     * @usage _general_field_
93     */
94    public static final String RESOURCE_PATH_PROPERTY = 
95      "com.healthmarketscience.jackcess.resourcePath";
96  
97    /** (boolean) system property which can be used to indicate that the current
98     *  vm has a poor nio implementation (specifically for
99     *  {@code FileChannel.transferFrom})
100    * @usage _intermediate_field_
101    */
102   public static final String BROKEN_NIO_PROPERTY = 
103     "com.healthmarketscience.jackcess.brokenNio";
104 
105   /** system property which can be used to set the default sort order for
106    *  table columns.  Value should be one {@link Table.ColumnOrder} enum
107    *  values.
108    * @usage _intermediate_field_
109    */
110   public static final String COLUMN_ORDER_PROPERTY = 
111     "com.healthmarketscience.jackcess.columnOrder";
112 
113   /** system property which can be used to set the default enforcement of
114    * foreign-key relationships.  Defaults to {@code true}.
115    * @usage _general_field_
116    */
117   public static final String FK_ENFORCE_PROPERTY = 
118     "com.healthmarketscience.jackcess.enforceForeignKeys";
119 
120   /** system property which can be used to set the default allow auto number
121    * insert policy.  Defaults to {@code false}.
122    * @usage _general_field_
123    */
124   public static final String ALLOW_AUTONUM_INSERT_PROPERTY = 
125     "com.healthmarketscience.jackcess.allowAutoNumberInsert";
126 
127   /**
128    * Enum which indicates which version of Access created the database.
129    * @usage _general_class_
130    */
131   public enum FileFormat {
132 
133     /** A database which was created by MS Access 97 */
134     V1997(".mdb"),
135     /** A database which was most likely created programmatically (e.g. using
136         windows ADOX) */
137     GENERIC_JET4(".mdb"),
138     /** A database which was created by MS Access 2000 */
139     V2000(".mdb"),
140     /** A database which was created by MS Access 2002/2003 */
141     V2003(".mdb"),
142     /** A database which was created by MS Access 2007 */
143     V2007(".accdb"),
144     /** A database which was created by MS Access 2010+ */
145     V2010(".accdb"),
146     /** A database which was created by MS Access 2016+ */
147     V2016(".accdb"),
148     /** A database which was created by MS Money */
149     MSISAM(".mny");
150 
151     private final String _ext;
152 
153     private FileFormat(String ext) {
154       _ext = ext;
155     }
156 
157     /**
158      * @return the file extension used for database files with this format.
159      */
160     public String getFileExtension() { return _ext; }
161 
162     @Override
163     public String toString() { 
164       return name() + " [" + DatabaseImpl.getFileFormatDetails(this).getFormat() + "]";
165     }
166   }
167 
168   /**
169    * Returns the File underlying this Database
170    */
171   public File getFile();
172 
173   /**
174    * @return The names of all of the user tables
175    * @usage _general_method_
176    */
177   public Set<String> getTableNames() throws IOException;
178 
179   /**
180    * @return The names of all of the system tables (String).  Note, in order
181    *         to read these tables, you must use {@link #getSystemTable}.
182    *         <i>Extreme care should be taken if modifying these tables
183    *         directly!</i>.
184    * @usage _intermediate_method_
185    */
186   public Set<String> getSystemTableNames() throws IOException;
187 
188   /**
189    * @return an unmodifiable Iterator of the user Tables in this Database.
190    * @throws RuntimeIOException if an IOException is thrown by one of the
191    *         operations, the actual exception will be contained within
192    * @throws ConcurrentModificationException if a table is added to the
193    *         database while an Iterator is in use.
194    * @usage _general_method_
195    */
196   public Iterator<Table> iterator();
197 
198   /**
199    * Convenience method for constructing a new TableIterableBuilder for this
200    * cursor.  A TableIterableBuilder provides a variety of options for more
201    * flexible iteration of Tables.
202    */
203   public TableIterableBuilder newIterable();
204   
205   /**
206    * @param name User table name (case-insensitive)
207    * @return The Table, or null if it doesn't exist (or is a system table)
208    * @usage _general_method_
209    */
210   public Table getTable(String name) throws IOException;
211 
212   /**
213    * @param name Table name (case-insensitive), may be any table type
214    *             (i.e. includes system or linked tables).
215    * @return The meta data for the table, or null if it doesn't exist
216    * @usage _intermediate_method_
217    */
218   public TableMetaData getTableMetaData(String name) throws IOException;
219 
220   /**
221    * Finds all the relationships in the database between the given tables.
222    * @usage _intermediate_method_
223    */
224   public List<Relationship> getRelationships(Table table1, Table table2)
225     throws IOException;
226 
227   /**
228    * Finds all the relationships in the database for the given table.
229    * @usage _intermediate_method_
230    */
231   public List<Relationship> getRelationships(Table table) throws IOException;
232 
233   /**
234    * Finds all the relationships in the database in <i>non-system</i> tables.
235    * </p>
236    * Warning, this may load <i>all</i> the Tables (metadata, not data) in the
237    * database which could cause memory issues.
238    * @usage _intermediate_method_
239    */
240   public List<Relationship> getRelationships() throws IOException;
241 
242   /**
243    * Finds <i>all</i> the relationships in the database, <i>including system
244    * tables</i>.
245    * </p>
246    * Warning, this may load <i>all</i> the Tables (metadata, not data) in the
247    * database which could cause memory issues.
248    * @usage _intermediate_method_
249    */
250   public List<Relationship> getSystemRelationships()
251     throws IOException;
252 
253   /**
254    * Finds all the queries in the database.
255    * @usage _intermediate_method_
256    */
257   public List<Query> getQueries() throws IOException;
258 
259   /**
260    * Returns a reference to <i>any</i> available table in this access
261    * database, including system tables.
262    * <p>
263    * Warning, this method is not designed for common use, only for the
264    * occassional time when access to a system table is necessary.  Messing
265    * with system tables can strip the paint off your house and give your whole
266    * family a permanent, orange afro.  You have been warned.
267    * 
268    * @param tableName Table name, may be a system table
269    * @return The table, or {@code null} if it doesn't exist
270    * @usage _intermediate_method_
271    */
272   public Table getSystemTable(String tableName) throws IOException;
273 
274   /**
275    * @return the core properties for the database
276    * @usage _general_method_
277    */
278   public PropertyMap getDatabaseProperties() throws IOException;
279 
280   /**
281    * @return the summary properties for the database
282    * @usage _general_method_
283    */
284   public PropertyMap getSummaryProperties() throws IOException;
285 
286   /**
287    * @return the user-defined properties for the database
288    * @usage _general_method_
289    */
290   public PropertyMap getUserDefinedProperties() throws IOException;
291 
292   /**
293    * @return the current database password, or {@code null} if none set.
294    * @usage _general_method_
295    */
296   public String getDatabasePassword() throws IOException;
297 
298   /**
299    * Create a new table in this database
300    * @param name Name of the table to create in this database
301    * @param linkedDbName path to the linked database
302    * @param linkedTableName name of the table in the linked database
303    * @usage _general_method_
304    */
305   public void createLinkedTable(String name, String linkedDbName,
306                                 String linkedTableName)
307     throws IOException;
308 
309   /**
310    * Flushes any current changes to the database file (and any linked
311    * databases) to disk.
312    * @usage _general_method_
313    */
314   public void flush() throws IOException;
315 
316   /**
317    * Close the database file (and any linked databases).  A Database
318    * <b>must</b> be closed after use or changes could be lost and the Database
319    * file corrupted.  A Database instance should be treated like any other
320    * external resource which would be closed in a finally block (e.g. an
321    * OutputStream or jdbc Connection).
322    * @usage _general_method_
323    */
324   public void close() throws IOException;
325 
326   /**
327    * Gets the currently configured ErrorHandler (always non-{@code null}).
328    * This will be used to handle all errors unless overridden at the Table or
329    * Cursor level.
330    * @usage _intermediate_method_
331    */
332   public ErrorHandler getErrorHandler();
333 
334   /**
335    * Sets a new ErrorHandler.  If {@code null}, resets to the
336    * {@link ErrorHandler#DEFAULT}.
337    * @usage _intermediate_method_
338    */
339   public void setErrorHandler(ErrorHandler newErrorHandler);
340 
341   /**
342    * Gets the currently configured LinkResolver (always non-{@code null}).
343    * This will be used to handle all linked database loading.
344    * @usage _intermediate_method_
345    */
346   public LinkResolver getLinkResolver();
347 
348   /**
349    * Sets a new LinkResolver.  If {@code null}, resets to the
350    * {@link LinkResolver#DEFAULT}.
351    * @usage _intermediate_method_
352    */
353   public void setLinkResolver(LinkResolver newLinkResolver);
354 
355   /**
356    * Returns an unmodifiable view of the currently loaded linked databases,
357    * mapped from the linked database file name to the linked database.  This
358    * information may be useful for implementing a LinkResolver.
359    * @usage _intermediate_method_
360    */
361   public Map<String,Database> getLinkedDatabases();
362 
363   
364   /**
365    * Returns {@code true} if this Database links to the given Table, {@code
366    * false} otherwise.
367    * @usage _general_method_
368    */
369   public boolean isLinkedTable(Table table) throws IOException;
370   
371   /**
372    * Gets currently configured TimeZone (always non-{@code null}).
373    * @usage _intermediate_method_
374    */
375   public TimeZone getTimeZone();
376 
377   /**
378    * Sets a new TimeZone.  If {@code null}, resets to the default value.
379    * @usage _intermediate_method_
380    */
381   public void setTimeZone(TimeZone newTimeZone);
382 
383   /**
384    * Gets currently configured Charset (always non-{@code null}).
385    * @usage _intermediate_method_
386    */
387   public Charset getCharset();
388 
389   /**
390    * Sets a new Charset.  If {@code null}, resets to the default value.
391    * @usage _intermediate_method_
392    */
393   public void setCharset(Charset newCharset);
394 
395   /**
396    * Gets currently configured {@link Table.ColumnOrder} (always non-{@code
397    * null}).
398    * @usage _intermediate_method_
399    */
400   public Table.ColumnOrder getColumnOrder();
401 
402   /**
403    * Sets a new Table.ColumnOrder.  If {@code null}, resets to the default value.
404    * @usage _intermediate_method_
405    */
406   public void setColumnOrder(Table.ColumnOrder newColumnOrder);
407 
408   /**
409    * Gets current foreign-key enforcement policy.
410    * @usage _intermediate_method_
411    */
412   public boolean isEnforceForeignKeys();
413 
414   /**
415    * Sets a new foreign-key enforcement policy.  If {@code null}, resets to
416    * the default value.
417    * @usage _intermediate_method_
418    */
419   public void setEnforceForeignKeys(Boolean newEnforceForeignKeys);
420 
421   /**
422    * Gets current allow auto number insert policy.  By default, jackcess does
423    * not allow auto numbers to be inserted or updated directly (they are
424    * always handled internally by the Table).  Setting this policy to {@code
425    * true} allows the caller to optionally set the value explicitly when
426    * adding or updating rows (if a value is not provided, it will still be
427    * handled internally by the Table).  This value can be set database-wide
428    * using {@link #setAllowAutoNumberInsert} and/or on a per-table basis using
429    * {@link Table#setAllowAutoNumberInsert} (and/or on a jvm-wide using the
430    * {@link #ALLOW_AUTONUM_INSERT_PROPERTY} system property).  Note that
431    * <i>enabling this feature should be done with care</i> to reduce the
432    * chances of screwing up the database.
433    * 
434    * @usage _intermediate_method_
435    */
436   public boolean isAllowAutoNumberInsert();
437 
438   /**
439    * Sets the new auto number insert policy for the database (unless
440    * overridden at the Table level).  If {@code null}, resets to the default
441    * value.
442    * @usage _intermediate_method_
443    */
444   public void setAllowAutoNumberInsert(Boolean allowAutoNumInsert);
445 
446   /**
447    * Gets currently configured ColumnValidatorFactory (always non-{@code null}).
448    * @usage _intermediate_method_
449    */
450   public ColumnValidatorFactory getColumnValidatorFactory();
451 
452   /**
453    * Sets a new ColumnValidatorFactory.  If {@code null}, resets to the
454    * default value.  The configured ColumnValidatorFactory will be used to
455    * create ColumnValidator instances on any <i>user</i> tables loaded from
456    * this point onward (this will not be used for system tables).
457    * @usage _intermediate_method_
458    */
459   public void setColumnValidatorFactory(ColumnValidatorFactory newFactory);
460   
461   /**
462    * Returns the FileFormat of this database (which may involve inspecting the
463    * database itself).
464    * @throws IllegalStateException if the file format cannot be determined
465    * @usage _general_method_
466    */
467   public FileFormat getFileFormat() throws IOException;
468 
469 }