home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1998 October A / Pcwk10a98.iso / Inprise / TRIAL / JBUILDER / JSAMPLES.Z / ResolverBean.java < prev    next >
Text File  |  1998-05-08  |  15KB  |  428 lines

  1. /*
  2.  * Copyright (c) 1997-1998 Borland International, Inc. All Rights Reserved.
  3.  * 
  4.  * This SOURCE CODE FILE, which has been provided by Borland as part
  5.  * of a Borland product for use ONLY by licensed users of the product,
  6.  * includes CONFIDENTIAL and PROPRIETARY information of Borland.  
  7.  *
  8.  * USE OF THIS SOFTWARE IS GOVERNED BY THE TERMS AND CONDITIONS 
  9.  * OF THE LICENSE STATEMENT AND LIMITED WARRANTY FURNISHED WITH
  10.  * THE PRODUCT.
  11.  *
  12.  * IN PARTICULAR, YOU WILL INDEMNIFY AND HOLD BORLAND, ITS RELATED
  13.  * COMPANIES AND ITS SUPPLIERS, HARMLESS FROM AND AGAINST ANY CLAIMS
  14.  * OR LIABILITIES ARISING OUT OF THE USE, REPRODUCTION, OR DISTRIBUTION
  15.  * OF YOUR PROGRAMS, INCLUDING ANY CLAIMS OR LIABILITIES ARISING OUT OF
  16.  * OR RESULTING FROM THE USE, MODIFICATION, OR DISTRIBUTION OF PROGRAMS
  17.  * OR FILES CREATED FROM, BASED ON, AND/OR DERIVED FROM THIS SOURCE
  18.  * CODE FILE.
  19.  */
  20.  
  21. //Title:        Custom Providers and Resolvers
  22. //Version:      2.0
  23. //Copyright:    Copyright (c) 1998
  24. //Author:       Jens Ole Lauridsen
  25. //Company:      Borland International
  26. //Description:  Tutorial, example of provider and resolver.
  27.  
  28. package borland.samples.tutorial.dataset.providers;
  29.  
  30. import borland.jbcl.dataset.*;
  31. import borland.jbcl.util.Variant;
  32. import java.io.*;
  33.  
  34. // ResolverBean
  35. //   Resolver   is an abstract base class for all resolvers
  36. //   DataLayout is an interface with constants describing the data layout in "data.txt"
  37. //
  38. public class ResolverBean extends Resolver implements DataLayout {
  39.  
  40.   // Set a limit for how large data.txt should grow:
  41.   private static final int ROW_MAX = 100;
  42.   
  43.   // resolveData = main Resolver method
  44.   // Parameters:
  45.   //   dataSetView : DataSet to save data from.
  46.   //
  47.   public void resolveData(DataSet dataSetView) throws DataSetException {
  48.  
  49.     // We are actually saving all the changes in the StorageDataSet:
  50.     //
  51.     StorageDataSet dataSet = dataSetView.getStorageDataSet();
  52.  
  53.     // Starting the resolution will lock the dataSet for refreshes
  54.     // momentarily. The second parameter will result in posting of
  55.     // all pending changes in any dataSetView of this data.
  56.     //
  57.     ProviderHelp.startResolution(dataSet, true);
  58.     
  59.     // Make a quick out, if there are no changes:
  60.     if (!dataSet.changesPending()) {
  61.       ProviderHelp.endResolution(dataSet);
  62.       return;
  63.     }
  64.  
  65.     // Read in the file. Each data line is kept as a separate string
  66.     // in the String array. The index used is the value of the ID 
  67.     // field of the data itself. This is the column used as rowID in
  68.     // this implementation of a Resolver.
  69.     //  
  70.     String[] file = readFile("data.txt");
  71.  
  72.     // Create 3 temporary DataSetView's
  73.     DataSetView inserted = new DataSetView();
  74.     DataSetView deleted  = new DataSetView();
  75.     DataSetView updated  = new DataSetView();
  76.  
  77.     // Get a couple of temporary Variant's
  78.     variant1 = new Variant();
  79.     variant2 = new Variant();
  80.  
  81.     // Use this flag to determine if the data was actually successfully 
  82.     // saved to disk.
  83.     boolean resolved = false;
  84.                              
  85.     try {
  86.       // Get all the inserted, deleted, and updated rows:
  87.       dataSet.getInsertedRows(inserted);
  88.       dataSet.getDeletedRows(deleted);
  89.       dataSet.getUpdatedRows(updated);
  90.  
  91. /**************************************************************************      
  92.       // Warning:
  93.       // This code is not used, but it demonstrates a point:
  94.       //   The StorageDataSet of these dataSetViews might not
  95.       //   be the same instance as the variable "dataSet"
  96.       StorageDataSet sds1 = ProviderHelp.getResolverDataSet(deleted);
  97.       StorageDataSet sds2 = deleted.getStorageDataSet();
  98.  
  99.       // "sds1" will be the same instance as "dataSet" nomatter what.
  100.       // "sds2" will not be the same instance as "dataSet" if the storage
  101.       // is a DataStore. Keep this in mind if certain properties are needed
  102.       // off the "dataSet" instance in the methods "processDeletes" and
  103.       // "processInserts" below.
  104. **************************************************************************/
  105.     
  106.       // Handle all these changes:
  107.       processInserts(inserted,file);
  108.       processDeletes(deleted,file);
  109.       processUpdates(updated,file);
  110.  
  111.       // Write the complete file back to disk:
  112.       // Note: one bug here: the "data.txt" file could have been
  113.       // changed since it was read. There is no guard against it here.
  114.       // 
  115.       writeFile("data.txt",file);
  116.  
  117.       // Mark that everything was saved properly:
  118.       resolved = true;
  119.     }                         
  120.     finally {
  121.       // Reset the status bits.
  122.       // If the changes were successfully saved, this will change the
  123.       // status bits accordingly.
  124.       dataSet.resetPendingStatus(resolved);
  125.  
  126.       // Remember to always close these temporary dataSetView's.
  127.       // Otherwise... there will be memory leaks !
  128.       inserted.close();
  129.       deleted.close();
  130.       updated.close();
  131.  
  132.       // End the resolution process here.
  133.       ProviderHelp.endResolution(dataSet);
  134.     }
  135.   }
  136.  
  137.   // processInserts
  138.   // Parameters:
  139.   //   insertDataSet : DataSet of all the inserted rows.
  140.   //   file          : The internal representation of "data.txt"
  141.   //
  142.   private void processInserts(DataSet insertDataSet, String[] file) throws DataSetException {
  143.     if (!insertDataSet.isEmpty()) {
  144.       insertDataSet.first();
  145.       int status;
  146.       do {
  147.         // Note, that DELETED rows that were inserted should not be resolved.
  148.         status = insertDataSet.getStatus();
  149.         if ((status& RowStatus.DELETED) == 0) {
  150.           processInsertRow(insertDataSet, file);
  151.  
  152.           // Mark this row as PENDING_RESOLVED i.e. this change might get resolved now. 
  153.           ProviderHelp.markPendingStatus(insertDataSet, true);
  154.         }
  155.       } while(insertDataSet.next());
  156.     }
  157.   }
  158.  
  159.   // processDeletes
  160.   // Parameters:
  161.   //   deleteDataSet : DataSet of all the deleted rows.
  162.   //   file          : The internal representation of "data.txt"
  163.   //
  164.   private void processDeletes(DataSet deleteDataSet, String[] file) throws DataSetException {
  165.     if (!deleteDataSet.isEmpty()) {
  166.       deleteDataSet.first();
  167.       int status;
  168.       do {
  169.         // Note, that INSERTED rows that were deleted should not be resolved.
  170.         status  = deleteDataSet.getStatus();     
  171.         if ((status & RowStatus.INSERTED) == 0) {
  172.           processDeleteRow(deleteDataSet, file);
  173.           
  174.           // Mark this row as PENDING_RESOLVED i.e. this change might get resolved now. 
  175.           ProviderHelp.markPendingStatus(deleteDataSet, true);
  176.         }                           
  177.       } while (deleteDataSet.next());
  178.     }
  179.   }
  180.   
  181.   // processUpdates
  182.   // Parameters:
  183.   //   updateDataSet : DataSet of all the updated rows.
  184.   //   file          : The internal representation of "data.txt"
  185.   //
  186.   private void processUpdates(DataSet updateDataSet, String[] file) throws DataSetException {
  187.     if (!updateDataSet.isEmpty()) {
  188.       DataRow         oldDataRow    = new DataRow(updateDataSet);
  189.       StorageDataSet  dataSetStore  = updateDataSet.getStorageDataSet();
  190.  
  191.       updateDataSet.first();
  192.       int status;
  193.       do {
  194.         // Note, that updated rows that were deleted should not be resolved.
  195.         status  = updateDataSet.getStatus();     
  196.         if (   (status&RowStatus.DELETED) == 0) {
  197.           // Get the original row from the StorageDataSet:
  198.           dataSetStore.getOriginalRow(updateDataSet, oldDataRow);
  199.           
  200.           processUpdateRow(updateDataSet, oldDataRow, file);
  201.           
  202.           // Mark this row as PENDING_RESOLVED i.e. this change might get resolved now. 
  203.           ProviderHelp.markPendingStatus(updateDataSet, true);
  204.         }                           
  205.       } while (updateDataSet.next());
  206.     }
  207.   }
  208.   
  209.   // processInsertRow
  210.   // Parameters:
  211.   //   insertRow : An inserted row.
  212.   //   file      : The internal representation of "data.txt"
  213.   //
  214.   private void processInsertRow(ReadRow insertRow, String[] file) throws DataSetException {
  215.     // Get the value of the rowID:
  216.     insertRow.getVariant(ROWID_NAME,variant1);
  217.     int id = variant1.getInt();
  218.  
  219.     // If the rowID is invalid or is null, generate one.
  220.     // Note, that the QueryResolver doesn't do this. There the
  221.     // insertingRow event (from ResolverListener) must be implemented
  222.     // to perform a similar task. 
  223.     if (id <= 0 || id > ROW_MAX || insertRow.isNull(ROWID_NAME)) {
  224.       id = generateID(file);
  225.       variant1.setInt(id);
  226.     }
  227.  
  228.     // If the rowID is already in use, this is an error:
  229.     if (file[id] != null)
  230.       throw new DataSetException("RowID is already used");
  231.  
  232.     // Construct a line for "data.txt" :
  233.     String value = makeField(variant1,0);
  234.     for (int i=1; i<COLUMN_COUNT; i++) {
  235.       insertRow.getVariant(COLUMN_NAMES[i],variant1);
  236.       value += makeField(variant1, i );
  237.     }
  238.  
  239.     // Save the new line into the line table:
  240.     file[id] = value;
  241.   }
  242.   
  243.   // processDeleteRow
  244.   // Parameters:
  245.   //   deleteRow : A deleted row.
  246.   //   file      : The internal representation of "data.txt"
  247.   //
  248.   private void processDeleteRow(ReadRow deleteRow, String[] file) throws DataSetException {
  249.     // Get the value of the rowID:
  250.     int id = deleteRow.getInt(ROWID_NAME);
  251.     
  252.     // If the rowID is invalid or is not already in use, this is an error:
  253.     if (id <= 0 || id > ROW_MAX || deleteRow.isNull(ROWID_NAME) || file[id] == null)
  254.       throw new DataSetException("RowID is not found");
  255.       
  256.     // Delete the line from the line table:
  257.     file[id] = null;
  258.   }                          
  259.   
  260.   // processUpdateRow
  261.   // Parameters:
  262.   //   updateRow  : An updated row.
  263.   //   oldDataRow : The original row (as the provider read it)
  264.   //   file       : The internal representation of "data.txt"
  265.   //
  266.   private void processUpdateRow(ReadRow updateRow, ReadRow oldDataRow, String[] file) throws DataSetException {
  267.     // Get the value of the rowID:
  268.     int    id     = oldDataRow.getInt(ROWID_NAME);
  269.     
  270.     // If the rowID is invalid or is not already in use, this is an error:
  271.     if (id <= 0 || id > ROW_MAX || oldDataRow.isNull(ROWID_NAME) || file[id] == null)
  272.       throw new DataSetException("RowID is not found");
  273.  
  274.     // Merge in the changes from this operation,
  275.     // Note, that we are using the raw text from "data.txt" for columns
  276.     // that didn't change.  
  277.     String line   = file[id];
  278.     String value  = "";
  279.     int    offset = 0;
  280.     for (int i=0; i<COLUMN_COUNT; i++) {
  281.       updateRow.getVariant( COLUMN_NAMES[i], variant1 );
  282.       oldDataRow.getVariant( COLUMN_NAMES[i], variant2 );
  283.       if (variant1.equals(variant2))
  284.         value += getFieldFromLine(line, offset, i);   // No change, use the current column text
  285.       else
  286.         value += makeField(variant1, i);              // Changed!, make a column of the current value
  287.       offset += COLUMN_WIDTHS[i];
  288.     }
  289.  
  290.     // Store the line to the line table:
  291.     file[id] = value;
  292.   }
  293.   
  294.   // generateID - Find an index in "file" that is currently unused.
  295.   // Parameters:
  296.   //   file : The internal representation of "data.txt"
  297.   //
  298.   private int generateID(String[] file) throws DataSetException {
  299.     int slot = 1;
  300.     while (slot < ROW_MAX && file[slot] != null)
  301.       slot++;
  302.     if (slot >= ROW_MAX)
  303.       throw new DataSetException("Capacity Overload");
  304.     return slot;
  305.   }
  306.   
  307.   // getFieldFromLine - Extract a column from the current line
  308.   // Parameters:
  309.   //   line    : The current line
  310.   //   offset  : The starting offset of the column.
  311.   //   columnNo: The column number of the wanted column.
  312.   //
  313.   private String getFieldFromLine(String line, int offset, int columnNo) {
  314.     int width = COLUMN_WIDTHS[columnNo];
  315.     return line.substring(offset,offset+width);
  316.   }
  317.   
  318.   // makeField - Make a textual representation of the column value
  319.   // Parameters:
  320.   //   value   : The value of the column.
  321.   //   columnNo: The column number.
  322.   //
  323.   private String makeField(Variant value, int columnNo) {
  324.     // Get the string value:
  325.     String val = "";
  326.     if (!value.isNull()) {
  327.       switch (value.getType()) {
  328.         case Variant.STRING:
  329.           val = value.getString();
  330.           break;
  331.         case Variant.INT:
  332.           val = Integer.toString(value.getInt());
  333.           break;
  334.         case Variant.BIGDECIMAL:
  335.           val = value.getBigDecimal().toString();
  336.           break;
  337.       }         
  338.     }
  339.     
  340.     // Make sure to use the correct column width:
  341.     int width = COLUMN_WIDTHS[columnNo];
  342.     if (val.length() > width)
  343.       val = val.substring(0,width);   // Zap long column values...
  344.     else if (val.length() < width) {
  345.       // Pad with spaces...
  346.       char[] chars = new char[width];
  347.       for (int i=0; i<width; i++)
  348.         chars[i] = ' ';
  349.       int start;
  350.       if (COLUMN_TYPES[columnNo] == Variant.STRING)
  351.         start = 0;  // Left align strings...
  352.       else
  353.         start = width - val.length();  // Right align all other types...
  354.       val.getChars(0, val.length(), chars, 0);
  355.       val = new String(chars);
  356.     }
  357.     return val;
  358.   }
  359.   
  360.   // skipLine - Skip up to next LF character:
  361.   //
  362.   private void skipLine(InputStream stream) throws IOException {
  363.     int ch = stream.read();
  364.     while (ch != '\n')
  365.       ch = stream.read();
  366.   }
  367.  
  368.   // readFile - Read the context of the file 'filename'.
  369.   //   Create a String array and store each line in there.
  370.   //   Use the value of the ID as the index of the array.
  371.   private String[] readFile(String filename) throws DataSetException {
  372.     try {
  373.       String[] result = new String[100];
  374.       FileInputStream fs = new FileInputStream("data.txt");
  375.       int rowWidth = 0;
  376.       for (int i=0; i<COLUMN_COUNT; i++)
  377.         rowWidth += COLUMN_WIDTHS[i];
  378.       byte[] buffer = new byte[rowWidth];
  379.     
  380.       skipLine(fs);
  381.       skipLine(fs);
  382.       while (true) {
  383.         int len = fs.read(buffer);
  384.         if (len < rowWidth)
  385.           break;
  386.         skipLine(fs);
  387.  
  388.         String value = new String(buffer);
  389.         String idStr = value.substring(0,COLUMN_WIDTHS[0]);
  390.         int id = Integer.parseInt(idStr.trim());
  391.  
  392.         result[id] = new String(buffer);
  393.       }
  394.       fs.close();
  395.       return result;
  396.     }
  397.     catch (IOException ex) {
  398.       DataSetException.IOException(ex);
  399.       return null;
  400.     }
  401.   }
  402.  
  403.   // writeFile
  404.   //  Write the file to disk, with changes applied here.
  405.   //
  406.   private void writeFile(String filename, String[] file) throws DataSetException {
  407.     try {
  408.       FileOutputStream fs = new FileOutputStream("data.txt");
  409.       fs.write("          1         2         3         4         5\r\n".getBytes());
  410.       fs.write("012345678901234567890123456789012345678901234567890123456789\r\n".getBytes());
  411.       for (int i=1; i<ROW_MAX; i++) {
  412.         if (file[i] != null) {
  413.           fs.write(file[i].getBytes());
  414.           fs.write('\r');
  415.           fs.write('\n');
  416.         }
  417.       }
  418.       fs.close();
  419.     }
  420.     catch (IOException ex) {
  421.     }
  422.   }
  423.   
  424.   private Variant variant1;
  425.   private Variant variant2;
  426. }
  427.  
  428.