package com.laytonsmith.persistence; import com.laytonsmith.PureUtilities.DaemonManager; import com.laytonsmith.PureUtilities.Pair; import com.laytonsmith.PureUtilities.Version; import com.laytonsmith.persistence.io.ConnectionMixinFactory; import java.io.IOException; import java.net.URI; import java.util.Map; import java.util.Set; import java.util.WeakHashMap; /** * Wraps a data source, and ensures that it is threadsafe. The static * accessor method ensures that all methods that access a data source * all operate on the one, threadsafe data source. This does not absolutely * ensure that the data source itself is threadsafe, as incompatible code * will be able to bypass restrictions, but all code that uses this class * can ensure that amongst those classes, the accesses will be threadsafe. */ public class ThreadsafeDataSource implements DataSource { private static final WeakHashMap<Pair<URI, ConnectionMixinFactory.ConnectionMixinOptions>, ThreadsafeDataSource> sources = new WeakHashMap<>(); /** * Returns the threadsafe data source for the given uri and options. If an existing * reference to a DataSource is currently cached, it is returned, otherwise a new one * is constructed. * @param uri The URI to be passed to the DataSourceFactory. * @param options The options to be passed to the DataSourceFactory. * @return * @throws DataSourceException If the underlying call to {@link DataSourceFactory#GetDataSource(java.net.URI, com.laytonsmith.persistence.io.ConnectionMixinFactory.ConnectionMixinOptions)} * throws a DataSourceException, it is re-thrown. */ public static synchronized ThreadsafeDataSource GetDataSource(URI uri, ConnectionMixinFactory.ConnectionMixinOptions options) throws DataSourceException{ Pair<URI, ConnectionMixinFactory.ConnectionMixinOptions> pair = new Pair<>(uri, options); if(sources.containsKey(pair) && sources.get(pair) != null){ return sources.get(pair); } else { ThreadsafeDataSource ds = new ThreadsafeDataSource(DataSourceFactory.GetDataSource(uri, options)); sources.put(pair, ds); return ds; } } private final DataSource source; private ThreadsafeDataSource(DataSource source){ this.source = source; } @Override public synchronized Set<String[]> keySet(String[] keyBase) throws DataSourceException { return source.keySet(keyBase); } @Override public synchronized Set<String> stringKeySet(String[] keyBase) throws DataSourceException { return source.stringKeySet(keyBase); } @Override public synchronized Set<String[]> getNamespace(String[] namespace) throws DataSourceException { return source.getNamespace(namespace); } @Override public synchronized String get(String[] key) throws DataSourceException { return source.get(key); } @Override public synchronized Map<String[], String> getValues(String[] leadKey) throws DataSourceException { return source.getValues(leadKey); } @Override public synchronized boolean set(DaemonManager dm, String[] key, String value) throws ReadOnlyException, DataSourceException, IOException, IllegalArgumentException { return source.set(dm, key, value); } @Override public synchronized void populate() throws DataSourceException { source.populate(); } @Override public synchronized void addModifier(DataSourceModifier modifier) { source.addModifier(modifier); } @Override public synchronized DataSourceModifier[] implicitModifiers() { return source.implicitModifiers(); } @Override public synchronized DataSourceModifier[] invalidModifiers() { return source.invalidModifiers(); } @Override public synchronized Set<DataSourceModifier> getModifiers() { return source.getModifiers(); } @Override public synchronized boolean hasModifier(DataSourceModifier modifier) { return source.hasModifier(modifier); } @Override public synchronized boolean hasKey(String[] key) throws DataSourceException { return source.hasKey(key); } @Override public synchronized void clearKey(DaemonManager dm, String[] key) throws DataSourceException, ReadOnlyException, IOException { source.clearKey(dm, key); } @Override public synchronized void startTransaction(DaemonManager dm) { source.startTransaction(dm); } @Override public synchronized void stopTransaction(DaemonManager dm, boolean rollback) throws DataSourceException, IOException { source.stopTransaction(dm, rollback); } @Override public synchronized void disconnect() throws DataSourceException { source.disconnect(); } @Override public synchronized String getName() { return source.getName(); } @Override public synchronized String docs() { return source.docs(); } @Override public synchronized Version since() { return source.since(); } @Override @SuppressWarnings("EqualsWhichDoesntCheckParameterClass") public synchronized boolean equals(Object obj) { return source.equals(obj); } @Override public synchronized int hashCode() { return source.hashCode(); } @Override public synchronized String toString() { return source.toString(); } }