Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.freedesktop.dbus.DBusConnection Maven / Gradle / Ivy
Go to download
Improved version of the DBus-Java library provided by freedesktop.org (https://dbus.freedesktop.org/doc/dbus-java/).
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
import static org.freedesktop.dbus.Gettext.t;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Proxy;
import java.text.MessageFormat;
import java.text.ParseException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.Vector;
import org.freedesktop.DBus;
import org.freedesktop.dbus.exceptions.DBusException;
import org.freedesktop.dbus.exceptions.DBusExecutionException;
import org.freedesktop.dbus.exceptions.NotConnected;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** 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 {
private final Logger logger = LoggerFactory.getLogger(getClass());
/**
* Add addresses of peers to a set which will watch for them to
* disappear and automatically remove them from the set.
*/
public class PeerSet implements Set, DBusSigHandler {
private Set addresses;
public PeerSet() {
addresses = new TreeSet();
try {
addSigHandler(new DBusMatchRule(DBus.NameOwnerChanged.class, null, null), this);
} catch (DBusException dbe) {
if (EXCEPTION_DEBUG) {
logger.error("", dbe);
}
}
}
@Override
public void handle(DBus.NameOwnerChanged noc) {
logger.debug("Received NameOwnerChanged(" + noc.name + "," + noc.oldOwner + "," + noc.newOwner + ")");
if ("".equals(noc.newOwner) && addresses.contains(noc.name)) {
remove(noc.name);
}
}
@Override
public boolean add(String address) {
logger.debug("Adding " + address);
synchronized (addresses) {
return addresses.add(address);
}
}
@Override
public boolean addAll(Collection extends String> _addresses) {
synchronized (this.addresses) {
return this.addresses.addAll(_addresses);
}
}
@Override
public void clear() {
synchronized (addresses) {
addresses.clear();
}
}
@Override
public boolean contains(Object o) {
return addresses.contains(o);
}
@Override
public boolean containsAll(Collection> os) {
return addresses.containsAll(os);
}
@Override
public boolean equals(Object o) {
if (o instanceof PeerSet) {
return ((PeerSet) o).addresses.equals(addresses);
} else {
return false;
}
}
@Override
public int hashCode() {
return addresses.hashCode();
}
@Override
public boolean isEmpty() {
return addresses.isEmpty();
}
@Override
public Iterator iterator() {
return addresses.iterator();
}
@Override
public boolean remove(Object o) {
logger.debug("Removing " + o);
synchronized (addresses) {
return addresses.remove(o);
}
}
@Override
public boolean removeAll(Collection> os) {
synchronized (addresses) {
return addresses.removeAll(os);
}
}
@Override
public boolean retainAll(Collection> os) {
synchronized (addresses) {
return addresses.retainAll(os);
}
}
@Override
public int size() {
return addresses.size();
}
@Override
public Object[] toArray() {
synchronized (addresses) {
return addresses.toArray();
}
}
@Override
public T[] toArray(T[] a) {
synchronized (addresses) {
return addresses.toArray(a);
}
}
}
private class SigHandler implements DBusSigHandler {
@Override
public void handle(DBusSignal s) {
if (s instanceof org.freedesktop.DBus.Local.Disconnected) {
logger.warn("Handling Disconnected signal from bus");
try {
Error err = new Error("org.freedesktop.DBus.Local", "org.freedesktop.DBus.Local.Disconnected", 0, "s", new Object[] {
t("Disconnected")
});
if (null != pendingCalls) {
synchronized (pendingCalls) {
long[] set = pendingCalls.getKeys();
for (long l : set) {
if (-1 != l) {
MethodCall m = pendingCalls.remove(l);
if (null != m) {
m.setReply(err);
}
}
}
}
}
synchronized (pendingErrors) {
pendingErrors.add(err);
}
} catch (DBusException exDb) {
}
} else if (s instanceof org.freedesktop.DBus.NameAcquired) {
busnames.add(((org.freedesktop.DBus.NameAcquired) s).name);
}
}
}
/**
* System Bus
*/
public static final int SYSTEM = 0;
/**
* Session Bus
*/
public static final int SESSION = 1;
public static final String DEFAULT_SYSTEM_BUS_ADDRESS = "unix:path=/var/run/dbus/system_bus_socket";
private List busnames;
private static final Map CONN = new HashMap();
private int refcount = 0;
private Object reflock = new Object();
private DBus dbus;
/**
* Connect to the BUS. If a connection already exists to the specified Bus, a reference to it is returned.
* @param address The address of the bus to connect to
* @throws DBusException If there is a problem connecting to the Bus.
* @return {@link DBusConnection}
*/
public static DBusConnection getConnection(String address) throws DBusException {
synchronized (CONN) {
DBusConnection c = CONN.get(address);
if (null != c) {
synchronized (c.reflock) {
c.refcount++;
}
return c;
} else {
c = new DBusConnection(address);
CONN.put(address, c);
return c;
}
}
}
/**
* Connect to the BUS. If a connection already exists to the specified Bus, a reference to it is returned.
* @param bustype The Bus to connect to.
* @see #SYSTEM
* @see #SESSION
*
* @return {@link DBusConnection}
*
* @throws DBusException If there is a problem connecting to the Bus.
*
*/
public static DBusConnection getConnection(int bustype) throws DBusException {
synchronized (CONN) {
Logger logger = LoggerFactory.getLogger(DBusConnection.class);
String s = null;
switch (bustype) {
case SYSTEM:
s = System.getenv("DBUS_SYSTEM_BUS_ADDRESS");
if (null == s) {
s = DEFAULT_SYSTEM_BUS_ADDRESS;
}
break;
case SESSION:
s = System.getenv("DBUS_SESSION_BUS_ADDRESS");
if (null == s) {
// address gets stashed in $HOME/.dbus/session-bus/`dbus-uuidgen --get`-`sed 's/:\(.\)\..*/\1/' <<< $DISPLAY`
String display = System.getenv("DISPLAY");
if (null == display) {
throw new DBusException(t("Cannot Resolve Session Bus Address"));
}
if (!display.startsWith(":") && display.contains(":")) { // display seems to be a remote display (e.g. X forward through SSH)
display = display.substring(display.indexOf(':'));
}
File uuidfile = new File("/var/lib/dbus/machine-id");
if (!uuidfile.exists()) {
throw new DBusException(t("Cannot Resolve Session Bus Address"));
}
try (BufferedReader r = new BufferedReader(new FileReader(uuidfile))) {
String uuid = r.readLine();
String homedir = System.getProperty("user.home");
File addressfile = new File(homedir + "/.dbus/session-bus", uuid + "-" + display.replaceAll(":([0-9]*)\\..*", "$1"));
if (!addressfile.exists()) {
throw new DBusException(t("Cannot Resolve Session Bus Address"));
}
try (BufferedReader rf = new BufferedReader(new FileReader(addressfile))) {
String l;
while (null != (l = rf.readLine())) {
logger.trace("Reading D-Bus session data: " + l);
if (l.matches("DBUS_SESSION_BUS_ADDRESS.*")) {
s = l.replaceAll("^[^=]*=", "");
logger.trace("Parsing " + l + " to " + s);
}
}
}
if (null == s || "".equals(s)) {
throw new DBusException(t("Cannot Resolve Session Bus Address"));
}
logger.info("Read bus address " + s + " from file " + addressfile.toString());
} catch (Exception e) {
if (EXCEPTION_DEBUG) {
logger.error("", e);
}
throw new DBusException(t("Cannot Resolve Session Bus Address"));
}
}
break;
default:
throw new DBusException(t("Invalid Bus Type: ") + bustype);
}
DBusConnection c = CONN.get(s);
logger.trace("Getting bus connection for " + s + ": " + c);
if (null != c) {
synchronized (c.reflock) {
c.refcount++;
}
return c;
} else {
logger.debug("Creating new bus connection to: " + s);
c = new DBusConnection(s);
CONN.put(s, c);
return c;
}
}
}
private DBusConnection(String address) throws DBusException {
super(address);
busnames = new Vector();
synchronized (reflock) {
refcount = 1;
}
try {
transport = new Transport(addr, AbstractConnection.TIMEOUT);
connected = true;
} catch (IOException ioe) {
if (EXCEPTION_DEBUG) {
logger.error("", ioe);
}
disconnect();
throw new DBusException(t("Failed to connect to bus ") + ioe.getMessage());
} catch (ParseException exP) {
if (EXCEPTION_DEBUG) {
logger.error("", exP);
}
disconnect();
throw new DBusException(t("Failed to connect to bus ") + exP.getMessage());
}
// start listening for calls
listen();
// register disconnect handlers
DBusSigHandler> h = new SigHandler();
addSigHandlerWithoutMatch(org.freedesktop.DBus.Local.Disconnected.class, h);
addSigHandlerWithoutMatch(org.freedesktop.DBus.NameAcquired.class, h);
// register ourselves
dbus = getRemoteObject("org.freedesktop.DBus", "/org/freedesktop/DBus", DBus.class);
try {
busnames.add(dbus.Hello());
} catch (DBusExecutionException dbee) {
if (EXCEPTION_DEBUG) {
logger.error("", dbee);
}
throw new DBusException(dbee.getMessage());
}
}
DBusInterface dynamicProxy(String source, String path) throws DBusException {
logger.info("Introspecting " + path + " on " + source + " for dynamic proxy creation");
try {
DBus.Introspectable intro = getRemoteObject(source, path, DBus.Introspectable.class);
String data = intro.Introspect();
logger.trace("Got introspection data: " + data);
String[] tags = data.split("[<>]");
Vector ifaces = new Vector();
for (String tag : tags) {
if (tag.startsWith("interface")) {
ifaces.add(tag.replaceAll("^interface *name *= *['\"]([^'\"]*)['\"].*$", "$1"));
}
}
Vector> ifcs = new Vector>();
for (String iface : ifaces) {
logger.debug("Trying interface " + iface);
int j = 0;
while (j >= 0) {
try {
Class> ifclass = Class.forName(iface);
if (!ifcs.contains(ifclass)) {
ifcs.add(ifclass);
}
break;
} catch (Exception e) {
}
j = iface.lastIndexOf(".");
char[] cs = iface.toCharArray();
if (j >= 0) {
cs[j] = '$';
iface = String.valueOf(cs);
}
}
}
if (ifcs.size() == 0) {
throw new DBusException(t("Could not find an interface to cast to"));
}
RemoteObject ro = new RemoteObject(source, path, null, false);
DBusInterface newi = (DBusInterface) Proxy.newProxyInstance(ifcs.get(0).getClassLoader(), ifcs.toArray(new Class[0]), new RemoteInvocationHandler(this, ro));
importedObjects.put(newi, ro);
return newi;
} catch (Exception e) {
if (EXCEPTION_DEBUG) {
logger.error("", e);
}
throw new DBusException(MessageFormat.format(t("Failed to create proxy object for {0} exported by {1}. Reason: {2}"), new Object[] {
path, source, e.getMessage()
}));
}
}
@Override
DBusInterface getExportedObject(String source, String path) throws DBusException {
ExportedObject o = null;
synchronized (exportedObjects) {
o = exportedObjects.get(path);
}
if (null != o && null == o.object.get()) {
unExportObject(path);
o = null;
}
if (null != o) {
return o.object.get();
}
if (null == source) {
throw new DBusException(t("Not an object exported by this connection and no remote specified"));
}
return dynamicProxy(source, path);
}
/**
* 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 {
if (!busname.matches(BUSNAME_REGEX) || busname.length() > MAX_NAME_LENGTH) {
throw new DBusException(t("Invalid bus name"));
}
synchronized (this.busnames) {
try {
dbus.ReleaseName(busname);
} catch (DBusExecutionException dbee) {
if (EXCEPTION_DEBUG) {
logger.error("", dbee);
}
throw new DBusException(dbee.getMessage());
}
this.busnames.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 {
if (!busname.matches(BUSNAME_REGEX) || busname.length() > MAX_NAME_LENGTH) {
throw new DBusException(t("Invalid bus name"));
}
synchronized (this.busnames) {
UInt32 rv;
try {
rv = dbus.RequestName(busname, new UInt32(DBus.DBUS_NAME_FLAG_REPLACE_EXISTING | DBus.DBUS_NAME_FLAG_DO_NOT_QUEUE));
} catch (DBusExecutionException dbee) {
if (EXCEPTION_DEBUG) {
logger.error("", dbee);
}
throw new DBusException(dbee.getMessage());
}
switch (rv.intValue()) {
case DBus.DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
break;
case DBus.DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
throw new DBusException(t("Failed to register bus name"));
case DBus.DBUS_REQUEST_NAME_REPLY_EXISTS:
throw new DBusException(t("Failed to register bus name"));
case DBus.DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
break;
default:
break;
}
this.busnames.add(busname);
}
}
/**
* Returns the unique name of this connection.
* @return unique name
*/
public String getUniqueName() {
return busnames.get(0);
}
/**
* Returns all the names owned by this connection.
* @return connection names
*/
public String[] getNames() {
Set names = new TreeSet();
names.addAll(busnames);
return names.toArray(new String[0]);
}
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 DBusException If busname or objectpath are incorrectly formatted.
*/
public DBusInterface getPeerRemoteObject(String busname, String objectpath) throws DBusException {
if (null == busname) {
throw new DBusException(t("Invalid bus name: null"));
}
if ((!busname.matches(BUSNAME_REGEX) && !busname.matches(CONNID_REGEX)) || busname.length() > MAX_NAME_LENGTH) {
throw new DBusException(t("Invalid bus name: ") + busname);
}
String unique = dbus.GetNameOwner(busname);
return dynamicProxy(unique, objectpath);
}
/**
* 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 busname or objectpath are incorrectly formatted.
*/
public DBusInterface getRemoteObject(String busname, String objectpath) throws DBusException {
if (null == busname) {
throw new DBusException(t("Invalid bus name: null"));
}
if (null == objectpath) {
throw new DBusException(t("Invalid object path: null"));
}
if ((!busname.matches(BUSNAME_REGEX) && !busname.matches(CONNID_REGEX)) || busname.length() > MAX_NAME_LENGTH) {
throw new DBusException(t("Invalid bus name: ") + busname);
}
if (!objectpath.matches(OBJECT_REGEX) || objectpath.length() > MAX_NAME_LENGTH) {
throw new DBusException(t("Invalid object path: ") + objectpath);
}
return dynamicProxy(busname, objectpath);
}
/**
* 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.
*/
public I getPeerRemoteObject(String busname, String objectpath, Class type, boolean autostart) throws DBusException {
if (null == busname) {
throw new DBusException(t("Invalid bus name: null"));
}
if ((!busname.matches(BUSNAME_REGEX) && !busname.matches(CONNID_REGEX)) || busname.length() > MAX_NAME_LENGTH) {
throw new DBusException(t("Invalid bus name: ") + 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 (null == busname) {
throw new DBusException(t("Invalid bus name: null"));
}
if (null == objectpath) {
throw new DBusException(t("Invalid object path: null"));
}
if (null == type) {
throw new ClassCastException(t("Not A DBus Interface"));
}
if ((!busname.matches(BUSNAME_REGEX) && !busname.matches(CONNID_REGEX)) || busname.length() > MAX_NAME_LENGTH) {
throw new DBusException(t("Invalid bus name: ") + busname);
}
if (!objectpath.matches(OBJECT_REGEX) || objectpath.length() > MAX_NAME_LENGTH) {
throw new DBusException(t("Invalid object path: ") + objectpath);
}
if (!DBusInterface.class.isAssignableFrom(type)) {
throw new ClassCastException(t("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(t("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));
importedObjects.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 {
if (!DBusSignal.class.isAssignableFrom(type)) {
throw new ClassCastException(t("Not A DBus Signal"));
}
if (source.matches(BUSNAME_REGEX)) {
throw new DBusException(t("Cannot watch for signals based on well known bus name as source, only unique names."));
}
if (!source.matches(CONNID_REGEX) || source.length() > MAX_NAME_LENGTH) {
throw new DBusException(t("Invalid bus name: ") + 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 {
if (!DBusSignal.class.isAssignableFrom(type)) {
throw new ClassCastException(t("Not A DBus Signal"));
}
if (source.matches(BUSNAME_REGEX)) {
throw new DBusException(t("Cannot watch for signals based on well known bus name as source, only unique names."));
}
if (!source.matches(CONNID_REGEX) || source.length() > MAX_NAME_LENGTH) {
throw new DBusException(t("Invalid bus name: ") + source);
}
String objectpath = importedObjects.get(object).objectpath;
if (!objectpath.matches(OBJECT_REGEX) || objectpath.length() > MAX_NAME_LENGTH) {
throw new DBusException(t("Invalid object path: ") + objectpath);
}
removeSigHandler(new DBusMatchRule(type, source, objectpath), handler);
}
@Override
protected void removeSigHandler(DBusMatchRule rule, DBusSigHandler handler) throws DBusException {
SignalTuple key = new SignalTuple(rule.getInterface(), rule.getMember(), rule.getObject(), rule.getSource());
synchronized (handledSignals) {
Vector> v = handledSignals.get(key);
if (null != v) {
v.remove(handler);
if (0 == v.size()) {
handledSignals.remove(key);
try {
dbus.RemoveMatch(rule.toString());
} catch (NotConnected exNc) {
if (EXCEPTION_DEBUG) {
logger.error("", exNc);
}
} catch (DBusExecutionException dbee) {
if (EXCEPTION_DEBUG) {
logger.error("", dbee);
}
throw new DBusException(dbee);
}
}
}
}
}
/**
* 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.
* @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 void addSigHandler(Class type, String source, DBusSigHandler handler) throws DBusException {
if (!DBusSignal.class.isAssignableFrom(type)) {
throw new ClassCastException(t("Not A DBus Signal"));
}
if (source.matches(BUSNAME_REGEX)) {
throw new DBusException(t("Cannot watch for signals based on well known bus name as source, only unique names."));
}
if (!source.matches(CONNID_REGEX) || source.length() > MAX_NAME_LENGTH) {
throw new DBusException(t("Invalid bus name: ") + source);
}
addSigHandler(new DBusMatchRule(type, source, null), (DBusSigHandler extends DBusSignal>) 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.
* @throws DBusException If listening for the signal on the bus failed.
* @throws ClassCastException If type is not a sub-type of DBusSignal.
*/
public void addSigHandler(Class type, String source, DBusInterface object, DBusSigHandler handler) throws DBusException {
if (!DBusSignal.class.isAssignableFrom(type)) {
throw new ClassCastException(t("Not A DBus Signal"));
}
if (source.matches(BUSNAME_REGEX)) {
throw new DBusException(t("Cannot watch for signals based on well known bus name as source, only unique names."));
}
if (!source.matches(CONNID_REGEX) || source.length() > MAX_NAME_LENGTH) {
throw new DBusException(t("Invalid bus name: ") + source);
}
String objectpath = importedObjects.get(object).objectpath;
if (!objectpath.matches(OBJECT_REGEX) || objectpath.length() > MAX_NAME_LENGTH) {
throw new DBusException(t("Invalid object path: ") + objectpath);
}
addSigHandler(new DBusMatchRule(type, source, objectpath), (DBusSigHandler extends DBusSignal>) handler);
}
@Override
protected void addSigHandler(DBusMatchRule rule, DBusSigHandler handler) throws DBusException {
try {
dbus.AddMatch(rule.toString());
} catch (DBusExecutionException dbee) {
if (EXCEPTION_DEBUG) {
logger.error("", dbee);
}
throw new DBusException(dbee.getMessage());
}
SignalTuple key = new SignalTuple(rule.getInterface(), rule.getMember(), rule.getObject(), rule.getSource());
synchronized (handledSignals) {
Vector> v = handledSignals.get(key);
if (null == v) {
v = new Vector>();
v.add(handler);
handledSignals.put(key, v);
} else {
v.add(handler);
}
}
}
/**
* Disconnect from the Bus.
* This only disconnects when the last reference to the bus has disconnect called on it
* or has been destroyed.
*/
@Override
public void disconnect() {
synchronized (CONN) {
synchronized (reflock) {
if (0 == --refcount) {
logger.info("Disconnecting DBusConnection");
// Set all pending messages to have an error.
try {
Error err = new Error("org.freedesktop.DBus.Local", "org.freedesktop.DBus.Local.Disconnected", 0, "s", new Object[] {
t("Disconnected")
});
synchronized (pendingCalls) {
long[] set = pendingCalls.getKeys();
for (long l : set) {
if (-1 != l) {
MethodCall m = pendingCalls.remove(l);
if (null != m) {
m.setReply(err);
}
}
}
pendingCalls = null;
}
synchronized (pendingErrors) {
pendingErrors.add(err);
}
} catch (DBusException dbe) {
}
CONN.remove(addr);
super.disconnect();
}
}
}
}
}