
org.freedesktop.dbus.connections.impl.DBusConnection Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dbus-java-osgi Show documentation
Show all versions of dbus-java-osgi Show documentation
Improved version of the DBus-Java library provided by freedesktop.org (https://dbus.freedesktop.org/doc/dbus-java/).
This is the OSGi compliant bundle of all required libraries in one bundle.
package org.freedesktop.dbus.connections.impl;
import static org.freedesktop.dbus.utils.CommonRegexPattern.*;
import org.freedesktop.dbus.DBusMatchRule;
import org.freedesktop.dbus.RemoteInvocationHandler;
import org.freedesktop.dbus.RemoteObject;
import org.freedesktop.dbus.connections.AbstractConnection;
import org.freedesktop.dbus.connections.IDisconnectAction;
import org.freedesktop.dbus.connections.config.ReceivingServiceConfig;
import org.freedesktop.dbus.connections.config.TransportConfig;
import org.freedesktop.dbus.exceptions.*;
import org.freedesktop.dbus.interfaces.DBus;
import org.freedesktop.dbus.interfaces.DBusInterface;
import org.freedesktop.dbus.interfaces.DBusSigHandler;
import org.freedesktop.dbus.interfaces.Introspectable;
import org.freedesktop.dbus.messages.DBusSignal;
import org.freedesktop.dbus.messages.ExportedObject;
import org.freedesktop.dbus.types.UInt32;
import org.freedesktop.dbus.utils.DBusObjects;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.lang.reflect.Proxy;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.function.Function;
/**
* Handles a connection to DBus.
*
* This is a Singleton class, only 1 connection to the SYSTEM or SESSION busses can be made. Repeated calls to
* getConnection will return the same reference.
*
*
* Signal Handlers and method calls from remote objects are run in their own threads, you MUST handle the concurrency
* issues.
*
*/
public final class DBusConnection extends AbstractConnection {
static final ConcurrentMap CONNECTIONS = new ConcurrentHashMap<>();
private final Logger logger = LoggerFactory.getLogger(getClass());
private final List busnames;
private final String machineId;
private DBus dbus;
/** Whether the connection was registered using 'Hello' message. */
private boolean registered;
/** Count how many 'connections' we manage internally.
* This is required because a {@link DBusConnection} to the same address will always return the same object and
* the 'real' disconnection should only occur when there is no second/third/whatever connection is left. */
//CHECKSTYLE:OFF
final AtomicInteger concurrentConnections = new AtomicInteger(1);
//CHECKSTYLE:ON
/**
* Whether this connection is used in shared mode.
*/
private final boolean shared;
DBusConnection(boolean _shared, String _machineId, ConnectionConfig _conCfg, TransportConfig _tranportCfg, ReceivingServiceConfig _rsCfg) throws DBusException {
super(_conCfg, _tranportCfg, _rsCfg);
busnames = new ArrayList<>();
machineId = _machineId;
shared = _shared;
}
private AtomicInteger getConcurrentConnections() {
return concurrentConnections;
}
/**
* Connect to bus and register if asked. Should only be called by Builder.
*
* @throws DBusException if registering or connection fails
*/
void connectImpl() throws DBusException {
// start listening for calls
try {
listen();
} catch (IOException _ex) {
throw new DBusException(_ex);
}
// register disconnect handlers
DBusSigHandler> h = new SigHandler();
addSigHandlerWithoutMatch(DBus.NameAcquired.class, h);
// register ourselves if not disabled
if (getTransportConfig().isRegisterSelf() && getTransport().isConnected()) {
register();
getLogger().debug("");
}
}
/**
* Register this connection on the bus using 'Hello' message.
* Will do nothing if session was already registered.
*
* @throws DBusException when sending message fails
*
* @since 5.0.0 - 2023-10-11
*/
public void register() throws DBusException {
if (registered) {
return;
}
dbus = getRemoteObject("org.freedesktop.DBus", "/org/freedesktop/DBus", DBus.class);
try {
doWithBusNames(bn -> {
bn.add(dbus.Hello());
registered = true;
});
} catch (DBusExecutionException _ex) {
logger.debug("Error while doing 'Hello' handshake", _ex);
throw new DBusException(_ex.getMessage(), _ex);
}
}
/**
* Do some action with the currently registered names in a synchronized manor.
*
* @param _exClz exception type which may be thrown
* @param _action action to execute
* @param type of exception
*
* @return whatever the action returns
*
* @throws X thrown when action throws
*/
private T doWithBusNamesAndReturn(Function, T> _action) {
if (_action == null) {
return null;
}
synchronized (busnames) {
return _action.apply(busnames);
}
}
/**
* Do some action with the currently registered names in a synchronized manor.
*
* @param _exClz exception type which may be thrown
* @param _action action to execute
* @param type of exception
*
* @throws X thrown when action throws
*/
private void doWithBusNames(Consumer> _action) {
doWithBusNamesAndReturn(bn -> {
_action.accept(bn);
return null;
});
}
/**
* Tries to resolve a proxy to a remote object.
* If a type class is given, it tries to convert the object using that class.
* If null is given as type, it tries to find a proper interface for this object.
*
* @param object type (DBusInterface compatible)
* @param _source source
* @param _path path
* @param _type class of object type
*
* @return DBusInterface compatible object
*
* @throws DBusException when something goes wrong
*
* @apiNote This method is only intended for internal use.
* Visibility may change in future release
*/
@SuppressWarnings("unchecked")
public T dynamicProxy(String _source, String _path, Class _type) throws DBusException {
logger.debug("Introspecting {} on {} for dynamic proxy creation", _path, _source);
try {
Introspectable intro = getRemoteObject(_source, _path, Introspectable.class);
String data = intro.Introspect();
logger.trace("Got introspection data: {}", data);
String[] tags = PROXY_SPLIT_PATTERN.split(data);
List ifaces = Arrays.stream(tags).filter(t -> t.startsWith("interface"))
.map(t -> IFACE_PATTERN.matcher(t).replaceAll("$1"))
.map(i -> {
if (i.startsWith("org.freedesktop.DBus.")) { // if this is a default DBus interface, look for it in our package structure
return DBUS_IFACE_PATTERN.matcher(i).replaceAll("$1");
}
return i;
})
.toList();
List> ifcs = findMatchingTypes(_type, ifaces);
// interface could not be found, we guess that this exported object at least support DBusInterface
if (ifcs.isEmpty()) {
ifcs.add(DBusInterface.class);
}
RemoteObject ro = new RemoteObject(_source, _path, _type, false);
DBusInterface newi = (DBusInterface) Proxy.newProxyInstance(ifcs.get(0).getClassLoader(),
ifcs.toArray(Class[]::new), new RemoteInvocationHandler(this, ro));
getImportedObjects().put(newi, ro);
return (T) newi;
} catch (Exception _ex) {
logger.debug("Cannot create proxy object", _ex);
throw new DBusException(
String.format("Failed to create proxy object for %s exported by %s. Reason: %s", _path,
_source, _ex.getMessage()));
}
}
@SuppressWarnings("unchecked")
@Override
public T getExportedObject(String _source, String _path, Class _type) throws DBusException {
ExportedObject o = doWithExportedObjectsAndReturn(DBusException.class, eo -> eo.get(_path));
if (null != o && o.getObject().get() == null) {
unExportObject(_path);
o = null;
}
if (null != o) {
return (T) o.getObject().get();
}
if (null == _source) {
throw new DBusException("Not an object exported by this connection and no remote specified");
}
return dynamicProxy(_source, _path, _type);
}
@Override
public DBusInterface getExportedObject(String _source, String _path) throws DBusException {
return getExportedObject(_source, _path, null);
}
/**
* Release a bus name. Releases the name so that other people can use it
*
* @param _busname
* The name to release. MUST be in dot-notation like "org.freedesktop.local"
* @throws DBusException
* If the busname is incorrectly formatted.
*/
public void releaseBusName(String _busname) throws DBusException {
DBusObjects.requireBusName(_busname);
try {
dbus.ReleaseName(_busname);
} catch (DBusExecutionException _ex) {
logger.debug("Failed to release bus name", _ex);
throw new DBusException(_ex.getMessage());
}
doWithBusNames(bn -> bn.remove(_busname));
}
/**
* Request a bus name. Request the well known name that this should respond to on the Bus.
*
* @param _busname
* The name to respond to. MUST be in dot-notation like "org.freedesktop.local"
* @throws DBusException
* If the register name failed, or our name already exists on the bus. or if busname is incorrectly
* formatted.
*/
public void requestBusName(String _busname) throws DBusException {
DBusObjects.requireBusName(_busname);
UInt32 rv;
try {
rv = dbus.RequestName(_busname,
new UInt32(DBus.DBUS_NAME_FLAG_REPLACE_EXISTING | DBus.DBUS_NAME_FLAG_DO_NOT_QUEUE));
} catch (DBusExecutionException _exDb) {
logger.debug("Failed to request bus name", _exDb);
throw new DBusException(_exDb);
}
if (rv.intValue() == DBus.DBUS_REQUEST_NAME_REPLY_IN_QUEUE
|| rv.intValue() == DBus.DBUS_REQUEST_NAME_REPLY_EXISTS) {
throw new DBusException("Failed to register bus name");
}
doWithBusNames(bn -> bn.add(_busname));
}
/**
* Returns the unique name of this connection.
*
* @return unique name
*/
public String getUniqueName() {
return doWithBusNamesAndReturn(bn -> bn.get(0));
}
/**
* Returns all the names owned by this connection.
*
* @return connection names
*/
public String[] getNames() {
return doWithBusNamesAndReturn(bn -> {
Set names = new TreeSet<>();
names.addAll(bn);
return names;
}).toArray(String[]::new);
}
public I getPeerRemoteObject(String _busname, String _objectpath, Class _type)
throws DBusException {
return getPeerRemoteObject(_busname, _objectpath, _type, true);
}
/**
* Return a reference to a remote object. This method will resolve the well known name (if given) to a unique bus
* name when you call it. This means that if a well known name is released by one process and acquired by another
* calls to objects gained from this method will continue to operate on the original process.
*
* This method will use bus introspection to determine the interfaces on a remote object and so may block and
* may fail. The resulting proxy object will, however, be castable to any interface it implements. It will
* also autostart the process if applicable. Also note that the resulting proxy may fail to execute the correct
* method with overloaded methods and that complex types may fail in interesting ways. Basically, if something odd
* happens, try specifying the interface explicitly.
*
* @param _busname
* The bus name to connect to. Usually a well known bus name in dot-notation (such as
* "org.freedesktop.local") or may be a DBus address such as ":1-16".
* @param _objectpath
* The path on which the process is exporting the object.$
* @return A reference to a remote object.
* @throws ClassCastException
* If type is not a sub-type of DBusInterface
* @throws InvalidBusNameException
* If busname or objectpath are incorrectly formatted.
* @throws DBusException
* If retrieving remote object fails
*/
public DBusInterface getPeerRemoteObject(String _busname, String _objectpath) throws InvalidBusNameException, DBusException {
DBusObjects.requireBusNameOrConnectionId(_busname);
String unique = dbus.GetNameOwner(_busname);
return dynamicProxy(unique, _objectpath, null);
}
/**
* Return a reference to a remote object. This method will always refer to the well known name (if given) rather
* than resolving it to a unique bus name. In particular this means that if a process providing the well known name
* disappears and is taken over by another process proxy objects gained by this method will make calls on the new
* proccess.
*
* This method will use bus introspection to determine the interfaces on a remote object and so may block and
* may fail. The resulting proxy object will, however, be castable to any interface it implements. It will
* also autostart the process if applicable. Also note that the resulting proxy may fail to execute the correct
* method with overloaded methods and that complex types may fail in interesting ways. Basically, if something odd
* happens, try specifying the interface explicitly.
*
* @param _busname
* The bus name to connect to. Usually a well known bus name name in dot-notation (such as
* "org.freedesktop.local") or may be a DBus address such as ":1-16".
* @param _objectpath
* The path on which the process is exporting the object.
* @return A reference to a remote object.
* @throws ClassCastException
* If type is not a sub-type of DBusInterface
* @throws DBusException
* If remote object cannot be retrieved
* @throws InvalidBusNameException
* If busname is incorrectly formatted
* @throws InvalidObjectPathException
* If objectpath is incorrectly formatted
*/
public DBusInterface getRemoteObject(String _busname, String _objectpath) throws DBusException, InvalidBusNameException, InvalidObjectPathException {
DBusObjects.requireBusNameOrConnectionId(_busname);
DBusObjects.requireObjectPath(_objectpath);
return dynamicProxy(_busname, _objectpath, null);
}
/**
* Return a reference to a remote object. This method will resolve the well known name (if given) to a unique bus
* name when you call it. This means that if a well known name is released by one process and acquired by another
* calls to objects gained from this method will continue to operate on the original process.
*
* @param
* class extending {@link DBusInterface}
* @param _busname
* The bus name to connect to. Usually a well known bus name in dot-notation (such as
* "org.freedesktop.local") or may be a DBus address such as ":1-16".
* @param _objectpath
* The path on which the process is exporting the object.$
* @param _type
* The interface they are exporting it on. This type must have the same full class name and exposed
* method signatures as the interface the remote object is exporting.
* @param _autostart
* Disable/Enable auto-starting of services in response to calls on this object. Default is enabled; when
* calling a method with auto-start enabled, if the destination is a well-known name and is not owned the
* bus will attempt to start a process to take the name. When disabled an error is returned immediately.
* @return A reference to a remote object.
* @throws ClassCastException
* If type is not a sub-type of DBusInterface
* @throws DBusException
* If busname or objectpath are incorrectly formatted or type is not in a package.
* @throws InvalidBusNameException
* If busname is incorrectly formatted
*/
public I getPeerRemoteObject(String _busname, String _objectpath, Class _type,
boolean _autostart) throws DBusException, InvalidBusNameException {
if (null == _busname) {
throw new InvalidBusNameException();
}
DBusObjects.requireBusNameOrConnectionId(_busname);
String unique = dbus.GetNameOwner(_busname);
return getRemoteObject(unique, _objectpath, _type, _autostart);
}
/**
* Return a reference to a remote object. This method will always refer to the well known name (if given) rather
* than resolving it to a unique bus name. In particular this means that if a process providing the well known name
* disappears and is taken over by another process proxy objects gained by this method will make calls on the new
* proccess.
*
* @param
* class extending {@link DBusInterface}
* @param _busname
* The bus name to connect to. Usually a well known bus name name in dot-notation (such as
* "org.freedesktop.local") or may be a DBus address such as ":1-16".
* @param _objectpath
* The path on which the process is exporting the object.
* @param _type
* The interface they are exporting it on. This type must have the same full class name and exposed
* method signatures as the interface the remote object is exporting.
* @return A reference to a remote object.
* @throws ClassCastException
* If type is not a sub-type of DBusInterface
* @throws DBusException
* If busname or objectpath are incorrectly formatted or type is not in a package.
*/
public I getRemoteObject(String _busname, String _objectpath, Class _type)
throws DBusException {
return getRemoteObject(_busname, _objectpath, _type, true);
}
/**
* Return a reference to a remote object. This method will always refer to the well known name (if given) rather
* than resolving it to a unique bus name. In particular this means that if a process providing the well known name
* disappears and is taken over by another process proxy objects gained by this method will make calls on the new
* proccess.
*
* @param
* class extending {@link DBusInterface}
* @param _busname
* The bus name to connect to. Usually a well known bus name name in dot-notation (such as
* "org.freedesktop.local") or may be a DBus address such as ":1-16".
* @param _objectpath
* The path on which the process is exporting the object.
* @param _type
* The interface they are exporting it on. This type must have the same full class name and exposed
* method signatures as the interface the remote object is exporting.
* @param _autostart
* Disable/Enable auto-starting of services in response to calls on this object. Default is enabled; when
* calling a method with auto-start enabled, if the destination is a well-known name and is not owned the
* bus will attempt to start a process to take the name. When disabled an error is returned immediately.
* @return A reference to a remote object.
* @throws ClassCastException
* If type is not a sub-type of DBusInterface
* @throws DBusException
* If busname or objectpath are incorrectly formatted or type is not in a package.
*/
@SuppressWarnings("unchecked")
public I getRemoteObject(String _busname, String _objectpath, Class _type,
boolean _autostart) throws DBusException {
if (_type == null) {
throw new ClassCastException("Not A DBus Interface");
}
DBusObjects.requireBusNameOrConnectionId(_busname);
DBusObjects.requireObjectPath(_objectpath);
if (!DBusInterface.class.isAssignableFrom(_type)) {
throw new ClassCastException("Not A DBus Interface");
}
// don't let people import things which don't have a
// valid D-Bus interface name
if (_type.getName().equals(_type.getSimpleName())) {
throw new DBusException("DBusInterfaces cannot be declared outside a package");
}
RemoteObject ro = new RemoteObject(_busname, _objectpath, _type, _autostart);
I i = (I) Proxy.newProxyInstance(_type.getClassLoader(), new Class[] {
_type
}, new RemoteInvocationHandler(this, ro));
getImportedObjects().put(i, ro);
return i;
}
/**
* Remove a Signal Handler. Stops listening for this signal.
*
* @param
* class extending {@link DBusSignal}
* @param _type
* The signal to watch for.
* @param _source
* The source of the signal.
* @param _handler
* the handler
* @throws DBusException
* If listening for the signal on the bus failed.
* @throws ClassCastException
* If type is not a sub-type of DBusSignal.
*/
public void removeSigHandler(Class _type, String _source, DBusSigHandler _handler)
throws DBusException {
validateSignal(_type, _source);
removeSigHandler(new DBusMatchRule(_type, _source, null), _handler);
}
/**
* Remove a Signal Handler. Stops listening for this signal.
*
* @param
* class extending {@link DBusSignal}
* @param _type
* The signal to watch for.
* @param _source
* The source of the signal.
* @param _object
* The object emitting the signal.
* @param _handler
* the handler
* @throws DBusException
* If listening for the signal on the bus failed.
* @throws ClassCastException
* If type is not a sub-type of DBusSignal.
*/
public void removeSigHandler(Class _type, String _source, DBusInterface _object,
DBusSigHandler _handler) throws DBusException {
validateSignal(_type, _source);
String objectPath = getImportedObjects().get(_object).getObjectPath();
DBusObjects.requireObjectPath(objectPath);
removeSigHandler(new DBusMatchRule(_type, _source, objectPath), _handler);
}
/**
* {@inheritDoc}
*/
@Override
protected void removeSigHandler(DBusMatchRule _rule, DBusSigHandler _handler)
throws DBusException {
Queue> dbusSignalList = getHandledSignals().get(_rule);
if (null != dbusSignalList) {
dbusSignalList.remove(_handler);
if (dbusSignalList.isEmpty()) {
getHandledSignals().remove(_rule);
try {
dbus.RemoveMatch(_rule.toString());
} catch (NotConnected _ex) {
logger.debug("No connection.", _ex);
} catch (DBusExecutionException _ex) {
logger.debug("Error removing signal", _ex);
throw new DBusException(_ex);
}
}
}
}
/**
* Add a Signal Handler. Adds a signal handler to call when a signal is received which matches the specified type,
* name and source.
*
* @param
* class extending {@link DBusSignal}
* @param _type
* The signal to watch for.
* @param _source
* The process which will send the signal. This MUST be a unique bus name and not a well known
* name.
* @return closeable that removes signal handler
* @param _handler
* The handler to call when a signal is received.
* @throws DBusException
* If listening for the signal on the bus failed.
* @throws ClassCastException
* If type is not a sub-type of DBusSignal.
*/
public AutoCloseable addSigHandler(Class _type, String _source, DBusSigHandler _handler)
throws DBusException {
validateSignal(_type, _source);
addSigHandler(new DBusMatchRule(_type, _source, null), (DBusSigHandler extends DBusSignal>) _handler);
return () -> removeSigHandler(_type, _source, _handler);
}
/**
* Add a Signal Handler. Adds a signal handler to call when a signal is received which matches the specified type,
* name, source and object.
*
* @param
* class extending {@link DBusSignal}
* @param _type
* The signal to watch for.
* @param _source
* The process which will send the signal. This MUST be a unique bus name and not a well known
* name.
* @param _object
* The object from which the signal will be emitted
* @param _handler
* The handler to call when a signal is received.
* @return closeable that removes signal handler
* @throws DBusException
* If listening for the signal on the bus failed.
* @throws ClassCastException
* If type is not a sub-type of DBusSignal.
*/
public AutoCloseable addSigHandler(Class _type, String _source, DBusInterface _object,
DBusSigHandler _handler) throws DBusException {
validateSignal(_type, _source);
String objectPath = getImportedObjects().get(_object).getObjectPath();
DBusObjects.requireObjectPath(objectPath);
addSigHandler(new DBusMatchRule(_type, _source, objectPath), (DBusSigHandler extends DBusSignal>) _handler);
return () -> removeSigHandler(_type, _source, _object, _handler);
}
/**
* Checks if given type is a DBusSignal and matches the required rules.
*
* @param type of class
* @param _type class
* @param _source
* @throws DBusException when validation fails
*/
private void validateSignal(Class _type, String _source) throws DBusException {
if (!DBusSignal.class.isAssignableFrom(_type)) {
throw new ClassCastException("Not A DBus Signal");
}
DBusObjects.requireNotBusName(_source, "Cannot watch for signals based on well known bus name as source. Only unique names supported");
DBusObjects.requireConnectionId(_source);
}
/**
* {@inheritDoc}
*/
@Override
public AutoCloseable addSigHandler(DBusMatchRule _rule, DBusSigHandler _handler)
throws DBusException {
Objects.requireNonNull(_rule, "Match rule cannot be null");
Objects.requireNonNull(_handler, "Handler cannot be null");
AtomicBoolean addMatch = new AtomicBoolean(false); // flag to perform action if this is a new signal key
Queue> dbusSignalList =
getHandledSignals().computeIfAbsent(_rule, v -> {
Queue> signalList = new ConcurrentLinkedQueue<>();
addMatch.set(true);
return signalList;
});
// add handler to signal list
dbusSignalList.add(_handler);
// add match rule if this rule is new
if (addMatch.get()) {
try {
dbus.AddMatch(_rule.toString());
} catch (DBusExecutionException _ex) {
logger.debug("Cannot add match rule: " + _rule.toString(), _ex);
throw new DBusException("Cannot add match rule.", _ex);
}
}
return () -> removeSigHandler(_rule, _handler);
}
/**
* Disconnect from the Bus.
* If this is a shared connection, it only disconnects when the last reference to the bus has called disconnect.
* If this is not a shared connection, disconnect will close the connection instantly.
*/
@Override
public synchronized void disconnect() {
if (!isConnected()) { // already disconnected
return;
}
// if this is a shared connection, keep track of disconnect calls
if (shared) {
synchronized (CONNECTIONS) {
DBusConnection connection = CONNECTIONS.get(getAddress().toString());
if (connection != null) {
if (connection.getConcurrentConnections().get() <= 1) { // one left, this should be ourselves
CONNECTIONS.remove(getAddress().toString());
super.disconnect();
} else {
logger.debug("Still {} connections left, decreasing connection counter", connection.getConcurrentConnections().get() - 1);
Optional.ofNullable(getDisconnectCallback()).ifPresent(cb -> cb.requestedDisconnect(connection.getConcurrentConnections().get()));
connection.getConcurrentConnections().decrementAndGet();
}
}
}
} else { // this is a standalone non-shared session, disconnect directly using super's implementation
IDisconnectAction beforeDisconnectAction = () -> {
// get all busnames from the list which matches the usual pattern
// this is required as the list also contains internal names like ":1.11"
// it is also required to put the results in a new list, otherwise we would get a
// concurrent modification exception later (calling releaseBusName() or unExportObject() will modify the busnames List)
doWithBusNames(bn -> {
List lBusNames = bn.stream()
.filter(DBusObjects::validateBusName)
.toList();
lBusNames.forEach(busName -> {
try {
releaseBusName(busName);
} catch (DBusException _ex) {
logger.error("Error while releasing busName '" + busName + "'.", _ex);
}
});
});
// remove all exported objects before disconnecting
doWithExportedObjects(null, eos -> {
List exportedKeys = eos.keySet().stream().filter(Objects::nonNull).toList();
for (String key : exportedKeys) {
unExportObject(key);
}
});
};
super.disconnect(beforeDisconnectAction, null);
}
}
/**
* Same as disconnect.
*/
@Override
public void close() throws IOException {
disconnect();
}
@Override
public String getMachineId() {
return machineId;
}
@Override
public void removeGenericSigHandler(DBusMatchRule _rule, DBusSigHandler _handler) throws DBusException {
Queue> genericSignalsList = getGenericHandledSignals().get(_rule);
if (null != genericSignalsList) {
genericSignalsList.remove(_handler);
if (genericSignalsList.isEmpty()) {
getGenericHandledSignals().remove(_rule);
try {
dbus.RemoveMatch(_rule.toString());
} catch (NotConnected _ex) {
logger.debug("No connection.", _ex);
} catch (DBusExecutionException _ex) {
logger.debug("Error removing generic signal", _ex);
throw new DBusException(_ex);
}
}
}
}
@Override
public AutoCloseable addGenericSigHandler(DBusMatchRule _rule, DBusSigHandler _handler) throws DBusException {
AtomicBoolean addMatch = new AtomicBoolean(false); // flag to perform action if this is a new signal key
Queue> genericSignalsList =
getGenericHandledSignals().computeIfAbsent(_rule, v -> {
Queue> signalsList = new ConcurrentLinkedQueue<>();
addMatch.set(true);
return signalsList;
});
genericSignalsList.add(_handler);
if (addMatch.get()) {
try {
dbus.AddMatch(_rule.toString());
} catch (DBusExecutionException _ex) {
logger.debug("Error adding signal handler", _ex);
throw new DBusException(_ex.getMessage());
}
}
return () -> removeGenericSigHandler(_rule, _handler);
}
private final class SigHandler implements DBusSigHandler {
@Override
public void handle(DBusSignal _signal) {
if (_signal instanceof DBus.NameAcquired na) {
doWithBusNames(bn -> bn.add(na.name));
}
}
}
public enum DBusBusType {
/**
* System Bus
*/
SYSTEM,
/**
* Session Bus
*/
SESSION;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy