// Copyright (c) 2001, 2003, Oracle Corporation.  All rights reserved.  
// File: PMMLDemo.java

/**
 * This sample program describes how to use the ODM Java API for importing of
 * a PMML model to Data Mining Server(DMS) and exporting of a PMML model from 
 * the DMS. 
 * This program to illustrate the import-export it builds a NaiveBayes model
 * using "MINING_DATA_BUILD_V" dataset. After building model it exports the 
 * model to "PMML_DEMO" table in the user schema. After exporting the model
 * it imports the exported model.
 * 
 * NOTE:
 *   Before executing this program you need to provide DB URL, username 
 *   and password in login method and a valid data schema name
 *   by changing the DATA_SCHEMA_NAME constant value in the program.
 */

// Generic Java Imports
import java.io.*;
import java.util.*;
import java.sql.*;
//Oracle JDBC import
import oracle.jdbc.*;
// ODM Imports
import oracle.dmt.odm.*;
import oracle.dmt.odm.data.*;
import oracle.dmt.odm.settings.function.*;
import oracle.dmt.odm.settings.algorithm.*;
import oracle.dmt.odm.task.*;
import oracle.dmt.odm.model.*;
import oracle.dmt.odm.result.*;

public class PMMLDemo extends Object {

  private static DataMiningServer m_dms = null;
  private static oracle.dmt.odm.Connection m_dmsConn = null;
  //provide schema name that has the data tables/views
  private static final String DATA_SCHEMA_NAME = "schema name";
  
  public static void main( String args[] ) { 
    try {      
      //1. Login to the Data Mining Server
          //Create a DMS object
          m_dms = new DataMiningServer(
            "put DB URL here", //JDBC URL jdbc:oracle:thin:@<Host name>:<Port>:<SID>
            "user name", //User Name
            "password" //Password 
          );
          //Login to the DMS and create a DMS Connection
          m_dmsConn = m_dms.login();
          //Remove the objects to avoid name conflicts
          cleanup();
      //2. Build a model
      buildModel();
      //3. Export the built model
      LocationCellAccessData pmmlDocLocation = exportModel();
      //4. Import the exported model
      importModel(pmmlDocLocation);
    } catch(Exception anyExp) {
      anyExp.printStackTrace(System.out);
    } finally {
      try {
        //6. Logout from the Data Mining Server
        m_dms.logout(m_dmsConn);
      } catch(Exception anyExp1) { }//Ignore
    }
  }

 /**
   * This method exports the mining model in native format to PMML format. It 
   * stores the PMML model as a record of an XMLType column in a
   * database table.
   * In this example, we will export "PMMLDemo_Model" and store the exported
   * model into a "PMML_DEMO" table. "PMML_DEMO" table will be created by the
   * demo program in the user schema. 
   */
  public static LocationCellAccessData exportModel() 
  throws ODMException, SQLException, IOException 
  {
    //1. Set up the table to export PMML document
      //Create a PMML_DEMO table with XML_DOC column
        String createTable = "CREATE TABLE " + DATA_SCHEMA_NAME + 
          ".PMML_DEMO ( XML_DOC SYS.XMLTYPE )";
        Statement stmt = m_dmsConn.getDBConnection().createStatement();
        stmt.execute(createTable);
      //Insert a null row and get the rowid
        String insertNullRow = "INSERT INTO " + DATA_SCHEMA_NAME + 
          ".PMML_DEMO VALUES(NULL)";
        stmt.executeUpdate(insertNullRow);
        m_dmsConn.getDBConnection().commit();
      //Select the rowId
        String selectRowId = "SELECT ROWID FROM " + DATA_SCHEMA_NAME +
          ".PMML_DEMO";    
        oracle.sql.ROWID rowID = null;
        OracleResultSet ors = (OracleResultSet) stmt.executeQuery(selectRowId);
        ors.next();
        rowID = ors.getROWID(1);
        ors.close();
        stmt.close(); 
    //2. Specify the XMLType column cell location using LocationCellAccessData
      LocationCellAccessData outputDataLocation = new LocationCellAccessData(
        "PMML_DEMO",
        DATA_SCHEMA_NAME,
        "XML_DOC",
        rowID);
    //3. Create model export task
      ModelExportTask exportTask = new ModelExportTask(
        "PMMLDemo_Model",
        outputDataLocation,
        MiningStandardType.PMML20);
    //4.Store & execute the task
      executeTask(exportTask, "PMMLDemo_ExportTask"); 
      return outputDataLocation;
  }  

  /**
   * This method stores the given task with the specified name in the DMS 
   * and submits the task for asynchronous execution in the DMS. After 
   * completing the task successfully it returns true. If there is a task 
   * failure, then it prints error description and returns false.
   * 
   * @param taskObj task object
   * @param taskName name of the task
   * 
   * @return boolean returns true when the task is successful
   */
  public static boolean executeTask(MiningTask taskObj, String taskName)
    throws ODMException, SQLException {
    boolean isTaskSuccess = false;
    taskObj.store(m_dmsConn, taskName); //Store the task
    taskObj.execute(m_dmsConn); //Submit the task for asynchronous execution
    System.out.print(taskName + " is started, please wait. ");
    //Wait for completion of the task
    MiningTaskStatus taskStatus = taskObj.waitForCompletion(m_dmsConn);
    //Check the status of the task after completion
    isTaskSuccess = taskStatus.getTaskState().equals(MiningTaskState.success);
    if( isTaskSuccess ) {
      //Task completed successfully
      System.out.println("It completed successfully.");
    } else {//Task failed
      throw new ODMException("It is failed.\nFailure Description: " + 
        taskStatus.getStateDescription() );
    }
    return isTaskSuccess;
  }
  

 /**
   * This method imports the mining model in PMML format to native format. It 
   * stores the native format model into the user schema.
   * In this example, we will import the PMML model in "PMML_DEMO" table. 
   */
  public static void importModel(LocationCellAccessData pmmlDataLocation) 
  throws ODMException, SQLException, IOException 
  {
    //1. Create model import task
    ModelImportTask importTask = new ModelImportTask(
        "PMMLDemo_ImportedModel",
        pmmlDataLocation,
        MiningStandardType.PMML20);
    //2.Store & execute the task
      executeTask(importTask, "PMMLDemo_ImportTask"); 
  }  

  /**
   * This method builds a mining model, build operation requires the training 
   * dataset location details and the mining function settings. 
   * In this example, we will build a classification model using the 
   * build dataset "MINING_DATA_BUILD_V" in the user schema, with the NaiveBayes 
   * algorithm. This model can be used to predict which customer should 
   * receive an "AFFINITY_CARD". After completing the build task, the model 
   * named "NBDemo_Model" will be created in the DMS.
   */
  public static void buildModel() throws ODMException, SQLException, IOException 
  {
    //1. Create PhysicalDataSpecification
        LocationAccessData lad = new LocationAccessData( 
                                       "MINING_DATA_BUILD_V", //Build Table Name
                                       DATA_SCHEMA_NAME //Schema Name
                                     );
        PhysicalDataSpecification pds = 
          new NonTransactionalDataSpecification( lad );
    //2. Create & Store Mining Function Settings
        NaiveBayesSettings nbAlgo = new NaiveBayesSettings(0.01f, 0.01f);
        ClassificationFunctionSettings mfs =
          ClassificationFunctionSettings.create(
                   m_dmsConn,       //DMS Connection
                   nbAlgo,          //NB algorithm settings
                   pds,             //Build data specification
                   "AFFINITY_CARD", //Target column
                   AttributeType.categorical, //Default attribute type
                   DataPreparationStatus.unprepared //Default preparation status
                   );
        //Set Cust_ID attribute as inactive attribute
        mfs.adjustAttributeUsage(new String[]{"CUST_ID"},AttributeUsage.inactive);
        mfs.store( m_dmsConn, "PMMLDemo_MFS");
    //3. Create, store & execute Build Task
        MiningBuildTask buildTask = new MiningBuildTask(
                     pds, //Build data specification
                     "PMMLDemo_MFS", //Mining function settings name
                     "PMMLDemo_Model" //Mining model name
                     );
        executeTask(buildTask, "PMMLDemo_BuildTask" );
  }

  /**
   * Cleanup the previously created objects if any. 
   */
  public static void cleanup() throws ODMException, SQLException
  {
    //Remove the MiningFunctionSettings
    try {
      ClassificationFunctionSettings.remove(m_dmsConn, "PMMLDemo_MFS");
    }catch(Exception anyExp1) { }//Ignore
    //Remove the MiningBuildTask
    try {
      MiningBuildTask.remove(m_dmsConn, "PMMLDemo_BuildTask");
    }catch(Exception anyExp2) { }//Ignore
    //Remove the MiningModel
    try {
      MiningModel.remove(m_dmsConn, "PMMLDemo_Model");
    }catch(Exception anyExp3) { }//Ignore
    //Remove the ModelExportTask
    try {
      ModelExportTask.remove(m_dmsConn, "PMMLDemo_ExportTask");
    }catch(Exception anyExp4) { }//Ignore
    //Remove the ModelImportTask
    try {
      ModelImportTask.remove(m_dmsConn, "PMMLDemo_ImportTask");
    }catch(Exception anyExp5) { }//Ignore
    //Remove the imported model
    try 
    {      
      MiningModel.remove(m_dmsConn, "PMMLDemo_ImportedModel");
    }catch(Exception anyExp6) { }//Ignore
    //Drop the PMML_DEMO table
    try {
      String dropTable = "DROP TABLE " + DATA_SCHEMA_NAME + 
          ".PMML_DEMO";
      Statement stmt = m_dmsConn.getDBConnection().createStatement();
      stmt.execute(dropTable);
      stmt.close();
    }catch(Exception anyExp7) { }//Ignore
  }
}