mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-13 19:29:06 +01:00
320 lines
9.6 KiB
Java
320 lines
9.6 KiB
Java
package net.sf.briar.plugins;
|
|
|
|
import java.io.IOException;
|
|
import java.util.ArrayList;
|
|
import java.util.Collections;
|
|
import java.util.HashSet;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
import java.util.concurrent.ExecutorService;
|
|
import java.util.logging.Level;
|
|
import java.util.logging.Logger;
|
|
|
|
import net.sf.briar.api.ContactId;
|
|
import net.sf.briar.api.TransportConfig;
|
|
import net.sf.briar.api.TransportProperties;
|
|
import net.sf.briar.api.db.DatabaseComponent;
|
|
import net.sf.briar.api.db.DbException;
|
|
import net.sf.briar.api.plugins.Plugin;
|
|
import net.sf.briar.api.plugins.PluginCallback;
|
|
import net.sf.briar.api.plugins.PluginExecutor;
|
|
import net.sf.briar.api.plugins.PluginManager;
|
|
import net.sf.briar.api.plugins.duplex.DuplexPlugin;
|
|
import net.sf.briar.api.plugins.duplex.DuplexPluginCallback;
|
|
import net.sf.briar.api.plugins.duplex.DuplexPluginFactory;
|
|
import net.sf.briar.api.plugins.duplex.DuplexTransportConnection;
|
|
import net.sf.briar.api.plugins.simplex.SimplexPlugin;
|
|
import net.sf.briar.api.plugins.simplex.SimplexPluginCallback;
|
|
import net.sf.briar.api.plugins.simplex.SimplexPluginFactory;
|
|
import net.sf.briar.api.plugins.simplex.SimplexTransportReader;
|
|
import net.sf.briar.api.plugins.simplex.SimplexTransportWriter;
|
|
import net.sf.briar.api.protocol.ProtocolConstants;
|
|
import net.sf.briar.api.protocol.TransportId;
|
|
import net.sf.briar.api.protocol.TransportIndex;
|
|
import net.sf.briar.api.transport.ConnectionDispatcher;
|
|
import net.sf.briar.api.ui.UiCallback;
|
|
|
|
import com.google.inject.Inject;
|
|
|
|
class PluginManagerImpl implements PluginManager {
|
|
|
|
private static final Logger LOG =
|
|
Logger.getLogger(PluginManagerImpl.class.getName());
|
|
|
|
private static final String[] SIMPLEX_PLUGIN_FACTORIES = new String[] {
|
|
"net.sf.briar.plugins.file.RemovableDrivePluginFactory"
|
|
};
|
|
|
|
private static final String[] DUPLEX_PLUGIN_FACTORIES = new String[] {
|
|
"net.sf.briar.plugins.bluetooth.BluetoothPluginFactory",
|
|
"net.sf.briar.plugins.socket.SimpleSocketPluginFactory"
|
|
};
|
|
|
|
private final ExecutorService pluginExecutor;
|
|
private final DatabaseComponent db;
|
|
private final Poller poller;
|
|
private final ConnectionDispatcher dispatcher;
|
|
private final UiCallback uiCallback;
|
|
private final List<SimplexPlugin> simplexPlugins; // Locking: this
|
|
private final List<DuplexPlugin> duplexPlugins; // Locking: this
|
|
|
|
@Inject
|
|
PluginManagerImpl(@PluginExecutor ExecutorService pluginExecutor,
|
|
DatabaseComponent db, Poller poller,
|
|
ConnectionDispatcher dispatcher, UiCallback uiCallback) {
|
|
this.pluginExecutor = pluginExecutor;
|
|
this.db = db;
|
|
this.poller = poller;
|
|
this.dispatcher = dispatcher;
|
|
this.uiCallback = uiCallback;
|
|
simplexPlugins = new ArrayList<SimplexPlugin>();
|
|
duplexPlugins = new ArrayList<DuplexPlugin>();
|
|
}
|
|
|
|
public synchronized int getPluginCount() {
|
|
return simplexPlugins.size() + duplexPlugins.size();
|
|
}
|
|
|
|
public synchronized int start() {
|
|
Set<TransportId> ids = new HashSet<TransportId>();
|
|
// Instantiate and start the simplex plugins
|
|
for(String s : SIMPLEX_PLUGIN_FACTORIES) {
|
|
try {
|
|
Class<?> c = Class.forName(s);
|
|
SimplexPluginFactory factory =
|
|
(SimplexPluginFactory) c.newInstance();
|
|
SimplexCallback callback = new SimplexCallback();
|
|
SimplexPlugin plugin = factory.createPlugin(pluginExecutor,
|
|
callback);
|
|
if(plugin == null) {
|
|
if(LOG.isLoggable(Level.INFO)) {
|
|
LOG.info(factory.getClass().getSimpleName()
|
|
+ " did not create a plugin");
|
|
}
|
|
continue;
|
|
}
|
|
TransportId id = plugin.getId();
|
|
if(!ids.add(id)) {
|
|
if(LOG.isLoggable(Level.WARNING))
|
|
LOG.warning("Duplicate transport ID: " + id);
|
|
continue;
|
|
}
|
|
TransportIndex index = db.getLocalIndex(id);
|
|
if(index == null) index = db.addTransport(id);
|
|
if(index == null) {
|
|
if(LOG.isLoggable(Level.WARNING))
|
|
LOG.warning("Could not allocate index for ID: " + id);
|
|
continue;
|
|
}
|
|
callback.init(id, index);
|
|
plugin.start();
|
|
simplexPlugins.add(plugin);
|
|
} catch(ClassCastException e) {
|
|
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
|
|
continue;
|
|
} catch(Exception e) {
|
|
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
|
|
continue;
|
|
}
|
|
}
|
|
// Instantiate and start the duplex plugins
|
|
for(String s : DUPLEX_PLUGIN_FACTORIES) {
|
|
try {
|
|
Class<?> c = Class.forName(s);
|
|
DuplexPluginFactory factory =
|
|
(DuplexPluginFactory) c.newInstance();
|
|
DuplexCallback callback = new DuplexCallback();
|
|
DuplexPlugin plugin = factory.createPlugin(pluginExecutor,
|
|
callback);
|
|
if(plugin == null) {
|
|
if(LOG.isLoggable(Level.INFO)) {
|
|
LOG.info(factory.getClass().getSimpleName()
|
|
+ " did not create a plugin");
|
|
}
|
|
continue;
|
|
}
|
|
TransportId id = plugin.getId();
|
|
if(!ids.add(id)) {
|
|
if(LOG.isLoggable(Level.WARNING))
|
|
LOG.warning("Duplicate transport ID: " + id);
|
|
continue;
|
|
}
|
|
TransportIndex index = db.getLocalIndex(id);
|
|
if(index == null) index = db.addTransport(id);
|
|
if(index == null) {
|
|
if(LOG.isLoggable(Level.WARNING))
|
|
LOG.warning("Could not allocate index for ID: " + id);
|
|
continue;
|
|
}
|
|
callback.init(id, index);
|
|
plugin.start();
|
|
duplexPlugins.add(plugin);
|
|
} catch(ClassCastException e) {
|
|
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
|
|
continue;
|
|
} catch(Exception e) {
|
|
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
|
|
continue;
|
|
}
|
|
}
|
|
// Start the poller
|
|
List<Plugin> plugins = new ArrayList<Plugin>();
|
|
plugins.addAll(simplexPlugins);
|
|
plugins.addAll(duplexPlugins);
|
|
poller.start(Collections.unmodifiableList(plugins));
|
|
// Return the number of plugins successfully started
|
|
return simplexPlugins.size() + duplexPlugins.size();
|
|
}
|
|
|
|
public synchronized int stop() {
|
|
int stopped = 0;
|
|
// Stop the simplex plugins
|
|
for(SimplexPlugin plugin : simplexPlugins) {
|
|
try {
|
|
plugin.stop();
|
|
stopped++;
|
|
} catch(IOException e) {
|
|
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
|
|
}
|
|
}
|
|
simplexPlugins.clear();
|
|
// Stop the duplex plugins
|
|
for(DuplexPlugin plugin : duplexPlugins) {
|
|
try {
|
|
plugin.stop();
|
|
stopped++;
|
|
} catch(IOException e) {
|
|
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
|
|
}
|
|
}
|
|
duplexPlugins.clear();
|
|
// Stop the poller
|
|
poller.stop();
|
|
// Shut down the executor service
|
|
pluginExecutor.shutdown();
|
|
// Return the number of plugins successfully stopped
|
|
return stopped;
|
|
}
|
|
|
|
private abstract class PluginCallbackImpl implements PluginCallback {
|
|
|
|
protected volatile TransportId id = null;
|
|
protected volatile TransportIndex index = null;
|
|
|
|
protected void init(TransportId id, TransportIndex index) {
|
|
assert this.id == null && this.index == null;
|
|
this.id = id;
|
|
this.index = index;
|
|
}
|
|
|
|
public TransportConfig getConfig() {
|
|
assert id != null;
|
|
try {
|
|
return db.getConfig(id);
|
|
} catch(DbException e) {
|
|
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
|
|
return new TransportConfig();
|
|
}
|
|
}
|
|
|
|
public TransportProperties getLocalProperties() {
|
|
assert id != null;
|
|
try {
|
|
TransportProperties p = db.getLocalProperties(id);
|
|
return p == null ? new TransportProperties() : p;
|
|
} catch(DbException e) {
|
|
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
|
|
return new TransportProperties();
|
|
}
|
|
}
|
|
|
|
public Map<ContactId, TransportProperties> getRemoteProperties() {
|
|
assert id != null;
|
|
try {
|
|
return db.getRemoteProperties(id);
|
|
} catch(DbException e) {
|
|
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
|
|
return Collections.emptyMap();
|
|
}
|
|
}
|
|
|
|
public void setConfig(TransportConfig c) {
|
|
assert id != null;
|
|
try {
|
|
db.setConfig(id, c);
|
|
} catch(DbException e) {
|
|
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
|
|
}
|
|
}
|
|
|
|
public void setLocalProperties(TransportProperties p) {
|
|
assert id != null;
|
|
if(p.size() > ProtocolConstants.MAX_PROPERTIES_PER_TRANSPORT) {
|
|
if(LOG.isLoggable(Level.WARNING))
|
|
LOG.warning("Plugin " + id + " set too many properties");
|
|
return;
|
|
}
|
|
for(String s : p.keySet()) {
|
|
if(s.length() > ProtocolConstants.MAX_PROPERTY_LENGTH) {
|
|
if(LOG.isLoggable(Level.WARNING))
|
|
LOG.warning("Plugin " + id + " set long key: " + s);
|
|
return;
|
|
}
|
|
}
|
|
for(String s : p.values()) {
|
|
if(s.length() > ProtocolConstants.MAX_PROPERTY_LENGTH) {
|
|
if(LOG.isLoggable(Level.WARNING))
|
|
LOG.warning("Plugin " + id + " set long value: " + s);
|
|
return;
|
|
}
|
|
}
|
|
try {
|
|
db.setLocalProperties(id, p);
|
|
} catch(DbException e) {
|
|
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
|
|
}
|
|
}
|
|
|
|
public int showChoice(String[] options, String... message) {
|
|
return uiCallback.showChoice(options, message);
|
|
}
|
|
|
|
public boolean showConfirmationMessage(String... message) {
|
|
return uiCallback.showConfirmationMessage(message);
|
|
}
|
|
|
|
public void showMessage(String... message) {
|
|
uiCallback.showMessage(message);
|
|
}
|
|
}
|
|
|
|
private class SimplexCallback extends PluginCallbackImpl
|
|
implements SimplexPluginCallback {
|
|
|
|
public void readerCreated(SimplexTransportReader r) {
|
|
assert id != null;
|
|
dispatcher.dispatchReader(id, r);
|
|
}
|
|
|
|
public void writerCreated(ContactId c, SimplexTransportWriter w) {
|
|
assert index != null;
|
|
dispatcher.dispatchWriter(c, id, index, w);
|
|
}
|
|
}
|
|
|
|
private class DuplexCallback extends PluginCallbackImpl
|
|
implements DuplexPluginCallback {
|
|
|
|
public void incomingConnectionCreated(DuplexTransportConnection d) {
|
|
assert id != null;
|
|
dispatcher.dispatchIncomingConnection(id, d);
|
|
}
|
|
|
|
public void outgoingConnectionCreated(ContactId c,
|
|
DuplexTransportConnection d) {
|
|
assert index != null;
|
|
dispatcher.dispatchOutgoingConnection(c, id, index, d);
|
|
}
|
|
}
|
|
} |