C H A P T E R  6

Using RFID Information Server Client API

This chapter describes the Sun Javatrademark System RFID Software Information Server and the client API for interfacing with RFID Information Server.

The following topics are covered:


Architecture

The Sun Java System RFID Software Information Server (IS) is a J2EE application that runs on one of the supported application servers. RFID Information Server stores all data in a relational database. In this release of Sun Java System RFID Software, RFID Information Server is supported on the following databases:

External applications interface with the RFID Information Server through XML message exchange. Requests and responses are expressed in XML and conform to an XML schema. The RFID Information Server supports HTTP and JMS message transports. The RFID Software provides a Java client library that can be used to access the RFID Information Server from your software applications. The APIs used to query and manipulate data in the RFID Information Server are independent of the protocol used. The following figure shows the architecture.


Illustration showing how client applications can access the data stored in the RFID Information Server.


Database Tables

This section describes the Sun Java System RFID Software database table names and keys.


TABLE 6-1 RFID Information Server Database Tables

Name

Definition

Keys

CONTAINER_TYPE

Each entry in this table represents a type of container.

Container types are specific to a deployment. Common container types include pallets, cases, inner packs and items.

Primary - NAME

CONTAINMENT

Maintains a hierarchy of container relationships between EPCs.

Each container is identified by the parent EPC. The parent may have zero or more child EPCs. Because a child EPC can represent a container, the hierarchy can be arbitrarily deep.

Primary - EPC

CONTAINMENT_LOG

Maintains the history of containment relationships between container EPCs.

 

CURRENT_OBSERVATION

Maintains the list of tags that are being reported as currently visible at a sensor.

This table can only be used in conjunction with the RFID Event Manager's Delta filter.

To keep the table consistent the RFID Information Server relies on the TagsIn and TagsOut property of the Delta event.

Foreign - SENSOR_EPC

CUSTOMER

Maintains the customer shipment information.

Primary - CUSTOMER_ID

EPCLOG

Maintains a history of shipments. This log provides a record of the EPCs (each representing a specific product or container) that comprised each shipment.

Primary - LOG_ID

Foreign - EPC, SHIPPING_ID

LOCATION

Maintains the physical locations.

Primary - LOCATION_ID

Foreign - EPC

OBSERVATION_LOG

Maintains the history of all tag observations.

Each entry in the table represents an observation which contains the EPC of the observer (sensor), the EPC of the observed value and the time at which it was observed.

Foreign - SENSOR_EPC

ORGANIZATION

A manufacturer or distributor of goods.

Primary - ORGANIZATION_ID

ORGANIZATION_EXT

Maintains a set of properties associated with an ORGANIZATION entry. These properties reference their respective ORGANIZATION using the ORGANIZATION_ID field. The properties consist of name and value pairs.

Foreign - ORGANIZATION_ID

ORGANIZATION_XREF

Identifies the hierarchy of an organization. This table is designed to describe a structure where an organization is part of a division and the division is part of a company and so on.

Primary - ORGANIZATION_ID

Foreign - ORGANIZATION_ID, PARENT_ORG

PRODUCT

A class of items, or Stock Keeping Unit (SKU) identified by a GTIN or UPC code.

Primary - PRODUCT_ID

Foreign -MANUFACTURER_ID

PRODUCT_EXT

Maintains a set of properties associated with a PRODUCT entry. These properties reference their respective PRODUCT instance using the PRODUCT_ID field. The properties consist of name and value pairs.

Foreign - PRODUCT_ID

SENSOR

An RFID reader or antenna uniquely identified by an EPC.

Primary - EPC

SHIPPING_INFO

Maintains the information specific

to a particular shipment.

By using this table, the CUSTOMER table, and EPCLOG, it is possible to find all of the shipments to a specific customer and to identify which products or containers were in the shipments.

Primary - SHIPPING_ID

Foreign - CUSTOMER_ID

TAG_ALLOCATION

Assigns and de-assigns ranges of EPC number and keep track of them.

Primary - TAG_ALLOCATION_ID

TAG_ALLOCATION_LOG

Maintains the history of all tag allocated.

 

TX_LOG

Associates a set of EPCs with a business transaction ID.

Common transaction IDs include PO numbers and ASNs.

Foreign - UNIT

UNIT

A tagged entity identified by a unique EPC. An entry in the UNIT table can represent a pallet, case or any other entity that's tracked.

Primary - EPC

Foreign - PRODUCT_ID, UNIT_TYPE,

LOCATION_ID, OWNER_ID

UNIT_EXT

Maintains a set of properties associated with a UNIT entry. These properties reference their respective UNIT instance by using the EPC field. The properties consist of name and value pairs.

Foreign - EPC



Connecting to RFID Information Server

The com.sun.autoid.epcis.client.EpcisConnection class represents a communication link between an application and RFID Information Server. An instance of the EpcisConnection class can support multiple requests. The transport protocol used by the connection is specified using the appropriate constructor. The user name and password that are used are the ones that are specified for access to the RFID Information Server. The process of creating users for access to the RFID Information Server reports and index page is described in the installation guide for this product. See Chapter 5 in the Sun Java System RFID Software 3.0 Installation Guide.

You specify the RFID Information Server database schema by using one of the following Java System properties:

The format of the URL is http://epcis-host:port/epcis/EpcisDbSchema.xml. Replace the variable, epcis-host, with the host name or IP address where your RFID Information Server is installed. The variable, port, is an optional port number for Application Server. The usual default port number is 80. For example, http://host1.sun.com/epcis/EpcisDbSchema.xml would point to the web server listening on port 80 that is hosting the RFID Information Server. The URL http://host1.sun.com:8080/epcis/EpcisDbSchema.xml specifies the web server on port 8080 that is hosting the RFID Information Server.

You can set these properties in the following ways:

If at least one of these properties is not set, then the RFID Information Server client API tries to infer the value. If the EPCISConnection is an HTTP type, then the URL is constructed from the URL for the RFID Information Server that is passed in the EPCISConnection constructor. If this constructed URL can be successfully contacted, then the system property rfidis.db.schema is set to this constructed URL. If connecting to that URL fails, the following URLs are tested in order, http://localhost/epcis/EpcisDbSchema.xml and http://localhost:8080/epcis/EpcisDbSchema.xml. If connectivity is successful to one of these constructed URLs, then the property, rfidis.db.schema is set to the first one that successfully connects.

If all the connection attempts that use the constructed URLs fail, then an EPCISException is thrown from the EPCISConnection constructor.

If the properties, rfidis.db.schema and rfidis.db.schema.file, are set prior to the EPCISConnection constructor, then there is no connectivity check during the EPCISConnection constructor and no exception will be thrown. However, if connectivity cannot be established later on, when you access the RFID Information Server APIs, then EPCISExceptions are thrown at that time.

This section contains the following code examples:



Note - Do not include the fscontext.jar in your class path when using a remote JNDI.




CODE EXAMPLE 6-2 Establishing a JMS Topic Connection on Sun Java System Application Server 8.1

EpcisConnection conn = new EpcisConnection(

"com.sun.jndi.fscontext.RefFSContextFactory",

"file:///imq_admin_objects", // file system JNDI provider URL

"TopicConnectionFactory", // name of the connection factory

"epcisTopic", // name of the topic

"true", // user JMS (true or false)

"myname", // user name

"mypassword"); // password

 


CODE EXAMPLE 6-3 Establishing a JMS Queue Connection on Sun Java System Application Server 8.1

EcpisConnection conn = new EpcisConnection (

null,//Initial context factory

"iiop://localhost:3700", //URL of the App Server JNDI provider

"jms/QueueConnectionFactory", //name of the Connection Factory for the JMS queue

"jms/epcisQueue", //name of the domain for the JMS queue

EPCISConstants.CONNECTION_TYPE_JMS_QUEUE, //the domain of the JMS queue

"myname", // user name

"mypassword"); // password

 



CODE EXAMPLE 6-4 Establishing a Connection Using JMS on BEA WebLogic Server 8.1 SP4 [1]

EcpisConnection conn = new EpcisConnection (

"weblogic.jndi.WLInitialContextFactory", // JNDI initial context factory

"t3://localhost:7001", // JNDI provider URL

"jms/TopicConnectionFactory", // name of the connection factory

"jms/epcisTopic", // name of the topic

"true",

"username", // authentication username

"password"); // authentication password

 


Closing the Connection

Calling the close() method on the connection calls the close() method of the underlying HttpURLConnection or TopicConnection object. It is recommended that the call to the close() method be captured in a finally block.


CODE EXAMPLE 6-5 Closing the Connection

EpcisConnection conn = null;

try {

conn = ... //initialize the connection here

} catch (Exception e) {

e.printStackTrace();

} finally {

try {

conn.close();

} catch (Exception e) {

e.printStackTrace();

}

}

 



Exchanging Data With RFID Information Server

Transfer objects are client-side representations of data that are exchanged between RFID Information Server and an application. The data in a Transfer object may be stored in one or more database tables. The Java class to database object relationships are shown in TABLE 6-2. Unit, Product, Organization, Container, Sensor, ContainerType, Transaction and Observation are all transfer objects.

You would typically expect to be able to insert, query, modify and delete these objects from the database. But the Transaction and Observation objects are exceptions to this rule. You use the UpdateRequest object to record an Observation or Transaction. Once an Observation or Transaction is recorded, it cannot be modified. In addition, an Observation cannot be deleted. There is no notion of erasing a past observation. The OBSERVATION_LOG table maintains the history of observations.


TABLE 6-2 Java Class to Database Objects Relationships

Package Name

Java Class Name

Request Object

Database Object

com.sun.autoid.epcis.client

 

ValueObjectWrapper

The superclass of all other classes in this table.

Request

 

 

ContainerType

ContainerTypeRequest

An entry in the CONTAINER_TYPE table

 

ContainmentLog

ContainmentLogRequest

An entry in the CONTAINMENTLOG table

 

Customer

CustomerRequest

An entry in the CUSTOMER table

 

EpcLog

EpcLogRequest

An entry in the EPCLOG table

 

Location

LocationRequest

An entry in the LOCATION table

 

Observation

ObservationRequest

An entry in the OBSERVATION_LOG or CURRENT_OBSERVATION table

 

Organization

OrganizationRequest

An entry in the ORGANIZATION table.

 

OrganizationXref

OrganizationXrefRequest

An entry in the ORGANIZATION_XREF table.

 

Product

ProductRequest

 

An entry in the PRODUCT table

 

Sensor

SensorRequest

An entry in the SENSOR table

 

TagAllocation

TagAllocationRequest

An entry in the TAG_ALLOCATION table

 

TagAllocationLog

TagAllocationLogRequest

An entry in the TAG_ALLOCATION_LOG table

 

Unit

UnitRequest

An entry in the UNIT table. A Unit could be a case, pallet or any other entity being tracked

com.sun.autoid.epcis.business

 

 

 

Container

ContainerRequest[2]

A set of rows in the CONTAINMENT table that correspond to a hierarchy of containers.

 

Transaction

TransactionRequest[3]

A set of rows in the TX_LOG table grouped by TX_ID.

com.sun.autoid.epcis.dao

 

 

 

 

PrimaryKey

 

A primary key value and table name



Modifying RFID Information Server Tables

You can work with the RFID Information Server Transfer objects in the following two ways:

Using Table Request Objects

A table Request object implements the CRUD pattern for an RFID Information Server table. Not all tables support the update and delete operations. Some tables do not have a natural primary key, thus a retrieval operation might return a list of matching Transfer objects.



Note - Observation objects must be created using the UpdateRequest object.




CODE EXAMPLE 6-6 Creating a Product

EpcisConnection conn = new EpcisConnection(...)

// Create Product client

ProductRequest req = new ProductRequest(conn);

//Create Product

Product create = new Product();

create.setProductId("26");

create.setManufacturerId("1");

create.setName("Test Product");

create.setGtin("00067933861108");

create.setDescription("Product to be inserted");

create.setObjectClass("3");

// Create Product

req.create(create);

 



CODE EXAMPLE 6-7 Retrieving a Product

EpcisConnection conn = new EpcisConnection(...)

// Create Product client

ProductRequest req = new ProductRequest(conn);

Product p2 = req.get("26");

if(p2 != null) {

System.out.println("Found Product: " + p2.getDescription());

}else {

System.out.println("Product # 26 not found!");

}



CODE EXAMPLE 6-8 Updating a Product

EpcisConnection conn = new EpcisConnection(...)

// Create Product client

ProductRequest req = new ProductRequest(conn);

Product p2 = req.get("26");

if(p2 != null) {

p2.setDescription("modified product description");

req.update(p2);

}else {

System.out.println("Product # 26 not found!");

}



CODE EXAMPLE 6-9 Deleting a Product

EpcisConnection conn = new EpcisConnection(...)

// Create Product client

ProductRequest req = new ProductRequest(conn);

Product p2 = req.get("26");

if(p2 != null) {

req.delete(p2);

}else {

System.out.println("Product # 26 not found!");

}


Using the Update/Delete/Query Request Object

A request class represents an update, delete or query request to the Information Server. All request classes extend the abstract com.sun.autoid.epcis.client.Request class. Instances of a request class are converted to an XML format so that they can be sent over the wire.


TABLE 6-3 Request Classes and Code Examples

Class

Description

Code Examples

UpdateRequest

Provides methods to update the RFID Information Server database tables. Instances of this class process insert and modify operations on Unit, Product, Organization, Container, Sensor and ContainerType transfer objects.

CODE EXAMPLE 6-10

CODE EXAMPLE 6-11

CODE EXAMPLE 6-12

CODE EXAMPLE 6-13

DeleteRequest

Provides methods to delete entries from the RFID Information Server tables. For most tables, the class uses a PrimaryKey object to identify the entry to delete.

CODE EXAMPLE 6-14

CODE EXAMPLE 6-15

CODE EXAMPLE 6-16



CODE EXAMPLE 6-10 Inserting a Unit

EpcisConnection conn = new EpcisConnection(...)

UpdateRequest updateReq = new UpdateRequest(conn);

 

Unit unit = new Unit();

unit.setEpc("urn:epc:id:gid:2.1.1");

unit.setExpiryDate(Calendar.getInstance());

unit.setProductId("1");

unit.setUnitType("ITEM");

unit.setAttr1("192.168.1.2"); // persists the non-EPC data

UpdateResponse updateResp = updateReq.add(unit);

 



CODE EXAMPLE 6-11 Inserting a Transaction

ArrayList epcs = new ArrayList();

epcs.add("urn:epc:id:gid:1.402.1");

epcs.add("urn:epc:id:gid:1.301.2");

Transaction trans = new Transaction("PO-909", Calendar.getInstance(),null, epcs);

updateResp = updateReq.createTransaction(trans);

 



CODE EXAMPLE 6-12 Inserting Observations Using the PML Method

DeltaEvent deltaEvent = ...

Sensor sensor = EventUtil.toSensor(deltaEvent);

UpdateResponse updateResp = updateReq.postPML(sensor);

 


CODE EXAMPLE 6-13 Insert Observations Using the ValueObject Method

Observation obs = new Observation(new ObservationLogVO());

obs.setSensorEpc("urn:epc:id:gid:1.1.1");

obs.setObservationType("NewExternal");

obs.setObservationValue("urn:epc:id:sgtin:0084691.142752.405");

obs.setTimestamp(Calendar.getInstance());

obs.setAttr1("Some test junk");

 

ArrayList voList = new ArrayList();

voList.add(obs);

UpdateRequest updateReq = new UpdateRequest(conn);

UpdateResponse updateResp = updateReq.add(voList);

 


CODE EXAMPLE 6-14 Deleting a Container

DeleteRequest deleteReq = new DeleteRequest(conn);

PrimaryKey pk =

new PrimaryKey("urn:epc:id:gid:1.402.1", "CONTAINMENT");

ArrayList pkList =new ArrayList();

pkList.add(pk);

DeleteResponse deleteResp =

deleteReq.deleteByPk(pkList);

 

  

Note - Containers can be deleted by specifying the parent EPC of the container. The method only deletes the contents of the top most container. If the children of the parent EPC are containers then their contents are not deleted.




CODE EXAMPLE 6-15 Delete a Unit

PrimaryKey pk = new PrimaryKey("urn:epc:id:gid:1.103.1", "UNIT");

ArrayList pkList =new ArrayList();

pkList.add(pk);

DeleteResponse deleteResp = deleteReq.deleteByPk(pkList);



CODE EXAMPLE 6-16 Delete a Transaction

ArrayList txIdList = new ArrayList();

txIdList.add("PO-909");

DeleteResponse deleteResp = deleteReq.deleteTxById(txIdList);




Note - The TX_LOG table does not have a primary key. The transaction to delete is identified by the TX_ID value.




Querying RFID Information Server Database Tables

Query conditions are expressed as simple attribute comparisons. The valid comparators are eq, lt, and gt. These comparators can be used when comparing the values of fixed attributes. When comparing the value of an extended attribute, the only valid operator is eq. If more than one condition is specified, append each comparator by using the AND operator. If no conditions are specified, then the query returns all the entries in the selected table.

The following table lists the query classes and code examples.


TABLE 6-4 Query Request Classes and Code Examples

Class

Description

Code Example

FindByAttrRequest

Handles queries on a specified table in the RFID Information Server

CODE EXAMPLE 6-17

CODE EXAMPLE 6-18

CODE EXAMPLE 6-19

ContainmentRequest

Handles queries on the CONTAINMENT table. A containment query condition can express a parent or child relationship. It can also specify if the search should recursively return all the EPCs in the hierarchy or only the immediate EPCs.

CODE EXAMPLE 6-20

CODE EXAMPLE 6-21



CODE EXAMPLE 6-17 All Transactions in the TX_LOG Table

FindByAttrRequest findReq =

new FindByAttrRequest(conn, "TX_LOG");

FindByAttrResponse findResp = findReq.process();

 



CODE EXAMPLE 6-18 Query for a specific EPC from the OBSERVATION Table

FindByAttrRequest findReq =
new FindByAttrRequest(conn, "OBSERVATION_LOG");
findReq.addCondition
("OBSERVATION_VALUE", "urn:epc:id:gid:1.402.1", "eq");
findResp = findReq.process();
 


CODE EXAMPLE 6-19 Conditional Query From the UNIT Table

FindByAttrRequest findReq =

new FindByAttrRequest(conn, "UNIT");

findReq.addCondition

("EXPIRY_DATE", Calendar.getInstance(), "gt");

findReq.addCondition("PRODUCT_ID", new Integer(1), "eq");

findResp = findReq.process();

 


CODE EXAMPLE 6-20 Querying for the Parent of an EPC Recursively
ContainmentResponse contReq = new ContainmentRequest(conn);
ContainmentResponse contResp = contReq.process("urn:epc:id:gid:1.103.1", ContainmentRequest.PARENT_OF,
true);


CODE EXAMPLE 6-21 Querying for the Immediate Child EPCs of a Given EPC
ContainmentResponse contResp = contReq.process("urn:epc:id:gid:1.402.1", ContainmentRequest.CHILD_OF,
false);


Processing RFID Information Server Responses

A response message from the Information Server is marshalled into a response object. All response classes extend com.sun.autoid.epcis.client.Response. The following table lists the response classes with examples.


TABLE 6-5 Response Classes and Code Examples

Class

Description

Code Example

UpdateResponse

Represents the status of the update request. Failure status is captured as a string. The status reported by a JDBC driver is returned verbatim

CODE EXAMPLE 6-22

DeleteResponse

Represents the status of a delete request. Failure status is captured as a string.

CODE EXAMPLE 6-23

FindByAttrResponse

Collects all the transfer objects that are returned as a result of a FindByAttrRequest. The transfer objects are generally returned as ArrayLists. The ArrayList may contain zero or more elements.

CODE EXAMPLE 6-24

CODE EXAMPLE 6-25

ContainmentResponse

This class can return the result as an ArrayList of EPCs or as a Container object. The former is useful if quick traversal of the result set is needed while the latter preserves the hierarchical relationships between the EPCs.

CODE EXAMPLE 6-26 CODE EXAMPLE 6-27



CODE EXAMPLE 6-22 Testing the Success of an Update Request
UpdateResponse updateResp = updateReq.modify(unit);
System.out.println("ModifyUnit. Success -> " + updateResp.success() + ". Should be true");


CODE EXAMPLE 6-23 Testing the Success of a Delete Request
DeleteResponse deleteResp = deleteReq.deleteByPk(pkList);
System.out.println("Success -> " +  deleteResp.success());


CODE EXAMPLE 6-24 Printing the Number of Transaction Objects Returned
FindByAttrResponse findResp = findReq.process();
System.out.println("Results -> Got " + findResp.getTransactions().size() );


CODE EXAMPLE 6-25 Printing the Attribute Value of the Returned UNIT Object

FindByAttrRequest  findReq = new FindByAttrRequest(conn, "UNIT");
findReq.addCondition("EPC", "urn:epc:id:gid:1.103.1", "eq");
findResp = findReq.process();
System.out.println("Results -> Got " + findResp.getUnits().size() );
if (findResp.getUnits().size() > 0)
{
    Unit unit = (Unit)findResp.getUnits().get(0);
    System.out.println("Got unit with manufacture date : " + unit.getManufactureDate());
}


CODE EXAMPLE 6-26 Using getResultSet()
ContainmentResponse contResp = contReq.process("urn:epc:id:gid:1.103.1",                                                            ContainmentRequest.PARENT_OF,                                                            true);
System.out.println("Results -> Got " + contResp.getResultSet().size() );


CODE EXAMPLE 6-27 Using getRoot()
ContainmentResponse contResp = contReq.process("urn:epc:id:gid:1.103.1",                                                            ContainmentRequest.PARENT_OF,                                                            true);
System.out.println("Results -> Got " + contResp.getRoot().getEpc() );


Handling Exceptions

Use the classes of the package, com.sun.autoid.epcis.EPCISException. EPCISException inherits and extends the Java Standard Edition standard Exception class.

EPCISException is defined as shown in the following code example:


CODE EXAMPLE 6-28 Define EPCISException

public class EPCISException extends Exception {

...

public EPCISException(String message) {

super (message);

}

}

 


How to Catch an EPCISException Error

A program can catch the EPCISException error by using a combination of the try, catch, and finally blocks as shown in the following code example:


CODE EXAMPLE 6-29 Catch EPCISException
public class MyQuery {
 
    public static void main(String[] args) {
        EpcisConnection conn = null;
        String epcisUrl = null;
        String httpProxyHost = null;
        String httpProxyPort = null;
        String epcisUsername = null;
        String epcisPassword = null;
 
        // get the properties for EpcisConnection
        ...
        try {
             conn = new EpcisConnection(
                     epcisUrl,
                     httpProxyHost,
                     httpProxyPort,
                     epcisUserName,
                     epcisPassword);
             // querying EPCIS
           ...
         } catch (EPCISException e) {
         }
         finally {
             ...
         }
         ...
     }
}

How to Throw an EPCISException Error

A program can use EPCISException to indicate an error occurred. To throw an EPCISException, you use the throw statement and provide an exception message as shown in the following code example:


CODE EXAMPLE 6-30 Throw Internal Exception
public class FindByAttrRequest extends Request {
    ....
 
    /**
     * Process the query and get a response synchronously.
     * Called after the conditions have been set. This results in
     * a request to the EPCIS 
     * @return The response object.
     */
   public FindByAttrResponse process() throws EPCISException{
       FindByAttrResponse findByAttrResp = null;
       EpcisMsgXML response = conn.synchAction (request);
       findByAttrResp = new FindByAttrResponse (response);
       reset();
       return findByAttrResp;
   }
   ....
}


1 (TableFootnote) If the initial-context-factory is not specified, the default is com.sun.jndi.fscontext.RefFSContextFactory.
2 (TableFootnote) Included in package com.sun.autoid.epcis.client
3 (TableFootnote) Included in package com.sun.autoid.epcis.client