Coverage Report - org.apache.commons.scaffold.sql.StorageBeanBase
 
Classes in this File Line Coverage Branch Coverage Complexity
StorageBeanBase
0%
0/301
0%
0/76
2.518
 
 1  
 /*
 2  
  * Copyright 2001,2004 The Apache Software Foundation.
 3  
  * 
 4  
  * Licensed under the Apache License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  * 
 8  
  *      http://www.apache.org/licenses/LICENSE-2.0
 9  
  * 
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 
 17  
 package org.apache.commons.scaffold.sql;
 18  
 
 19  
 
 20  
 import java.sql.SQLException;
 21  
 import java.sql.Timestamp;
 22  
 import java.util.Collection;
 23  
 import java.util.Iterator;
 24  
 import java.util.List;
 25  
 import java.util.Map;
 26  
 import java.util.Properties;
 27  
 
 28  
 import org.apache.commons.beanutils.BeanUtils;
 29  
 import org.apache.commons.scaffold.lang.ParameterException;
 30  
 import org.apache.commons.scaffold.lang.PopulateException;
 31  
 import org.apache.commons.scaffold.lang.PropertiesException;
 32  
 import org.apache.commons.scaffold.lang.ResourceException;
 33  
 import org.apache.commons.scaffold.lang.Tokens;
 34  
 import org.apache.commons.scaffold.lucene.Engine;
 35  
 import org.apache.commons.scaffold.lucene.SearchUtils;
 36  
 import org.apache.commons.scaffold.text.ConvertUtils;
 37  
 import org.apache.commons.scaffold.util.ProcessBeanBase;
 38  
 import org.apache.commons.scaffold.util.ProcessResult;
 39  
 import org.apache.commons.scaffold.util.ProcessResultBase;
 40  
 import org.apache.commons.scaffold.util.StorageBean;
 41  
 
 42  
 // ------------------------------------------------------------------------ 78
 43  
 
 44  
 /**
 45  
  * Implements StorageBean interface using
 46  
  * <code>StatementUtils</code> and <code>ResultSetUtils</code> in
 47  
  * this package. Specialty operations may be added using the same
 48  
  * utilities.
 49  
  * <P>
 50  
  * <B>To use this class, the developer must:</B>
 51  
  * <UL>
 52  
  * <LI>Declare a subclass adding the properties to be stored.
 53  
  * <LI>Provide in a set of standard SQL queries naming the properties
 54  
  * to be stored as columns in the command
 55  
  * <LI>Override <code>getStorageKey</code> to return the property used
 56  
  * as the primary or unique key in the SQL commands.
 57  
  * <LI>Override <code>getParameters</code> to return an array of
 58  
  * properties as needed by object's insert and update SQL commands.
 59  
  * <LI>Override <code>getPrefix</code> to set a unique prefix
 60  
  * for each StorageBean class.
 61  
  * Include the prefix in the resource file, but not in the Java code.
 62  
  * <LI>Provide keys.next and keys.inc SQL commands to obtain a new
 63  
  * primary key or override createKey to use some other method.
 64  
  * </UL>
 65  
  * <P>
 66  
  * <B>To specify a connection pool and load the SQL commands:</B>
 67  
  * <UL>
 68  
  * <LI>Load the <code>ConnectionAdaptor</code> for your database
 69  
  * connection pool
 70  
  * <LI>Load the <code>Properties</code> file with your commands and
 71  
  * pass it to the StorageBeanBase <code>init</code> method.
 72  
  * </UL>
 73  
  * <P>The <code>ConnectionServlet</code> in this package is designed
 74  
  * to load <code>ConnectionAdapters<code> and resource
 75  
  * (<code>Properties</code>) files.
 76  
  * <P>
 77  
  * Regarding the queries:
 78  
  * <UL>
 79  
  * <LI>The SQL commands are given in a standard Properties file
 80  
  * (e.g, user.retrieve=SELECT name,address FROM userTable).
 81  
  * The default runtime location is
 82  
  * [WEB-INF/classes/resources/command.properties].
 83  
  * <LI>See the command.properties.sample file in this package
 84  
  * for a starter file.
 85  
  * <LI>All the subclass share the same Properties file.
 86  
  * The prefix property lets you use the same standard query names for
 87  
  * more than one StorageBean.
 88  
  * <LI>The standard queries are insert, update, retrieve, delete, and
 89  
  * recycle, and restore.
 90  
  * <LI>The insert and update commands should use same columns in same
 91  
  * order.
 92  
  * <LI>The retrieve, delete, recycle, and restore command should use
 93  
  * the storageKey property for selection.
 94  
  * <LI>Hint: If columns cannot follow property naming conventions,
 95  
  * rename column in command
 96  
  * <LI>Hint: You can use the same object for more than one table or
 97  
  * resultset if you like
 98  
  * </UL>
 99  
  *
 100  
  * @todo Refactor recycle,restore,delete to use common util method
 101  
  * @todo Javadocs for new classes
 102  
  * @todo Use reflection to read parameter key and make array from
 103  
  * that.
 104  
  * @todo Check for key.paramlist then paramlist.
 105  
  * @todo Permit each subclass to have its own properties (collection
 106  
  * of properties, like Struts Actions).
 107  
  * @todo Switch to CommandStore (or eliminate that object if not
 108  
  * needed).
 109  
  * @todo Add properties to manage optimistic locking
 110  
  * @todo Change from BeanUtil.populate to copyProperties in 1.1
 111  
  * version.
 112  
  * @author Ted Husted
 113  
  * @author OK State DEQ
 114  
  * @version $Revision: 155464 $ $Date: 2005-02-26 13:26:54 +0000 (Sat, 26 Feb 2005) $
 115  
  */
 116  0
 public class StorageBeanBase extends ProcessBeanBase implements StorageBean {
 117  
 
 118  
 
 119  
     /**
 120  
      * Convenience method to check for null, empty String.
 121  
      */
 122  
     protected boolean blank(String s) {
 123  0
         return ConvertUtils.blank(s);
 124  
     }
 125  
 
 126  
     /**
 127  
      * Convenience method to check for null, empty String,
 128  
      * or "0" String.
 129  
      */
 130  
     protected boolean blankValue(String s) {
 131  0
         return ConvertUtils.blankValue(s);
 132  
     }
 133  
 
 134  
     /**
 135  
      * Returns true if null or zero.
 136  
      */
 137  
     public static boolean blank(Number key) {
 138  0
       return ConvertUtils.blank(key);
 139  
     }
 140  
 
 141  
 
 142  
 
 143  
 // ------------------------------------------------------------------ Commands
 144  
 // TODO: Refactor this to use a CommandStore
 145  
 
 146  
 
 147  
     /**
 148  
      * [:TODO: Javadoc]
 149  
      */
 150  
     public final static String like(String parameter) {
 151  0
         return StatementUtils.like(parameter);
 152  
     }
 153  
 
 154  
 
 155  
     /**
 156  
      * [:TODO: Javadoc]
 157  
      */
 158  
     public final static String DOT = ".";
 159  
 
 160  
 
 161  
     /**
 162  
      * Our command string properties.
 163  
      * Can be loaded from an external properties file at startup.
 164  
      */
 165  
     protected static Properties commands;
 166  
 
 167  
 
 168  
     /**
 169  
      * Retrieve command from <code>commands</code> Properties
 170  
      */
 171  
     protected String lookup(String key)
 172  
         throws PropertiesException {
 173  
 
 174  0
         if (null==commands) throw new PropertiesException(
 175  
             PropertiesException.MESSAGE + key);
 176  
 
 177  0
         String command = null;
 178  0
         String prefix = getPrefix();
 179  0
         if (null!=prefix) {
 180  0
             StringBuffer sb = new StringBuffer(prefix);
 181  0
             sb.append(DOT);
 182  0
             sb.append(key);
 183  0
             command = sb.toString();
 184  0
         }
 185  0
         else command = key;
 186  
 
 187  0
         return commands.getProperty(command);
 188  
     }
 189  
 
 190  
 
 191  
     /**
 192  
      * Retrieve command from <code>commands</code> Properties
 193  
      */
 194  
     protected String lookupRoot(String key)
 195  
         throws PropertiesException {
 196  
 
 197  0
         if (null==commands) throw new PropertiesException(
 198  
             PropertiesException.MESSAGE + key);
 199  
 
 200  0
         return commands.getProperty(key);
 201  
 
 202  
     }
 203  
 
 204  
 
 205  
     /**
 206  
      * Set the Properties file to be used for SQL commands.
 207  
      * This can be called by main or in a servlet.init
 208  
      * method at startup. If called more than once, the
 209  
      * new commands are added to the existing store.
 210  
      * If  keys clash,the last one wins.
 211  
      */
 212  
     public static final void init(Properties _commands) {
 213  
 
 214  0
         if (null==commands) {
 215  0
             commands = _commands;
 216  
         }
 217  
         else {
 218  0
             commands.putAll(_commands);
 219  
         }
 220  0
     }
 221  
 
 222  
 
 223  
 // ----------------------------------------------------------- Base Properties
 224  
 
 225  
     /**
 226  
      * [:TODO: Javadoc]
 227  
      */
 228  
     public final static String INSERT = "insert";
 229  
 
 230  
 
 231  
     /**
 232  
      * [:TODO: Javadoc]
 233  
      */
 234  
     public final static String UPDATE = "update";
 235  
 
 236  
 
 237  
     /**
 238  
      * [:TODO: Javadoc]
 239  
      */
 240  
     public final static String RETRIEVE = "retrieve";
 241  
 
 242  
 
 243  
     /**
 244  
      * [:TODO: Javadoc] purge
 245  
      */
 246  
     public final static String DELETE = "delete";
 247  
 
 248  
 
 249  
     /**
 250  
      * [:TODO: Javadoc]
 251  
      */
 252  
     public final static String RESTORE = "restore";
 253  
 
 254  
 
 255  
     /**
 256  
      * [:TODO: Javadoc] delete
 257  
      */
 258  
     public final static String RECYCLE = "recycle";
 259  
 
 260  
 
 261  
     /**
 262  
      * [:TODO: Javadoc]
 263  
      */
 264  
     public final static String TABLE = "table";
 265  
 
 266  
 
 267  
     /**
 268  
      * [:TODO: Javadoc]
 269  
      */
 270  
     public final static String PARAMS = DOT + "params";
 271  
 
 272  
 
 273  
     /**
 274  
      * A unique identifier for this StorageBean's
 275  
      * commands.
 276  
      */
 277  0
     private String prefix = null;
 278  
 
 279  
 
 280  
      // See interface for Javadoc
 281  
     public String getPrefix() {
 282  0
         return prefix;
 283  
     }
 284  
 
 285  
 
 286  
      // See interface for Javadoc
 287  
     public void setPrefix(String prefix) {
 288  0
         this.prefix = prefix;
 289  0
     }
 290  
 
 291  
 
 292  
     /**
 293  
      * The array of parameters required by the
 294  
      * insert and update commands for this object.
 295  
      */
 296  0
     private Object[] parameters = null;
 297  
 
 298  
 
 299  
     /**
 300  
      * Return the runtime parameters for the given command.
 301  
      *
 302  
      * The comma-delimited list of parameter properties can be provided
 303  
      * as a ${command}.params element in the command resource. 
 304  
      * <code>getParameters</code> will automatically retrieve the *.params element 
 305  
      * and use it to create an array of the runtime values for each parameter. 
 306  
      * The sequence of runtime values can then be merged with a prepared 
 307  
      * statement (the command).
 308  
      * Since the parameters are inserted into the command by position, 
 309  
      * the column names and parameter names do not need to match. 
 310  
      * @exception ResourceException if the command resource or command cannot 
 311  
      * be found.
 312  
      */
 313  
     public Object[] getParameters(String command) throws ResourceException {
 314  
         
 315  0
         if (null==command) {
 316  0
             if ((null==parameters) && (null!=paramList)) {
 317  0
                 return paramList.toArray();
 318  
             }       
 319  0
             return parameters;
 320  
         }
 321  
         
 322  
         // Lookup parameters for command ( * + .params)        
 323  0
         String paramToken = command + PARAMS;        
 324  0
         String params = lookup(paramToken);
 325  
 
 326  0
         if (null==params) { 
 327  0
             throw new PropertiesException(
 328  
                 PropertiesException.MESSAGE + paramToken);
 329  
         } 
 330  
         else {
 331  0
             String[] tokens = ConvertUtils.tokensToArray(params,PARAM_SEP);
 332  0
             Object[] values = new Object[tokens.length];
 333  
             try {
 334  0
                 for (int i=0; i<values.length; i++) {
 335  0
                     values[i] = BeanUtils.getProperty(this,tokens[i]);
 336  
                 }
 337  
             }
 338  0
             catch (Exception e) {
 339  0
                 throw new PropertiesException(
 340  
                     PropertiesException.MESSAGE + params);
 341  0
             }
 342  
             
 343  0
             return values;
 344  
         }       
 345  
     }
 346  
 
 347  
 
 348  
      // See interface for Javadoc
 349  
     public void setParameters(Object[] parameters) {
 350  0
         this.parameters = parameters;
 351  0
     }
 352  
 
 353  
 
 354  
     /**
 355  
      * The list of parameters required by the
 356  
      * insert and update commands for this object.
 357  
      */
 358  0
     private List paramList = null;
 359  
 
 360  
 
 361  
     /**
 362  
      * Return the vparamList or parameters field. 
 363  
      * If both are null, return an empty list.
 364  
      */
 365  
     private List paramListDefault() throws ResourceException {
 366  
         
 367  0
         List list = paramList;
 368  0
         if (null==list) { 
 369  
                 // Start with empty list
 370  0
             list = new java.util.ArrayList();
 371  
                 // Add array parameters, if any
 372  0
             Object[] array = getParameters(null);
 373  0
             if (null!=array) {
 374  0
                 for (int i =0; i<array.length; i++) {
 375  0
                     list.add(array[i]);
 376  
                 }
 377  
             }
 378  
         }
 379  0
         return list;
 380  
 
 381  
     }
 382  
 
 383  
 
 384  
     /**
 385  
      * Default separator character for list of parameters [","] (comma).
 386  
      */
 387  
     public static final String PARAM_SEP = ",";
 388  
 
 389  
 
 390  
     /**
 391  
      * Return the runtime parameters for the given command.
 392  
      *
 393  
      * The comma-delimited list of parameter properties can be provided
 394  
      * as a ${command}.params element in the command resource. 
 395  
      * <code>getParameters</code> will automatically retrieve the *.params element 
 396  
      * and use it to create a list of the runtime values for each parameter. 
 397  
      * The sequence of runtime values can then be merged with a prepared 
 398  
      * statement (the command).
 399  
      * Since the parameters are inserted into the command by position, 
 400  
      * the column names and parameter names do not need to match. 
 401  
      * @exception ResourceException if the command resource or command cannot 
 402  
      * be found.
 403  
      */
 404  
     public List getParamList(String command) throws ResourceException {
 405  
         
 406  
         // If no command, return the list or array field
 407  0
         if (null==command) return paramListDefault();
 408  
         
 409  0
         List values = new java.util.ArrayList();
 410  
         // Lookup parameters for command ( * + .params)        
 411  0
         String paramToken = command + PARAMS;        
 412  0
         String params = lookup(paramToken);
 413  0
         if (null==params) {
 414  0
             throw new PropertiesException(
 415  
                 PropertiesException.MESSAGE + paramToken);
 416  
         }
 417  
         else {           
 418  
             // Tokenize into list/iterator (:TODO: Cache?) (:FIXME: List better than array?)
 419  0
             Iterator tokens = ConvertUtils.tokensToList(params,PARAM_SEP).iterator();
 420  
             // Get the runtime property for each parameter (token)
 421  
             try {
 422  0
                 while (tokens.hasNext()) { 
 423  0
                     values.add(BeanUtils.getProperty(this,(String)tokens.next()));
 424  
                 }
 425  
             }
 426  0
             catch (Exception e) {
 427  0
                 throw new PropertiesException(
 428  
                     PropertiesException.MESSAGE + params);
 429  0
             }
 430  
         }
 431  0
        return values;
 432  
     }
 433  
 
 434  
 
 435  
      // See interface for Javadoc
 436  
     public void setParamList(List paramList) {
 437  0
         this.paramList = paramList;
 438  0
     }
 439  
 
 440  
 
 441  
     /**
 442  
      * The marked status of the record.
 443  
      * <p>
 444  
      * Records to be deleted are marked and may be
 445  
      * restored before they are removed from the
 446  
      * database.
 447  
      * The default value is "1" - nominal.
 448  
      */
 449  0
     private Short marked = ConvertUtils.SHORT_ONE;
 450  
 
 451  
 
 452  
     /**
 453  
      * Return the marked status.
 454  
      * <p>
 455  
      * @return the marked status
 456  
      */
 457  
     public Short getMarked() {
 458  0
         return (this.marked);
 459  
     }
 460  
 
 461  
 
 462  
     /**
 463  
      * Set the marked status.
 464  
      * @param marked The new marked status
 465  
      */
 466  
     public void setMarked(Short marked) {
 467  0
         this.marked = marked;
 468  0
     }
 469  
 
 470  
 
 471  
 // ------------------------------------------------------------ Public Methods
 472  
 
 473  
 
 474  
         // See interface for JavaDoc
 475  
     public void populate(Map parameters) throws Exception {
 476  
 
 477  0
         if (parameters!=null) {
 478  0
             BeanUtils.copyProperties(this,parameters);
 479  
         }
 480  
 
 481  0
     } // end populate
 482  
 
 483  
 
 484  
 // ------------------------------------------------------------ Create Methods
 485  
 
 486  
 
 487  
         // See interface for JavaDoc
 488  
     public void executeUpdate(String command)
 489  
             throws ResourceException {
 490  
 
 491  
         try {
 492  
 
 493  0
              int result = StatementUtils.executeUpdate(
 494  
                  null,lookup(command),getParameters(command));
 495  
 
 496  
         }
 497  0
         catch (SQLException e) {
 498  0
             throw new ResourceException(e);
 499  0
         }
 500  
 
 501  0
     } // end executeUpdate
 502  
 
 503  
 
 504  
     public void executeUpdateRoot(String command)
 505  
             throws ResourceException {
 506  
 
 507  
         try {
 508  
 
 509  0
              int result = StatementUtils.executeUpdate(
 510  
                  null,lookupRoot(command));
 511  
 
 512  
         }
 513  0
         catch (SQLException e) {
 514  0
             throw new ResourceException(e);
 515  0
         }
 516  
 
 517  0
     } // end executeUpdate
 518  
 
 519  
 // ----------------------------------------------------------- Retrieval Methods
 520  
 
 521  
 
 522  
         // Convenience method
 523  
     public int count(
 524  
             String command)
 525  
             throws ResourceException {
 526  
 
 527  0
         Integer result = null;
 528  
         try {
 529  0
             result = (Integer) StatementUtils.getColumn(
 530  
                 null,
 531  
                 1,
 532  
                 lookup(command)
 533  
             );
 534  
         }
 535  0
         catch (SQLException e) {
 536  0
             throw new ResourceException(e);
 537  0
         }
 538  0
         return result.intValue();
 539  
     }
 540  
 
 541  
 
 542  
         // See interface for JavaDoc
 543  
     public int count(
 544  
             String command,
 545  
             Object parameter)
 546  
             throws ResourceException {
 547  
 
 548  0
         Integer result = null;
 549  
         try {
 550  0
             result = (Integer) StatementUtils.getColumn(
 551  
                 null,
 552  
                 1,
 553  
                 lookup(command),
 554  
                 parameter
 555  
             );
 556  
         }
 557  0
         catch (SQLException e) {
 558  0
             throw new ResourceException(e);
 559  0
         }
 560  0
         return result.intValue();
 561  
     }
 562  
 
 563  
 
 564  
 
 565  
         // See interface for JavaDoc
 566  
     public boolean findElement(
 567  
             Object target,
 568  
             String command,
 569  
             Object key) throws ResourceException {
 570  
 
 571  0
         boolean found = false;
 572  
 
 573  
         try {
 574  
 
 575  0
             found = StatementUtils.getElement(null,target,
 576  
                 lookup(command),key);
 577  
 
 578  
         }
 579  0
         catch (SQLException e) {
 580  0
             throw new ResourceException(e);
 581  0
         }
 582  
 
 583  0
         return found;
 584  
 
 585  
    } // end findElement
 586  
 
 587  
 
 588  
     /**
 589  
      * Convenience method that calls
 590  
      * <code>findCollection(Object,String,Object[])</code>
 591  
      * with appropriate parameters.
 592  
      */
 593  
     public Collection findCollection(Object target,
 594  
         String command) throws ResourceException {
 595  
 
 596  
         try {
 597  
 
 598  0
             return StatementUtils.getCollection(null,
 599  
                 target,lookup(command));
 600  
 
 601  
         }
 602  0
         catch (SQLException e) {
 603  0
             throw new ResourceException(e);
 604  
         }
 605  
 
 606  
     } // end findCollection
 607  
 
 608  
 
 609  
     /**
 610  
      * Convenience method that calls
 611  
      * <code>findCollection(Object,String,Object[])</code>
 612  
      * with appropriate parameters.
 613  
      */
 614  
     protected final Collection findCollection(Object target,
 615  
         String command, int parameter) throws ResourceException {
 616  
 
 617  
 
 618  
         try {
 619  
 
 620  0
             return StatementUtils.getCollection(null,
 621  
                 target,lookup(command),parameter);
 622  
 
 623  
         }
 624  0
         catch (SQLException e) {
 625  0
             throw new ResourceException(e);
 626  
         }
 627  
     } // end findCollection
 628  
 
 629  
 
 630  
 
 631  
     /**
 632  
      * Convenience method that calls
 633  
      * <code>findCollection(Object,String,Object[])</code>
 634  
      * with appropriate parameters.
 635  
      */
 636  
     protected final Collection findCollection(Object target,
 637  
         String command, Object parameter) throws ResourceException {
 638  
 
 639  
         try {
 640  
 
 641  0
             return StatementUtils.getCollection(null,
 642  
                 target,lookup(command),parameter);
 643  
 
 644  
         }
 645  0
         catch (SQLException e) {
 646  0
             throw new ResourceException(e);
 647  
         }
 648  
 
 649  
     } // end findCollection
 650  
 
 651  
 
 652  
         // See interface for JavaDoc
 653  
     public Collection findCollection(Object target,
 654  
         String command, Object[] parameters) throws ResourceException {
 655  
 
 656  
         try {
 657  
 
 658  0
             return StatementUtils.getCollection(null,
 659  
                 target,lookup(command),parameters);
 660  
 
 661  
         }
 662  0
         catch (SQLException e) {
 663  0
             throw new ResourceException(e);
 664  
         }
 665  
 
 666  
     } // end findCollection
 667  
 
 668  
 
 669  
         // See interface for JavaDoc
 670  
     public Collection findByProperty(
 671  
             Object target,
 672  
             String property,
 673  
             String value) throws ParameterException, PopulateException,
 674  
             ResourceException {
 675  
 
 676  0
          return SearchUtils.getCollection(target,
 677  
             Engine.getHits(
 678  
                 Engine.getQuery(value,property)));
 679  
 
 680  
     } // end findByProperty
 681  
 
 682  
 
 683  
 // ================================================================ UD Methods
 684  
 
 685  
     /**
 686  
      * The storageKey field, if needed.
 687  
      * <p>
 688  
      * Many subclasses may choose to ingore this field and
 689  
      * use the storageKey property as a wrapper around
 690  
      * their own field of a specific type (e.g. 
 691  
      * an Integer primaryKey property).
 692  
      */
 693  0
     private Object storageKey = null;
 694  
 
 695  
 
 696  
         // See interface for JavaDoc
 697  
     public Object getStorageKey() {
 698  0
         return this.storageKey;
 699  
     }
 700  
 
 701  
 
 702  
         // See interface for JavaDoc
 703  
     public void setStorageKey(Object storageKey) {
 704  0
         this.storageKey = storageKey;
 705  0
     }
 706  
 
 707  
     /**
 708  
      * The timestamp of the last edit.
 709  
      * <p>
 710  
      * This can be checked against the edited
 711  
      * timestamp on the record in storage
 712  
      * to see if anyone else has alreaded
 713  
      * edited the record.
 714  
      */
 715  0
     private Timestamp modified = ConvertUtils.NULL_TIMESTAMP;
 716  
 
 717  
     /**
 718  
      * Return the edited timestamp.
 719  
      * <p>
 720  
      * @return the edited timestamp.
 721  
      */
 722  
     public Timestamp getModified() {
 723  0
         return (this.modified);
 724  
     }
 725  
 
 726  
 
 727  
     /**
 728  
      * Set the edited timestamp.
 729  
      * @param edited The new edited timestamp.
 730  
      */
 731  
     public void setModified(Timestamp modified) {
 732  0
         this.modified = modified;
 733  0
     }
 734  
 
 735  
 
 736  
     /**
 737  
      * Check to see if another modified timetamp
 738  
      * matches the one for this instance.
 739  
      * Returns true if the timestamps match.
 740  
      * @returns true if the timestamps match.
 741  
      * @param edited The new edited timestamp.
 742  
      */
 743  
     public boolean isCurrent(Timestamp modified) {
 744  0
         return (modified!=getModified());
 745  
     }
 746  
 
 747  
 
 748  
     /**
 749  
      * [:TODO: Javadoc]
 750  
      */
 751  0
     private int resultCode = 0;
 752  
 
 753  
 
 754  
         // See interface for JavaDoc
 755  
     public int getResultCode() {
 756  0
         return resultCode;
 757  
     }
 758  
 
 759  
 
 760  
         // See interface for JavaDoc
 761  
     public void setResultCode(int resultCode) {
 762  0
         this.resultCode = resultCode;
 763  0
     }
 764  
 
 765  
 
 766  
     /**
 767  
      * [:TODO: Javadoc]
 768  
      */
 769  0
     private Object result = this;
 770  
 
 771  
 
 772  
         // See interface for JavaDoc
 773  
     public Object getResult() {
 774  0
         return result;
 775  
     }
 776  
 
 777  
 
 778  
         // See interface for JavaDoc
 779  
     public void setResult(Object result) {
 780  0
         this.result = result;
 781  0
     }
 782  
 
 783  
 
 784  
 // --------------------------------------------------------------------- store
 785  
 
 786  
 
 787  
     /**
 788  
      * If timestamp is null (or ConvertUtils.NULL_TIMESTAMP), 
 789  
      * set our modified property to the current time. 
 790  
      * This emulates how MySQL treats the first null Timestamp in a record.
 791  
      */
 792  
    public void fixModified() {   
 793  0
        Timestamp modified = getModified();
 794  0
        if ((null==modified) || (ConvertUtils.NULL_TIMESTAMP==modified)) {
 795  0
            setModified(new Timestamp(System.currentTimeMillis()));
 796  
        }
 797  0
    }
 798  
            
 799  
    
 800  
    public int updateResultCode(String command) throws ResourceException {     
 801  
        
 802  0
         int result = 0;
 803  
         try {
 804  
 
 805  0
             result = StatementUtils.executeUpdate(
 806  
                 null,lookup(command),getParameters(command));
 807  
 
 808  
         }
 809  0
         catch (SQLException e) {
 810  0
             throw new ResourceException(e);
 811  0
         }
 812  
         
 813  0
         return result;
 814  
    }
 815  
 
 816  
         // see interface for Javadoc
 817  
     public Object update(Object parameters) throws Exception {
 818  
         
 819  0
         populate((Map) parameters);
 820  
         
 821  0
         String command = getParameter();
 822  
 
 823  0
         fixModified();
 824  0
         setResultCode(updateResultCode(command));
 825  
 
 826  0
         String message = null;
 827  0
         if (isNew()) message = Tokens.DATA_RECORD_INSERTED;
 828  0
         else message = Tokens.DATA_RECORD_UPDATED;
 829  
 
 830  0
         ProcessResult result = new ProcessResultBase(getResult());
 831  0
             result.addMessage(message);
 832  0
             result.addMessage(getStorageKey());
 833  0
             result.setSingleForm(true);
 834  0
         return result;
 835  
     }
 836  
 
 837  
 
 838  
     public ProcessResult elementResult(String command) throws Exception {
 839  
 
 840  0
         boolean found = false;
 841  
         try {
 842  
 
 843  0
             found = StatementUtils.getElement(null,this,
 844  
                 lookup(command),getParameters(command));
 845  
 
 846  
         }
 847  0
         catch (SQLException e) {
 848  0
             throw new ResourceException(e);
 849  0
         }
 850  
 
 851  0
         if (found) {
 852  
 
 853  0
             setResult(this);
 854  0
             setResultCode(1);
 855  
 
 856  
         }
 857  
         else {
 858  0
             setResultCode(0);
 859  
         }
 860  
 
 861  0
         ProcessResult result = new ProcessResultBase(this);
 862  0
             result.setSingleForm(true);
 863  0
          return result;         
 864  
     }
 865  
 
 866  
 
 867  
     /**
 868  
      * Retrieve an element (record) from storage.
 869  
      * The element is retrieved is determined by what command 
 870  
      * has been set to the parameter property.
 871  
      * <P>
 872  
      * This signature is designed for compatibilty with
 873  
      * the Executable interface.
 874  
      */
 875  
     public Object element(Object command) throws Exception {
 876  
 
 877  0
         populate((Map) command);
 878  
         
 879  0
         return elementResult(getParameter());       
 880  
         
 881  
     }
 882  
 
 883  
 
 884  
     public Object collectionResult(String command) throws Exception {
 885  
         
 886  0
         Collection result = null;
 887  
 
 888  
         try {
 889  
 
 890  0
             result = StatementUtils.getCollection(null,
 891  
                 this,lookup(command),getParameters(command));
 892  
 
 893  
         }
 894  0
         catch (SQLException e) {
 895  0
             throw new ResourceException(e);
 896  0
         }
 897  
 
 898  0
         setResult(result);
 899  
 
 900  0
         return new ProcessResultBase(result);
 901  
         
 902  
     }
 903  
 
 904  
         
 905  
     /**
 906  
      * Retrieve a collection of objects from storage.
 907  
      * The objects retrieved is determined by what command 
 908  
      * has been set to the parameter property.
 909  
      * <P>
 910  
      * This signature is designed for compatibilty with
 911  
      * the Executable interface.
 912  
      */
 913  
     public Object collection(Object parameters) throws Exception {
 914  
 
 915  0
         populate((Map) parameters);
 916  
         
 917  0
         return collectionResult(getParameter());
 918  
 
 919  
     }
 920  
 
 921  
 // --------------------------------------------------------------------- store
 922  
 
 923  
     /**
 924  
      * [:TODO: Javadoc]
 925  
      */
 926  0
     public static String KEYS_NEXT = "keys.next";
 927  
 
 928  
 
 929  
     /**
 930  
      * [:TODO: Javadoc]
 931  
      */
 932  0
     public static String KEYS_INC = "keys.inc";
 933  
 
 934  
 
 935  
         // See interface for JavaDoc
 936  
     public boolean isNew() {
 937  0
         Object key = getStorageKey();
 938  0
         return ((null==key) || (blankValue(key.toString())));
 939  
     }
 940  
 
 941  
 
 942  
         // See interface for JavaDoc
 943  
         // @todo Refactor to use fixed-length high/low String as key.
 944  
     public Object createKey(String keyName)
 945  
             throws ResourceException {
 946  
 
 947  0
         Object result = null;
 948  
 
 949  
         try {
 950  
 
 951  0
             result = StatementUtils.createKey(
 952  
                 null,
 953  
                 1,
 954  
                 lookupRoot(KEYS_NEXT),
 955  
                 lookup(keyName),
 956  
                 lookupRoot(KEYS_INC)
 957  
             );
 958  
         }
 959  
 
 960  0
         catch (SQLException e) {
 961  0
             throw new ResourceException(e);
 962  0
         }
 963  
 
 964  0
         return result;
 965  
 
 966  
     } // end createKey()
 967  
 
 968  
 
 969  
         // See interface for JavaDoc
 970  
     public void allocateKey() throws Exception {
 971  
 
 972  0
         setStorageKey(createKey(TABLE));
 973  
 
 974  0
     }
 975  
 
 976  
 
 977  
         // see interface for Javadoc
 978  
         // INSERT The name of the insert command
 979  
         // UPDATE The name of the delete command
 980  
     public void store() throws Exception {
 981  
 
 982  0
         boolean isInsert = isNew();
 983  0
         String token = null;
 984  0
         if (isInsert) { 
 985  0
             token = INSERT; 
 986  0
             allocateKey();
 987  
         }
 988  
         else {
 989  0
             token = UPDATE;
 990  
         }
 991  
 
 992  0
         String command = lookup(token);
 993  
 
 994  0
         Timestamp modified = getModified();
 995  0
         if ((null==modified) || (ConvertUtils.NULL_TIMESTAMP==modified)) {
 996  0
             setModified(new Timestamp(System.currentTimeMillis()));
 997  
         }
 998  
         
 999  
         // :FIXME: Way to get remoteNode
 1000  
 
 1001  0
         int result = 0;
 1002  
         try {
 1003  
 
 1004  0
             result = StatementUtils.executeUpdate(
 1005  
                 null,command,getParameters(token));
 1006  
 
 1007  
         }
 1008  0
         catch (SQLException e) {
 1009  0
             throw new ResourceException(e);
 1010  0
         }
 1011  0
         setResultCode(result);
 1012  
 
 1013  0
     }
 1014  
 
 1015  
 
 1016  
     /**
 1017  
      * Commit record to storage.
 1018  
      * If storageKey is null, new storage for this object is created.
 1019  
      * Otherwise, an existing object is updated.
 1020  
      * @return ProcessResult with messages and this object as data
 1021  
      * @exception ResourceException if data access error occurs
 1022  
      @ @parameters The properties to use with operation
 1023  
      *
 1024  
      */
 1025  
     public Object store(Object parameters) throws Exception {
 1026  
 
 1027  0
         populate((Map) parameters);
 1028  
 
 1029  0
         String message = null;
 1030  0
         if (isNew()) message = Tokens.DATA_RECORD_INSERTED;
 1031  0
         else message = Tokens.DATA_RECORD_UPDATED;
 1032  
 
 1033  0
         store();
 1034  
 
 1035  0
         ProcessResult result = new ProcessResultBase(getResult());
 1036  0
             result.addMessage(message);
 1037  0
             result.addMessage(getStorageKey());
 1038  0
             result.setSingleForm(true);
 1039  0
         return result;
 1040  
     }
 1041  
 
 1042  
 
 1043  
 // ------------------------------------------------------------------ retrieve
 1044  
 
 1045  
         // see interface for Javadoc
 1046  
     public void retrieve() throws Exception {
 1047  
 
 1048  0
         boolean found = findElement(this,RETRIEVE,getStorageKey());
 1049  
 
 1050  0
         if (found) {
 1051  
 
 1052  0
             setResult(this);
 1053  0
             setResultCode(1);
 1054  
 
 1055  
         }
 1056  
         else {
 1057  0
             setResultCode(0);
 1058  
         }
 1059  
 
 1060  0
     }
 1061  
 
 1062  
         // see interface for Javadoc
 1063  
     public Object retrieve(Object parameters) throws Exception {
 1064  
 
 1065  0
         populate((Map) parameters);
 1066  0
         Object key = getStorageKey();
 1067  0
         if (null==key) {
 1068  0
             throw new ParameterException();
 1069  
         }
 1070  
 
 1071  0
         retrieve();
 1072  0
         int resultCode = getResultCode();
 1073  
 
 1074  0
         ProcessResult result = new ProcessResultBase(this);
 1075  0
             if (0==resultCode) {
 1076  0
                 result.addMessage(Tokens.DATA_ACCESS_EMPTY);
 1077  
             }
 1078  
             else {
 1079  0
                 result.addMessage(Tokens.DATA_RECORD_RETRIEVED);
 1080  
             }
 1081  0
             result.addMessage(key);
 1082  0
             result.setSingleForm(true);
 1083  
 
 1084  0
         return result;
 1085  
 
 1086  
     } // end retrieve
 1087  
 
 1088  
 
 1089  
 // -------------------------------------------------------------------- delete
 1090  
 
 1091  
 
 1092  
         // see interface for Javadoc
 1093  
     public void delete() throws Exception {
 1094  
 
 1095  0
         retrieve();
 1096  0
         int result = getResultCode();
 1097  
 
 1098  0
         if (0!=result) {
 1099  
 
 1100  
             try {
 1101  
 
 1102  
                 // Mark as deleted
 1103  0
                 result = StatementUtils.executeUpdate(null,
 1104  
                     lookup(DELETE),getStorageKey());
 1105  
             }
 1106  
 
 1107  0
             catch (SQLException e) {
 1108  0
                 throw new ResourceException(e);
 1109  0
             }
 1110  
 
 1111  0
             setResultCode(result);
 1112  
         }
 1113  
 
 1114  0
     }
 1115  
 
 1116  
 
 1117  
     /**
 1118  
      * [:TODO: Javadoc]
 1119  
      */
 1120  
     public Object delete(Object parameters) throws Exception {
 1121  
 
 1122  0
         populate((Map) parameters);
 1123  0
         Object key = getStorageKey();
 1124  0
         if (null==key) {
 1125  0
             throw new ParameterException();
 1126  
         }
 1127  
 
 1128  0
         delete();
 1129  0
         int resultCode = getResultCode();
 1130  
 
 1131  0
         ProcessResult result = new ProcessResultBase(this);
 1132  0
            if (0==resultCode) {
 1133  0
                 result.addMessage(Tokens.DATA_ACCESS_EMPTY);
 1134  
             }
 1135  
             else {
 1136  0
                 result.addMessage(Tokens.DATA_RECORD_DELETED);
 1137  
             }
 1138  0
             result.addMessage(key);
 1139  0
             result.setSingleForm(true);
 1140  
 
 1141  0
         return result;
 1142  
 
 1143  
     } // end delete
 1144  
 
 1145  
 
 1146  
 // -------------------------------------------------------------------- recycle
 1147  
 
 1148  
 
 1149  
         // see interface for Javadoc
 1150  
     public void recycle() throws Exception {
 1151  
 
 1152  0
         retrieve();
 1153  0
         int result = getResultCode();
 1154  
 
 1155  0
         if (0!=result) {
 1156  
 
 1157  
             try {
 1158  
 
 1159  
                 // Mark as recycled
 1160  0
                 result = StatementUtils.executeUpdate(null,
 1161  
                     lookup(RECYCLE),getStorageKey());
 1162  
             }
 1163  
 
 1164  0
             catch (SQLException e) {
 1165  0
                 throw new ResourceException(e);
 1166  0
             }
 1167  
 
 1168  0
             setResultCode(result);
 1169  
         }
 1170  
 
 1171  0
     }
 1172  
 
 1173  
 
 1174  
         // see interface for Javadoc
 1175  
     public Object recycle(Object parameters) throws Exception {
 1176  
 
 1177  0
         populate((Map) parameters);
 1178  0
         Object key = getStorageKey();
 1179  0
         if (null==key) {
 1180  0
             throw new ParameterException();
 1181  
         }
 1182  
 
 1183  0
         recycle();
 1184  0
         int resultCode = getResultCode();
 1185  
 
 1186  0
         ProcessResult result = new ProcessResultBase(this);
 1187  0
            if (resultCode==0) {
 1188  0
                 result.addMessage(Tokens.DATA_ACCESS_EMPTY);
 1189  
             }
 1190  
             else {
 1191  0
                 result.addMessage(Tokens.DATA_RECORD_RECYCLED);
 1192  
             }
 1193  0
             result.addMessage(key);
 1194  0
             result.setSingleForm(true);
 1195  
 
 1196  0
         return result;
 1197  
 
 1198  
     } // end recycle
 1199  
 
 1200  
 
 1201  
 // ------------------------------------------------------------------- restore
 1202  
 
 1203  
     /**
 1204  
      * Unmark entry for deletion.
 1205  
      * Returns copy of restored entry in target parameter.
 1206  
      *
 1207  
      * @return 0 if fails
 1208  
      * @exception ResourceException if data access error occurs
 1209  
      * @param target Bean to hold copy of record being unmarked
 1210  
      * @param article Primary key of record to unmark
 1211  
      */
 1212  
     public void restore() throws Exception {
 1213  
 
 1214  0
         int result = 0;
 1215  
 
 1216  
         try {
 1217  
 
 1218  0
             result = StatementUtils.executeUpdate(null,
 1219  
                 lookup(RESTORE),getStorageKey());
 1220  
 
 1221  
         }
 1222  0
         catch (SQLException e) {
 1223  0
             throw new ResourceException(e);
 1224  0
         }
 1225  
 
 1226  0
         setResultCode(result);
 1227  
 
 1228  0
     } // end restore
 1229  
 
 1230  
 
 1231  
    /**
 1232  
      * Update indicated entry in data storage.
 1233  
      * Return confirmation message in a ProcessResult object.
 1234  
      *
 1235  
      * @param parameters The map or other object to use with this
 1236  
      * operation
 1237  
      * @throws ParameterException if article not found in parameters
 1238  
      * @throws ResourceException if SQLException or other data exception
 1239  
      */
 1240  
     public Object restore(Object parameters) throws Exception {
 1241  
 
 1242  0
         populate((Map) parameters);
 1243  0
         Object key = getStorageKey();
 1244  0
         if (null==key) {
 1245  0
             throw new ParameterException();
 1246  
         }
 1247  
 
 1248  0
         restore();
 1249  0
         int resultCode = getResultCode();
 1250  
 
 1251  0
         ProcessResult result = new ProcessResultBase(this);
 1252  0
            if (0==resultCode) {
 1253  0
                 result.addMessage(Tokens.DATA_ACCESS_EMPTY);
 1254  
             }
 1255  
             else {
 1256  0
                 result.addMessage(Tokens.DATA_RECORD_RESTORED);
 1257  
             }
 1258  0
             result.addMessage(key);
 1259  0
             result.setSingleForm(true);
 1260  
 
 1261  0
         return result;
 1262  
 
 1263  
     } // end restore
 1264  
 
 1265  
 } // end StorageBeanBase
 1266