// *************************************************************************
//   (c) Copyright IBM Corp. 2007 All rights reserved.
//   
//   The following sample of source code ("Sample") is owned by International 
//   Business Machines Corporation or one of its subsidiaries ("IBM") and is 
//   copyrighted and licensed, not sold. You may use, copy, modify, and 
//   distribute the Sample in any form without payment to IBM, for the purpose of 
//   assisting you in the development of your applications.
//   
//   The Sample code is provided to you on an "AS IS" basis, without warranty of 
//   any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR 
//   IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
//   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do 
//   not allow for the exclusion or limitation of implied warranties, so the above 
//   limitations or exclusions may not apply to you. IBM shall not be liable for 
//   any damages you suffer as a result of using, copying, modifying or 
//   distributing the Sample, even if IBM has been advised of the possibility of 
//   such damages.
// *************************************************************************
//                                                                          
// SAMPLE FILE NAME: XmlDecomposition.java                                     
//
// PURPOSE: To demonstrate annotated XML schema decomposition 
//
// USER SCENARIO:
//	       A bookstore has books for sale and the descriptive information about
//         each book is stored as an XML document. The store owner needs to store 
//         these details in different relational tables with referential 
//         constraints for easy retreival of data.
//         The Bookstore that has two types of customers, retail customers and
//         corporate customers. Corporate customers do bulk purchases of books
//         for their company libraries. The store has a DBA for maintaining 
//         the database, the store manager runs queries on different tables 
//         to view the book sales. The information about books returned by 
//         customers due to damage or due to exchange with some other book
//         is stored as xml document in books_returned table. At the end of 
//         the day a batch process decomposes these XML documents to update 
//         the books available status with the latest information. The batch 
//         process uses the DECOMPOSE XML DOCUMENTS command to decompose 
//         binary or XML column data into relational tables. 
//
// SOLUTION:
//         The store manager must have an annotated schema based on which the XML data 
//         can be decomposed. Once a valid annotated schema for the instance document  
//         is ready, it needs to be registered with the XML schema repository with 
//         the decomposition option enabled. Also, the tables in which the data will be 
//         decomposed must exist before the schema is registered. The user can 
//         decompose the instance documents and store the data in the relational 
//         tables using annotated XML Decomposition.
//
//    
//  PREREQUISITE:
//        The instance documents and the annotated schema must exist in the same
//        directory as the sample.
//        Copy bookdetails.xsd, booksreturned.xsd, bookdetails.xml,
//        booksreturned.del, booksreturned1.xml, booksreturned2.xml, booksreturned3.xml,
//        setupfordecomposition.db2 and cleanupfordecomposition.db2 from directory
//        <install_path>/sqllib/samples/xml/data in UNIX and
//        <install_path>\sqllib\samples\xml\data in Windows to the working directory.
//                                                                          
//  EXECUTION:    i)   db2 -tvf setupfordecomposition.db2 (setup script 
//                     to create the required tables and populate them)
//                ii)  javac XmlDecomposition.java (compile the sample)
//                     java XmlDecomposition (run the sample)               
//                iii) db2 -tvf cleanupfordecomposition.db2 (clean up 
//                     script to drop all the objects created)
//                                                                          
//  INPUTS:       NONE
//                                                                          
//  OUTPUTS:      Decomposition of XML documents according to the dependencies 
//                specified in the annotated XML schema.
//                                                                          
//                            
//                                     
// SQL STATEMENTS USED:
//         REGISTER XMLSCHEMA
//         COMPLETE XMLSCHEMA
//         SELECT
//         CALL
//         DECOMPOSE XML DOCUMENT
//         DECOMPOSE XML DOUMENTS IN
//
//***************************************************************************
//
// For more information on the sample programs, see the README file.
//
// For information on developing JDBC applications, see the Application
// Development Guide.
//
// For information on using SQL statements, see the SQL Reference.
//
// For the latest information on programming, compiling, and running DB2
// applications, visit the DB2 Information Center at
//     http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/index.jsp
//***************************************************************************
//
//  SAMPLE DESCRIPTION                                                     
//
// *************************************************************************
// 1. Register the annotated XML schemas.
// 2. Decompose a single XML document using the registered XML schema.
// 3. Decompose XML documents using the registered XML schema from
//    3.1. An XML column.
//    3.2. A BLOB column. 
// 4. Decompose XML documents from an XML column resulted by
//    4.1. Join operation 
//    4.2. Union operation
// *************************************************************************

import java.lang.*;
import java.sql.*;
import java.io.*;

class XmlDecomposition
{
	
  public static String relSchema=new String("XDB");
  public static String schemaName=new String("BOOKDETAILS");;
  public static String schemaLocation= new String("http://book.com/bookdetails.xsd");
  public static String primaryDocument= new String("bookdetails.xsd");
  
  public static String schemaName1=new String("BOOKSRETURNED");;
  public static String schemaLocation1= new String("http://book.com/booksreturned.xsd");
  public static String primaryDocument1= new String("booksreturned.xsd");

  public static String query = " "; 
  
  public static void main(String argv[])
  {
    try
    {
 
      Db db = new Db(argv);

      System.out.println();
      System.out.println("THIS SAMPLE SHOWS HOW TO " + "\n 1. DECOMPOSE A SINGLE XML DOCUMENT");
      System.out.println(" 2. DECOMPOSE XML DATA FROM AN XML COLOUMN ");
      System.out.println(" 3. DECOMPOSE XML DATA FROM A BLOB COLOUMN ");
      System.out.println(" 4. DECOMPOSE XML DATA FROM AN XML COLOUMN RESULT OF JOIN OPERATION");
      System.out.println(" 5. DECOMPOSE XML DATA FROM AN XML COLOUMN RESULT OF UNION OPERATION");

      // connect to the 'sample' database
      db.connect();
 
      // register the XML Schemas
      registerXmlSchema(db.con,schemaName,schemaLocation,primaryDocument);
      registerXmlSchema(db.con,schemaName1,schemaLocation1,primaryDocument1);
      
      System.out.println("/*************************************************************************");
      System.out.println(" Decompose a single XML document using the registered XML schema.");
      System.out.println("*************************************************************************/");

      singleXMLDecompose(db.con);
      
      System.out.println("/*************************************************************************");
      System.out.println(" Decompose XML documents from an XML column.");
      System.out.println("*************************************************************************/");

      query = "SELECT customerID, booksreturned FROM xdb.books_returned";
      bulkXmlDecompose(db.con, query);

      System.out.println("/************************************************************************* ");
      System.out.println(" Decompose XML documents from a BLOB column.");
      System.out.println("*************************************************************************/ ");

      query = "SELECT supplierID, booksinfo from xdb.books_received_BLOB";
      bulkXmlDecompose(db.con, query);

      System.out.println("/*************************************************************************");
      System.out.println(" Decompose XML documents from an XML column resulted by Join operation.");
      System.out.println("*************************************************************************/");
      query = "SELECT id, data FROM(SELECT br.customerID as id, br.booksreturned AS info " +
              "FROM xdb.books_returned as br,xdb.books_received AS brd " +
              "WHERE XMLEXISTS('$bi/books/book[@isbn] = $bid/books/book[@isbn]' " +
              "PASSING br.booksreturned as \"bi\", " +
              "brd.booksinfo as  \"bid\")) AS temp(id,data)";
      bulkXmlDecompose(db.con, query);

      
      System.out.println("/*************************************************************************");
      System.out.println(" Decompose XML documents from an XML column resulted by union operation.");
      System.out.println("*************************************************************************/");
      
      query = "SELECT id, data FROM(SELECT customerID as cid, booksreturned AS info " +
              "FROM xdb.books_returned " +
              "WHERE XMLEXISTS('$bk/books/book[author=\"Carl\"]' " +
              "PASSING booksreturned AS \"bk\") "+
              "UNION ALL " +
              "SELECT supplierID as sid, booksinfo AS books " +
              "FROM xdb.books_received " +
              "WHERE XMLEXISTS('$br/books/book[author=\"Carl\"]' " +
              "PASSING booksinfo AS \"br\")) AS temp(id,data) ";
      bulkXmlDecompose(db.con, query);

      // disconnect from the 'sample' database
      db.disconnect();
    }
    catch (Exception e)
    {
      JdbcException jdbcExc = new JdbcException(e);
      jdbcExc.handle();
    }
  } // main

  
  
  // Method to register an XML Schema
  static void registerXmlSchema(Connection con,String schName,String schLoc,String schDoc)
  {
    try
    {
    	int shred = 1;
      // register XML Schema
      System.out.println("\nRegistering Schema "+ relSchema + "." +schName +"..."); 
      CallableStatement callStmt = con.prepareCall("CALL SYSPROC.XSR_REGISTER(?,?,?,?,NULL)");
      File xsdFile = new File(schDoc);
      FileInputStream xsdData = new FileInputStream(xsdFile);
      callStmt.setString(1, relSchema);
      callStmt.setString(2, schName);
      callStmt.setString(3, schLoc);
      callStmt.setBinaryStream(4, xsdData, (int)xsdFile.length() );
      callStmt.execute();
      xsdData.close();
   
      // complete the registration 
      System.out.println("Completing XML Schema registration...");
      callStmt=con.prepareCall("CALL SYSPROC.XSR_COMPLETE(?,?,NULL,?)");
      callStmt.setString(1, relSchema);
      callStmt.setString(2, schName);
      callStmt.setInt(3, shred);
      callStmt.execute();
      System.out.println("Schema "+ relSchema + "." +schName +" registered successfully \n\n");
      callStmt.close();
      
      // Check the status of the XSR object registered.
      PreparedStatement pstmt = con.prepareStatement(
           "SELECT status, decomposition, decomposition_version " +
           "FROM SYSIBM.SYSXSROBJECTS WHERE XSROBJECTNAME = ? ");
      pstmt.setString(1,schName);
      ResultSet rs = pstmt.executeQuery();
      while(rs.next())
          {
            String Status = rs.getString(1);
            String Decomposition = rs.getString(2);
            String Decomposition_version = rs.getString(3);

            System.out.println("\nStatus : " + Status + "\n" +
                               "Decomposition  : " + Decomposition + "\n" +
                               "Version : " + Decomposition_version);
          } 
      rs.close();    
    } 
    catch(SQLException sqle)
    {
      System.out.println("Error Msg: "+sqle.getMessage());
      System.out.println("SQLState: "+sqle.getSQLState());
      System.out.println("SQLError: "+sqle.getErrorCode());
      System.out.println("Rollback the transaction and quit the program");
      System.out.println();
      try { con.rollback(); }
      catch (Exception e) {}
      System.exit(1);
    }
    catch(IOException ioe)
    {
      System.out.println("Error opening file " + schDoc);
    }
  }// registerXmlSchema
  
  static void singleXMLDecompose(Connection con)
  {
    try
      {
         String xmlfilename = "bookdetails.xml";
         int shred = 1;
         
        // Decompose the XML document by calling the SYSPROC.XDBDECOMPXML
        CallableStatement callStmt = con.prepareCall("CALL SYSPROC.XDBDECOMPXML(?,?,?,?,?, NULL, NULL, NULL)");
        File xmlfile = new File(xmlfilename);
        FileInputStream xmlfileis = new FileInputStream(xmlfile);
        callStmt.setString(1, relSchema );
        callStmt.setString(2, schemaName );
        callStmt.setBinaryStream(3, xmlfileis, (int)xmlfile.length() );
        callStmt.setString(4, schemaName );
        callStmt.setInt(5, shred);
        callStmt.execute();
        xmlfileis.close();
        callStmt.close();
        System.out.println("**** CALL SYSPROC.XDBDECOMPXML SUCCESSFULLY");

        // Read Data from the tables, where the data is stored after decomposition.
        SelectFromAllTables(con);
      }
    catch(SQLException sqle)
    {
      System.out.println("Error Msg: "+sqle.getMessage());
      System.out.println("SQLState: "+sqle.getSQLState());
      System.out.println("SQLError: "+sqle.getErrorCode());
      System.out.println("Rollback the transaction and quit the program");
      System.out.println();
      try { con.rollback(); }
      catch (Exception e) {}
      System.exit(1);
    }
    catch(IOException ioe)
    {
      System.out.println("Error opening file ");
    }

  }
  
 static void bulkXmlDecompose(Connection con, String query)
  {
    try
      {
         System.out.print(query); 
        // Decompose the XML document by calling the SYSPROC.XDBDECOMPXML
        CallableStatement callStmt = 
        con.prepareCall("CALL SYSPROC.XDB_DECOMP_XML_FROM_QUERY('XDB','BOOKSRETURNED',?, 1, 0, 0, NULL, NULL, 1, ?, ?, ?)");
        System.out.println("Calling SYSPROC.XDB_DECOMP_XML_FROM_QUERY....");
        // register the output parameter
        callStmt.setString(1, query);
        callStmt.registerOutParameter(2, Types.INTEGER);
        callStmt.registerOutParameter(3, Types.INTEGER);
        callStmt.registerOutParameter(4, Types.BLOB);
        callStmt.execute();
        ResultSet rs = callStmt.getResultSet();   
        System.out.println("\n CALLED SYSPROC.XDB_DECOMP_XML_FROM_QUERY SUCCESSFULLY");
        int  totaldocs = callStmt.getInt(2);
        System.out.println("\nTotal documents to be decomposed:" + totaldocs);
        int  numdocsdecomposed = callStmt.getInt(3);
        System.out.println("\nNumber of documents decomposed:" + numdocsdecomposed);
        String err = callStmt.getObject(4).toString();     
        System.out.println("\n \n Error report :" + err);
        //callStmt.close();      

        // Read Data from the tables, where the data is stored after decomposition.
        SelectFromBooksAvail(con);
        //rs.close();      

     }
    catch(SQLException sqle)
    {
      System.out.println("Error Msg: "+sqle.getMessage());
      System.out.println("SQLState: "+sqle.getSQLState());
      System.out.println("SQLError: "+sqle.getErrorCode());
      System.out.println("Rollback the transaction and quit the program");
      System.out.println();
      try { con.rollback(); }
      catch (Exception e) {}
      System.exit(1);
    }
  }
    
  
  static void SelectFromBooksAvail(Connection con)
  {
    try
      {
        String isbn = " ";
        int authid = 0;
        String authname = " ";
        String book_title = " ";
        float price =  0;
        int no_of_copies = 0;

        Statement stmt = con.createStatement();
        ResultSet rs1 = stmt.executeQuery("SELECT isbn, book_title, authid, authname, price, no_of_copies FROM XDB.BOOKS_AVAIL");
        System.out.println("\n SELECT isbn, book_title, authid, authname, price, no_of_copies FROM XDB.BOOKS_AVAIL");
        while(rs1.next())
          {
            isbn = rs1.getString(1);
            book_title = rs1.getString(2);
            authid = rs1.getInt(3);
            authname = rs1.getString(4);
            price = rs1.getFloat(5);
            no_of_copies = rs1.getInt(6);

            System.out.println("\nISBN  : " + isbn + 
                              "\nBook Title : " + book_title +
                              "\nAuthor ID : " + authid +
                              "\nAuthor : " + authname +
                              "\nPrice : " + price +
                              "\nNo of copies : " + no_of_copies);
          }
       // rs1.close();
       // stmt.close();
        Statement stmt1 = con.createStatement();
        stmt1.executeUpdate("DELETE FROM XDB.BOOKS_AVAIL");
       // stmt1.close();
 
      }
    catch(SQLException sqle)
    {
      System.out.println("Error Msg: "+sqle.getMessage());
      System.out.println("SQLState: "+sqle.getSQLState());
      System.out.println("SQLError: "+sqle.getErrorCode());
      System.out.println("Rollback the transaction and quit the program");
      System.out.println();
      try { con.rollback(); }
      catch (Exception e) {}
      System.exit(1);
    }
 }  //SelectFromBooksAvail

  static void SelectFromAllTables(Connection con)
  {
    try
      {
        String isbn = " ";
        int chptnum = 0;
        String chpttittle = " ";
        String chptcontent = " ";
        int authid = 0;
        String authname = " ";
        String book_title = " ";
        String status = " ";
        String decompose = " ";
        String decomp_version = " ";

        Statement stmt = con.createStatement();
        ResultSet rs = stmt.executeQuery(
          "SELECT isbn, chptnum, chpttitle, chptcontent FROM XDB.BOOK_CONTENTS");
        System.out.println("\n SELECT isbn, chptnum, chpttitle, chptcontent FROM XDB.BOOK_CONTENTS");
        while (rs.next())
          {
            isbn = rs.getString(1);
            chptnum = rs.getInt(2);
            chpttittle = rs.getString(3);
            chptcontent = rs.getString(4);
 
            System.out.println("\nISBN          : " + isbn + "\n" +
                               "Chapter Number  : " + chptnum + "\n" +
                               "Chapter Title   : " + chpttittle + "\n" +
                               "Chapter Content : " + chptcontent);
          } 
  
        // Select data from the ADMIN.BOOK_AUTHOR TABLE.
        rs = stmt.executeQuery("SELECT authid, authname, isbn, book_title FROM ADMIN.BOOK_AUTHOR");
        System.out.println("\n SELECT authid, authname, isbn, book_title FROM ADMIN.BOOK_AUTHOR");
        while(rs.next())
          {
            authid = rs.getInt(1);
            authname = rs.getString(2);
            isbn = rs.getString(3);
            book_title = rs.getString(4);
            
            System.out.println("\nAuthor ID   : " + authid + "\n" +
                              "Author Name    : " + authname + "\n" +
                              "ISBN       : " + isbn + "\n" +
                              "Book Title : " + book_title);
          } 
          rs.close();
          
          // Select data from the XDB.BOOKS_AVAIL TABLE.
          SelectFromBooksAvail(con);
 
      }
   catch(SQLException sqle)
    {
      System.out.println("Error Msg: "+sqle.getMessage());
      System.out.println("SQLState: "+sqle.getSQLState());
      System.out.println("SQLError: "+sqle.getErrorCode());
      System.out.println("Rollback the transaction and quit the program");
      System.out.println();
      try { con.rollback(); }
      catch (Exception e) {}
      System.exit(1);
    }
   }  //SelectFromAllTables
   
   
}  //XmlDecomposition Class