Skip to content

Commit

Permalink
Implementation of shared database support (full system). (JabRef#1451)
Browse files Browse the repository at this point in the history
Support for MySQL, PostgreSQL and Oracle database systems.
Full entry synchronisation.
Full meta data synchronization.
Group synchrnoization.
Semi-automatic/event based synchronization.
Version control system.
Conflicts resolving machanisms.
User interfaces for different situations.
Extensive synchronization and class tests.
  • Loading branch information
obraliar authored and koppor committed Aug 9, 2016
1 parent 98e53aa commit 5d8b15c
Show file tree
Hide file tree
Showing 105 changed files with 3,999 additions and 3,575 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# no generated files in version control
src/main/gen/

# do not distribute Oracle's JDBC driver
lib/ojdbc.jar

# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err*

Expand Down
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ install: true
# allow gui testing on travis
before_script:
- psql -c 'create database jabref;' -U postgres
- mysql -u root -e 'create database jabref'

script:
- ./gradlew check
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `#
## [Unreleased]

### Changed
- [#970](https://github.com/JabRef/jabref/issues/970): Implementation of shared database support (full system) with event based synchronization for MySQL, PostgreSQL and Oracle database systems.
- Externally fetched information can be merged for entries with an ISBN
- Externally fetched information can be merged for entries with an ArXiv eprint
- [#462](https://github.com/JabRef/jabref/issues/462) Extend the OpenConsoleFeature by offering a selection between default terminal emulator and configurable command execution.
Expand Down
38 changes: 38 additions & 0 deletions src/main/java/net/sf/jabref/BibDatabaseContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
import net.sf.jabref.model.database.BibDatabase;
import net.sf.jabref.model.database.BibDatabaseMode;
import net.sf.jabref.model.database.BibDatabaseModeDetection;
import net.sf.jabref.model.database.DatabaseLocation;
import net.sf.jabref.model.entry.FieldName;
import net.sf.jabref.preferences.JabRefPreferences;
import net.sf.jabref.shared.DBMSSynchronizer;

/**
* Represents everything related to a BIB file.
Expand All @@ -25,6 +27,8 @@ public class BibDatabaseContext {
private final Defaults defaults;
/** The file where this database was last saved to. */
private File file;
private DBMSSynchronizer dbmsSynchronizer;
private DatabaseLocation location;

public BibDatabaseContext() {
this(new Defaults());
Expand All @@ -43,9 +47,15 @@ public BibDatabaseContext(BibDatabase database, Defaults defaults) {
}

public BibDatabaseContext(BibDatabase database, MetaData metaData, Defaults defaults) {
this(database, metaData, defaults, DatabaseLocation.LOCAL);
}

public BibDatabaseContext(BibDatabase database, MetaData metaData, Defaults defaults, DatabaseLocation location) {
this.defaults = Objects.requireNonNull(defaults);
this.database = Objects.requireNonNull(database);
this.metaData = Objects.requireNonNull(metaData);

updateDatabaseLocation(location);
}

public BibDatabaseContext(BibDatabase database, MetaData metaData) {
Expand All @@ -62,6 +72,10 @@ public BibDatabaseContext(BibDatabase database, MetaData metaData, File file) {
this(database, metaData, file, new Defaults());
}

public BibDatabaseContext(Defaults defaults, DatabaseLocation location) {
this(new BibDatabase(), new MetaData(), defaults, location);
}

public BibDatabaseMode getMode() {
Optional<BibDatabaseMode> mode = metaData.getMode();

Expand Down Expand Up @@ -181,4 +195,28 @@ private String getFileDirectoryPath(String directoryName) {
public List<String> getFileDirectory() {
return getFileDirectory(FieldName.FILE);
}

public DBMSSynchronizer getDBSynchronizer() {
return this.dbmsSynchronizer;
}

public DatabaseLocation getLocation() {
return this.location;
}

public void updateDatabaseLocation(DatabaseLocation newLocation) {

if ((this.location == DatabaseLocation.SHARED) && (newLocation == DatabaseLocation.LOCAL)) {
this.database.unregisterListener(dbmsSynchronizer);
this.metaData.unregisterListener(dbmsSynchronizer);
}

if (newLocation == DatabaseLocation.SHARED) {
this.dbmsSynchronizer = new DBMSSynchronizer(this);
this.database.registerListener(dbmsSynchronizer);
this.metaData.registerListener(dbmsSynchronizer);
}

this.location = newLocation;
}
}
75 changes: 48 additions & 27 deletions src/main/java/net/sf/jabref/MetaData.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
import java.util.TreeMap;
import java.util.Vector;

import net.sf.jabref.event.GroupUpdatedEvent;
import net.sf.jabref.event.MetaDataChangedEvent;
import net.sf.jabref.importer.fileformat.ParseException;
import net.sf.jabref.logic.config.SaveOrderConfig;
import net.sf.jabref.logic.exporter.FieldFormatterCleanups;
Expand All @@ -43,8 +45,8 @@
import net.sf.jabref.logic.util.strings.StringUtil;
import net.sf.jabref.model.database.BibDatabaseMode;
import net.sf.jabref.model.entry.FieldName;
import net.sf.jabref.sql.DBStrings;

import com.google.common.eventbus.EventBus;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

Expand All @@ -66,14 +68,12 @@ public class MetaData implements Iterable<String> {

private final Map<String, List<String>> metaData = new HashMap<>();
private GroupTreeNode groupsRoot;
private final EventBus eventBus = new EventBus();

private AbstractLabelPattern labelPattern;

private DBStrings dbStrings = new DBStrings();

private Charset encoding = Globals.prefs.getDefaultEncoding();


/**
* The MetaData object stores all meta data sets in Vectors. To ensure that
* the data is written correctly to string, the user of a meta data Vector
Expand All @@ -82,7 +82,22 @@ public class MetaData implements Iterable<String> {
*/
private MetaData(Map<String, String> inData) throws ParseException {
Objects.requireNonNull(inData);
setData(inData);
}

/**
* The MetaData object can be constructed with no data in it.
*/
public MetaData() {
// No data
}

public static MetaData parse(Map<String, String> data) throws ParseException {
return new MetaData(data);
}

public void setData(Map<String, String> inData) throws ParseException {
clearMetaData();
for (Map.Entry<String, String> entry : inData.entrySet()) {
StringReader data = new StringReader(entry.getValue());
List<String> orderedData = new ArrayList<>();
Expand All @@ -98,25 +113,15 @@ private MetaData(Map<String, String> inData) throws ParseException {
if (GROUPSTREE.equals(entry.getKey())) {
putGroups(orderedData);
// the keys "groupsversion" and "groups" were used in JabRef versions around 1.3, we will not support them anymore
eventBus.post(new GroupUpdatedEvent(this));
} else if (SAVE_ACTIONS.equals(entry.getKey())) {
setSaveActions(FieldFormatterCleanups.parse(orderedData));
metaData.put(SAVE_ACTIONS, FieldFormatterCleanups.parse(orderedData).getAsStringList()); // Without MetaDataChangedEvent
} else {
putData(entry.getKey(), orderedData);
metaData.put(entry.getKey(), orderedData);
}
}
}

/**
* The MetaData object can be constructed with no data in it.
*/
public MetaData() {
// No data
}

public static MetaData parse(Map<String, String> data) throws ParseException {
return new MetaData(data);
}

public Optional<SaveOrderConfig> getSaveOrderConfig() {
List<String> storedSaveOrderConfig = getData(SAVE_ORDER_CONFIG);
if (storedSaveOrderConfig != null) {
Expand Down Expand Up @@ -161,7 +166,10 @@ public List<String> getData(String key) {
* @param key the key to remove
*/
public void remove(String key) {
metaData.remove(key);
if (metaData.containsKey(key)) { //otherwise redundant and disturbing events are going to be posted
metaData.remove(key);
postChange();
}
}

/**
Expand All @@ -172,6 +180,7 @@ public void remove(String key) {
*/
public void putData(String key, List<String> orderedData) {
metaData.put(key, orderedData);
postChange();
}

/**
Expand All @@ -182,6 +191,7 @@ public void putData(String key, List<String> orderedData) {
private void putGroups(List<String> orderedData) throws ParseException {
try {
groupsRoot = GroupTreeNode.parse(orderedData, Globals.prefs);
eventBus.post(new GroupUpdatedEvent(this));
} catch (ParseException e) {
throw new ParseException(Localization.lang(
"Group tree could not be parsed. If you save the BibTeX database, all groups will be lost."), e);
Expand All @@ -198,6 +208,7 @@ public GroupTreeNode getGroups() {
*/
public void setGroups(GroupTreeNode root) {
groupsRoot = root;
eventBus.post(new GroupUpdatedEvent(this));
}

/**
Expand Down Expand Up @@ -225,14 +236,6 @@ private static Optional<String> getNextUnit(Reader reader) throws IOException {
return Optional.empty();
}

public DBStrings getDBStrings() {
return dbStrings;
}

public void setDBStrings(DBStrings dbStrings) {
this.dbStrings = dbStrings;
}

/**
* @return the stored label patterns
*/
Expand Down Expand Up @@ -390,7 +393,6 @@ public Map<String, String> getAsStringMap() {
}
serializedMetaData.put(GROUPSTREE, stringBuilder.toString());
}

return serializedMetaData;
}

Expand Down Expand Up @@ -448,6 +450,13 @@ public void clearSaveOrderConfig() {
remove(SAVE_ORDER_CONFIG);
}

/**
* Posts a new {@link MetaDataChangedEvent} on the {@link EventBus}.
*/
public void postChange() {
eventBus.post(new MetaDataChangedEvent(this));
}

/**
* Returns the encoding used during parsing.
*/
Expand All @@ -458,4 +467,16 @@ public Charset getEncoding() {
public void setEncoding(Charset encoding) {
this.encoding = Objects.requireNonNull(encoding);
}

public void clearMetaData() {
metaData.clear();
}

public void registerListener(Object listener) {
this.eventBus.register(listener);
}

public void unregisterListener(Object listener) {
this.eventBus.unregister(listener);
}
}
19 changes: 19 additions & 0 deletions src/main/java/net/sf/jabref/event/GroupUpdatedEvent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package net.sf.jabref.event;

import net.sf.jabref.MetaData;

public class GroupUpdatedEvent {

private final MetaData metaData;

/**
* @param metaData Affected instance
*/
public GroupUpdatedEvent(MetaData metaData) {
this.metaData = metaData;
}

public MetaData getMetaData() {
return this.metaData;
}
}
22 changes: 22 additions & 0 deletions src/main/java/net/sf/jabref/event/MetaDataChangedEvent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package net.sf.jabref.event;

import net.sf.jabref.MetaData;

/**
* {@link MetaDataChangedEvent} is fired when a tuple of meta data has been put or removed.
*/
public class MetaDataChangedEvent {

private final MetaData metaData;

/**
* @param metaData Affected instance
*/
public MetaDataChangedEvent(MetaData metaData) {
this.metaData = metaData;
}

public MetaData getMetaData() {
return this.metaData;
}
}
26 changes: 26 additions & 0 deletions src/main/java/net/sf/jabref/event/source/EntryEventSource.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/* Copyright (C) 2016 JabRef contributors.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package net.sf.jabref.event.source;

/**
* This enum represents the context EntryEvents were sent from.
*/
public enum EntryEventSource {
LOCAL,
SHARED,
UNDO,
SAVE_ACTION
}
Loading

0 comments on commit 5d8b15c

Please sign in to comment.