# Cling Core

## User Manual

### Authors:

Christian Bauer

### Table Of Contents:

1. A first UPnP service and control point

The most basic UPnP service imaginable is the binary light. This device has one service, the power switch, turning the light on and off. In fact, the SwitchPower:1 service and the BinaryLight:1 device are standardized templates you can download here.

In the following sections we'll implement this UPnP service and device with the Cling Core library as a simple Java console application.

1.1. The SwitchPower service implementation

This is the source of the SwitchPower:1 service - note that although there are many annotations in the source, no runtime dependency on Cling exists:

    package example.binarylight;

    import org.teleal.cling.binding.annotations.*;

    @UpnpService(
            serviceId = @UpnpServiceId("SwitchPower"),
            serviceType = @UpnpServiceType(value = "SwitchPower", version = 1)
    )
    public class SwitchPower {

        @UpnpStateVariable(defaultValue = "0", sendEvents = false)
        private boolean target = false;

        @UpnpStateVariable(defaultValue = "0")
        private boolean status = false;

        @UpnpAction
        public void setTarget(@UpnpInputArgument(name = "NewTargetValue")
                              boolean newTargetValue) {
            target = newTargetValue;
            status = newTargetValue;
            System.out.println("Switch is: " + status);
        }

        @UpnpAction(out = @UpnpOutputArgument(name = "RetTargetValue"))
        public boolean getTarget() {
            return target;
        }

        @UpnpAction(out = @UpnpOutputArgument(name = "ResultStatus"))
        public boolean getStatus() {
            return status;
        }

    }

To compile this class the Cling Core library has to be available on your classpath. However, once compiled this class can be instantiated and executed in any environment, there are no dependencies on any framework or library code.

The annotations are used by Cling to read the metadata that describes your service, what UPnP state variables it has, how they are accessed, and what methods should be exposed as UPnP actions. You can also provide Cling metadata in an XML file or programmatically through Java code - both options are discussed later in this manual. Source code annotations are usually the best choice.

You might have expected something even simpler: After all, a binary light only needs a single boolean state, it is either on or off. The designers of this service also considered that there might be a difference between switching the light on, and actually seeing the result of that action. Imagine what happens if the light bulb is broken: The target state of the light is set to true but the status is still false, because the SetTarget action could not make the switch. Obviously this won't be a problem with this simple demonstration because it only prints the status to standard console output.

1.2. Binding a UPnP device

Devices (and embedded devices) are created programmatically in Cling, with plain Java code that instantiates an immutable graph of objects. The following method creates such a device graph and binds the service from the previous section to the root device:

    LocalDevice createDevice()
            throws ValidationException, LocalServiceBindingException, IOException {

        DeviceIdentity identity =
                new DeviceIdentity(
                        UDN.uniqueSystemIdentifier("Demo Binary Light")
                );

        DeviceType type =
                new UDADeviceType("BinaryLight", 1);

        DeviceDetails details =
                new DeviceDetails(
                        "Friendly Binary Light",
                        new ManufacturerDetails("ACME"),
                        new ModelDetails(
                                "BinLight2000",
                                "A demo light with on/off switch.",
                                "v1"
                        )
                );

        Icon icon =
                new Icon(
                        "image/png", 48, 48, 8,
                        getClass().getResource("icon.png")
                );

        LocalService<SwitchPower> switchPowerService =
                new AnnotationLocalServiceBinder().read(SwitchPower.class);

        switchPowerService.setManager(
                new DefaultServiceManager(switchPowerService, SwitchPower.class)
        );

        return new LocalDevice(identity, type, details, icon, switchPowerService);
    }

Let's step through this code. As you can see, all arguments that make up the device's metadata have to be provided through constructors, because the metadata classes are immutable and hence thread-safe.

DeviceIdentity

  Every device, no matter if it is a root device or an embedded device of a root device, requires a unique device name (UDN). This UDN should be stable, that is, it should not change when the device is restarted. When you physically unplug a UPnP appliance from the network (or when you simply turn it off or put it into standby mode), and when you make it available later on, it should expose the same UDN so that clients know they are dealing with the same device. The `UDN.uniqueSystemIdentifier()` method provides exactly that: A unique identifier that is the same every time this method is called on the same computer system. It hashes the network cards hardware address and a few other elements to guarantee uniqueness and stability.

DeviceType

  The type of a device also includes its version, a plain integer. In this case the BinaryLight:1 is a standardized device template which adheres to the UDA (UPnP Device Architecture) specification.

DeviceDetails

  This detailed information about the device's "friendly name", as well as model and manufacturer information is optional. You should at least provide a friendly name value, this is what UPnP applications will display primarily.

Icon

  Every device can have a bunch of icons associated with it which similar to the friendly name are shown to users when appropriate. You do not have to provide any icons if you don't want to, use a constructor of `LocalDevice` without an icon parameter.

Service

  Finally, the most important part of the device are its services. Each `Service` instance encapsulates the metadata for a particular service, what actions and state variables it has, and how it can be invoked. Here we use the Cling annotation binder to instantiate a `Service`, reading the annotation metadata of the `SwitchPower` class.

Because a `Service` instance is only metadata that describes the service, you have to set a `ServiceManager` to do some actual work. This is the link between the metadata and your implementation of a service, where the rubber meets the road. The `DefaultServiceManager` will instantiate the given `SwitchPower` class when an action which operates on the service has to be executed (this happens lazily, as late as possible). The manager will hold on to the instance and always re-use it as long as the service is registered with the UPnP stack. In other words, the service manager is the factory that instantiates your actual implementation of a UPnP service.

Also note that `LocalDevice` is the interface that represents a UPnP device which is "local" to the running UPnP stack on the host. Any device that has been discovered through the network will be a `RemoteDevice` with `RemoteService`'s, you typically do not instantiate these directly.

A `ValidationException` will be thrown when the device graph you instantiated was invaild, you can call `getErrors()` on the exception to find out which property value of which class failed an integrity rule. The local service annotation binder will provide a `LocalServiceBindingException` if something is wrong with your annotation metadata on your service implementation class. An `IOException` can only by thrown by this particular `Icon` constructor, when it reads the resource file.

1.3. Running the server

The Cling Core main API entry point is a thread-safe and typically single shared instance of `UpnpService`:

    package example.binarylight;

    import org.teleal.cling.UpnpService;
    import org.teleal.cling.UpnpServiceImpl;
    import org.teleal.cling.binding.*;
    import org.teleal.cling.binding.annotations.*;
    import org.teleal.cling.model.*;
    import org.teleal.cling.model.meta.*;
    import org.teleal.cling.model.types.*;

    import java.io.IOException;

    public class BinaryLightServer implements Runnable {

        public static void main(String[] args) throws Exception {
            // Start a user thread that runs the UPnP stack
            Thread serverThread = new Thread(new BinaryLightServer());
            serverThread.setDaemon(false);
            serverThread.start();
        }

        public void run() {
            try {

                final UpnpService upnpService = new UpnpServiceImpl();

                Runtime.getRuntime().addShutdownHook(new Thread() {
                    @Override
                    public void run() {
                        upnpService.shutdown();
                    }
                });

                // Add the bound local device to the registry
                upnpService.getRegistry().addDevice(
                        createDevice()
                );

            } catch (Exception ex) {
                System.err.println("Exception occured: " + ex);
                ex.printStackTrace(System.err);
                System.exit(1);
            }
        }

    }

(The `createDevice()` method from the previous section should be added to this class.)

As soon as the `UPnPServiceImpl` is created, the stack is up and running. You always have to create a `UPnPService` instance, no matter if you write a client or a server. The `UpnpService` maintains a registry of all the discovered remote device on the network, and all the bound local devices. It manages advertisements for discovery and event handling in the background.

You should shut down the UPnP service properly when your application quits, so that all other UPnP systems on your network will be notified that bound devices which are local to your application are no longer available. If you do not shut down the `UpnpService` when your application quits, other UPnP control points on your network might still show devices as available when they are in fact already gone.

The `createDevice()` method from the previous section is called here, as soon as the `Registry` of the local UPnP service stack is available.

You can now compile and start this server, it should print some informational messages to your console and then wait for connections from UPnP control points. Use the Cling Workbench if you want to test your server immediately.

1.4. Creating a control point

The client application has the same basic scaffolding as the server, it also uses a shared single instance of `UpnpService`:

    package example.binarylight;

    import org.teleal.cling.UpnpService;
    import org.teleal.cling.UpnpServiceImpl;
    import org.teleal.cling.controlpoint.*;
    import org.teleal.cling.model.action.*;
    import org.teleal.cling.model.message.*;
    import org.teleal.cling.model.message.header.*;
    import org.teleal.cling.model.meta.*;
    import org.teleal.cling.model.types.*;
    import org.teleal.cling.registry.*;

    public class BinaryLightClient implements Runnable {

        public static void main(String[] args) throws Exception {
            // Start a user thread that runs the UPnP stack
            Thread clientThread = new Thread(new BinaryLightClient());
            clientThread.setDaemon(false);
            clientThread.start();

        }

        public void run() {
            try {

                UpnpService upnpService = new UpnpServiceImpl();

                // Add a listener for device registration events
                upnpService.getRegistry().addListener(
                        createRegistryListener(upnpService)
                );

                // Broadcast a search message for all devices
                upnpService.getControlPoint().search(
                        new STAllHeader()
                );

            } catch (Exception ex) {
                System.err.println("Exception occured: " + ex);
                System.exit(1);
            }
        }

    }

Typically a control point sleeps until a device with a specific type of service becomes available on the network. The `RegistryListener` is called by Cling when a remote device has been discovered - or when it announced itself automatically. Because you usually do not want to wait for the periodic announcements of devices, a control point can also execute a search for all devices (or devices with certain service types or UDN), which will trigger an immediate discovery announcement from those devices that match the search query.

You can already see the `ControlPoint` API here with its `search(...)` method, this is one of the main interfaces you interact with when writing a UPnP client with Cling.

If you compare this code with the server code from the previous section you can see that we are not shutting down the `UpnpService` when the application quits. This is not an issue here, because this application does not have any local devices or service event listeners (not the same as registry listeners) bound and registered. Hence, we do not have to announce their departure on application shutdown and can keep the code simple for the sake of the example.

Let's focus on the registry listener implementation and what happens when a UPnP device has been discovered on the network.

1.5. Executing an action

The control point we are creating here is only interested in services that implement SwitchPower. According to its template definition this service has the `SwitchPower` service identifier, so when a device has been discovered we can check if it offers that service:

    RegistryListener createRegistryListener(final UpnpService upnpService) {
        return new DefaultRegistryListener() {

            ServiceId serviceId = new UDAServiceId("SwitchPower");

            @Override
            public void remoteDeviceAdded(Registry registry, RemoteDevice device) {

                Service switchPower;
                if ((switchPower = device.findService(serviceId)) != null) {

                    System.out.println("Service discovered: " + switchPower);
                    executeAction(upnpService, switchPower);

                }

            }

            @Override
            public void remoteDeviceRemoved(Registry registry, RemoteDevice device) {
                Service switchPower;
                if ((switchPower = device.findService(serviceId)) != null) {
                    System.out.println("Service disappeared: " + switchPower);
                }
            }

        };
    }

If a service becomes available we immediately execute an action on that service. When a `SwitchPower` device disappears from the network a log message is printed. Remember that this is a very trivial control point, it executes a single a fire-and-forget operation when a service becomes available:

    void executeAction(UpnpService upnpService, Service switchPowerService) {

            ActionInvocation setTargetInvocation =
                    new SetTargetActionInvocation(switchPowerService);

            // Executes asynchronous in the background
            upnpService.getControlPoint().execute(
                    new ActionCallback(setTargetInvocation) {

                        @Override
                        public void success(ActionInvocation actionInvocation) {
                            assert actionInvocation.getOutput()
                                    .getValues().length == 0;
                            System.out.println("Successfully called action!");
                        }

                        @Override
                        public void failure(ActionInvocation actionInvocation,
                                            UpnpResponse operation) {
                            System.err.println(
                                    createDefaultFailureMessage(
                                            actionInvocation,
                                            operation
                                    )
                            );
                        }
                    }
            );

    }

    class SetTargetActionInvocation extends ActionInvocation {

        SetTargetActionInvocation(Service service) {
            super(service.getAction("SetTarget"));
            try {

                // Throws ActionException if the value is of wrong type
                getInput().addValue(true);

            } catch (ActionException ex) {
                System.err.println(ex.getMessage());
            }
        }
    }

The `Action` (metadata) and the `ActionInvocation` (actual call data) APIs allow very fine-grained control of how an invocation is prepared, how input values are set, how the action is executed, and how the output and outcome is handled. UPnP is inherently asynchronous, so just like the registry listener, executing an action is exposed to you as a callback-style API.

It is recommended that you encapsulate specific action invocations within a subclass of `ActionInvocation`, which gives you an opportunity to further abstract the input and output values of an invocation. Note however that an instance of `ActionInvocation` is not thread-safe and should not be executed in parallel by two threads.

The `ActionCallback` has two main methods you have to implement, one is called when the execution was successful, the other when it failed. There are many reasons why an action execution might fail, read the API documentation for all possible combinations. The `createDefaultFailureMessage()` method is a convenient way to create a user-friendly error message quickly.

1.6. Starting the application

Compile the binary light demo application:

Don't forget to copy your `icon.png` file into the `classes` output directory as well, into the right package from which it is loaded as a reasource (the `example.binarylight` package if you followed the previous sections verbatim).

You can start the server or client first, which one doesn't matter as they will discover each other automatically:

You should see discovery and action execution messages on each console. You can stop and restart the applications individually (press CTRL+C on the console).

1.7. Debugging and logging

Although the binary light is a very simple example, you might run into problems. Cling Core helps you resolve most problems with extensive logging. Internally, Cling Core uses Java JDK logging, also known as `java.util.logging` or JUL. There are no wrappers, logging frameworks, logging services, or other dependencies.

By default, the implementation of JUL in the Sun JDK will print only messages with level INFO, WARNING, or SEVERE on `System.out`, and it will print each message over two lines. This is quite inconvenient and ugly, so your first step is probably to configure one line per message. This requires a custom logging handler.

Next you want to configure logging levels for different logging categories. Cling Core will output some INFO level messages on startup and shutdown, but is otherwise silent during runtime unless a problem occurs - it will then log messages at WARNING or SEVERE level.

For debugging, usually more detailed logging levels for various log categories are required. The logging categories in Cling Core are package names, e.g the root logger is available under the name `org.teleal.cling`. The following tables show typically used categories and the recommended level for debugging:

Network/Transport |
--- | ---
`org.teleal.cling.transport.spi.DatagramIO (FINE)` `org.teleal.cling.transport.spi.MulticastReceiver (FINE)` | UDP communication
`org.teleal.cling.transport.spi.DatagramProcessor (FINER)` | UDP datagram processing and content
`org.teleal.cling.transport.spi.UpnpStream (FINER)` `org.teleal.cling.transport.spi.StreamServer (FINE)` `org.teleal.cling.transport.spi.StreamClient (FINE)` | TCP communication
`org.teleal.cling.transport.spi.SOAPActionProcessor (FINER)` | SOAP action message processing and content
`org.teleal.cling.transport.spi.GENAEventProcessor (FINER)` | GENA event message processing and content
`org.teleal.cling.transport.impl.HttpHeaderConverter (FINER)` | HTTP header processing

UPnP Protocol |
--- | ---
`org.teleal.cling.protocol.ProtocolFactory (FINER)` `org.teleal.cling.protocol.async (FINER)` | Discovery (Notification & Search)
`org.teleal.cling.protocol.ProtocolFactory (FINER)` `org.teleal.cling.protocol.RetrieveRemoteDescriptors (FINE)` `org.teleal.cling.protocol.sync.ReceivingRetrieval (FINE)` `org.teleal.cling.binding.xml.DeviceDescriptorBinder (FINE)` `org.teleal.cling.binding.xml.ServiceDescriptorBinder (FINE)` | Description
`org.teleal.cling.protocol.ProtocolFactory (FINER)` `org.teleal.cling.protocol.sync.ReceivingAction (FINER)` `org.teleal.cling.protocol.sync.SendingAction (FINER)` | Control
`org.teleal.cling.model.gena (FINER)` `org.teleal.cling.protocol.ProtocolFactory (FINER)` `org.teleal.cling.protocol.sync.ReceivingEvent (FINER)` `org.teleal.cling.protocol.sync.ReceivingSubscribe (FINER)` `org.teleal.cling.protocol.sync.ReceivingUnsubscribe (FINER)` `org.teleal.cling.protocol.sync.SendingEvent (FINER)` `org.teleal.cling.protocol.sync.SendingSubscribe (FINER)` `org.teleal.cling.protocol.sync.SendingUnsubscribe (FINER)` `org.teleal.cling.protocol.sync.SendingRenewal (FINER)` | GENA

Core |
--- | ---
`org.teleal.cling.transport.Router (FINER)` | Message Router
`org.teleal.cling.registry.Registry (FINER)` `org.teleal.cling.registry.LocalItems (FINER)` `org.teleal.cling.registry.RemoteItems (FINER)` | Registry
`org.teleal.cling.binding.annotations (FINER)` `org.teleal.cling.model.meta.LocalService (FINER)` `org.teleal.cling.model.action (FINER)` `org.teleal.cling.model.state (FINER)` `org.teleal.cling.model.DefaultServiceManager (FINER)` | Local service binding & invocation
`org.teleal.cling.controlpoint (FINER)` | Control Point interaction

One way to configure JUL is with a properties file. For example, create the following file as `mylogging.properties`:

You can now start your application with a system property that names your logging configuration:

You should see the desired log messages printed on `System.out`.

2. The Cling Core API

The programming interface of Cling is fundamentally the same for UPnP clients and servers. The single entry point for any program is the `UpnpService` instance. Through this API you access the local UPnP stack, and either execute operations as a client (control point) or provide services to local or remote clients through the registry.

The following diagram shows the most important interfaces of Cling Core:

You'll be calling these interfaces to work with UPnP devices and interact with UPnP services. Cling provides a fine-grained meta-model representing these artifacts:

In this chapter we'll walk through the API and metamodel in more detail, starting with the `UpnpService`.

2.1. Working with a UpnpService

The `UpnpService` is an interface:

An instance of `UpnpService` represents a running UPnP stack, including all network listeners, background maintenance threads, and so on. Cling Core bundles a default implementation which you can simply instantiate as follows:

With this implementation, the local UPnP stack is ready immediately, it listens on the network for UPnP messages. You should call the `shutdown()` method when you no longer need the UPnP stack. The bundled implementation will then cut all connections with remote event listeners and also notify all other UPnP participants on the network that your local services are no longer available. If you do not shutdown your UPnP stack, remote control points might think that your services are still available until your earlier announcements expire.

The bundled implementation offers two additional constructors:

This constructor accepts your custom `RegistryListener` instances, which will be activated immediately even before the UPnP stack listens on any network interface. This means that you can be notified of all incoming device and service registrations as soon as the network stack is ready. Note that this is rarely useful, you'd typically send search requests after the stack is up and running anyway - after adding listeners to the registry.

The second constructor supports customization of the UPnP stack configuration:

This example configuration will change the TCP listening port of the UPnP stack to `8081`, the default being an ephemeral (system-selected free) port. The `UpnpServiceConfiguration` is also an interface, in the example above you can see how the bundled default implementation is instantiated.

The following section explain the methods of the `UpnpService` interface and what they return in more detail.

2.1.1. Customizing configuration settings

This is the configuration interface of the default UPnP stack in Cling Core, an instance of which you have to provide when creating the `UpnpServiceImpl`:

This is quite an extensive SPI but you typically won't implement it from scratch. Overriding and customizing the bundled `DefaultUpnpServiceConfiguration` should suffice in most cases.

The configuration settings reflect the internal structure of Cling Core:

Network

  The `NetworkAddressFactory` provides the network interfaces, ports, and multicast settings which are used by the UPnP stack. At the time of writing, the following interfaces and IP addresses are ignored by the default configuration: any IPv6 interfaces and addresses, interfaces whose name starts with "vmnet", and the local loopback. Otherwise, all interfaces and their TCP/IP addresses are used and bound.

  You can set the system property `org.teleal.cling.network.useInterfaces` to provide a comma-separated list of network interfaces you'd like to bind excusively. Additionally, you can restrict the actual TCP/IP addresses to which the stack will bind with a comma-separated list of IP address provided through the `org.teleal.cling.network.useAddresses` system property.

  Furthermore, the configuration declares the network-level message listeners and senders, that is, the implementations used by the network `Router`.

  Stream messages are TCP HTTP requests and responses, the bundled implementation will use the Sun JDK webserver to listen for HTTP requests, and it sends HTTP requests through the standard JDK `HttpURLConnection`. Therefore, the default network stack bundled with Cling Core will only work on Sun's JDK. You can provide your own `StreamServer` if you can not use the Sun JDK.

  UDP unicast and multicast datagrams are received, parsed, and send by a custom implementation bundled with Cling Core that does not require any particular Sun JDK classes.

Descriptors

  Reading and writing UPnP XML descriptors is handled by binders, you can provide alternative implementations if necessary.

Executors

  The Cling UPnP stack is multi-threaded, thread creation and execution is handled through `java.util.concurrent` executors. The default configuration uses a pool of threads with a maximum size of 64 concurrently running threads, which should suffice for even very large installations. Executors can be configured fine-grained, for network message handling, actual UPnP protocol execution (handling discovery, control, and event procedures), and local registry maintenance and listener callback execution. Most likely you will not have to customize any of these settings.

2.1.2. The protocol factory

Cling Core internals are modular and any aspect of the UPnP protocol is handled by an implementation (class) which can be replaced without affecting any other aspect. The `ProtocolFactory` provides implementations, it is always the first access point for the UPnP stack when a message which arrives on the network or an outgoing message has to be handled:

This API is a low-level interface that allows you to access the internals of the UPnP stack, in the rare case you need to manually trigger a particular procedure.

The first two methods are called by the networking code when a message arrives, either multicast or unicast UDP datagrams, or a TCP (HTTP) stream request. The default protocol factory implementation will then pick the appropriate receiving protocol implementation to handle the incoming message.

The local registry of local services known to the UPnP stack naturally also sends messages, such as alive and byebye notifications. Also, if you write a UPnP control point various search, control, and eventing messages are send by the local UPnP stack. The protocol factory decouples the message sender (registry, control point) from the actual creation, preparation, and transmission of the messages.

Transmission and reception of messages at the lowest-level is the job of the network `Router`.

2.1.3. Accessing low-level network services

The reception and sending of messages, that is, all message transport, is encapsulated through the `Router` interface:

UPnP works with two types of messages: Multicast and unicast UDP datagrams which are typically handled asynchronously, and request/response TCP messages with an HTTP payload. The Cling Core bundled `RouterImpl` will instantiate and maintain the listeners for incoming messages as well as transmit any outgoing messages.

The actual implementation of a message receiver which listens on the network or a message sender is provided by the `UpnpServiceConfiguration`, which we have introduced earlier. You can access the `Router` directly if you have to execute low-level operations on the network layer of the UPnP stack.

Most of the time you will however work with the `ControlPoint` and `Registry` interfaces to interact with the UPnP stack.

2.2. Client operations with ControlPoint

Your primary API when writing a UPnP client application is the `ControlPoint`. An instance is available with `getControlPoint()` on the `UpnpService`.

A UPnP client application typically wants to:

- Search the network for a particular service which it knows how to utilize. Any response to a search request will be delivered asynchronously, so you have to listen to the `Registry` for device registrations, which will occur when devices respond to your search request.
- Execute actions which are offered by services. Action execution is processed asynchronously in Cling Core, and your `ActionCallback` will be notified when the execution was a success (with result values), or a failure (with error status code and messages).
- Subscribe to a service's eventing, so your `SubscriptionCallback` is notified asynchronously when the state of a service changes and an event has been received for your client. You also use the callback to cancel the event subscription when you are no longer interested in state changes.

Let's start with searching for UPnP devices on the network.

2.2.1. Searching the network

When your control point joins the network it probably won't know any UPnP devices and services that might be available. To learn about the present devices it can broadcast - actually with UDP multicast datagrams - a search message which will be received by every device. Each receiver then inspects the search message and decides if it should reply directly (with notification UDP datagrams) to the sending control point.

Search messages carry a search type header and receivers consider this header when they evaluate a potential response. The Cling `ControlPoint` API accepts a `UpnpHeader` argument when creating outgoing search messages.

Most of the time you'd like all devices to respond to your search, this is what the dedicated `STAllHeader` is used for:

    upnpService.getControlPoint().search(
            new STAllHeader()
    );

Notification messages will be received by your control point and you can listen to the `Registry` and inspect the found devices and their services.

On the other hand, when you already know the unique device name (UDN) of the device you are searching for - maybe because your control point remembered it while it was turned off - you can send a message which will trigger a response from only a particular device:

    upnpService.getControlPoint().search(
            new UDNHeader(udn)
    );

This is mostly useful to avoid network congestion when dozens of devices might all respond to a search request. Your `Registry` listener code however still has to inspect each newly found device, as registrations might occur independently from searches.

You can also search by device or service type. This search request will trigger responses from all devices of type "`urn:schemas-upnp-org:device:BinaryLight:1`":

    UDADeviceType udaType = new UDADeviceType("BinaryLight");
    upnpService.getControlPoint().search(
            new UDADeviceTypeHeader(udaType)
    );

If the desired device type is of a custom namespace, use this variation:

    DeviceType type = new DeviceType("org-mydomain", "MyDeviceType", 1);
    upnpService.getControlPoint().search(
            new DeviceTypeHeader(type)
    );

Or, you can search for all devices which implement a particular service type:

    UDAServiceType udaType = new UDAServiceType("SwitchPower");
    upnpService.getControlPoint().search(
            new UDAServiceTypeHeader(udaType)
    );

    ServiceType type = new ServiceType("org-mydomain", "MyServiceType", 1);
    upnpService.getControlPoint().search(
            new ServiceTypeHeader(type)
    );

2.2.2. Invoking an action

UPnP services expose state variables and actions. While the state variables represent the current state of the service, actions are the operations used to query or maniuplate the service's state. You have to obtain a `Service` instance from a `Device` to access any `Action`. The target device can be local to the same UPnP stack as your control point, or it can be remote of another device anywhere on the network. We'll discuss later in this chapter how to access devices through the local stack's `Registry`.

Once you have the device, access the `Service` through the metadata model, for example:

    Service service = device.findService(new UDAServiceId("SwitchPower"));
    Action getStatusAction = service.getAction("GetStatus");

This method will search the device and all its embedded devices for a service with the given identififer and returns either the found `Service` or `null`. The Cling metamodel is thread-safe, so you can share an instance of `Service` or `Action` and access it concurrently.

Invoking an action is the job of an instance of `ActionInvocation`, note that this instance is NOT thread-safe and each thread that wishes to execute an action has to obtain its own invocation from the `Action` metamodel:

    ActionInvocation getStatusInvocation = new ActionInvocation(getStatusAction);

    ActionCallback getStatusCallback = new ActionCallback(getStatusInvocation) {

        @Override
        public void success(ActionInvocation invocation) {
            ActionArgumentValue[] output = invocation.getOutput().getValues();
            assertEquals(output.length, 1);

            ActionArgumentValue status = output[0];

            assertEquals(status.getArgument().getName(), "ResultStatus");

            assertEquals(status.getDatatype().getClass(), BooleanDatatype.class);
            assertEquals(status.getDatatype().getBuiltin(), Datatype.Builtin.BOOLEAN);
            assertEquals(status.getDatatype().getValueType(), Boolean.class);

            assertEquals((Boolean) status.getValue(), Boolean.valueOf(false));
            assertEquals(status.toString(), "0"); // '0' is 'false' in UPnP
        }

        @Override
        public void failure(ActionInvocation invocation, UpnpResponse res) {
            System.err.println(
                    createDefaultFailureMessage(invocation, res)
            );
        }
    };

    upnpService.getControlPoint().execute(getStatusCallback);

Execution is asynchronous, your `ActionCallback` has two methods which will be called by the UPnP stack when the execution completes. If the action is successful, you can obtain any output argument values from the invocation instance, which is conveniently passed into the `success()` method. You can inspect the output argument values and their datatypes to continue processing the result.

When invocation fails you can access the failure details through `invocation.getFailure()`, or use the shown convenience method to create a simple error message. See the Javadoc of `ActionCallback` for more details.

When an action requires input argument values, you have to provide them. Arguments of actions, input as well as output, are always ordered, so you can set them one after another by calling `addValue(o)`:

    ActionInvocation setTargetInvocation =
            new ActionInvocation(service.getAction("SetTarget"));

    setTargetInvocation.getInput().addValue(true); // Can throw InvalidValueException
    // or
    //setTargetInvocation.getInput().setValue(0, true);

    ActionCallback setTargetCallback = new ActionCallback(setTargetInvocation) {

        @Override
        public void success(ActionInvocation invocation) {
            ActionArgumentValue[] output = invocation.getOutput().getValues();
            assertEquals(output.length, 0);
        }

        @Override
        public void failure(ActionInvocation invocation, UpnpResponse res) {
            System.err.println(
                    createDefaultFailureMessage(invocation, res)
            );
        }
    };

    upnpService.getControlPoint().execute(setTargetCallback);

This action has one input argument of UPnP type "boolean". You can set a Java `boolean` primitive or `Boolean` instance and it will be automatically converted. If you set an invalid value for a particular argument, such as an instance with the wrong type for the "current" argument, an `InvalidValueException` will be thrown immediately. You can also set a particular value with `setValue(zeroBasedIndex, o)`.

Empty values and null in Cling
You always have to prepare all input argument values, that is, you have to call `invocation.getInput().addValue(o)` as many times as there are input arguments. If you want to fill up all the remaining input arguments with `null` quickly, use the `invocation.getInput().fillValuesWithNull()` convenience method. There is no difference between empty string `""` and `null`, because the UPnP specification does not address this issue. The SOAP message of an action call or an event message must contain an element `` for all variables, even if it is an empty XML element. If you provide an empty string or a null value when preparing a message, it will always be a `null` on the receiving end because we can only transmit one thing, an empty XML element.
2.2.3. Receiving events from services

The UPnP specification defines a general event notification system (GENA) which is based on a publish/subscribe paradigm. Your control point subscribes with a service in order to receive events. When the service state changes, an event message will be delivered to the callback of your control point. Subscriptions are periodically refreshed until you unsubscribe from the service. If you do not unsubscribe and if a refresh of the subscription fails, maybe because the control point was turned off without proper shutdown, the subscription will timeout on the publishing service's side.

This is an example subscription on a service that sends events for a state variable named `Status` (e.g. the SwitchPower service previously shown). Its refresh and timeout period is 600 seconds:

    SubscriptionCallback callback = new SubscriptionCallback(service, 600) {

        @Override
        public void established(GENASubscription sub) {
            System.out.println("Established: " + sub.getSubscriptionId());
        }

        @Override
        public void failed(GENASubscription sub,
                           UpnpResponse response,
                           Exception ex) {
            System.err.println(
                    createDefaultFailureMessage(response, ex)
            );
        }

        @Override
        public void ended(GENASubscription sub,
                          CancelReason reason,
                          UpnpResponse response) {
            assert reason == null;
        }

        public void eventReceived(GENASubscription sub) {

            System.out.println("Event: " + sub.getCurrentSequence().getValue());

            Map<String, StateVariableValue> values = sub.getCurrentValues();
            StateVariableValue status = values.get("Status");

            assertEquals(status.getDatatype().getClass(), BooleanDatatype.class);
            assertEquals(status.getDatatype().getBuiltin(), Datatype.Builtin.BOOLEAN);
            assertEquals(status.getDatatype().getValueType(), Boolean.class);

            System.out.println("Status is: " + status.toString());

        }

        public void eventsMissed(GENASubscription sub, int numberOfMissedEvents) {
            System.out.println("Missed events: " + numberOfMissedEvents);
            testAssertions.add(false);
        }

    };

    upnpService.getControlPoint().execute(callback);

The `SubscriptionCallback` offers the methods `failed()`, `established()`, and `ended()` which are called during a subscription's lifecycle. When a subscription ends you will be notified with a `CancelReason` whenever the termination of the subscription was irregular. See the Javadoc of these methods for more details.

Every event message from the service will be passed to the `eventReceived()` method, and every message will carry a sequence number. Variable values are not transmitted individually, each message contains `StateVariableValue` instances for all evented variables of a service. You'll receive a snapshot of the state of the service at the time the event was triggered.

Whenever the receiving UPnP stack detects an event message that is out of sequence, e.g. because some messages were lost during transport, the `eventsMissed()` method will be called before you receive the event. You then decide if missing events is important for the correct behavior of your application, or if you can silently ignore it and continue processing events with non-consecutive sequence numbers.

You end a subscription regularly by calling `callback.end()`, which will unsubscribe your control point from the service.

2.3. The Registry

The `Registry`, which you access with `getRegistry()` on the `UpnpService`, is the heart of a Cling Core UPnP stack. The registry is responsible for:

- Maintaining discovered UPnP devices on your network. It also offers a management API so you can register local devices and offer local services. This is how you expose your own UPnP devices on the network. The registry handles all notification, expiration, request routing, refreshing, and so on.
- Managing GENA (general event & notification architecture) subscriptions. Any outgoing subscription to a remote service is known by the registry, it is refreshed periodically so it doesn't expire. Any incoming eventing subscription to a local service is also known and maintained by the registry (expired and removed when necessary).
- Providing the interface for the addition and removal of `RegistryListener` instances. A registry listener is used in client or server UPnP applications, it provides a uniform interface for notification of registry events. Typically, you write and register a listener to be notified when a service you want to work with becomes available on the network - on a local or remote device - and when it disappears.

2.3.1. Browsing the Registry

Although you typically create a `RegistryListener` to be notified of discovered and disappearing UPnP devices on your network, sometimes you have to browse the `Registry` manually.

The following call will return a device with the given unique device name, but only a root device and not any embedded device. Set the second parameter of `registry.getDevice()` to `false` if the device you are looking for might be an embedded device.

    Registry registry = upnpService.getRegistry();
    Device foundDevice = registry.getDevice(udn, true);

    assertEquals(foundDevice.getIdentity().getUdn(), udn);

If you know that the device you need is a `LocalDevice` - or a `RemoteDevice` - you can use the following operation:

    LocalDevice localDevice = registry.getLocalDevice(udn, true);

Most of the time you need a device that is of a particular type or that implements a particular service type, because this is what your control point can handle:

    DeviceType deviceType = new UDADeviceType("MY-DEVICE-TYPE", 1);
    Collection<Device> devices = registry.getDevices(deviceType);

    ServiceType serviceType = new UDAServiceType("MY-SERVICE-TYPE-ONE", 1);
    Collection<Device> devices = registry.getDevices(serviceType);

3. Cling on Android

Cling Core provides a UPnP stack for Android applications. Typically you'd write control point applications, as most Android systems today are small hand-held devices. You can however also write UPnP server applications on Android, all features of Cling Core are supported.

The following sections explain how to integrate Cling with your Android application.

3.1. Creating an Android service

You can instantiate the Cling `UpnpService` in your Android application's main activity. On the other hand, if several activities in your application require access to the UPnP stack, a better design would utilize a background `android.app.Service`. Any activity that wants to access the UPnP stack can then bind and unbind from this service as needed.

First, define an interface which is exposed to activities:

An activity typically accesses the `Registry` of known UPnP devices or searches for and controls UPnP devices. This interface provides the entry-point.

Next you implement an `android.app.Service` that offers the `IBinder` to connections from activities:

This is basically a wrapper around the Cling `UpnpService`, it starts and stops the UPnP stack when the service is created and destroyed. You also have to enable IP multicast on your WiFi network interface.

3.2. Accessing the service from an activity

The lifecycle of services in Android is well defined. The first activity which binds to a service will start the service if it is not already running. When no activity is bound to the service any more, the operating system will destroy the service.

Let's write a simple UPnP browsing activity. It shows all devices on your network in a list and it has a menu option which triggers a search action. The activity connects to the UPnP service and then listens to any device additions or removals in the registry, so the displayed list of devices is kept up-to-date.

This is the skeleton of the activity class:

We utilize the default layout provided by the Android runtime and the `ListActivity` superclass. Note that this activity can be your applications main activity, or further down in the stack of a task. The `listAdapter` is the glue between the device additions and removals on the Cling `Registry` and the list of items shown in the user interface.

The `upnpService` variable is `null` when no backend service is bound to this activity. Binding and unbinding occurs in the `onStart()` and `onStop()` callbacks, so the activity is only bound to the service when it is in the foreground. When the user clicks the Home button on his Android device, the activity will go into the background and unbind from the UPnP service. If no other activity is bound to the service, it will be destroyed at this time.

Binding and unbinding the service is handled with this `ServiceConnection`:

When connected, it obtains the `Registry` of the Cling UPnP stack and registers a listener. This listener will process additions and removals of devices as they are discovered on your network and update the items shown in the user interface list. It also prints a message on the screen, letting the user know that the activity has connected with the backend. The `RegistryListener` is removed when the activity unbinds from the service.

This is the `RegistryListener` which updates the list data:

Note that the `Registry` will call the listener methods in a separate thread. You have to update the displayed list data in the thread of the user interface.

The service connection will send a search message as soon as the service is bound, which will trigger replies from all UPnP devices on your network. The following two methods on the activity add a menu with a search action, so a user can refresh the list manually:

Finally, the `DeviceDisplay` class is a very simple JavaBean that only provides a `toString()` method for rendering the list. You can display any information about UPnP devices by changing this method:

We have to override the equality operations as well, so we can remove and add devices from the list manually with the `DeviceDisplay` instance as a convenient handle.

This manual has been created with Lemma from tested source code and Javadoc. Try it, you will like it.