How to write a Target in Java

Table of Contents

  1. Define your Target
  2. Choose and Configure a TUN Link
  3. Define your UI Sockets
  4. Write a Target Description
  5. Write your Resource Descriptions
  6. Write a Presentation Template
  7. Implement ITarget
  8. Target Initialization
  9. Implement ISocketListener
  10. Implement ISessionListener
  11. Binding and Unbinding to TUN(s)

1.   Define your Target

First you will need to have at least a geneal idea of how you would like your Target to function. We will use as an example throughout this tutorial a light switch. Our light switch was implemented using Swing. It has a simple graphical interface in which you can click on a switch to toggle the lights in the picture on and off. It also has a dimmer that cannot be accessed through the Swing interface, but can be accessed through a URC client. The dimmer takes an integer value from 0 to 10, with 10 representing the brightest setting and 0 representing the darkest.

The complete target code is provided in LightSwitchTarget.java and LightSwitchLauncher.java.

2.   Choose and Configure a TUN Link

Once you have a solid definition of your Target, you can begin thinking about how it will be used with a URC. What connection technologies will a URC use to connect to your Target? (Ethernet? Bluetooth? 802.11? Infrared?) What networking technologies will the Target be able to communicate? (UPnP? Jini?) A Target-URC Network (TUN) Link implements the protocol stack necessary to use a combination of connection and networking technologies. Your Target must use at least one TUN Link, but you may use as many as you would like.

Our light switch example uses only one TUN Link, implementing the UPnP 2-Service TUN (see note below). This TUN Link is available in the URC SDK in the package edu.wisc.trace.urcsdk.target.upnp2s. If you have the need for a different TUN, you will need to write your own TUN class which extends AbstractTargetTun. For more on this, see How to Write a Target TUN.

Note: The UPnP 2-Service TUN uses two vendor-specific, discoverable UPnP devices, named “URCDevice” and “TargetDevice”.  Each one includes a UPnP service, named “URCService” and “TargetService”, through which they offer actions that can be invoked by the other device.  See package.html in package edu.wisc.trace.urcsdk.target.upnp2s for more information.

3.   Define your UI Sockets

For each TUN you choose to implement, your Target will need at least one UI Socket specific to this TUN, but is allowed to have multiple. To define a Socket, you will need to ask yourself, what variables will the user be able to view from the URC? What variables will the user be able to manipulate from the URC? What relationships exist between variables?

For each Socket you choose to implement, you must write an XML User Interface Socket Description according to ANSI 390-2005. The Socket Description is a way to answer the previous questions. It defines the variables that the URC will have access to, and defines the read and write dependencies of these variables.

The following overview of Socket Descriptions is by no means a complete guide, therefore you should read the standard to avoid leaving out any details.

Basic Framework of the UI Socket Description

The root element of the Socket Description is <uiSocket>. This element must have an ‘about’ attribute that is a URI referencing the Socket Description. In the light switch, the about attribute is the URI of the Target Description, followed by the name of the Socket (a URI). If your Target contained multiple Sockets, you would want to use a more descriptive name than "socket" to distinguish between Sockets.

Note: To avoid duplication of Socket names in the global space, you should use your own domain, and append any suffixes suitable for URIs.  Large companies may define their own policies and rules for generating these global URIs.

The <uiSocket> element also needs an id attribute which should contain an identifier unique among all ‘id’ attributes in this file.

<uiSocket about="http://www.myurc.com/UrcSimEnv/lightswitch/socket"
id="lightSwitchSocket"
xmlns="http://www.incits.org/incits390-2005"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
</uiSocket>

Inside the <uiSocket> element you need the following element:

<dcterms:conformsTo>http://www.incits.org/incits390-2005</dcterms:conformsTo>

Also, if you modify your Socket Description, you will want to include the following element to indicate new revisions:

<dcterms:modified>2004-01-30</dcterms:modified>

Basics of UI Socket Elements

Inside <uiSocket> element you will define all of the elements in your Target that a URC Client should be aware of. There are four types of elements- variable, static, command, and notify. 

Each of the element types has an 'id' attribute which contains a unique string used to identify the element.

The variable and static elements have a 'type' attribute which associates the element with a XML Schema Datatype. Possible types include: xsd:string, xsd:boolean, xsd:integer, xsd:decimal, xsd:double, xsd:duration, xsd:dateTime, xsd:time, xsd:date, xsd:gYearMonth, xsd:gYear, xsd:gMonthDay, xsd:gDay, and xsd:gMonth. You may also define your own types using xsd:simpleType. For more information on XML Schema Datatypes, see the document "XML Schema Part 2: Datatypes Second Edition" at: http://www.w3.org/TR/xmlschema-2/

Elements may also contain a <dependency> element with attributes such as 'read', 'write', 'calculate', 'execute', and 'acknowledge'. These attributes contain strings that should be formatted as XPath 1.0 expressions. In addition, the function value('elementId'), with 'elementId' being the name of an element, should be used to represent the current value of an element. XPath expressions may contain operators such as 'and, 'or', '=', '!=', '>', '<', etc... as well as mathematical expressions. For more information on XPath 1.0, refer to: http://www.w3.org/TR/xpath.

Variable Elements

Variable elements should be used to represent values that change, and may or may not allow the user to change them, depending on the write dependencies. A variable element's <dependency> element may have 'read', 'write', and 'calculate' attributes. The 'read' attribute defines when the variable is visible to the user. The 'write' attribute defines when the user is allowed to change the value of the variable. The 'calculate' attribute specifies the relationship of a variable to other variables. The 'calculate' attribute should only be used with variables whose 'write' attribute is always false.

The light switch example contains only two elements, both of which are variables. The first is a boolean value called 'power' which is true when the light switch power is on. The second is an integer value ranging from zero to ten called 'dimmer'. The user is allowed to view both variables at all times. Also, the user is allowed to change the 'power' variable at any time, but may only change the 'dimmer' variable when the power is on.

<variable id="power" type="xsd:boolean">
<dependency read="true()" write="true()"/>
</variable>
<variable id="dimmer" type="dimmernumbertype">
<dependency read="true()" write="value('power')"/>
</variable>
<xsd:schema>
<xsd:simpleType name="dimmernumbertype" id="iddimmernumbertype">
<xsd:restriction base="xsd:integer">
<xsd:minInclusive value="0"/>
<xsd:maxInclusive value="10"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>

Static Elements

Static elements should be used to represent unchanging values in the the Target. Static elements only require the 'id' attribute, but may optionally have a 'type' attribute. The <dependency> element is also optional, and may contain a 'read' attribute.

For example, the serial number of a product may be represented by a static element. The serial number would always be readable, and could be defined to have type xsd:integer.

Command Elements

Command elements should be used to represent an command a user may issue to a Target that is more complex than the changing of a single variable. The 'read' attribute specifies whether or not the command should be visible to the user. The 'execute' attribute specifies whether or not the user should be able to invoke the command.

An example of a command would be the 'submit' button on the bottom of a form. The submit command should be visible to the user whenever the user is currently filling out the form. The submit command should only be executable when the user has completed all necessary portions of the form.

Notify Elements

Nofify elements should be used to represent notifications the Target wishes to pass on to the user. Notifications have three states: active, inactive, or stacked. When stacked, the most recent notification takes priority.

Notify elements may also have an 'explicitAck' attribute. The default values is true, meaning that the notification must be explicitly acknowleged by the user. Since a notification may suspend normal operation until acknowledged if it is defined to require explicit acknowlegement, notification elements may also define timeouts. For more on this topic, refer to the standard.

Notify elements must also have a <dependency> element containing the 'acknowledge' attribute. If explicitAck is true, the user must explicitly acknowledge the notification, but may only make the acknowledgement when the expression in the acknowledge attribute evaluates to true(). If explicitAck is false, the acknowledge expression evaluating to true() acts as an implicit user acknowledgement.

An example of a notify element would be a notification that informed the user that the batteries in a device are low. This notification might have 'explicitAck' set to true() and also have 'acknowledge' set to true(). This would represent a notification which the user may acknowledge at any time, for example, by clicking on an 'OK' button.

The full UI Socket Description for the light switch example is given here: lightswitch.uisocket.xml

4.   Write a Target Description

You may now write a Target Description according to ANSI 392-2005. Without going into detail, a Target Description is an xml document that defines a name for your Target, and provides the names of the XML documents where the your Socket and Resource definitions can be found. (Resource Descriptions will be explained in the next section.) The Target Description is the only document a URC Client needs to know the location of because it can find references to all other documents in the Target Description.

Basic Framework of the Target Description

The root element of the Target Description is <target>. The <target> element should have and 'about' attribute that contains a URI reference to the Target Description. It should also have an 'id' attribute which contains a unique identifier referencing the Target.

<target 
about="http://www.myurc.com/UrcSimEnv/lightswitch"
id="lightswitch"
hidden="false"
xmlns="http://www.incits.org/incits392-2005"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:dcterms="http://purl.org/dc/terms/"
xmlns:myComp="http://www.myComp.com"
xmlns:gml="http://www.opengis.net/gml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<dcterms:conformsTo>http://www.incits.org/incits392-2005</dcterms:conformsTo>
<location id="location">
</location>
</target>

Inside the <target> element you need the following element:

<dcterms:conformsTo>http://www.incits.org/incits392-2005</dcterms:conformsTo>

You also need a <location> element that should have a unique 'id' attribute. If your Target has a specific location, you should define a <geocoordinates> element with <location> to define a set of geographical coordinates.

The light switch does not have a specific location, so its <location> element is empty:

<location id="location"></location>

Socket References

You should define a <socket> element for each UI Socket Description you have written. The <socket> element contains basic information about the Socket and a reference to the location of the Socket Description file.

The <socket> element should contain an 'id' attribute defining a unique identifier for the Socket. It should also have a 'name' attribute that contains the URI of the Socket. The 'type' attribute can have one of three values: "location-dependent", "location-informative", and "location-free". Location-dependent Targets have alocation and require the user to be near the Target to control it. Location-informative have a location, but can be controlled from anywhere. Location-free Targets have no location. The 'hidden' attribute may be "true" or "false". "True" means that the Socket should be hidden from the user when discovered on a URC Client. An example of a Socket that would be hidden is a Socket on a Target of which there are many of, such as one in a line of ATMs. The user might only be allowed to connect to a seperate Target whose purpose was to queue up waiting users and forward their sessions onto an ATM as one opens up.

Our single light switch Socket is location-informative because it can be used from anywhere over the UPnP 2 Service TUN. We might have defined a second Socket on the light switch Target which communicated via infrared. This would be an example of a location-dependent Socket.

Inside the <socket> element, you should define a <socketDescriptionLocalAt> element which contains a URI that gives the location of the Socket Description relative to the location of the Target Description. You may also define a <category> element which describes how to categorize a Target.

In the light switch example, we have used the 'taxonomyName' attribute of category to describe a classification scheme (http://www.unspsc.org) and our Target's classification within this scheme.

<socket id="lightSwitchSocket" 
name="http://www.myurc.com/UrcSimEnv/lightswitch/socket"
type="location-informative"
hidden="false">
<socketDescriptionLocalAt>lightswitch.uisocket.xml</socketDescriptionLocalAt>
<category taxonomyName="http://www.unspsc.org">39.11.24.02</category>
</socket>

The Resource Directory

Your Target Description should also contain one Resource directory. Resource directories are defined by ANSI  393-2005. Your Resource directory should have a <rdf:RDF> element, with a <ResourceDirectory> element within. Within the <ResourceDirectory> element you should have the following element: <dcterms:conformsTo rdf:resource="http://www.incits.org/incits393-2005"/>

<rdf:RDF 
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:dcterms="http://purl.org/dc/terms/"
xmlns="http://www.incits.org/incits393-2005#">
<ResourceDirectory rdf:about="http://www.myurc.com/UrcSimEnv/lightswitch/resdir.rdf">
<dcterms:conformsTo rdf:resource="http://www.incits.org/incits393-2005"/>
</ResourceDirectory>
</rdf:RDF>

Resource Sheets

Within <ResourceDirectory> you should list any Resource sheets you have defined (explained in section 5), a reference to your presenetation template (explained in section 6), and references to any Resourceservices that the user may want to query to look for more Resource Descriptions.

For each Resource sheet you define in section 6, you should make a <resourceSheet> element. Within this should be a <ResourceSheet> element. The <ResourceSheet> element should have a 'rdf:about' element that contains the URI of the Resource Description. You will also need the <dcterms:conformsTo> element, as well as a <localAt> element which should contain a URI that gives the location of the Resource Description relative to the location of the Target Description.You should have a <containsDomain> element for each domain that has elements from it defined in the Resource Description. You should also have a <containsRole> element for each type of Resource defined in the Resource Description. Resource roles includelabel, help, accesskey and keyword. Lastly, you should have a <containsLanguageContext> element describing which languages are present in the Resource Description. The language codes are specified by specified by IETF RFC 2277, “IETF Policy on Character Sets and Languages,” with reference to RFC 3066, “Tags for the Identification of Languages.”  You may look at this webpage maintained by the Library of Congress for a list of language codes, although the codes are currently unstable: http://www.loc.gov/standards/iso639-2/langcodes.html

Below is a <resourceSheet> element defined in the light switch Target Description. Because the light switch has more than one Resource Description, there are other <resourceSheet> elements as well.

<resourceSheet>
<ResourceSheet rdf:about="http://www.myurc.com/UrcSimEnv/lightswitch/lightswitch-label-en.rdf.xml">
<dcterms:conformsTo rdf:resource="http://www.incits.org/incits393-2005"/>
<localAt>lightswitch-label-en.rdf.xml</localAt>
<containsType>Text</containsType>
<containsDomain rdf:resource="http://www.myurc.com/UrcSimEnv/lightswitch"/>
<containsDomain rdf:resource="http://www.myurc.com/UrcSimEnv/lightswitch/socket"/>
<containsRole rdf:resource="http://www.incits.org/incits393-2005#label"/>
<containsLanguageContext>en</containsLanguageContext>
</ResourceSheet>
</resourceSheet>

UIID Descriptions

After writing a Presentation Template (PreT) in section 7, you should write a <uiidDescription> element to reference the PreT. Within the <uiidDescription> element you should have a <UiidDescription> element. This element should have an 'rdf:about' attribute containing the URI of the PreT. Within this element you will need the <decterms:conformsTo> element. You will also need a <coreForSocket> element which should have a 'rdf:resource' attribute containing the URI of the UI Socket that the PreT is describing. Also, you will need a <localAt> element which should contain a URI that gives that location of the PreT document in relation the location of the Target Description.You may also want to add Dublin Core Metadata Initiative (DCMI) Metadata
Terms such <dc:creator>, <dc:publisher>, <dc:contributor>, <dc:date>, <dc:rights> and <dcterms:audience>. See this website for more information on Metadata Terms: http://dublincore.org/documents/dcmi-terms/

Below is the <uiidDescription> element from the light switch Target description.

<uiidDescription>
<UiidDescription rdf:about="http://www.myurc.com/UrcSimEnv/lightswitch/socket/pret">
<dcterms:conformsTo rdf:resource="http://www.incits.org/incits391-2005"/>
<coreForSocket rdf:resource="http://www.myurc.com/UrcSimEnv/lightswitch/socket"/>
<localAt>lightswitch.pret.xml</localAt>
<dc:publisher>Trace Center</dc:publisher>
</UiidDescription>
</uiidDescription>

The Target Description for the light switch example is provided here: lightswitch.td.xml

5.   Write your Resource Descriptions

A Resource Description provides information to the URC on how to display the Socket variables defined in your Socket Description. Resource Descriptios are definined in ANSI 393-2005.

Basic Framework of the Resource Description

The root element of a Resource Description is the <rdf:RDF> element. Within this, you should have a <ResourceSheet> element. The <ResourceSheet> element contains the same elements describing the content of the Resource Description as the <ResourceSheet> element had in the above Target Description section on Resource Sheets. Please read the section on Resource Sheets for a description of these elements.

<rdf:RDF 
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:dcterms="http://purl.org/dc/terms/"
xmlns="http://www.incits.org/incits393-2005#">
<ResourceSheet rdf:about="http://www.myurc.com/UrcSimEnv/lightswitch/lightswitch-label-en.rdf.xml">
<dcterms:conformsTo rdf:resource="http://www.incits.org/incits393-2005"/>
<containsType>Text</containsType>
<containsFormat>text/xml</containsFormat>
<containsDomain rdf:resource="http://www.myurc.com/UrcSimEnv/lightswitch"/>
<containsDomain rdf:resource="http://www.myurc.com/UrcSimEnv/lightswitch/socket"/>
<containsRole rdf:resource="http://www.incits.org/incits393-2005#label"/>
<containsLanguageContext>en</containsLanguageContext>
<dc:publisher>Trace Center</dc:publisher>
</ResourceSheet>
</rdf:RDF>

Resource Descriptions

For each label, access key, help text, or keyword you would like to define in your Resource sheet, you will need a seperate <aResourceDescription> element. Within this, you should have a <AResourceDescription> element. The 'rdf:about' attribute of this element should be a URI referencing the Resource you are describing. Next you should have a either a <contentLocalAt> or a <content> element. <contentLocalAt> should be used to describe the location of a Resource relative the the Resource Description, and <content> may contain any XML-encoded information. You will also need the <dcterms:confromsTo> element. You will need a <useContext> element. Within the <useContext> element, you should have an <elementRef> element containing a URI referencing the element being described, a <role> element describing the type of Resource (label, acesskey, etc...), and a <languageContext> element identifying the language context of the Resource. (Language codes were previously described in the section on Resource Sheets.) You will also need a <dc:type> element which should contain the type of Resource provided, such as "Text" or "Image" If the type is not "Text", you should have a <dc:format> element describing the MIME type of the provided Resource. (See here for a list of MIME types: http://www.iana.org/assignments/media-types/) Additionally, you may include any of the DCMI Metadata types as previously described in the section on Uiid Descritptions.

<aResourceDescription>
<AResourceDescription rdf:about="http://www.myurc.com/UrcSimEnv/lightswitch/lightswitch-label-en.rdf.xml#portal_label">
<content rdf:parseType="Literal">Light Switch</content>
<dcterms:conformsTo rdf:resource="http://www.incits.org/incits393-2005"/>
<useContext>
<UseContext>
<elementRef rdf:resource="ttp://www.myurc.com/UrcSimEnv/lightswitch#lightSwitchSocket"/>
<role rdf:resource="http://www.incits.org/incits393-2005#label"/>
<languageContext>en</languageContext>
</UseContext>
</useContext>
<dc:publisher>Trace Center</dc:publisher>
<dc:type>Text</dc:type>
</AResourceDescription>
</aResourceDescription>

<aResourceDescription>
<AResourceDescription rdf:about="http://www.myurc.com/UrcSimEnv/lightswitch/lightswitch-label-en.rdf.xml#power_label">
<content rdf:parseType="Literal">Power</content>
<dcterms:conformsTo rdf:resource="http://www.incits.org/incits393-2005"/>
<useContext>
<UseContext>
<elementRef rdf:resource="http://www.myurc.com/UrcSimEnv/lightswitch/socket#power"/>
<role rdf:resource="http://www.incits.org/incits393-2005#label"/>
<languageContext>en</languageContext>
</UseContext>
</useContext>
<dc:publisher>Trace Center</dc:publisher>
<dc:type>Text</dc:type>
</AResourceDescription>
</aResourceDescription>

<aResourceDescription>
<AResourceDescription rdf:about="http://www.myurc.com/UrcSimEnv/lightswitch/lightswitch-label-en.rdf.xml#portal_label">
<contentLocalAt>resources/lightbulb.gif</contentLocalAt>
<dcterms:conformsTo rdf:resource="http://www.incits.org/v2/2004/res"/>
<useContext>
<UseContext>
<elementRef rdf:resource="http://www.myurc.com/UrcSimEnv/lightswitch#lightSwitchSocket"/>
<role rdf:resource="http://www.incits.org/incits393-2005#label"/>
<languageContext>en</languageContext>
<languageContext>de</languageContext>
</UseContext>
</useContext>
<dc:publisher>Trace Center</dc:publisher>
<dc:type>Image</dc:type>
</AResourceDescription>
</aResourceDescription>

The Resource Descriptions for the light switch example are provide here: lightswitch-label-en.rdf.xml, lightswitch-label-image.rdf.xml, lightswitch-label-de.rdf.xml

6.   Write a Presentation Template

A Presentation Template (PreT) contains hints on how a the elements of a UI Socket should be displayed. The Presentation Template is defined by ANSI 391-2005.

Below is the PreT for the light switch example. It indicates that the 'power' element should be displayed with the input interactor, and the 'dimmer' element should be displayed with the range interector.

<pret id="pret" about="http://www.myurc.com/UrcSimEnv/lightswitch/socket/pret" xmlns="http://www.incits.org/incits391-2005" xmlns:dcterms="http://purl.org/dc/terms/">
<dcterms:conformsTo>http://www.incits.org/incits391-2005</dcterms:conformsTo>
<input id="power" ref="http://www.myurc.com/UrcSimEnv/lightswitch/socket#power"/>
<range id="dimmer" ref="http://www.myurc.com/UrcSimEnv/lightswitch/socket#dimmer"/>
</pret>

The Presentation Template for the light switch example is provide here: lightswitch.pret.xml

7.   Implement ITarget

Assuming that you have already written the core functionality of your Target in Java, your Target will now have to implement the interfaces neccessary to use the URC SDK. These are ITarget, ISocketListener, and ISessionListener. First we will talk about implementing the ITarget interface.

Extending GenericTarget

The easiest way to implement ITarget is to extend the GenericTarget class. GenericTarget implements ITarget.

If you extend GenericTarget, you will need to call super(URI tdLocation) first in your constructor. The GenericTarget constructor takes care of parsing the Target Description and creating a TargetDirectory object to represent it. It also adds a UISocket to the ArrayList called uiSockets for each Socket found in the Target Description.

public class LightSwitchTarget extends GenericTarget implements ISocketListener, ISessionListener{

public LightSwitchTarget(URL codeBase, URI tdLocation) {

super(codeBase, tdLocation);

power = false;
dimmer = 10;
initialize();
initComponents();
initializeSocket();
}
}

Implementing ITarget

If you want to write your own Target class that does not inherit from GenericTarget, your Target class must implement the ITarget interface with its methods:

8.   Target Initialization

When you initialize your taget object, you will need to do the following things.

You should call the constructor of GenericTarget (if you extended GenericTarget) as discussed in the previous section. GenericTarget creates a UISocket object for each UI Socket definition it finds in the Target Description and places them in an array. Since you will need to invoke methods from these UISocket objects frequently, you will probably want to reference them in your Target.

In the light switch example, we only have one UI Socket, which we call lightSwitchUISocket:

lightSwitchUISocket = (UISocket) this.getUISockets().toArray()[0];

If you do not extend GenericTarget, you will need to parse the Target Description in your constructor and identify all of the UI Sockets defined.

Also upon initialization, you will need to make a Socket listener for each UI Socket. The Socket listener takes care of listening for requests from URC Clients to open new sessions on the Target.

lightSwitchUISocket.addSocketListener(this);

9.   Implement ISocketListener

You will also need to implement the ISocketListener interface. ISocketListener contains methods to allow URC Clients to open new sessions on your Target.

sessionOpenRequest

The sessionOpenRequest(UISocket uiSocket) method should return a boolean value stating whether or not the Target allows a new session to be opened.

In the light switch example, the Target always allows new sessions to be opened.

public boolean sessionOpenRequest(UISocket uiSocket) {
return true;
}

An example of a Target which should control the opening of new sessions is an ATM, which should only allow one session to be open at a time. In this case, the Target would most likely check the value of sessionCount and only open a new session if it was zero.

sessionOpened

The sessionOpened(TargetSession session) method is called when a new session is opened by the URC. Here you should implement any actions that need to be taken at the beginning of every new session. Here you must also add the new session to the session listener.

public void sessionOpened(TargetSession session) {
session.setSessionListener(this);
}

10. Implement ISessionListener

You will also need to implement the ISessionListener interface. ISessionListener contains methods which allow a URC Client to interact with your Target through an open session.

sessionClosed

The sessionClosed(SessionClosedEvent event) method is called when a session is closed by the URC. Here you should implement any actions that need to be taken at the end of a session. Here you must also remove the session from the session listener.

public void sessionClosed(SessionClosedEvent event) {
this.getSessionById(sessionId).removeSessionListener();
}

setElementStateRequest

The setElementStateRequest(UISocketVariable uiSocketVariable, Object value) method returns a boolean value stating whether or not the Target allows the URC to modify an element. If the Target allows the element to be changed to the value passed, it should update the value of the element within the Target. If the element is common to other sessions, the Target should also pass the updated element to any sessions it is common to.

In the light switch example, the Target always allows variables to be changed, so the method always updates the element and returns true. To update the element, it checks the id of the UISocketVariable parameter against all of the possible element names, and calls a method that takes care of updating each element.

The arguement variable is of type UISocketVariable, which inherits from IUISocketElement. It includes a method called getID() that returns a string to identify the variable with. This string is identical to the name you gave the variable in your Socket Description. You will probably want to use getId() to identify the Socket variables you are looking for.

In the light switch example, we need to check for the changing of the Socket variables 'power' and 'dimmer. We have a case for each element. Within each case a different method for the changing of each variable is invoked.

public boolean setElementStateRequest(UISocketVariable uiSocketVariable, Object value) {
logger.info("setElementStateRequest called");
String id = uiSocketVariable.getId();

if (id.equals("lightOn")) {
togglePower(new Boolean((String)value));
}else if(id.equals("dimmer")){
dim(new Integer((String)value));
}
return true;
}

In each of the methods called when a variable is changed, the state of the swing interface of the Target is updated. Also, if the variable changed is shared between all open sessions, two things must be done. First, the template element within each UISocket needs to be updated. Each UISocket in your Target contains a set of all of the UISocketElements within that Socket. Whenever a new Session object is created, these template elements are copied to create the elements within the new session. Therefore, you must update the template elements whenever they change so that any new sessions opened in the future will begin with the current values of each element. This is done by getting the element from the UISocet and calling setValue(String value) where value is a string representing the new value of the element. Second, you must pass the update to any other open sessions so that they remain up to date on the status of the Target. This is done by calling setValueForAllSessions(String elementId, String value) where elementId the the id of the element and value is a string representing the new value of the element.

private void togglePower(Boolean p) {
power = p;

try{
lightSwitchUISocket.getUISocketElementById("power").setValue(power.toString());
lightSwitchUISocket.setValueForAllSessions("power", power.toString());
}catch(UrcException urcException){ }

powerButton.setIcon(power ? powerOn : powerOff);
lightPanel.setBackground(power ? new Color(dimmer*25,dimmer*25,dimmer*25) : Color.black);
}

private void dim(Integer level) {
if(level != null && level >=0 && level <=10) {
dimmer = level;
try{
lightSwitchUISocket.getUISocketElementById("dimmer").setValue(dimmer.toString());
lightSwitchUISocket.setValueForAllSessions("dimmer", dimmer.toString());
}catch(UrcException urcException){ }

lightPanel.setBackground(power ? new Color(dimmer*25,dimmer*25,dimmer*25) : Color.black);
}
}

Note: Remember, if the writeablity of a variable is dependent on another variable, you should describe this dependency in the Socket Description. This will prevent the URC from requesting to change a variable, so you should not implement these kinds of dependencies here. On the other hand, write dependencies that depend on conditions other than the state of another Socket variable should be defined here. For example, if there were multiple users using your Target, and your Target only allowed a user to change a variable if another user was not accessing the same variable, you would implement this here.

If desired, you may also accumulate updates and pass them all onto any clients at the same time. This is done by first changing the values of the elements in the internal target-side socket (as well as in the socket template), and then calling propagateUpdatesForAllSessions() on the socket to propagate all of the element changes onto all sessions. For example, in the alarm clock target, when the user acknowleges a notification that the alarm has gone off, both the notification and a boolean indicating whether the alarm is set are updated and passed onto all sessions at the same time.

public void notificationAcknowledged(UISocketNotification notification) {
 alarmEnabled = false;
 try {
  // Set template
  clockUISocket.getUISocketElementById("alarmnotify").setValue(Constants.BasicNotificationState.Inactive.toString());
  clockUISocket.getUISocketElementById("alarmEnable").setValue(alarmEnabled.toString());
  // Set internal
  clockUISocket.setInternalValueForAllSessions("alarmnotify",Constants.BasicNotificationState.Inactive.toString());
  clockUISocket.setInternalValueForAllSessions("alarmEnable",alarmEnabled.toString());
  // Update
  clockUISocket.propagateUpdatesForAllSessions();
 } catch (UrcException e) { e.printStackTrace(); }
 toggleAlarmButton.setText("Alarm Off");
}

commandInvokeRequest

The invokeCommandRequest(UISocketCommand uiSocketCommand) method is called when a command has been invoked by a URC client.

The light switch example doesn't contain any commands, so it simply returns Ready.

public String invokeCommandRequest(UISocketCommand uiSocketCommand) {
return Constants.BasicCommandState.Ready.toString();
}

notificationAcknowledged

The method is called when a notification has been acknowledged by a URC client.

The light switch example doesn't contain any commands, so it does nothing.

In the alarm clock target, there is a notification called alarmnotifiy that is set to "active" when the alarm goes off.

// send the alarm here
try{
 clockUISocket.getUISocketElementById("alarmnotify").setValue(Constants.BasicNotificationState.Active.toString());
}catch(UrcException urcException){
 logger.severe(urcException.getMessage());
}
clockUISocket.setValueForAllSessions("alarmnotify", Constants.BasicNotificationState.Active.toString());
alarmSent = true;

In the notificationAcknowledged method, after the user has acknowledged the notification, alarmnotify is set back to "inactive". Also, in this example, the alarmEnabled variable has been updated to show that the alarm has been turned off.

public void notificationAcknowledged(UISocketNotification notification) {
 alarmEnabled = false;
 try{
  clockUISocket.getUISocketElementById("alarmnotify").setValue(Constants.BasicNotificationState.Inactive.toString());
 }catch(UrcException urcException){
   logger.severe(urcException.getMessage());
 }
 clockUISocket.setValueForAllSessions("alarmnotify", Constants.BasicNotificationState.Inactive.toString());
 try{
  clockUISocket.getUISocketElementById("alarmEnable").setValue(
  alarmEnabled.toString());
  clockUISocket.setValueForAllSessions("alarmEnable", alarmEnabled.toString());
 }catch(UrcException urcException){
  logger.severe(urcException.getMessage());
 }
}

connectionLost and reconnect

The connectionLost(String sessionId) and reconnect(String sessionId) methods are part of the interface for future version, but are not currently supported by the SDK. Therefore, you can simply leave these methods empty.

11. Binding and Unbinding to TUN(s)

When your Target object is created, you must notify the TargetTunManager of any TUNs that your Target wishes to bind to.

The bindToTun method takes the name of a TUN class, and a map of parameters. The purpose of the parameter map is to pass to the TUN any information it needs. If you choose to implement any TUNs, you may define the parameters needed however you wish, The parameter map for the UPnP 2 Service TUN should be set up as follows:

In the light switch example, we have a class called LightSwitchLauncher. The launcher class is the main class from which the light switch is run, and may be run as an application or as an applet. The launcher class creates a single light switch object and binds it to the UPnP 2 Service TUN:

lsTarget = new LightSwitchTarget(codeLocation, tdLocation);

Map<String, Object> parameters = new HashMap<String, Object>();
parameters.put("UDN", "www.myurc.com_UrcSimEnv_lightswitch_socket");
parameters.put("friendlyName", "Light Switch");
parameters.put("presentationURL", lsTarget.getTargetDocumentURI().toString());
parameters.put("targetName", lsTarget.getName());
lsTarget.setParameters(parameters);
System.out.println("Calling bindToTun");

try{
lsTarget.bindToTargetTun("edu.wisc.trace.urcsdk.target.upnp2s.Upnp2sTargetTun", parameters);
}catch(UrcException urcException){
logger.severe(urcException.getMessage());
}

Also, when the applet is destroyed or when the application is ended, the launcher unbinds the Target from each TUN.

public void destroy() {
try {
lsTarget.unbindTargetTun("edu.wisc.trace.urcsdk.target.upnp2s.Upnp2sTargetTun");
} catch(UrcException e) {
logger.warning(e.getMessage()); }
}

Last updated: Jamie Tabaka, 2006-05-15