001/*
002 * #%L
003 * Netarchivesuite - harvester
004 * %%
005 * Copyright (C) 2005 - 2014 The Royal Danish Library, the Danish State and University Library,
006 *             the National Library of France and the Austrian National Library.
007 * %%
008 * This program is free software: you can redistribute it and/or modify
009 * it under the terms of the GNU Lesser General Public License as
010 * published by the Free Software Foundation, either version 2.1 of the
011 * License, or (at your option) any later version.
012 * 
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016 * GNU General Lesser Public License for more details.
017 * 
018 * You should have received a copy of the GNU General Lesser Public
019 * License along with this program.  If not, see
020 * <http://www.gnu.org/licenses/lgpl-2.1.html>.
021 * #L%
022 */
023
024package dk.netarkivet.harvester.datamodel;
025
026import java.sql.Connection;
027import java.sql.SQLException;
028
029import org.slf4j.Logger;
030import org.slf4j.LoggerFactory;
031
032import dk.netarkivet.common.CommonSettings;
033import dk.netarkivet.common.exceptions.ArgumentNotValid;
034import dk.netarkivet.common.exceptions.IOFailure;
035import dk.netarkivet.common.exceptions.IllegalState;
036import dk.netarkivet.common.exceptions.NotImplementedException;
037import dk.netarkivet.common.utils.DBUtils;
038import dk.netarkivet.common.utils.SettingsFactory;
039
040/**
041 * Defines database specific implementations used by the Harvester.
042 * <p>
043 * The actual actual implementation which is loaded is defined by the {@link CommonSettings#DB_SPECIFICS_CLASS} setting.
044 * See the sub class list for available implementations
045 */
046public abstract class DBSpecifics extends SettingsFactory<DBSpecifics> {
047
048    /** The instance of the DBSpecifics class. */
049    private static DBSpecifics instance;
050
051    private static final Logger log = LoggerFactory.getLogger(DBSpecifics.class);
052
053    /**
054     * Get the singleton instance of the DBSpecifics implementation class.
055     *
056     * @return An instance of DBSpecifics with implementations for a given DB.
057     */
058    public static synchronized DBSpecifics getInstance() {
059        if (instance == null) {
060            instance = getInstance(CommonSettings.DB_SPECIFICS_CLASS);
061        }
062        return instance;
063    }
064
065    /**
066     * Get a temporary table for short-time use. The table should be disposed of with dropTemporaryTable. The table has
067     * two columns domain_name varchar(Constants.MAX_NAME_SIZE) + config_name varchar(Constants.MAX_NAME_SIZE) All rows
068     * in the table must be deleted at commit or rollback.
069     *
070     * @param c The DB connection to use.
071     * @return The name of the created table
072     * @throws SQLException if there is a problem getting the table.
073     */
074    public abstract String getJobConfigsTmpTable(Connection c) throws SQLException;
075
076    /**
077     * Dispose of a temporary table gotten with getTemporaryTable. This can be expected to be called from within a
078     * finally clause, so it mustn't throw exceptions.
079     *
080     * @param c The DB connection to use.
081     * @param tableName The name of the temporarily created table.
082     */
083    public abstract void dropJobConfigsTmpTable(Connection c, String tableName);
084
085    /**
086     * Get the name of the JDBC driver class that handles interfacing to this server.
087     *
088     * @return The name of a JDBC driver class
089     */
090    public abstract String getDriverClassName();
091
092    /**
093     * Update a table to a newer version, if necessary. This will check the schemaversions table to see the current
094     * version and perform a table-specific update if required.
095     *
096     * @param tableName The table to update
097     * @param toVersion The version to update the table to.
098     * @throws IllegalState If the table is an unsupported version, and the toVersion is less than the current version
099     * of the table
100     * @throws NotImplementedException If no method exists for migration from current version of the table to the
101     * toVersion of the table.
102     * @throws IOFailure in case of problems in interacting with the database
103     */
104
105    public synchronized void updateTable(String tableName, int toVersion) {
106        ArgumentNotValid.checkNotNullOrEmpty(tableName, "String tableName");
107        ArgumentNotValid.checkPositive(toVersion, "int toVersion");
108
109        Connection c = HarvestDBConnection.get();
110        int currentVersion = -1;
111        try {
112            currentVersion = DBUtils.getTableVersion(c, tableName);
113        } finally {
114            HarvestDBConnection.release(c);
115        }
116        if (currentVersion == toVersion) {
117            // Nothing to do. Version of table is already correct.
118            return;
119        }
120        log.info("Trying to migrate table '" + tableName + "' from version '" + currentVersion + "' to version '"
121                + toVersion + "'.");
122
123        if (currentVersion > toVersion) {
124            throw new IllegalState("Database is in an illegalState: The current version of table '" + tableName
125                    + "' is not acceptable (current version is greater than requested version).");
126        }
127
128        if (tableName.equals(HarvesterDatabaseTables.JOBS.getTablename())) {
129            upgradeJobsTable(currentVersion, toVersion);
130        } else if (tableName.equals(HarvesterDatabaseTables.FULLHARVESTS.getTablename())) {
131            upgradeFullharvestsTable(currentVersion, toVersion);
132        } else if (tableName.equals(HarvesterDatabaseTables.CONFIGURATIONS.getTablename())) {
133            upgradeConfigurationsTable(currentVersion, toVersion);
134        } else if (tableName.equals(HarvesterDatabaseTables.GLOBALCRAWLERTRAPLISTS.getTablename())) {
135            upgradeGlobalcrawlertraplistsTable(currentVersion, toVersion);
136        } else if (tableName.equals(HarvesterDatabaseTables.GLOBALCRAWLERTRAPEXPRESSIONS.getTablename())) {
137            upgradeGlobalcrawlertrapexpressionsTable(currentVersion, toVersion);
138        } else if (tableName.equals(HarvesterDatabaseTables.RUNNINGJOBSHISTORY.getTablename())) {
139            upgradeRunningjobshistoryTable(currentVersion, toVersion);
140        } else if (tableName.equals(HarvesterDatabaseTables.RUNNINGJOBSMONITOR.getTablename())) {
141            upgradeRunningjobsmonitor(currentVersion, toVersion);
142        } else if (tableName.equals(HarvesterDatabaseTables.FRONTIERREPORTMONITOR.getTablename())) {
143            upgradeFrontierreportmonitorTable(currentVersion, toVersion);
144        } else if (tableName.equals(HarvesterDatabaseTables.EXTENDEDFIELD.getTablename())) {
145            upgradeExtendedFieldTable(currentVersion, toVersion);
146        } else if (tableName.equals(HarvesterDatabaseTables.EXTENDEDFIELDVALUE.getTablename())) {
147            upgradeExtendedFieldValueTable(currentVersion, toVersion);
148        } else if (tableName.equals(HarvesterDatabaseTables.EXTENDEDFIELDTYPE.getTablename())) {
149            upgradeExtendedFieldTypeTable(currentVersion, toVersion);
150        } else if (tableName.equals(HarvesterDatabaseTables.DOMAINS.getTablename())) {
151            upgradeDomainsTable(currentVersion, toVersion);
152        } else if (tableName.equals(HarvesterDatabaseTables.HARVESTDEFINITIONS.getTablename())) {
153            upgradeHarvestdefinitionsTable(currentVersion, toVersion);
154        } else if (tableName.equals(HarvesterDatabaseTables.HARVESTCHANNELS.getTablename())) {
155            upgradeHarvestchannelTable(currentVersion, toVersion);
156            // Add new if else when other tables need to be upgraded
157        } else {
158            throw new NotImplementedException("No method exists for migrating table '" + tableName + "' to version "
159                    + toVersion);
160        }
161    }
162
163    private void upgradeHarvestdefinitionsTable(int currentVersion, int toVersion) {
164        if (currentVersion < 2) {
165            throw new IllegalState("Database is in an illegalState: The current version " + currentVersion
166                    + " of table '" + HarvesterDatabaseTables.HARVESTDEFINITIONS.getTablename()
167                    + "' is not acceptable. The current table version is less than open source version 2. "
168                    + "Probably a wrong entry in the schemaversions table");
169        }
170        if (currentVersion == 2 && toVersion >= 3) {
171            migrateHarvestdefinitionsv2tov3();
172            currentVersion = 3;
173        }
174        if (currentVersion == 3 && toVersion >= 4) {
175            migrateHarvestdefinitionsv3tov4();
176            currentVersion = 4;
177        }
178        // insert new migrations here
179        if (currentVersion != HarvesterDatabaseTables.HARVESTDEFINITIONS.getRequiredVersion()) {
180            throw new NotImplementedException("No method exists for migrating table '"
181                    + HarvesterDatabaseTables.HARVESTDEFINITIONS.getTablename() + "' from version " + currentVersion
182                    + " to version " + toVersion);
183        }
184
185    }
186
187    private void upgradeExtendedFieldTypeTable(int currentVersion, int toVersion) {
188        if (currentVersion == 0 && toVersion >= 1) {
189            createExtendedFieldTypeTable();
190            currentVersion = 1;
191        }
192        if (currentVersion > HarvesterDatabaseTables.EXTENDEDFIELDTYPE.getRequiredVersion()) {
193            throw new NotImplementedException("No method exists for migrating table '"
194                    + HarvesterDatabaseTables.EXTENDEDFIELDTYPE.getTablename() + "' from version " + currentVersion
195                    + " to version " + toVersion);
196        }
197    }
198
199    private void upgradeExtendedFieldValueTable(int currentVersion, int toVersion) {
200        if (currentVersion == 0 && toVersion >= 1) {
201            createExtendedFieldValueTable();
202            currentVersion = 1;
203        }
204        if (currentVersion == 1 && toVersion >= 2) {
205            migrateExtendedFieldTableValueV1toV2();
206            currentVersion = 2;
207        }
208
209        if (currentVersion > HarvesterDatabaseTables.EXTENDEDFIELDVALUE.getRequiredVersion()) {
210            throw new NotImplementedException("No method exists for migrating table '"
211                    + HarvesterDatabaseTables.EXTENDEDFIELDVALUE.getTablename() + "' from version " + currentVersion
212                    + " to version " + toVersion);
213        }
214    }
215
216    private void upgradeExtendedFieldTable(int currentVersion, int toVersion) {
217        if (currentVersion == 0 && toVersion >= 1) {
218            createExtendedFieldTable();
219            currentVersion = 1;
220        }
221        if (currentVersion == 1 && toVersion >= 2) {
222            migrateExtendedFieldTableV1toV2();
223            currentVersion = 2;
224        }
225        if (currentVersion > HarvesterDatabaseTables.EXTENDEDFIELD.getRequiredVersion()) {
226            throw new NotImplementedException("No method exists for migrating table '"
227                    + HarvesterDatabaseTables.EXTENDEDFIELD.getTablename() + "' from version " + currentVersion
228                    + " to version " + toVersion);
229        }
230    }
231
232    /**
233     * Migrate the frontierreportmonitor table.
234     *
235     * @param currentVersion the current version of the frontierreportmonitor table
236     * @param toVersion the required version of the frontierreportmonitor table
237     */
238    private void upgradeFrontierreportmonitorTable(int currentVersion, int toVersion) {
239        if (currentVersion == 0 && toVersion == 1) {
240            createFrontierReportMonitorTable();
241            currentVersion = 1;
242        }
243        // insert new migrations here
244        if (currentVersion > HarvesterDatabaseTables.FRONTIERREPORTMONITOR.getRequiredVersion()) {
245            throw new NotImplementedException("No method exists for migrating table '"
246                    + HarvesterDatabaseTables.FRONTIERREPORTMONITOR.getTablename() + "' from version " + currentVersion
247                    + " to version " + toVersion);
248        }
249    }
250
251    /**
252     * Migrate the runningjobsmonitor table.
253     *
254     * @param currentVersion the current version of the runningjobsmonitor table
255     * @param toVersion the required version of the runningjobsmonitor table
256     */
257    private void upgradeRunningjobsmonitor(int currentVersion, int toVersion) {
258        if (currentVersion == 0 && toVersion >= 1) {
259            createRunningJobsMonitorTable();
260            currentVersion = 1;
261        }
262        if (currentVersion == 1 && toVersion >= 2) {
263            migrateRunningJobsMonitorTableV1ToV2();
264            currentVersion = 2;
265        }
266        if (currentVersion > HarvesterDatabaseTables.RUNNINGJOBSMONITOR.getRequiredVersion()) {
267            throw new NotImplementedException("No method exists for migrating table '"
268                    + HarvesterDatabaseTables.RUNNINGJOBSMONITOR.getTablename() + "' from version " + currentVersion
269                    + " to version " + toVersion);
270        }
271    }
272
273    /**
274     * Migrate the runningjobshistory table.
275     *
276     * @param currentVersion the current version of the runningjobshistory table
277     * @param toVersion The required version of the runningjobshistory table
278     */
279    private void upgradeRunningjobshistoryTable(int currentVersion, int toVersion) {
280        if (currentVersion == 0 && toVersion >= 1) {
281            createRunningJobsHistoryTable();
282            currentVersion = 1;
283        }
284        if (currentVersion == 1 && toVersion >= 2) {
285            migrateRunningJobsHistoryTableV1ToV2();
286            currentVersion = 2;
287        }
288        // insert new migrations here
289        if (currentVersion > HarvesterDatabaseTables.RUNNINGJOBSHISTORY.getRequiredVersion()) {
290            throw new NotImplementedException("No method exists for migrating table '"
291                    + HarvesterDatabaseTables.RUNNINGJOBSHISTORY.getTablename() + "' from version " + currentVersion
292                    + " to version " + toVersion);
293        }
294
295    }
296
297    /**
298     * Migrate the globalecrawlertrapexpressions table.
299     *
300     * @param currentVersion the current version of the jobs table
301     * @param toVersion The required version of the jobs table
302     */
303    private void upgradeGlobalcrawlertrapexpressionsTable(int currentVersion, int toVersion) {
304        if (currentVersion == 0 && toVersion >= 1) {
305            createGlobalCrawlerTrapExpressions();
306            currentVersion = 1;
307        }
308        // insert new migrations here
309        if (currentVersion > HarvesterDatabaseTables.GLOBALCRAWLERTRAPEXPRESSIONS.getRequiredVersion()) {
310            throw new NotImplementedException("No method exists for migrating table '"
311                    + HarvesterDatabaseTables.GLOBALCRAWLERTRAPEXPRESSIONS.getTablename() + "' from version "
312                    + currentVersion + " to version " + toVersion);
313        }
314
315    }
316
317    /**
318     * Migrate the globalecrawlertraplists table.
319     *
320     * @param currentVersion the current version of the globalecrawlertraplists table
321     * @param toVersion The required version of the globalecrawlertraplists table
322     */
323    private void upgradeGlobalcrawlertraplistsTable(int currentVersion, int toVersion) {
324        if (currentVersion == 0 && toVersion >= 1) {
325            createGlobalCrawlerTrapLists();
326            currentVersion = 1;
327        }
328        // insert new migrations here
329        if (currentVersion > HarvesterDatabaseTables.GLOBALCRAWLERTRAPLISTS.getRequiredVersion()) {
330            throw new NotImplementedException("No method exists for migrating table '"
331                    + HarvesterDatabaseTables.GLOBALCRAWLERTRAPLISTS.getTablename() + "' from version "
332                    + currentVersion + " to version " + toVersion);
333        }
334
335    }
336
337    /**
338     * Migrate the jobs table.
339     *
340     * @param currentVersion the current version of the jobs table
341     * @param toVersion The required version of the jobs table
342     */
343    private void upgradeJobsTable(int currentVersion, int toVersion) {
344        if (currentVersion < 3) {
345            throw new IllegalState("Database is in an illegalState: " + "The current version " + currentVersion
346                    + " of table '" + HarvesterDatabaseTables.JOBS.getTablename() + "' is not acceptable. "
347                    + "(current version is less than open source version).");
348        }
349        if (currentVersion == 3 && toVersion >= 4) {
350            migrateJobsv3tov4();
351            currentVersion = 4;
352        }
353        if (currentVersion == 4 && toVersion >= 5) {
354            migrateJobsv4tov5();
355            currentVersion = 5;
356        }
357        if (currentVersion == 5 && toVersion >= 6) {
358            migrateJobsv5tov6();
359            currentVersion = 6;
360        }
361        if (currentVersion == 6 && toVersion >= 7) {
362            migrateJobsv6tov7();
363            currentVersion = 7;
364        }
365        if (currentVersion == 7 && toVersion >= 8) {
366            migrateJobsv7tov8();
367            currentVersion = 8;
368        }
369        if (currentVersion == 8 && toVersion >= 9) {
370            migrateJobsv8tov9();
371            currentVersion = 9;
372        }
373        if (currentVersion == 9 && toVersion >= 10) {
374            migrateJobsv9tov10();
375            currentVersion = 10;
376        }
377        // future updates of the jobs table are inserted here
378        if (currentVersion == HarvesterDatabaseTables.JOBS.getRequiredVersion()
379                && toVersion >= HarvesterDatabaseTables.JOBS.getRequiredVersion() + 1) {
380            throw new NotImplementedException("No method exists for migrating table '"
381                    + HarvesterDatabaseTables.JOBS.getTablename() + "' from version " + currentVersion + " to version "
382                    + toVersion);
383        }
384
385        if (currentVersion > HarvesterDatabaseTables.JOBS.getRequiredVersion()) {
386            throw new IllegalState("Database is in an illegalState: " + "The current version (" + currentVersion
387                    + ") of table '" + HarvesterDatabaseTables.JOBS.getTablename()
388                    + "' is not an acceptable/known version. ");
389        }
390    }
391
392    /**
393     * Migrate the configurations table.
394     *
395     * @param currentVersion the current version of the configurations table
396     * @param toVersion the required version of the configurations table
397     */
398    private void upgradeConfigurationsTable(int currentVersion, int toVersion) {
399        if (currentVersion < 3) {
400            throw new IllegalState("Database is in an illegalState: " + "The current version " + currentVersion
401                    + " of table '" + HarvesterDatabaseTables.CONFIGURATIONS.getTablename() + "' is not acceptable. "
402                    + "(current version is less than open source version).");
403        }
404        if (currentVersion == 3 && toVersion >= 4) {
405            migrateConfigurationsv3ov4();
406            currentVersion = 4;
407        }
408
409        if (currentVersion == 4 && toVersion >= 5) {
410            migrateConfigurationsv4tov5();
411            currentVersion = 5;
412        }
413        // insert future migrations here
414        if (currentVersion == HarvesterDatabaseTables.CONFIGURATIONS.getRequiredVersion()
415                && toVersion >= HarvesterDatabaseTables.CONFIGURATIONS.getRequiredVersion() + 1) {
416            throw new NotImplementedException("No method exists for migrating table '"
417                    + HarvesterDatabaseTables.CONFIGURATIONS.getTablename() + "' from version " + currentVersion
418                    + " to version " + toVersion);
419        }
420
421        if (currentVersion > HarvesterDatabaseTables.CONFIGURATIONS.getRequiredVersion()) {
422            throw new IllegalState("Database is in an illegalState: " + "The current version (" + currentVersion
423                    + ") of table '" + HarvesterDatabaseTables.CONFIGURATIONS.getTablename()
424                    + "' is not an acceptable/known version. ");
425        }
426    }
427
428    private void upgradeDomainsTable(int currentVersion, int toVersion) {
429        if (currentVersion < 2) {
430            throw new IllegalState("Database is in an illegalState: " + "The current version " + currentVersion
431                    + " of table '" + HarvesterDatabaseTables.DOMAINS.getTablename() + "' is not acceptable. "
432                    + "(current version is less than open source version).");
433        }
434        if (currentVersion == 2 && toVersion >= 3) {
435            migrateDomainsv2tov3();
436            currentVersion = 3;
437        }
438    }
439
440    /**
441     * Migrate the fullharvests table.
442     *
443     * @param currentVersion the current version of the fullharvests table
444     * @param toVersion the required version of the fullharvests table
445     */
446    private void upgradeFullharvestsTable(int currentVersion, int toVersion) {
447        if (currentVersion < 2) {
448            throw new IllegalState("Database is in an illegalState: " + "The current version " + currentVersion
449                    + " of table '" + HarvesterDatabaseTables.FULLHARVESTS.getTablename() + "' is not acceptable. "
450                    + "(current version is less than open source version).");
451        }
452        if (currentVersion == 2 && toVersion >= 3) {
453            migrateFullharvestsv2tov3();
454            currentVersion = 3;
455        }
456
457        if (currentVersion == 3 && toVersion >= 4) {
458            migrateFullharvestsv3tov4();
459            currentVersion = 4;
460        }
461
462        if (currentVersion == 4 && toVersion >= 5) {
463            migrateFullharvestsv4tov5();
464            currentVersion = 5;
465        }
466
467        // insert future migrations here
468        if (currentVersion == HarvesterDatabaseTables.FULLHARVESTS.getRequiredVersion()
469                && toVersion >= HarvesterDatabaseTables.FULLHARVESTS.getRequiredVersion() + 1) {
470            throw new NotImplementedException("No method exists for migrating table '"
471                    + HarvesterDatabaseTables.FULLHARVESTS.getTablename() + "' from version " + currentVersion
472                    + " to version " + toVersion);
473        }
474    }
475
476    /**
477     * Migrate the harvestchannel table.
478     *
479     * @param currentVersion the current version of the harvestchannel table
480     * @param toVersion the required version of the harvestchannel table
481     */
482    private void upgradeHarvestchannelTable(int currentVersion, int toVersion) {
483        if (currentVersion == 0 && toVersion >= 1) {
484            createHarvestChannelTable();
485            currentVersion = 1;
486        }
487    }
488
489    protected abstract void createHarvestChannelTable();
490
491    /**
492     * Migrates the 'jobs' table from version 3 to version 4 consisting of a change of the field forcemaxbytes from int
493     * to bigint and setting its default to -1. Furthermore the default value for field num_configs is set to 0.
494     *
495     * @throws IOFailure in case of problems in interacting with the database
496     */
497    protected abstract void migrateJobsv3tov4();
498
499    /**
500     * Migrates the 'jobs' table from version 4 to version 5 consisting of adding new fields 'resubmitted_as_job' and
501     * 'submittedDate'.
502     *
503     * @throws IOFailure in case of problems in interacting with the database
504     */
505    protected abstract void migrateJobsv4tov5();
506
507    /**
508     * Migrates the 'configurations' table from version 3 to version 4. This consists of altering the default value of
509     * field 'maxbytes' to -1.
510     */
511    protected abstract void migrateConfigurationsv3ov4();
512
513    /**
514     * Migrates the 'fullharvests' table from version 2 to version 3. This consists of altering the default value of
515     * field 'maxbytes' to -1.
516     */
517    protected abstract void migrateFullharvestsv2tov3();
518
519    /**
520     * Migrates the 'runningjobshistory' table from version 1 to version 2. This consists of adding the new column
521     * 'retiredQueuesCount'.
522     */
523    protected abstract void migrateRunningJobsHistoryTableV1ToV2();
524
525    /**
526     * Migrates the 'runningjobsmonitor' table from version 1 to version 2. This consists of adding the new column
527     * 'retiredQueuesCount'.
528     */
529    protected abstract void migrateRunningJobsMonitorTableV1ToV2();
530
531    /**
532     * Migrates the 'domains' table from version 2 to version 3. This consists of altering the type of the crawlertraps
533     * column to "text" in postgres, and noop in derbyDB
534     */
535    protected abstract void migrateDomainsv2tov3();
536
537    /**
538     * Creates the initial (version 1) of table 'global_crawler_trap_lists'.
539     */
540    protected abstract void createGlobalCrawlerTrapLists();
541
542    /**
543     * Creates the initial (version 1) of table 'global_crawler_trap_expressions'.
544     */
545    protected abstract void createGlobalCrawlerTrapExpressions();
546
547    /**
548     * Formats the LIMIT sub-clause of an SQL order clause. This sub-clause allows to paginate query results and its
549     * syntax might be dependant on the target RDBMS
550     *
551     * @param limit the maximum number of rows to fetch.
552     * @param offset the starting offset in the full query results.
553     * @return the proper sub-clause.
554     */
555    public abstract String getOrderByLimitAndOffsetSubClause(long limit, long offset);
556
557    /**
558     * Returns true if the target RDBMS supports CLOBs. If possible seedlists will be stored as CLOBs.
559     *
560     * @return true if CLOBs are supported, false otherwise.
561     */
562    public abstract boolean supportsClob();
563
564    /**
565     * Create the frontierReportMonitor table in the database.
566     */
567    public abstract void createFrontierReportMonitorTable();
568
569    /**
570     * Create the frontierReportMonitor table in the database.
571     */
572    public abstract void createRunningJobsHistoryTable();
573
574    /**
575     * Create the frontierReportMonitor table in the database.
576     */
577    public abstract void createRunningJobsMonitorTable();
578
579    /**
580     * Migrates the 'jobs' table from version 5 to version 6. Adds the field 'forcemaxrunningtime'.
581     *
582     * @throws IOFailure in case of problems in interacting with the database
583     */
584    protected abstract void migrateJobsv5tov6();
585
586    /**
587     * Migrates the 'configurations' table from version 4 to version 5. This consists of altering the field 'maxobjects'
588     * from being an int to a bigint.
589     */
590    protected abstract void migrateConfigurationsv4tov5();
591
592    /**
593     * Migrates the 'fullharvests' table from version 3 to version 4. This consists of adding the field
594     * 'maxjobrunningtime'.
595     */
596    protected abstract void migrateFullharvestsv3tov4();
597
598    /**
599     * Migrates the 'fullharvests' table from version 4 to version 5. This consists of adding the field 'isindexready'.
600     */
601    protected abstract void migrateFullharvestsv4tov5();
602
603    /**
604     * Create the extendedfieldtype table in the database.
605     */
606    protected abstract void createExtendedFieldTypeTable();
607
608    /**
609     * Create the extendedfield table in the database.
610     */
611    protected abstract void createExtendedFieldTable();
612
613    /**
614     * Create the extendedfieldvalue table in the database.
615     */
616    protected abstract void createExtendedFieldValueTable();
617
618    /**
619     * Migrates the 'jobs' table from version 6 to version 7 consisting of adding the bigint fieldcontinuationof with
620     * null as default.
621     */
622    protected abstract void migrateJobsv6tov7();
623
624    /**
625     * Migrates the 'jobs' table from version 7 to version 8 consisting of adding the date creationdate with null as
626     * default.
627     */
628    protected abstract void migrateJobsv7tov8();
629
630    /**
631     * Migrates the 'jobs' table from version 8 to version 9 consisting of adding the string harvestname_prefix with
632     * null as default.
633     */
634    protected abstract void migrateJobsv8tov9();
635
636    /**
637     * Migrates the 'harvestdefinitions' table from version 2 to version 3 consisting of adding the string audience with
638     * null as default.
639     */
640    protected abstract void migrateHarvestdefinitionsv2tov3();
641
642    /**
643     * Migrates the 'harvestdefinitions' table from version 3 to version 4 consisting of adding the bigint channel_id
644     * field.
645     */
646    protected abstract void migrateHarvestdefinitionsv3tov4();
647
648    /**
649     * Migrates the 'jobs' table from version 9 to version 10 consisting of adding the channel (varchar 300) and a
650     * 'snapshot'
651     */
652    protected abstract void migrateJobsv9tov10();
653
654    /**
655     * Migrates the 'ExtendedFieldTable' from version 1 to version 2 consisting of adding the maxlen field
656     */
657    protected abstract void migrateExtendedFieldTableV1toV2();
658
659    /**
660     * Migrates the 'ExtendedFieldValueTable' from version 1 to version 2 changing the maxlen of content to 30000
661     */
662    protected abstract void migrateExtendedFieldTableValueV1toV2();
663
664    /**
665     * Update all tables in the enum class {@link HarvesterDatabaseTables} to the required version. There is no attempt
666     * to undo the update.
667     */
668    public void updateTables() {
669        for (HarvesterDatabaseTables table : HarvesterDatabaseTables.values()) {
670            updateTable(table.getTablename(), table.getRequiredVersion());
671        }
672    }
673
674}