1<?xml version="1.0" encoding="UTF-8" standalone="no"?> 2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 3<html xmlns="http://www.w3.org/1999/xhtml"> 4 <head> 5 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 6 <title>Program Listing</title> 7 <link rel="stylesheet" href="gettingStarted.css" type="text/css" /> 8 <meta name="generator" content="DocBook XSL Stylesheets V1.62.4" /> 9 <link rel="home" href="index.html" title="Getting Started with Replicated Berkeley DB Applications" /> 10 <link rel="up" href="txnapp.html" title="Chapter 2. Transactional Application" /> 11 <link rel="previous" href="txnapp.html" title="Chapter 2. Transactional Application" /> 12 <link rel="next" href="repapp.html" title="Chapter 3. The DB Replication Framework" /> 13 </head> 14 <body> 15 <div class="navheader"> 16 <table width="100%" summary="Navigation header"> 17 <tr> 18 <th colspan="3" align="center">Program Listing</th> 19 </tr> 20 <tr> 21 <td width="20%" align="left"><a accesskey="p" href="txnapp.html">Prev</a> </td> 22 <th width="60%" align="center">Chapter 2. Transactional Application</th> 23 <td width="20%" align="right"> <a accesskey="n" href="repapp.html">Next</a></td> 24 </tr> 25 </table> 26 <hr /> 27 </div> 28 <div class="sect1" lang="en" xml:lang="en"> 29 <div class="titlepage"> 30 <div> 31 <div> 32 <h2 class="title" style="clear: both"><a id="simpleprogramlisting"></a>Program Listing</h2> 33 </div> 34 </div> 35 <div></div> 36 </div> 37 <p> 38 Our example program is a fairly simple transactional 39 application. At this early stage of its development, the 40 application contains no hint that it must be network-aware 41 so the only command line argument that it takes is one that 42 allows us to specify the environment home directory. 43 (Eventually, we will specify things like host names and 44 ports from the command line). 45 </p> 46 <p> 47 Note that the application performs all writes under the 48 protection of a transaction; however, multiple database 49 operations are not performed per transaction. Consequently, 50 we simplify things a bit by using autocommit for our 51 database writes. 52 </p> 53 <p> 54 Also, this application is single-threaded. It is possible 55 to write a multi-threaded or multi-process application that 56 performs replication. That said, the concepts described in 57 this book are applicable to both single threaded and 58 multi-threaded applications so nothing 59 is gained by multi-threading this application other than 60 distracting complexity. This manual 61 does, however, identify where care must be taken when 62 performing replication with a non-single threaded 63 application. 64 </p> 65 <p> 66 Finally, remember that transaction processing is not described in 67 this manual. Rather, see the 68 <i class="citetitle">Berkeley DB Getting Started with Transaction Processing</i> guide for details on 69 that topic. 70 </p> 71 <div class="sect2" lang="en" xml:lang="en"> 72 <div class="titlepage"> 73 <div> 74 <div> 75 <h3 class="title"><a id="repconfiginfo_cxx"></a> 76 77 <span>Class: RepConfig</span> 78 </h3> 79 </div> 80 </div> 81 <div></div> 82 </div> 83 <p> 84 Before we begin, we present a 85 class that we will use to maintain useful 86 information for us. Under normal circumstances, 87 this class would not be necessary for a simple 88 transactional example such as this. However, this code will 89 grow into a replicated example that needs to 90 track a lot more information for the 91 application, and so we lay the groundwork for 92 it here. 93 </p> 94 <p> 95 The class that we create is called 96 97 <tt class="classname">RepConfig</tt> 98 and its only purpose at this time is to track 99 the location of our environment home directory. 100 </p> 101 <pre class="programlisting">package db.simpletxn; 102 103public class RepConfig 104{ 105 // Constant values used in the RepQuote application. 106 public static final String progname = "SimpleTxn"; 107 public static final int CACHESIZE = 10 * 1024 * 1024; 108 109 // member variables containing configuration information 110 public String home; // String specifying the home directory for 111 // rep files. 112 113 public RepConfig() 114 { 115 home = "TESTDIR"; 116 } 117 118 public java.io.File getHome() 119 { 120 return new java.io.File(home); 121 } 122 123} </pre> 124 </div> 125 <div class="sect2" lang="en" xml:lang="en"> 126 <div class="titlepage"> 127 <div> 128 <div> 129 <h3 class="title"><a id="simpletxnusage_java"></a>Class: SimpleTxn</h3> 130 </div> 131 </div> 132 <div></div> 133 </div> 134 <p> 135 Our transactional example will 136 consist of a class, 137 <tt class="classname">SimpleTxn</tt>, that performs 138 all our work for us. 139 </p> 140 <p> 141 First, we provide the package declaration and 142 then a few import statements that the class 143 needs. 144 </p> 145 <pre class="programlisting">package db.simpletxn; 146 147import java.io.FileNotFoundException; 148import java.io.BufferedReader; 149import java.io.InputStreamReader; 150import java.io.IOException; 151import java.io.UnsupportedEncodingException; 152 153import com.sleepycat.db.Cursor; 154import com.sleepycat.db.Database; 155import com.sleepycat.db.DatabaseConfig; 156import com.sleepycat.db.DatabaseEntry; 157import com.sleepycat.db.DatabaseException; 158import com.sleepycat.db.DatabaseType; 159import com.sleepycat.db.Environment; 160import com.sleepycat.db.EnvironmentConfig; 161import com.sleepycat.db.LockMode; 162import com.sleepycat.db.OperationStatus; 163import db.simpletxn.RepConfig; 164 165public class SimpleTxn 166{ 167 private RepConfig repConfig; 168 private Environment dbenv; </pre> 169 <p> 170 Next, we provide our class constructor. This simply initializes our 171 class data members. 172</p> 173 <pre class="programlisting"> public SimpleTxn() 174 throws DatabaseException 175 { 176 repConfig = null; 177 dbenv = null; 178 } </pre> 179 <p> 180 And then we provide our <tt class="methodname">usage()</tt> method. At 181 this point, this method has very little to report: 182</p> 183 <pre class="programlisting"> public static void usage() 184 { 185 System.err.println("usage: " + repConfig.progname); 186 System.err.println("[-h home]"); 187 188 System.err.println("\t -h home directory\n"); 189 190 System.exit(1); 191 } </pre> 192 </div> 193 <div class="sect2" lang="en" xml:lang="en"> 194 <div class="titlepage"> 195 <div> 196 <div> 197 <h3 class="title"><a id="simpletxnmain_java"></a>Method: SimpleTxn.main()</h3> 198 </div> 199 </div> 200 <div></div> 201 </div> 202 <p> 203 Having implemented our 204 <tt class="methodname">usage()</tt> 205 method, we can jump directly into our 206 <tt class="methodname">main()</tt> 207 method. This method begins by instantiating a 208 <tt class="classname">RepConfig</tt> object, and 209 then collecting the command line arguments so 210 that it can populate the object with the 211 appropriate data (just the environment home 212 directory, at this time): 213 </p> 214 <pre class="programlisting"> public static void main(String[] argv) 215 throws Exception 216 { 217 RepConfig config = new RepConfig(); 218 // Extract the command line parameters 219 for (int i = 0; i < argv.length; i++) 220 { 221 if (argv[i].compareTo("-h") == 0) { 222 // home - a string arg. 223 i++; 224 config.home = argv[i]; 225 } else { 226 System.err.println("Unrecognized option: " + argv[i]); 227 usage(); 228 } 229 } </pre> 230 <p> 231 And then perform a little sanity checking on the command line 232 input: 233</p> 234 <pre class="programlisting"> // Error check command line. 235 if (config.home.length() == 0) 236 usage(); </pre> 237 <p> 238 Now we perform the class' work. To begin, we initialize the 239 object. The <tt class="methodname">init()</tt> method actually 240 opens our environment for us (shown in the next section). 241 </p> 242 <pre class="programlisting"> SimpleTxn runner = null; 243 try { 244 runner = new SimpleTxn(); 245 runner.init(config); </pre> 246 <p> 247 And then we call our <tt class="methodname">doloop()</tt> 248 method. This method is where we perform all our database 249 activity. See <a href="simpleprogramlisting.html#doloop_java">Method: SimpleTxn.doloop()</a> 250 for it's details. 251 </p> 252 <pre class="programlisting"> runner.doloop(); </pre> 253 <p> 254 And then, finally terminate the application (which closes our 255 environment handle) and end the method. 256 </p> 257 <pre class="programlisting"> runner.terminate(); 258 } catch (DatabaseException dbe) { 259 System.err.println("Caught an exception during " + 260 "initialization or processing: " + dbe.toString()); 261 if (runner != null) 262 runner.terminate(); 263 } 264 System.exit(0); 265 } // end main </pre> 266 </div> 267 <div class="sect2" lang="en" xml:lang="en"> 268 <div class="titlepage"> 269 <div> 270 <div> 271 <h3 class="title"><a id="simpletxn_init_java"></a>Method: SimpleTxn.init()</h3> 272 </div> 273 </div> 274 <div></div> 275 </div> 276 <p> 277 The <tt class="methodname">SimpleTxn.init()</tt> 278 method is used to open our environment handle. 279 For readers familiar with writing transactional 280 DB applications, there should be no surprises 281 here. However, we will be adding to this in later 282 chapters as we roll replication into this example. 283 </p> 284 <p> 285 The only thing worth noting in this method here is that 286 we relax our transactional durability guarantee for this application. 287 We do this because the application will eventually be replicated and 288 so we don't need a high durability guarantee. 289</p> 290 <pre class="programlisting"> public int init(RepConfig config) 291 throws DatabaseException 292 { 293 int ret = 0; 294 repConfig = config; 295 EnvironmentConfig envConfig = new EnvironmentConfig(); 296 envConfig.setErrorStream(System.err); 297 envConfig.setErrorPrefix(RepConfig.progname); 298 299 envConfig.setCacheSize(RepConfig.CACHESIZE); 300 envConfig.setTxnNoSync(true); 301 302 envConfig.setAllowCreate(true); 303 envConfig.setRunRecovery(true); 304 envConfig.setInitializeLocking(true); 305 envConfig.setInitializeLogging(true); 306 envConfig.setInitializeCache(true); 307 envConfig.setTransactional(true); 308 try { 309 dbenv = new Environment(repConfig.getHome(), envConfig); 310 } catch(FileNotFoundException e) { 311 System.err.println("FileNotFound exception: " + e.toString()); 312 System.err.println( 313 "Ensure that the environment directory is pre-created."); 314 ret = 1; 315 } 316 317 return ret; 318 } </pre> 319 <p> 320 Finally, we present the <tt class="methodname">SimpleTxn.terminate()</tt> 321 method here. All this does is close the environment handle. Again, 322 there should be no surprises here, but we provide the 323 implementation for the sake of completeness anyway. 324</p> 325 <pre class="programlisting"> public void terminate() 326 throws DatabaseException 327 { 328 dbenv.close(); 329 } </pre> 330 </div> 331 <div class="sect2" lang="en" xml:lang="en"> 332 <div class="titlepage"> 333 <div> 334 <div> 335 <h3 class="title"><a id="doloop_java"></a>Method: SimpleTxn.doloop()</h3> 336 </div> 337 </div> 338 <div></div> 339 </div> 340 <p> 341 We now implement our application's 342 primary data processing method. This 343 method provides a command prompt at which the 344 user can enter a stock ticker value and a price for 345 that value. This information is then entered to the 346 database. 347 </p> 348 <p> 349 To display the database, simply enter 350 <tt class="literal">return</tt> at the prompt. 351 </p> 352 <p> 353 To begin, we declare a database pointer: 354 </p> 355 <pre class="programlisting"> public int doloop() 356 throws DatabaseException, , UnsupportedEncodingException 357 { 358 Database db = null; </pre> 359 <p> 360 Next, we begin the loop and we immediately open our 361 database if it has not already been opened. 362 </p> 363 <pre class="programlisting"> for (;;) 364 { 365 if (db == null) { 366 DatabaseConfig dbconf = new DatabaseConfig(); 367 // Set page size small so page allocation is cheap. 368 dbconf.setPageSize(512); 369 dbconf.setType(DatabaseType.BTREE); 370 dbconf.setAllowCreate(true); 371 dbconf.setTransactional(true); 372 373 try { 374 db = dbenv.openDatabase(null, // Txn handle 375 RepConfig.progname, // db filename 376 null, // db name 377 dbconf); 378 } catch (FileNotFoundException fnfe) { 379 System.err.println("File not found exception" + fnfe.toString()); 380 // Get here only if the environment home directory 381 // somehow does not exist. 382 } 383 } </pre> 384 <p> 385 Now we implement our command prompt. This is a simple and not 386 very robust implementation of a command prompt. 387 If the user enters the keywords <tt class="literal">exit</tt> 388 or <tt class="literal">quit</tt>, the loop is exited and the 389 application ends. If the user enters nothing and instead simply 390 presses <tt class="literal">return</tt>, the entire contents of the 391 database is displayed. We use our 392 <tt class="methodname">printStocks()</tt> method to display the 393 database. (That implementation is shown next in this chapter.) 394 </p> 395 <p> 396 Notice that very little error checking is performed on the data 397 entered at this prompt. If the user fails to enter at least one 398 space in the value string, a simple help message is printed and 399 the prompt is returned to the user. That is the only error 400 checking performed here. In a real-world application, 401 at a minimum the application would probably check to ensure 402 that the price was in fact an integer or float value. 403 However, in order to keep this example code as simple as 404 possible, we refrain from implementing a thorough user interface. 405 </p> 406 <pre class="programlisting"> BufferedReader stdin = 407 new BufferedReader(new InputStreamReader(System.in)); 408 409 // listen for input, and add it to the database. 410 System.out.print("QUOTESERVER> "); 411 System.out.flush(); 412 String nextline = null; 413 try { 414 nextline = stdin.readLine(); 415 } catch (IOException ioe) { 416 System.err.println("Unable to get data from stdin"); 417 break; 418 } 419 String[] words = nextline.split("\\s"); 420 421 // A blank line causes the DB to be dumped to stdout. 422 if (words.length == 0 || 423 (words.length == 1 && words[0].length() == 0)) { 424 try { 425 printStocks(db); 426 } catch (DatabaseException e) { 427 System.err.println("Got db exception reading " + 428 "DB: " + e.toString()); 429 break; 430 } 431 continue; 432 } 433 434 if (words.length == 1 && 435 (words[0].compareToIgnoreCase("quit") == 0 || 436 words[0].compareToIgnoreCase("exit") == 0)) { 437 break; 438 } else if (words.length != 2) { 439 System.err.println("Format: TICKER VALUE"); 440 continue; 441 } </pre> 442 <p> 443 Now we assign data to the <tt class="classname">DatabaseEntry</tt> 444 classes that we will use to write the new information to the database. 445 </p> 446 <pre class="programlisting"> DatabaseEntry key = 447 new DatabaseEntry(words[0].getBytes("UTF-8")); 448 DatabaseEntry data = 449 new DatabaseEntry(words[1].getBytes("UTF-8")); </pre> 450 <p> 451 Having done that, we can write the new information to the 452 database. Remember that because a transaction handle is not 453 explicitly used, but we did open the database such that it 454 supports transactions, then autocommit is automatically 455 used for this database write. 456 </p> 457 <p> 458 Autocommit is described in the 459 <i class="citetitle">Berkeley DB Getting Started with Transaction Processing</i> guide. 460 </p> 461 <p> 462 Also, the database is not configured for duplicate records, so 463 the data portion of a record is overwritten if the provided 464 key already exists in the database. However, in this case 465 DB returns <tt class="methodname">OperationStatus.KEYEXIST</tt> — which 466 we ignore. 467 </p> 468 <pre class="programlisting"> db.put(null, key, data); </pre> 469 <p> 470 Finally, we close our database before returning from the 471 method. 472 </p> 473 <pre class="programlisting"> } 474 if (db != null) 475 db.close(true); 476 return 0; 477 } </pre> 478 </div> 479 <div class="sect2" lang="en" xml:lang="en"> 480 <div class="titlepage"> 481 <div> 482 <div> 483 <h3 class="title"><a id="printstocks_c"></a> 484 485 486 <span>Method: SimpleTxn.printStocks()</span> 487 </h3> 488 </div> 489 </div> 490 <div></div> 491 </div> 492 <p> 493 The 494 <tt class="methodname">printStocks()</tt> 495 496 <span>method</span> 497 simply takes a database handle, opens a cursor, and uses 498 it to display all the information it finds in a database. 499 This is trivial cursor operation that should hold 500 no surprises for you. We simply provide it here for 501 the sake of completeness. 502 </p> 503 <p> 504 If you are unfamiliar with basic cursor operations, 505 please see the <i class="citetitle">Getting Started with Berkeley DB</i> 506 guide. 507 </p> 508 <pre class="programlisting"> public void terminate() 509 throws DatabaseException 510 { 511 dbenv.close(); 512 } 513 514 /* 515 * void return type since error conditions are propagated 516 * via exceptions. 517 */ 518 private void printStocks(Database db) 519 throws DatabaseException 520 { 521 Cursor dbc = db.openCursor(null, null); 522 523 System.out.println("\tSymbol\tPrice"); 524 System.out.println("\t======\t====="); 525 526 DatabaseEntry key = new DatabaseEntry(); 527 DatabaseEntry data = new DatabaseEntry(); 528 OperationStatus ret; 529 for (ret = dbc.getFirst(key, data, LockMode.DEFAULT); 530 ret == OperationStatus.SUCCESS; 531 ret = dbc.getNext(key, data, LockMode.DEFAULT)) { 532 String keystr = new String 533 (key.getData(), key.getOffset(), key.getSize()); 534 String datastr = new String 535 (data.getData(), data.getOffset(), data.getSize()); 536 System.out.println("\t"+keystr+"\t"+datastr); 537 538 } 539 dbc.close(); 540 } 541} // end class </pre> 542 </div> 543 </div> 544 <div class="navfooter"> 545 <hr /> 546 <table width="100%" summary="Navigation footer"> 547 <tr> 548 <td width="40%" align="left"><a accesskey="p" href="txnapp.html">Prev</a> </td> 549 <td width="20%" align="center"> 550 <a accesskey="u" href="txnapp.html">Up</a> 551 </td> 552 <td width="40%" align="right"> <a accesskey="n" href="repapp.html">Next</a></td> 553 </tr> 554 <tr> 555 <td width="40%" align="left" valign="top">Chapter 2. Transactional Application </td> 556 <td width="20%" align="center"> 557 <a accesskey="h" href="index.html">Home</a> 558 </td> 559 <td width="40%" align="right" valign="top"> Chapter 3. The DB Replication Framework</td> 560 </tr> 561 </table> 562 </div> 563 </body> 564</html> 565