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