5.6 Network User Data

For user data defined through the xxx_SDO_NETWORK_USER_DATA views, the default user data I/O implementation (LODUserDataIOSDO) is used to access the user data during network analysis. However, some user data is not included in the node or link table, and thus cannot be registered through xxx_SDO_NETWORK_USER_DATA views.

For such user data, users must provide their own custom implementation of the user data I/O interface. A typical way of implementing a custom data I/O interface is to generate BLOBs corresponding to node and link user data, one BLOB for each partition, and then retrieve user data information from the BLOBs during network analysis.

Network Data Model also allows you to associate multiple categories of user-defined data (categorized user data) with a single network. For example, in a multimodal network, if you need to associate driving-related attributes (such as speed limit) with a link in addition to the link's multimodal attributes, user-defined data can be organized in two categories, one for driving-related attributes and the other for multimodal attributes.

See these examples of user-defined data:

5.6.1 User-Defined Data Example (PL/SQL and Java)

This section presents an example of using network user-defined data, which is the information (not related to connectivity) that users want to associate with a network representation. The USER_SDO_NETWORK_USER_DATA and ALL_SDO_ NETWORK_USER_DATA metadata views (described in xxx_SDO_NETWORK_USER_DATA Views) contain information about user-defined data.

To use user-defined data, you must set the USER_DEFINED_DATA column value to Y in the appropriate xxx_SDO_NETWORK_METADATA views (described in Section xxx_SDO_NETWORK_METADATA Views).

Example 5-1 inserts link-related user-defined data into the network metadata.

Example 5-1 Inserting User-Defined Data into Network Metadata

-- Insert link user data named 'interaction' of
-- type varchar2 (50) in network 'bi_test'.
--'interaction' is a column of type varchar2(50) in the link table of network 'bi_
test'.
insert into user_sdo_network_user_data (network, table_type, data_name, data_type, data_length, category_id) 
                  values ('bi_test', 'LINK', 'interaction', 'VARCHAR2', 50, 0) ;
-- insert link user data named 'PROB' of type Number.
--'PROB' is a column of type NUMBER in the link table of network 'bi_test'.
insert into user_sdo_network_user_data (network, table_type, data_name, data_type, category_id)
                  values ('bi_test','LINK','PROB','NUMBER', 0) ;
 
After a network or network partition is loaded, user-defined data is available in Java representations. You can access user-defined data through the getCategorizedUserData and setCategorizedUserData methods for the Node, Link, Path, and SubPath interfaces. For example:
 
//The user data index is the sequence number of a user data within a category sorted by data name.
 
int interactionUserDataIndex = 0;
int probUserDataIndex = 1;
 
String interaction = (String)link.getCategorizedUserData().getUserData(0).
                                get(interactionUseDataIndex);
 
double prob = ((Double)link.getCategorizedUserData().getUserData(0).
                       get(probUserdataIndex)).doubleValue();

5.6.2 User-Defined Data Example (Custom User Data I/O Implementation)

This section presents an example of a custom user data I/O implementation (nondefault implementation) of the LODUserDataIO interface. In Example 5-2, user data associated with links is written to BLOBs (one BLOB per partition) and read from BLOBs during analysis. It is assumed that the user-defined data BLOB for multimodal data for each partition has the partition ID and number of links associated with the partition, followed by <Link ID, link route ID> for each link.

Example 5-2 Implementation of writeUserData method of LODUserDataIO

//Method getLinksInPartition(partitionId) computes a vector that
// consists of  the ID and the route ID of each link associated with a partition
// with ID = partitionId
LinkVector = getLinksInPartition(partitionId);

ObjectOutputStream dout = null;

//Insert an empty blob for the partition with ID = partition_id
String insertStr = "INSERT INTO " + MULTIMODAL_USER_DATA +
                             " (partition_id, blob) " + " VALUES " + " (?, EMPTY_LOB())" ;

PreparedStatement stmt = conn.prepareStatement(insertStr);
stmt.setInt(1,partitionId);
int n = stmt.executeUpdate();
stmt.close();

//lock the row for blob update
 String lockRowStr = "SELECT blob FROM " + MULTIMODAL_USER_DATA +
                                  " WHERE partition_id = ? " + " FOR UPDATE";
 stmt = conn.prepareStatement(lockRowStr);
 stmt.setInt(1,partitionId);
 ResultSet rs = stmt.executeQuery();

 rs.next();
oracle.sql.BLOB userDataBlob = (oracle.sql.BLOB) rs.getBlob(1);
stmt.close();

 OutputStream blobOut = ((oracle.sql.BLOB) userDataBlob).setBinaryStream(1);
 dout = new ObjectOutputStream(blobOut);

 //write partition ID
 dout.writeInt(partitionId);
 int numLinks = linkVector.size()

  for (int i=0; i<linkVector.size(); i++) {
        //MultimodalLink is a class with variables link ID and route ID
        MultimodalLink link = (MultimodalLink) linkVector.elementAt(i);
         //write link ID 
        dout.writeLong(link.getLinkId());

        // write route ID into file
        dout.writeInt(link.getRouteId());
   }
   dout.close();
    blobOut.close();
    rs.close();

The subsections that follow describe the implementations of the writeUserData and readUserData methods of the LODUserDataIO interface.

5.6.2.1 Implementation of writeUserData method of LODUserDataIO

In the implementation of the writeUserData method of LODUserDataIO, the user-defined data BLOB table name is assumed to be MULTIMODAL_USER_DATA.

//Method getLinksInPartition(partitionId) computes a vector that
// consists of  the ID and the route ID of each link associated with a partition
// with ID = partitionId
LinkVector = getLinksInPartition(partitionId);

ObjectOutputStream dout = null;

//Insert an empty blob for the partition with ID = partition_id
String insertStr = "INSERT INTO " + MULTIMODAL_USER_DATA +
                      " (partition_id, blob) " + " VALUES " + " (?, EMPTY_BLOB())" ;

PreparedStatement stmt = conn.prepareStatement(insertStr);
stmt.setInt(1,partitionId);
int n = stmt.executeUpdate();
stmt.close();

//lock the row for blob update
 String lockRowStr = "SELECT blob FROM " + MULTIMODAL_USER_DATA +
                                  " WHERE partition_id = ? " + " FOR UPDATE";
 stmt = conn.prepareStatement(lockRowStr);
 stmt.setInt(1,partitionId);
 ResultSet rs = stmt.executeQuery();

 rs.next();
oracle.sql.BLOB userDataBlob = (oracle.sql.BLOB) rs.getBlob(1);
stmt.close();

 OutputStream blobOut = ((oracle.sql.BLOB) userDataBlob).setBinaryStream(1);
 dout = new ObjectOutputStream(blobOut);

 //write partition ID
 dout.writeInt(partitionId);
 int numLinks = linkVector.size()

  for (int i=0; i<linkVector.size(); i++) {
        //MultimodalLink is a class with variables link ID and route ID
        MultimodalLink link = (MultimodalLink) linkVector.elementAt(i);
         //write link ID 
        dout.writeLong(link.getLinkId());

        // write route ID into file
        dout.writeInt(link.getRouteId());
   }
   dout.close();
    blobOut.close();
    rs.close();

5.6.2.2 Implementation of readUserData method of LODUserDataIO

The user-defined data is accessed through the getCategorizedUserData and setCategorizedUserData methods for the Node, Link, Path, and SubPath interfaces and getUserData and setUserData methods of the CategorizedUserData interface.

//Read the blob for the required partition from the user data blob table
// In this example,
// MULTIMODAL_USER_DATA  is the name of user –defined data blob table
BLOB multimodalBlob = null;
String queryStr = "SELECT blob FROM " + MULTIMODAL_USER_DATA                                
                             " WHERE partition_id = ?";
PreparedStatement stmt = conn.prepareStatement(queryStr);
stmt.setInt(1,partitionId);
ResultSet rs = stmt.executeQuery();
if (rs.next())   {
     multimodalBlob = (oracle.sql.BLOB)rs.getBlob(1);
}
 
// Materialize the blob value as an input stream        
InputStream is = multimodalBlob.getBinaryStream();
 
//Create an ObjectInputStream that reads from the InputStream is
ObjectInputStream ois = new ObjectInputStream(is);
 
//Read the values of partition ID and number of links from the blob
int partitionId = ois.readInt();
int numLinks = ois.readInt();
 
for (int i=0; i<numLinks; i++)  {
 
    //Read link ID and route ID for each link
     long linkId = ois.readLong();
     int routeId = ois.readInt();
 
     //MultimodalLinkUserData is an implementation of NDM LOD UserData interface
     //Implementation is provided at the end of the example 
     linkUserData = new MultimodalLinkUserData(routeId);
 
     //Get the link object corresponding to the link ID
     LogicalNetLink link = partition.getLink(linkId);
 
     //Get the (categorized) user data associated with the link. 
     CategorizedUserData cud = link.getCategorizedUserData();
    
     // If the link does not have categorized user data associated with it,
     // initialize it to linkUserData
     // Else, set the user data for category USER_DATA_MULTIMODAL 
     // to linkUserData 
     if (cud == null) {
            UserData [] userDataArray = {linkUserData};
            cud = new CategorizedUserDataImpl(userDataArray);
             link.setCategorizedUserData(cud);
     }
     else {                   
            cud.setUserData(USER_DATA_MULTIMODAL,linkUserData);
     }
}

The following segment shows how to read the user-defined data, specifically the route ID associated with a link during analysis.

//info is an instance of LODAnalysisInfo 
LogicalLink currentLink = info.getCurrentLink();
 
//Read the user-defined data (in this case, route ID) 
int linkRouteId   = (Integer)currentLink.getCategorizedUserData().
                           getUserData(USER_DATA_MULTIMODAL).                                      
                           get(INDEX_LINK_ROUTEID);
        
 
Implementation of MultimodalLinkUserData :
 
class MultimodalLinkUserData implements UserData
{
    private int routeId;
 
    protected MultimodalLinkUserData(int routeId)
   {
        this.routeId = routeId;
   }
 
  public Object get(int index)
  {
    switch(index)
    {
         case INDEX_LINK_ROUTEID:
              return routeId;
    }
    return null;
  }
 
  public void set(int index, Object userData)
  {
    switch(index)
    {
         case INDEX_LINK_ROUTEID:
            this.routeId = (Integer) userData;
    }
  }
 
  public int getNumberOfUserData()
  {
       return 1;
  }
 
  public Object clone()
{
    return new MultimodalLinkUserData(routeId);
  }
}