Package com.lucimber.dbus.standard


package com.lucimber.dbus.standard
Standard D-Bus interfaces and implementations for common D-Bus functionality.

This package provides Java implementations of standard D-Bus interfaces that are commonly used across different D-Bus applications. These interfaces follow the official D-Bus specification and provide type-safe access to standard D-Bus functionality.

Getting Started

For first-time users: Start with Introspectable to discover available interfaces and methods, then use Properties for property access. The Peer interface provides connectivity testing, while ObjectManager enables efficient object hierarchy discovery. Most D-Bus interactions use custom interfaces specific to each service.

Standard Interfaces

Introspection Interface

The org.freedesktop.DBus.Introspectable interface allows clients to discover the structure and capabilities of D-Bus objects:


 // Introspect a D-Bus object
 OutboundMethodCall introspectCall = OutboundMethodCall.Builder
     .create()
     .withPath(DBusObjectPath.valueOf("/org/example/Object"))
     .withInterface(DBusString.valueOf("org.freedesktop.DBus.Introspectable"))
     .withMember(DBusString.valueOf("Introspect"))
     .withDestination(DBusString.valueOf("org.example.Service"))
     .withReplyExpected(true)
     .build();

 CompletableFuture<InboundMessage> response = connection.sendRequest(introspectCall);
 response.thenAccept(reply -> {
     if (reply instanceof InboundMethodReturn) {
         InboundMethodReturn returnMsg = (InboundMethodReturn) reply;
         List<DBusType> body = returnMsg.getBody();
         if (!body.isEmpty()) {
             DBusString xmlData = (DBusString) body.get(0);
             System.out.println("Introspection XML: " + xmlData.toString());
         }
     }
 });
 

Properties Interface

The org.freedesktop.DBus.Properties interface provides standardized property access for D-Bus objects:


 // Get a property value
 OutboundMethodCall getProperty = OutboundMethodCall.Builder
     .create()
     .withPath(DBusObjectPath.valueOf("/org/example/Object"))
     .withInterface(DBusString.valueOf("org.freedesktop.DBus.Properties"))
     .withMember(DBusString.valueOf("Get"))
     .withDestination(DBusString.valueOf("org.example.Service"))
     .withBody(Arrays.asList(
         DBusString.valueOf("org.example.Interface"),
         DBusString.valueOf("PropertyName")
     ))
     .withReplyExpected(true)
     .build();

 // Set a property value
 OutboundMethodCall setProperty = OutboundMethodCall.Builder
     .create()
     .withPath(DBusObjectPath.valueOf("/org/example/Object"))
     .withInterface(DBusString.valueOf("org.freedesktop.DBus.Properties"))
     .withMember(DBusString.valueOf("Set"))
     .withDestination(DBusString.valueOf("org.example.Service"))
     .withBody(Arrays.asList(
         DBusString.valueOf("org.example.Interface"),
         DBusString.valueOf("PropertyName"),
         DBusVariant.valueOf(DBusString.valueOf("NewValue"))
     ))
     .withReplyExpected(true)
     .build();

 // Get all properties
 OutboundMethodCall getAllProperties = OutboundMethodCall.Builder
     .create()
     .withPath(DBusObjectPath.valueOf("/org/example/Object"))
     .withInterface(DBusString.valueOf("org.freedesktop.DBus.Properties"))
     .withMember(DBusString.valueOf("GetAll"))
     .withDestination(DBusString.valueOf("org.example.Service"))
     .withBody(Arrays.asList(
         DBusString.valueOf("org.example.Interface")
     ))
     .withReplyExpected(true)
     .build();
 

Peer Interface

The org.freedesktop.DBus.Peer interface provides basic peer-to-peer functionality for D-Bus connections:


 // Ping a D-Bus peer
 OutboundMethodCall ping = OutboundMethodCall.Builder
     .create()
     .withPath(DBusObjectPath.valueOf("/"))
     .withInterface(DBusString.valueOf("org.freedesktop.DBus.Peer"))
     .withMember(DBusString.valueOf("Ping"))
     .withDestination(DBusString.valueOf("org.example.Service"))
     .withReplyExpected(true)
     .build();

 // Get machine UUID
 OutboundMethodCall getMachineId = OutboundMethodCall.Builder
     .create()
     .withPath(DBusObjectPath.valueOf("/"))
     .withInterface(DBusString.valueOf("org.freedesktop.DBus.Peer"))
     .withMember(DBusString.valueOf("GetMachineId"))
     .withDestination(DBusString.valueOf("org.example.Service"))
     .withReplyExpected(true)
     .build();
 

ObjectManager Interface

The org.freedesktop.DBus.ObjectManager interface provides efficient enumeration of object hierarchies:


 // Get all managed objects
 OutboundMethodCall getManagedObjects = OutboundMethodCall.Builder
     .create()
     .withPath(DBusObjectPath.valueOf("/org/example"))
     .withInterface(DBusString.valueOf("org.freedesktop.DBus.ObjectManager"))
     .withMember(DBusString.valueOf("GetManagedObjects"))
     .withDestination(DBusString.valueOf("org.example.Service"))
     .withReplyExpected(true)
     .build();

 CompletableFuture<InboundMessage> response = connection.sendRequest(getManagedObjects);
 response.thenAccept(reply -> {
     if (reply instanceof InboundMethodReturn) {
         InboundMethodReturn returnMsg = (InboundMethodReturn) reply;
         List<DBusType> body = returnMsg.getBody();
         if (!body.isEmpty()) {
             DBusDict<DBusObjectPath, DBusDict<DBusString, DBusDict<DBusString, DBusVariant>>>
                 managedObjects = (DBusDict) body.get(0);

             managedObjects.forEach((path, interfaces) -> {
                 System.out.println("Object: " + path);
                 interfaces.forEach((iface, properties) -> {
                     System.out.println("  Interface: " + iface);
                     properties.forEach((prop, value) -> {
                         System.out.println("    " + prop + " = " + value);
                     });
                 });
             });
         }
     }
 });
 

Bus Interface

The org.freedesktop.DBus interface provides access to the D-Bus daemon functionality:


 // List available services
 OutboundMethodCall listNames = OutboundMethodCall.Builder
     .create()
     .withPath(DBusObjectPath.valueOf("/org/freedesktop/DBus"))
     .withInterface(DBusString.valueOf("org.freedesktop.DBus"))
     .withMember(DBusString.valueOf("ListNames"))
     .withDestination(DBusString.valueOf("org.freedesktop.DBus"))
     .withReplyExpected(true)
     .build();

 // Request a service name
 OutboundMethodCall requestName = OutboundMethodCall.Builder
     .create()
     .withPath(DBusObjectPath.valueOf("/org/freedesktop/DBus"))
     .withInterface(DBusString.valueOf("org.freedesktop.DBus"))
     .withMember(DBusString.valueOf("RequestName"))
     .withDestination(DBusString.valueOf("org.freedesktop.DBus"))
     .withBody(Arrays.asList(
         DBusString.valueOf("org.example.MyService"),
         DBusUInt32.valueOf(0) // No flags
     ))
     .withReplyExpected(true)
     .build();

 // Get service owner
 OutboundMethodCall getNameOwner = OutboundMethodCall.Builder
     .create()
     .withPath(DBusObjectPath.valueOf("/org/freedesktop/DBus"))
     .withInterface(DBusString.valueOf("org.freedesktop.DBus"))
     .withMember(DBusString.valueOf("GetNameOwner"))
     .withDestination(DBusString.valueOf("org.freedesktop.DBus"))
     .withBody(Arrays.asList(
         DBusString.valueOf("org.example.Service")
     ))
     .withReplyExpected(true)
     .build();
 

Signal Handling

Standard interfaces also define common signals:


 // Handle PropertiesChanged signals
 connection.getPipeline().addLast("properties-handler", new AbstractInboundHandler() {
     @Override
     public void handleInboundMessage(Context ctx, InboundMessage msg) {
         if (msg instanceof InboundSignal) {
             InboundSignal signal = (InboundSignal) msg;
             String interfaceName = signal.getInterfaceName()
                 .map(DBusString::toString)
                 .orElse("");
             String memberName = signal.getMember().toString();

             if ("org.freedesktop.DBus.Properties".equals(interfaceName) &&
                 "PropertiesChanged".equals(memberName)) {
                 handlePropertiesChanged(signal);
             }
         }
         ctx.propagateInboundMessage(msg);
     }

     private void handlePropertiesChanged(InboundSignal signal) {
         List<DBusType> arguments = signal.getBody();
         if (arguments.size() >= 2) {
             DBusString interfaceName = (DBusString) arguments.get(0);
             DBusDict<DBusString, DBusVariant> changedProperties =
                 (DBusDict<DBusString, DBusVariant>) arguments.get(1);

             System.out.println("Properties changed on " + interfaceName);
             changedProperties.forEach((key, value) -> {
                 System.out.println("  " + key + " = " + value);
             });
         }
     }
 });

 // Handle NameOwnerChanged signals
 connection.getPipeline().addLast("name-owner-handler", new AbstractInboundHandler() {
     @Override
     public void handleInboundMessage(Context ctx, InboundMessage msg) {
         if (msg instanceof InboundSignal) {
             InboundSignal signal = (InboundSignal) msg;
             String interfaceName = signal.getInterfaceName()
                 .map(DBusString::toString)
                 .orElse("");
             String memberName = signal.getMember().toString();

             if ("org.freedesktop.DBus".equals(interfaceName) &&
                 "NameOwnerChanged".equals(memberName)) {
                 handleNameOwnerChanged(signal);
             }
         }
         ctx.propagateInboundMessage(msg);
     }

     private void handleNameOwnerChanged(InboundSignal signal) {
         List<DBusType> arguments = signal.getBody();
         if (arguments.size() >= 3) {
             String serviceName = ((DBusString) arguments.get(0)).toString();
             String oldOwner = ((DBusString) arguments.get(1)).toString();
             String newOwner = ((DBusString) arguments.get(2)).toString();

             if (oldOwner.isEmpty() && !newOwner.isEmpty()) {
                 System.out.println("Service appeared: " + serviceName);
             } else if (!oldOwner.isEmpty() && newOwner.isEmpty()) {
                 System.out.println("Service disappeared: " + serviceName);
             }
         }
     }
 });

 // Handle ObjectManager InterfacesAdded/Removed signals
 connection.getPipeline().addLast("object-manager-handler", new AbstractInboundHandler() {
     @Override
     public void handleInboundMessage(Context ctx, InboundMessage msg) {
         if (msg instanceof InboundSignal) {
             InboundSignal signal = (InboundSignal) msg;
             String interfaceName = signal.getInterfaceName()
                 .map(DBusString::toString)
                 .orElse("");
             String memberName = signal.getMember().toString();

             if ("org.freedesktop.DBus.ObjectManager".equals(interfaceName)) {
                 if ("InterfacesAdded".equals(memberName)) {
                     handleInterfacesAdded(signal);
                 } else if ("InterfacesRemoved".equals(memberName)) {
                     handleInterfacesRemoved(signal);
                 }
             }
         }
         ctx.propagateInboundMessage(msg);
     }

     private void handleInterfacesAdded(InboundSignal signal) {
         List<DBusType> arguments = signal.getBody();
         if (arguments.size() >= 2) {
             DBusObjectPath objectPath = (DBusObjectPath) arguments.get(0);
             DBusDict<DBusString, DBusDict<DBusString, DBusVariant>> interfaces =
                 (DBusDict) arguments.get(1);

             System.out.println("Interfaces added to " + objectPath);
             interfaces.forEach((iface, properties) -> {
                 System.out.println("  Interface: " + iface);
             });
         }
     }

     private void handleInterfacesRemoved(InboundSignal signal) {
         List<DBusType> arguments = signal.getBody();
         if (arguments.size() >= 2) {
             DBusObjectPath objectPath = (DBusObjectPath) arguments.get(0);
             DBusArray<DBusString> interfaces = (DBusArray) arguments.get(1);

             System.out.println("Interfaces removed from " + objectPath);
             interfaces.forEach(iface -> {
                 System.out.println("  Interface: " + iface);
             });
         }
     }
 });
 

Error Handling

Standard D-Bus error names are defined for common error conditions:


 // Handle standard D-Bus errors
 private void handleStandardErrors(InboundError error) {
     String errorName = error.getErrorName().toString();

     switch (errorName) {
         case "org.freedesktop.DBus.Error.ServiceUnknown":
             System.err.println("Service not found");
             break;
         case "org.freedesktop.DBus.Error.UnknownMethod":
             System.err.println("Method not found");
             break;
         case "org.freedesktop.DBus.Error.UnknownInterface":
             System.err.println("Interface not found");
             break;
         case "org.freedesktop.DBus.Error.UnknownObject":
             System.err.println("Object not found");
             break;
         case "org.freedesktop.DBus.Error.InvalidArgs":
             System.err.println("Invalid arguments");
             break;
         case "org.freedesktop.DBus.Error.AccessDenied":
             System.err.println("Access denied");
             break;
         case "org.freedesktop.DBus.Error.NoReply":
             System.err.println("No reply received");
             break;
         default:
             System.err.println("D-Bus error: " + errorName);
     }
 }
 

Utility Classes

Helper classes for working with standard interfaces:


 // Standard interface constants
 public static final String INTROSPECTABLE_INTERFACE = "org.freedesktop.DBus.Introspectable";
 public static final String PROPERTIES_INTERFACE = "org.freedesktop.DBus.Properties";
 public static final String PEER_INTERFACE = "org.freedesktop.DBus.Peer";
 public static final String OBJECT_MANAGER_INTERFACE = "org.freedesktop.DBus.ObjectManager";
 public static final String DBUS_INTERFACE = "org.freedesktop.DBus";

 // Helper methods for common operations
 public static CompletableFuture<String> introspectObject(Connection connection,
                                                           String serviceName,
                                                           String objectPath) {
     // Implementation for introspection
 }

 public static CompletableFuture<DBusVariant> getProperty(Connection connection,
                                                          String serviceName,
                                                          String objectPath,
                                                          String interfaceName,
                                                          String propertyName) {
     // Implementation for property access
 }
 

Best Practices

  • Use Standard Interfaces: Always use these standard interfaces when available
  • Error Handling: Handle standard D-Bus errors appropriately
  • Property Changes: Subscribe to PropertiesChanged signals for reactive updates
  • Service Discovery: Use introspection to discover available interfaces and methods
  • Peer Communication: Use Peer interface for basic connectivity testing

Compatibility

All standard interfaces in this package are compatible with:

  • D-Bus specification version 1.0 and later
  • Common D-Bus implementations (dbus-daemon, systemd, etc.)
  • Cross-platform D-Bus services
  • Both system and session bus environments
Since:
1.0
See Also:
  • Interfaces
    Class
    Description
    The org.freedesktop.DBus.Introspectable interface provides introspection data for D-Bus objects.
    The org.freedesktop.DBus.ObjectManager interface provides a standardized way to enumerate all objects below a certain path in the object hierarchy, along with their interfaces and properties.
    The org.freedesktop.DBus.Peer interface provides basic peer-to-peer functionality between D-Bus connections.
    The org.freedesktop.DBus.Properties interface provides methods to expose properties or attributes of objects.