| Oracle® Retail POS Suite Implementation Guide, Volume 2 – Extension Solutions Release 14.1 E54476-02 | 
 | 
|  Previous |  Next | 
This chapter describes how to extend the Intra Store Data Distribution.
Extensibility is supported through the interface-based design and the use of the Spring Framework. From an extensibility stand point, an alternate implementation of any of the exposed interfaces could inherit from one of the out-of-the-box implementation classes and be injected into the system through Spring.
Additionally, the schema has been designed to enable the addition of datasets and dataset tables.
Adding a new dataset table to the data model is as simple as adding a new row to the table CO_DT_ST_TB_IDDI and creating table script in CreateSchema.sql.
The following example walks through the process of adding more tables to the existing DataSet in IDDI.
Insert the tables to be associated with the existing DataSet by adding records to CO_DT_ST_TB_IDDI using SQL.
Run the following queries to insert the table association to DataSet.
Example 16-1 Adding Table Association To Employee DataSet
insert into CO_DT_ST_TB_IDDI (ID_DT_ST, ID_STR_RT, NM_TB, NM_FL,AI_LD_SEQ) values (<<Employee DataSet ID>>, <<'Store ID'>>,<<'Table1'>>,<<'Table1.txt'>>,1 ); TableName: CO_DT_ST_TB_IDDI Column Description ID_DT_ST : DataSet ID ID_STR_RT: Store ID NM_TB : Table Name NM_FL : File Name of the Flat file to be generated AI_LD_SEQ: Table Order in which the data to be exported and imported eg: Get the Employee DataSet ID from CO_DT_ST_IDDI table insert into CO_DT_ST_TB_IDDI (ID_DT_ST, ID_STR_RT, NM_TB, NM_FL,AI_LD_SEQ) values (1,'04241','TABLE1','TABLE1.TXT',1 ); insert into CO_DT_ST_TB_IDDI (ID_DT_ST, ID_STR_RT, NM_TB, NM_FL,AI_LD_SEQ) values (1,'04241','TABLE2','TABLE2.TXT',2 );
Add CREATE TABLE scripts in CreateSchema.sql.
CREATE TABLE "offlinedb"."TABLE1"
    (   "COLUMN1” <<TYPE>> <<Constraint>>,
        "COLUMN2, <<TYPE>> <<Constraint>>)
CREATE TABLE "offlinedb"."TABLE2"
    (   "COLUMN1” <<TYPE>> <<Constraint>>,
        "COLUMN2, <<TYPE>> <<Constraint>>)
Do the following to add a table using the build script:
Open <source_directory>\modules\utility\build.xml.
Find the target dataset's offline table list:
ordered.<data set name>.tables
Add the name of the SQL file that contains the create script.
The create scripts are located at <source_directory>\modules\common\deploy\server\common\db\sql\Create.
Do the following to add new DataSet:
Add DataSet information in CO_DT_ST_IDDI.
Add DataSet tables to CO_DT_ST_TB_IDDI.
Create <DataSetKey>Producer and <DataSetKey>Consumer classes extending from AbstractDataSetProducer and AbstractDataSetConsumer respectively.
Define service_config_<<DataSetKey>> in ServiceContext.xml
Define service_<<DataSetKey>>Producer with class=<DataSetKey>Producer and service_<<DataSetKey>>Consumer wit h class=<DataSetKey>Consumer in ServiceContext.xml
Add to service_<<DataSetKey>>Producer and service_<<DataSetKey>>Consumer to service_DataSetService and service_ClientDataSetService respectively in ServiceContext.xml
Add DataSet key to service_FrequentProducerJob/service_InfrequentProducerJob and service_FrequentConsumerJob/service_InfrequentConsumerJob in ServiceContext.xml
Add create table scripts and insert script for newly added DataSet in CreateSchema.sql.
Do the following to add a new dataset using the build script:
Open <source_directory>\modules\utility\build.xml .
Find the section that defines the offline table lists (target assemble.iddi).
Create the ordered list of tables, following the pattern established in the file. All create scripts are located at <source_directory>\modules\common\deploy\server\common\db\sql\Create.
Add a call to concat.file for the new data set schema, following the other calls in the file:
        <antcall target="concat.file">
            <param name="target.file" value="${raw.sql.file}"/>  -- The path and name of the file being generated
            <param name="file.comment" value="-- Employee DataSet Tables"/> -- Comment added to the file ahead of the create SQL
            <param name="src.dir" value="${sql.src.dir}"/> -- Path to the create scripts listed in the "ordered.<data set name>.tables" list
            <param name="file.list" value="${ordered.employee.tables}"/> -- Variable holding the ordered list of create scripts
            <reference refid="comment.filter" torefid="filter"/>
        </antcall>
Any existing DataSet Producer and Consumer can be individually configured to run on scheduled basis.
Do the following to configure DataSet Producer:
Add JobDetailBean bean configuration service_<<DataSet>>ProducerJob.
    <bean id="service_<<DataSet>>ProducerJob" class="org.springframework.scheduling.quartz.JobDetailBean">
        <property name="jobClass">
            <value>oracle.retail.stores.foundation.iddi.DataSetProducerJob</value>
        </property>
        <property name="jobDataAsMap">
            <map>
                <entry key="producer" value-ref="service_DataSetService"/>
                <entry key="dataSets">
                    <list>
                        <ref local="service_config_<<DataSetKey>>"/>
                    </list>
                </entry>
            </map>
        </property>
    </bean>
| Note:service_config_<<DataSetKey>> should have been configured with the DataSetKey | 
Add CronTriggerBean bean configuration service_Trigger<<DataSet>>Producer
    <bean id="service_Trigger<<DataSet>>Producer" class = "org.springframework.scheduling.quartz.CronTriggerBean">
        <property name = "jobDetail">
            <ref local="service_<<DataSet>>ProducerJob"/>
        </property>
        <property name="cronExpression" value="0 0,15,30,45 0 * * ?"/>
    </bean>
The above DataSet is configured to run once every 15 minutes.
For more information about the Quartz scheduler, see the documentation at http://www.quartz-scheduler.org/documentation.
Add service_Trigger<<DataSet>>Producer to the SchedulerFactoryBean bean configuration:
    <bean id="service_ProducerSchedulerFactory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="triggers">
            <list>
                <ref local="service_TriggerFrequentProducer"/>
                <ref local="service_TriggerInfrequentProducer"/>
                <ref local="service_Trigger<<DataSet>>Producer"/>
            </list>
        </property>
    </bean>
Do the following to configure DataSet Consumer:
Add JobDetailBean bean configuration service_<<DataSet>>ConsumerJob:
    <bean id="service_<<DataSet>>ConsumerJob" class="org.springframework.scheduling.quartz.JobDetailBean">
        <property name="jobClass">
            <value>oracle.retail.stores.foundation.iddi.ClientDataSetController</value>
        </property>
        <property name="jobDataAsMap">
            <map>
               <entry key="dataSets">
                    <list>
                        <ref local="service_config_<< DataSetKey>>"/>
                    </list>
                </entry>
            </map>
        </property>
    </bean>
| Note: service_config_<<DataSetKey>>should have been configured with the DataSetKey. | 
Add CronTriggerBean bean configuration service_Trigger<<DataSet>>Consumer:
    <bean id="service_Trigger<<DataSet>>Consumer" class = "org.springframework.scheduling.quartz.CronTriggerBean">
        <property name = "jobDetail">
            <ref local="service_<<DataSet>>ConsumerJob"/>
        </property>
        <property name="cronExpression" value="0 0,15,30,45 0 * * ?"/>
    </bean>
The DataSet is configured to run once every 15 minutes.
Add service_Trigger<<DataSet>>Consumer to the SchedulerFactoryBean bean configuration:
    <bean id=" service_clientSchedulerFactory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="triggers">
            <list>
                <ref local="service_TriggerFrequentConsumer"></ref>
                <ref local="service_TriggerInfrequentConsumer"></ref>
                <ref local="service_Trigger<<DataSet>>Consumer"/>
            </list>
        </property>
    </bean>
The following example walks through the process of adding a new DataSet to the existing IDDI.
Insert the new DataSet information in into the databaset table CO_DT_ST_IDDI using SQL:
Insert the tables associated with the DataSet added to CO_DT_ST_TB_IDDI using SQL.
Run the following queries to insert new DataSet information and table association to DataSet.
Example 16-2 Adding New DataSet
insert into CO_DT_ST_IDDI (ID_DT_ST, ID_STR_RT, NM_DT_ST) values (maxid+1,<<'StoreID'>> ,<<'DataSetName'>>); TableName: CO_DT_ST_IDDI Column Description ID_DT_ST : DataSet ID ID_STR_RT: Store ID NM_DT_ST : DataSet Name eg: insert into CO_DT_ST_IDDI (ID_DT_ST, ID_STR_RT, NM_DT_ST) values (6,'04241','NEW');
Example 16-3 Adding Table association to New DataSet
insert into CO_DT_ST_TB_IDDI (ID_DT_ST, ID_STR_RT, NM_TB, NM_FL,AI_LD_SEQ) values (<<New DataSet ID>>, <<'Store ID'>>,<<'Table1'>>,<<'Table1.txt'>>,1 ); eg: insert into CO_DT_ST_TB_IDDI (ID_DT_ST, ID_STR_RT, NM_TB, NM_FL,AI_LD_SEQ) values (6,'04241','TABLE1','TABLE1.TXT',1 ); insert into CO_DT_ST_TB_IDDI (ID_DT_ST, ID_STR_RT, NM_TB, NM_FL,AI_LD_SEQ) values (6,'04241','TABLE2','TABLE2.TXT',2 );
Create <DataSetKey>Producer and <DataSetKey>Consumer classes extending from AbstractDataSetProducer and AbstractDataSetConsumer respectively.
Example 16-4 DataSetProducer Code
package oracle.retail.stores.domain.iddi;
 
import oracle.retail.stores.foundation.iddi.AbstractDataSetProducer;
import oracle.retail.stores.foundation.iddi.DataSetMetaData;
import oracle.retail.stores.foundation.iddi.TableQueryInfo;
import oracle.retail.stores.foundation.iddi.ifc.DataSetMetaDataIfc;
 
public class NewDataSetProducer extends AbstractDataSetProducer 
{
 
        private final String[] TABLE_FIELDS={"*"};
        
/**
        
         * NewDataSetProducer constructor
         */
 
        public NewDataSetProducer ()
        {
                
        }
        /**
        * Get DataSetMetatIfc reference 
        * 
        */
        public DataSetMetaDataIfc getDataSetMetaData() 
        {
                // Get the table names for the Key
                return dataSetMetaData;
        }
        /**
        * Initialize the MetaData for the DataSetProducer 
        */
        public void initializeDataSet() 
        {
                dataSetMetaData = new DataSetMetaData(dataSetKey);
        }
        /**
        * Create TableQueryInfo object with the column names to fetch 
        * @param TableName
        * @return TableQueryInfo Object
        */
        public TableQueryInfo getTableQueryInfo(String tableName) 
        {
                TableQueryInfo tableQueryInfo = new TableQueryInfo(tableName);
                tableQueryInfo.setTableFields(TABLE_FIELDS);
                return tableQueryInfo;
        }
        /**
         * Finalize DataSet Method
         * 
         */
        public void finalizeDataSet()
        {
                
        }
}
Example 16-5 DataSetConsumer Code
package oracle.retail.stores.domain.iddi;
 
import oracle.retail.stores.foundation.iddi.AbstractDataSetConsumer;
 
//--------------------------------------------------------------------------
/**
    The NewDataSetConsumer defines methods that the
    application calls to import Employee dataset files into
    offline database.
     @version $Revision: $
**/
//--------------------------------------------------------------------------
 
public class NewDataSetConsumer extends AbstractDataSetConsumer
{         /**  DataSet key name for currency dataset.
 
    */    private String dataSetKey = null;
 
    //  --------------------------------------------------------------------------    
    /**
        @return Returns the dataSetKey
    **/
    //--------------------------------------------------------------------------
 
    public String getDataSetKey()
    {
       
        return dataSetKey;            
    }   
 
    //  --------------------------------------------------------------------------
    /**
      @param dataSetKey The DataSetKey to set
    **/
    //--------------------------------------------------------------------------
 
    public void setDataSetKey(String dataSetKey)
    {               
 
        this.dataSetKey = dataSetKey;  
        
  }
}
Define service_config_<<DataSetKey>> in ServiceContext.xml:
    <bean id="service_config_<<datasetKey>> " class="java.lang.String">
        <constructor-arg type="java.lang.String" value="<<DataSetKey>>"/>
    </bean>eg:    <bean id="service_config_NEW_KEY" class="java.lang.String">
        <constructor-arg type="java.lang.String" value="NEW"/>
    </bean>
Define service_<<DataSetKey>>Producer with class=<DataSetKey>Producer and service_<<DataSetKey>>Consumer with class=<DataSetKey>Consumer in ServiceContext.xml:
<bean id="service_NewProducer" class="oracle.retail.stores.domain.iddi.NewDataSetProducer" lazy-init="true" singleton=”true”>
        <property name="dataSetKey" ref="service_config_NEW_KEY"/>
        <property name="dataExportFilePath" ref="service_config_DataExportFilePath"/>
        <property name="dataExportZipFilePath" ref="service_config_DataExportZipFilePath"/>
    </bean>
    <bean id="service_NewConsumer"
 class="oracle.retail.stores.domain.iddi.NewDataSetConsumer"
             lazy-init="true"
             singleton="true">
        <property name="dataSetKey" ref="service_config_NEW_KEY"/>
        <property name="dataImportFilePath" ref="service_config_DataImportFilePath"/>
    </bean>
Add to service_<<DataSetKey>>Producer and service_<<DataSetKey>>Consumer to service_DataSetService and service_ClientDataSetService respectively in ServiceContext.xml
   <bean id="service_DataSetService" class="oracle.retail.stores.foundation.iddi.DataSetService" singleton="true">
        <property name="producers">
            <map>
                <entry key-ref="service_config_EMP_KEY" value-ref="service_EmployeeProducer"/>
                <entry key-ref="service_config_ITM_KEY" value-ref="service_ItemProducer"/>
                <entry key-ref="service_config_PRC_KEY" value-ref="service_AdvancedPricingProducer"/>
                <entry key-ref="service_config_TAX_KEY" value-ref="service_TaxProducer"/>
                <entry key-ref="service_config_CUR_KEY" value-ref="service_CurrencyProducer"/>
                <entry key-ref="service_config_NEW_KEY" value-ref="service_NewProducer"/>
            </map>
        </property>
    </bean>
    <bean id="service_ClientDataSetService"
     class="oracle.retail.stores.foundation.iddi.ClientDataSetService" singleton="true">
        <property name="consumers">
            <map>
                <entry key-ref="service_config_EMP_KEY" value-ref="service_EmployeeConsumer"/>
                <entry key-ref="service_config_CUR_KEY" value-ref="service_CurrencyConsumer"/>
                <entry key-ref="service_config_TAX_KEY" value-ref="service_TaxConsumer"/>
                <entry key-ref="service_config_ITM_KEY" value-ref="service_ItemConsumer"/>
                <entry key-ref="service_config_PRC_KEY" value-ref="service_AdvancedPricingConsumer"/>
                <entry key-ref="service_config_NEW_KEY" value-ref="service_NewConsumer"/>
            </map>
        </property>
        <property name="dataImportFilePath" ref="service_config_DataImportFilePath"/>
    </bean>
Add DataSet key to service_FrequentProducerJob/service_InfrequentProducerJob and service_FrequentConsumerJob/service_InfrequentConsumerJob in ServiceContext.xml
    <bean id="service_FrequentProducerJob" class="org.springframework.scheduling.quartz.JobDetailBean">
        <property name="jobClass">
            <value>oracle.retail.stores.foundation.iddi.DataSetProducerJob</value>
        </property>
        <property name="jobDataAsMap">
            <map>
                <entry key="producer" value-ref="service_DataSetService"/>
                <entry key="dataSets">
                    <list>
                        <ref local="service_config_EMP_KEY"/>
                        <ref local="service_config_PRC_KEY"/>
                        <ref local="service_config_TAX_KEY"/>
                        <ref local="service_config_NEW_KEY"/>
                    </list>
                </entry>
            </map>
        </property>
    </bean>
<bean id="service_FrequentConsumerJob" class="org.springframework.scheduling.quartz.JobDetailBean">
        <property name="jobClass">
            <value>oracle.retail.stores.foundation.iddi.ClientDataSetController</value>
        </property>
        <property name="jobDataAsMap">
            <map>
               <entry key="dataSets">
                    <list>
                        <ref local="service_config_EMP_KEY"/>
                        <ref local="service_config_PRC_KEY"/>
                        <ref local="service_config_TAX_KEY"/>
                        <ref local="service_config_NEW_KEY"/>
                    </list>
                </entry>
            </map>
        </property>
    </bean>
Add CREATE TABLE scripts and insert scripts to newly added DataSet in CreateSchema.sql.
CREATE TABLE "offlinedb"."TABLE1"
    (   "COLUMN1” <<TYPE>> <<Constraint>>,
        "COLUMN2, <<TYPE>> <<Constraint>>)
CREATE TABLE "offlinedb"."TABLE2"
    (   "COLUMN1” <<TYPE>> <<Constraint>>,
        "COLUMN2, <<TYPE>> <<Constraint>>)
insert into CO_DT_ST_IDDI(ID_DT_ST, ID_STR_RT, NM_DT_ST) values(6,'04241','NEW');
Do the following to add a new dataset type using the build script:
Open <source_directory>\modules\utility\build.xml .
Find the section that defines the offline table lists (target assemble.iddi).
Create the ordered list of tables, following the pattern established in the file. All create scripts are located at <source_directory>\modules\common\deploy\server\common\db\sql\Create.
Add a call to concat.file for the new data set schema, following the other calls in the file:
        <antcall target="concat.file">
            <param name="target.file" value="${raw.sql.file}"/>  -- The path and name of the file being generated
            <param name="file.comment" value="-- Employee DataSet Tables"/> -- Comment added to the file ahead of the create SQL
            <param name="src.dir" value="${sql.src.dir}"/> -- Path to the create scripts listed in the "ordered.<data set name>.tables" list
            <param name="file.list" value="${ordered.employee.tables}"/> -- Variable holding the ordered list of create scripts
            <reference refid="comment.filter" torefid="filter"/>
        </antcall>
Currently the Oracle Retail Point-of-Service client uses Derby Database. However, the modifications to the code are minimal for replacing the Oracle Retail Point-of-Service client database from Derby to another database. Do the following to change the Oracle Retail Point-of-Service client database:
Add Offline<<DBName>>Helper class which implements offlineDBHelperIfc.
Change the installer to have new database driver jar file paths.
Update the "<POOL name="jdbcpool class="DataConnectionPool" package="oracle.retail.stores.foundation.manager.data">" section of PosLFFDataTechnician.xml file with the driver, databaseUrl, userid, password.