Abo
ut
aandx
Ba
About
utJav
ava
ndxBa
BasseJ
RolandHughes
LogikalSolutions
Copyright2010byRolandHughes
Allrightsreserved
PrintedandboundintheUnitedStatesofAmerica
ISBN13 9780982358030
ThisbookwaspublishedbyLogikalSolutionsfortheauthor.NeitherLogikalSolutionsnortheauthorshallbe
heldresponsibleforanydamage,claim,orexpenseincurredbyauserofthisbookandthecontentspresented
withinorprovidedfordownloadathttp://www.theminimumyouneedtoknow.com.
Thesetrademarksbelongtothefollowingcompanies:
Borland
BorlandSoftwareCorporation
Btrieve
BtrieveTechnologies,Inc.
CIndex/II
TrioSystemsLLC
Clipper
ComputerAssociates,Inc.
CodeBaseSoftware
SequiterInc.
CodeBase++
SequiterInc.
CommLib
GreenleafSoftware
Cygwin
RedHat,Inc.
DataBoss
KedwellSoftware
DataWindows
GreenleafSoftware
dBASE
dataBasedIntelligence,Inc.
DEC
DigitalEquipmentCorporation
DECBASIC
HewlettPackardCorporation
DECCOBOL
HewlettPackardCorporation
Foxbase
FoxSoftware
FoxPro
MicrosoftCorporation
FreeDOS
JimHall
GDB
GreenleafSoftware
HP
HewlettPackardCorporation
IBM
InternationalBusinessMachines,Inc.
Java
SunMicrosystems,Inc.
Kubuntu
CanonicalLtd.
Linux
LinusTorvals
LotusSymphony
InternationalBusinessMachines,Inc.
MAC
AppleInc.
MappppQuest
MapQuest,Inc.
MySQL
MySQLAB
Netware
Novell,Inc.
OpenVMS
HewlettPackardCorporation
OpenOffice
SunMicrosystems,Inc.
openSuSE
Novell,Inc.
ORACLE
OracleCorporation
OS/2
InternationalBusinessMachines,Inc.
Paradox
CorelCorporation
ProC
ProCCorp.
Quicken
IntuitInc.
RMS
HewlettPackardCorporation
RDB
OracleCorporation
SourceForge
SourceForge,Inc.
Ubuntu
CanonicalLtd.
Unix
VisualBasic
Watcom
Windows
ZincApplicationFramework
OpenGroup
MicrosoftCorporation
Sybase
MicrosoftCorporation
ProfessionalSoftwareAssociates,Inc.
Allothertrademarksinadvertentlymissingfromthislistaretrademarksoftheirrespectiveowners.Abesteffort
wasmadetoappropriatelycapitalizealltrademarkswhichwereknownatthetimeofthiswriting.Neitherthe
publishernortheauthorcanattesttotheaccuracyofanysuchinformationcontainedherein.Useofaterminthis
bookshouldnotbe regardedasaffectingthevalidityofanytrademarkorservicemark.
Ad
diti
Hughe
Add
itioona
nallBooksby
BooksbyRoland
ndH
hess
You can always find the latest information about this book series by visiting http://
www.theminimumyouneedtoknow.com. Information regarding upcoming and outofprint books
maybefoundbyvisiting http://www.logikalsolutions.com andclickingthe upcomingandoutof
printbooks link. Atthetimeofthiswriting,Logikal SolutionsandRolandHughes offer the
followingbookseitherinprintoraseBooks.
TheMinimumYouNeedtoKnowAboutLogictoWorkinIT
ISBN139780977086627
Pages:154
Coverslogic,flowcharting,andpseudocode.IfyouonlylearnedOOP,youreallyneed
toreadthisbookfirst.
TheMinimumYouNeedtoKnowToBeanOpenVMSApplicationDeveloper
ISBN139780977086603
Pages:795
IncludesCDROM
CoversDCL,logicals,symbols,commandprocedures,BASIC,COBOL,FORTRAN,C/
C++,Mysql,RDB,MMS,FMS,RMSindexedfiles,CMS,VMSPhone,VMSMAIL,
LSE,TPU,EDTandmanyothertopics.ThisbookwashandedoutbyHPatatechnical
bootcampbecausetheOpenVMSengineeringteamthoughtsohighlyofit.
TheMinimumYouNeedtoKnowAboutJavaonOpenVMS,Volume1
ISBN139780977086610
Pages:352
IncludesCDROM
CoversusingJavawithFMSandRMSindexedfiles.ThereisalotofJNIcoding.We
alsocovercallingOpenVMSlibraryroutines,buildingwithMMSandstoringsourcein
CMS.
TheMinimumYouNeedtoKnowAboutServiceOrientedArchitecture
ISBN139780977086665
Pages:370
TheNationalBestBooks2008AwardWinnerBusiness:Technology/Computer
CoversaccessingyourMySQL,RDB,andRMSindexedfiledatasilosviaJavaandport
servicesfromaLinuxorotherPCfrontend.Alsocoversdesignanddevelopmentof
ACMSbackendsystemsforguaranteedexecutionapplications.
InfiniteExposure
ISBN139780977086696
Pages:471
AnovelabouthowtheoffshoringofITjobsanddatacenterswillleadtothelargest
terroristattackthefreeworldhaseverseenandultimatelytonuclearwar.
Thereareanumberofreviewsofthisbookavailableonline.Thefirst18chaptersare
alsobeinggivenawayforfreeatBookHabit,ShortCovers,Sony'seBookstore,andmany
otherplaces.Ifyoucan'tdecideyoulikeitafterthefirst18chapters,Rolandreally
doesn'twanttodobusinesswithyou.
SourceCodeLicense
Thisbookisbeingofferedtothepublicfreely,asisthesourcecode.Pleaseleavecomments
aboutthesourceoforigininplacewhenincorporatinganyportionofthecodeintoyourownprojects
orproducts.
Usersofthesourcecodecontainedwithinthisbookagreetoholdharmlessboththeauthorand
thepublisherforanyerrors,omissions,losses,orotherfinancialconsequenceswhichresultfrom
theuseofsaidcode.Thissoftwareisprovidedas is withnowarrantyofanykindexpressedor
implied.
Visithttp://www.theminimumyouneedtoknow.comtofindadownloadlinkifyoudon't
want
toretypeorcutandpastecodefromthisbookintoyourowntexteditor.
TableofContents
Introduction......................................................................................................................................11
WhyThisBook?...................................................................................................................
11
WhyxBaseJ?.........................................................................................................................
13
ABriefHistoryofxBASE....................................................................................................
15
WhatisxBASE?...................................................................................................................
17
Limits,Restrictions,andGotchas.........................................................................................
24
Summary...............................................................................................................................
28
ReviewQuestions.................................................................................................................
28
Chapter1
...................................................................................................................................
29
1.1 OurEnvironment................................................................................................................
29
env1.......................................................................................................................................29
1.2 OpenorCreate?..................................................................................................................
30
1.3 Example1...........................................................................................................................
32
example1.java.......................................................................................................................32
1.4 ExceptionHandlingandExample1...................................................................................
37
1.5 rollie1.java..........................................................................................................................
39
rollie1.java............................................................................................................................39
...............................................................................................................................................48
testRollie1.java......................................................................................................................49
1.6 ProgrammingAssignment1...............................................................................................
49
1.7 SizeMatters........................................................................................................................
49
example5.java.......................................................................................................................49
1.8 ProgrammingAssignment2...............................................................................................
51
1.9 ExaminingaDBF...............................................................................................................
51
showMe.java.........................................................................................................................52
1.10ProgrammingAssignment3
...............................................................................................
61
1.11DescendingIndexesandIndexLifespan
............................................................................
62
doeHistory.java.....................................................................................................................63
testDoeHistory.java...............................................................................................................76
1.12ProgrammingAssignment4
...............................................................................................
82
1.13DeletingandPacking
.........................................................................................................
83
testpackDoeHistory.java.......................................................................................................84
1.14ProgrammingAssignment5
...............................................................................................
88
1.15DataIntegrity
......................................................................................................................
88
1.16ProgrammingAssignment6
...............................................................................................
89
1.17Summary
............................................................................................................................
90
1.18ReviewQuestions
...............................................................................................................
91
Chapter2
...................................................................................................................................
93
2.1 WhyThisExample?............................................................................................................
93
2.2 SupportingClasses............................................................................................................
102
MegaDBF.java....................................................................................................................102
StatElms.java...................................................................................................................... 106
StatDBF.java.......................................................................................................................107
MegaXDueElms.java..........................................................................................................112
.............................................................................................................................................113
DueSortCompare.java.........................................................................................................114
2.3 ThePanels.........................................................................................................................
115
MegaXbaseDuePanel.java.................................................................................................. 115
MegaXbaseBrowsePanel.java.............................................................................................124
MegaXbaseEntryPanel.java................................................................................................128
2.4 TheImportDialog.............................................................................................................
153
MegaXImport.java..............................................................................................................153
.............................................................................................................................................157
.............................................................................................................................................157
.............................................................................................................................................157
MegaXbase.java..................................................................................................................157
testMegaXbase.java............................................................................................................163
2.5 ProgrammingAssignment1..............................................................................................
164
2.6 ProgrammingAssignment2..............................................................................................
165
2.7 ProgrammingAssignment3..............................................................................................
165
2.8 ProgrammingAssignment4.............................................................................................
165
2.9 Summary...........................................................................................................................
165
2.10ReviewQuestions
.............................................................................................................
167
Chapter3
.................................................................................................................................
169
3.1 AuthoritativeResources....................................................................................................
169
3.2 TimestampsonReports.....................................................................................................
172
3.3 DoomedtoFailureandTooStupidtoKnow....................................................................
176
AppendixA....................................................................................................................................181
AnswerstoIntroductionReviewQuestions:......................................................................
181
AnswerstoChapter1ReviewQuestions...........................................................................
182
AnswerstoChapter2ReviewQuestions...........................................................................
185
Introduction
WhyThisBook?
IaskedmyselfthatsamequestioneverydaywhileIwaswritingit.WhyamIgoingtowrite
abookmuchlikemyotherbooksandgiveitawayforfree?ThesimpleansweristhatIhadtodo
alotoftheresearchanyway.IfIhavetodothatmuchresearch,thenIshouldputoutabook.
Giventhenarrownessofthemarketandthepropensityforpeopleinthatmarkettobelieveall
softwaredevelopersworkforfree,thebookwouldphysicallysellabouttwocopiesifIhadit
printed.(Lessthan1/10thof1%ofallLinuxusersactuallypayforanysoftwareortechnology
booktheyuse.)
Whatstartedmedownthispathwasasimplething.InordertomakeaWebsitereallywork,
afamilymemberneededtobeabletocalculatethe100miletruckingrateforthecommodity
beingsold.ThecommercialWebsitehadareallycoolfeaturewhereitwouldautomaticallysort
allbidswithin300milesbasedupontheperbushelprofitoncethetransportationcostsweretaken
out.Thepersonalreadyhadaprintedlistofthetruckingrates,sohowdifficultcoulditbe?
Somequestionsshouldneverbeaskedinlife.Wha tcouldgowrong? andH owdifficult
coulditbe? aretwowhichfallintothatcategory.Whenyouaskquestionslikethat,youtendto
getanswersyouwereunpreparedtohear.
InmyearlyDOSdays,IwouldhavesatdownandbeguncodingupaCprogram using
GreenleafDataWindowsandtheGreenleafDatabaselibrary.Ofcourse,backthen,wedidn'thave
theInternet,soIwouldhavehadtousetheGreenleafCommLibtodialouttosomeBBStoget
theDOE(DepartmentofEnergy)nationalaveragefuelprice.
DuringlaterDOSdays,butbeforeMicrosoftwroteataskswitchingGUIthatsatontopof
DOSandthatwasstartedbytypingWINattheC:>promptwhichtheyhadtheaudacitytocall
The WindowsOperatingSystem, IwouldhavereachedforaC/C++codegeneratorlikeProC
fromVestronix(laterProCCorp.)orDataBossfromKedwellSoftware. Neither program did
communications,but bothcouldbeusedtoquicklylayoutxBASEdatabases,generatingentry/
maintenancescreens,menus,and reportsin amatterof minutes. Youcouldcreateanentire
applicationthatusedjustafewfilesfordistribution,allofwhichcouldbecopiedintoasingle
directory,andtheuserwouldbehappy.
12
Chapter1Fundamentals
OnceWindowscameout,thingsgotugly.IdidalotofOS/2work,eventhoughnotmany
companiesorpeopleusedit.TheproblemwithOS/2wasthatIBMhadMicrosoftdevelopitand
Microsoftwasintentonensuring thatOS/2 would neverbeathreattoWindows. (Windows
wasn't
evenanactualoperatingsystemuntilmanyyearsafterOS/2cameout.)OnceIBMhadthe
bulkoftheMicrosoftcoderemovedfromit,OS/2becameanincrediblystableplatformwhich
managedmemorywell. IBMdidn't
manageitwell,saddlingdeveloperswithexpensivedevice
driver development tools that would only work with an increasingly hardtofind version of
MicrosoftC.
Mostofusdidcrossplatformdevelopmentinthosedays.IusedWatcomC/C++forDOS,
Windows,andOS/2development(nowOpenWatcomastheprojectisOpenSource).Itwaseasy
when you used the Zinc Application Framework for your GUI. There were a ton of cross
platform indexedfilelibraries. Greenleafsupportedalotofcompilersandplatformswith its
DatabaselibraryforxBASEfiles.Ofcourse,therewerealotofsharewareandcommercialBtree
type indexed file systems out there. These had the advantage of locking the user into your
services.Thesehadthedisadvantageoflockingtheuserintoyourservices.Theyweren't
widely
supportedbycommon tools likespreadsheetsandwordprocessors.TheoneIrememberusing
themostwasCIndex/IIfromTrioSystemsLLC.AsIrecallitwaswrittengenericallyenough
thatitactuallyworkedonDOS,MAC,Windows,andOS/2.Ofcourse,thatwasduringthebrief
periodinlifewhentheMetrowerksCodeWarriortoolsetsupportedtheMAC.
Inshort,fromthe80sthroughtheendofthe90swealwayshadsomewayofcreatinga
standaloneapplicationwithitsownindexedlocaldatastoragethatdidn't
requirelotsofother
thingstobeinstalled.WhenWindowsstartedgoingdownthepathofneedinglotsofotherstuff
was when you started seeing companies selling software to do nothing other than develop
installationprogramsforWindows.
Asanapplicationdeveloper whoisquitelonginthetooth,Idon't
wanttolinkwithDLLs,
sharedlibraries,installedimages,oranyotherthingwhichisexpectedtobeinstalledonthetarget
platform.Ihaveheardeveryjustificationforitknowntoman.Iwasthereandlistenedtopeople
slam my C program because their Visual Basic (VB) application took only 8K and looked
slicker than my application which consumed an entire floppy. I was also there to watch
productioncometoascreechinghaltwhenanewversionoftheVBruntimegotinstalledto
supportsomeothermission criticalapp onlytofindallpreviousappswerenowincompatible.
(ThemachinerunningmyCprogramwhichtookawholefloppycontinuedtokeepthebusinessit
supportedrunningwhilemuchscreamingandfingerpointingwasgoingonallaroundit.)
Chapter1Fundamentals
13
Whythisbook? BecausethepersondownloadingyourSourceForgeprojectorotherfree
pieceofsoftwaredoesn't
considerrecompilingaLinuxKernelafunthingtodoinhisorherfree
time.
Why this book? Because Mom and Dad shouldn'thave to take a course on MySQL
administrationjusttoentertheirexpensesandfiletheirtaxes.
Whythisbook?BecauseIhadtodoallofthisresearch,whichmeantIhadtotakealotof
notesanyway.
Whythisbook?BecauseOpenSourcelibrariesdon'tcomewithsquatfordocumentation.
WhyxBaseJ?
That'sagoodquestion. Partoftheanswerhasto dowiththehistoryIprovidedinthe
previoussection.Theotherparthastodowiththelanguagechosen.
Idon't
domuchPCprogramminganymore.IneededthisapplicationtorunonbothUbuntu
Linux andWindows. Thereisn't
agood OpenSourcecrossplatformGUIlibraryoutthere.
MostoftheLinuxGUIlibrariesrequirealotofstuffto be installedonaWindowsplatform
(usuallythebulkofCygwin)andthatrequireswritingsomekindofinstallationutility.Let's
just
saythattheOpenSourceinstallationgenerationtoolsforWindowshaven't
quitecaughtuptotheir
expensivecommercialcounterparts.Youdon't
reallywanttosaddleaWindowsmachinewhich
hasthebareminimumWindowsconfigurationwithsomethinglikeCygwinontopofit.
WhenIdiddoPCprogramming, IneverreallydidmuchwithTCP/IPcallsdirectly. IfI
magicallyfoundanOpenSourcecrossplatformGUIwhichdideverythingIneededonbothLinux
andWindows,IwasstillgoingtohavetofindacrossplatformTCP/IPlibrary.Letusnotforget
thatsome64bitLinuxdistroswon't
run32bitsoftwareandsome32bitsoftwarewon't
runon
64bitversionsofWindowsVista.ProgrammingthisinC/C++wasgoingtorequirealotmore
effortthanIwantedtoputintosomethingIwouldbasicallyhandoutfreeonceitwasworking
correctly.(YoumayalsohavenoticedIdidn't
evenmentionfindingalibrarywhichwouldwork
onWindows,Linux,andMAC.)
Java,whilenotmyfavoritelanguage,tendstobeinstalledonanymachinewhichconnectsto
theInternet.MostWindowsusersknowwheretogotodownloadandinstalltheJREwhichisn't
installedbydefaultforsomeversionsofWindows.FromwhatIhear,thepissingcontestisstill
goingonbetweenwhatisleftofBillGates'sEvilEmpireandwhatisleftofSun.
Java,whilenotmyfavoritelanguage,providesaGUIforalmosteveryplatformitrunson.
14
Chapter1Fundamentals
Java,whilenotmyfavoritelanguage,makesopeningaURLandparsingthroughthetextto
findcertaintokensprettysimpleifyouhappentoknowwhatclasstouse.
Java,whilenotmyfavoritelanguage,willnotcareiftheunderlyingoperatingsystemis32
or64bit.
MostmachineswhichuseabrowserandconnecttotheWebhavesomeformoftheJava
Runtime Environment (JRE) installed on them. This is true of current Linux, MAC, and
Windowsmachines.
Obviously I was going to have to develop this package with a language that wasn'tmy
favorite.
Theonlyquestionremainingwasdatastorage.WouldIforceMom,Dad,andAuntCarolto
enrollinaMySQLadministrationcourseeventhough theycanbarely answeremailandfind
MapQuestontheInternet,orwasIgoingtousesomethingselfcontained? Givenmyearlier
tirade,youknowIwantedtousesomethingselfcontainedjusttopreservemyownsanity.
Atthetimeofthiswriting,asearchonSourceForgeusing javaindexfile yieldsjustshyof
29,000projectsandasearchusingjava xbase yieldsjustshyof20,000projects.Granted,after
yougetseveralpagesintothesearchresults,thepercentageofrelevancydropsexponentially,but
therearestillalotofchoices.Btreetypeindexedfileswhichstoretheindexinthefilewiththe
datatendtobefarmorereliablefromadataintegritystandpoint.Allindexesarealwayskeptin
syncbythelibrary/engine.xBASEtypefilesstoretheindexesoffindifferentfiles.Youcanadd
alloftherecordsyouwanttoanxBASEdatafilewithouteverupdatinganindex.
Ican heartheheadscratchingnow. But ifthat's
true, whywouldyou use30yearold
xBASEtechnologyinsteadofaBtree? Becauseofthetools,child.OpenOfficecanopenaDBF
fileinaspreadsheettoletauserviewthedata.Ifanyofthesefilesbecomecorruptedthereare
literallyhundredsofxBASErepairtoolsoutthere.Ifauserdecidesheorshewantstoloadthe
dataintosomeotherdatabaseformatforanalysis,therearetoolsouttheretoexportxBASEinto
CSV(CommaSeparatedValue)fileswhichcaneasilybeimportedbymostrelationaldatabase
engines. Some relational database engines can directly import xBASE files. Nearly every
programminglanguageouttherehassomeformofxBASElibrary,orcancallonewritteninsome
otherlanguage. PerlevenhasanxBASElibrarythatI've
usedtoextractdatafromanexpense
trackingsystembefore.UnderLinux,thereisevenadbf_dumputility(dbfdumponOpenSuSE
forsomereason)whichwillletyoudumpaDBFfiletoaCSVinonecommand.
dbfdump /windows/D/net_f/xpns_$tax_year/payee.dbf > payee.csv
Chapter1Fundamentals
15
WhathappensifIuseoneofthosereallyfastBtreeorB+treelibrariesandtheuserneedsto
getthedataout?Suchuserscussmeprettyhardwhennoneoftheofficesuitesontheircomputer
canopenthefiletodoanexport.WhentheytrackmedownviatheWebandcallmyoffice,they
getdisappointedfindingoutIdon't
havetimetodropeverythingandflytotheirlocationtohelp
themfree ofcharge. Then theysaymy name, spit,andstartbadmouthing me allover the
Internet.Thatreallyhelpsmyconsultingbusiness.
NowthatwehavedeterminedthedatawillbestoredinanxBASEfileformat,weonlyhave
tochooseanOpenSourcexBASElibraryfor Java. IselectedxBaseJbecauseitusedtobea
commerciallibraryknownasXbaseJandwassoldbyBMTMicro.Theproducthassincebecome
anOpenSourceProjectwhichgetsperiodicimprovements.Thedeveloperactuallymonitorshis
SourceForgesupportforumandseemstobeactivelyaddingnewthingstothelibrary. Some
thingsdon't
workoutsowell,liketheDTDtoxBASEXMLparser,buttheattemptwasmade.
Someoneelseinthecommunitymightfinishit.
Pleasepayattentiontothethoughtprocessofthissection.Aseasonedsystemsanalystand/or
consultantgoesthroughexactlythisthoughtprocesswhenheorshetriestodesignasystem.You
lookatwhatisavailableonthetargetplatform,thenwalkbackwardstryingtoreducetheamount
ofpainyoufeelwhenyoucan't
changethetargetplatform.Icannotchangethecomputerspeople
have,northeirpersonalskilllevels.Ihavetodesignanapplicationbasedupontheabilityofthe
user,notmyabilitytobecreative,orthetoolsIwouldprefertouse.
ABriefHistoryofxBASE
TherearemanyvariationsinthecapitalizationofxBASE,whichisIguessfitting,sincethere
aremanyslightvariationsfortheactualfileformats.ThehistoryofxBASEisasordidtale,but
allversionsofxBASEinoneway oranother tracetheirrootsbackto the1970sandtheJet
PropulsionLaboratory.HereisthetaleasbestIcanremember.
PCswereoriginallyveryexpensive. Inthelate1970s youcouldbuyawell equipped
ChevroletCapriceClassic4doorsedanforjustover$4,000.Intheearly1980syoucouldbuya
dualfloppymonochromePCforaboutthesameamount.Whenclonevendorsenteredthemarket
youstartedseeingdualfloppyclonePCsforunder$2,000.ThehigherendPCsstartedadding
fullheight10MEGharddrivestojustifykeepingtheirpricesohigh.Eventually,youcouldgeta
clonePCwithawhopping20MEGharddrivefornearly$2000.
16
Chapter1Fundamentals
Oncethat$2000pricepointforaPCwithaharddrivewasachieved,thePCstartedgetting
pushedintotheworldofbusiness.Thefirstthingthebusinesseswantedtodowithitwaskeep
thingsinsortedorder. Theyheardfromkidsenrolledincomputerprogramming coursesthat
midrange andmainframecomputersusedalanguagecalledCOBOLwhichsupported indexed
filesthatcouldbeusedtostoreinvoices,payments,etc.,allinsortedorder,soinformationwas
quickly(fortheday)retrievable. Well,thePCdidn'thavethat,andbusinessusersneededit.
There was a noncommercial product called Vulcan written by Wayne Ratliff which kind of
answeredsomeofthoseneeds. AshtonTateeventuallyreleasedacommercialproductnamed
dBASEII.(TheyusedIIinsteadofItomaketheproductseemmorestable.I'm
notmakingthat
up.)
AshtonTatehadalotofsales,alotofmoney,alotofattitude,andalotoflawyers.Thisled
tothembelievingtheyhadtherightstoallthingsdBASE.Whenthecashcowstartedgivinglots
ofgreenmilktheclonevendorspiledintothefray. AshtonTateletloosewithablizzardof
lawsuitstryingtoshowitwasthemeanestdoginthejunkyard.Theclonevendorsquicklygot
aroundthedBASEtrademarkinfringementbycallingtheirfileformatsxBASE. (Somecalled
theirsXBase,othersXBase,etc.)
Times and public sentiment turned against AshtonTate. The people who spent many
hundredsofdollarsforthesetoolsandevenmoremoneyforsomeoftheruntimelicenseswhich
hadtobeinplaceonthemachinesbeforeapplicationswrittenwiththetoolwantedastandard.
WhentheywerefinallyfedupwithAshtonTateoroneoftheclones,theynaivelybelievedit
wouldbelikethoseoldCOBOLprograms,recompileandrun. Sillycustomers. Thiswasthe
peakofproprietarysoftware(theheightofwhichturnedouttobeMicrosoftWindows,which
even today is considered one of the most proprietary operating systems running on a PC
architecture),andtherewasnoincentiveforanyofthosereceivingruntimelicensefeestoagree
toastandard.Well,noincentiveuntilthebusinesscommunityasawholedeemedthefeesthey
chargedtoohigh.
Whenthepriceofaruntimelicensereachedhundreds,thebusinesscommunitycriedfoul.
Whenthememoryfootprintoftheruntimemeantyoucouldn't
loadnetworkdriversorother
applicationsin thatprecious 640KwindowaccessiblebyDOS,dirtylaundry gotairedrather
publicly.
Chapter1Fundamentals
17
VultureCapitalists,alwayssniffingthewindfordirtylaundryandviewingitasopportunity,
startedhurlingmoneyatsoftwaredeveloperswhosaidtheycouldwriteaCprogramminglibrary
which wouldlet other programmersaccessthesefileswithout requiring a runtime imageor
license. Theinitialpricetagforthoselibrariestendedtobequitehigh. Sincetherewereno
royaltypayments,thedevelopersandtheVultureCapitaliststhoughttheb est pricetheycould
offerwassomethingtotallingabouthalfofwhatthebigcorporationswerecurrentlypayingfor
development+runtimelicensefees. Forabriefperiodoftime,theywerecorrect. Thenthe
numberoftheselibrariesincreasedandthepricegotdowntounder$500each.Thecompanies
vendingproductswhichrequiredruntimelicensefeessawtheirrevenuestreamsevaporate.
Theevaporationwasagoodthingfortheindustry.ItallowedBorlandtopurchaseAshton
Tatein1991.PartofthepurchaseagreementappearstohavebeenthatAshtonTatedropallofits
lawsuits. After that committee ANSI/X3J19 was formed and began working on xBASE
standards.In1994BorlandendedupsellingthedBASEnameandproductlinetodBASEInc.
The standards committee accomplished little, despite all the major vendors participating.
Moreofthedatafileformats,values,andstructureswereexposedbyeachvendor,buteachofthe
vendors in the meetings wanted every other vendor to adopt its programming language and
methodsofdoingthingssoitwouldbethefirsttomarketwiththeindustrystandard.
TherearestillcommercialxBASEvendorsoutthere. MicrosoftownswhatwasFoxbase.
dBASEisstillsellingproductsandmigratingintoWebapplicationcreation.Mostofthereally
bignameproductsfromthelate80sarestillaround; theyjusthavedifferent owners. Sadly,
LotusApproachwasdroppedbyIBMandnotresurrectedwhenitcameoutwiththeSymphony
OfficeSuite.
IwillhazardaguessthatsomeoftheC/C++xBASEprogramminglibrariesfrommyDOS
daysarestillaroundandbeingsoldbysomeone. ThatwouldmakesensenowthatFreeDOSis
startingtogetafollowing.NotquiteasmuchsensegivenalloftheOpenSourceC/C++xBASE
librariesoutthere,buttheoldcommercialtoolshavealotmoretimeinthefield,andshould
thereforebemorestable.IknowthatGreenleafisbackinbusinessandyoucanprobablygeta
copyofGDB(GreenleafDatabase)fromthem;Ijustdon'tknowwhatplatformstheystillsupport.
ThereisalotofhistoryandfolkloresurroundingthehistoryofxBASE.Youcouldprobably
makeamovieoutofitliketheymadeamovieoutoftheriseofMicrosoftandApplecalled
Pirates ofSiliconValley in1999. Youcanpiecetogetherpartofthehistory,atleastfroma
compatibility standpoint, byobtaining acopy of The dBASELanguage Handbook written by
DavidM.KalmanandpublishedbyMicrotrendBooksin1989. Anotherworkwhichmightbe
worthy of your time is Xbase Cross Reference Handbook written by Sheldon M. Dunn and
18
Chapter1Fundamentals
publishedin1993bySybex,Inc.
For our purposes, you only need to know that back in the 1970s the Jet Propulsion
Laboratoryneededanindexedfilesystemtostoredataforvariousretrievalneeds. Whatthey
designedeventuallydevelopedmanyflavors,butallofthoseflavorsarenowlumpedunderthe
xBASEheadingbythegeneralpublic.
WhatisxBASE?
Note: This information is correct. You will find other information on the Web which
completelycontradictsportionsofthisinformation,anditwillalsobecorrect.Whatyouhaveto
takeintoaccountisthepointintimetheinformationreferences.Therearesomenewtoolsonthe
marketwhichclaimtheyarexBASEandhavenomaximumfilesize.Asyouwillseelater,thisis
not the original xBASE, which has a 1,000,000,000 byte file size limit, nor the later DOS/
WindowsxBASEproducts,whicheventuallyexpandedthemaximumfilesizeto2GB.xBASE
evolvedwiththeDOSPCfromthetimewhenwehaddualfloppysystemswhichwouldhaveat
least64KofRAM,butcouldhaveallthewayupto640K.Therewasatimewhenthelargest
harddriveyoucouldbuyforaPContheretailmarketwas20MB.
Note2:Alotofwellmeaningpeoplehavetakenthetimetoscaninorrekeydocumentation
fromthe1980swhichshippedwithvariousproducts.Iapplaudtheirefforts.Hopefullywewill
find some method of parsing through all of this documentation and updating it for today's
environment.Themostconfusingthingsyouwillreadarewhereactualproductliteraturesays,
Themaximumfilesizeis1,000,000,000bytesunlesslargedisksupportisenabled,thenyouare
limitedonlybythesizeofyourdisk. AtthepointintimewhentheauthorwrotethatthexBASE
formatcouldstore2GBandthelargestdiskdriveonthemarketwas1.08GB.Thestatementis
blatantly wrong now, but the online documentation is still trapped at that point in time. I
rememberthispointintimewell.Shortlyafterthatdocumentationcameout,SCSIdrivesstarted
increasinginsizeallofthewayupto8GBinlessthanayear.Alotofcustomershitthat2GB
wallprettyhard,thenreachedforlawyersclaimingfraud.Itwasn't
deliberatefraud,itwassimply
outdatedinformation.
MostonlinereferenceswillsaythatXbase(xBASE)isagenerictermforthedBASEfamily
ofdatabaselanguagescoinedinresponsetothreatsoflitigationoverthecopyrightedtrademark
dBASE . Thatwouldbetrueforapointintimelongago.TodayxBASEreallyreferstothe
data storage specification, not the language(s) involved in the application. People who are
programmersknowthis;peoplewhoaren't
programmersdon't
appeartohavetheabilitytoreason
itout.
Chapter1Fundamentals
19
IhavealreadytalkedaboutthevariousC/C++xBASElibrarieswhichareoutthere. Ifthe
definitionfoundonlineweretrue, itwouldrequirethoselibrariestoparseadBASEscriptand
executeit,ratherthandirectlyaccessthedataandindexfiles.Thesamewouldberequiredofthe
xBaseJlibrarywewillbecoveringinthisbook.Mostlibrariesdon't
provideanykindofscript
parsingcapability. Whattheydoprovidearefunctionswithnamesveryclosetosomeofthe
originaldBASEsyntax,alongwithalotofotherfunctionsthataccessthedataandindexfiles.
Puttingitinsimpleterms,xBASEisasystemofflatfileswhichcanorganizedatainauseful
mannerwhenoneormorespecificsetsofformatrulesarefollowed.Eachfileisintwoparts:a
file header and actual contents. Each header has twoparts: a file descriptor anda content
descriptor.Alotofdefinitionsyoufindpublishedandonlinewon't
usethewordcontent, they
willusethewordrecord. Thosedefinitionsareonlyaccurateforthedatafile.Whileitistrue
thateachindexvaluecouldbeviewedasarecordcontainingakeyvalue,recordnumber,sort
orderinformationandotherinternaldata,wedon't
haveanyconceptoftherecordorganization
unlesswearewritinganxBASElibraryofsomekind.
Theabovedoesnotdescribearelationaldatabasebyanystretchoftheimagination.There
have been various products on the market which put SQL type syntax around xBASE file
structures, but the organization really is flat file. If you have gone to school for computer
programming,youmayhaveencounteredthetermr elativefile. Arelativefileisaccessedby
record number, notakeyvalue. Itisoneofthesimplestfilestructurestocreate andisthe
foundationofseveralotherfilesystems.
You may have also encountered the term hashed file or hash file. This is an
enhancementtotherelativefile.Aparticularfieldorsetoffieldsischosenfromarecordtobe
consideredakey value. Someformofalgorithm(usuallyamathfunction)isfedthekeyvalue
and out the other side of the function comes the record number where the record you want
should be.Ifyouhaveareallybadhashalgorithmyouendupwithmultiplekeyshashingto
the same record number, a condition known as hash collision or simply collision . The
program then has to go sequentially through from that record either forward or backward
dependinguponkeysortorder,untilitfindstherecordyouarelookingfor,orakeysodifferent
thatitcantellyourrecordisn't
inthefile.Almosteveryprogrammerhastowriteaprogramlike
thiswhileearninghisorherbachelorsdegree.
20
Chapter1Fundamentals
TherewasalotofbrainpowerinvolvedwiththecreationofxBASE.Youmightremember
thatItoldyouitwasacreationwhichfelloutoftheJetPropulsionLaboratory andintothe
commercialworld.WhenyouwriteadatarecordtoanxBASEfile,itgetswrittencontiguously
inthenextavailableslot. Theactualrecordnumber isrecordedwiththekeyvalue(s)inthe
indexedfileswhicharebothopenandassociatedwiththedatafile. Whenyouwanttofinda
record,allofthedancingoccursinthefilecontainingtheindex.Asageneralrulekeyvaluesare
smallerthanrecordvaluessoyoucanload/traversemanymoreoftheminashorterperiodof
time.Oncetheenginelocatesthekey,ithastherecordnumberforadirectreadfromthedata
file. Thereallygoodlibrariesandengineswillalsoverifythekeyontherecordreadactually
matchesthekeyvaluefromtheindexfile.(Moreonthattopiclater.)
Idon't
knowwhatmagicactuallyhappenswhenthekeyisbeingprocessedandIdon't
care.
Ifyoureallywanttofindout,xBaseJcomeswithsourcecode,asdomanyotherOpenSource
projectswhichcreateandprocessxBASEfiles.Pulldownthesourceandplowthroughit.From
anapplicationdeveloperstandpoint, allweneedtoknowisthatiftheindexfileisopenand
associatedwiththedatafile,itwillbeupdated.Whenakeyisfoundwegettherecordandwhen
itisn'twegetanerrorvalue.
ItisimportanttonotethattheoriginalxBASEfilesystemsstoredonlycharacterdatainthe
datafiles.Numbersanddateswereallconvertedtotheircharacterrepresentations.Thissevere
restrictionmadethedesignhighlyportable. Binarydataisfarmoreefficientwhenitcomesto
storage,buttendstobearchitecturespecific.(RefertoThe MinimumYouNeedtoKnowtoBe
anOpenVMSApplicationDeveloper ISBN139780977086603page103foradiscussion
onLittleEndianvs.BigEndiananddataportability.)
Another benefit this severe restriction created was that it allowed nonprogrammers the
abilitytocreatedatabases.TheaverageJoehasnoideawhatthedifferencebetweenSingleand
Doubleprecisionfloatingpointisorevenwhateitherofthosephrasesmean.TheaverageMBA
wouldn't
knowwhatG_FLOAT,F_FLOAT,andD_FLOATwereorthattheyexistevenifthe
terms were carved on a 2x4 that smacked them between the eyes. The average user could
understand 9 digits in sizewith 3 decimal digits, though. By that time in America, most
everyonehadfilledoutsomegovernmenttaxwithholdingorotherformthatprovidedneatlittle
boxesforyoutowritedigitsin.
Chapter1Fundamentals
21
DOS,andbyextensionWindows,madesignificantuseofthreecharacterfileextensionsto
determinefiletypes. Linuxdoesn't
supportfileextensions. ItcanbeconfusingforaPCuser
when they see MYFILE.DBF on a Linux machine and they hear the . is simply another
characterinafilename.Itisevenmoreconfusingwhenyoureaddocumentationforapplications
writteninitiallyforLinux,likeOpenOffice,andittalksaboutfiles withanODT extension.I
camefrommultipleoperatingsystemswhichallusedfileextensions.Idon't
carethatI'm
writing
thisbookusingLotusSymphonyonKUbuntu,I'm
goingtocall.NNN afileextensionandthe
puristscanjustputtheirfingersintheirearsandhumreallyloud.
TheoriginalfileextensionforthedBASEdatafilewas.DBF.Somecloneplatformschanged
this,andsomedidnot.Itreallydependedonhowfaralongthelegalprocesswasbeforethesuits
weredropped.Intruth,youcouldusenearlyanyfileextensionwiththeprogramminglibraries
becauseyoupassedtheentirenameasastring.MostoftheC/C++,andJavalibrarieslookata
specialidentifiervalueinthedatafiletodetermineifthefileformatisdBASEIII,dBASEIV,
dBASEIIIwithMemo,dBASEIVwithMemo,dBASEVwithoutmemo,FoxProwithMemo,
dBASEIVwithSQLtable,Paradox,or oneoftheotherflavors. FoxbaseandFoxProwere
actuallytwodifferentproducts.
TheMemofieldwassomethingakintoatrainwreck.ThisaddedtheDBTfileextensionto
themix(FPTforFoxPro.)AMemofieldwasmuchasitsounded,alargefreeformtextfield.It
cameaboutlongbeforetheITindustryhadanagreeduponbest practice forhandlingvariable
lengthstringfieldsinrecords.ThefreeformtextgetsstoredasanentityintheDBTfile,anda
referencetothatentitywasstoredinafixedlengthfieldwiththedatarecord.
You have to remember that disk space was still considered expensive and definitely not
plentifulbackinthosedays.Oh,wethoughtwewouldneverfillupthat80MEGharddrivewhen
itwasfirstinstalled.Itdidn't
takelongbeforewewerebacktoarchivingthingswedidn't
need
rightawayonfloppies.
ThememofieldgavexBASEdevelopersamethodofadding commentssections torecords
withouthavingtoallocateagreatbigfieldineverydatarecord.Ofcourse,thememofieldhada
lotofdifferentflavors. Insomedialectsthememofieldinthedatarecordwas10bytesplus
howevermanybytesofthememoyouwantedtostoreinthedatarecord.ThedeclarationM25
would take 35 bytes in the record. According to the CodeBase++ version 5.0 manual from
SequiterSoftware,Inc.,thedefaultsizeforevaluatingamemoexpressionwas1024.Thebuiltin
memoeditor/wordprocessorfordBaseIIIwouldnotallowausertoeditmorethan4000bytesfor
amemofield.Youhadtoloadyourowneditortogetmorethanthatintoafield.
22
Chapter1Fundamentals
Chapter1Fundamentals
23
Itdidn't
takelongbeforewehadMultipleIndexFiles(MDX),CompoundIndexFiles(CDX),
ClipperIndexFiles(NTX),DatabaseContainer(DBC),andfinallyIDXfiles,whichcouldbe
eithercompressedoruncompressed.TheremayevenhavebeenothersIdon'tremember.
MDX was a creation which came with dBASE IV. This was a direct response to the
problemsencounteredwhenNDXfilesweren't
updatedasnewrecordswereadded.Youcould
associatea production MDXfilewithaDBFfile.Itwaspromisedthattheproduction MDX
file would be automatically opened when the database was opened...unless that process was
deliberately overridden by a programmer. This let the runtime keep indexes up to date.
AdditionalkeyscouldbeaddedtothisMDXuptosomemaximumsupportednumber.Ishould
point out that a programmer could create nonproduction MDX files which weren'topened
automaticallywiththeDBFfile. (xBaseJiscurrentlyknowntohavecompatibilityissueswith
dBASEVformatsandMDXfilesusingnumericand/ordatekeydatatypes.) MDXcalledthe
keysitstoredtagsandallowedupto47tagstobestoredinasingleMDX.
WhilethereissomecommonalityofdatatypeswithxBASEfilesystems,eachcommercial
versiontriedtodifferentiateitselffromthepackbyprovidingadditionalcapabilitiestofields.
Thisresultedinalotofcompatibilityissues.
Type
Description
AutoincrementSameaslong
Timestamp8bytestwolongs,firstfordate,secondfortime. Thedateisthe
number of days since 01/01/4713 BC. Time is hours * 3600000L + minutes *
60000L+Seconds*1000L
10digitsrepresentinga.DBTblocknumber.Thenumberisstoredasastring,right
justifiedandpaddedwithblanks.AddedwithdBaseIV.
ASCIIcharactertextoriginally<254charactersinlength.ClipperandFoxProare
knowntohaveallowedthesefieldstobe32Kinsize.Onlyfields<=100characters
canbeusedinanindex.Someformatschoosetoreadthelengthasunsignedwhich
allowsthemtostoreupto64Kinthisfield.
DatecharactersintheformatYYYYMMDD
FloatingpointsupportedbydBASEIV,FoxPro,andClipper,whichprovidesupto
20significantdigitsofprecision.Storedasrightjustifiedstringpaddedwithblanks.
OLE10digits(bytes)representinga.DBTblocknumber,storedasstring,right
justifiedandpaddedwithblanks.CameaboutwithdBASEV.
Chapter1Fundamentals
24
Type
Description
Long4bytelittleendianinteger(FoxPro)
LogicalBoolean8bitbyte.Legalvalues
?=Notinitialized
Y,yYes
N,nNo
F,fFalse
T,tTrue
Values are always displayed as T, F, or ?. Some odd dialects (or more
accuratelyC/C++librarieswithbugs)wouldputaspaceinanuninitializedBoolean
field.Ifyouareexchangingdatawithothersources,expecttohandlethatsituation.
10digits(bytes)representingaDBTblocknumber.Storedasrightjustifiedstring
paddedwithspaces.
SomexBASEdialectswouldalsoallowdeclarationasMnn,storingthefirstnnbytes
ofthememofieldintheactualdatarecord.Thisformatworkedwellforsituations
wherearecordwouldgeta1015characterSTATUScodealongwithafreeform
descriptionofwhyithadthatstatus.
Paradoxdefinedthisasavariablelengthalphafieldupto256MBinsize.
UnderdBASEtheactualmemoentry(storedinaDBTfile)couldcontainbinary
data.
xbaseJdoesnotsupporttheformatMnnandneitherdomostOpenSourcetools.
N
NumericField19characterslong.FoxProandClipperallowthesefieldstobe20
characters long. Minus sign, commas, and the decimal point are all counted as
characters. Maximum precision is 15.9. The largest integer value storable is
999,999,999,999,999.Thelargestdollarvaluestorableis9,999,999,999,999.99
Doublenoconversions,storedasdouble
Picture(FoxPro)Muchlikeamemofield,butforimages
Paradox3.5andlater.Fieldtypewhichcouldstore16bitintegers.
Chapter1Fundamentals
Type
25
Description
DateTime(FoxPro)
Currency(FoxPro)
Therewasalsoabizarrecharacternamevariablewhichcouldbeupto254characterson
someplatforms,but64KunderFoxbaseandClipper.Idon't
haveacodeforit,andIdon't
care
aboutit.
Limits,Restrictions,andGotchas
OurlibraryofchoicesupportsonlyL,F,C,N,D,P,andMwithoutanynumbersfollowing.
Unlessyouforcecreationofadifferentfiletype,thislibrarydefaultstothedBASEIIIfileformat.
YoushouldnevereveruseadBASEIIfileformator,moreimportantly,adBASEIIproduct/tool
onadatafile.Thereisafieldonthefileheaderwhichcontainsadateoflastupdate/modification.
dBASEIIIandlaterproductshavenoproblems,butdBASEIIceasedworkingsometimearound
Jan1,2001.
Mostoftoday's
librariesandtoolssupportdBASEIIIfiles.Thismeanstheysupportthese
fieldandrecordlimitations:
dBASEIIallowedupto1000bytestobeineachrecord.dBASEIIIallowedupto4000bytes
ineachrecord.Clipper5.0allowedfor8192bytesperrecord.LaterdBASEversionsallowed
upto32767bytesperrecord.Paradoxallowed10800forindexedtablesbut32750fornon
indexedtables.
dBASEIIIallowedupto128fieldsperrecord.dBASEIVincreasedthatto255.dBASEII
allowedonly32fieldsperrecord.Clipper5.0allowed1023fieldsperrecord.
dBASEIVhadamaximumkeysizeof102bytes. FoxProallowedupto240bytesand
Clipper388bytes.
Field/columnnamescontainamaximumof10characters.
26
Chapter1Fundamentals
IlistedsomeofthenondBASEIIIvaluestogiveyouasenseofwhatyoumightbeup
againstwhenafriendcallsyouupandsaysI 'v
e gotsomedataonanoldxBASEfile,canyou
extractitforme? TheflavorsofxBASEwhichwentwellbeyondevendBASEIVlimitations
haveverylimitedsupportintheOpenSourcecommunity.
Letmesaythisplainlyforthosewhohaven't
figureditout:xbaseislikeLinux.Therearea
zilliondifferentflavors,notwoofwhicharethesame,yet,afewcorethingsarecommon,sothey
arealllumpedtogetherunderoneheading.
Ifyoureadthroughthecommentsinthesourcefiles,you'll
seethatxBaseJclaimstosupport
onlydBASEIIIanddBASEIV.Ifyouarelookingfortransportabilitybetweenmanysystems,
thisistheleastcommondenominator(LCD)andshouldworkinmostcases.Thecommentsmay
verywellbeoutofdate,though,becausethecreateDBF()protectedmethodoftheDBFclass
supportsaformatvaluecalledFOXPRO_WITH_MEMO.
When I did a lot of C/C++ programming on the PC platform, I found GDB (Greenleaf
DatabaseLibrary)tobethemostrobustlibraryavailable. IhadusedCodeBasefromSequiter
Softwareandfoundittobedramaticallylacking.WiththeCversionoftheirlibrary,youcould
not develop an application which handled dBASE, FoxPro, and Clipper filessimultaneously.
Theirentireobjectlibrarywascompiledfor asingleformatatatime. GDBcreatedseparate
classesandseparatefunctionstohandleopening/creatingallofthedatabaseformatsitsupported.
Eachofthoserootclasses/structuresweretaskedwithkeepingtrackofandenforcingthevarious
limitseachfiletypeimposed.ThelibrarywasalsotestedunderWindows,Win32,genericDOS,
16bitDOS,32bitDOS,andOS/2.Itwasthecreamofthecropandverywellmaystillbetoday.
I'm
bringingupthosecommerciallibrariestomakeapointhere.Afterreadingthroughthe
code,IhavecometotheconclusionthatonlytheformatwasimplementedbyxBaseJ,notallof
therules.WhenyoureadthesourcefortheDBFclass,youwillseethatifweareusingadBASE
IIIformat,afieldcountof128isenforced,andeverythingelseislimitedto255.Thetruthisthat
theoriginalDOSbasedFoxbasehadafieldlimitof128aswell,butthatformatisn't
directly
supported.
Thereisalsonocheckformaximumrecordlength. TheDBFclasshasaprotectedshort
variablenamedlreclwhereitkeepstrackoftherecordlength,buttherearenoteststhatIcould
seeimplementingthevariousmaximumrecordlengths.Intruth,sinceitsupportsonlyasubsetof
theformats,ahardcodedtestcheckingagainst4000wouldworkwellenough.NotalotofDOS
usersouttherewithlegitimatedBASEIIIPlusruntimestoworryabout.
Chapter1Fundamentals
27
Anothergotchatowatchoutforismaximumrecords.TheDBFclasscontainsthislineof
code:
file.writeInt(Util.x86(count));
AlltheUtil.x86calldoesisreturna4bytebuffercontainingabinaryrepresentationofalong
intheformatusedbyanx86CPU.(Javahasitsowninternalrepresentationforbinarydatawhich
mayormaynotmatchthecurrentCPUrepresentation.)Thevariablefile issimplyaninstance
of the Java RandomAccessFile class, and writeInt() is a method of that class. There is no
surrounding check to ensure we haven'texceeded a maximum record count for one of the
architectures.OurvariablecounthappenstobeaJavaintwhichis32bits.WeknowfromourC
programmingdays(oratleasttheCheaderfilelimits.h)thefollowingthings:
Typ
ypee
16bit
32bit
unsigned
65,535
4,294,967,295
signed
32,767
2,147,483,647
WhilewewillnothavemuchtroublewhenhandingdataovertotheotherOpenSourcetools
whichdon't
checkmaximums,wecouldhavetroubleifweaddedalotofrecordstoafileflagged
asdBASEIIIthenhandeditofftoanactualdBASEIIIruntime.Recordmaximumsweren't
as
bigaproblemasfilesize.Thatfunky1billionbytefilesizelimitwasaresultofDOSandthe
drivetechnologyoftheday.Wehada1Gigwallforawhile.Evenafterthatbarrierhadbeen
pushedbackto8Gigwestillhadthatbuiltin1Giglimitdueinlargepartto16bitmathandthe
FAT16diskstructureusedatthetime.MostofyounowusediskstorageformatslikeFAT32,
NTFS,HPFS,EXT3,orEXT4.Noneofthesenewerformatshavethe16bitproblemswehadin
daysgoneby.(Forwhatitisworth,DOSfloppyformatstillusesFAT16.)
1diskblock=512bytes
1K=1024bytesor2blocks
1Meg=1Ksquaredor10242blockunits
1GB=1Kcubedor1024bytes*1024*1024=1,073,741,824
1GB/512=2,097,152diskblocks
2GB=2*1GB=2,147,483,648(notice1greaterthanmaxsigned32bitvalue)
2GB/512=4,194,304diskblocks
4GB=4*1GB=4,294,967,296(notice1greaterthanmaxunsigned32bitvalue)
4GB/512=8,388,608diskblocks
32767*512=16,776,704
16Meg=16*1024*1024=16,777,216
28
Chapter1Fundamentals
Chapter1Fundamentals
29
Summary
Despiteallofitslimitationsandfaults,thexBASEdatastoragemethodwasgroundbreaking
whenithitthemarket.Withoutsomeformofindexedfilesystem,thePCwouldnothavecaught
on.
Itisimportantforbothusersanddevelopersto understand thelimitationsofany chosen
storage method before developing an application or systems around that method. While a
relationaldatabaseismuchmorerobustfromadatastoragestandpoint,itrequiresalotmore
investment and overhead. Even a free relational database requires someone to install and
configureitbeforeanapplicationcanbewrittenusingit.AdevelopercanuseaC/C++/Java/etc.
library and create a single executable file which requires no configuration, simply an empty
directorytoplaceitin.Thatprogramcancreateallofthefilesitneedsthenallowausertostore
andaccessdatainameaningfulfashionwithoutthemhavinganysignificantcomputerskills.
There willalways be arole for standalone indexed filesystems. Both commercial and
OpenSourcevendorsneeddatastoragemethodswhichrequirenousercomputerskills.Justhow
manycopiesofQuickendoyouthinkwouldhaveeversoldifauserhadtodownload+install
+configureaMySQLdatabasebeforeQuickenwouldinstallandletthemtracktheirexpenses?
Nomatterhowoldthetechnologyis,theneedforitstillexists.
ReviewQuestions
1. HowmanyfieldsdiddBASEIIIallowtobeinarecord?
2. WhatgeneralcomputingtermdefinesthetypeoffileanxBASEDBFreallyis?
3. WhatdoesxBASEmeantoday?
4. WhatwasthenoncommercialpredecessortoallxBASEproducts?
5. IntermsofthePCandDOS,wheredidthe64Kobject/variablesizelimitreallycomefrom?
6. WhatcompanysoldthefirstcommercialxBASEproduct?
7. IsthereanANSIxBASEstandard?Why?
8. WhatisthemaximumfilesizeforaDBFfile?Why?
9. WhatwasthemaximumnumberofbytesdBASEIIIallowedinarecord?dBASEII?
10. Whatform/typeofdatawasstoredintheoriginalxBASEDBFfile?
11. CanyoustorevariablelengthrecordsinaDBFfile?
12. DoesanxBASElibraryautomaticallyupdateallNDXfiles?
13. WhatistheacceptedmaximumprecisionforaNumericfield?
14. Whatisthemaximumlengthofafieldorcolumnname?
Chapter1Fundamentals
30
Pageleftblankintentionally.
Chapter1
Chapter1
Fundamentals
1.1 Ou
nt
OurrEnvironme
Environmen
IamwritingthebulkofthiscodeonadesktopPCrunningthe32bitKarmicKoalapre
releaseofKUbuntu.IhaveSunJava6installedonthismachine,butseveralearlierreleasesof
Javashouldworkjustfinewiththislibrary.
After unzipping the download file, I copied the JAR files into a working directory. Of
course,thenewerJavaenvironmentswillonlylookforclassfileslocally,notJARfiles,soyou
needtocreateaCLASSPATHenvironmentvariable.Iusethefollowingcommandfilesinceit
loadsjustabouteverythingIcouldwantintoCLASSPATH:
env1
1)
2)
3)
4)
5)
6)
7)
8)
9)
10)
11)
12)
13)
14)
15)
16)
17)
18)
19)
20)
21)
22)
23)
24)
25)
#! /bin/bash
#set -v
#sudo update-java-alternatives -s java-6-sun
export JAVA_HOME='/usr/lib/jvm/java-6-sun'
set_cp() {
local curr_dir=$(echo *.jar | sed 's/ /:/g')':'
local jvm_home_jars=$(echo $JAVA_HOME/*.jar | sed 's/ /:/g')':'
local shr_jars=$(echo /usr/share/java/*.jar | sed 's/ /:/g')':'
local loc_jars=$(echo /usr/local/share/java/*.jar | sed 's/ /:/g')':'
if [ "$curr_dir" == "*.jar" ]; then
unset curr_dir
fi;
export CLASSPATH=$(echo .:$curr_dir$jvm_home_jars$shr_jars$loc_jars)
}
ecp() {
echo $CLASSPATH | sed 's/:/\n/g'
}
# set class path by default
set_cp
#set +v
roland@logikaldesktop:~$ cd fuelsurcharge2
roland@logikaldesktop:~/fuelsurcharge2$ echo $CLASSPATH
roland@logikaldesktop:~/fuelsurcharge2$ source ./env1
roland@logikaldesktop:~/fuelsurcharge2$ echo $CLASSPATH
.:commons-logging-1.1.1.jar:junit.jar:xBaseJ.jar:xercesImpl.jar:/usr/lib/jvm/
java-6-sun/*.jar:/usr/share/java/hsqldb-1.8.0.10.jar:/usr/share/java/hsqldb.jar:/
usr/share/java/hsqldbutil-1.8.0.10.jar:/usr/share/java/hsqldbutil.jar:/usr/share/
java/ItzamJava-2.1.1.jar:/usr/share/java/jsp-api-2.0.jar:/usr/share/java/jspapi.jar:/usr/share/java/LatestVersion.jar:/usr/share/java/libintl.jar:/usr/share/
java/mysql-5.1.6.jar:/usr/share/java/mysql-connector-java-5.1.6.jar:/usr/share/
java/mysql-connector-java.jar:/usr/share/java/mysql.jar:/usr/share/java/
QuickNotepad.jar:/usr/share/java/servlet-api-2.4.jar:/usr/share/java/servletapi.jar:/usr/local/share/java/*.jar:
32
Chapter1Fundamentals
Asyoucansee,thatscriptfindseveryJARfileandaddsittomyenvironmentvariable.The
occasional*.jar valueinthesymboldefinitiondoesn't
appeartoimpacttheJVMwhenitgoes
searchingforclasses. Ifyoudon't
havetheJARfilesspecificallylistedinyourCLASSPATH
variable,thenyouwillseesomethinglikethisthefirsttimeyoutrytocompile:
roland@logikaldesktop:~/fuelsurcharge2$ javac example1.java
example1.java:3: package org.xBaseJ does not exist
import org.xBaseJ.*;
^
example1.java:4: package org.xBaseJ.fields does not exist
import org.xBaseJ.fields.*;
^
example1.java:5: package org.xBaseJ.Util does not exist
import org.xBaseJ.Util.*;
^
example1.java:18: cannot find symbol
symbol : variable Util
location: class example1
Util.setxBaseJProperty("fieldFilledWithSpaces","true");
Windows users will need to view the information provided by Sun on how to set the
CLASSPATHvariable.
http://java.sun.com/j2se/1.4.2/docs/tooldocs/windows/classpath.html
Youmayalsowishtolookatthismessagethread:
http://www.computing.net/answers/programming/howtosetjavaclasspathinvista/15739.html
1.2 Op
OpeenorCrea
norCreatte?
YouwillfindquiteafewexamplesofvariousxBASEprogramminglanguages/toolsonthe
Web. ExamplesarealittlescarceforxBaseJ,asisdocumentation,hence,thecreationofthis
book.Mostoftheexamplespissmeoff.Iunderstandthattheyaretryingtoshowthesimplestof
thingstoauserwhomayhavenoothercomputerknowledge,butthosewellmeaningexamples
showauserhowtodothingsbadly,andthatisexactlyhowtheywillcontinuetodothem.
ThemainWebsiteforxBaseJhastwoexampleswhich,whilewellmeaning,fallintothis
category: example1.javaandexample2.java. Thefirstcreatesadatabase,thesecondopensit.
Whileyoucanarguethatthecreatealwayswantedtocreate,justhavingtheopenexamplecrash
outwhenthefileismissingisprobablynotwhatyouwantwhendevelopinganapplicationwhich
willbesentoutintotheuniverse.Mostofyoudon't
eventhinkaboutwhysomeapplicationstake
solongtostartuptheveryfirsttimeyourunthem.Thestartupcodeforthoseapplicationsisvery
graciouslyrunningaroundcheckingforallofthenecessarydatafiles.Whenfilesaremissing,it
createsdefaultones.Justhowmanyofyouwoulduseawordprocessorifitrequiredyoutorun
somespecial(probablyundocumented)programbeforeitwoulddoanythingotherthancrashout?
Chapter1Fundamentals
33
WhenIimbibeenoughcaffeineandthinkaboutit,therealproblemistheconstructorusinga
Booleanforthedestroy parameter.ABooleangivesyouonlyTrueandFalse.Aproduction
classsystemneedsthreeoptions:
1. Useexisting
2. Overwrite
3. Createifmissing
Ifyouhavereadsomeofmyotherbooksyouwillknowthatmanylanguagesnamethistype
ofparameterorattributedisposition orfile disposition. TheDBFconstructordoesn't
havea
filedispositionattribute,sowehavesomelessthangreatexamplesfloatingaround.
I'm
notgoingtodiscussJavamuchinthisbook.IwillpointoutodditiesasIseethem,butif
youarelookingforaJavatutorial,therearemanyofthoseontheWeb.I've
evenwrittenabook
onJavawhichsomepeoplelike.(The MinimumYouNeedtoKnowAboutJavaonOpenVMS
Volume1 ISBN139780977086610) I'm
aveteransoftwaredeveloper,butnotatenured
Javadeveloper.Afewdiscussionsofodditiesaside,wearereallyfocusingonhowtousexBaseJ
withJavainthisbook.
Thereareveryfewclassesofapplicationswhichalwaysneedtocreateanindexedfilewhen
theyrun.MostbusinesssystemsusethedispositionofCreate ifmissing. Manywilldisplay
some kind of messagestating they arecreating a missing indexedfile, just in case it wasn't
supposedtobemissing,butingeneral,onlyextracttypeapplicationsalwaysneedtocreatewhen
itcomestoindexedfiles.
Incaseyoudonotunderstandthephraseextracttype applications, these areapplications
which arerunagainstlargedatasetsthatpulloutcopiesofrecords/rowswhichmeetcertain
criteriaandplacethesecopiesinafile.Thefileisknownasanextractfileandtheapplication
whichcreatesitanextractapplication.
Chapter1Fundamentals
34
1.3 Example1
example1.javaisrepresentativeofthefirstexampleprogramfloatingaroundontheWebat
thetimeofthiswriting.Notethatsomeolderexamplesdon't
showtheproperimportstatements.
YouneedtoincludethefullpathasIhavedonewithlistinglines3through5.
example1.java
1)
2)
3)
4)
5)
6)
7)
8)
9)
10)
11)
12)
13)
14)
15)
16)
17)
18)
19)
20)
21)
22)
23)
24)
25)
26)
27)
28)
29)
30)
31)
32)
33)
34)
35)
36)
37)
38)
39)
40)
41)
42)
import
import
import
import
import
java.io.*;
java.util.*;
org.xBaseJ.*;
org.xBaseJ.fields.*;
org.xBaseJ.Util.*;
aDB.createIndex("classId.ndx","classId",true,true);
// true delete ndx, true - unique index,
43)
aDB.createIndex("TchrClass.ndx","teacherID+classId", true, false);
//true - delete NDX, false - unique index,
44)
System.out.println("index created");
45)
46)
classId.put("JAVA10100");
47)
className.put("Introduction to JAVA");
48)
teacherId.put("120120120");
49)
daysMeet.put("NYNYNYN");
50)
timeMeet.put("0800");
51)
credits.put(3);
Chapter1Fundamentals
35
52)
UnderGrad.put(true);
53)
54)
aDB.write();
55)
56)
classId.put("JAVA10200");
57)
className.put("Intermediate JAVA");
58)
teacherId.put("300020000");
59)
daysMeet.put("NYNYNYN");
60)
timeMeet.put("0930");
61)
credits.put(3);
62)
UnderGrad.put(true);
63)
64)
aDB.write();
65)
66)
classId.put("JAVA501");
67)
className.put("JAVA And Abstract Algebra");
68)
teacherId.put("120120120");
69)
daysMeet.put("NNYNYNN");
70)
timeMeet.put("0930");
71)
credits.put(6);
72)
UnderGrad.put(false);
73)
74)
aDB.write();
75)
76)
77)
}catch(Exception e){
78)
e.printStackTrace();
79)
}
80) }
81) }
roland@logikaldesktop:~/fuelsurcharge2$ javac example1.java
roland@logikaldesktop:~/fuelsurcharge2$ java example1
index created
roland@logikaldesktop:~/fuelsurcharge2$
Listingline18containsaveryimportantpropertysetting. Bydefault,xBaseJpadsstring
fieldswithNULLbyteswhenwritingtodisk.Whiletherewasatimewhenthiswasdone,most
xBASEenvironmentsdidawaywiththatpractice.Asmoreandmoretoolsbecameabletoopen
rawdatafiles,itbecamenecessarytosupplyspaces.Pleaseconductthefollowingtest:
1.
2.
3.
4.
CompileandrunthisprogramasIhavedone.
UseOpenOfficetoopenclass.dbfinaspreadsheet.Lookcloselyatthedata.
Commentoutlistingline18;compileandrerunthisprogram.
UseOpenOfficetoopenclass.dbfinaspreadsheet.Lookcloselyatthedata.
Whatyouwillnoticeisthatthefirstspreadsheethadsomefunkylookingzerocharactersin
thetextcolumns. Thosecharacterswerethenullbytespaddingoutthecharacterfields. The
secondversionofthefileopenedmoreasyouexpected.Itshouldlookmuchlikethefollowing:
36
Chapter1Fundamentals
PleasenotecolumnFonthespreadsheet. Eventhoughthenumericdatabasecolumnwas
declared tohavetwodigits,wedon'tgetaleadingzero. ColumnE(TIME)mayseemabit
deceiving at first. This wasn'tdeclared as a numeric database column; it was declared as a
charactersotheleadingzerocouldbeforced.Listingline29iswhereCREDITS(columnF)is
declared,andlistingline28declaresTIMEMEET(columnE). Pleasenotethatnumericfield
declarations have two numeric parameters. The first is the size of the field including the
punctuationcharacters,andthesecondisthenumberofdecimalplaces.
Listingline21iswheretheinitialemptydatabasefileiscreated.TheBooleanvaluetrueas
thefinalparameterforcesfilecreation.
Onceyoucreateafield,ithastobeaddedtothedatabasebeforeitbecomesacolumninthe
database.Wedothisatlistinglines34through40.
Anindexeddatafileisn'tmuchuseunlessithasatleastoneindex. Twoindexfilesare
createdatlistinglines42and43. ThefirstBooleanvaluepassedintothesemethodscontrols
deletionofexistingfiles.Thesecondvaluecontrolswhethertheindexisauniquekeyornot.A
uniquekeywillallowonlyoneinstanceofavaluetobestoredasakeyforonlyonerecord.A
nonuniquekeywillallowthesamekeyvaluetopointtomultiplerecords.Youcannotguarantee
whatorderrecordswillberetrievedforrecordshavingthesamekeyvalue.Ifsomeonerebuilds
theindexfile,oraddsotherrecordsinthatrange,orpacksthedatabase,theretrievalordercan
change.JustbecausetherecordforFRED SMITH cameoutfirstinthisdepartmentreportrun
doesn'tmeanitwillcomeoutfirstnexttime.
Chapter1Fundamentals
37
Note:xBASEfilesdonotphysicallydeleterecords.Theyflagrecordsasbeingdeleted.The
onlywaytoreclaimthewastedspaceistocreateanewversionofthedatabasefilewithafunction
knownasPACK.Oneoftwothingswouldhappendependinguponthetoolinvolved:
1. Thedatafilewouldbewalkedthroughsequentiallyandrecordsnotflaggedasdeletedwould
beshuffledup,replacingdeletedornewlyemptiedrecords.
2. Anewversionofthedatabasewouldbecreatedwithatemporaryname.Thisversionwould
containonlythenondeletedrecordsfromtheoriginaldatabase.Uponcompletiontheoriginal
databasewouldbedeletedandthenewonerenamed.
Thesecondapproachwasmuchmoreefficient,butrequiredalotofdiskspace.Nomatter
whichapproachwastaken,allindexfilesforthedatabasehadtoberebuilt.UntilwehadMDX
files,mostlibrariesanddialectsofxBASEhadanoptionwhichwouldallowadevelopertocreate
anindexaneweachtimetheyopenedthefile.xbaseJhasthesameoption:
public
NDX(String name,
String NDXString,
DBF indatabase,
boolean destroy,
boolean unique) throws
xBaseJException, IOException
Whenyoupassinadestroyflagoftrue,xBaseJrebuildstheindexbasedupontherecords
currentlyinthedatabase.PleasenotethatifyoudonotPACKthedatabasepriortocreatinga
newindex,thenewindexwillcontainentriesfordeletedrecords.WhenyouopenanMDXtag,
theindexisautomaticallyrebuiltinplace.Wewilldiscusspackingmorelater.
PleaseturnbacktothescreenshotshowingthisdatabaseinanOpenOfficespreadsheetand
reallylookatrowone.Whenthisexampleprogramwaswrittentheprogrammerusedmixedcase
column names because that looked very Javalike. (It actually looked very PASCALian, and
PASCALisadeadlanguage,soyoudothemathonthatone.)Noticewhatactuallygotwrittento
thedatabase,though:itisalluppercase.Ihavefoundbugsovertheyearsinvarioustoolswhich
enduplettinglowercaseslipintotheheaderrecord.Itisagoodprogrammingpracticetoalways
useuppercaseinsideofstringswhichwillbeusedforcolumnorindexnames.Youwillneverbe
burnedbyanupcase()bugifyoualwayspassinuppercase.
Takeareallygoodlookatlistingline43. Thatkeyiscomposedoftwodatabasecolumns
concatenatedtogether.Onpage17ofthisbookyouweretoldthattheoriginaldBASEversion
supportedonlycharacterdata.Alln umeric valueswerestoredintheircharacterrepresentations
toincreaseportability.Thisfeaturealsomadeindexcreationwork.Wearen't
addingtwovalues
togetherwiththatsyntax,weareconcatenatingtwostringsintoonesort/keyvalue.
38
Chapter1Fundamentals
Chapter1Fundamentals
39
1.4 Exce
ption
ngandExample1
Excep
tionHandli
ndlin
IwillassumeyouarefamiliarenoughwithJavatoknowthatstatementswhichcanthrowan
exceptiontraditionallygetencapsulatedinatry/catchblock. Nearlyeveryexceptionclassyou
willeverencounterisderivedfromtherootJavaExceptionclass.Thisallowseverycatchblock
seriestohaveanultimatecatchallliketheoneyouseeatlistingline77.Asfaraserrorhandling
goes,itdoesn't
dosquatfortheuser.Thereisnorecoveryandtheywillhavenoideawhatthe
stacktracemeans.
Thecodeinthetryblockisreallywherethetrainwentofftherails.Yes,Iunderstandthe
intentwastoshowonlythemoststraightforwardmethodofcreatinganewxBASEfilewithan
index.Theactualflowwillgetlostifeachstatementhasitsownlocalizedtry/catchblock,but
youneedtogroupthingslogically.
Those of you unfamiliar with objectoriented error handling won'tbe familiar with this
particularrant.Othersmaybetiredofhearingit,butthenewbiesneedtobeeducated.Themove
tomoremodernlanguagesmeantamoveawayfromlinenumbersandGOTOstatements.While
thiswasn'ta bad thing in general, itreally waxed error handling. Mostprogrammers didn't
completelyembracetheloca lizederrorhandler methodology,andwithoutlinenumbersand
RESUMEstatementsthequalityoferrorhandlingtanked.Wehaveagoodexampleofthetypical
errorhandlingqualityItypicallyseewithJavainthisexample.Ifanystatementintherangeof
listinglines14through76throwsanexception,welandinthecatchblockwithoutanyideaof
whichstatementactuallythrewtheexception.Evenifwecouldidentifyexactlywhichlinethrew
theexception,wewouldhavenomethodofgettingbackthere.Javadoesn't
haveaRETRYor
RESUMEthatwouldallowustofixaproblemthencontinueon.
Manypeoplewilltryto characterize codelikethisasaprogrammer beinglazy,andthat
wouldbeunfair.The authorshereweretryingtoshowhowtodosomethingwithouttheerror
handlinggettingintheway. Thetroubleisthatmostoftheseexampleswillbemodifiedonly
slightlybyprogrammersnewtothefield,thendistributedtoothers.Theydon't
knowanybetter,
andcodelikethiswilleventuallycreepintoproductionsystems.
If you want to be even more unfair you can also point out that catching the universal
Exceptionclassasisdoneatlistingline77isnowlistedasabad/undesirablepracticebySun.
Lotsofcodecurrentlyinproductiondoesthis. Theproblemwithdoingthisisthatyoumask
reallyhardruntimeerrors(likeadiskfailureorbadRAM)whichreallyshouldn'tbemasked.Not
onlyistherenothingyoucandoabouttheminyourprogram,thesystemmanagerneedstoknow
aboutthemASAP!
Chapter1Fundamentals
40
Part of the desire for a clean and simple source listing came from the early days of
programming. Classicallytrainedprogrammers learnedstructuredanalysisanddesign. More
importantly, the first language they learned was BASIC. Later versions of BASIC removed
nearlyalllinenumbersfromthelanguage.Thismigrationmadethelanguagenearlyuseless.The
movetolocalizederrorhandlingwithWHENERRORIN...USE...ENDWHENconstructs
prettymuchruinedthelanguageforbusinessuse.Itallcameaboutbecausealotofpeopletrying
tolearnthelanguageeitherrefusedtokeepeitheraprintoutbytheirsideortwoeditwindows
open.
One of the very first executable lines you would find in most BASIC modules read as
follows:
99
Otherthancheckingafunctionreturnvalue,noothererrorhandlingexistedinthesource
untilyougottoBASICline32000.
32000 !;;;;;;;;;;
!
Old style error handling
!;;;;;;;;;;
SELECT ERL
CASE = 910%
L_ERR% = ERR
PRINT "Unable to open input file"; drawing_data$
PRINT "Error: ";L_ERR%;" ";ERT$( L_ERR%)
RESUME 929
CASE = 912%
L_ERR% = ERR
PRINT "Unable to open report file "; rpt_file$
PRINT "Error: ";L_ERR%;" ";ERT$( L_ERR%)
RESUME 929
CASE = 930%
PRINT "Invalid input"
PRINT "Please re-enter"
RESUME 930
CASE = 940%
L_ERR% = ERR
PRINT "Unable to retrieve record GE |";BEG_DATE$;"|"
PRINT "Error: ";L_ERR%;" ";ERT$( L_ERR%)
RESUME 949
CASE = 942%
B_EOF% = 1%
IF ERR <> 11%
THEN
L_ERR% = ERR
PRINT "Unable to fetch next input record"
PRINT "Error: ";L_ERR%;" ";ERT$( L_ERR%)
END IF
Chapter1Fundamentals
41
RESUME 942
CASE ELSE
ON ERROR GOTO 0
END SELECT
32767 ! End of module
PROGRAM_EXIT:
I'llbe the first to admit that this SELECT statement used to get out of hand. Some
programmers refused touseaSELECTsoyouhad anugly seriesofnestedIFTHENELSE
statements. Itdid,however,leavethelogicflowcleanandapparent(ifyouwereacompetent
programmer)anditallowedyoutohandlejustabouteveryerroryoucouldpotentiallyrecover
from.RESUMEandRETRYallowedustoreturnprogramcontroltoanylinenumberorlabelin
theprogram.Someabusedit,forcertain,butthepowerandgraceofthistechnologyislacking
fromallOOPerrorhandlingtoday.
EverybodywantsthecleanlookthatBASICwitholdstyleerrorhandlinghad,somostJava
programshavenousableerrorhandling.
1.5 rollie1.j
rollie1.jaava
Quitesimply, wearegoing totakeexample1.java,fixafewthings,thenadd someprint
functionality.Imuststressthatthisisn't
agreatexample,butitisaverycommondesign.Ihave
encounteredthissamedesigntimeandtimeagain,nomatterwhatlanguageorxBASElibrarywas
beingused.
rollie1.java
1)
2)
3)
4)
5)
6)
7)
8)
9)
10)
11)
12)
13)
14)
15)
16)
17)
18)
19)
20)
21)
22)
23)
24)
import
import
import
import
import
java.io.*;
java.util.*;
org.xBaseJ.*;
org.xBaseJ.fields.*;
org.xBaseJ.Util.*;
Chapter1Fundamentals
42
25)
26)
27)
28)
29)
30)
31)
32)
33)
34)
35)
36)
37)
38)
39)
40)
41)
42)
43)
44)
45)
46)
47)
48)
49)
50)
51)
52)
53)
54)
55)
56)
57)
58)
59)
60)
61)
62)
63)
64)
65)
66)
67)
68)
69)
70)
71)
72)
73)
74)
75)
76)
77)
78)
79)
80)
81)
82)
83)
84)
85)
86)
87)
if (!continue_flg) {
continue_flg = true;
create_database(); // if none exists create
if (continue_flg)
add_rows();
} // end test for successful open of existing database
//;;;;;
// You cannot just blindly run the report.
// We could have tried to create a database on a full disk
// or encountered some other kind of error
//;;;;;
if ( continue_flg) {
dump_records();
dump_records_by_primary();
dump_records_by_secondary();
aDB.close();
} // end test for open database
}catch(IOException i){
i.printStackTrace();
} // end catch
} // end do_it
//;;;;;;;;;;
// method to add some rows
//
// Notice that I added the rows in reverse order so we could
// tell if the unique index worked
//;;;;;;;;;;
private void add_rows() {
try {
classId.put("JAVA501");
className.put("JAVA And Abstract Algebra");
teacherId.put("120120120");
daysMeet.put("NNYNYNN");
timeMeet.put("0930");
credits.put(6);
UnderGrad.put(false);
aDB.write();
classId.put("JAVA10200");
className.put("Intermediate JAVA");
teacherId.put("300020000");
daysMeet.put("NYNYNYN");
timeMeet.put("0930");
credits.put(3);
UnderGrad.put(true);
aDB.write();
Chapter1Fundamentals
88)
89)
90)
91)
92)
93)
94)
95)
96)
97)
98)
99)
100)
101)
102)
103)
104)
105)
106)
107)
108)
109)
110)
111)
112)
113)
114)
115)
116)
117)
43
classId.put("JAVA10100");
className.put("Introduction to JAVA");
teacherId.put("120120120");
daysMeet.put("NYNYNYN");
timeMeet.put("0800");
credits.put(3);
UnderGrad.put(true);
aDB.write();
//;;;;;;;;;;
//
Method to create a shiny new database
//;;;;;;;;;;
private void create_database() {
try {
//Create a new dbf file
aDB=new DBF("class.dbf",true);
attach_fields(true);
aDB.createIndex("classId.ndx","classId",true,true);
// true delete ndx, true - unique index,
118)
aDB.createIndex("TchrClass.ndx","teacherID+classId", true, false);
//true - delete NDX, false - unique index,
119)
System.out.println("created database and index files");
120)
121)
} catch( xBaseJException j){
122)
j.printStackTrace();
123)
continue_flg = false;
124)
} // end catch
125)
catch( IOException i){
126)
i.printStackTrace();
127)
} // end catch IOException
128)
} // end create_database method
129)
130)
//;;;;;;;;;;
131)
//
Method to open an existing database and attach primary key
132)
//;;;;;;;;;;
133)
public void open_database() {
134)
try {
135)
//Create a new dbf file
136)
aDB=new DBF("class.dbf");
137)
138)
attach_fields( false);
139)
140)
aDB.useIndex("classId.ndx");
141)
System.out.println("opened database and primary index");
142)
} catch( xBaseJException j){
143)
continue_flg = false;
144)
} // end catch
145)
catch( IOException i){
146)
continue_flg = false;
147)
} // end catch IOException
148)
} // end open_database method
Chapter1Fundamentals
44
149)
150)
151)
152)
153)
154)
155)
156)
157)
158)
159)
160)
161)
162)
163)
164)
165)
166)
167)
168)
169)
170)
171)
172)
173)
174)
175)
176)
177)
178)
179)
180)
181)
182)
183)
184)
185)
186)
187)
188)
189)
190)
191)
192)
193)
194)
195)
196)
197)
198)
199)
200)
201)
202)
203)
204)
205)
206)
207)
208)
209)
210)
211)
//;;;;;;;;;;
//
Method to populate known class level field objects.
//
This was split out into its own method so it could be used
//
by either the open or the create.
//;;;;;;;;;;
private void attach_fields( boolean created_flg) {
try {
if ( created_flg) {
//Create the fields
classId
= new CharField("classId",9);
className
= new CharField("className",25);
teacherId
= new CharField("teacherId",9);
daysMeet
= new CharField("daysMeet",7);
timeMeet
= new CharField("timeMeet",4);
credits
= new NumField("credits",2, 0);
UnderGrad
= new LogicalField("UnderGrad");
//Add field definitions to database
aDB.addField(classId);
aDB.addField(className);
aDB.addField(teacherId);
aDB.addField(daysMeet);
aDB.addField(timeMeet);
aDB.addField(credits);
aDB.addField(UnderGrad);
} else {
classId
className
teacherId
daysMeet
timeMeet
credits
UnderGrad
}
=
=
=
=
=
=
=
(CharField) aDB.getField("classId");
(CharField) aDB.getField("className");
(CharField) aDB.getField("teacherId");
(CharField) aDB.getField("daysMeet");
(CharField) aDB.getField("timeMeet");
(NumField) aDB.getField("credits");
(LogicalField) aDB.getField("UnderGrad");
Chapter1Fundamentals
212)
213)
214)
215)
216)
217)
218)
219)
220)
221)
222)
223)
224)
225)
226)
227)
228)
229)
230)
231)
232)
233)
234)
235)
236)
237)
238)
239)
240)
241)
242)
243)
244)
245)
246)
247)
248)
249)
250)
251)
252)
253)
254)
255)
256)
257)
258)
259)
260)
261)
262)
263)
264)
265)
266)
267)
268)
269)
270)
271)
272)
273)
274)
45
aDB.gotoRecord( x);
}
catch( xBaseJException j){
j.printStackTrace();
} // end catch IOException
catch( IOException i){
i.printStackTrace();
} // end catch IOException
System.out.println( classId.get() + " " + className.get() +
" " + teacherId.get() + " " + daysMeet.get() + " " +
timeMeet.get() + " " + credits.get() + " " +
UnderGrad.get());
} // end for x loop
} // end dump_records method
//;;;;;;;;;;
//
Method to dump records via primary key
//;;;;;;;;;;
public void dump_records_by_primary() {
System.out.println( "\n\nRecords in primary key order\n");
System.out.println( "classId
className
" +
"teacherId daysMeet time cr UnderGrad");
try {
aDB.useIndex("classId.ndx");
continue_flg = true;
aDB.startTop();
while( continue_flg) {
aDB.findNext();
System.out.println( classId.get() + "
className.get() + " " +
teacherId.get() + " " +
daysMeet.get() + " " +
timeMeet.get() + " " +
credits.get() + " " +
UnderGrad.get());
" +
//;;;;;;;;;;
//
Method to dump records off by secondary key
//;;;;;;;;;;
public void dump_records_by_secondary() {
System.out.println( "\n\nRecords in secondary key order\n");
System.out.println( "classId
className
" +
"teacherId daysMeet time cr UnderGrad");
try {
aDB.useIndex("TchrClass.ndx");
continue_flg = true;
Chapter1Fundamentals
46
275)
aDB.startTop();
276)
277)
while( continue_flg) {
278)
aDB.findNext();
279)
280)
System.out.println( classId.get() + "
281)
className.get() + " " +
282)
teacherId.get() + " " +
283)
daysMeet.get() + " " +
284)
timeMeet.get() + " " +
285)
credits.get() + " " +
286)
UnderGrad.get());
287)
288)
} // end while loop
289)
}
290)
catch( xBaseJException j) {
291)
continue_flg = false;
292)
}
293)
catch( IOException i) {
294)
continue_flg = false;
295)
}
296)
297)
} // end dump_records_by_secondary method
298) } // end class rollie1
" +
ThefirstthingyouwillnoticeaboutthisexampleisthatIrippedoutthemain()method.Most
peoplewritingJavaexamplestrytogetbywithasinglesourcefileexample,evenwhentheyare
usingacomplexlibraryordatabasesystem. I'm
nowherenearOne WiththeObject levelof
OOPwiththisdesign,butitistypicalofthingsyouwillencounterinthefield.
Thisdesignworkswhenyouhavecreatedasinglefiledatabasewhichistobeusedbyone
andonlyoneapplication. Thisdesignfailsassoonasyouneedtousethatsamedatabasein
anotherapplication. Whenyouenterashopthathadaprogrammerwholikedthisdesign,you
willusuallybeenteringafterthatprogrammerhasleft(orwasaskedtoleave).Whenyouneedto
addadditionalfunctionalityyoueitherhavetocutandpastelargechunksofcodeoutofthisclass
intoanewone,oryouwatchthisclassgrowtobehundredsofthousandsoflinesofsource.
One of the many things I don'tlike about Java is its lack of header files. Most Java
developersendupusingsomekindofIDElikeEclipse,notbecauseit'sa
goodeditor,butbecause
ithasbuiltinJavaspecificfunctionalitywhichwillcreateviewsofallthemethodsandmembers
inaclassifyouloadthecorrectplugin. InC++wehadheaderfiles inwhich theclasswas
prototypedandyoucouldeasilyseeallofitsmethodsandmembers.Thissourcefileisjustshyof
300 lines in length, and if I didn'tprefix my methods with a comment containing ten ;
charactersyouwouldhavetroublelocatingthem. Imaginewhatitislikewhenthelistingis
12,000lineslong.
Chapter1Fundamentals
47
Allinstancesofthedatabaseandcolumnnamesaremovedouttotheclasslevelinthisclass.
Doingsoallowsthemtobesharedbyallmethodsintheclass.Iflaggedthemasprivatesoothers
couldn'ttouchthemfromoutsidetheclass.
Listing line 25 is where the public method do_it() begins. This is really the whole
application.Theflowwouldbealittlebiteasiertoreadifwedidn't
havetokeepcheckingthe
continue_flgvariable,orifJavaallowedstatementmodifierslikeDECBASICdid:
GOSUB C2000_PAGE_HEADING
A lot of people complained about statement modifiers, but those people never wrote
productionsystems.Eventually,BASICbecametheonlysurvivingcommerciallanguagetohave
thissyntax.Theflowofthisparticularmethodwouldcleanupconsiderablyifwecouldusesuch
syntax.
Evenwiththecumbersomeifstatements,youshouldbeabletoascertaintheflowofthe
method.Firstwetrytouseanexistingdatabase.Ifthatfails,wecreatethedatabase.Ifdatabase
creationwassuccessful,weaddsomedatatothedatabase.Oncewehavesuccessfullyestablished
adatabase,wereportoffthedatainthreedifferentsortorders,closethedatabase,andexit.
Pleasetakenoticeoflistinglines67,78,and88.Theselinesassigntheprimarykeyvaluesto
each row that wewillbeadding. Whatyou need to notice isthat I stored theserecords in
descendingorderbyprimarykey.Havingdatawhichwasaddedinaknownsortorderiscritical
tounderstandingwhetherourreportsworkedcorrectlyornot.
Bothcreate_database()andopen_database()callamethodnamedattach_fields(). Wehave
verylittletodiscussinthecreate_database()methodsincemuchofthecodewasstolenfrom
example1.java.Youwillnoticethatinopen_database()wedon't
providethetrue parameterto
theDBFconstructor. ItisthisparameterwhichtellstheDBFconstructorwhether tousean
existingdatabaseorcreateanewone.
Noticeatlistingline140thatwedon't
createanindex,butratherusetheexistingindexfile.
Using an existing index file can be an incredibly dangerous thing to do when working with
xBASEfiles.Attemptingtocreateashinynewindexfileusingthesamehardcodednameaslast
timecanalsobeadangerousthingasanotherusermayhavethefileopened,whichmeansyour
processwillfail.DuringthedarkdaysofDOSitwasalmostimpossibletogenerateauniquefile
name every time. The 8.3 naming schema was pretty restrictive. Not many of your disk
partitionswillbeFAT16thesedays,though.FAT32cameontothescenein1996withWindows
95OSR2.FloppydiskdriveswillstilluseFAT16,butmostofthesuper floppy disks(120and
240Meg)willuseFAT32orsomethingelse,whichallowsforverylongfilenames.
48
Chapter1Fundamentals
IntheDOSdays,mostxBASElibrariesdidn't
haveareindex()function.Theywereallbusy
tryingtobemultiuserandtheresimplywasn't
agoodmultiusermethodofrebuildinganindex
whileotherusers had thefile open. (There reallyisn'teven today.) We alsodidn'thave a
universaltemporarydirectory.Thereweresomeenvironmentvariablesyoucouldhopewereset
(TMP,TEMP,etc.),butallinall,youwereonyourown.
FewthingswouldcausemoreproblemsinxBASEsoftwarethanoneprogrammerforgetting
toopentheproduc tion indexwhentheyaddedrecordstothedatabase.Anyapplicationwhich
usedtheproduction indextoaccessrecordswouldsimplyskipprocessinganyrecordsin the
databasewhichdidn'thaveanindex.
Inafeatofpurelydefensivecoding,mostprogrammerswouldtakeastabatgeneratinga
uniquefilenamefortheindex,thencreatetheneededindexaftertheyopenedthedatabase.When
youhadthousandsofrecordsonthoseoldandslow40Megharddrives,itcouldtakeminutesfor
thefirstscreentoload,butatleastyouknewyouwereprocessingallofthedata...ordidyou?
Nobody elseknewaboutyourshinynewindexedfile. Thismeanstheyweren'tbothering to
updateanyentriesinitwhiletheywereaddingrecordstothedatabase.Thelackofacommon
OSenforcedtemporarydirectoryledtoalotofpoliciesandproceduresconcerningwhatfilesto
delete when. More than one shop blew away their production index while trying to delete
temporaryindexfilestofreeupspace.
Some shops learned to live with and work around the pitfalls. They put policies and
proceduresinplacesousersdidn't
havetowaitentireminutesforthefirstapplicationscreento
displaydata.TheworldofxBASEeventuallycreatedtheMDXfileinanattempttosolvethese
issues.WewilldiscusstheMDXfileinalaterexample.
Listinglines159through183showabitofdifferencebetweencreatinganewfileandusing
anexistingfile.Whenthedatabaseisshinyandnew,youmustcreatethecolumnobjects,then
addthemtothedatabaseobject.Theactofaddingthemtotheobjectactuallycreatesthecolumns
inthedatabase.Whenyouareusinganexistingdatabaseyoumustpullthefielddefinitionsoutof
thedatabaseobject. Ifyoucreatefielddefinitionsandattempttoaddthem,theywillbenew
columns,unlesstheyhaveamatchingcolumnnamealreadyinthedatabase,thenanexception
willbethrown.
OnethingIwouldhavelikedtoseeninthelibrarywasaseriesofge t methods,onefor
eachsupporteddatatype.Thiswouldmoveanycastinginsideofaclassmethod.ManyoftheC/
C++librariesIusedovertheyearshadthisfunctionalitytokeepcodeascastfreeaspossible.It
wouldbenicetocallamethodnamedaDB.getCharField(classId) andhaveiteitherreturna
CharFieldobjectorthrowanexception.Ofcourse,itwouldalsobeniceiftheexceptioncould
Chapter1Fundamentals
49
haveactualerrorcodeswhichtoldyouwhattheexceptionwas,notjustthatithappenedtohave
died.
Thedump_records()methodstartingonlistingline205doesn't
havemuchcomplexitytoit.I
useasimpleforlooptoreadfrom1tothemaximumnumberofrecordsinthedatabase,printing
eachrecordout.ThemethodgetRecordCount()returnsthecurrentrecordcountinthedatabase.
ThemethodgotoRecord()physicallyreadsthatrecordnumberfromthedatabase.Youmay
recall that I told you xBASE is a relative file format. All relative file formats are actually
accessedbyrecordnumber. Theindexfilesarereallystoringakeyvalueandcorresponding
recordnumberinaBtree(binarytree)fashion.Thismethodwalksthroughtherecordsasthey
werewrittentothedatafilewithoutpayinganyattentiontokeyvalues.
Atlistingline239,Ishowyouhowtoclearthec urrentrecord valuestoredinternallyinthe
class.ThemethodstartTop()willsetthecurrentrecordvaluetozeroandmovetheindexpointer
backtotherootofthecurrentlyactiveindex.
Mostofyouwouldhavetriedtouseread()insteadoffindNext()atlistingline241. Iwill
admitthatonceIreadthecommentsinthesourcefile,Igaveitawhirlaswell.Itbehavedthe
wayIthoughtitwould.AnyofyouwhohavereadThe MinimumYouNeedtoKnowtoBean
OpenVMSApplicationDeveloper ISBN139780977086603wouldhaveexpectedittonot
work as well. There is a problem with most read and readNext type functions in most
languages. Youmustfirstestablishakeyofreference viasomeotherIOoperationbeforean
ordinaryreadorreadNexttypefunctionwillwork.FindandfindNexttypemethodsarealmost
alwayssetuptofindakeyvalueequal toorgreaterthan thevaluetheycurrentlyhaveinsome
designatedkeybuffer.Ifthatbufferisnull,theytendtofindthefirstrecordinthefileviathe
currentlyactiveindex.
Chapter1Fundamentals
50
Noticeineachofthereportmethodsthatwehavetocalltheget()methodforeachfieldin
ordertoobtainitsvalue.Wedonothavedirectaccesstothedatavaluesinthislibrary.Some
othersallowfordirectretrieval andsomedon't.Idon'treallyhave apreferencethesedays.
DuringmyDOSprogramming daysIalwayswantedtouseClibraries,whichalloweddirect
accesstothevalues.Thiswasn't
becauseIwasanUbergeektryingtobeonewiththeCPU,but
becauseofthewonderful640Kmemorylimitationoftheday.IfIallocatedthestorageforthe
returnedvalues,IcouldputitinanEMSpagewhichcouldbeswappedoutondemand.Most
vendorsofthirdpartylibrariesrefusedtoprovideanysupportifyouwereswappingtheircodein
andoutofthelower640Kviaanoverlaylinker.
Compilingandrunning thisthingisn't
abigchallenge,assumingyou'vealreadygotyour
CLASSPATHenvironmentvariableset.
roland@logikaldesktop:~/fuelsurcharge2$ rm class.dbf
roland@logikaldesktop:~/fuelsurcharge2$ rm teacher.dbf
roland@logikaldesktop:~/fuelsurcharge2$ java testRollie1
created database and index files
Records in the order they were entered
classId
JAVA501
JAVA10200
JAVA10100
className
teacherId daysMeet
JAVA And Abstract Algebra 120120120 NNYNYNN
Intermediate JAVA
300020000 NYNYNYN
Introduction to JAVA
120120120 NYNYNYN
time
0930
0930
0800
cr
6
3
3
UnderGrad
F
T
T
time
0800
0930
0930
cr
3
3
6
UnderGrad
T
T
F
time
0800
0930
0930
cr
3
6
3
UnderGrad
T
F
T
className
teacherId daysMeet
Introduction to JAVA
120120120 NYNYNYN
Intermediate JAVA
300020000 NYNYNYN
JAVA And Abstract Algebra 120120120 NNYNYNN
className
teacherId daysMeet
Introduction to JAVA
120120120 NYNYNYN
JAVA And Abstract Algebra 120120120 NNYNYNN
Intermediate JAVA
300020000 NYNYNYN
Ideletedtheexistingdatafileandindexbyhandsoyoucouldseetheresultofafirstrun
situation.Youwillalsowanttodothisifyouhavecompiledandruntheexample1.javaprogram.
Thisparticularsetoftestdataisreordered.Ifyourunitagainsttheoriginaldatafile,youwon't
seeanydifferencesbetweenthefirstandthesecondreport.
Justtobecomplete,letmeshowyouthesimplelittletestsource.
Chapter1Fundamentals
51
testRollie1.java
1) public class testRollie1 {
2)
3)
public static void main(String args[]){
4)
rollie1 r = new rollie1();
5)
6)
r.do_it();
7)
8)
} // end main method
9)
10) } // end class testRollie1
1.6 Progra
mming
As
sign
ment
ogram
mingAs
Assign
signm
ent1
Modifyrollie1.javatoremovetheopeningoftheprimarykeyfilewhenopeningtheexisting
database. Replace dump_records_by_primary() and dump_records_by_secondary() with one
methoddump_records_by_key() whichacceptsaStringparameter thatistheindexfilename.
Compileandrunyourprogram.Testitwithbothavalidfilenameandanonexistentfilename.
1.7 SizeMatters
Iknow,thatsectionheadingmakesitsoundlikeI'm
goingtobesellinggymequipmentor
maleenhancementtablets,butitreallyistruewithxBaseJ:sizereallydoesmatter.Itisyourjob
to ensure your application doesn'toverrun a numeric field. Character fields will throw an
exception,butnumericfieldswillnot.
example5.java
1)
2)
3)
4)
5)
6)
7)
8)
9)
10)
11)
12)
13)
14)
15)
16)
17)
18)
19)
20)
21)
22)
23)
24)
25)
26)
import
import
import
import
import
java.io.*;
java.util.*;
org.xBaseJ.*;
org.xBaseJ.fields.*;
org.xBaseJ.Util.*;
Chapter1Fundamentals
52
27)
28)
29)
30)
31)
32)
33)
34)
aDB.createIndex("roik0.ndx","pctrtn",true,true);
// true delete ndx, true - unique index,
35)
System.out.println("\nindex created ... now adding records");
36)
37)
fundnm.put("LargeCap");
38)
pctrtn.put(-4.5);
39)
invstamt.put(550000);
40)
aDB.write();
41)
42)
fundnm.put("MidCap");
43)
pctrtn.put(2.3);
44)
invstamt.put(120000);
45)
aDB.write();
46)
47)
fundnm.put("Growth");
48)
pctrtn.put(3.4);
49)
invstamt.put(45000000);
50)
aDB.write();
51)
52)
fundnm.put("SmallCap");
53)
pctrtn.put(-6.2);
54)
invstamt.put(23000000000.0);
55)
aDB.write();
56)
57)
fundnm.put("Spyder");
58)
pctrtn.put(2);
59)
invstamt.put(78923425);
60)
aDB.write();
61)
62)
fundnm.put("PennyStk");
63)
pctrtn.put(26.5);
64)
invstamt.put(888000);
65)
aDB.write();
66)
67)
fundnm.put("BioTech");
68)
pctrtn.put(-34.6);
69)
invstamt.put(345567.89);
70)
aDB.write();
71)
72)
System.out.println( "Records added\n");
73)
System.out.println( "ROI
Fund
Amount");
74)
System.out.println( "-------------------------------");
75)
76)
aDB.startTop();
77)
for( int i=0; i < aDB.getRecordCount(); i++)
78)
{
79)
aDB.findNext();
80)
System.out.println( pctrtn.get() + "
" + fundnm.get() +
81)
invstamt.get());
82)
}
83)
84)
}catch(Exception e){
85)
e.printStackTrace();
86)
}
87) }
88) }
Chapter1Fundamentals
53
Noticeatlistingline24thatIdeclarepctrtntobesixlongwiththreedecimalplaces.Ithen
goaheadandmakethisanindexforthedatafile.Atlistingline68Iassignthevalue34.6tothe
field.Itseemsinnocentenough,doesn'tit?Let'stakealookatwhathappens.
roland@logikaldesktop:~/fuelsurcharge2$ javac example5.java
roland@logikaldesktop:~/fuelsurcharge2$ java example5
index created
Records added
ROI
------6.200
-4.600
-4.500
2.000
2.300
3.400
26.500
...
Fund
-------------------SmallCap
BioTech
LargeCap
Spyder
MidCap
Growth
PennyStk
Amount
------23000000000.00
345567.89
550000.00
78923425.00
120000.00
45000000.00
888000.00
TakealookatwhereourBioTechrecordendedup.That's
notthevalueweassigned,isit?
Therewasnoexceptionthrownwhenwerantheprogram;wesimplygotthewrongvaluestored.
1.8 Progra
mming
As
sign
ment
ogram
mingAs
Assign
signm
ent2
Modifyexample5.javabyexpandingthesizeoftheROIcolumnandtrytoaddarecordwith
afundnamegreaterthan20characters.
1.9 Exami
nin
Examin
ingga
aDBF
Fromthe1960sthroughmuchofthe1980s,softwarevendorstriedtolockpeopleintotheir
productlinesinavarietyofways.Oneofthemosttriedandtruemethodswastocreateyourown
proprietarydatafileformat.Evenifyouusedtheindexedfilesystemprovidedbythecomputer
operating system,aslongasyoudidn'tcoughuptherecordlayouts, your customerscouldn't
accesstheirdatawithoutusingyoursoftwareand/orbuyingadditionalservicesfromyou.Given
thatMBAsarecreatureswhogotoschooltohaveboththeirethicsandsoulremovedsotheycan
runabusinessinthemostprofitablemethodpossible,thefeeskeptgoingupandthelawyerskept
gettingricheroverbreachofcontractlawsuits.
AshtonTatecertainlytried togothatroutewithdBASE,buttherewasalotofexisting
technologyoutthereforpeopletoworkwith.Thelawyersandtheattitudecontinuedtoturnall
potentialnew customers against Ashton Tateand theother xBASEplatforms gainedground.
Ultimately,therewerequiteafewthingsthatdidAshtonTatein.Firstoff,allofthexBASEfile
formatsstoredthefilelayoutinformationintheheader.Allyouhadtodowasfigureouthowto
parsetheheaderandyoucouldgettomostofthedata.Second,Vulcan,theoriginalversionof
Chapter1Fundamentals
54
whatbecamedBASEII,wasn't
releasedasacommercialproduct. Wedidn't
havetheInternet
backthen,butwehadBBSnetworkswhichparticipatedinechorelaysandgaveaccesscreditfor
fileuploads.OnceVulcanmadeittoacoupleofthelargerboards,itwaseverywhereinundera
month.Thisgavenearlyeverycompetingproductthesamestartingpoint.
Giventhememoryrestrictionsoftheday,AshtonTateandothersdidn't
havetheoptionof
hidingalloftheinformationinsomeencryptedformatandrequiringanenginetoberunninglike
MySQL,Oracle,oranyoftheotherdatabaseenginesoftoday. TheJetPropulsionLaboratory
wasn'tin
thebusinessofputtingoutcommercialsoftware.Theysimplyhadasevereneedtostore
datainsomeindexedformatforreportingpurposes.Aneedsoseverethatsomeonewasallowed
totakehowevermuchtimeittookthemtosolvetheproblem.Theychosetosolvetheproblemin
themosteasilysupportablemeansavailabletothematthetime.
Ifyouaren'tlong
inthetoothlikemyself,youprobablydon't
understandjusthoweasyitisto
supportthexBASEformat.Ournextexampleshouldgiveyousomeidea.
showMe.java
1)
2)
3)
4)
5)
6)
7)
8)
9)
10)
11)
12)
13)
14)
15)
16)
17)
18)
19)
20)
21)
22)
23)
24)
25)
26)
27)
28)
29)
30)
31)
32)
33)
34)
35)
36)
37)
import
import
import
import
import
import
java.io.*;
java.util.*;
java.text.*;
org.xBaseJ.*;
org.xBaseJ.fields.*;
org.xBaseJ.Util.*;
Chapter1Fundamentals
38)
39)
40)
41)
42)
43)
44)
45)
46)
47)
48)
49)
50)
51)
52)
53)
54)
55)
56)
57)
58)
59)
60)
61)
62)
63)
64)
65)
66)
67)
68)
69)
70)
71)
72)
73)
74)
75)
76)
77)
78)
79)
80)
81)
82)
83)
84)
85)
86)
87)
88)
89)
90)
91)
92)
93)
94)
95)
96)
97)
98)
99)
100)
55
"----------------------");
StringBuilder sb = new StringBuilder();
Formatter r = new Formatter( sb, Locale.US);
for( int i=1; i <= aDB.getFieldCount(); i++) {
try {
Field f = aDB.getField(i);
r.format( " %-25s
%1c
%4d
%4d\n",
f.getName(),
f.getType(),
f.getLength(),
f.getDecimalPositionCount());
} catch( xBaseJException x) {
System.out.println( "Error obtaining field info");
}
}
System.out.println( r.toString());
try {
aDB.close();
} catch( IOException o) {}
} // end showDBF method
//;;;;;;;;;;
// Method to dump all records in database
//;;;;;;;;;;
public void dump_records( String _dbfName) {
dump_records( _dbfName, -1);
} // end dump_records method
//;;;;;;;;;;
// Method to dump first N records from database.
//;;;;;;;;;;
public void dump_records( String _dbfName, int _reccount) {
int the_count = 0;
if (_reccount < 1) {
try{
aDB = new DBF( _dbfName);
the_count = aDB.getRecordCount();
aDB.close();
} catch( xBaseJException j){
System.out.println( "Unable to open " + _dbfName);
} // end catch xBaseJException
catch( IOException i){
System.out.println( "Unable to open " + _dbfName);
} // end catch IOException
} else {
the_count = _reccount;
} // end test for negative _reccount parameter
}
//;;;;;;;;;;
// Method to dump a range of records from start to end.
//;;;;;;;;;;
public void dump_records( String _dbfName, int _startRec,
int l_x=0;
int _endRec) {
Chapter1Fundamentals
56
101)
102)
103)
104)
105)
106)
107)
108)
109)
110)
111)
112)
113)
114)
115)
116)
117)
118)
119)
120)
121)
122)
123)
124)
125)
126)
127)
128)
129)
130)
131)
132)
133)
134)
135)
136)
137)
138)
139)
140)
141)
142)
143)
144)
145)
146)
147)
148)
149)
150)
151)
152)
153)
154)
155)
156)
157)
158)
159)
160)
161)
162)
163)
int curr_width=0;
StringBuilder sb = new StringBuilder();
Formatter r = new Formatter( sb, Locale.US);
try {
try {
int field_count = aDB.getFieldCount();
int heading_length = 0;
String dash_line = "";
for (int i=1; i <= field_count; i++) {
int fld_width = MAX_NAME_LEN;
int x;
Field f = aDB.getField(i);
String namStr = f.getName();
x = (fld_width > f.getLength()) ? fld_width : f.getLength();
String s8 = "%-" + x + "s ";
r.format( s8, namStr);
//
// I have never understood how Java could be declared
// so advanced by so many and the language not
// include something as fundamental as the STRING$()
// function from BASIC to generate an N length string
// of some character.
//
char[] dl = new char[ x];
Arrays.fill( dl, '-');
dash_line += new String(dl) + " ";
}
System.out.println( r.toString());
System.out.println( dash_line);
for (l_x=_startRec; l_x <= _endRec; l_x++) {
if (sb.length() > 0)
{
sb.delete(0, sb.length()); // nuke output buffer
}
aDB.gotoRecord( l_x);
for (int j=1; j <= field_count; j++) {
Field f = aDB.getField(j);
switch (f.getType()) {
case 'C':
CharField c = (CharField) f;
curr_width = (MAX_NAME_LEN > c.getLength()) ?
MAX_NAME_LEN : c.getLength();
String s = "%-" + curr_width + "s ";
r.format( s, c.get());
break;
case 'D':
Chapter1Fundamentals
164)
165)
166)
167)
168)
169)
170)
171)
172)
173)
174)
175)
176)
177)
178)
179)
180)
181)
182)
183)
184)
185)
186)
187)
188)
189)
190)
191)
192)
193)
194)
195)
196)
197)
198)
199)
200)
201)
202)
203)
204)
205)
206)
207)
208)
209)
210)
211)
212)
213)
214)
215)
216)
217)
218)
219)
220) }
57
DateField d = (DateField) f;
r.format( "%8s ", d.get());
break;
case 'F':
FloatField o = (FloatField) f;
curr_width = (MAX_NAME_LEN > o.getLength()) ?
MAX_NAME_LEN : o.getLength();
String s6 = "%" + curr_width + "s ";
r.format( s6, o.get());
break;
case 'L':
LogicalField l = (LogicalField) f;
curr_width = MAX_NAME_LEN;
String s1 = "%" + curr_width + "s ";
r.format( s1, l.get());
break;
case 'M':
case 'N':
NumField n = (NumField) f;
curr_width = (MAX_NAME_LEN > n.getLength()) ?
MAX_NAME_LEN : n.getLength();
String s2 = "%" + curr_width + "s ";
r.format( s2, n.get());
break;
case 'P':
PictureField p = (PictureField) f;
curr_width = (MAX_NAME_LEN > p.getLength()) ?
MAX_NAME_LEN : p.getLength();
String s3 = "%" + curr_width + "s ";
r.format( s3, p.get());
break;
default:
r.format("?");
} // end type switch
} // end inner for loop to print each field
System.out.println( r.toString());
// end for loop to write detail
aDB.close();
} catch( xBaseJException j){
System.out.println( "Error processing record ");
} // end catch xBaseJException
catch( IOException i){
System.out.println( "Unable to open " + _dbfName);
} // end catch IOException
} // end dump_records method
// end showMe class
58
Chapter1Fundamentals
Incasesomeofyoudon't
reallyknowanythingaboutJava,letmepointoutthatlistingline
10ishowyoudeclareaclassconstant.Thisconstantcanbereferencedfromanyapplicationeven
ifusersdon'tha
veaninstanceofthisclass,aslongastheyhaveimportedtheclassfile.Toaccess
ittheywouldsimplyneedtotypeshowMe.MAX_NAME_LENinanysourcefilewhichimports
the showMe class. The maximum name allowed by early xBASE implementations was ten
characters;avalueofelevenallowsforatrailingspace.
Listinglines22through29wereanattempttoshowyoulocalizederrorhandling. Itdoes
make the code ugly. If xBaseJException had a constructor which allowed for an integer
parameter,orbetteryet,anenumtype,wewouldn'thavetoperformlocalizedhandlingjusttotrap
foranopenerror.Ifallofthecodeisinonebigtry/catchblock,wehavenomethodoffiguring
outexactlywheretheexceptionoccurred.Yes,youcanprintthestacktrace,butifdoingsoonly
releasesaJARfilecontainingyourapplication,whatgoodisthattotheuser?
Oneofthefirstthingsthatshouldcatchyourattentionislistinglines32and33.Theheader
recordofaDBFactuallykeepstrackofboththerecordcountandthefieldcount.Weusethe
methodsprovidedbytheclasstoaccessthesevalues.
I need to get on my high horse a minute about StringBuilder and Formatter. Up until
FormatterwasaddedtotheJavalanguage,itwascompletelyunusableforbusinesspurposes.I
havebeenlambastedbymanyauselessPhDforpointingoutthatJavawasabsolutelyuselessin
thebusinessworldbecauseitwasphysicallyincapableofproducingacolumnarreport. Every
language those neverworkedintherealworld academics put down as being inferior to Java
becausetheyprecededitcould,anddid,producecolumnarreports.Youseethesereportsevery
timeyougetyourcreditcardstatement,phonebill,etc. Businesscannotfunctionwithoutthe
capabilitytoproducecolumnarreports.
TheClanguagegaveusaformatstringveryearlyon.Itevolvedovertheyearstobecome
quiteadynamicthing.Listingline46showsyouanexamplewhatweendedupwithinJava.It
resemblestheCformatstringinmanyways,butfailsinonecriticalway.TheCformatstring
allowedadevelopertousesomethinglikethefollowing:
printf( %-*s\n, curr_width, some kind of day);
Chapter1Fundamentals
59
Everyclassderivedfromitendsuphavingcodelikethis:
/**
* return the character 'D' indicating a date field
*/
public char getType()
{
return 'D';
}
Field.javanowhasthecodebelow.
/**
* @return char field type
*/
public abstract char getType();
Chapter1Fundamentals
60
Youwillnoticethatwehavemultipledump_records()methods.Allofthemtakingdifferent
parameters.Thisisanexampleofpolymorphism.ActuallyIwasforcedintoitbecauseJavaisn't
politeenoughtoallowdefaultargumentvalues,asdoesC++.Thefirstmethodwilldumpallof
therecordsinthedatabase,thesecondwilldumponlythefirstNrecordsinthedatabase,andthe
lastwilldumprecordsXthroughYfromthedatabase.
Ofcourse,inordertodumptherecords,onehastoknowwhateachcolumnisandhowwide
thecolumnwillbeuponoutput. Thefor loopatlistinglines148through 168takescareof
displayingthecolumnheadings.Thecalculationofxisanattempttocentertheheadingoverthe
datacolumn.
Takealookatlistinglines135through137.WhenyouprograminBASIConrealcomputers
youmakeastringofasinglecharacterbycallingSTRING$(len,ascii_value). Ifyouwantto
createastringof30hyphensyouwouldtypethefollowing:
STRING$( 30%, ASCII("-"))
The30%couldofcoursebeanintegervariablelikeX%.TheStringclassforJavacomesup
shortinthisarea.IntheworldofCprogrammingweusedtodeclareagenericbufferatthestart
ofamodule,thendothethreestepshuffle:
char
work_str[1024];
Cusednullterminatedstrings.Thefirststepnulledoutthebuffer.Thesecondstepputjust
therightnumberofcharactersintothebufferandthethirdstepaddedthebuffertothedestination
string. Itisn't
thatmuchdifferentthanwhatwewereforcedtodoinJava. Herewehadthe
restrictionthatJavadoesn'tusenullterminatedchararraysforstrings.Theexpedientmethodwas
todynamicallydeclarethechararrayeachpassthroughtheforloop. Thefill()methodofthe
Arraysclassallowsustoseteveryelementtoaspecificvalue.Finallywecanaddthehyphen
stringalongwithsomespacestothestringwhichwillactuallybeprinted.
Listinglines152through206getjustalittleugly.Thecodeisn't
complex,itsimplygotugly
trying to fit. I had to deal with page margin issues when writing this, hence the use of the
conditionaloperator?:. IfyouhavereadtheotherbooksinthisseriesyouwillknowthatIam
definitelyNOTafanofthisoperator.Itmakescodedifficulttoread,especiallyforanovice.Itis
reallyshorthandforif ()thenotherwise. Iftheexpressionintheparenthesisevaluatestotrue,
thenyoureturnthevaluebetweenthe?andthe:,otherwise,youreturnthevaluefollowingthe:.
ItistruethatIcouldhavereplacedeachofthoselineswiththefollowing:
Chapter1Fundamentals
61
Noneofyoureallywantedmetouseif statementsinsideofswitchcases,thoughifyou
workintherealworldyouwillseethemquiteoften.Asageneralrule,youarenotintrouble
untilyournestinggetsmorethan3levelsdeep.
The display logicforeachcolumn isn'tcomplex, butmight require abit of explanation.
MAX_NAME_LENisdefinedtobeelevenbecausetenusedtobethemaximumlengthfora
columnnameundermostxBASEflavors,andelevenensureswewillhaveatleastonetrailing
space.Whendisplayingadatacolumn,Iwantthisexampletobeatleastwideenoughtodisplay
thename. (Onethingwhichreallyannoysmeaboutmostspreadsheetapplicationsistheysize
columnstothedatasize,evenwhenthecolumnisaBoolean.) Whenwearedealingwitha
characterfieldIusethe intheformatstringtoleftjustifytheoutput.MosteverythingelseI
simplyletslamagainsttheright.Idon't
botherformattingdatevaluesinthisexample.Youcan
writethousandsoflinesofcodeformattingdatesineveryformatimaginable,andstillsomebody
willwantthedateformatteddifferently.
testShowMe.java
1) public class testShowMe {
2)
3)
public static void main(String args[]){
4)
showMe s = new showMe();
5)
6)
s.showDBF("class.dbf");
7)
System.out.println( "\n");
8)
s.showDBF( "teacher.dbf");
9)
System.out.println( "\n");
10)
System.out.println( "
Entire class.dbf");
11)
s.dump_records( "class.dbf");
12)
System.out.println( "\n");
13)
System.out.println( "
Records 2 and 3 from class.dbf");
14)
s.dump_records( "class.dbf", 2, 3);
15)
System.out.println( "\n");
16)
System.out.println( "
First record from teacher.dbf");
17)
s.dump_records( "teacher.dbf", 1);
18)
19)
} // end main method
20)
21) } // end class testShowMe
ThetestmodulesimplydisplaysvariousthingsfromthetwoDBFfilescreatedbythesample
programswhicharepostedonthexBaseJWebsite.Ihaveshownyoutheprogramwhichcreates
theclass.dbffileinthisbook.Wedon't
reallyhaveanyneedtocovertheteacher.dbf,butitis
createdbyexample3.javafoundinthexBaseJdistributionorontheSourceForgesite.
Chapter1Fundamentals
62
Entire class.dbf
CLASSID
CLASSNAME
----------- ------------------------JAVA501
JAVA And Abstract Algebra
JAVA10200
Intermediate JAVA
JAVA10100
Introduction to JAVA
TEACHERID
----------120120120
300020000
120120120
DAYSMEET
----------NNYNYNN
NYNYNYN
NYNYNYN
TIMEMEET
----------0930
0930
0800
CREDITS
----------6
3
3
UNDERGRAD
----------F
T
T
Records
CLASSID
----------JAVA10200
JAVA10100
TEACHERID
----------300020000
120120120
DAYSMEET
----------NYNYNYN
NYNYNYN
TIMEMEET
----------0930
0800
CREDITS
----------3
3
UNDERGRAD
----------T
T
DEPT
----------0800
TENURE
----------T
WhenIpastetheoutputintothisbooklayout,weendupwithsomewrappingproblemsdue
tothewidthrestrictionsofthepage.Ihadtoshrinkthefontsoitwouldfitonalineforyou.As
youcansee,theoutputisnicelyformatted.OnceIgetpastdisplayingallofthecolumnsoneach
database,Idisplaytheentirecontentsoftheclass.dbffile.Thisfirstdisplayallowsustoverify
thattheseconddisplay,restrictingoutputtothesecondandthirdrecord,actuallyworked. The
lasttestissimplydisplayingonlythefirstrecordfromtheteacher.dbffile.
Chapter1Fundamentals
63
YouwillsquirrelawaytheshowMe.javasourcefileinyourtoolbox.Youmightevenjointhe
xBaseJprojectteamandfixafewthingswiththelibrary,thencleanthisexampleup.Ifyouwere
payingattentionreadingthechartstartingonpage20youalsonotedthatthexBASEuniverse
containsalotofdatatypeswhichsimplyaren'tsupportedbythislibrary. Autoincrement(+)
wouldbeaniceaddition,butprobablynotthefirstyoushouldtacklesincedoingsowouldmost
likelyrequirethatyouunderstandmoreabouttheheaderrecord.TheDatetime(T)columntype
wouldbeawelcomeaddition.Whenyougetintomoretransactionorientedapplicationsthefield
becomesextremelyimportant. Double(O)andInteger(I)wouldbeinterestingforthosewho
believetheyareUbergeeksandcapableof gettingthosedatatypestobecorrectlystored no
matterwhatplatformxBaseJisrunningon.
ImustwarnyouthatInevertestedthePicture(P)datatype. Ihadnodesiretocreatea
databaseandstoreimagesinit.Moreimportantly,Ihadnodesiretofigureoutwhatimagetypes
(JPEG,BMP,PNG,etc.)wereactuallysupported.Iknowwhypictureswereadded,butInever
playedmuchinthatworld.Imageswereaddedsostorecatalog/inventoryrecordscouldcontaina
memofieldwiththeitemdescription,andapicturefieldwithanimageoftheitem.Ifyouhave
aneBaystorewitharound100items,thisisfine.Ifyouarerunningaseriousbusinessorthinkit
mightturnintoaseriousbusiness,youshouldreallystartwitharelationaldatabaseandbolton
whatyouneedlater.(Rememberthat2GBdatafilelimit?Wealwayssaythe4GBfilelimitwas
imposedbyFAT32,buthaveyoucheckedtheheaderfileand10digittagalgorithmofamemo
filetoensureitisn'tlimitedbyanunsigned32bitintegeraswell?)
1.10
1.10ProgrammingAssignment3
Modifythelasttwodump_records()callsintestShowMe.javatodumponlythesecondrecord
ofclass.dbfandonlythethirdrecordrespectively.Thisisaverysimpleassignmentdesignedto
buildconfidenceintheboundarylogicofthedump_records()method.
CreateyourownversionoftestShowMe.javawhichoperatesontheteacher.dbffile.Ihaven't
providedyouthesourcetocreatetheteacher.dbffile,soyouwillneedtopullitdownfromthe
xBaseJprojectsite.
Chapter1Fundamentals
64
1.11
1.11DescendingIndexesandIndexLifespan
Youhavealreadyseenhowindexescanbeusefulwhenitcomestokeepingdatainasorted
order.Evenifthedataisn't
physicallysorted,theindexallowsyoutoretrieveitintheorderyou
want. Wehaven't
donemuchwithdirectrecordaccessyet,butyouprobablyunderstanditis
anotherbenefitofhavinganindex.
Oneextremelyusefultypeofindexisthedescendingindex.Youwillfindthistypeofindex
usedformanydifferentthingsinaproductionworld.Someinventorysystemsuseadescending
indexfor product keysintheirinventory files. Let's
say yourun agasstationwitha small
convenience storeinit. Youaddnewproductstoyourinventoryfilebasedona4character
productcategoryanda10digititemnumber,thenyouassignitsomekindofbarcodescanvalue.
Youneedtokeepthecategoriessplitoutforvarioustaxreasons.Aslongastheitemnumberis
unique,youdon'tpersonallycarewhatitis.Youmighthavesomedatalookinglikethis:
TOBA0009876543
TOBA0009876542
TOBA0009876541
DARY0000056432
DARY0000056431
DARY0000056430
Wheneveryouaddedanewproduct,youwouldonlyneedtoknowwhatcategorytoputit
underandyoursystemcouldautomaticallycalculatethenextitemnumberbyusingthecategory
against the descending key. Given the data above, the first hit for TOBA would return
TOBA00009876543 whichwouldletourroutineaddonetothenumericportionforanewkey.
Likewise,DARY wouldreturnDARY0000056432 . (Yes,daryisreallyspelleddairy,butnot
inoldschoolinventoryspeak.)
xBaseJdidn'tprovideuswith descending indexes. Thiswasactuallyaflawmany early
xBASEpackageshad.Alotofuselessdataendedupgettingstoredinproductiondatafilestrying
to work around this problem. It was not uncommon to find bogus numeric columns which
containedtheresultofafieldofall9's
withanothercolumn(usuallyadate)subtractedfromit.It
wouldbethisboguscolumn,nottheactualcolumn,whichwouldbemadepartofakey.
MYDT
19990801
19550401
19200101
MYDTDS
80009198
80449598
80799898
Asyoucansee,thenewestdatehasthesmallestvalue,whichmakesitthefirstkeyinan
ascending key list. Developers dealing with character fields wrotefunctions and subroutines
whichwouldsubtractthestringfromastringofallZ'stoachievethissamesortorder.
Chapter1Fundamentals
65
Ifyouaresomeonewhohasneverhadamachineslowerthan2Ghzorlessthan2GBof
RAM,youprobablyhavealotoftroubleunderstandingwhydescendingindexesaresoimportant.
YouwillhappilyusethestartBottom()andreadPrev()methodsprovidedbyxBaseJperforming
needlessI/Oonnearlyonethirdofthedatabaselookingforthatoneparticularrecord.Thoseof
uswhogrewupinthePCeraunderstandtheneedcompletely.Weusedtohavetowaitmultiple
secondsforeachrecordtoberetrievedfromthat10MBfullheightharddrive.Eveniftheydeny
it,weallknowthatSeagateaddedthatchirpingcricketsoundandflashinglightsimplytokeep
peopleentertainedwhiletheyweredesperatelytryingtofindthediskblocktheywereinterested
in.
Whileyoucanfindtherecordyouarelookingfor by bruteforce,indexsearchingismuch
lessresourceintensive.I'm
notgoingtoprintthesourceforfind_entry(NodeKey,Node,int)of
theNDX.javafileinthisbook.It's
someprettyintensecode.It's
notdifficulttoread,justoneof
thoseroutineswhereyouhavetowrapyourmindarounditatonesitting,andnotgetuptogoto
thebathroomuntilyouhavefoundwhatyouintendedtofind. Allyouneedtoknowisthatit
reliesonabunchofotherclassestowalkthenodesintheBtreelookingforyourkeyvalue.
Ultimately,itisthismethodwhichgetscalledfromtheDBFclasswheneveryoucallfind( abc ).
(Assuming,ofcourse,thatyouareusingNDXinsteadofMDXasyourindexedfile.)
doeHistory.java
1)
2)
3)
4)
5)
6)
7)
8)
9)
10)
11)
12)
13)
14)
15)
16)
17)
18)
19)
20)
21)
22)
23)
24)
25)
26)
27)
28)
29)
30)
import
import
import
import
import
import
java.io.*;
java.util.*;
org.xBaseJ.*;
org.xBaseJ.fields.*;
org.xBaseJ.Util.*;
org.xBaseJ.indexes.NDX;
= 1;
= 2;
Chapter1Fundamentals
66
31)
32)
33)
34)
35)
36)
37)
38)
39)
40)
41)
42)
43)
44)
45)
46)
47)
48)
49)
50)
51)
52)
53)
54)
55)
56)
57)
58)
59)
60)
61)
62)
63)
64)
65)
66)
67)
68)
69)
70)
71)
72)
73)
74)
75)
76)
77)
78)
79)
80)
81)
82)
83)
84)
85)
86)
87)
88)
89)
90)
91)
92)
93)
public
public
public
public
public
public
public
public
public
static
static
static
static
static
static
static
static
static
final
final
final
final
final
final
final
final
final
int
int
int
int
int
int
int
int
int
DOE_KEY_NOT_FOUND
DOE_FILE_OPEN_ERR
DOE_DEVICE_FULL
DOE_NO_CURRENT_REC
DOE_DELETE_FAIL
DOE_GOTO_FAIL
DOE_DB_CREATE_FAIL
DOE_INVALID_DATA
DOE_END_OF_FILE
=
=
=
=
=
=
=
=
=
3;
4;
5;
6;
7;
8;
9;
10;
11;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
//
Method to add a record
//
This method assumes you have values already loaded
//
//
Many different flavors exist to accommodate what the
//
user may have for input
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
public int add_record() {
int ret_val = DOE_SUCCESS;
long x;
try {
x = 99999999 - Long.parseLong(effectiveDT.get());
} catch (NumberFormatException n) {
x = 99999999;
} // end catch NumberFormatException
//
// stop the user from doing something stupid
//
if (!dbOpen)
return DOE_FILE_OPEN_ERR;
try {
effectiveDTDesc.put( x);
aDB.write();
} catch ( xBaseJException j){
ret_val = DOE_DUPE_KEY;
System.out.println( j.getMessage());
} // end catch
catch( IOException i){
ret_val = DOE_DEVICE_FULL;
} // end catch IOException
return ret_val;
// end add_record method
Chapter1Fundamentals
94)
95)
96)
97)
98)
99)
100)
101)
102)
103)
104)
105)
106)
107)
108)
109)
110)
111)
112)
113)
114)
115)
116)
117)
118)
119)
120)
121)
122)
123)
124)
125)
126)
127)
128)
129)
130)
131)
132)
133)
134)
135)
136)
137)
138)
139)
140)
141)
142)
143)
144)
145)
146)
147)
148)
149)
150)
151)
152)
153)
154)
155)
156)
return add_record();
else
return ret_val;
if (ret_val == DOE_SUCCESS)
return add_record();
else
return ret_val;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
//
Method to close the database.
//
Don't print stack traces here. If close fails it is
//
most likely because the database was never opened.
67
Chapter1Fundamentals
68
157)
158)
159)
160)
161)
162)
163)
164)
165)
166)
167)
168)
169)
170)
171)
172)
173)
174)
175)
176)
177)
178)
179)
180)
181)
182)
183)
184)
185)
186)
187)
188)
189)
190)
191)
192)
193)
194)
195)
196)
197)
198)
199)
200)
201)
202)
203)
204)
205)
206)
207)
208)
209)
210)
211)
212)
213)
214)
215)
216)
217)
218)
219)
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
public void close_database() {
if (!dbOpen)
return;
try {
if (aDB != null) {
aDB.close();
dbOpen = false;
}
} catch (IOException i) {}
}
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
//
Method to create a shiny new database
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
public void create_database() {
try {
//Create a new dbf file
aDB=new DBF(DEFAULT_DB_NAME,true);
attach_fields(true);
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
//
Method to delete a record from the database
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
public int delete_record() {
int ret_val = DOE_SUCCESS;
if (!dbOpen)
return DOE_FILE_OPEN_ERR;
if (aDB.getCurrentRecordNumber() < 1) {
System.out.println( "current record number " +
aDB.getCurrentRecordNumber());
ret_val = DOE_NO_CURRENT_REC;
}
else {
try {
aDB.delete();
} catch( xBaseJException j){
ret_val = DOE_DELETE_FAIL;
} // end catch
catch( IOException i){
ret_val = DOE_DELETE_FAIL;
} // end catch IOException
} // end test for current record
Chapter1Fundamentals
220)
221)
222)
223)
224)
225)
226)
227)
228)
229)
230)
231)
232)
233)
234)
235)
236)
237)
238)
239)
240)
241)
242)
243)
244)
245)
246)
247)
248)
249)
250)
251)
252)
253)
254)
255)
256)
257)
258)
259)
260)
261)
262)
263)
264)
265)
266)
267)
268)
269)
270)
271)
272)
273)
274)
275)
276)
277)
278)
279)
280)
281)
282)
69
return ret_val;
// end delete_record method
aDB.gotoRecord( record_num);
} catch( xBaseJException j){
j.printStackTrace();
ret_val = DOE_NO_CURRENT_REC;
} // end catch
catch( IOException i){
i.printStackTrace();
ret_val = DOE_NO_CURRENT_REC;
} // end catch IOException
if (ret_val == DOE_SUCCESS)
ret_val = delete_record();
return ret_val;
// end delete_record method
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
// Method to dump first 10 records
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
public void dump_first_10() {
if (!dbOpen) {
System.out.println( "Must open database first");
return;
} // end test for open database
try {
System.out.println( "\nDate
Price");
System.out.println( "-------- ----------");
for (int x=1; x < 11; x++) {
aDB.gotoRecord(x);
System.out.println( effectiveDT.get() + "
} // end for x loop
} catch( xBaseJException j){
j.printStackTrace();
} // end catch
catch( IOException i){
i.printStackTrace();
} // end catch IOException
}
" + fuelPrice.get());
Chapter1Fundamentals
70
283)
284)
285)
286)
287)
288)
289)
290)
291)
292)
293)
294)
295)
296)
297)
298)
299)
300)
301)
302)
303)
304)
305)
306)
307)
308)
309)
310)
311)
312)
313)
314)
315)
316)
317)
318)
319)
320)
321)
322)
323)
324)
325)
326)
327)
328)
329)
330)
331)
332)
333)
334)
335)
336)
337)
338)
339)
340)
341)
342)
343)
344)
try {
aDB.useIndex( DEFAULT_K0_NAME);
aDB.startTop();
System.out.println( "\nDate
Price");
System.out.println( "-------- ----------");
for (int x=1; x < 11; x++) {
aDB.findNext();
System.out.println( effectiveDT.get() + "
} // end for x loop
} catch( xBaseJException j){
j.printStackTrace();
} // end catch
catch( IOException i){
i.printStackTrace();
} // end catch IOException
}
" + fuelPrice.get());
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
// Method to find a record
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
public int find_EQ_record( String d) {
int ret_val = DOE_SUCCESS;
boolean perfect_hit;
if (!dbOpen)
return DOE_FILE_OPEN_ERR;
try {
aDB.useIndex( DEFAULT_K0_NAME);
perfect_hit = aDB.findExact( d);
if ( !perfect_hit) {
System.out.println( "missed");
System.out.println( "Current Record " +
aDB.getCurrentRecordNumber());
" + fuelPrice.get());
Chapter1Fundamentals
345)
346)
347)
348)
349)
350)
351)
352)
353)
354)
355)
356)
357)
358)
359)
360)
361)
362)
363)
364)
365)
366)
367)
368)
369)
370)
371)
372)
373)
374)
375)
376)
377)
378)
379)
380)
381)
382)
383)
384)
385)
386)
387)
388)
389)
390)
391)
392)
393)
394)
395)
396)
397)
398)
399)
400)
401)
402)
403)
404)
405)
406)
407)
ret_val = DOE_KEY_NOT_FOUND;
}
} catch( xBaseJException j){
System.out.println( j.getMessage());
ret_val = DOE_KEY_NOT_FOUND;
} // end catch
catch( IOException i){
ret_val = DOE_KEY_NOT_FOUND;
} // end catch IOException
}
return ret_val;
// end find_EQ_record method
aDB.useIndex( DEFAULT_K0_NAME);
aDB.find( d);
} catch( xBaseJException j){
ret_val = DOE_KEY_NOT_FOUND;
} // end catch
catch( IOException i){
ret_val = DOE_KEY_NOT_FOUND;
} // end catch IOException
return ret_val;
// end find_GE_record method
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
//
Method to retrieve the newest record by date
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
public int get_newest() {
int ret_val = DOE_SUCCESS;
if (!dbOpen)
return DOE_FILE_OPEN_ERR;
try {
aDB.useIndex( DEFAULT_K1_NAME);
aDB.startTop();
aDB.findNext();
} catch( xBaseJException j){
ret_val = DOE_KEY_NOT_FOUND;
} // end catch
catch( IOException i){
ret_val = DOE_KEY_NOT_FOUND;
} // end catch IOException
return ret_val;
// end get_newest method
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
//
method to get next record no matter
//
what index is in use.
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
public int get_next() {
int ret_val = DOE_SUCCESS;
try {
aDB.findNext();
71
72
Chapter1Fundamentals
408)
} catch( xBaseJException j){
409)
ret_val = DOE_KEY_NOT_FOUND;
410)
} // end catch
411)
catch( IOException i){
412)
ret_val = DOE_KEY_NOT_FOUND;
413)
} // end catch IOException
414)
415)
return ret_val;
416)
417)
418)
} // end get_next method
419)
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
420)
//
method to retrieve the oldest record
421)
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
422)
public int get_oldest() {
423)
int ret_val = DOE_SUCCESS;
424)
if (!dbOpen)
425)
return DOE_FILE_OPEN_ERR;
426)
427)
try {
428)
aDB.useIndex( DEFAULT_K0_NAME);
429)
aDB.startTop();
430)
aDB.findNext();
431)
} catch( xBaseJException j){
432)
ret_val = DOE_KEY_NOT_FOUND;
433)
} // end catch
434)
catch( IOException i){
435)
ret_val = DOE_KEY_NOT_FOUND;
436)
} // end catch IOException
437)
438)
return ret_val;
439)
} // end get_oldest method
440)
441)
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
442)
//
Method to test private flag and see
443)
//
if database has been successfully opened.
444)
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
445)
public boolean isOpen() {
446)
return dbOpen;
447)
} // end ok_to_continue method
448)
449)
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
450)
//
Method to open an existing database and attach primary key
451)
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
452)
public int open_database() {
453)
int ret_val = DOE_SUCCESS;
454)
455)
try {
456)
457)
//Create a new dbf file
458)
aDB=new DBF(DEFAULT_DB_NAME);
459)
460)
attach_fields( false);
461)
462)
aDB.useIndex( DEFAULT_K0_NAME);
463) //
aDB.useIndex( DEFAULT_K1_NAME);
464)
dbOpen = true;
465)
} catch( xBaseJException j){
466)
continue_flg = false;
467)
} // end catch
468)
catch( IOException i){
469)
continue_flg = false;
470)
} // end catch IOException
Chapter1Fundamentals
471)
472)
473)
474)
475)
476)
477)
478)
479)
480)
481)
482)
483)
484)
485)
486)
487)
488)
489)
490)
491)
492)
493)
494)
495)
496)
497)
498)
499)
500)
501)
502)
503)
504)
505)
506)
507)
508)
509)
510)
511)
512) }
73
if (!continue_flg) {
continue_flg = true;
System.out.println( "Open failed, attempting create");
create_database();
} // end test for open failure
if (isOpen())
return DOE_SUCCESS;
else
return DOE_FILE_OPEN_ERR;
// end open_database method
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
//
Method to re-index all of the associated index files.
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
public void reIndex() {
if (aDB != null) {
if (isOpen()) {
try {
NDX n = null;
for (int i=1; i <= aDB.getIndexCount(); i++) {
n = (NDX) aDB.getIndex( i);
n.reIndex();
}
} catch( xBaseJException j){
j.printStackTrace();
} // end catch
catch( IOException i){
i.printStackTrace();
} // end catch IOException
} // end test for open database
} // end test for initialized database object
} // end reIndex method
//
// We don't need to create a finalize method since
// each object we create has one. You only create a finalize
// method if you allocate some resource which cannot be
// directly freed by the Java VM.
//
// end class doeHistory
Itookthisexamplealittlefartherthanmostofyouprobablywouldinreallife.Thoseofyou
whohavereadotherbooksinthisseriesknowthatatonepointinmylifeIworkedataDEC
VARwhichsoldacustomizedERPpackage.ThepackagewaswritteninDECBASIC.Allof
ourmainfileshadI/Oroutineswrittenforthem.Therewereoneortwoincludefilesyouadded
tothetopofyourprogram,andpresto,youhadaccesstoalloftheI/Oroutinesforthatfile.The
filenameandchannelnumberwaspreassigned,methodswerethereforreading/writing/deleting/
finding records, and all exceptions were caught in the routine itself. Thefunctionsreturned
valueswhichhadstandardizednames;infact,allofthefunction/methodnameswerethesamefor
allofthefiles.
74
Chapter1Fundamentals
WritingthatfirstI/Omodulewasamassivepain.Everyotherfileweaddedafterthatone
wasalmostfree.Dependinguponhowfastatypistyouwere,ittook14hourstocreateallofthe
recordlayoutsandcloneanewI/Osourcefilefromtheoriginal.Theprogramsthemselvesgota
lotsimpler.
MostofyouwillnotethatIdidn't
takethisI/Oroutinequitethatfar.Ididn't
wanttoprinta
5000linesourcefileinthisbook.Evena500linesourcefileispushingitifIactuallywantyou
toreadit.
Itoldyoutheabovestorysoyouwouldhavesomeframeofreferenceforwhythissourcefile
wasstructuredthewayitwas. Javadoesn't
haverecordlayoutsandmaps,soImadethetwo
primaryfieldspublic.IdeliberatelymadeeffectiveDTDescprivatebecausethatisreallyforclass
useonly. IkepttheDBFprivateaswell. AsweproceedwithourdesignImayregretthat
decision,butIwantedtofendoffbit twiddler's
impulse. OddsaregreaterthatIwilladdthe
functiontotheclassifIhavetoopentheclasssourcefiletogetaccesstothedatabaseobject...at
leastthatismyworkingtheory.
Thisclassalsohasabunchofpublicconstants.Allofthefilenamesarestringconstantsand
theresultcodesofintegerconstants.IfyouspendanytimeatallworkinginITandworkingwith
indexedfiles,youwillseeK0usedtorefertoaprimarykey,K1tothefirstalternatekey,etc.I
haveusedthisnotationthroughoutmycareerandthisbookseries. Whenyouaredealingwith
segmentedkeysyouwillseeeachfieldofthekeyhavea.n afterthekeynumber,suchasK1.1,
K1.2,K1.3etc.Thereisneverazerosegment. It's
notbecausewedon't
likezero,wesimply
don't
wanttoconfusemanagementtellingthemK0onthisfileisasinglefieldprimarykey,but
K0.0onthisotherfileindicatesthefirstfieldofasegmentedprimarykey. Asageneralrule,
MBAsdon'tdozerowell.
SinceIdidnotwantsomeuserdirectlymanipulatingtheBooleanworkvariablestheclass
neededImadethemprivate. Oneofthemisforinternaluseonlyandtheotherhasamethod
whichwillbepresentedlatertoallowreadaccess.
Ididquiteabitofpolymorphismwiththisclass.Theadd_record()methodsshouldserveasa
goodexample.TheonewhichdoesactualIOisalsothedefaultone.NoticehowIsubtractthe
datevaluefrom99999999togetavalueforeffectiveDTDesc.Whileitistruethat99999999isn't
avaliddate,itisalsotruethatastringofall9swilldowhatweneed.Sinceourindexesonly
ascend,weneedavaluethatgetssmallerasthedategetsbigger. Theoverriddenmethodsof
add_record()aresimplytheretoprovideaconvenientwayofaddingarecordinasinglestep.
Chapter1Fundamentals
75
Theattach_fields()methodshouldn't
requiremuchexplanationasyouhavealreadyseenme
createamethodjustlikethis.Itiseasiertohandlethisallinonemethodthanreplicateitinother
methods.
Wecouldhavequiteabitofdiscussionovertheclose_database()method. Notsomuch
concerningthemethoditself,butthefactIdidn't
includeafinalize()methodcallingit.Thereare
multipleschoolsofthoughtonthistopic,andnowisagoodtimetodiscussthem.
Myclassdidn'tallocatean
ysystemresourcesonitsown.Itdidn'topen
anyfiles,allocateany
devices,orphysicallyallocateregionsofmemoryonitsown.Everytimeitdidsuchathingit
usedsomethingelsetodoit. OurclassvariableswereallocatedbytheJavaVirtualMachine
(JVM).Theywereeithernativedatatypesorinstancesofclassesprovidedbyothers.Whenyou
developaclass,youareresponsibleforfreeinganyresourceswhichcannotbefreedbytheJVM
inyourfinalize()method.
WhenanobjectgoesoutofscopeitisflaggedforgarbagecollectioninsideoftheJVM.That
collectionmayoccurinstantaneouslyoritmaytakedaysfortheJVMtogarbagecollectit.The
finalize()methodmustphysicallyfreeanyresources(other thandynamicallyallocatedRAM)
whichmightbeneededsomewhereelse.(Wearenotgoingintoadiscussionoverthedifferences
between dynamically allocated and physically mapped memory as it is a topic for lowlevel
programming,notbusinessapplicationprogramming.)
Theclasswehavepresentedhereusesotherclassestoopenthefiles.Whenyoulookatthe
sourceforDBF.java,youwillseethefollowing:
public void finalize() throws Throwable {
try {
close();
} catch (Exception e) {
;
}
}
Whenyoupokearoundinthatsamesourcefileandfindtheclose()method,youwillseethe
following:
Chapter1Fundamentals
76
public void close() throws IOException {
short i;
if (dbtobj != null)
dbtobj.close();
Index NDXes;
NDX n;
if (jNDXes != null) {
for (i = 1; i <= jNDXes.size(); i++) {
NDXes = (Index) jNDXes.elementAt(i - 1);
if (NDXes instanceof NDX) {
n = (NDX) NDXes;
n.close();
}
}
} // end test for null jNDXes 20091010_rth
if (MDXfile != null)
MDXfile.close();
dbtobj = null;
jNDXes = null;
MDXfile = null;
unlock();
file.close();
}
Asyoushouldbeabletotell,thereisacascadingeffectwhengarbagecollectionstartsto
cleanupourclass.WhenitattemptstoreclaimtheclassvariableaDBitwillbeforcedtocallthe
finalize()methodfortheDBFclass.Thatwillfreeupthedatafileandtheindexobjects.The
indexobjectswillthenbegarbagecollected,whichwillfreeupthefilestheyused,etc.
Sincewearetalkingaboutdeletingthings,weshouldmoveontothedelete_record()method
and its overrides. I seriously debated making the default method, which deletes the current
record,private.It's
adangerousthing,especiallyifsomeonedoesn't
bothertochecktheresultsof
their find callbefore performingthedelete. Theoverriddenversions ofthemethod actually
ensuretheylocatethecorrectrecordpriortodeletion.
Iprobablyshouldnothavestuckthedumpmethodsinthisclass,butitmadethemquickto
write.Besides,doingsoensuresIhaveaprogrammingassignmentforyouafterthis.Noticethat
each dump routine makes certain the database is open before proceeding. A lot of Java
developersdon't
dostufflikethis;theysimplyletthingscrash,throwingexceptions.Onething
youmaynotreadilynoticeisthateachdumproutinewhichneedsanindexmakescertainthe
indexitneedsiscurrentlyontopbycallinguseIndex().Readersofotherbooksinthisserieswill
recognizethatasestablishingthekeyofreferencefromotherlanguages.
Chapter1Fundamentals
77
Oncewehaveourkeyofreferenceestablished,theDBFclassprovidestwohandyindex
positioningmethods:startTop()andstartBottom().Onceyouhaveestablishedapositionanda
keyofreferenceyoucanuseeitherfindNext()orfindPrev()tonavigateforwardorbackward
fromyourcurrentposition.TheDBFclassalsoprovidesread()andreadPrev().Thereisabig
differencebetweenthereadandthefindmethods,though. Thereadmethodsrequirethatyou
haveacurrentrecordtoestablishapositioninthefile. Thefindmethodsonlyrequiresome
position tohavebeenestablishedin thecurrently active index. Ifyou open adatabase,call
startTop(),thenattempttocallread()thecallwillfail.
Iaddedtwofindmethodstothisclass.Bothofthemonlyworkwiththeprimarykey.The
firstwillsucceedonlyifaperfectlymatchingkeyisfound;thesecondwillsucceedifakeywhich
isgreaterthanorequaltothesearchvalueisfound. Itshouldbenotedthatthesearehighly
restrictivemethodswhichshouldhavenameswhichbetterindicatetheirrestrictiveness.
TheonlymethodIprovidedtooperateonthesecondindexisget_newest().TheapplicationI
needtowriteinreallifeneedstoquicklyidentifythenewestrecordonfile. Thatrecordwill
providethecurren t valueuntilanewerrecordisadded.Thismethodlooksmuchlikeourother
findmethods. Weestablishakeyofreference,callstartTop()toestablishaposition,thencall
findNext()topullintherecord.
Youmightthinkatfirstglancethatget_next()iscodedincorrectly.Itmakesnoattemptto
establishanykeyofreferenceorpositionviathatkey.Itcouldn't
carelesswhereitisorwhereit
isgoing.Ifyouhappentohitoneendortheotheronthefileitwillletyouknowbyreturning
DOE_KEY_NOT_FOUND,otherwiseitreturnsDOE_SUCCESSandyoucanbefairlycertain
yougottherecordyouwanted.
Ifyouwereconfusedbyget_next()orget_newest(),thenyoushouldloveget_oldest().It's
notacomplexroutine;itsimplyneedsyoutoreallyunderstandbothhowtheindexesworkand
whatthekeyactuallycontains.Remember,indexesarestoredonlyinascendingorderwiththis
library.Thesmallestdatevalueonfilewillbethefirstrecordintheprimaryindex.Wefindthe
oldestrecordbygettingtherecordatthetopoftheprimaryindex(K0)andthenewestrecordby
gettingtherecordatthetopofthesecondary(K1)index.Itistruethatyoucouldalsogetthe
newestrecordonfilebycallingstartBottom()ontheprimarykeyandworkyourwaybacktothe
oldestrecordbyusingfindPrev(), butwhenyougetyourprogramming assignmentsyouwill
thankme.
Chapter1Fundamentals
78
Finallywegettolistingline445.Ihadtokeeptrackofthedatabaseopenstateandprovidea
methodofdeterminingitscurrentstatetotheoutsideworld.ImustapologizetotheJavahackers
oftheworldwhothinkitisjustdandytoneverprovidethiscapabilityandtojustletthingsthrow
exceptionsinproduction.Iamnotfromthatschool.I'm
fromtheschoolofthosewhousedto
workinoperationsandhadtowakepeopleupat2AM.I'm
alsofromtheschoolofthosewho
usedtoworkproductionsupportalongwiththeirdevelopmentdutiesandhadtogetthosecallsat
2AM.Thereasonweusedtomakeprogrammersstartoutinoperations,thenworkproduction
support,istoteachthemwhathappenswhenbustedthingsgetsturnedintoproduction. Call
isOpen()beforeyoudosomethingandavoidcrashingfromanunhandledexception.
WewilltalkaboutreIndex()afterwediscussthetestapplication.
testDoeHistory.java
1)
2)
3)
4)
5)
6)
7)
8)
9)
10)
11)
12)
13)
14)
15)
16)
17)
18)
19)
20)
21)
22)
23)
24)
25)
26)
27)
28)
29)
30)
31)
32)
33)
34)
35)
36)
37)
38)
39)
40)
41)
42)
import java.text.*;
import java.util.*;
import java.io.*;
import org.xBaseJ.*;
public class testDoeHistory {
public static void main(String args[]){
doeHistory d = new doeHistory();
//
// You must set this unless you want NULL bytes padding out
// character fields.
//
try {
Util.setxBaseJProperty("fieldFilledWithSpaces","true");
} catch (IOException e) {
System.out.println( "An IO Exception occurred");
System.out.println( e.toString());
e.printStackTrace();
}
d.create_database();
if (d.isOpen()) {
String line_in_str = null;
long l_record_count = 0;
boolean eof_flg = false;
FileReader in_file = null;
BufferedReader input_file = null;
try {
in_file = new FileReader( "fuel_prices.csv");
} catch (FileNotFoundException f) {
System.out.println( "File Not Found fuel_prices.csv");
eof_flg = true;
} // end catch for file not found
if (eof_flg == false) {
input_file = new BufferedReader( in_file,4096);
System.out.println("\nPopulating database");
}
Chapter1Fundamentals
43)
44)
45)
46)
47)
48)
49)
50)
51)
52)
53)
54)
55)
56)
57)
58)
59)
60)
61)
62)
63)
64)
65)
66)
67)
68)
69)
70)
71)
72)
73)
74)
75)
76)
77)
78)
79)
80)
81)
82)
83)
84)
85)
86)
87)
88)
89)
90)
91)
92)
93)
94)
95)
96)
97)
98)
99)
100)
101)
102)
103)
104)
105)
try {
d.effectiveDT.put( input_flds[0]);
d.fuelPrice.put( input_flds[1]);
d.add_record();
} catch ( xBaseJException j){
j.printStackTrace();
} // end catch
// end while loop to load records
79
Chapter1Fundamentals
80
106)
107)
108)
109)
110)
111)
112)
113)
114)
115)
116)
117)
118)
119)
120)
121)
122)
123)
124)
125)
126)
127)
128)
129)
130)
131)
132)
133)
134)
135)
136)
137)
138)
139)
140)
141)
142)
143)
144)
145)
146)
147)
148)
149)
150)
151)
152)
153) }
h.dump_first_10();
System.out.println( "First 10 in descending date order");
h.dump_first_10_k1();
System.out.println( "First 10 in ascending date order");
h.dump_first_10_k0();
// Now let us see what keys have actual
// data
//
System.out.println( "\nBefore reIndex\n");
System.out.println( "finding 20071010");
x = h.find_EQ_record( "20071010");
System.out.println( "\nResult of EQ find " + x + "\n");
System.out.println( "Date: " + h.effectiveDT.get()
+ " Price: " + h.fuelPrice.get());
x = h.get_newest();
System.out.println( "Result of get_newest " + x);
System.out.println( "Date was: " + h.effectiveDT.get());
//
Not all keys are updated when using NDX
//
h.reIndex();
System.out.println( "\nAfter reIndex\n");
System.out.println( "First 10 in descending date order\n");
h.dump_first_10_k1();
System.out.println( "\nfinding 20071010");
x = h.find_GE_record( "20071010");
System.out.println( "\nResult of EQ find " + x + "\n");
System.out.println( "Date: " + h.effectiveDT.get()
+ " Price: " + h.fuelPrice.get());
if ( x == h.DOE_SUCCESS) {
x = h.delete_record();
System.out.println( "Result of delete " + x + "\n");
}
x = h.get_newest();
System.out.println( "Result of get_newest " + x);
System.out.println( "Date was: " + h.effectiveDT.get());
}
}
h.close_database();
} // end test for successful open
// end test for open dbf
ThisisoneofthelongertestprogramsIhaveprovidedyou.Abigpartofthatisduetothe
factIcreatedaCSV(CommaSeparatedValue)filecalledfuel_prices.csvwhichhaslinesinit
lookinglikethis:
Chapter1Fundamentals
81
20070905,289.3
20070912,292.4
20070919,296.4
20070926,303.2
20071003,304.8
20071010,303.5
20071017,303.9
20071024,309.4
20071031,315.7
20071107,330.3
20071114,342.5
20071121,341.0
20071128,344.4
Actuallyithasover100linesinit,butI'm
certainlynotgoingtoprintithere.Ifyouwant,
youcanvisittheDepartmentofEnergyWebsiteandpulldownthespreadsheetwhichhashistoric
dieselfuelprices,andcreateyourownfile.
IntheoryIcouldhavedonetheUtilcallfoundatlistingline17insideofthedoeHistoryclass,
butIdidn't
haveawarmandfuzzyfeelingabouttheactualruntimescopeofUtilinallsituations.
Feelfreetoexperimentonyourownwithplacingthiscallatvariousplacesintheclasshierarchy.
Listinglines26through78servenootherpurposethantoreadalinefromthisCSVandload
itasarecordinthedatabase. SinceItriedtoimplementlocalizederrorhandlingandprovide
meaningfulerrormessages,thiscodeisalotlargerthanyouwillseeinmostexampleswhich
wouldsimplytrapallexceptionsatoneplaceandprintastacktrace.
Weshoulddiscussthiscodebrieflyforthosewhohavenevertriedtoreadlinesinfromatext
filebefore.FirstyouhavetocreateaFileReaderobjectasIdidatlistingline33.Onceyouhave
donethatyoucancreateaBufferedReaderobjecttoreadfromandbuffertheFileReaderobject
youjustcreatedasIdidatlistingline40.Thesecondparameter(4096)isanoptionalbuffersize
inbytes.Ifyoudonotpassabuffersize,thereissomevaluewhichgetsusedbydefault.
OnehastouseaBufferedReaderobjectifonewishestoreadalineofinputatatimeaswe
doatlistingline46.ThereadLine()methodofaBufferedReaderobjectensuresthatweeitherget
allcharactersasaStringuptothenewLinecharacterortheendofthestream. Youwillnot
receivethenewLineorendofstreamterminationcharacter(s)intheString.
Afterwegetdonedealingwiththepotentialendoffilesituationweincrementtherecord
counterthenusethereallycoolsplit()methodprovidedbytheStringclass.Sinceweknowthe
numberandorderofdataintheinputfile,wecandirectlyputthevaluesintothedatabasefields
andaddtherecordtothedatabase.Roughly50linesofcodejusttogetourtestdata,butnowwe
haveit.
Chapter1Fundamentals
82
Listinglines84through147containthemeatofthistest.Weneedtoseetheoutputbefore
wetalkaboutthem,though.
roland@logikaldesktop:~/fuelsurcharge2$ java testDoeHistory
Populating database
End of input file reached
Finished adding 107 records
Result of add 1
result of second add 1
First 10 in order added
Date
Price
-------- ---------20070905
89.300
20070912
92.400
20070919
96.400
20070926
03.200
20071003
04.800
20071010
03.500
20071017
03.900
20071024
09.400
20071031
15.700
20071107
30.300
First 10 in descending date order
Date
Price
-------- ---------20090916
63.400
20090909
64.700
20090902
67.400
20090826
66.800
20090819
65.200
20090812
62.500
20090805
55.000
20090729
52.800
20090722
49.600
20090715
54.200
First 10 in ascending date order
Date
-------20070905
20070912
20070919
20070926
20071003
20071010
20071017
20071024
20071031
20071107
Price
---------89.300
92.400
96.400
03.200
04.800
03.500
03.900
09.400
15.700
30.300
Before reIndex
finding 20071010
Result of EQ find 1
Date: 20071010 Price: 03.500
Chapter1Fundamentals
83
Result of get_newest 1
Date was: 20090916
After reIndex
First 10 in descending date order
Date
-------20121003
20110830
20090916
20090909
20090902
20090826
20090819
20090812
20090805
20090729
Price
---------13.410
29.950
63.400
64.700
67.400
66.800
65.200
62.500
55.000
52.800
finding 20071010
Result of EQ find 1
Date: 20071010 Price: 03.500
Result of delete 1
Result of get_newest 1
Date was: 20121003
Youshouldnotethattheresultofboththefirstadd(20121003,13.41)andthesecondadd
(20110830,29.95)returneda1,meaningtheyweresuccessfullyaddedtothedatabase,yetthey
didn'tshowuponourinitialdumpreports.Therecordsdon'tshowupuntil
afterIcallreIndex().
Hereisanotherlovelylittletidbitforyou.NDXobjectsdon't
monitorchanges.If,insteadof
obtainingthetheNDXcurrentlyattachedtotheDBFobject,Isimplycreatetwonewobjectsand
reindex,thosechangeswillbereflectedinthefile,butnotinourapplication.
NDX a = new NDX( DEFAULT_K0_NAME, aDB, false);
a.reIndex()
NDX b = new NDX( DEFAULT_K1_NAME, aDB, false);
b.reIndex()
Thecodeabovewillnotplaceentriesinourindexeventhoughthevalueswillbecorrecton
file.Why?BecausetheBtreegetsloadedintoRAM. Youhavetomanipulatetheexactsame
Btreethedatabaseobjectisusing.Makenomistake,acalltoreIndex()changesthecontentsof
thefile,buttheotherloadedviewofitdoesnot. Youshouldnever,underanycircumstances,
attempttoletmultipleusershavewriteaccesstothesameDBFforthis,andmanyother,reasons.
ThereisnotriggeringmethodinplacetokeepBtreesinsynchbecausethereisnodatabaseengine
inplace.
84
Chapter1Fundamentals
Takeanotherlookatlistingline463indoeHistory.java.IhavetheuseIndex()forthesecond
keycommentedout.OnpagetwelveinthisbookItoldyouthatrecordscouldbeaddedtoaDBF
filewithoutevercreatinganentryinanindexfile.Thistesthasbeenashiningexample.When
wecallopen_database()weonlyopenoneindex.Indeed,thedatabaseobjectdoesn't
careifwe
choose to not openany. Agood many xBASElibraries out there support only readingand
writingofrecordsinxBASEformat.Theyprovidenoindexsupportwhatsoever.
1.12
1.12ProgrammingAssignment4
Thisisamultipartassignment. Yourfirstassignmentistouncommentlistingline463,
recompileandrerunthisapplication.Youwillnotethatthefirstsetofdumpreportsnowhasthe
addedrecords.Canyouexplainwhy?
Part2:Moveallofthedump_methodsoutofdoeHistory.javaandmakethemmethodsin
testDoeHistory.java.Getthemtoactuallywork.DONOTMAKETHEDBFOBJECTPUBLIC
ORUSEAMETHODWHICHPROVIDESACOPYOFITTOACALLER. Don't
forgetto
check for the database being open prior to running. Do not add any new methods to
doeHistory.java.
Part3: Aftercompletingpart two,change getNext()touseread() insteadoffindNext(),
compileanddocumentwhat,ifany,differencethereisintheoutput.
Part 4: After completing part three, add one method to doeHistory.java which uses the
readPrev()methodoftheDBFclasstoreadthepreviousrecord.Clonethedump_first_10_k1()
methodyoujustmovedtotestDoeHistory.javatoamethodnameddump_last_10_k0().Without
usingthealternateindex,getthesame10recordstodisplay.
Chapter1Fundamentals
85
1.13
1.13DeletingandPacking
Imentionedmuchofthisinformationearlierbutwearegoingtogooveritagainindetail
becauseittendstocatchmostnewbiesoffguardevenaftertheyhavebeentoldahundredtimes.
DeletingarecordinanxBASEfiledoesnotphysicallydeletetherecord(inmostversions),nor
does it update any NDX index file information. (A production MDX is a slightly different
situation.)
Basically,eachrecordinaDBFfilehasanextrabyteatthefrontofit. Whenthatbyteis
filledin,usuallywithanasterisk,therecordisconsideredtobedeleted . Yourapplicationswill
continuetoreadthisrecordandprocessitunlesstheycallthedeleted()methodimmediatelyafter
readingarecord.Thedeleted()methodoftheDBFclassreturnstrueiftherecordisflaggedfor
deletion.
OneofthedBASEfeaturesgeneralusersfoundmostendearingwastheabilitytound elete
arecordtheyhadaccidentallydeleted.Thisfeaturewaspossiblesimplybecausetherecordhad
notbeenphysicallydeleted.TheDBFclassprovidesanundelete()methodforyouaswell.Ifyou
findarecordwhichhasbeenmarkedasdeletedthatyouwishtorestore,yousimplyreaditand
callundelete().
ItisnotunusualtofindxBASEfileswhichhaveneverhaddeletedrecordsremoved.Aslong
asauserneverhitsthe2GBfilesizelimitforaDBF,thereisnothingwhichforcesthemtogetrid
ofdeletedrecords.Untilyouhitasizelimit(eithermaximumfilesizeorrunoutofdiskspace),
youcanjustgohappilyonyourway.
Whatifyouwanttogetthatspaceback?Whatifyouneedtogetitback?Well,thenyou
needtoknowaboutthepack()methodoftheDBFclass. Manybookswilltellyouthatpack()
removesthedeletedrecordsfromyourdatabase. TheremayactuallybeanxBASEtoolsetout
theresomewherewhichactuallyimplementspack()thatway. AlmosteverylibraryIhaveused
throughoutmycareerdoeswhatxBaseJdoes.Theycreateashinynewdatabasewithatemporary
filename,copyalloftherecordswhicharenotflaggedfordeletiontothetemporarydatabase,
closeandnuketheoriginaldatabase,thenrename/copythetemporarybacktowheretheoriginal
databasewas. Ifyouarelookingtopack() becauseyouareoutofdiskspace,itisprobably
alreadytoolateforyouunlessyour/tmportmpenvironmentvariableispointingtoadifferent
physicaldisk.
CarefulreaderswillnotethatIdidn't
sayanythingaboutyourindexfiles.pack()couldn'tcar
e
lessaboutthem. Ifyoudonotreindexyourindexfilesorcreatenewindexfilesaftercalling
pack(),thenyouareaskingfordisaster.
Chapter1Fundamentals
86
testpackDoeHistory.java
1) ...
2)
3)
4)
5)
6)
7)
8)
9)
10)
11)
12)
13)
14)
15)
16)
17)
18)
19)
20)
21)
22)
23)
24)
25)
26)
27)
28)
29)
30)
31)
32)
33)
34)
35)
36)
37)
38)
39)
40)
41)
42)
43)
44)
45)
46)
47)
48)
49)
50)
51)
52)
53)
54)
55)
56)
57)
58)
59)
60)
61)
=
=
=
=
=
h.add_record(
h.add_record(
h.add_record(
h.add_record(
h.add_record(
"20201003",
"20190903",
"20180803",
"20170703",
"20160603",
"19.58");
"21.58");
"19.58");
"21.58");
"19.58");
Chapter1Fundamentals
62)
63)
64)
65)
66)
67)
68)
69)
70)
71)
72)
73)
74)
75)
76)
77)
78)
79)
80)
81)
82)
83)
84)
85)
86)
87)
88)
89)
90)
91)
92)
93)
94)
95)
96)
97)
98)
99)
100)
101)
102)
103)
104)
105)
87
h.dump_first_10_k1();
System.out.println( "First 10 in ascending date order");
h.dump_first_10_k0();
// Now let us see what keys have actual
// data
//
System.out.println( "\n\nBefore reIndex\n");
System.out.println( "finding 20071010");
x = h.find_EQ_record( "20071010");
System.out.println( "\nResult of EQ find " + x + "\n");
System.out.println( "Date: " + h.effectiveDT.get()
+ " Price: " + h.fuelPrice.get());
x = h.get_newest();
System.out.println( "Result of get_newest " + x);
System.out.println( "Date was: " + h.effectiveDT.get());
//
Not all keys are updated when using NDX
//
h.reIndex();
System.out.println( "\nAfter reIndex\n");
System.out.println( "First 10 in descending date order\n");
h.dump_first_10_k1();
System.out.println( "\nfinding 20071010");
x = h.find_GE_record( "20071010");
System.out.println( "\nResult of EQ find " + x + "\n");
System.out.println( "Date: " + h.effectiveDT.get()
+ " Price: " + h.fuelPrice.get());
if ( x == h.DOE_SUCCESS) {
x = h.delete_record();
System.out.println( "Result of delete " + x + "\n");
}
x = h.get_newest();
System.out.println( "Result of get_newest " + x);
System.out.println( "Date was: " + h.effectiveDT.get());
}
}
h.close_database();
} // end test for successful open
// end test for open dbf
IdidnotprovidethebeginningofthissourcefilebecauseIdidn't
feellikereprintingthe
codetoloadtherecordsagain.Ifyouwanttogetthisprogramrunningyoucansimplystealthe
CSVimportcodefromthepreviouslypresentedprogram.
Atlistingline9Icreatedaforloopwhichwilldeleterecordsfromthedatabase.Weonly
needafewnearthebeginningtodisappear.
Listinglines18through24containthecodewhereIopenthedatabaseandcallpack(). I
cheatedhereanddirectlycreatedadatabaseobjectbecauseIhadnotaddedapack_database()
methodtothedoeHistoryclass.
Chapter1Fundamentals
88
Youwillnoticeatlistinglines53through57thatIchosetoaddsomemorerecords.Ijust
wantedtomakethingspainfullyobviousduringtherestofthetest.Thereisnothingreallymagic
aboutthevaluesinthoserecords,otherthanthefacttheyareeasytospot.
Payspecialattentiontolistingline82.DoyourememberwhatIsaidearlier?Ideliberately
leftthislinewhereitwastoprovethatstatement.Now,let'stakealookattheoutput.
roland@logikaldesktop:~/fuelsurcharge2$ javac doeHistory.java
roland@logikaldesktop:~/fuelsurcharge2$ javac testpackDoeHistory.java
roland@logikaldesktop:~/fuelsurcharge2$ java testpackDoeHistory
Populating database
End of intput file reached
Finished adding 107 records
packing the database
Database has been packed record count 100
adding records with future dates
First 10 in order added
Date
Price
-------- ---------20070912
92.400
20070919
96.400
20071003
04.800
20071010
03.500
20071024
09.400
20071031
15.700
20071114
42.500
20071121
41.000
20071205
41.600
20071212
32.500
First 10 in descending date order
Date
Price
-------- ---------20160603
19.580
20170703
21.580
20180803
19.580
20190903
21.580
20201003
19.580
20110830
29.950
20121003
13.410
20090916
63.400
20090909
64.700
20090902
67.400
First 10 in ascending date order
Date
-------20070912
20070919
20071003
20071010
20071024
20071031
20071114
Price
---------92.400
96.400
04.800
03.500
09.400
15.700
42.500
Chapter1Fundamentals
20071121
20071205
20071212
89
41.000
41.600
32.500
Before reIndex
finding 20071010
Result of EQ find 1
Date: 20071031 Price: 15.700
Result of get_newest 1
Date was: 20160603
After reIndex
First 10 in descending date order
Date
-------20201003
20190903
20180803
20170703
20160603
20121003
20110830
20090916
20090909
20090902
Price
---------19.580
21.580
19.580
21.580
19.580
13.410
29.950
63.400
64.700
67.400
finding 20071010
Result of EQ find 1
Date: 20071010 Price: 03.500
Result of delete 1
Result of get_newest 1
Date was: 20201003
Pleaselookatthehighlightedlinesintheoutput.WhenwearedoneloadingtheCSVfile
intothedatabasethereare107records.Afterdeletingandpackingwehave100records.Takea
lookatthedescendingdateorderreport. Theoutputisquiteobviouslytrashed. Theindexes
haven'tbeen
updated.Theystillhavevalueswhichpointtorecordnumbers.Theonlyproblemis
thatthoserecordsnolongercontaininformationwhichcorrespondstotheindexvalue.
Ineedtopointoutthatitisquitepossibletocrashwhenusingastaleindexfileagainsta
recentlypackeddatabase.Youcouldattempttoreadarecordnumberwhichdoesn't
existinthe
database.Itallreallydependsonwhatkeyyouareusingandhowmanyrecordsweredeleted.
ScandowntothereportgeneratedafterwecalledreIndex().Noticethateverythingisbackto
thewayyouexpectittobe.
90
Chapter1Fundamentals
IfyouusexBASEproductslongenough,youwilleventuallyfindyourselfinasituationin
which youneedtopackadatabase. Packingadatabaseisalwaysagamble. Ifyouareina
productionenvironmentyouwillsimplynotknoweveryindexfileeveryapplicationcreatedto
viewyourdatatheamanneritchose.Youalsowon't
haveanywaytotellthoseapplicationsthey
needtorebuildtheindex.Itistheresponsibilityofthepackertocontactalloftheotherusers,not
justletthemcrash.
1.14
1.14ProgrammingAssignment5
Add a pack_database() method to doeHistory(). Don'tjust call pack(), reindex BOTH
indexes.Youwon't
justbeabletocallreIndex().Ifyoureadthatcodecarefullyyouwillseethat
itreliesonallindexfileshavingbeenopenedandattachedalready.
1.15
1.15DataIntegrity
Wetouchedonthisabitinthelastsection,butIneedtodrivethepointhomenow.Idon't
care what xBASE library you use orwhat language you work in,without a database engine
betweeneveryapplicationandtheactualdata,youcannotandwillnothavedataintegrity.
Dataintegrityismuchmorethansimplykeepingindexesinsynchwithactualdatarecords.
Dataintegrityinvolvesdatarulesandyoucannotimplementruleswithoutanengine,VM,or
someothersingleaccesspointbetweentheapplicationandtheactualdata.
Don't
worry,I'm
notgoingtoboreyouwithahighlytechnicalrantthatsoundslikealecture
onvenerealdisease.Dataintegrityisquiteeasytoexplaininlayman'sterms.
Letussaythatyourunalandfill.Everycompanywhichhassignedacontractwithyouhas
providedalistoftrucknumbersalongwithothertruckidentifyinginformation. Thesearethe
onlytrucksallowedtodumpatyourlandfillbecausethecompanieswillpayfortheirowntrucks
only.YoudutifullyputallofthisinformationintoaDBFfileusingauniquesegmentedkeyof
companyIdandtruckNum.
Withthattaskoutofthewayyousetaboutwritingyourscaleticketapplication.Theinbound
scaleoperatorwillpickatruckfromthelistyouprovideandkeyinthetruckfull(gross)weight.
Thesystemwillfillinthedateandtimebeforewritingtherecordtothetransactionfile.Afterthe
truckisdumped,itwillpullontotheoutboundscalewherethatoperatorwillpullpicktheticket
recordfromthelistofavailableticketsbaseduponthetrucknumberandcompany. Once the
operatorkeysintheempty(tare)weightthesystemwillprinttheticketandthescaleoperatorwill
handacopytothedriver.
Chapter1Fundamentals
91
Haveyounoticedanyproblemsyet?
You,thedeveloper,hadtowriteanapplicationwhichenforceddataintegrityonitsown.You
didn't
letthescaleoperatorkeyintruckinformation,heorshehadtopickfromalist,presumably
alistyoupopulatedfromyourtruckandcompanydatabase.Theoutboundscaleoperatorhadto
chooseoneofthecurrentlyopenticketstocomplete.
Thereisnothingintheenvironmentwhichwouldstopaticketrecordfromgettingwrittento
theticketdatabasewithatruckandcompanythatisn't
onthetruckandcompanydatabase.Your
applicationisprovidingthatdatarule,butthenextprogrammermaynotbeawareoftherule.
Withoutadatabaseengineprovidingasinglepointofaccessforallusersandapplications,
there isnomethodof enforcing integrityrules. There isno requirement that this engine be
relational,itsimplyneedstoprovidecontrolandrestrictaccess.
Itmightseemdifficulttounderstand,buttherearepeopleoutthereintoday's
worldpaying
hundredsandsometimesthousandsofdollarsforcommercialxBASEproductswhichprovidethis
verything.AruntimeorvirtualmachineisinstalledunderadifferentuserIDwhichownsand
controlsalldataandindexfiles.Theruntimecoordinatesallaccesstothedataandinmanycases
willenforcedataintegrityrules.Somewillevenforcetherebuildingofindexfileswhenevera
databasefileispacked.
Wearen't
dealingwithanengineorasinglepointofaccess.Ifyourapplicationisgoingto
haveanyformofdataintegritythenyouaregoingtohavetocodeitin.
1.16
1.16ProgrammingAssignment6
Thisismoreofa learnitonyourown assignment.Pickanyoneofthedatabaseswehave
coveredwhichhasauniqueprimarykeydefined. Writeormodifyaprogramwhichaddsfive
recordstothatfile.Afteraddingfiverecords,makesuretherecordsappearwhenreportingvia
theuniquekey. Oncetheyarethere,deletethreeofthoserecords,thenattempttoaddthree
recordswhichhavethesameprimarykeyvalue.
Whathappens?
Ifyoumanagetogettherecordsadded,whathappenswhenyouattempttoreIndex()?
Howaboutwhenyoutrytoundelete?
92
Chapter1Fundamentals
1.17
1.17Summary
It should now be obvious that xBaseJ provides a lot of functionality for applications of
limitedsizeandscope. Whenallyouneedisanindexedfileofsomekindforastandalone
applicationthiscanbeagreattool. Asyoushouldhavelearned from theindexproblemswe
covered,itisnotformultiuseruse.YouwillfindthatmostxBASElibrariesoutthereonlytalk
aboutbeingmultiuserforthedatafile,nottheindexes.Inordertogainspeed,mostofthese
librariesloadtheindexfilecontentsintomemory.
YoucangetalotofspeedoutofanxBASEfileformatontoday's
computerhardware.Most
of the concepts and original libraries were written to run on dual floppy computers running
4.77Mhz.Laterreimplementationsoftheselibrariesusedlessefficienthigherlevellanguages,
butmosttriedtohonortheoriginalspecifications.Javaisnotalanguageknownforperformance,
butonamachinewitha1Ghzorfasterclockspeed,itreallydoesn'thavetobethatefficient.
Withallthatithasgoing for it,adeveloperhastorememberthatxBASEwasoriginally
createdtosolveadatastorageandorderedinputproblem,notprovidethetypesofdataservices
weassociatewithtoday's
relationaldatabases. Theoriginalcreatorcouldnothaverealistically
envisioned all of the bastardized uses for this solution people would come up with in the
followingdecades.Oddlyenough,itisthehorrorstoriesfromimplementationsthatshouldhave
neverbeensignedoffonwhichgavexBASEitssomewhatmalignedreputation.
Youmightfinditdifficulttobelieve,butnexttoaCSV(CommaSeparatedValue)file,a
DBFfileisoneofthemostcommonmethodsofdataexchange.WhilesomecoreDBFformats
are widely supported, NDX and MDX files are not widely supported. xBaseJ focuses on
supportingtheminimalcoreofDBFdatatypesalongwiththememofields.Idon't
reallyknow
whythePicturedatatypewassupported,unlessthatwassimplyfalloutfromaddingMemofield
support.
Itwouldbeniceifoneormoreofyoureadingthiswouldtakeituponyourselvestoadd
supportforDatetime(T)andAutoincrement(+)sincethosedatatypesbecameratherwidelyused
inlateryears.Ihaven't
researchedeithersubject,butIimaginethatneithertypewillbeeasyto
adduntilsupporthasbeenaddedfornativeInteger(I).
IdidnotcoverMDXsupportatthistimebecauseitdoesn't
work.Keysareadded,butsort
orderisnotmaintained.
Chapter1Fundamentals
93
1.18
1.18ReviewQuestions
1. Whattwosituationsforceauserorapplicationtophysicallyremovedeletedrecords?
2. Bydefault,whatarestringandcharacterfieldspaddedwithwhenusingxBaseJ?
3. IfyouhaveaDBFopenwithNDXfilesattachedtoitthencallasubroutinewhichcreates
newNDXobjectsforthosesamefilesandcallsreIndex()onthem,willthechangestothe
indexfilesbereflectedintheNDXobjectsyouDBFholds?Whyorwhynot?
4. WhattwoJavaclassesdoyouneedtousetobuildcreateareportlinemakingthedataline
upincolumns?
5. HowdoesonetellxBaseJtopadstringandcharacterfieldswithspaces?
6. WhatDBFclassmethodphysicallyremovesrecordsfromthedatabase?
7. WhatisthemaximumsizeofaDBFfile?
8. WhatDBFclassmethodisusedtoretrieveavaluefromadatabaseFieldregardlessof
fieldtype?
9. AftercreatingashinynewDBFobjectandcorrespondingdatafile,whatmethoddoyou
usetoactuallycreatecolumnsinthedatabase?
10. WhatDBFclassmethodisusedtoassignavaluetoadatabaseField?
11. WhatDBFclassmethoddoyoucalltochangetheNDXkeyofreference?
12. WhatDBFclassmethodignoresallindexesandphysicallyreadsaspecificrecord?
13. Whenyoudeleteadatabaserecord,isitactuallydeleted?
14. WhatDBFclassmethodsetsthecurrentrecordtozeroandresetsthecurrentindexpointer
totherootofthecurrentindex?
15. WhatisthemaindifferencebetweenreadNext()andfindNext()?
16. Whatfunctionormethodreturnsthenumberofrecordsonfile?
17. Whathappenswhenyouattempttostoreanumericvaluetoolargeforthecolumn?
18. Whathappenswhenyouattempttostoreacharactervaluetoolargeforthecolumn?
19. Whenaccessingviaanindex,howdoyouobtaintherecordoccurringbeforethecurrent
record?
20. WhatDBFmethodreturnsthenumberoffieldscurrentlyinthetable?
21. Whenretrievingdatafromadatabasecolumn,whatdatatypeisreturned?
22. WhatisthemaximumlengthofacolumnnameformostearlyxBASEformats?
23. Whatdoestheinstanceofoperatorreallytellyou?
24. AredescendingkeysdirectlysupportedbyxBaseJ?
25. WhatNDXmethodcanyoucalltorefreshindexvaluesstoredintheNDXfile?
26. WhatJavaStringmethodallowsyoutosplitaStringintoanarrayofStringsbasedupona
delimitingString?
27. DoNDXobjectsmonitordatabasechangesmadebyotherprogramsorusers?
94
Chapter1Fundamentals
28. Canyou"undelete"arecordinaDBFfile?Ifso,whyandforhowlong?
29. WhenaNumericfieldisdeclaredwithawidthof6and3decimalplaces,howmanydigits
canexisttotheleftofthedecimalwhenthefieldcontainsanegativevalue?
30. Whendoyouneedtocreateafinalize()methodforyourclass?
31. WhatJavaclassprovidesthereadLine()methodtoobtainalineofinputfromatextfileor
stream?
32. DoxBASEdatafilesprovideanybuiltinmethodofdataintegrity?
33. Whatmustexist,nomatterhowthedataisstored,toprovidedataintegrity?
Chapter2
Chapter2
Mega
Zilli
MegaZ
illioonaire
naireApplica
Applicattion
2.1 WhyThisExample?
Thoseofyouwho havereadtheotherbooksinthisserieswon'tbetheonesaskingthis
question.I'm
answeringthisquestionforthenewcomers.WheneverIcoveranewlanguageor
tool,Iusethisapplicationtoputthefundamentalfeaturesthroughtheirpaces.Itrytoimplement
the application as close as possible to the original implementation covered in ISBN13
9780977086603. Besides being a good test application, having the same application
developed over and over again using different tools and languages allows people who own
legitimatecopiesofthisbookseriestoquicklytransitionbetweenlanguages,tools,andplatforms.
Theapplicationisnotallthatinvolved.Itisasimplelotterytrackingsystemwhichcontains
aprimarydatafileorderedbydrawingdateandtwostatisticsfilesorderedbyelementnumber.
Admittedly,Iusedaverybroaddefinitionofthetermstatisticssincewearesimplykeepingafew
countsandacoupleofpercentages.Theapplicationdoesencompasstheminimumofwhatyou
needtoknowaboutanytoolsetbeforeyoucanrealisticallybeginusingit.Youneedtobeableto
createamenu,animportutility,anentryscreen,adatabrowsingscreen,andsomereports.Ifyou
candoallofthat,youcanprettymuchfigureeverythingelseoutasyougo.
Herearethethreefiles:
Drawing_Data
Draw_dt
Date
No_1
Numeric
No_2
Numeric
No_3
Numeric
No_4
Numeric
No_5
Numeric
Mega_no
Numeric
Drawing_Stats
Elm_no
Hit_count
Last_draw_no
Since_last
Curr_seq
Longest_seq
Pct_hits
Max_btwn
Ave_btwn
2
2
2
2
2
2
Numeric
Numeric
Numeric
Numeric
Numeric
Numeric
Numeric
Numeric
Numeric
k0
2 k0
6
6
6
4
4
8,4
6
8,4
Mega_Stats
Elm_no
Hit_count
Last_draw_no
Since_last
Curr_seq
Longest_seq
Pct_hits
Max_btwn
Ave_btwn
Numeric
Numeric
Numeric
Numeric
Numeric
Numeric
Numeric
Numeric
Numeric
2 k0
6
6
6
4
4
8,4
6
8,4
96
Chapter2MegaZillionaireApplication
Carefulreaderswillnoticethatthelayoutforbothstatsfilesisthesame.WhenIoriginally
designedthisapplicationIdidn't
wanttocomplicateanapplicationIwasgoingtouseforseveral
introductorytexts. Yes,Ihaveenoughtechnicalskillstomergebothofourstatsfilesintoone
withtheadditionofatype orflag bytetosegregatetherecords.Exactlyhowmanypeople
whoarebrandnewtosoftwaredevelopmentorbrandnewtotheconceptofindexedfilesreading
this(orany)bookwillhaveallofthefundamentalskillsneededtojumprightintoanapplication
withasegmentedprimarykeythatspanstwodatatypes?Somestoragesystemswon't
evenallow
suchabeasttoexist.
HopefullyyouspentsometimeworkingthroughprogrammingassignmentsixfromChapter
1.Ifyoudid,thenregardlessofyourpriorskilllevel,youhaveagrasponhowconvolutedthis
demonstrationapplicationwouldgetwhentryingtocreaterecordsinthestatsfilesforthe nth
time.Whileitmaynotbesexy,adesignwhichallowseachstatisticsfiletobedeletedandcreated
fromscratcheachtimeauserchoosestogeneratestatsisbothcleanerandmoreunderstandable.
Let's
faceit:thefirstprogramyouareassignedincollegeprintsHello totheprinter,itdoesn't
solvetheTowerofHanoiproblem.EventuallyyougettotheTowerofHanoiproblem,butyou
don'tstartthere.
With the exception of the Logic book, the books in this series have all been aimed at
professionalprogrammers. Ididn't
givetwofullchaptersofexplanationpriortodroppingthis
exampleonthem.Thisbookisprimarilyaimedatpeoplewhoeitherhavehadoneprogramming
coursecoveringJavaorhavereadaTeach YourselfHowtoBeTotallyUselessin21Daysor
Less typebookandarelookingtoobtainactualskills.Becauseofthisapplicationthebookwill
alsobeusefultoanyonewhoownstherestofthebookseriesandneedstoquicklygetuptospeed
usingxBaseJ,orevenJavaunderLinux.
Unlikepriorbooksinthisseries,thisoneisgoingtodescribewhattheapplicationlookslike
first,thenwewilldiscussit. Themainmenu/formforthisapplicationlooksmuchlikemany
otherapplicationsimplementingtheCUA(CommonUserAccess)interface.Ithasamainmenu
acrossthetop,andthosedropdownwhenyouclickontheentries.
Chapter2MegaZillionaireApplication
Figure1Mainmenuatstartup
Figure2Filemenucontents
97
98
Figure3Reportmenucontents
Figure4Importafterfileimport
Chapter2MegaZillionaireApplication
Chapter2MegaZillionaireApplication
99
Figure5FileChooserusedwithimport
Changingjustacouplelinesofcodeinourapplication(andmakingsureanotherJARfileis
included)createsanapplicationwhichlookslikethis:
100
Chapter2MegaZillionaireApplication
Figure6EntryformwithNimrodlookandfeel
Figure7FileChooserwithNimrodlookandfeel
Youmightnoticethatitisn't
onlythecoloringwhichchanges,butthelayoutandstyleof
things.ThecommonJavatoolslikeFileChooseralsoaredramaticallydifferent.NotallLookand
FeelsareavailableforallversionsofJava.
Chapter2MegaZillionaireApplication
101
Figure8Entryform
Onethingwhichmightnotbeobviousisthe Deleted: prompt.Youcannotenteravalue
here,butwhenarecordwhichhasbeenflaggedfordeletionisdisplayed* willdisplayinthis
box. UnlessyouusealotofVCRtypesoftwaretherowofbuttonscontaininglessthanand
greaterthansignsmightnotbeintuitive.Asinglelessthansignmovestowardsthebeginning,
multiplesmovetotheverybeginning.Asinglegreaterthanmovestowardstheendandmultiples
movetotheveryend.
Itprobablywasn't
thebestchoiceoflabels,butOK performseitheranAddoranUpdate
dependinguponwhichmodeyouarecurrentlyin.Thereisnobuttontosetthemodeperse.If
youfindarecordviatheFind buttonoroneofthenavigationbuttons,youwillbeinfindmode.
Bydefaultthescreenstartsoutinaddmode. Ifyouneedtogetbacktoaddmodeyoumust
Clear,whichwillbothclearallentriesonthescreenandresetthescreenbacktoaddmode.
102
Chapter2MegaZillionaireApplication
Figure9Browseform
Althoughitisagainstmyreligiontodesignapplicationswhichloadeveryrecord froma
databaseintoaspreadsheet,thatiswhatendusershavecometoexpectthankstotheworld's
lowest quality software vendor, Microsoft. Nobody with even the tiniest shred of computer
scienceeducationwouldeverconsidergettingusers used toseeingdatadisplayedthisway. It
worksonlyundertheconditionwhichletsitworkhere:averylimitedsetofdatastoredlocally
andaccessreadonly.Ididitbecausemostofyouweregoingtowhineandsnivelaboutwanting
todoit.
Mostofyoureadingthisbookwillnothavehadprofessionalsoftwaredevelopmenttraining.
I cover this topic quite a bit in the OpenVMS Application Developer book (ISBN13
9780977086603) andtheSOAbook(ISBN139780977086665). Thespreadsheetdesign
ishorriblyinefficient.I'm
nottalkingaboutthecodetocreatethespreadsheetitself,I'm
talking
abouttheconceptsbehindthedesign. Itisaresourceintensivepigthatimposesseveredata
accessrestrictionsbyrequiringeitherexclusiveaccesstotheentiredataset,oralivedatamonitor
communicatingwiththedatabasetomonitorforanyandallrecordchanges.
Chapter2MegaZillionaireApplication
103
Chapter2MegaZillionaireApplication
104
2.2 SupportingClasses
MegaDBF.java
1)
2)
3)
4)
5)
6)
7)
8)
9)
10)
11)
12)
13)
14)
15)
16)
17)
18)
19)
20)
21)
22)
23)
24)
25)
26)
27)
28)
29)
30)
31)
32)
33)
34)
35)
36)
37)
38)
39)
40)
41)
42)
43)
44)
45)
46)
47)
48)
49)
50)
51)
52)
53)
54)
55)
56)
57)
58)
59)
package com.logikal.megazillxBaseJ;
import
import
import
import
import
import
java.io.*;
java.util.*;
org.xBaseJ.*;
org.xBaseJ.fields.*;
org.xBaseJ.Util.*;
org.xBaseJ.indexes.NDX;
int
int
int
int
int
int
int
int
int
int
int
MEGA_SUCCESS
MEGA_DUPE_KEY
MEGA_KEY_NOT_FOUND
MEGA_FILE_OPEN_ERR
MEGA_DEVICE_FULL
MEGA_NO_CURRENT_REC
MEGA_DELETE_FAIL
MEGA_GOTO_FAIL
MEGA_DB_CREATE_FAIL
MEGA_INVALID_DATA
MEGA_END_OF_FILE
=
=
=
=
=
=
=
=
=
=
=
1;
2;
3;
4;
5;
6;
7;
8;
9;
10;
11;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
//
Method to populate known class level field objects.
//
This was split out into its own method so it could be used
//
by either the open or the create.
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
private void attach_fields( boolean created_flg) {
try {
if ( created_flg) {
//Create the fields
Draw_Dt
= new DateField( "DrawDt");
No_1
= new NumField( "No1", 2, 0);
No_2
= new NumField( "No2", 2, 0);
No_3
= new NumField( "No3", 2, 0);
Chapter2MegaZillionaireApplication
60)
61)
62)
63)
64)
65)
66)
67)
68)
69)
70)
71)
72)
73)
74)
75)
76)
77)
78)
79)
80)
81)
82)
83)
84)
85)
86)
87)
88)
89)
90)
91)
92)
93)
94)
95)
96)
97)
98)
99)
100)
101)
102)
103)
104)
105)
106)
107)
108)
109)
110)
111)
112)
113)
114)
115)
116)
117)
118)
119)
120)
121)
122)
No_4
No_5
Mega_No
=
=
=
=
=
=
=
(DateField) aDB.getField("Drawdt");
(NumField) aDB.getField("No1");
(NumField) aDB.getField("No2");
(NumField) aDB.getField("No3");
(NumField) aDB.getField("No4");
(NumField) aDB.getField("No5");
(NumField) aDB.getField("MegaNo");
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
//
Method to close the database.
//
Don't print stack traces here. If close fails it is
//
most likely because the database was never opened.
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
public void close_database() {
if (!dbOpen)
return;
try {
if (aDB != null) {
aDB.close();
dbOpen = false;
}
} catch (IOException i) {}
}
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
//
Method to create a shiny new database
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
public void create_database() {
try {
//Create a new dbf file
aDB=new DBF(DEFAULT_DB_NAME,true);
attach_fields(true);
aDB.createIndex(DEFAULT_K0_NAME,"DrawDt",true,true);
dbOpen = true;
} catch( xBaseJException j){
System.out.println( "xBaseJ Error creating database");
j.printStackTrace();
105
Chapter2MegaZillionaireApplication
106
123)
124)
125)
126)
127)
128)
129)
130)
131)
132)
133)
134)
135)
136)
137)
138)
139)
140)
141)
142)
143)
144)
145)
146)
147)
148)
149)
150)
151)
152)
153)
154)
155)
156)
157)
158)
159)
160)
161)
162)
163)
164)
165)
166)
167)
168)
169)
170)
171)
172)
173)
174)
175)
176)
177)
178)
179)
180)
181)
182)
183)
184)
185)
continue_flg = false;
} // end catch
catch( IOException i){
System.out.println( "IO Error creating database");
i.printStackTrace();
continue_flg = false;
} // end catch IOException
// end create_database method
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
//
method to retrieve a copy of the DBF object
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
public DBF getDBF() {
return aDB;
} // end getDBF method
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
//
Method to test private flag and see
//
if database has been successfully opened.
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
public boolean isOpen() {
return dbOpen;
} // end ok_to_continue method
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
//
Method to open an existing database and attach primary key
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
public int open_database() {
int ret_val = MEGA_SUCCESS;
try {
//Create a new dbf file
aDB=new DBF(DEFAULT_DB_NAME);
attach_fields( false);
aDB.useIndex( DEFAULT_K0_NAME);
dbOpen = true;
reIndex();
// gets around problem with stale index info
} catch( xBaseJException j){
continue_flg = false;
} // end catch
catch( IOException i){
continue_flg = false;
} // end catch IOException
if (!continue_flg) {
continue_flg = true;
System.out.println( "Open failed, attempting create");
create_database();
} // end test for open failure
if (isOpen())
return MEGA_SUCCESS;
else
return MEGA_FILE_OPEN_ERR;
// end open_database method
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
//
Method to re-index all of the associated index files.
Chapter2MegaZillionaireApplication
186)
187)
188)
189)
190)
191)
192)
193)
194)
195)
196)
197)
198)
199)
200)
201)
202)
203)
204)
205)
206)
207)
208)
209)
210)
211)
212)
213)
214)
215)
216)
217)
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
public void reIndex() {
if (aDB != null) {
if (isOpen()) {
try {
NDX n = null;
for (int i=1; i <= aDB.getIndexCount(); i++) {
n = (NDX) aDB.getIndex( i);
n.reIndex();
}
} catch( xBaseJException j){
j.printStackTrace();
} // end catch
catch( IOException i){
i.printStackTrace();
} // end catch IOException
} // end test for open database
} // end test for initialized database object
} // end reIndex method
public int find_EQ_record( String d) {
int ret_val = MEGA_SUCCESS;
boolean perfect_hit;
if (!dbOpen)
return MEGA_FILE_OPEN_ERR;
try {
107
Chapter2MegaZillionaireApplication
108
248)
249) }
Thisisagoodexampleofthefarthestmostofyouwillgowhenwritingyourownclassesfor
applicationreuse,beitreusewithintheapplicationorotherapplications.Onceagainyouwill
seetheopen,close,andcreatemethodshavebeenprovided. Ahiddenattach_fields()method
ensureswealwayshavethesamefieldnames.AttheendofthesourcelistingIaddedmethodsto
findamatchingkeyandfindakeywhichisgreaterthanorequaltoaprovidedkeyvalue.Idid
notprovidemethodsfordeletion,butIdidprovidethereIndex()method.Thenicethingabout
thereIndex()methodisthatyouwillprobablycutandpasteitintoeveryDBFclassyoucreate.
AslongasyoumaketheDBFvariablenameaDBthismethodwillalwaysworkforyou.
Listing lines 56 through 62 might just provide some interesting confusion. I chose the
externallyvisiblecolumnnamesdeliberately. Theyareconsistentwiththenamesusedinthe
otherbooksofthisseries.GiventhenamingrestrictionsxBASEenforcesoncolumnnames,you
willnotethattheactualphysicalcolumnnamesdon't
matchtheexternallyvisible.Ididnotwant
toexperimentwithtryingtomakethe _ characterworkasacolumnname.Somecharactersets
forsomecountriesusethe_ asthede lete character. Iranintothisyearsago. WhenI'm
workingwithsomethinglikearelationalengineIwillusethe_ inacolumnname.Theengine
protectsmefromthepossibilityofthecharactersetchanging.
We should discuss listing line 163 before moving on. I would like to say I originally
designedthisapplicationinsuchawayastoinsulateitfromchangesmadebyothers.Thatwas
myoriginalintention.I,however,didnotoriginallyhavethereIndex()beingcalledoneachopen.
IhadtodothisbecauseofabuginthexBaseJlibrarywhichapparentlyIintroducedwhilefixing
anotherbug.ThankfullytheoriginaldeveloperranthedebuggeronanexampleIprovidedand
foundwherethingswentbad.WhenyouinitiallyopenedanNDXfile,somethingwasnotloaded
correctlywiththeindex.Youcangetaroundthisproblembymovingavalue,anyvalue,tothe
Fieldobjectnamedinthekey,oryoucancallreIndex().CallingreIndex()atthetimeofopen
won't
beabigburdenonmostapplicationshaving fewerthan5000records.Today's
computer
speedsarefastenoughthatyouprobablywon't
evennotice.Unlessyouaretheonlypersonusing
yourapplicationonyourcomputer,youshouldalwayscallreIndex()afteropeninganexisting
NDXfileanyway.
StatElms.java
1)
2)
3)
4)
5)
6)
7)
package com.logikal.megazillxBaseJ;
public class StatElms extends Object {
public int elmNo, hitCount, lastDrawNo, sinceLast, currSeq,
longestSeq, maxBtwn;
public double pctHits, aveBtwn;
} // end StatElms class
Chapter2MegaZillionaireApplication
109
Otherthanchangingthepackagename,thissourcefileisunchangedfromhowitappearedin
otherbooksintheseries.IfyouareunfamiliarwiththeshortcomingsofJava,thisclassfilewill
helppointthemout.Whengeneratingstatistics,weneedanarraytohold abunchofvalues.
Someofthesevaluesareupdatedeachtimeanumberoccursinadrawing,othersareupdated
onlyoncewehaveprocessedalldrawingrecords.Every3GLthebookseriescoversallowsusto
declarearecord/structurecontainingonlythesefields,thencreateanarrayofthatstructure.Java
doesn't
understandtheconceptofrecordsordatastructures,asitiscompletelyObjectOriented.
OOPisgoodforsomethings,butformoststandarddataprocessingtasks,itfails.Whenyouneed
a limited number of records containing a handful of fields OOP fails rather spectacularly.
Ultimately,thecontentsofthisarraygetwrittentooneofthetwostatisticsdatabases.
StatDBF.java
1)
2)
3)
4)
5)
6)
7)
8)
9)
10)
11)
12)
13)
14)
15)
16)
17)
18)
19)
20)
21)
22)
23)
24)
25)
26)
27)
28)
29)
30)
31)
32)
33)
34)
35)
36)
37)
38)
39)
40)
41)
42)
43)
package com.logikal.megazillxBaseJ;
import
import
import
import
import
import
java.io.*;
java.util.*;
org.xBaseJ.*;
org.xBaseJ.fields.*;
org.xBaseJ.Util.*;
org.xBaseJ.indexes.NDX;
Elm_No = null;
Hit_Count = null;
Last_Draw_No = null;
Since_Last = null;
Curr_Seq = null;
Longest_Seq = null;
Pct_Hits = null;
Max_Btwn = null;
Ave_Btwn = null;
// file names
public String DEFAULT_DB_NAME = null;
public String DEFAULT_K0_NAME = null;
// work variables
private boolean continue_flg = true;
private boolean dbOpen
= false;
// result codes
public static final
public static final
public static final
public static final
public static final
public static final
public static final
public static final
int
int
int
int
int
int
int
int
MEGA_SUCCESS
MEGA_DUPE_KEY
MEGA_KEY_NOT_FOUND
MEGA_FILE_OPEN_ERR
MEGA_DEVICE_FULL
MEGA_NO_CURRENT_REC
MEGA_DELETE_FAIL
MEGA_GOTO_FAIL
=
=
=
=
=
=
=
=
1;
2;
3;
4;
5;
6;
7;
8;
Chapter2MegaZillionaireApplication
110
44)
45)
46)
47)
48)
49)
50)
51)
52)
53)
54)
55)
56)
57)
58)
59)
60)
61)
62)
63)
64)
65)
66)
67)
68)
69)
70)
71)
72)
73)
74)
75)
76)
77)
78)
79)
80)
81)
82)
83)
84)
85)
86)
87)
88)
89)
90)
91)
92)
93)
94)
95)
96)
97)
98)
99)
100)
101)
102)
103)
104)
105)
106)
=
=
=
=
=
=
=
=
=
(NumField)
(NumField)
(NumField)
(NumField)
(NumField)
(NumField)
(NumField)
(NumField)
(NumField)
aDB.getField("ElmNo");
aDB.getField("HitCount");
aDB.getField("LstDrwNo");
aDB.getField("SinceLst");
aDB.getField("CurrSeq");
aDB.getField("LngstSeq");
aDB.getField("PctHits");
aDB.getField("MaxBtwn");
aDB.getField("AveBtwn");
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
//
Method to close the database.
//
Don't print stack traces here. If close fails it is
//
most likely because the database was never opened.
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
public void close_database() {
if (!dbOpen)
return;
Chapter2MegaZillionaireApplication
107)
108)
109)
110)
111)
112)
113)
114)
115)
116)
117)
118)
119)
120)
121)
122)
123)
124)
125)
126)
127)
128)
129)
130)
131)
132)
133)
134)
135)
136)
137)
138)
139)
140)
141)
142)
143)
144)
145)
146)
147)
148)
149)
150)
151)
152)
153)
154)
155)
156)
157)
158)
159)
160)
161)
162)
163)
164)
165)
166)
167)
168)
169)
try {
if (aDB != null) {
aDB.close();
dbOpen = false;
}
} catch (IOException i) {}
}
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
//
Method to create a shiny new database
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
public void create_database( String dbf_name) {
try {
// Define default names
DEFAULT_DB_NAME = dbf_name + ".dbf";
DEFAULT_K0_NAME = dbf_name + "k0.ndx";
//Create a new dbf file
aDB=new DBF(DEFAULT_DB_NAME,true);
attach_fields(true);
aDB.createIndex(DEFAULT_K0_NAME,"ElmNo",true,true);
dbOpen = true;
} catch( xBaseJException j){
System.out.println( "xBaseJ Error creating database");
j.printStackTrace();
continue_flg = false;
} // end catch
catch( IOException i){
System.out.println( "IO Error creating database");
i.printStackTrace();
continue_flg = false;
} // end catch IOException
// end create_database method
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
//
method to retrieve a copy of the DBF object
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
public DBF getDBF() {
return aDB;
} // end getDBF method
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
//
Method to test private flag and see
//
if database has been successfully opened.
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
public boolean isOpen() {
return dbOpen;
} // end ok_to_continue method
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
//
Method to open an existing database and attach primary key
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
public int open_database( String dbf_name) {
int ret_val = MEGA_SUCCESS;
// Define default names
DEFAULT_DB_NAME = dbf_name + ".dbf";
DEFAULT_K0_NAME = dbf_name + "k0.ndx";
111
Chapter2MegaZillionaireApplication
112
170)
171)
172)
173)
174)
175)
176)
177)
178)
179)
180)
181)
182)
183)
184)
185)
186)
187)
188)
189)
190)
191)
192)
193)
194)
195)
196)
197)
198)
199)
200)
201)
202)
203)
204)
205)
206)
207)
208)
209)
210)
211)
212)
213)
214)
215)
216)
217)
218)
219)
220)
221)
222)
223)
224) }
try {
//Create a new dbf file
aDB=new DBF(DEFAULT_DB_NAME);
attach_fields( false);
aDB.useIndex( DEFAULT_K0_NAME);
reIndex();
dbOpen = true;
reIndex();
} catch( xBaseJException j){
continue_flg = false;
} // end catch
catch( IOException i){
continue_flg = false;
} // end catch IOException
if (!continue_flg) {
continue_flg = true;
System.out.println( "Open failed, attempting create");
create_database( dbf_name);
} // end test for open failure
if (isOpen())
return MEGA_SUCCESS;
else
return MEGA_FILE_OPEN_ERR;
// end open_database method
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
//
Method to re-index all of the associated index files.
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
public void reIndex() {
if (aDB != null) {
if (isOpen()) {
try {
NDX n = null;
for (int i=1; i <= aDB.getIndexCount(); i++) {
n = (NDX) aDB.getIndex( i);
n.reIndex();
}
} catch( xBaseJException j){
j.printStackTrace();
} // end catch
catch( IOException i){
i.printStackTrace();
} // end catch IOException
} // end test for open database
} // end test for initialized database object
} // end reIndex method
// end class StatDBF
YouwillnoticethatIdidn't
providemethodstofindindividualrecordsviaakey. Idid
providethegetDBF()methodsoauseroftheclasscoulddomostofwhat heorshe wanted.
TherewasareIndex()methodprovidedtofacilitateworkingaroundthepreviouslymentioned
bug,butotherwise,thisclassisprettybasic.
Chapter2MegaZillionaireApplication
113
Pleaseallowmetodirectyourattentiontolistinglines119through123and163through168.
Youmayrecallthatbothstatisticsfileshaveexactlythesamelayout. (Ifyoudon't
recallthis
pleaseflipbacktothefirstpageofthechapterandlookattheproposedrecordlayoutsagain.)The
onlygoodwayofreusingadatabaseclassunderthoseconditionsistomaketheopenandcreate
methodssetthefilenamesfortheclass.
AsyouprogressinyourprofessionalcareeryouwillencountermanyOOPprogrammerswho
consideraclassoperatinginthismannercompletesacrilege.Theywouldbewrong.Theywould
alsonotbeproductionprogrammers.Pleasedonotconfusesomeonewhoisalwaysworkingon
new development with someone who is a production programmer. Newdevelopmentonly
peoplecreatethemessproductionpeoplehavetocleanup.
Classeswhichrequireafilenameatthetimeofobjectcreationand/oropenadatabase/file
resourceatthattimearetwoofthemainhallmarksofbadapplicationdesign.Theyseemohso
politicallycorrectwhenyouaresittingthereinschooldoingyourhomework,buttheyareatrain
wreckwaitingtohappeninreallife.Pleasetakeagoodlookatthetopofthissourcefilewhere
the data which will be global for the class instance is declared. Do you see a constructor
anywhereafterthatglobaldatawhichforcesafilenametobesupplied?Forthatmatter,doyou
seeaconstructordeclared?
SomeofyouaregoingtotaketheopportunitytoopenthesourcefortheDBFclass,orflipto
thebackofthisdocumentandpointtotheconstructordocumentationandcryfoul. Youaren't
pointingoutmyerrorwhenyoudothat,youarepointingoutthefactthatyoudonotunderstand
thedifference between application design and library design. Inparticular,lowlevel library
design.Whydoyouthinkthefourexampleprogramsprovidedwiththelibraryitselfaresohard
codedandhavetoberuninaspecificorder?Thisisalowlevellibrary,atleastasfarasxBASE
accessisconcerned.Whileithidessomeoftheuglydetailsfromyou,itcertainlydoesn't
provide
muchinthewayofhighlevelinterfaces.
IhaveseenC/C++codegeneratorswhichtakealistoffieldsalongwiththeirdatatypesanda
listofindexcomponents,thengenerateacompleteclassforyou. Thatclassdoesn't
allowany
lowlevelaccesstoanyportionofthedatastorage.Eachfieldhasitsownuniquelynamedget()
andset()methodsand eachkey hasitsownfindEQ,GT,LTmethods. Inmanycases, the
developerusingtheclasshasnoideawherethedataisstoredorhowitisstored.Ineffect,itis
likethoseI/OmodulesItoldyouaboutearlier.Thetheorybehindthemisthatthedatastorage
couldbechangedwithoutanyonehavingtochangetheapplicationinanyway.Itneverworksin
practice,butitisanicetheory.
Chapter2MegaZillionaireApplication
114
Youaretheoneresponsibleforcreatingthelevelofabstractionnecessaryforyourproject.It
isuptoyoutodecidethedefinitionofcodereuseinyourenvironment.
Someofyouwillbehardcorecoderswhothink thatcuttingandpastingfrominsidethe
editoriswhattheindustrymeanswhentheysaycode reuse. Yourview is thatifonlyyou
knowallofthemodulesaparticularpieceofcodehasbeenpastedinto,thenyoucanneverbe
fired.Youwouldbewrong,butthatwouldbeyourview.
Othersreadingthisbookwilltakeituponthemselvestowriteadatabaseclassgeneratorlike
theoneIdescribed.Youwillalsoincludeextract_to()andcopy()methodstoallowdevelopersto
generateCSVfilesandsafetycopiesofdata. Thestarsmayalignandyoumaychoosetoadd
yourcreationtotheproject,thusimprovingit.
Mostofyouwillfallsomeplaceinthemiddleofthosetwoextremes.Ifyouhadn't
founda
copyofthisbookyouwouldhaveprobablytriedtostumblethroughviathecutandpastemethod,
butnowyouhavesomefilebasedDBFclassesasastartingpoint.Theywillstartoutasdirect
copiesorjustsubsetsoftheclassesIhaveprovided,butasyourcodingandneedsincrease,sowill
the default methodsyouprovide.Youwilleventuallycometorealizethattherealvalueofthis
bookisn'tjustthelibraryexplanation,buttheinstructions
concerninghowtodesignapplications.
MegaXDueElms.java
1)
2)
3)
4)
5)
6)
7)
8)
9)
10)
11)
12)
13)
14)
15)
16)
17)
18)
19)
20)
21)
22)
23)
24)
25)
26)
27)
28)
29)
30)
31)
package com.logikal.megazillxBaseJ;
import java.util.*;
import com.logikal.megazillxBaseJ.StatElms;
public class MegaXDueElms extends StatElms
implements Comparable {
//
// method to cause sort in Descending order
// based upon how many drawings it has been since
// it hit. Number is only "due" if it is past its average.
//
public int compareTo( Object o2) {
MegaXDueElms s2 = (MegaXDueElms) o2;
double o1_value, o2_value;
int ret_val=0;
o1_value = this.aveBtwn - this.sinceLast;
o2_value = s2.aveBtwn - s2.sinceLast;
if ( o2_value > o1_value)
ret_val = 1;
else if ( o2_value < o1_value)
ret_val = -1;
}
return ret_val;
// end compare method
Chapter2MegaZillionaireApplication
32)
33)
34)
35)
36)
37)
38)
39)
40)
41)
42)
43)
44)
45)
46)
47) }
115
return ret_val;
// end equals method
Youdidn'treallythinkIwasgoingtoletyouoffwithonlyonerantabouttheshortcomingsof
OOP,didyou?ImustadmitthatinJava1.6thingsgotabitbetter,butyoucan't
simplycodein
Java1.6sinceJava1.4isstillthemostwidelyusedinthefield.Becauseofthat,Ihadtoextend
the StatElms class just to create a class which could implement the Comparable interface.
TechnicallyIdidn'thavetocodetheequals()methodsinceIdidn't
callit,butcompareTo()is
required.
ThemajordownsidetothisdesignisthatIhavetocreateaseparateclassforeverysortorder
needed.I'm
nottalkingaboutanindividualsortcomparefunctionforeachorder,butanactual
classthatIcreateanarrayofandloaddatainto.
SomedocumentationclaimsthattheComparatorinterfacestartedwith1.4.2. Itmayhave,
butonmymachineIcouldn't
getittocompilewhenusingthe1.4switch.AComparatorobject
wouldhaveallowedmetohaveaseparateobjectforeachsortingoftheStatElmsarray,butwould
notrequiredifferentarraysandcopiesofdata. Inthatcase,theclasswouldhaveencompassed
aboutasmuchcode,butyouwouldhavehadlessworktodowithyourassignmentslaterinthis
chapter.Hadwebeenusingversion5orhigherwecouldhavedonethis.
Chapter2MegaZillionaireApplication
116
DueSortCompare.java
1)
2)
3)
4)
5)
6)
7)
8)
9)
10)
11)
12)
13)
14)
15)
16)
17)
18)
19)
20)
21)
22)
23)
24)
25)
26)
27)
28)
29)
30)
31)
32)
33)
34)
35)
package com.logikal.megazillxBaseJ;
import java.util.*;
import com.logikal.megazillxBaseJ.StatElms;
//;;;;;;;;;;;;;;;;;;;;
//
EXAMPLE ONLY
//
Code not actually used in application
//;;;;;;;;;;;;;;;;;;;;
public class DueSortCompare
implements Comparator<StatElms> {
//
// method to cause sort in Descending order
// based upon how many drawings it has been since
// it hit. Number is only "due" if it is past its average.
//
public int compare( StatElms s1, StatElms s2) {
double o1_value, o2_value;
int ret_val=0;
o1_value = s1.aveBtwn - s1.sinceLast;
o2_value = s2.aveBtwn - s2.sinceLast;
if ( o2_value > o1_value)
ret_val = 1;
else if ( o2_value < o1_value)
ret_val = -1;
}
}
return ret_val;
// end compare method
ThecalltoArrays.sort()wouldhavehadtheComparatorobjectprovidedasanadditional
parameterratherthanexpectingtheobjectarraytoimplementtheComparableinterface.Itishard
toshowjusthowresourceintensivethisshortcomingiswithouthavinganapplicationthatalready
squeezessystemresourcesandneedingthedatasortedmultipleways.Whatifthedatafilewhich
fedthisarraywasover1GBinsizeandweneededtosortitthreedifferentwaysforareport?
Evenifwedirectlycopiedfromonearrayelementtoanother,wewouldconsumeatleast2GBof
RAMmakingthecopy,thenwewouldhaveto hope garbagecollectionquicklygotaroundto
reclaimingtheoriginalarraysowecouldmakeournextcopy.This,ofcourse,assumesthatwe
hadatleast2GBofRAMavailabletotheJavaVM.
Ididn't
usetheequals()methodinthisapplication,butweshouldtalkaboutitabit.Someof
youmaybehorrifiedtoseeifstatementsnestedthatdeep,but,intruth,itisthesimplestwayto
implementsuchamethod.Ifanyoneofthosefieldsdidn't
match,wecouldstoplooking.You
mayhavenoticedthatIomittedcheckingeitherofthedoublefieldsforbeingequal,butdidyou
hazardaguessastowhy?
Chapter2MegaZillionaireApplication
117
Javaisn't
aperfectlanguage. TheVMbringswithitmuchofthebaggagewehaveseen
throughouttheyearswithfloatingpointnumbers. True,itreducedtheproblemtoexactlytwo
floatingpointimplementations,floatanddouble.Itisalsotruethatthosetwodatatypesusetwo
differentIEEEstandardstohelpreduceproblemswithportingtheVMtovariousplatforms.Even
givenallofthat,westillhavefloatingpointbaggagetodealwith. (AlanguagecalledDIBOL
usedBinaryCodedDecimalorBCDtodofloatingpointmathwhileearlyxBASEformatsstored
everythingincharacterformattocompletelysidesteptheissue.)
Themainbaggageproblemwehavetodealwithisthefactthat1.234willnotequal1.234
most of the time. The IEEE floating point standards are approximations. They introduce
precision errors and rely on rounding rules of the output utilities to correct these errors.
Dependinguponhowyouarrivedat1.234itmaybe1.2344123or1.2344389.Toushumansit
willbedisplayedas1.234,but,toabinaryequalitytestlike==thetwovaluesarenotequal.
Youdon't
knowenoughabouttheapplicationyet,butpctHitsandAveBtwnarecalculated
baseduponthetotalnumberofdrawingsandtheintegervalueswehavealreadytested.Thetotal
numberofdrawingswillbeanintegerwhichisthesameforallelementsandisnotstoredonthe
file.Thebeautyofthisrealityisthatweonlyhavetocomparetheintegerstoseeiftheelements
match.
OurMegaXDueElmsarray isusedtocalculatethevaluesofourDuereport. Ihavenot
providedascreenshotofthisreport,butwewilldiscussitslogicanyway.
2.3 ThePanels
MegaXbaseDuePanel.java
1)
2)
3)
4)
5)
6)
7)
8)
9)
10)
11)
12)
13)
14)
15)
16)
17)
18)
19)
20)
21)
22)
package com.logikal.megazillxBaseJ;
import
import
import
import
import
import
java.awt.*;
java.awt.event.*;
javax.swing.*;
java.util.*;
java.text.*;
java.lang.Integer;
import org.xBaseJ.*;
import org.xBaseJ.fields.*;
import org.xBaseJ.Util.*;
import com.logikal.megazillxBaseJ.MegaXDueElms;
import com.logikal.megazillxBaseJ.StatDBF;
// You need to import the java.sql package to use JDBC
//
import java.sql.*;
import java.io.*;
118
Chapter2MegaZillionaireApplication
23)
24)
25) public class MegaXbaseDuePanel extends JPanel
26)
implements ActionListener {
27)
28)
public final int ELM_COUNT = 57;
// highest number is 56 but I don't
29)
// feel like messing with zero
30)
31)
private JPanel
mainPanel;
32)
private JScrollPane sp;
33)
private JButton
refreshButton;
34)
private JTextArea
dueRptArea;
35)
36)
37)
//;;;;;;;;;;
38)
// Constructor
39)
//;;;;;;;;;;
40)
public MegaXbaseDuePanel( ) {
41)
mainPanel = new JPanel( new GridBagLayout());
42)
GridBagConstraints gbc = new GridBagConstraints();
43)
44)
// Add our refresh button first
45)
// This way we have an object to find the root panel of
46)
//
47)
JPanel buttonPanel = new JPanel();
48)
refreshButton = new JButton("Refresh");
49)
refreshButton.addActionListener( this);
50)
buttonPanel.add( refreshButton, BorderLayout.NORTH);
51)
gbc.anchor
= GridBagConstraints.NORTH;
52)
gbc.gridwidth
= GridBagConstraints.REMAINDER;
53)
mainPanel.add( buttonPanel, gbc);
54)
55)
dueRptArea = new JTextArea();
56)
// Gives you a fixed width font.
57)
dueRptArea.setFont(new Font("Courier", Font.PLAIN, 12));
58)
dueRptArea.setEditable( false);
59)
dueRptArea.setTabSize(4);
60)
dueRptArea.setColumns( 80);
61)
dueRptArea.setRows(120);
62)
dueRptArea.setDoubleBuffered( true);
63)
sp = new JScrollPane( dueRptArea);
64)
sp.setPreferredSize( new Dimension( 500, 300));
65)
66)
67)
mainPanel.add( sp);
68)
add(mainPanel);
69)
setVisible( true);
70)
} // end constructor
71)
72)
73)
public void actionPerformed(ActionEvent event) {
74)
System.out.println( "Entered action event");
75)
76)
generateReport();
77)
78)
} // end actionPerformed method
79)
80)
81)
//;;;;;
82)
// Method which does all of the interesting work.
83)
//;;;;;
84)
private void generateReport() {
85)
StatDBF dDB = new StatDBF();
Chapter2MegaZillionaireApplication
86)
87)
88)
89)
90)
91)
92)
93)
94)
95)
96)
97)
98)
99)
100)
101)
102)
103)
104)
105)
106)
107)
108)
109)
110)
111)
112)
113)
114)
115)
116)
117)
118)
119)
120)
121)
122)
119
try {
// load the array
dDB.open_database("drawst");
for (int i=1; i < ELM_COUNT; i++) {
dDB.getDBF().gotoRecord( i);
d_elms[i] = new MegaXDueElms();
d_elms[i].elmNo = Integer.parseInt(dDB.Elm_No.get().trim());
d_elms[i].hitCount = Integer.parseInt(dDB.Hit_Count.get
().trim());
d_elms[i].lastDrawNo = Integer.parseInt(dDB.Last_Draw_No.get
().trim());
d_elms[i].sinceLast = Integer.parseInt(dDB.Since_Last.get
().trim());
d_elms[i].currSeq = Integer.parseInt(dDB.Curr_Seq.get().trim
());
d_elms[i].longestSeq = Integer.parseInt(dDB.Longest_Seq.get
().trim());
d_elms[i].maxBtwn = Integer.parseInt(dDB.Max_Btwn.get().trim
());
d_elms[i].pctHits = Double.parseDouble(dDB.Pct_Hits.get
().trim());
d_elms[i].aveBtwn = Double.parseDouble(dDB.Ave_Btwn.get());
}
System.out.println("Finished loading array");
// finished with this database
dDB.close_database();
// Sort the array.
Arrays.sort( d_elms, 1, ELM_COUNT-1);
// generate report
DateFormat heading_format = DateFormat.getDateInstance
( DateFormat.SHORT);
123)
NumberFormat nf_elm
= NumberFormat.getInstance();
124)
NumberFormat nf_hits
= NumberFormat.getInstance();
125)
NumberFormat nf_since
= NumberFormat.getInstance();
126)
NumberFormat nf_pct
= NumberFormat.getInstance();
127)
NumberFormat nf_ave
= NumberFormat.getInstance();
128)
129)
nf_elm.setMinimumIntegerDigits(2);
130)
nf_pct.setMinimumFractionDigits(3);
131)
nf_ave.setMinimumFractionDigits(3);
132)
133)
Calendar c
= Calendar.getInstance();
134)
// obtain current date
135)
//
136)
c.setTime( new java.util.Date());
137)
138)
dueRptArea.append( "Date: " + heading_format.format( c.getTime()
)
139)
+ "\n
"
120
140)
141)
142)
Chapter2MegaZillionaireApplication
+ "Due NumbersReport\n");
dueRptArea.append("\n
Regular
Drawing Numbers\n\n");
143)
dueRptArea.append(" NO
Hits Since
Pct_Hits
Ave_Btwn
\n");
144)
dueRptArea.append(" ----- ------------------\n");
145)
146)
String detail_line=null;
147)
int l_x = 1;
148)
while ( l_x < ELM_COUNT ) {
149)
if ((double)d_elms[l_x].sinceLast > d_elms[l_x].aveBtwn) {
150)
detail_line = " " + nf_elm.format( d_elms[ l_x].elmNo)
151)
+ "
" + nf_hits.format( d_elms[ l_x].hitCount)
152)
+ "
" + nf_since.format( d_elms[l_x].sinceLast)
153)
+ "
" + nf_pct.format( d_elms[ l_x].pctHits)
154)
+ "
" + nf_ave.format( d_elms[ l_x].aveBtwn)
155)
+ "\n";
156)
dueRptArea.append( detail_line);
157)
}
158)
l_x++;
159)
} // end while loop
160)
161)
dueRptArea.append( "\n\n");
162)
dueRptArea.append( "\n\n====================================\n
\n");
163)
updateText();
164)
165)
//----166)
// Now process the Mega numbers
167)
//----168)
// load the array
169)
mDB.open_database( "megast");
170)
for (int i=1; i < ELM_COUNT; i++) {
171)
mDB.getDBF().gotoRecord( i);
172)
m_elms[i] = new MegaXDueElms();
173)
m_elms[i].elmNo = Integer.parseInt(mDB.Elm_No.get().trim());
174)
m_elms[i].hitCount = Integer.parseInt(mDB.Hit_Count.get
().trim());
175)
m_elms[i].lastDrawNo = Integer.parseInt(mDB.Last_Draw_No.get
().trim());
176)
m_elms[i].sinceLast = Integer.parseInt(mDB.Since_Last.get
().trim());
177)
m_elms[i].currSeq = Integer.parseInt(mDB.Curr_Seq.get().trim
());
178)
m_elms[i].longestSeq = Integer.parseInt(mDB.Longest_Seq.get
().trim());
179)
m_elms[i].maxBtwn = Integer.parseInt(mDB.Max_Btwn.get().trim
());
180)
m_elms[i].pctHits = Double.parseDouble(mDB.Pct_Hits.get
().trim());
181)
m_elms[i].aveBtwn = Double.parseDouble(mDB.Ave_Btwn.get
().trim());
182)
}
183)
184)
// finished with this database
185)
mDB.close_database();
186)
187)
// Sort the array.
188)
Arrays.sort( m_elms, 1, ELM_COUNT-1);
189)
190)
// generate report
Chapter2MegaZillionaireApplication
191)
192)
193)
194)
195)
196)
121
+ "\n
+ "Due NumbersReport\n");
"
dueRptArea.append("\n
Mega
Numbers\n\n");
197)
dueRptArea.append(" NO
Hits Since
Pct_Hits
Ave_Btwn
\n");
198)
dueRptArea.append(" ----- ------------------\n");
199)
200)
l_x = 1;
201)
while ( l_x < ELM_COUNT ) {
202)
if ((double)m_elms[l_x].sinceLast > m_elms[l_x].aveBtwn) {
203)
detail_line = " " + nf_elm.format( m_elms[ l_x].elmNo)
204)
+ "
" + nf_hits.format( m_elms[ l_x].hitCount)
205)
+ "
" + nf_since.format( m_elms[l_x].sinceLast)
206)
+ "
" + nf_pct.format( m_elms[ l_x].pctHits)
207)
+ "
" + nf_ave.format( m_elms[ l_x].aveBtwn)
208)
+ "\n";
209)
dueRptArea.append( detail_line);
210)
}
211)
l_x++;
212)
} // end while loop
213)
214)
dueRptArea.append( "\n\n");
215)
dueRptArea.setCaretPosition(0); // scroll back to top
216)
} catch (xBaseJException x) {
217)
} catch (NumberFormatException n) {
218)
n.printStackTrace();
219)
} catch (IOException e) {
220)
}
221)
222)
} // end generateReport method
223)
224)
public void updateText() {
225)
mainPanel.invalidate();
226)
mainPanel.validate();
227)
mainPanel.paintImmediately( mainPanel.getVisibleRect());
228)
mainPanel.repaint();
229)
} // end updateText method
230)
231)
232) } // end MegaXbaseDuePanel class
You will be getting two assignments based upon this module, so I'mgoing to take the
discussionabitslowerthanIhavebeenfortheothermodules.Withtheexceptionoftheimport
function, alloftheothermenuoptionsareimplementedaspanelswhichdisplayonthemain
menupanelusingCardLayout.TheCardLayoutallowsyoutostack1Npanelsontopofeach
otherlikeadeckofcardswhicharefaceup.Youthenshufflethecardyouwanttothetopofthe
faceupdecksoitisdisplayed. Alloftheothercardsareleftintheircurrentstatewhenyou
changethedisplayedcard.Whenyouchoosetoredisplayoneofthecardsyoudonotcreatea
newinstanceofitorreinitializeitscontentsinanyway;itissimplyshownagainasitwaslast
seen.
122
Chapter2MegaZillionaireApplication
EachpanelwhichgetsplacedintotheCardLayoutcan,anddoes,haveitsownlayout. It
couldactuallyhavemanydifferentlayoutsonit,butwehaveonlyonelayoutinusebecausewe
don'thavemuchtodisplay.
Thisparticularpanelhasonlyarefreshbuttontodisplayatthetopofthescreenandatext
areawhichgetsdisplayedinsideofascrollpane.Intruth,itlooksmuchlikethebrowsescreen
snapshotI've
providedyou,onlyithasregulartextinsteadofaspreadsheetinsideofthescroll
pane.
OurpanelusesaGridBagLayout.Don't
askmetotellyouwherethenamecamefromorall
ofthedetails.GridBagLayoutisoneofthefewfunctionallayoutsexistinginJava,atleastinthe
daysofversion1.4.ThetopicoflayoutshasbecomesoheatedanddebatedthattheC++cross
platform GUI library named Qt has released a Java wrapper for its library and many Java
developershave begunmigratingawayfromSwing. Whenitcomestothesubjectoflayout
managersandJava,itlookslikethesubjectwastableduntillaterandlaterstillhasn'tcome.
YoupositionobjectsinaGridBagLayoutviaaGridBagConstraintsobject. Ordinarilyyou
willfillinonlytheanchorandgridwidthvalues,leavingtherestoftheGridBagConstraintsfields
attheirdefaultvalues.Normallygridwidthisanumericconstantsuchas1or2,butitcanbea
coupleofspecial values.OnesuchvalueisREMAINDERasshownonlistingline52.This
tellsthelayoutmanagertheobjectisthelastoneonthecurrentlineofobjectsitisbuilding.
TheanchorportionofGridBagConstraintshasalotofdirectionsoundingconstants,which
canbealittleconfusing. MostpeopleassumethatalloftheNORTHbasedconstraintshave
somethingtodowiththetopofthedisplayandtheSOUTHbasedconstraintshavesomethingto
dowiththebottomofthedisplay.Ingeneral,thisistrue,butnotastrueasitsounds.Tostart
with,theenclosingobject,inthiscaseourJPanel,canchangethecomponent orientationand
insteadoflefttorighttoptobottomthescreenmightbedisplayedrighttoleftbottomtotop.In
anycase,NORTHisassociatedwiththestartingpointandSOUTHwiththefinishingpoint.We
willdiscussthistopicingreaterdetailwhenwecovertheEntryscreen.Ijustwantedtogetyou
thinkingaboutitnow.LayoutsinJavaarenotaneasysubjecttodiscussinabook.Somereaders
willhavetenyearsofcodingundertheirbeltsandafewhundredsourcetemplatessavedondisk;
otherswillhaveonlywrittenHelloWorld.java.
Wecreateourtextareaatlistinglines55through62,thenplaceitinascrollpaneatlisting
line63.MostofwhatIdidwasprettyselfexplanatory.Wedo,however,needtotalkaboutthe
setFont()call.IchosetousethefontnameCourier . Mostsystemswhichhavesomekindof
WebbrowserwillhavesomekindofCourier fontinstalledonthem.Whenyouarecreating
columnarreportsyouneedtohaveafixedwidthfontsothosecolumnshaveachanceatliningup.
Chapter2MegaZillionaireApplication
123
MostJavapuristsreadingthiswillscreamthatIshouldhaveusedthelogicalfontname
Monospaced whichisrequiredtobeimplementedbyallJavaVMs. Thesimpletruthisthat
Monospaced isnotrequiredtobeimplemen ted, itisrequiredtohaveaphysicalfontmapped
toit.Thatfontmayhaveabsolutelynothingtodowithfixedwidthormonospace.EvenCourier
isnotafixedwidthfontwhendealingwithTrueTypefonts.Atcertainpointsizesthingswillline
up,butitwon't
beperfect.Ultimately,thefontyouchoosetouseisuptoyou.Ichoseafont
whichworkswellonmostplatforms. Ifitdoesn't
workwellforyou,changethesourceand
recompileit.
TheworkhorseofthisclassisthegenerateReport()method.Herewereadeachrecordfrom
eachstatfile,savethevaluesintoourarrays,sortourarrays,thenprintourreportintothetext
area.YouwillnotethatIcallupdateText()fromtimetotime.Wheneveryoucallappend()toadd
texttoaJtextArea,thetextisaddedtotheinmemoryobject,butaneventisonlyqueuedto
updateanyassociatedonscreendisplay.ThedisplaymanagerinJavawaitsuntilitthinks the
systemisidletoupdatethedisplay,orfindsitselfforcedtoupdatethedisplay.Thelinesofcode
inupdateText()forcethedisplaymanagertoconsolidatealloftheupdatesanddisplaythem.This
stepdoesslowdownprocessing,soyoushoulddoitonlyatpointsintimewhenyoufeeltheuser
mustseetheprogresswhichhasbeenmade.
Ineedtopointoutonetinylittlethingatlistingline103.YoumaynotgraspwhyIcalled
trim()aftercallingget().TheparseInt()staticmethodthrowsexceptionsifthenumericstringyou
handitcontainsspaces.Idon't
knowwhyitdoesn't
calltrim()onitsown,butitdoesn't
.Asyou
canseebylistingline111,parseDouble()managedtohandlethingsjustfine.
Listinglines123through131containsomethingItrulyhateaboutJava1.4andearlier.The
NumberFormatobjectisveryprimitive.Itdoesprovidemethodstosettheminimumnumberof
fractionaldigits,andminimumnumberofintegerdigits,butithasnoconceptofjustification,fill
character,ordisplaywidth.Ifyoutrytosetboththeintegerandfractiondigitsforacolumn,it
willzerofillonthefrontandforcethedisplaytolooksomethinglikethefollowing.
NO
-30
16
52
23
25
48
43
45
03
46
04
Hits Since
Pct_Hits
Ave_Btwn
---- ------------------0,035
00,010
000.092
009.886
0,036
00,010
000.094
009.583
0,041
00,009
000.108
008.293
0,027
00,014
000.071
013.111
0,040
00,010
000.105
008.525
0,042
00,010
000.110
008.071
0,038
00,011
000.100
009.026
0,031
00,014
000.081
011.290
0,030
00,015
000.079
011.700
0,044
00,011
000.116
007.659
0,031
00,016
000.081
011.290
Chapter2MegaZillionaireApplication
124
NotexactlywhatIwouldcallhumanfriendlyoutput.WediscussedtheFormatterclasson
page54.ThisclassaddedsomethingwhichwasrequiredtobringJavaintothebusinessworld,
theabilitytocreateacolumnarreport.Notoneofyouwouldpayyourcreditcardbillifthetext
swamalloverthepage,butthatisjustwhattheJavadevelopersatSunthoughtweshouldputup
withuntilJava1.5cameout.Ouroutputwilllookasfollows,andwewilllivewithitfornow.
Mega Numbers
NO
-02
27
22
32
31
08
19
05
37
15
14
Hits
---13
7
13
7
7
6
5
6
8
10
7
Since
----11
15
16
18
19
22
23
21
27
25
24
Pct_Hits
Ave_Btwn
--------------0.000
10.222
0.000
11.333
0.000
9.946
0.000
11.333
0.000
10.686
0.000
12.931
0.000
11.750
0.000
9.146
0.000
14.346
0.000
11.242
0.000
9.590
PleasenotethatweaddanewLinecharacteratlistingline155.Wearenotprinting tothe
textarea,weareappending.ItisourresponsibilitytoinserttheappropriatenumberofnewLine
charactersattheappropriateplaces.
Let's
nowdiscussthecalltosort()atlistinglines119and188.Ineededtopassinthesecond
andthirdparameterbecauseIchosetouseelements156insteadof055.Thezeroelementwas
neverfilledinandIdidn't
wanttohavestalegarbageinfluencingtheoutcomeofthesort.Ihave
alreadydiscussedthefactthatIimplementedComparablewithourobjectbecausethecompiler
wouldn'tlet me implement a Comparator object when compiling for version 1.4 targets. In
theory,IguessthemakersofJava1.4didyouafavor.Someofyourassignmentswillbemuch
morecutandpastethanIlike.
Listingline215isatrickyoureallyneedtoknow.Theproblemwithtextareasisthatwhen
yougetdonewritingtothem,thedisplayisatthebottomofthem,notthetop.Youneedtoget
backtothetopofthedisplaysotheuserisn'tcompletelylost.Thislittlestatementhandlesthat.It
resetsthecursorpositionbacktooffsetzero.Thisforcestheeventualscreenupdateshowingthe
topofthetextarea.
Whileitisprobably morecode thanyouwanted tolook at,theDue reportisn'tallthat
complex. I've
alreadyshownyouhowtocreatesimilarreportstothescreenusingxBaseJand
DBFfiles.Allyouhadtolearnherewashowtocreateapanelwithatextarea.Onceyouknew
that,youcouldsimplywalkdownthedatabases,sortthedata,andprintthereport.
Chapter2MegaZillionaireApplication
125
MegaXbaseBrowsePanel.java
1)
2)
3)
4)
5)
6)
7)
8)
9)
10)
11)
12)
13)
14)
15)
16)
17)
18)
19)
20)
21)
22)
23)
24)
25)
26)
27)
28)
29)
30)
31)
32)
33)
34)
35)
36)
37)
38)
39)
40)
41)
42)
43)
44)
45)
46)
47)
48)
49)
50)
51)
52)
53)
54)
55)
56)
57)
58)
59)
60)
61)
package com.logikal.megazillxBaseJ;
import
import
import
import
import
import
java.io.*;
java.awt.*;
java.awt.event.*;
javax.swing.*;
java.util.*;
java.text.*;
import
import
import
import
org.xBaseJ.*;
org.xBaseJ.fields.*;
org.xBaseJ.Util.*;
org.xBaseJ.indexes.NDX;
import com.logikal.megazillxBaseJ.MegaDBF;
public class MegaXbaseBrowsePanel extends JPanel
implements ActionListener {
private
private
private
private
private
private
JPanel
JScrollPane
JButton
JTable
DateFormat
DateFormat
final static
mainPanel;
sp;
refreshButton;
drawTable;
file_date_format = new SimpleDateFormat( "yyyyMMdd");
out_date_format = new SimpleDateFormat( "yyyy/MM/dd");
//;;;;;;;;;;
// Constructor
//;;;;;;;;;;
public MegaXbaseBrowsePanel( ) {
mainPanel = new JPanel( new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
// Add our refresh button first
// This way we have an object to find the root panel of
//
JPanel buttonPanel = new JPanel();
refreshButton = new JButton("Refresh");
refreshButton.addActionListener( this);
buttonPanel.add( refreshButton, BorderLayout.NORTH);
gbc.anchor
= GridBagConstraints.NORTH;
gbc.gridwidth
= GridBagConstraints.REMAINDER;
mainPanel.add( buttonPanel, gbc);
Object tData [][] = new Object [1][7];
// dummy table.
mainPanel.add( sp);
add(mainPanel);
setVisible( true);
// end constructor
Chapter2MegaZillionaireApplication
126
62)
63)
64)
65)
66)
67)
68)
69)
70)
71)
72)
73)
74)
75)
76)
77)
78)
79)
80)
81)
82)
83)
84)
85)
86)
87)
88)
89)
90)
Chapter2MegaZillionaireApplication
127
123)
SwingUtilities.getAncestorOfClass( JRootPane.class,
refreshButton);
124)
if ( m != null)
125)
{
126)
JOptionPane.showMessageDialog(m, j.toString(), "Browse",
127)
JOptionPane.ERROR_MESSAGE);
128)
}
129)
else
130)
System.out.println( "m was null");
131)
}
132)
133)
aDB.close_database();
134)
135)
return tableData;
136)
} // end fetchTableData method
137)
138)
139)
140)
public void actionPerformed(ActionEvent event) {
141)
System.out.println( "Entered action event");
142)
mainPanel.setVisible( false);
143)
mainPanel.remove( sp);
144)
145)
//
146)
// Build a new table and scroll panel
147)
//
148)
Object tData [] [] = fetchTableData( );
149)
drawTable = new JTable( tData, columnNames);
150)
sp = new JScrollPane(drawTable);
151)
sp.setPreferredSize( new Dimension( 600, 300));
152)
mainPanel.add( sp);
153)
mainPanel.setVisible(true);
154)
} // end actionPerformed method
155)
156)
157)
public void updateText() {
158)
mainPanel.invalidate();
159)
mainPanel.validate();
160)
mainPanel.paintImmediately( mainPanel.getVisibleRect());
161)
mainPanel.repaint();
162)
}
163) } // end MegaXbaseBrowsePanel class definition
OtherthancreatingandmanipulatingaJTableobject,thecodeforthispanel doesn't
work
muchdifferentlyfromtheDuereportpanel.I'm
notfondoflistinglines50through55,butIhad
tohavethem. Remembermyearlierrantaboutrequiringvaluestoinstantiate? Thisisagreat
exampleofhowthatgetsyouintotrouble.Ihadtocreateauselesstablesothescreenwouldbe
somewhatselfexplanatorywhenauserfirstseesit.
128
Chapter2MegaZillionaireApplication
Figure10EmptyBrowsewindow
IfIdidn't
putanemptytableonthescreenauser's
firstthoughtwouldbeRefresh what?
whentheysawthescreen.Thiswouldn't
besobadifyoucouldcleanlyadddatatoit,butthere
wasn'tacleanwaytoachievethatalongwiththerefreshconcept.
WhydoIneedtherefreshconcept?Thispanelattachestothedatabase,loadsalloftherows,
closesthedatabase,thendisplaysthespreadsheet. Itdoesallofthatwhentheuserclicksthe
refresh button. Ithastowaitfortheusertoclickthatbuttonbecausethevery firsttimethe
applicationisruntherewon't
beadatabase.Eveniftherewasadatabase,Iwouldstillneedthe
refreshbuttonsotheusercanverifythatrecordsheorsheaddsviatheEntrypanelareactuallyin
thedatabasealongwithalloftheotherdata.
Listingline63mightlookabitoddifyouhaven't
donemuchwitharraysinJava. This
privatemethodreturnsanewlyallocatedtwodimensionalarrayofobjects.WhileIcouldhave
hardcodedtheseconddimensionatthemethodlevel,Ioptedtoleaveitatthepointofallocation.
Wehavesevenfields,soweneedsevencolumns,butuntilweobtaintherecordcountfromthe
database,wehavenoideahowmanyrowsareneeded.
Chapter2MegaZillionaireApplication
129
NoticehowIloadedthearray. Atlistingline70IobtainareferencetotheinternalDBF
object.Atlistingline84IusethatDBFobjecttoforceindexpositioningtothebeginning.Inside
ofthewhileloopatlistingline87IusetheDBFobjectagaintocallfindNext().
WhydidIgotoallofthistrouble?BecauseIdidn't
addastartTop()orfindNext()wrapper
methodtotheMegaDBF.javasourcefile,andyoucannotpassanullstringorastringofallspaces
toaDBFfindmethodwhenadateornumerickeyisinvolved. Iwantedthedatatoappearin
sortedorder. Whileitispossibletosortatableafteritisloaded,thatisnotthekindofcodeI
wanttowritewhencompilingagainsta1.4target.Java6addedRowSorterandTableRowSorter
tothelanguagetomakesortingdatainatablemucheasier.Youshouldspendsometimereading
uponthosecapabilities.
Pleaselookatlistinglines122through130.It'snota
lotofcodeandmostexampleprograms
youfindwon'tshow
youhowtodoit.TheresultisthatmostexampleprogramsshowaniceGUI
whichwritesallofitserrorstoaterminalwindowauserissupposedlymonitory.Thislittlecode
snippet pops up a message dialog when an error happens. Depending on the classof error
indicated (error, warning, informational, etc.) a different dialog displays. Under normal
circumstancesyouwillalsogetwhateverhasbeenconfiguredastheassociatedsystemsoundfor
thattypeofmessage.
Listinglines148through153containthecodewhichactuallyperformstherefreshfunction.
WecallfetchTableData()tocreateanewdynamicarrayofObjects.Oncewehavethatwecreate
a new JTable object then wrap it in a shiny new JScrollPane and display it. I tweaked the
preferredsizesothedatecolumnwoulddisplaycompletelywithoutrequiringausertomanually
resizeit.
WeactuallynevercalltheupdateText()method.ThatisjustamethodIcarryaroundfrom
panelclasstopanelclass.
MegaXbaseEntryPanel.java
1)
2)
3)
4)
5)
6)
7)
8)
9)
10)
11)
12)
13)
14)
15)
16)
package com.logikal.megazillxBaseJ;
import
import
import
import
import
java.awt.*;
java.awt.event.*;
javax.swing.*;
java.util.*;
java.text.*;
import
import
import
import
org.xBaseJ.*;
org.xBaseJ.fields.*;
org.xBaseJ.Util.*;
org.xBaseJ.indexes.NDX;
import com.logikal.megazillxBaseJ.MegaDBF;
import com.logikal.megazillxBaseJ.StatElms;
Chapter2MegaZillionaireApplication
130
17)
18)
19)
20)
21)
22)
23)
24)
25)
26)
27)
28)
29)
30)
31)
32)
33)
34)
35)
36)
37)
38)
39)
40)
41)
42)
43)
44)
45)
46)
47)
48)
49)
50)
51)
52)
53)
54)
55)
56)
57)
58)
59)
60)
61)
62)
63)
64)
65)
66)
67)
68)
69)
70)
71)
72)
73)
74)
75)
76)
77)
78)
79)
import com.logikal.megazillxBaseJ.StatDBF;
// You need to import the java.sql package to use JDBC
//
import java.sql.*;
import java.io.*;
private
private
private
private
private
private
private
private
JFormattedTextField drawingDate;
JFormattedTextField no1;
JFormattedTextField no2;
JFormattedTextField no3;
JFormattedTextField no4;
JFormattedTextField no5;
JFormattedTextField megaNo;
JTextField deletedFlg;
private
private
private
private
private
private
private
private
private
private
JButton
JButton
JButton
JButton
JButton
JButton
JButton
JButton
JButton
Connection
okButton;
findButton;
genStatsButton;
deleteButton;
clearButton;
nextButton;
prevButton;
firstButton;
lastButton;
conn;
megaDBF=null;
//
// Fields to hold previous record values from Find
//
private int lNo1, lNo2, lNo3, lNo4, lNo5, lMegaNo;
private java.util.Date dDrawingDate;
private String draw_dt_str;
public MegaXbaseEntryPanel( ) {
//
// This internal class handles verification of numeric
// input for JTextField
//
InputVerifier verifier = new InputVerifier() {
Chapter2MegaZillionaireApplication
80)
81)
82)
83)
84)
85)
86)
87)
88)
89)
90)
91)
92)
93)
94)
95)
96)
97)
98)
99)
100)
101)
102)
103)
104)
105)
106)
107)
108)
109)
110)
111)
112)
113)
114)
115)
116)
117)
118)
119)
120)
121)
122)
123)
};
= GridBagConstraints.NORTH;
= GridBagConstraints.REMAINDER;
//
// Our Date prompt
//
gbc.anchor
= GridBagConstraints.WEST;
gbc.gridwidth
= 1;
JLabel dateLabel
= new JLabel( "Drawing Date:");
controlPanel.add( dateLabel);
drawingDate
= new JFormattedTextField( new DecimalFormat
("########"));
124)
drawingDate.setColumns( 10);
125)
gbc.gridwidth
= GridBagConstraints.REMAINDER;
126)
controlPanel.add( drawingDate, gbc);
127)
128)
//
129)
// Prompts for the drawing numbers
130)
//
131)
gbc.anchor
= GridBagConstraints.WEST;
132)
gbc.gridwidth
= 1;
133)
JLabel no1Label = new JLabel( "No 1:");
134)
controlPanel.add( no1Label, gbc);
135)
gbc.gridwidth
= GridBagConstraints.REMAINDER;
136)
no1 = new JFormattedTextField(new DecimalFormat("##"));
137)
no1.setInputVerifier( verifier);
138)
no1.setColumns(2);
139)
controlPanel.add( no1, gbc);
140)
141)
131
132
142)
143)
144)
145)
146)
147)
148)
149)
150)
151)
152)
153)
154)
155)
156)
157)
158)
159)
160)
161)
162)
163)
164)
165)
166)
167)
168)
169)
170)
171)
172)
173)
174)
175)
176)
177)
178)
179)
180)
181)
182)
183)
184)
185)
186)
187)
188)
189)
190)
191)
192)
193)
194)
195)
196)
197)
198)
199)
200)
201)
202)
203)
204)
Chapter2MegaZillionaireApplication
gbc.anchor
= GridBagConstraints.WEST;
gbc.gridwidth
= 1;
JLabel no2Label = new JLabel( "No 2:");
controlPanel.add( no2Label, gbc);
gbc.gridwidth
= GridBagConstraints.REMAINDER;
no2 = new JFormattedTextField( new DecimalFormat("##"));
no2.setInputVerifier( verifier);
no2.setColumns(2);
controlPanel.add( no2, gbc);
gbc.anchor
= GridBagConstraints.WEST;
gbc.gridwidth
= 1;
JLabel no3Label = new JLabel( "No 3:");
controlPanel.add( no3Label, gbc);
gbc.gridwidth
= GridBagConstraints.REMAINDER;
no3 = new JFormattedTextField( new DecimalFormat("##"));
no3.setInputVerifier( verifier);
no3.setColumns(2);
controlPanel.add( no3, gbc);
gbc.anchor
= GridBagConstraints.WEST;
gbc.gridwidth
= 1;
JLabel no4Label = new JLabel( "No 4:");
controlPanel.add( no4Label, gbc);
gbc.gridwidth
= GridBagConstraints.REMAINDER;
no4 = new JFormattedTextField(new DecimalFormat("##"));
no4.setInputVerifier( verifier);
no4.setColumns(2);
controlPanel.add( no4, gbc);
gbc.anchor
= GridBagConstraints.WEST;
gbc.gridwidth
= 1;
JLabel no5Label = new JLabel( "No 5:");
controlPanel.add( no5Label, gbc);
gbc.gridwidth
= GridBagConstraints.REMAINDER;
no5 = new JFormattedTextField(new DecimalFormat("##"));
no5.setInputVerifier( verifier);
no5.setColumns(2);
controlPanel.add( no5, gbc);
gbc.anchor
= GridBagConstraints.WEST;
gbc.gridwidth
= 1;
JLabel megaNoLabel = new JLabel( "Mega No:");
controlPanel.add( megaNoLabel, gbc);
gbc.gridwidth
= GridBagConstraints.REMAINDER;
megaNo = new JFormattedTextField(new DecimalFormat("##"));
megaNo.setInputVerifier( verifier);
megaNo.setColumns(2);
controlPanel.add( megaNo, gbc);
gbc.anchor
= GridBagConstraints.WEST;
gbc.gridwidth
= 1;
JLabel deletedFlgLabel = new JLabel( "Deleted:");
controlPanel.add( deletedFlgLabel, gbc);
gbc.gridwidth
= GridBagConstraints.REMAINDER;
deletedFlg = new JTextField(1);
deletedFlg.setEditable(false);
controlPanel.add( deletedFlg, gbc);
Chapter2MegaZillionaireApplication
205)
206)
207)
208)
209)
210)
211)
212)
213)
214)
215)
216)
217)
218)
219)
220)
221)
222)
223)
224)
225)
226)
227)
228)
229)
230)
231)
232)
233)
234)
235)
236)
237)
238)
239)
240)
241)
242)
243)
244)
245)
246)
247)
248)
249)
250)
251)
252)
253)
254)
255)
256)
257)
258)
259)
260)
261)
262)
263)
264)
265)
266)
267)
//
// The Clear Button
//
gbc.anchor
= GridBagConstraints.SOUTHWEST;
gbc.gridwidth
= 1;
clearButton = new JButton("Clear");
clearButton.addActionListener( this);
controlPanel.add( clearButton, gbc);
//
// The Find Button
//
gbc.anchor
= GridBagConstraints.SOUTHWEST;
gbc.gridwidth
= 1;
findButton = new JButton("Find");
findButton.addActionListener( this);
controlPanel.add( findButton, gbc);
//
// The Delete Button
//
gbc.anchor
= GridBagConstraints.SOUTHWEST;
gbc.gridwidth
= 1;
deleteButton = new JButton("Delete");
deleteButton.addActionListener( this);
controlPanel.add( deleteButton, gbc);
//
// The Gen Stats Button
//
gbc.anchor
= GridBagConstraints.SOUTH;
gbc.gridwidth
= 1;
genStatsButton = new JButton("Gen Stats");
genStatsButton.addActionListener( this);
controlPanel.add( genStatsButton, gbc);
//
//
The OK Button
//
gbc.anchor
= GridBagConstraints.SOUTHEAST;
gbc.gridwidth
= GridBagConstraints.REMAINDER;
okButton = new JButton("OK");
okButton.addActionListener( this);
controlPanel.add( okButton, gbc);
//
// The First Button
//
gbc.anchor
= GridBagConstraints.LINE_START;
gbc.gridwidth
= 1;
gbc.weightx
= 1.0;
firstButton = new JButton("<<<");
firstButton.addActionListener( this);
controlPanel.add( firstButton, gbc);
//
// The Prev Button
//
gbc.anchor
= GridBagConstraints.SOUTH;
gbc.gridwidth
= 1;
gbc.weightx
= 0.0;
prevButton = new JButton(" < ");
133
Chapter2MegaZillionaireApplication
134
268)
269)
270)
271)
272)
273)
274)
275)
276)
277)
278)
279)
280)
281)
282)
283)
284)
285)
286)
287)
288)
289)
290)
291)
292)
293)
294)
295)
296)
297)
298)
299)
300)
301)
302)
303)
304)
305)
306)
307)
308)
309)
310)
311)
312)
313)
314)
315)
316)
317)
318)
319)
320)
321)
322)
323)
324)
325)
326)
327)
328)
329)
330)
prevButton.addActionListener( this);
controlPanel.add( prevButton, gbc);
//
// The next Button
//
gbc.anchor
= GridBagConstraints.SOUTH;
gbc.gridwidth
= GridBagConstraints.RELATIVE;
nextButton = new JButton(" > ");
nextButton.addActionListener( this);
controlPanel.add( nextButton, gbc);
//
// The Last Button
//
gbc.anchor
= GridBagConstraints.SOUTHEAST;
gbc.gridwidth
= GridBagConstraints.REMAINDER;
gbc.weightx
= 1.0;
lastButton = new JButton(">>>");
lastButton.addActionListener( this);
controlPanel.add( lastButton, gbc);
// Show the world
//
add( controlPanel);
drawingDate.requestFocus();
setVisible( true);
//
Default mode is entry
//
currMode = ENTRY_MODE;
megaDBF = new MegaDBF();
}
// end constructor
//;;;;;
// Method to handle button actions.
// Java has a real failing here. This code would be so much
// cleaner if a switch could be used on an object or string
//;;;;;
public void actionPerformed(ActionEvent e) {
if ( e.getSource() == okButton) {
if ( currMode == ENTRY_MODE) {
if (addRecord() == false)
display_error_msg( "Add Error");
} else {
if (updateRecord() == false)
display_error_msg( "Update Error");
}
return;
} // end test for okButton
if ( e.getSource() == deleteButton) {
if ( currMode != FIND_MODE) {
display_error_msg( "Must find before deleting");
} else {
if ( deleteRecord() != true)
display_error_msg( "Delete Error");
Chapter2MegaZillionaireApplication
331)
332)
333)
334)
335)
336)
337)
338)
339)
340)
341)
342)
343)
344)
345)
346)
347)
348)
349)
350)
351)
352)
353)
354)
355)
356)
357)
358)
359)
360)
361)
362)
363)
364)
365)
366)
367)
368)
369)
370)
371)
372)
373)
374)
375)
376)
377)
378)
379)
380)
381)
382)
383)
384)
385)
386)
387)
388)
389)
390)
391)
392)
393)
}
return;
// end test for deleteButton
if ( e.getSource() == findButton) {
currMode = FIND_MODE;
if ( findRecord() == false)
display_error_msg( "Drawing Not Found");
return;
} // end test for findButton
if ( e.getSource() == genStatsButton) {
createStatsTable();
return;
} // end test for clear button
if ( e.getSource() == clearButton) {
currMode = ENTRY_MODE;
draw_dt_str = " ";
lNo1 = lNo2 = lNo3 = lNo4 = lNo5 = lMegaNo = 0;
no1.setValue( null);
no2.setValue( null);
no3.setValue( null);
no4.setValue( null);
no5.setValue( null);
megaNo.setValue( null);
deletedFlg.setText("");
drawingDate.setValue( null);
} // end test for clear button
if ( e.getSource() == firstButton) {
currMode = FIND_MODE;
if ( firstRecord() == false)
display_error_msg( "Drawing Not Found");
return;
} // end test for firstButton
if ( e.getSource() == prevButton) {
if ( prevRecord() == false)
display_error_msg( "Drawing Not Found");
return;
} // end test for prevButton
if ( e.getSource() == nextButton) {
if ( nextRecord() == false)
display_error_msg( "Drawing Not Found");
return;
} // end test for nextButton
if ( e.getSource() == lastButton) {
currMode = FIND_MODE;
if ( lastRecord() == false)
display_error_msg( "Drawing Not Found");
return;
} // end test for lastButton
}
/*;;;;;
* method to add a record to the database
*;;;;;
*/
135
Chapter2MegaZillionaireApplication
136
394)
395)
396)
397)
398)
399)
400)
401)
402)
403)
404)
405)
406)
407)
408)
409)
410)
411)
412)
413)
414)
415)
416)
417)
418)
419)
420)
421)
422)
423)
424)
425)
426)
427)
428)
429)
430)
431)
432)
433)
434)
435)
436)
437)
438)
439)
440)
441)
442)
443)
444)
445)
446)
447)
448)
449)
450)
451)
452)
453)
454)
455)
456)
return retVal;
// end addRecord method
/*;;;;;
Chapter2MegaZillionaireApplication
457)
458)
459)
460)
461)
462)
463)
464)
465)
466)
467)
468)
469)
470)
471)
472)
473)
474)
475)
476)
477)
478)
479)
480)
481)
482)
483)
484)
485)
486)
487)
488)
489)
490)
491)
492)
493)
494)
495)
496)
497)
498)
499)
500)
501)
502)
503)
504)
505)
506)
507)
508)
509)
510)
511)
512)
513)
514)
515)
516)
517)
518)
519)
137
Chapter2MegaZillionaireApplication
138
520)
521)
522)
523)
524)
525)
526)
527)
528)
529)
530)
531)
532)
533)
534)
535)
536)
537)
538)
539)
540)
541)
542)
543)
544)
545)
546)
547)
548)
549)
550)
551)
552)
553)
554)
555)
556)
557)
558)
559)
560)
561)
562)
563)
564)
565)
566)
567)
568)
569)
570)
571)
572)
573)
574)
575)
576)
577)
578)
579)
580)
581)
582)
} catch( IOException i) {
display_error_msg( "Error adding record " + i.toString());
}
return retVal;
// end updateRecord method
/*;;;;;
* method to delete a record which has been found
*;;;;;
*/
private boolean deleteRecord() {
boolean retVal = false;
int
l_x;
String del_str;
String localDateStr=null;
draw_dt_str = drawingDate.getText();
//pad_draw_dt_str();
try {
localDateStr = out_format.format( out_format.parse(draw_dt_str));
}
catch( ParseException p) {
display_error_msg( "Error parsing date " + p.toString());
}
if (localDateStr == null)
return false;
try {
megaDBF.open_database();
megaDBF.find_EQ_record( localDateStr);
megaDBF.getDBF().delete();
megaDBF.close_database();
retVal = true;
currMode = ENTRY_MODE;
draw_dt_str = " ";
lNo1 = lNo2 = lNo3 = lNo4 = lNo5 = lMegaNo = 0;
no1.setValue( null);
no2.setValue( null);
no3.setValue( null);
no4.setValue( null);
no5.setValue( null);
megaNo.setValue( null);
drawingDate.setValue( null);
deletedFlg.setText(" ");
} catch( xBaseJException s) {
display_error_msg( "Error deleting record " + s.toString());
} catch( IOException i) {
display_error_msg( "Error adding record " + i.toString());
}
}
return retVal;
// end deleteRecord method
/*;;;;;
* method to find a record based upon drawing date
*;;;;;
*/
private boolean findRecord() {
Chapter2MegaZillionaireApplication
583)
584)
585)
586)
587)
588)
589)
590)
591)
592)
593)
594)
595)
596)
597)
598)
599)
600)
601)
602)
603)
604)
605)
606)
607)
608)
609)
610)
611)
612)
613)
614)
615)
616)
617)
618)
619)
620)
621)
622)
623)
139
int
l_x=0;
boolean retVal=false;
String find_str;
String localDateStr=null;
draw_dt_str = drawingDate.getText();
pad_draw_dt_str();
try {
localDateStr = out_format.format( out_format.parse(draw_dt_str));
}
catch( ParseException p) {
display_error_msg( "Error parsing date " + p.toString());
localDateStr = null;
}
if (localDateStr == null)
return false;
try {
megaDBF.open_database();
l_x = megaDBF.find_GE_record( localDateStr);
());
dDrawingDate
lNo1
lNo2
lNo3
lNo4
lNo5
lMegaNo
=
=
=
=
=
=
=
out_format.parse(
Integer.parseInt(
Integer.parseInt(
Integer.parseInt(
Integer.parseInt(
Integer.parseInt(
Integer.parseInt(
megaDBF.Draw_Dt.get());
megaDBF.No_1.get().trim());
megaDBF.No_2.get().trim());
megaDBF.No_3.get().trim());
megaDBF.No_4.get().trim());
megaDBF.No_5.get().trim());
megaDBF.Mega_No.get().trim
if (megaDBF.getDBF().deleted())
deletedFlg.setText("*");
else
deletedFlg.setText(" ");
megaDBF.close_database();
Chapter2MegaZillionaireApplication
140
644)
645)
646)
647)
648)
649)
650)
651)
652)
653)
654)
655)
656)
657)
658)
659)
660)
661)
662)
663)
664)
665)
666)
667)
668)
669)
670)
671)
672)
673)
674)
675)
676)
677)
678)
679)
680)
681)
682)
683)
684)
685)
686)
687)
688)
689)
690)
691)
692)
693)
694)
695)
696)
697)
698)
699)
700)
701)
702)
703)
704)
705)
706)
drawingDate.setValue( null);
} catch( NumberFormatException n) {
display_error_msg( "Error parsing date " + draw_dt_str +
"Error was " + n.toString());
draw_dt_str = " ";
lNo1 = lNo2 = lNo3 = lNo4 = lNo5 = lMegaNo = 0;
no1.setValue( null);
no2.setValue( null);
no3.setValue( null);
no4.setValue( null);
no5.setValue( null);
megaNo.setValue( null);
deletedFlg.setText(" ");
drawingDate.setValue( null);
}
return retVal;
// end findRecord method
//;;;;;
// Internal method to pad the display of numbers to 2 digits
//;;;;;
private void pad_draw_dt_str() {
draw_dt_str = draw_dt_str.trim();
switch( draw_dt_str.length()) {
case 4:
// only year provided
draw_dt_str += "0101";
break;
case 6:
// year and month
draw_dt_str += "01";
break;
case 8:
// full date, no padding
break;
default:
// no idea, pick a default
draw_dt_str = "19900101";
break;
} // end switch of length
}
/*;;;;;
* Begin logic to rebuild the Stats tables
*;;;;;
*/
public void createStatsTable()
{
int
l_x;
int
l_record_count;
l_draw_no = 0;
//
// It will seem odd to you, but you have to do 2
// allocations when working with a non native array.
//
//
drawNoStat = new StatElms[ ELM_COUNT];
for (l_x=1; l_x < ELM_COUNT; l_x++ ) {
drawNoStat[ l_x]
= new StatElms();
drawNoStat[ l_x].elmNo
= l_x;
} // end for loop to init stats
Chapter2MegaZillionaireApplication
707)
708)
709)
710)
711)
712)
713)
714)
715)
716)
717)
718)
719)
720)
721)
722)
723)
724)
725)
726)
727)
728)
729)
730)
731)
732)
733)
734)
735)
736)
737)
738)
739)
740)
741)
742)
743)
744)
745)
746)
747)
748)
749)
750)
751)
752)
753)
754)
755)
756)
757)
758)
759)
760)
761)
762)
763)
141
()));
()));
()));
()));
()));
().trim()));
if (l_draw_no % 100 == 0)
System.out.println( "Processed " + l_x + " Records");
// end for l_y loop
megaDBF.close_database();
} catch( xBaseJException s) {
display_error_msg( "Error reading DBF " + s.toString());
} catch( IOException i) {
display_error_msg( "Error reading DBF " + i.toString());
} catch( NumberFormatException n) {
display_error_msg( "Error parsing integer " + n.toString());
}
System.out.println( "Processed " + l_draw_no + " Records");
writeDrawStats( );
}
//;;;;;;;;;;
// Method to actually write all of our Stats records to the database.
//;;;;;;;;;;
private void writeDrawStats( ) {
int l_x, l_missed, l_y;
StatDBF drawStatDBF=null;
StatDBF megaStatDBF=null;
drawStatDBF = new StatDBF();
megaStatDBF = new StatDBF();
drawStatDBF.create_database( "drawst");
megaStatDBF.create_database( "megast");
Chapter2MegaZillionaireApplication
142
764)
765)
766)
767)
768)
769)
770)
771)
772)
773)
774)
775)
776)
777)
778)
779)
780)
781)
782)
783)
784)
785)
786)
787)
788)
789)
790)
791)
792)
793)
794)
795)
796)
797)
798)
799)
800)
801)
802)
803)
804)
805)
806)
807)
808)
809)
810)
811)
812)
813)
814)
815)
816)
817)
818)
819)
820)
821)
822)
823)
824)
} catch( xBaseJException s) {
display_error_msg( "Error adding Mega stat record " +
s.toString());
} catch( IOException i) {
display_error_msg( "Error reading DBF " + i.toString());
}
// end for l_x loop
Chapter2MegaZillionaireApplication
825)
826)
827)
828)
829)
143
}
// end for l_x loop
Chapter2MegaZillionaireApplication
144
881)
882)
883)
884)
885)
886)
887)
888)
889)
890)
891)
892)
893)
894)
895)
896)
897)
898)
899)
900)
901)
902)
903)
904)
905)
906)
907)
908)
909)
910)
911)
912)
913)
914)
915)
916)
917)
918)
919)
920)
921)
922)
923)
924)
925)
926)
927)
928)
929)
930)
931)
932)
933)
934)
935)
936)
937)
938)
939)
940)
941)
942)
943)
megaNoStat[ num_sub].hitCount++;
megaNoStat[ num_sub].lastDrawNo = l_draw_no;
megaNoStat[ num_sub].sinceLast = l_x;
// end updateMegaStats method
return true;
// end is_record_valid method
Chapter2MegaZillionaireApplication
944)
945)
946)
947)
948)
949)
950)
951)
952)
953)
954)
955)
956)
957)
958)
959)
960)
961)
962)
963)
964)
965)
966)
967)
968)
969)
970)
971)
972)
973)
974)
975)
976)
977)
978)
145
/*;;;;;
* method to find first record
*;;;;;
*/
private boolean firstRecord() {
int
l_x=0;
boolean retVal=false;
String find_str;
String localDateStr=null;
try {
megaDBF.open_database();
megaDBF.getDBF().startTop();
megaDBF.getDBF().findNext();
());
dDrawingDate
lNo1
lNo2
lNo3
lNo4
lNo5
lMegaNo
=
=
=
=
=
=
=
out_format.parse(
Integer.parseInt(
Integer.parseInt(
Integer.parseInt(
Integer.parseInt(
Integer.parseInt(
Integer.parseInt(
megaDBF.Draw_Dt.get());
megaDBF.No_1.get().trim());
megaDBF.No_2.get().trim());
megaDBF.No_3.get().trim());
megaDBF.No_4.get().trim());
megaDBF.No_5.get().trim());
megaDBF.Mega_No.get().trim
if (megaDBF.getDBF().deleted())
deletedFlg.setText("*");
else
deletedFlg.setText(" ");
megaDBF.close_database();
146
Chapter2MegaZillionaireApplication
1005)
no1.setValue( null);
1006)
no2.setValue( null);
1007)
no3.setValue( null);
1008)
no4.setValue( null);
1009)
no5.setValue( null);
1010)
megaNo.setValue( null);
1011)
deletedFlg.setText(" ");
1012)
drawingDate.setValue( null);
1013)
} catch( ParseException p) {
1014)
display_error_msg( "Error parsing date " + draw_dt_str +
1015)
"Error was " + p.toString());
1016)
draw_dt_str = " ";
1017)
lNo1 = lNo2 = lNo3 = lNo4 = lNo5 = lMegaNo = 0;
1018)
no1.setValue( null);
1019)
no2.setValue( null);
1020)
no3.setValue( null);
1021)
no4.setValue( null);
1022)
no5.setValue( null);
1023)
megaNo.setValue( null);
1024)
deletedFlg.setText(" ");
1025)
drawingDate.setValue( null);
1026)
} catch( NumberFormatException n) {
1027)
display_error_msg( "Error parsing date " + draw_dt_str +
1028)
"Error was " + n.toString());
1029)
draw_dt_str = " ";
1030)
lNo1 = lNo2 = lNo3 = lNo4 = lNo5 = lMegaNo = 0;
1031)
no1.setValue( null);
1032)
no2.setValue( null);
1033)
no3.setValue( null);
1034)
no4.setValue( null);
1035)
no5.setValue( null);
1036)
megaNo.setValue( null);
1037)
deletedFlg.setText(" ");
1038)
drawingDate.setValue( null);
1039)
}
1040)
1041)
return retVal;
1042)
} // end firstRecord method
1043)
1044)
/*;;;;;
1045)
* method to find previous record based upon drawing date
1046)
*;;;;;
1047)
*/
1048)
private boolean prevRecord() {
1049)
int
l_x=0;
1050)
boolean retVal=false;
1051)
String find_str;
1052)
String localDateStr=null;
1053)
1054)
if (currMode != FIND_MODE) {
1055)
display_error_msg( "Must have previously found to move back one
record");
1056)
return false;
1057)
}
1058)
1059)
draw_dt_str = drawingDate.getText();
1060)
pad_draw_dt_str();
1061)
1062)
try {
1063)
localDateStr = out_format.format( out_format.parse
(draw_dt_str));
1064)
}
1065)
catch( ParseException p) {
Chapter2MegaZillionaireApplication
147
1066)
display_error_msg( "Error parsing date " + p.toString());
1067)
localDateStr = null;
1068)
}
1069)
1070)
if (localDateStr == null)
1071)
return false;
1072)
1073)
try {
1074)
megaDBF.open_database();
1075)
megaDBF.find_EQ_record( draw_dt_str);
1076)
megaDBF.getDBF().findPrev();
1077)
1078)
dDrawingDate
= out_format.parse( megaDBF.Draw_Dt.get());
1079)
lNo1
= Integer.parseInt( megaDBF.No_1.get().trim());
1080)
lNo2
= Integer.parseInt( megaDBF.No_2.get().trim());
1081)
lNo3
= Integer.parseInt( megaDBF.No_3.get().trim());
1082)
lNo4
= Integer.parseInt( megaDBF.No_4.get().trim());
1083)
lNo5
= Integer.parseInt( megaDBF.No_5.get().trim());
1084)
lMegaNo
= Integer.parseInt( megaDBF.Mega_No.get().trim
());
1085)
1086)
if (megaDBF.getDBF().deleted())
1087)
deletedFlg.setText( "*");
1088)
else
1089)
deletedFlg.setText(" ");
1090)
1091)
megaDBF.close_database();
1092)
1093)
// Update the screen
1094)
//
1095)
drawingDate.setValue( new Integer(out_format.format
(dDrawingDate)));
1096)
draw_dt_str = out_format.format( dDrawingDate);
1097)
no1.setValue( new Integer(lNo1));
1098)
no2.setValue( new Integer(lNo2));
1099)
no3.setValue( new Integer(lNo3));
1100)
no4.setValue( new Integer(lNo4));
1101)
no5.setValue( new Integer(lNo5));
1102)
megaNo.setValue( new Integer(lMegaNo));
1103)
retVal = true;
1104)
} catch( xBaseJException s) {
1105)
display_error_msg( "Unable to find " + localDateStr +
1106)
"Error was " + s.toString());
1107)
draw_dt_str = " ";
1108)
lNo1 = lNo2 = lNo3 = lNo4 = lNo5 = lMegaNo = 0;
1109)
no1.setValue( null);
1110)
no2.setValue( null);
1111)
no3.setValue( null);
1112)
no4.setValue( null);
1113)
no5.setValue( null);
1114)
megaNo.setValue( null);
1115)
drawingDate.setValue( null);
1116)
deletedFlg.setText(" ");
1117)
} catch( IOException i) {
1118)
display_error_msg( "Unable to find " + localDateStr +
1119)
"Error was " + i.toString());
1120)
draw_dt_str = " ";
1121)
lNo1 = lNo2 = lNo3 = lNo4 = lNo5 = lMegaNo = 0;
1122)
no1.setValue( null);
1123)
no2.setValue( null);
1124)
no3.setValue( null);
1125)
no4.setValue( null);
1126)
no5.setValue( null);
148
Chapter2MegaZillionaireApplication
1127)
megaNo.setValue( null);
1128)
drawingDate.setValue( null);
1129)
deletedFlg.setText(" ");
1130)
} catch( ParseException p) {
1131)
display_error_msg( "Error parsing date " + draw_dt_str +
1132)
"Error was " + p.toString());
1133)
draw_dt_str = " ";
1134)
lNo1 = lNo2 = lNo3 = lNo4 = lNo5 = lMegaNo = 0;
1135)
no1.setValue( null);
1136)
no2.setValue( null);
1137)
no3.setValue( null);
1138)
no4.setValue( null);
1139)
no5.setValue( null);
1140)
megaNo.setValue( null);
1141)
drawingDate.setValue( null);
1142)
deletedFlg.setText(" ");
1143)
} catch( NumberFormatException n) {
1144)
display_error_msg( "Error parsing date " + draw_dt_str +
1145)
"Error was " + n.toString());
1146)
draw_dt_str = " ";
1147)
lNo1 = lNo2 = lNo3 = lNo4 = lNo5 = lMegaNo = 0;
1148)
no1.setValue( null);
1149)
no2.setValue( null);
1150)
no3.setValue( null);
1151)
no4.setValue( null);
1152)
no5.setValue( null);
1153)
megaNo.setValue( null);
1154)
drawingDate.setValue( null);
1155)
deletedFlg.setText(" ");
1156)
}
1157)
1158)
return retVal;
1159)
} // end prevRecord method
1160)
1161)
/*;;;;;
1162)
* method to find a next record based upon drawing date
1163)
*;;;;;
1164)
*/
1165)
private boolean nextRecord() {
1166)
int
l_x=0;
1167)
boolean retVal=false;
1168)
String find_str;
1169)
String localDateStr=null;
1170)
1171)
draw_dt_str = drawingDate.getText();
1172)
pad_draw_dt_str();
1173)
1174)
try {
1175)
localDateStr = out_format.format( out_format.parse
(draw_dt_str));
1176)
}
1177)
catch( ParseException p) {
1178)
display_error_msg( "Error parsing date " + p.toString());
1179)
localDateStr = null;
1180)
}
1181)
1182)
if (localDateStr == null)
1183)
return false;
1184)
1185)
try {
1186)
megaDBF.open_database();
1187)
megaDBF.find_GE_record( localDateStr.trim());
1188)
megaDBF.getDBF().findNext();
Chapter2MegaZillionaireApplication
149
1189)
1190)
dDrawingDate
= out_format.parse( megaDBF.Draw_Dt.get());
1191)
lNo1
= Integer.parseInt( megaDBF.No_1.get().trim());
1192)
lNo2
= Integer.parseInt( megaDBF.No_2.get().trim());
1193)
lNo3
= Integer.parseInt( megaDBF.No_3.get().trim());
1194)
lNo4
= Integer.parseInt( megaDBF.No_4.get().trim());
1195)
lNo5
= Integer.parseInt( megaDBF.No_5.get().trim());
1196)
lMegaNo
= Integer.parseInt( megaDBF.Mega_No.get().trim
());
1197)
if (megaDBF.getDBF().deleted())
1198)
deletedFlg.setText("*");
1199)
else
1200)
deletedFlg.setText(" ");
1201)
1202)
megaDBF.close_database();
1203)
1204)
// Update the screen
1205)
//
1206)
drawingDate.setValue( new Integer(out_format.format
(dDrawingDate)));
1207)
draw_dt_str = out_format.format( dDrawingDate);
1208)
no1.setValue( new Integer(lNo1));
1209)
no2.setValue( new Integer(lNo2));
1210)
no3.setValue( new Integer(lNo3));
1211)
no4.setValue( new Integer(lNo4));
1212)
no5.setValue( new Integer(lNo5));
1213)
megaNo.setValue( new Integer(lMegaNo));
1214)
retVal = true;
1215)
} catch( xBaseJException s) {
1216)
display_error_msg( "Unable to find " + localDateStr +
1217)
"Error was " + s.toString());
1218)
draw_dt_str = " ";
1219)
lNo1 = lNo2 = lNo3 = lNo4 = lNo5 = lMegaNo = 0;
1220)
no1.setValue( null);
1221)
no2.setValue( null);
1222)
no3.setValue( null);
1223)
no4.setValue( null);
1224)
no5.setValue( null);
1225)
megaNo.setValue( null);
1226)
drawingDate.setValue( null);
1227)
} catch( IOException i) {
1228)
display_error_msg( "Unable to find " + localDateStr +
1229)
"Error was " + i.toString());
1230)
draw_dt_str = " ";
1231)
lNo1 = lNo2 = lNo3 = lNo4 = lNo5 = lMegaNo = 0;
1232)
no1.setValue( null);
1233)
no2.setValue( null);
1234)
no3.setValue( null);
1235)
no4.setValue( null);
1236)
no5.setValue( null);
1237)
megaNo.setValue( null);
1238)
drawingDate.setValue( null);
1239)
} catch( ParseException p) {
1240)
display_error_msg( "Error parsing date " + draw_dt_str +
1241)
"Error was " + p.toString());
1242)
draw_dt_str = " ";
1243)
lNo1 = lNo2 = lNo3 = lNo4 = lNo5 = lMegaNo = 0;
1244)
no1.setValue( null);
1245)
no2.setValue( null);
1246)
no3.setValue( null);
1247)
no4.setValue( null);
1248)
no5.setValue( null);
1249)
megaNo.setValue( null);
150
Chapter2MegaZillionaireApplication
1250)
drawingDate.setValue( null);
1251)
}
1252)
1253)
return retVal;
1254)
} // end nextRecord method
1255)
1256)
/*;;;;;
1257)
* method to find last record based upon drawing date
1258)
*;;;;;
1259)
*/
1260)
private boolean lastRecord() {
1261)
int
l_x=0;
1262)
boolean retVal=false;
1263)
String find_str;
1264)
String localDateStr=null;
1265)
1266)
try {
1267)
megaDBF.open_database();
1268)
megaDBF.getDBF().startBottom();
1269)
megaDBF.getDBF().findPrev();
1270)
1271)
dDrawingDate
= out_format.parse( megaDBF.Draw_Dt.get());
1272)
lNo1
= Integer.parseInt( megaDBF.No_1.get().trim());
1273)
lNo2
= Integer.parseInt( megaDBF.No_2.get().trim());
1274)
lNo3
= Integer.parseInt( megaDBF.No_3.get().trim());
1275)
lNo4
= Integer.parseInt( megaDBF.No_4.get().trim());
1276)
lNo5
= Integer.parseInt( megaDBF.No_5.get().trim());
1277)
lMegaNo
= Integer.parseInt( megaDBF.Mega_No.get().trim
());
1278)
1279)
if (megaDBF.getDBF().deleted())
1280)
deletedFlg.setText("*");
1281)
else
1282)
deletedFlg.setText(" ");
1283)
1284)
megaDBF.close_database();
1285)
1286)
// Update the screen
1287)
//
1288)
drawingDate.setValue( new Integer(out_format.format
(dDrawingDate)));
1289)
draw_dt_str = out_format.format( dDrawingDate);
1290)
no1.setValue( new Integer(lNo1));
1291)
no2.setValue( new Integer(lNo2));
1292)
no3.setValue( new Integer(lNo3));
1293)
no4.setValue( new Integer(lNo4));
1294)
no5.setValue( new Integer(lNo5));
1295)
megaNo.setValue( new Integer(lMegaNo));
1296)
retVal = true;
1297)
} catch( xBaseJException s) {
1298)
display_error_msg( "Unable to find " + localDateStr +
1299)
"Error was " + s.toString());
1300)
draw_dt_str = " ";
1301)
lNo1 = lNo2 = lNo3 = lNo4 = lNo5 = lMegaNo = 0;
1302)
no1.setValue( null);
1303)
no2.setValue( null);
1304)
no3.setValue( null);
1305)
no4.setValue( null);
1306)
no5.setValue( null);
1307)
megaNo.setValue( null);
1308)
drawingDate.setValue( null);
1309)
} catch( IOException i) {
1310)
display_error_msg( "Unable to find " + localDateStr +
Chapter2MegaZillionaireApplication
1311)
1312)
1313)
1314)
1315)
1316)
1317)
1318)
1319)
1320)
1321)
1322)
1323)
1324)
1325)
1326)
1327)
1328)
1329)
1330)
1331)
1332)
1333)
1334)
1335)
1336)
1337)
1338)
1339) }
151
return retVal;
// end findRecord method
I'm
sorry.ThelistingforMegaXbaseEntryPanelisjustlong.Itwouldhavebeenevenlonger
ifIhadcontinuedaddingsomeotherneatfeatures.
Weneedtostartourdiscussionatlistinglines79through102.Ihavenowayofknowing
whatlevelyourJavaskillsare,soletmepointouttheinternalclasscontraptionweusetoverify
drawingnumberinputiswithinavalidrange.Everythingbetweenthefirst{andtheending}
becomes the body of the abstract class. We must provide a Boolean verify() method and a
Boolean shouldYieldFocus() method. The actual editing/validating happens in the verify()
method.HereweconverttheJComponentobjecttoatypeweknowittobe.(Yes,Icouldhave
madethisevenmorerobustbycheckingwithinstanceof.)Wepassbackeithertrueorfalseto
indicatethequalityofthedata.
YouwillfinddocumentationonlinewhichclaimstheshouldYieldFocus()methodisoptional.
Iwouldn't
buythatstatementeveniftheypaidmetotakeit,mainlybecauseyearsagoItriedto
leaveitout.Wearen't
farenoughintothesourcecodeyet,butitshouldn't
takemuchforyouto
believethatIliketotossuperrormessagedialogswhensomethingfailedvalidation.Afterthe
firsterrortriestothrowadialogupyoufindyourselfinadeadlyembracewithmultiplethings
absolutelydemandingtheybeallowedtohavefocusatthesametime.It's
notaprettypicture.
Dependingonhowyoulaunchedyourapplicationyoucouldevenbeforcedtoreboot.Youdon't
directlycallshouldYieldFocus(),theunderlyingSwingAPIdoes.
152
Chapter2MegaZillionaireApplication
Chapter2MegaZillionaireApplication
153
Thesectionofcodeatlistinglines493through504containsaseriousmultiuserproblem.I
dutifullyfoundtherecordtoupdate,movedinthevalues,andwroteitbacktothefile.WhatI
didn'tdowaschecktosee
whetheranyotheruserorprocesshadchangedthevaluesofthatrecord
betweenthetimetheentryscreenloadeditandtheuserchosetosaveit.
Wedon't
haveanythinginterestingtotalkaboutuntilwegetdowntolistinglines762and
763.Thisisthefirst,andonly,timeIusetheStatDBFclasswecreated.NoticehowIpasseda
short name without extensionto thecreate_database() method. Ido not know ifthe xBaseJ
libraryhasafilenamelengthlimitation,butitwas8.3atonepointduringthedaysofDOS.Since
Iwillbeaddingk 0 totheendofthenametocreatetheNDXfiles,Ioptedtopassonly6
charactersin. IalsoallowJavagarbage collectiontocloseoffthesefilessometimeafterthe
objectsgooutofscope.
Listing line 832 contains another version of that message dialog. This time we pass
PLAIN_MESSAGE as the option so Swing displays a runofthemill status message dialog
insteadofanerrormessage.
Listinglines969through972containanifstatementwhichisreplicatedinafewplaces.Here
wecallthedeleted()methodprovidedbytheDBFclasstodetermineifwedisplayaspaceoran
*intheDeletedfieldonthescreen.
Noticethateachfind methodinthisclassstoresthevaluesfoundinclassglobalfields.You
needtopayattention tothatdesignfeatureifyouintendtocompleteoneoftheassignments
comingupattheendofthechapter.
Listinglines978and979mayrequireatinybitofexplanation.Theobjectwhichallowsfor
dateentryonourpanelisasimpleJformattedTextField.Ichosenottoplaygamestryingtomake
thisdisplaywithaprettyformat.It's
notthatIdon't
likeprettydateformats,it's
justthatIdidn't
wanttoinstallandincludetheapachelibrariestogettheirJdateFieldobjectandIdidn't
wantto
complicatetheentrysequencebycreatingaJDateChooserobject.Theendresultisthatwehave
toconvertthedatefromthedatabasefromstringtoadateobjectJavalikes,thenformatittoa
newstringtoconverttoanIntegerobject.Theconversionfromstringintoadatedatatypehelps
validatethecolumnonthedatabase.Wecouldchoosetotrustit,butwhybotherwhenitdoesn't
costthatmanycyclestobesure?
Thereyouhaveit:ThebiggestsourcefileI'v
eshownyousofarinthisbook.Perhapsyou
noticed we talked more about the Java aspects of this module than the xBaseJ aspects. You
alreadyhavemostofthefundamentalsdown.Thepurposeofthischapteristogiveyouideason
howtoboltthemtogethercorrectly,atleastfromadesignstandpoint.
Chapter2MegaZillionaireApplication
154
2.4 TheImportDialog
Theimportdialogisgoingtoseemreallylameafterthemainportionofthisapplication.I
chosetomaketheimportmoduleadialogbefore Istartedwritingtherestoftheapplication.
Therewasactuallyamethodtothemadness.IftheImportfunctionwassimplyanotherpanel,it
wouldbepossibleforausertochooseafilename,thenleavethescreenbyselectinganother
menuoption.Heorshewouldnothaveactuallyperformedtheimport,butmightbelieveitwas
complete.Makingthisadialogstoppedthatfromhappening.
MegaXImport.java
1)
2)
3)
4)
5)
6)
7)
8)
9)
10)
11)
12)
13)
14)
15)
16)
17)
18)
19)
20)
21)
22)
23)
24)
25)
26)
27)
28)
29)
30)
31)
32)
33)
34)
35)
36)
37)
38)
39)
40)
41)
42)
43)
44)
45)
46)
47)
package com.logikal.megazillxBaseJ;
import
import
import
import
import
import
import
java.awt.*;
java.awt.event.*;
javax.swing.*;
javax.swing.filechooser.*;
java.text.*;
java.util.*;
java.io.*;
import
import
import
import
org.xBaseJ.*;
org.xBaseJ.fields.*;
org.xBaseJ.Util.*;
org.xBaseJ.indexes.NDX;
import com.logikal.megazillxBaseJ.MegaDBF;
public class MegaXImport extends JDialog implements ActionListener{
// Variables
public JButton
importData=null;
public JButton
exitButton=null;
public JButton
chooseFile=null;
private JTextField
csvNameField=null;
private JPanel
line1Panel=null;
private JPanel
line2Panel=null;
private MegaDBF
MegaDB = null;
private String
CsvName=null;
private JTextArea
importRptArea;
private JScrollPane
sp;
private JFileChooser
fc;
// constructor
public MegaXImport(Frame owner) {
super( owner, "Import CSV", true);
setSize( 800, 500);
setLayout( new FlowLayout());
Chapter2MegaZillionaireApplication
48)
49)
50)
51)
52)
53)
54)
55)
56)
57)
58)
59)
60)
61)
62)
63)
64)
65)
66)
67)
68)
69)
70)
71)
72)
73)
74)
75)
76)
77)
78)
79)
80)
81)
82)
83)
84)
85)
86)
87)
88)
89)
90)
91)
92)
93)
94)
95)
96)
97)
98)
99)
100)
101)
102)
103)
104)
105)
106)
107)
108)
109)
110)
//;;;;;
// Obtain file name and kick off import process
//;;;;;
public void actionPerformed(ActionEvent event) {
String actionStr = event.getActionCommand();
if (actionStr.indexOf( "Exit") > -1) {
this.setVisible( false);
return;
}
if (actionStr.indexOf( "Choose") > -1) {
fc = new JFileChooser();
int ret_val = fc.showOpenDialog(this);
if (ret_val == JFileChooser.APPROVE_OPTION) {
File f = fc.getSelectedFile();
csvNameField.setText( f.getAbsolutePath());
}
} // end test for choose actionStr
155
Chapter2MegaZillionaireApplication
156
111)
112)
113)
114)
115)
116)
117)
118)
119)
120)
121)
122)
123)
124)
125)
126)
127)
128)
129)
130)
131)
132)
133)
134)
135)
136)
137)
138)
139)
140)
141)
142)
143)
144)
145)
146)
147)
148)
149)
150)
151)
152)
153)
154)
155)
156)
157)
158)
159)
160)
161)
162)
163)
164)
165)
166)
167)
168)
169)
170)
171)
172)
173)
//;;;;;
// Actual import logic happens here
//;;;;;
private boolean importCSV( String the_file) {
String line_in_str = null;
long l_record_count = 0;
boolean eof_flg = false, ret_val = false;
FileReader in_file = null;
BufferedReader input_file = null;
importRptArea.append( "\nAttempting to import " + the_file + "\n");
updateText();
try {
in_file = new FileReader( the_file);
} catch (FileNotFoundException f) {
importRptArea.append("File Not Found " + the_file);
eof_flg = true;
} // end catch for file not found
if (eof_flg == true)
return ret_val;
MegaDB.create_database();
input_file = new BufferedReader( in_file,4096);
importRptArea.append("\nPopulating database\n");
updateText();
while (eof_flg == false) {
try {
line_in_str = input_file.readLine();
}
catch (EOFException e) {
importRptArea.append( "End of file exception\n");
eof_flg = true;
}
catch (IOException e) {
importRptArea.append( "An IO Exception occurred\n");
importRptArea.append( e.toString());
//e.printStackTrace();
eof_flg = true;
}
if (eof_flg == true)
continue;
if (line_in_str == null) {
importRptArea.append( "End of intput file reached\n");
eof_flg = true;
continue;
}
l_record_count++;
String input_flds[] = line_in_str.split( ",");
try {
Chapter2MegaZillionaireApplication
174)
175)
176)
177)
178)
179)
180)
181)
182)
157
MegaDB.No_1.put( input_flds[1]);
MegaDB.No_2.put( input_flds[2]);
MegaDB.No_3.put( input_flds[3]);
MegaDB.No_4.put( input_flds[4]);
MegaDB.No_5.put( input_flds[5]);
MegaDB.Mega_No.put( input_flds[6]);
String date_parts[] = input_flds[0].split("-");
String dt_str = date_parts[0] + date_parts[1] + date_parts
[2];
183)
MegaDB.Draw_Dt.put( dt_str);
184)
185)
MegaDB.getDBF().write();
186)
187)
} catch ( xBaseJException j){
188)
j.printStackTrace();
189)
} catch( IOException i) {
190)
importRptArea.append( i.getMessage());
191)
}
192)
193)
if ( (l_record_count % 100) == 0) {
194)
importRptArea.append( "Processed " + l_record_count +
195)
" records\n");
196)
updateText();
197)
} // end of test for status message
198)
199)
} // end while loop to load records
200)
201)
importRptArea.append( "Finished adding " + l_record_count +
202)
" records\n");
203)
204)
return true;
205)
206)
} // end importCSV method
207)
208)
public void updateText() {
209)
importRptArea.invalidate();
210)
importRptArea.validate();
211)
importRptArea.paintImmediately( importRptArea.getVisibleRect());
212)
}
213) } // end MegaXImport class
Listinglines24and25areworthyofnote. Someofyoumayhavetheimpressionthata
panelisascreen.Asourconstructorshows,thisissimplynotthecase.Weallocateonepanelto
containthetheCSVfilenameprompt,textfield,andtheChoosebutton. Asecondpanelis
createdtocontainthetextareaandscrollpanealongwiththeOkandExitbuttons.Whenyouare
usingtheFlowLayoutinsteadoftheGridLayoutitisquitecommontohavemultiplepanelsina
containingobject.Itprovidesamethodofcontrollingtheflowbygroupingobjectstogether.
Noticelistinglines81through84.Afterwehaveaddedthepanelstothedialog,wehavethe
buttontochooseafilerequestfocusbutwesetthedefaultbuttontobetheimportbutton.Ifyou
havetriedrunningtheapplicationyouwillalreadyhavelearnedthe lastoneinwon. Thetext
entryfieldisthefieldwhichactuallyhasfocus,buttheOkbuttonishighlightedtoindicatethat
hittingreturnwillactivateit.
Chapter2MegaZillionaireApplication
158
Listingline104iswhatensurestheusermustcompletethefilechooserdialogonewayor
anotherbeforethisdialogcontinues.Ihopeyoudon't
finditstrangethatadialogcanthrowupa
dialogwhichcanthrowupanotherdialogthatcanthrowupanotherdialog.Ihaven't
conducteda
testtoseejusthowdeepyoucango,butIassumeithassomethingtodowitha2GBmemory
limitimposedonmanyJVMinstalls.
Thedialogreturnsanintegervaluetoinformusofitscompletionstatus.Iftheuserchose
andapprovedafilename,wecallgetSelectedFile()toobtaintheFileobject.Wethenhavetocall
getAbsolutePath()toobtainthefullpathname.Undermostcircumstances,youcannotopenthe
fileunlessyouprovidethefullpathname.Ididn't
provideastartinglocationforthefilechooser
soitwillstartintheuser's
homedirectoryinsteadofthecurrentworkingdirectory.Ifyouwantit
tostarttheresimplychangelistingline103toreadasfollows:
fc = new JfileChooser(System.getProperty("user.dir"));
There isn'tmuch left to discuss in the importCSV() method. You know that I call the
updateText()methodtoforcescreenupdatessomystatusmessagesgetdisplayedwhiletheyare
relevantinsteadofafterthetaskcompletes.Ihavealreadyprovidedyouseveralexampleswhich
readalineofinputfromatextfileandusetheStringsplit()methodtobreakitintoseparatedata
items. WehaveusedtheFieldput()methodandtheDBFwrite()methodmanytimesoverin
previoussourcelistings.
MegaXbase.java
1)
2)
3)
4)
5)
6)
7)
8)
9)
10)
11)
12)
13)
14)
15)
16)
17)
18)
19)
20)
21)
22)
23)
24)
25)
26)
27)
28)
import
import
import
import
java.awt.*;
java.awt.event.*;
javax.swing.*;
javax.swing.plaf.*;
import com.sun.java.swing.plaf.windows.WindowsLookAndFeel;
import com.sun.java.swing.plaf.gtk.GTKLookAndFeel;
import com.sun.java.swing.plaf.motif.MotifLookAndFeel;
import
import
import
import
com.logikal.megazillxBaseJ.MegaXImport;
com.logikal.megazillxBaseJ.MegaXbaseBrowsePanel;
com.logikal.megazillxBaseJ.MegaXbaseEntryPanel;
com.logikal.megazillxBaseJ.MegaXbaseDuePanel;
JFrame
JPanel
JMenuBar
JPanel
MegaXbaseBrowsePanel
MegaXbaseEntryPanel
MegaXbaseDuePanel
static
static
static
static
String
String
String
String
mainFrame=null;
mainPanel=null;
mb = null;
blankPanel=null;
mxb=null;
mxe=null;
md=null;
Chapter2MegaZillionaireApplication
29)
30)
31)
32)
33)
34)
35)
36)
37)
38)
39)
40)
41)
42)
43)
44)
45)
46)
47)
48)
49)
50)
51)
52)
53)
54)
55)
56)
57)
58)
59)
60)
61)
62)
63)
64)
65)
66)
67)
68)
69)
70)
71)
72)
73)
74)
75)
76)
77)
78)
79)
80)
81)
82)
83)
84)
85)
86)
87)
88)
89)
90)
91)
159
Chapter2MegaZillionaireApplication
160
92)
93)
94)
95)
96)
97)
98)
99)
100)
101)
102)
103)
104)
105)
106)
107)
108)
109)
110)
111)
112)
113)
114)
115)
116)
117)
118)
119)
120)
121)
122)
123)
124)
125)
126)
127)
128)
129)
130)
131)
132)
133)
134)
135)
136)
137)
138)
139)
140)
141)
142)
143)
144)
145)
146)
147)
148)
149)
150)
151)
152)
153)
154)
Chapter2MegaZillionaireApplication
155)
156)
157)
158)
159)
160)
161)
162)
163)
164)
165)
166)
167)
168)
169)
170)
171)
172)
173)
174)
175)
176)
177)
178)
179)
180)
181)
182)
183)
184)
185)
186)
187)
188)
189)
190)
191)
192)
193)
194)
195)
196)
197)
198)
199)
200)
201)
202)
203)
204)
205)
206)
207)
208)
209)
210)
211)
212)
213)
214)
215)
216)
217)
menuItem.setActionCommand("Exit");
menuItem.addActionListener( new ActionListener() {
public void actionPerformed(ActionEvent evt){
System.exit(0);}});
fileMenu.add( menuItem);
//;;;;;
// Build the File menu
//;;;;;
reportMenu = new JMenu("Report");
reportMenu.setMnemonic(KeyEvent.VK_R);
reportMenu.getAccessibleContext().setAccessibleDescription(
"Report creation menu");
// Import menu option
menuItem = new JMenuItem("Complete Data Dump", KeyEvent.VK_C);
menuItem.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_C,
ActionEvent.ALT_MASK));
menuItem.getAccessibleContext().setAccessibleDescription(
"Reports all data on file");
menuItem.setActionCommand("Dump");
menuItem.addActionListener( this);
reportMenu.add( menuItem );
menuItem = new JMenuItem("Most Often Hit", KeyEvent.VK_M);
menuItem.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_M,
ActionEvent.ALT_MASK));
menuItem.getAccessibleContext().setAccessibleDescription(
"Most frequently drawn numbers");
menuItem.setActionCommand("Most");
menuItem.addActionListener( this);
reportMenu.add( menuItem );
menuItem = new JMenuItem("Due Numbers", KeyEvent.VK_D);
menuItem.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_D,
ActionEvent.ALT_MASK));
menuItem.getAccessibleContext().setAccessibleDescription(
"Due numbers");
menuItem.setActionCommand("Due");
menuItem.addActionListener( this);
reportMenu.add( menuItem );
//;;;;;
// Add the new menus to the bar
//;;;;;
mb.add( fileMenu);
mb.add( reportMenu);
}
return mb;
// end createMenu method
//;;;;;
//
When a user choses a menu item we process it here
//
If Java would allow a switch to use strings, or would give
//
the JButton class a number field which got passed to a field in
//
the ActionEvent class, this code would be a lot cleaner.
//;;;;;
public void actionPerformed( ActionEvent e) {
String actionStr = e.getActionCommand();
System.out.println( "\nSelected action " + actionStr);
161
162
Chapter2MegaZillionaireApplication
218)
Frame f = (Frame) SwingUtilities.getAncestorOfClass( Frame.class, mb);
219)
220)
if (actionStr.indexOf( "Import") > -1) {
221)
MegaXImport importDialog = new MegaXImport( f);
222)
importDialog.setVisible(true);
223)
importDialog.dispose();
224)
}
225)
else if (actionStr.indexOf("Browse") > -1) {
226)
CardLayout cl = (CardLayout)(mainPanel.getLayout());
227)
cl.show(mainPanel, BROWSEPANEL );
228)
229)
} else if (actionStr.indexOf("Entry") > -1) {
230)
CardLayout cl = (CardLayout)(mainPanel.getLayout());
231)
cl.show(mainPanel, ENTRYPANEL );
232)
233)
} else if (actionStr.indexOf("Due") > -1) {
234)
CardLayout cl = (CardLayout)(mainPanel.getLayout());
235)
cl.show(mainPanel, DUEPANEL );
236)
237)
} else {
238)
System.out.println( "unhandled action");
239)
}
240)
241)
} // end actionPerformed method
242)
243)
public void itemStateChanged( ItemEvent e) {
244)
System.out.println( "state change");
245)
System.out.println( e.toString());
246)
}
247)
248)
249)
250) } // end MegaXbase class definition
Thecodeforthemainmenuisjustatinybitconvoluted.Listinglines41through76exist
becauseIbelieveMetalisprobablytheugliestLookandFeelanyonecouldhaveinvented. I
neededtochangethatlookandfeelwithouthavingthisthingcrashthefirsttimeyou tried to
compileit.ThesafethingformetodowasscanthroughthelistofLookandFeelswhichJava
thought were installed. Until the advent of Java 1.6 and the creation of a file called
swing.properties,JavahadnorealwayoffindingoutaboutanylookandfeelSundidn'tprovide.
Traditionally,applicationswillinclude anextraJARfilecontaininga Lookand Feeland
makecertainthatJARfilegetsaddedtotheCLASSPATHenvironmentvariable.Thisallowsthe
codetochangeaLookandFeeltobemuchshorter.Simplyaddanimportlineatthetopandthen
replacethetryblockwithacleanerpieceofcode.
import com.nilo.plaf.nimrod.*;
try {
UIManager.setLookAndFeel( new com.nilo.plaf.nimrod.NimRODLookAndFeel());
}
catch (UnsupportedLookAndFeelException e) {
System.out.println( "Unsupported look and feel");
}
Chapter2MegaZillionaireApplication
163
Itshouldn't
surpriseyoutolearnthatthisisexactlywhatIdidtogeneratethescreenshots
shownonpage96. Some Lookand Feelshaveverysubtlechanges,andsomeworkonlyon
specificplatforms.Ifyouaregoingtopickoneorcreateone,pleasemakecertainitworksonall
desktopoperatingsystemsbeforeyoureleaseit.IcannottellyouhowmanyOfficeXPtypelook
andfeelpackagesareoutthere,andeveryoneofthemworksonlyontheWindowsplatform.Gee,
thanks,guys.
IfyouhavenotdonemuchJavaprogramming,pleaseletmetakethetimetopointoutlisting
line78.Wehavenotdeclaredaninstanceofthis,asourclasseshaveallbeensupportorpanel
classesup to this point. An application requires you to construct a frame. The frame is a
containerwithanoptionaltitlethatholdsallothercomponentswhichmakeuptheapplication.
Listingline79isonelineyouwon'tnoticeyouforgotuntilyoutrytoclosetheapplication.If
youstarteditfromthecommandline,yourpromptwon't
return.Thewindowwillbegone,but
theappwillstillberunning.Atthatpointyoueithergetverygoodwithsystemutilitiestofindit,
or reboot and hope your operating system doesn'ttry to help you out by restarting all
applicationswhichwererunningattimeofshutdown.
Aftercallingamethodtocreateourmenubaratlistingline81,Icreateaninstanceofeach
panelandaddeachtothemainPanelalongwithaStringnamesoIcanfinditagain.OnceIhave
allofthepanelsadded,IsetthecontentpaneoftheframetobethemainPanel. Trustme,it
soundsfarmorecomplexthanitis.
WhydoyouthinkIaddedablankpanel?
Comeon,thinkaboutit.WhywouldIaddablankpaneltotheapplicationandgiveitaname
soIcouldfinditagain?Perhapstoclearthescreen?Thatwouldbethecorrectanswer.Iruninto
alotofGUIbasedmenuapplicationswrittenwithalotofdifferenttoolsandalotofthemhave
thesamebug.Onceyouchangethatinitialpanelunderthemenu,theydon't
provideanymethod
ofclearingitotherthanexitingtheprogramandreentering.
ThecreateMenu()methodshowsthefunkyprocessJavamakesadeveloperendurejustto
buildastandardmenu.Toahuman,thewholething,File+Report+dropdowns,isthemenu.In
Swing,FileisitsownmenuaswellasReports.EachmenuishungonthemenuBarandthename
ofthemenuisdisplayedatthatlocationonthemenuBar.
Chapter2MegaZillionaireApplication
164
Please pay attention to the nested ifelse structure starting at listing line 220. Your
assignmentswillrequireyoutocreatenewconditionsinthisstructure.Onceweidentifywhich
menuoptionwaschosenbaseduponthetextofitsactionweneedtoeitherlaunchtheassociated
dialogorshufflethecorrectpaneltothetop.Weneedthenameeachpanelwasaddedwithin
ordertofinditwiththeshow()method.
testMegaXbase.java
1)
2)
3)
4)
5)
6)
7)
8)
9)
10)
11)
12)
13)
14)
15)
import
import
import
import
java.awt.*;
java.awt.event.*;
javax.swing.*;
javax.swing.plaf.*;
import com.logikal.megazillxBaseJ.*;
public class testMegaXbase {
public static void main(String args[]){
MegaXbase mx = new MegaXbase();
}
}
We don'thave anything to discuss with this module. I simply needed to include it for
completeness.Mybuildcommandfileisequallynoncomplex.
b.sh
1)
2)
3)
4)
5)
6)
7)
8)
9)
10)
11)
12)
13)
14)
15)
16)
17)
18)
19)
20)
21)
22)
23)
24)
25)
26)
27)
28)
29)
30)
#! /bin/bash
#
#
# rm *.dbf
# rm *.ndx
#
javac -source 1.4 -target 1.4 -d . MegaDBF.java
javac -source 1.4 -target 1.4 -d . StatDBF.java
javac -source 1.4 -target 1.4 -d . StatElms.java
#
jar -cfv megaX.jar com/logikal/megazillxBaseJ/MegaDBF.class
jar -ufv megaX.jar com/logikal/megazillxBaseJ/StatDBF.class
jar -ufv megaX.jar com/logikal/megazillxBaseJ/StatElms.class
#
javac -source 1.4 -target 1.4 -d . MegaXImport.java
javac -source 1.4 -target 1.4 -d . MegaXbaseBrowsePanel.java
javac -source 1.4 -target 1.4 -d . MegaXbaseEntryPanel.java
javac -source 1.4 -target 1.4 -d . MegaXDueElms.java
#
jar -ufv megaX.jar com/logikal/megazillxBaseJ/MegaXbaseBrowsePanel.class
jar -ufv megaX.jar com/logikal/megazillxBaseJ/MegaXImport.class
jar -ufv megaX.jar com/logikal/megazillxBaseJ/MegaXbaseEntryPanel.class
jar -ufv megaX.jar com/logikal/megazillxBaseJ/MegaXDueElms.class
#
javac -source 1.4 -target 1.4 -d . MegaXbaseDuePanel.java
#
jar -ufv megaX.jar com/logikal/megazillxBaseJ/MegaXbaseDuePanel.class
#
javac -source 1.4 -target 1.4 MegaXbase.java
#
Chapter2MegaZillionaireApplication
165
ThesourcequalifiertellstheJavacompilertorestricttheinputsourceto1.4syntax. We
control the bytecode output by the target switch, which tells the Java compiler to generate
bytecodesequenceswhicharecompatiblewithversion1.4JVMs.
IputalmostallofthiscodeintoaJARfile.Wheneveryouwishtocreateapackageyouneed
toindicatetotheJavacompilerwhereto puttheclassfiles. Thisisdonebythepackage
statementinthesourcefileandthed . switchIputonthecommandline.Thisswitchtellsthe
compilertousethecurrentdirectoryastherootofthepackage.
roland@logikaldesktop:~/mega_xbasej$ ./b.sh
added manifest
adding: com/logikal/megazillxBaseJ/MegaDBF.class(in = 4429) (out= 2404)(deflated 45%)
adding: com/logikal/megazillxBaseJ/StatDBF.class(in = 4152) (out= 2227)(deflated 46%)
adding: com/logikal/megazillxBaseJ/StatElms.class(in = 394) (out= 282)(deflated 28%)
adding: com/logikal/megazillxBaseJ/MegaXbaseBrowsePanel.class(in = 5063) (out= 2713)(deflated 46%)
adding: com/logikal/megazillxBaseJ/MegaXImport.class(in = 5728) (out= 3134)(deflated 45%)
adding: com/logikal/megazillxBaseJ/MegaXbaseEntryPanel.class(in = 20237) (out= 8860)(deflated 56%)
adding: com/logikal/megazillxBaseJ/MegaXDueElms.class(in = 823) (out= 546)(deflated 33%)
adding: com/logikal/megazillxBaseJ/MegaXbaseDuePanel.class(in = 6054) (out= 3189)(deflated 47%)
roland@logikaldesktop:~/mega_xbasej$ dir com
logikal
roland@logikaldesktop:~/mega_xbasej$ dir com/logikal
megazillxBaseJ
roland@logikaldesktop:~/mega_xbasej$ dir com/logikal/megazillxBaseJ
MegaDBF.class
MegaXbaseDuePanel.class
MegaXbaseEntryPanel.class MegaXImport.class
StatElms.class
MegaXbaseBrowsePanel.class MegaXbaseEntryPanel$1.class MegaXDueElms.class
StatDBF.class
166
Chapter2MegaZillionaireApplication
2.7 ProgrammingAssignment3
Modifytheopen_database()methodofStatDBF.javatocheckwhetherthedatabaseisalready
open.Ifitisopen,closethecurrentlyopendatabasebeforeproceedingwiththeopen.
2.8 Progra
mming
As
sign
ment
ogram
mingAs
Assign
signm
ent4
There are currently two reports listed on the menu which do not currently have any
implementationprovided.TheMost OftenHit reportcaneasilybeimplementedbyprovidinga
newclass,MegaXMostElms,whichcomparesonlythehitcounts.YoucanthenclonetheDue
report,changingreportheadings,whileloops,andarraydatatypenames. Becertainyournew
reportrunsfromthemenu!
Youhavetocreatethedumpreportfromscratch.Thereisnothingcomplexaboutit.The
reportwillbeverymuchlikethebrowsewindowexceptthatrecordswillbewrittentoatextarea
insteadofaspreadsheet.
2.9 Summary
ThischapterhasbeenmeanttoprovidearealworldexampletohelpusersnewtoxBaseJ,
andpossiblyevennewtoJava,getuptospeed.Mostoftheexamplesyoufindonlinearevery
oneshot innature.Anattemptwasmadetoprovideyouwithanearlycompletebusinesstype
application.Youshouldbeabletopickandchoosepiecesofthisdesignforyourownuse.Don't
juststealthecode,considerthedesign!
Professionaldeveloperscandesigntheirwayaroundmostofthecriticalweakpointsfoundin
anytoolsettheyareforcedtouse.Peoplewhocutandpastecodewithoutconsideringthedesign
constraintsineffectatthetimetendtoblindlystumbleintoeverycriticalflawknowntoman.
Don'tstumblearound;readtheexplanationwhichhasbeenprovidedfirst.
Younowknowhowtoaddrecordstoadatafile,createanNDXfile,andreadrecordsbothin
indexorderanddirectly. Moreimportantly,youhavebeeninformedofsomeofthebugsand
been showncode which worksaround them. There isno reason youshouldnot be ableto
develop usable applications after having read this entire book. You might think you can
developapplicationsaftermerelyskimmingthischapterandstealingthecode,butyouwouldbe
mistaken. The beginning of this book provides you with questions you need to ask before
designinganyapplication.ThemostimportantquestionofallisS houldyoubeusinganxBASE
filetostorethisdata?
Chapter2MegaZillionaireApplication
167
Too many application developers simply reach for what they used last time without
consideringthelifespanofwhattheywillproduce.Sometimesthislapseleadstooverkill,suchas
acompleteMySQLdatabasetostore50records,andothertimesitisunderkill,suchastryingto
managewhatisnowa100,000itemproductcatalogwithxBASEfiles. Youmustlookatthe
currentneedandthepotentialfutureneedwhendesigninganapplication.
Wheneveryouhaveasystemwhichwillbeusedbyonlyoneperson,willstorefewerthana
couplethousandrecords,andneedstobestandalone,xBASEfilesareagoodoption. Justbe
certainyouaren't
limitingsomeone's
futurewhenyoumakethedecision.Iseealotofcomments
and messages online to the various commercial xBASE engine providers from people and
companieswhohavebeendevelopingasystemwiththetoolinquestionsincethe1980s.Business
keptgrowingandtheykeptcustomizing,andnowtheyissuepleastothevendorstodosomething
aboutthe2GBlimit,astheyhavehadtohacktheirsystemstosupportmultipleprimaryDBFfiles.
LaughallyouwantI'v
e actuallyreadmorethanonemessagelikethatrecently.I'm
not
tryingtodiscourageyoufromusingthistool,I'm
tryingtoeducateyouastoitsproperuse.In
eachcase,thosepoorbastardsstartedoutwithafewhundreditems,butbusinessgrewintoafew
hundredthousanditemsandtheircustomsystemnowcannothandleit.Theyarenowlookingata
completesystemredevelopment,andastheemailssuggest,arewillingtotryanythingtoavoidit.
Certain applications will always lend themselves to a small selfcontained indexed file
system.Ourlotterytrackerisagoodexample.Personalincometaxfilingsystemsareanother.
Smallretailsystemscandoverywell,butyouhavetodevelopcompleteIOclassestocompletely
shieldtheapplicationfromdatastorage.Idomeancompletelyshield.Yourmainapplicationcan
neveruseanobjectfromthelibraryortrapanexceptionfromit. InsteadofhavingyourField
objectspublicasIdid,youhavetomakethemprivateandwriteauniqueget()andset()method
foreachcolumn.Mostofyouwon't
dothis.InsteadyouwilldevelopmuchasIhaveshownyou.
It seems pretty clean at first glance, until you try to replace the underlying database with
PostgreSQLorMySQL.Thenitbecomesarewrite.Ifyouaredesigningforthehereandnow
knowingtherecouldbeamigration,youhavetodesigninthemigrationpathnow,notlater.
Chapter2MegaZillionaireApplication
168
Asacommunityproject,xBaseJisalmostperfect. I'm
notsayingthatitisbugfree, I'm
sayingitistheperfectclassofprojectforacommunity(OpenSource)effort.Thereareliterally
hundredsofplacesonlinecontainingdocumentationaboutthevariousxBASEformats. There
aremanyPython,Perl,andC/C++OpenSourcexBASElibrariesonecanobtainthesourcecode
for aswell.Despitetheir current Javaskilllevel, developersparticipatingintheprojectcan
obtainalltheinformationtheyneedwithouthavingtohavealargesupportforum.Youcaneven
testyourchangesforinteroperabilitywiththeotherOpenSourcexBASEprojectssoyoudon't
have to wonder if you did them correctly. If it works cleanly with two other OpenSource
products,youdiditcorrectlyenoughfortheOpenSourcecommunity. Remember,thereisno
ANSIstandardforxBASE.WhatreallymattersisthatallofthestuffintheOpenSourceworld
workstogether.Don't
forgetthatOpenOfficeandKSpreadbothprovidetheabilitytoopenaDBF
filedirectly.Besuretotestyourresultswiththeseapplicationsaswell.SomedayIBMmayeven
adddirectsupportforDBFfilestoLotusSymphony.
2.10
2.10ReviewQuestions
1.
2.
3.
4.
5.
WhatdoesCUAstandfor?
WhatisthedefaultlookandfeelforJavaapplications?
WhatDBFmethodtellsyouifarecordhasbeendeleted?
UnderwhatconditionsisitokaytoloadDBFcontentsintoaspreadsheet?
AfteropeninganexistingDBFandattachingoneormoreexistingNDXfiles,whatshould
youdo?
6. Are the various Field variable names required to match their corresponding xBASE
columnnames?
7. WhatinterfacemustaclassimplementinorderforittobeusedwithanArrays.sort()call?
8. Doesthestatement:
MegaXDueElms d_elms[] = new MegaXDueElms[ELM_COUNT];
Chapter3
Chapter3
Ruminations
Someofyoumaynotbefamiliarwiththisbookseries,soletmeexplain.Itrytoendeach
onewithachapternamedRuminations.TheseareessaysaboutITandlifeingeneralmeantto
makeyouthink.Somemayverywellpissyouofformorallyoffendyou.Sobeit.Somemay
causeyoutoshoutoutsupportonacrowdedtrainorplanewhenmosteverybodyisasleep.Sobe
it.
Inshort,thischapterismyrewardforwritingthebookandmayverywellbeyourrewardfor
readingit.Onthewhole,youshouldtakeawaysomethingfromeachessaywhichmakesyoua
moreworldlyITdeveloper,ifnotabetterperson.
Enjoy!
3.1 AuthoritativeResources
TheeventsI'm
abouttorelateactuallyoccurredwhileIwaswritingthisbook.Theprimary
developer/creatorofthexBaseJOpenSourceprojectwasshocked,toputitmildly,thatIdidn't
use
EclipseforJavadevelopment. HementionedsomeAuthoritative Resources claimingsome
extremelyhighpercentageofdevelopersusedEclipsetowriteJava.I've
beeninITlongenough
toknowthetruthaboutthoseauthoritative resources, sopleaseallowmetoshedsomelighton
thesubject.
Mostofthese AuthoritativeResources comefromapublisherorasupposedlyindependent
analyst.Thevastmajorityalsopointtoasurveydonebysomestandardsbodytohelpreenforce
theirownmanufactureddata.Suchsurveysdrawinthegullible(readthatMBAs)whohaven't
goteventheslightesttechnicalclue.Inshort,peoplerunningaroundquotingtheseauthoritative
resources withoutanyconceptofhowthedatawasobtainedarenaivelyhelpingtoperpetratea
fraud.
Itisnotofteninthisbookseriesthatyouwillfinditspoutinganypercentagepulledfromany
placeotherthanmydirectexperiencesinlife.Iholdthisseriestoamuchhigherstandardthan
the mass market publishers hawking everything from romance novels, to cook books, to
supposedlyscholarlytomesonIT.Thecontentinthisbookseriescomesfromatrenchwarrior,
notawishfulthinkeroramarketingdepartment.
170
Chapter3Ruminations
GiveneverythingIhavejusttoldyou,itshouldcomeasnosurpriseIwroteanessayonthis
whenthedeveloperquotedamassmarketpublisherandastandardsbodyasthesourceof his
information.TheversionpresentedhereisaslightlymoresanitizedversionofwhatItoldhim.
Yousee,heforgotthathewastalkingtonotonlyanauthor,butabookpublisher.Iknowthe
publishinggame.AtleastIknowthekindofgameplayedbythemassmarkethouses.
WhenmassmarketPublisherXputsoutabunchoffree informationstatingthatN%ofall
developersarecurrentlyusingtechnologyZyoucanprettymuchbetthatthisinformationwas
writtenbythemarketingdepartmentandhasabsolutelynobasisinfact. Youcanprettymuch
provethisbylookingattheirtitleselectionandcountingthenumberoftitlestheyhaverecently
releasedcoveringcompetingtechnologies.YouwillfindfifteentotwentytitlescoveringtheN%
technologyanditscomplimentarytopics(anexamplewouldbeEclipse+Java+OOP)andatbest
tworecenttitlesoncompetingtechnologies(Kate,SciTE,jEdit,TEA,C/C++,Python,etc.)
Ther ecent qualifierismostimportant.YouwillfinddozensoftitlesonC/C++fromthe
massmarkethouses,butveryfewpublishedinthepasttwoyears.Themassmarkethouses(and
Microsoftforthatmatter)makemoneyonlyiftechnologyiscontinuallybeingreplaced.Youwill
findbothmassmarketpublishersandretailsoftwarevendorstryingtocreatetrendswherenone
exist(orareneeded)simplytogeneraterevenue.Thevastmajorityofpeopleworkingforeither
vendorwillcompletelyignorethefactthatonceabusinessapplicationiswrittenandinplace,it
tendstostayaroundfor30years.
Oh,please,don't
takemywordforhowlongbusinessapplicationsstayinplaceoncewritten.
SimplysearchthroughthenewsarchivesforallofthoseY2Kstoriestalkingaboutsystemswhich
havebeenmakingmoneyforcompaniesforroughly30years. Whenyouaredonewiththat,
searchforallofthecurrentstoriesaboutHeritage DataSilos andLegacy Systems. Any
applicationmorethaneightyearsoldtendstofallintotheheritage category.WhenMicrosoft
founditselfbeingviewedasalegacysystemwithXP,theyquicklytriedtoreinventthemselves
asanIndiansoftwarecompanyviathereleaseofWindowsVista.Itwassucharousingsuccess,
with highranking business officials from around the globe giving interviews stating their
companies would never upgrade that Microsoft had to pull a lot of the development back
onshore and put out abillable bugfix labeled Windows 7. They have removed theword
Vista frommosteverythingtheycontrol.Onceagain,gosearchforthearticles,don't
justquote
me.
Chapter3Ruminations
171
So,whenmassmarketPublisherXtellsyouthat80%ofalldevelopersareusingtoolZ,you
lookandseethattheysaidthesamethingeightyearsagoabouttoolCandhaven't
publisheda
bookontoolCinthepast6years.Ohmy!TheycurrentlyhaveelevenbooksinprintontoolZ
andandasearchoftheBooksInPrintdatabaseshowstheyhavefourmorebeingpublishedthis
year.WhathappenedtoallofthoseapplicationswrittenusingtoolC?Hmmm.Naryawordis
spokenaboutthat.Businessesmustrewrite100%oftheirapplicationseachandeverytimemass
marketPublisherXwantstosellmorebooks.Nowonderbusinessesarehavingtroublemaking
money!
Of course Publisher X will try to quote some survey from a recognized standards or
intellectualbodylikeIEEEorACM.IEEEisastandardsbody.I've
neverbelongedtoIEEE,but
IhavebelongedtoACMandDECus. IcurrentlybelongtoEncompass. Letmetellyouhow
numbersgetgeneratedbysuchorganizations.Theysendoutasurveytotheirmembers.Those
whorespondrightawayarethoseworkinginacademiaandaredesperatetohaveaquoteprinted
somewherebecausetheyareinapublishorperishworld. Everyoneelse,thoseworkingfora
living,filetheemailawaysayingtheywillgettoitwhentimeallows. Lessthan1%ofthose
peopleactuallygetaroundtoresponding,whichisroughlythesamenumberofmemberswho
bothertovotefortheorganization's
leaders.So,whenanorganizationlikethisputsoutanumber
saying80%ofitssurveyedmembersusetoolZ,it's
really80%of1%.Thenumberisvalidasfar
asitgoes,butitdoesn'tgoveryfar.
Ifyouhaveneverbeenavotingmemberofanyorganization,youprobablydon't
haveagood
frameofreferenceforthis. Yousee,mostoftheseorganizationsprovidesomehooktokeep
members,thenprettymuchdisregardthewishesoftheirmembership.Inonecase,youhavetobe
amembertoobtainafreeHobbyistoperatingsystemlicense.Theorganizationthenturnsaround
andcompletelydisregardsanyandallwhohaveaninterestinthatoperatingsystembecausethe
tokenfewontheboardarebusytryingtokissuptoavendorchampioningafarlesscapable
operating system. Nomatterhowmanypeoplecastballots,onlythenamesintheleadership
change,nottheactualleadership.Mostgettiredoffightingthebattle.Theytakethefreelicense,
dowhattheyneedtodowithit,andletthescamcontinue.
Thescamgetsevenworsewhenmarketingfirmstrytorelabelaportionofthemselvesas
industry analysts. IcannottellyouhowmanyMBAsgethandedfourcolormarketingglossies
andhonestlybuythestorythatthiswasindependentindustryresearch.
Simplyput,almostnobodygoestoprisonforwireormailfraudthesedays,certainlynotthe
marketing departments for publicly traded companies. This means that there are no
Authoritative Resources forcurrenttrendsinsoftware,simplymarketingfraud,whichmostare
conditionedtofollow.
172
Chapter3Ruminations
3.2 TimestampsonReports
Thiswon't
bealonglecture,butitisoneIneedtocoverinthisedition.Hopefully,youhave
beenaloyalreaderfromthelogicbookthroughthefirsteditionofthisapplicationdevelopment
book,Java,SOA,andnowthisverybook. Thisdiscussionwillmakemoresensetomyloyal
readersthanmycasualreaders.
Duringthe70sandearly80swhenjobswererunonlydailyorweeklywewouldputthedate
ontheflagpageandsometimesonthefirstheadingline.Somereportwritingstandardshadeach
jobcreatingitsownheading page or coverpage asthefirstpageinthereportfile.Thispage
wouldbetheonlyplacenondetailleveldateinformationwasplaced.
Beforetheyoungwhippersnappersreadingthisgetallupinarmsaboutourstandards,letme
paintapictureofthetimes.Thevastmajorityofreportscamefrombatchjobsrunbycomputer
operators. Thesejobswereeitherpartofaregularlyscheduledproductioncycle,ortheywere
requestedbyvariousmanagerso ndemand andtheleadoperatorwouldworkthemintothe
schedule. (Notalldatawaskeptonlinebackthen,sojobshadtobescheduledbasedupon
availabilityoftapeandremovablediskdrives.)Therewasnosuchthingasapersonal printer
andveryfew workgroup printersscatteredaroundthecampus fromwhich userscouldprint
theirownreports. (Intruth,probablythebiggestdriving forcebehindfloppybased personal
computersgettingintocompaniesprobablywasn't
thesoftware,butthefactyoucouldget$300
dotmatrixprinterstogowiththem.Anofficeworkerwhogeneratedalotofpaperhadabetter
chance of surviving a layoff than an office worker who simply fetched coffee and attended
meetings.)
Themostimportantthingforyoutorememberisthatprinterswereexpensive,noisy,and
used tractorfed continuous form. Unlike today'slaser printers which willtake one or more
bundlesofcopierpaperandquietlyhumouthundredsofduplexprintedpagessittingonatablein
thecenterofaworkgroup,earlyprintershadtobekeptinthemachineroombecauseofthesound
dampeningandsecurityprovidedbythatroom.Mostreportsofthedaywerefinancialinnature.
You certainlydidn'twantjustanybody knowing youwere120dayspastdueforallofyour
vendors.
Manyjobswouldcomeoffthesystemprinterbeforeanoperatorgotaroundtoseparating
them.Normallythebatchjobscreatingthemwouldprintthereportwithastatementlikethis:
$ PRINT/FLAG/BURST/NOTE=Deliver to Roland
created ''f$time()'
some.rpt
Chapter3Ruminations
173
174
Chapter3Ruminations
Thisistheeraofthe24hourlifestyleandinstantgratification.Largebatchjobslikecredit
cardinvoicingstillhappen. Companies willcreatedozens,ifnotthousands,ofprintfileseach
containing hundreds, ifnot thousands, of individual credit card statements. Insomeobscure
location,andpossiblyencrypted,eachstatementwillhavethetimestampprintedonit. Itmay
evenbeprintedusingaverysmallfontinwhatlookslikearunningpagefooter.Employeesof
thecreditcardcompanywillknowhowtoreadit. Theywill divulge thisknowledgeduringa
customerservicecallwhenexplainingtoahusbandandwifewhomadechargesattheexactsame
timeintheexactsamestoreontheirpersonalcreditcardswhyonlyonehadthechargeshowup
onthestatement.
WhilemanyreportsontheInternetwillbegeneratedbysomeJavaorJavascriptcallsto
backendreportservices,theservicesthemselveswillmostlikelybeonatrustyOpenVMScluster
oranIBMmainframe.TheWebpageswhichwillreceivetheinformationwillbeinthebusiness
ofaggregatingthisinformationfromthedifferentreportingservicestheyarecalling.Itisreally
funnywhentheydon't
bothercoordinatingas of timestampsfromthevariousbackendservices
priortodisplay.
Onceagainwecanusecreditcardsasanexample.Manypeoplehaveacreditcardwhich
willgivethemsomekind ofaward,suchasairlinemilesorhotelbucksorsomesuchthing.
When a user opens up an online accountto monitor this information he or she usually gets
presented some kind of su mmary screen. The summary screen will coordinate responses
receivedfromallofthebackendservicesintoonecohesivedisplayshowingcurrentcharges,
payments,mileage,hotelbucks,etc.Mostoftheresponsesitchewsontocreatethedisplaywill
bestoredinsometemporarystorageontheWebbrowsingcomputer,usuallyintheformofa
cookie,butcouldbeanything.Thingsgethilariouswhenoneormoreofthebackendservices
aredownbutyouhaven't
deletedallyourcookiesnoremptiedyourcachesinceyourlastvisitto
thesite. Youlookatasummaryreportshowingyourlasttime's
awardedmileage(orcharges)
withthistime's
charges(ormileage).Thesethingsgettobeaproblemwhenyouarelookingto
useupyourmilesforyourvacation.
ManyPCbasedoperatingsystemswillonlygiveyouatimestampdowntothenumberof
secondssincemidnightJanuary1,1970.Thatlevelofresolutionisnotenoughfortoday's
world.
Itmightgetyoubyonareportheading,butnotatthetransactionlevel.Giventhatmostofyour
timeargumentsaregoingtobeabouttransactionleveldata,youneedtoprovidesomemethodof
defending yourself when the argument becomes why did this transaction show up on this
invoice? Ifyourreportpageheadingcontainsonlythestarttimeandthereisnoreportfooter
containingthecompletiontime,howdoyoudefendyourself?
Chapter3Ruminations
175
Letmeleaveyouponderingreportingtimestampswiththislittleditty.
Atanygivenstockexchangearoundtheworld,therewillbeorderscominginatafurious
pacealongwithconsolidatedlastsales.Orderswhicharen't
ma rket orders(meaningtobuyor
sellatthema rket price)getplacedinthebooktobecomepartofthecurrentmarket.Theactual
currentmarketpriceisdeterminedbytheconsolidatedlastsale,whichisgeneratedeverysecond
orso(longertimespansforlightlytradedstocks)bysaleswhichare printedtotape. The
consolidatedlastsalehastheeffectofcausingordersinthespecialist's
booktosuddenlybeduea
fill,andinsomecasestheseautomaticallyexecute.Anyexecutedorderhasitssaleinformation
senttotheprimaryexchangeforthatissuetobecomepartofthenextconsolidatedlastsale.Itis
calledconsolidated becauseitisacalculatedvaluebaseduponallsalesprinted totape during
thecalculationtimespan.(Tradeinformationusedtoprintonpapertapescalledticker tapes.
Nowthattradeinformationissenttotheprimaryexchangeinaparticulardataformat,butthe
lingoprintedtotapestillexists.)
Thingsgetdiceywithmarketorders.Manyexchangescanallowamarketordertobebriefly
heldformanualpriceimprovement.Thereisnofearofthemarketmovingbecausethemarket
orderisrequiredtobetaggedwiththeconsolidatedlastsalevaluethatwasineffectatthetimethe
marketordercameinorcurrentlastsaleprice .
Thislastparagraphsoundskindofsimple,doesn't
it?Itis...untilyougetaroundtodefining
current . Highvolume stocks with millions or billions of transactions per day can require
current tobedowntothenanosecond.Nowwegetintotheissueofin effect. Technically
thatconsolidatedlastsaleisin effect thenanosecondtheprimarymarketsendsitout. The
realityisthatittakesmorethanananosecondforthatlastsaletotransmitfromonecoasttothe
otherandberecorded.Onceitisrecorded,allofthebook checking thenhappenstoseeifany
fixedpriceordersarenowdueafill.
WhenIwasjuststartinginJuniorCollege,thistimethingwassomethingonlyacademics
thoughtabout.Wehaddiskseektimesmeasuredinseconds,andthoseseeksonlyhappenedonce
anoperatorgotaroundtomountingtheremovabledisk...ifwewereluckyenoughtobeusinga
disk.NowthatI'm
approachingtheautumnofmycareeritisbecomingarealissue.Tothoseof
youjuststartingout,whatcanIsayotherthan,itsuckstobeyou,Fred.
176
Chapter3Ruminations
3.3 DoomedtoFailureandTooStupidtoKnow
I get a lot of phone calls and emails for contracts. There are few phone calls more
entertainingthanlarge projecttogetoffofOpenVMS. Inevitably,theseprojectsarerunbythe
BigNconsultingfirmswithalloftheactualworkwhoredouttopreferred vendors. Recently,I
gotanotheroneofthesecalls.Hereisprettymuchhowitwent.(Callerisinblue.)
HowmanyyearshaveyouworkedonOpenVMS?
20plus.
HowmanyyearshaveyouworkedwithathingcalledPowerHouse?
It's
notathing,itisa4GLanditwasagodsendwhenitcameout.I've
beenworkingwithit
sincetheVAX11/750wastheprideofmostshops.
Howlongisthat?
Well,DECwasstillinbusiness...1985?ShortlyafterthatDECcameoutwiththeAlpha.
Ohwow.WehaveaprojecttomigratefromaVAX.Ididn't
realizethehardwarewasthat
old.
Most likely you have a project to migrate from either an Alpha or an Itanium. Since
OpenVMSmigratedfromVAXtoAlphatoItanium,mostpeoplestillcallthehardwarewhich
runsitaVAX.Thisiswrong,anduntilweendteachertenureinthiscountry,theproblemisn't
likelytoimprove.
Oh.WellI've
beenmoreinvolvedintherequirementsgatheringphaseoftheprojectforthe
pastsixmonths.Weareonlynowstartingtolookattheexistinghardware.Theyhavesomething
calledamultinodeclusterrunningRDB,haveyoueverworkedonthathardware?
Once again, it wasOpenVMS. Multiplemachines could beclusteredtogether toreally
increasecomputingpowerandfaulttolerance.I've
workedonclustersthatrangedinsizefrom
two machines in a room to lots of nodes scattered around the globe. From a development
standpointitreallydoesn'tmakemuchdifferencehowmanyorwheretheyare.
Well, I'msure that will come up. We are looking at replacing it with an OpenSource
platform.
Chapter3Ruminations
177
Well, if they were using RDB on a multinode cluster, odds are they needed the fault
tolerancethecombinationprovided.YoucannotcreateafaulttolerantsolutionviaUnix/Linux
becausetheOSkerneldoesn't
havetheconceptofarecord.Withouttheconceptofarecord,you
cannot have a kernel level lock manager. Withouta kernel level lock manager, you cannot
developalocaltransactionmanager. Withoutalocaltransactionmanageryoucannotbuilda
distributedtransactionmanager. Withoutbeingabletodistributetransactionsacrossacluster
withtwophasecommit,youcannotcreatefaulttolerance.
I'msurewewilldiscussfaulttoleranceatsomepoint.
You mean to tell me you've burned through 6 months of billable hours gathering
requirements and never discussed fault tolerance? You never asked if their current system
providedguaranteeddelivery+guaranteedexecution?
Wewillbeusingamessagequeuethatprovidesguaranteeddelivery.
Withouttheguaranteedexecutionpart,deliverydoesn't
matter. Adistributedtransaction
managerlikeDECdtmallowsyoutohaveasingletransactionwhichencompassesamessagefrom
an MQ Series message queue, multiple RMS Journaled file, RDB, ACMS, and every other
productwhichwasdevelopedtoparticipateinaDECdtmtransaction.Ifthattransactionisspread
acrossnine nodesin acluster andoneofthosenodes goesdownmidprocess, DECdtmwill
rollbackthetransaction.IfthetransactionwasalsopartofanACMSqueuedtask,ACMSwillre
dispatchthetransactionuptoNtimesuntiliteithersuccessfullyexecutesorexceedstheretry
countandhastoberoutedofftoanerrorhandlingqueue.
Oh.Well,thosediscussionswillhappeninacoupleofmonths.Icantellyouhavealotof
experienceonthisplatform,soI'm
goingtopresentyoutotheprimaryandoneofthemwillget
backtoyouforatechnicalinterview.
YoumeantotellmetheyactuallyhaveOpenVMSprofessionals?
Well,itwillprobablybesomeonefromHRexplainingthenoncompeteandotherpolicies.
I originally wrote the above essay when I was working on the second edition of The
MinimumYouNeedtoKnowtoBeanOpenVMSApplicationDeveloper. Thateditionwon't
be
outforacoupleofyearsandmostofthepeoplewhobuy/readthatbookliveouttheabovescene
far toooften. Itis more appropriatefor metoplace sucha story here, wheremany of the
problemswillcomefrom.
178
Chapter3Ruminations
Oh, don'tgo getting alldefensive now. If that statementoffended you itis mostlikely
becauseyoudon't
knowenoughabouttheindustrytounderstandthetruthofthematter.Wedid
notcoverwritingfaulttolerantapplicationsinthisbookbecause doingso isnearlyimpossible
usinganxBASEfileformatandhavingnocontrollingengineprovidingabarrierbetweenall
applicationsandthedata.Evenifyouusedthislibrarytocreatesuchanengine,youwouldhave
toensurenofileusedaneasilyrecognizableextensionandthattheenginehaditsownuserID
whichownedalldatafilesanddidnotallowsharedaccess. Evenifyouachievedallofthese
things,youwouldnothaveprovidedfaulttolerance.Thesethingsfixonlythedatasharingand
indexproblemswhicharenotoriouswithxBASEdatafiles.
Faulttoleranceisasdescribedabove,thetransactionscontinuenomatterwhatfails.
Thinkaboutthatline.It's
notjustanacademicmantra.Itisabusinessphilosophywherea
BRP(BusinessRecoveryPlan)documentisn't
createdbecausethesystemsaredesignedtonever
allowthebusinesstofail. Youwillfindthevastmajorityofpubliclytradedcompanieseither
haveacompletelyuntestedBRPinplace,orhavesimplynevergottenaroundtowritingone.A
tokenfewcompaniesdesignapplicationsandinfrastructuretosurviveanything.
When thetwin towersfellon 9/11 there werecompanies in those buildings using every
operatingsystemknowntoman.ThecompanieswhichwereusingdistributedOpenVMSclusters
hesitatedforupto15minuteswhiletheclustermadecertainallhardwareatthelocationhad
ceasedtorespond,thencontinuedprocessingeachandeverytransaction.Notransactionwaslost.
Despite the loss of life and location, the company neither ceased operation nor went out of
business.Everycompanybasingitsbusinessonotherplatformsstoppeddoingbusinessthatday.
Manyneverreturnedtobusiness.
I'm
tellingthisstoryinabookcoveringJavaandxBASEdevelopmenttoprovideyouwith
someconceptofthelimitationsyourtoolsimpose. Developerstendtobecomeenamoredwith
theirchoiceofdevelopmenttools.Theyrunaroundtryingtousetheminsituationsinwhichthey
arecompletelyinappropriate.IhavesatinconferenceroomswhereClipperhackersproposedto
useasystemwritteninClippertomeetalltheaccountingneedsofaFortune500company.They
wanted all data stored on a single instance of a file server which had some minimal RAID
capabilitiesandhonestlybelievedthatwasgoodenough.Don'tyoumakethissamemistake.
Chapter3Ruminations
179
EarlyoninthisbookIwalkedyouthroughthethoughtprocesswhichhadmeselecting
xBaseJ as a development tool for a project. Granted, the project I ended up writing wasn't
providedinthisbook,butitisoutthere.YoucanfinditonSourceForge:http://sourceforge.net/
projects/fuelsurcharge/ IusedthelotteryapplicationbecauseIalwaysusethatapplicationin
ordertolearnorteachnewtools.Thethoughtprocessusedtoselectthetoolsistheimportant
part,nottheapplicationIendedupwriting.
RereadtheconversationIhadwiththepersonwhocalledaboutthecontract. Theyhad
burnedsixmonthsandnotcoveredthemostimportantquestion. Theyhadnotaskedthefirst
questionwhichmustbeaskedatthestartofeachrequirementsgatheringsession.What isthe
expectedavailabilityofthissystem?
Woulditsurpriseyoutolearnthattheprojectwasforahealthcarecompanyandthatthe
systembeing replaced washandling patientrecords along withprescriptionsand pharmacy
dispensing? Wouldyoubeshockedtolearnthatmanyofthepatientsbeinghandled bythis
systemweresufferingfromHIVandcouldenteranemergencyroomonanygivenminuteofany
given24hourperiodandthatitmightnotbeahospitalwheretheirdoctorworksorevenbein
theirhomecityorcountry?
IfyouthinkyoucanuseJavaonaplatformwhichdoesn't
provideadistributedlockmanager
integratedintotheoperatingsystemkerneltodeliverasystemforthatenvironment,youaren't
anybetterthanthepersonwhocalledmeabouttheproject. Inmostcases,thecombinationof
high availabilityandfault tolerancepreclude theuseof anykind ofVM. Ingeneral, aVM
designedtorunonmultipleplatformscannotmakeuseofadistributedlockmanagerwhichwas
integratedintotheOSkernelofoneplatformbecausethelesserplatformstheVMrunsondon't
haveaprayerofeverhavingsuchatool.Ifyoustore100%ofalldatainarelationaldatabase
whichisnativetotheplatformprovidingthedistributedlockmanagerandintegratedwithsaid
manager,andyouhaveamessagequeueingsystemwhichisintegratedwiththedistributedlock
manager,andamessagedispatchingsystemwhichisnotonlyintegratedwiththedistributedlock
manager,butwillrollbackandredispatchthemessagewhentheprocesshandlingithangsor
dies,thenandonlythen,canyouthinkaboutusingaVMbasedlanguagefordevelopment.Yes,
therewerealotofandsinthatsentence,andforgoodreason.
Beforeyoucangooutworkingintherealworld,youneedtoknowtwothings:
1. Thelimitsofyourtools.
2. ThefirstquestionyouaskisWhatisthissystem'sexpectedavailability?
180
Chapter3Ruminations
Availabilitywasn't
anissueforthelotterytracking application. Itwasmeanttobefora
singlepersonandthedatabasecouldbecompletelyrecreatedfromaCSVfileinjustafewsteps.
AllofthedatawhichwentintotheCSVfilewouldbegleanedfromsomestatelotterysystem
Webpage,soeventheCSVcouldberecreatedfromscratchifneeded.Thistypeoflotteryhas
drawingswhichhappen,atmost,afewtimesperweek,soarecoveryprocesswhichtakesadayis
fine.
Let's
contrastthoserequirementswithanapplicationwhichmustbeabletoprovidemedical
recordstoanyhospitalintheworldforanypatientcontainedinthesystem.Doyouthinka12
dayrecoveryperiodisacceptable?Justhowlongdoyouthinktheemergencyroomhaswhena
patientcomesinalreadyseizingandthestaffneedstoidentifywhichmedicationthepatienthas
beenonbeforegivinghimsomethingtohelpwiththeseizing?Howdoyouaccomplishsystem
and data backup yet provide the necessary availability? How do you do OS and hardware
upgradeswithoutimpactingavailability?
As the availability requirement goes up, your tool choices go down and the number of
mandatoryquestionsrises. Witha12dayrecoveryperiod,wedidn't
askabouthardwareand
operatingsystemupgradesbecausetheydidn't
matter.Whenasystemisneeded24x7x365these
questionsbecomeimportant.Nevermakethemistakeofassumingyoucandoanythingyouwant
withlanguage A or toolZ. Theavailabilityrequirementsdictatethetools.Ifmanagement
cannotbemadetounderstandthis,youhavetoeithereducatethemorleavewithoutwarning.
Appe
ndi
xA
ppendi
ndix
AnswerstoIntroductionReviewQuestions:
HowmanyfieldsdiddBASEIIIallowtobeinarecord?
128
WhatgeneralcomputingtermdefinesthetypeoffileanxBASEDBFreallyis?
Relativefile
WhatdoesxBASEmeantoday?
Itreferstothedatastorageformatusedbyvariousapplications.
WhatwasthenoncommercialpredecessortoallxBASEproducts?
Vulcan
IntermsofthePCandDOS,wheredidthe64Kobject/variablesizelimitreallycomefrom?
TheLIM(LotusIntelMicrosoft)EMS(ExpandedMemoryStandard)
WhatcompanysoldthefirstcommercialxBASEproduct?
AshtonTate
IsthereanANSIxBASEstandard?Why?
No
EachofthevendorswanteditsownproducttobethestandardputforthbyANSIandthey
refusedtoreachanycompromise.
WhatisthemaximumfilesizeforaDBFfile?Why?
2GB.Thatisthemaximumvaluefora32bitsignedinteger.
WhatwasthemaximumnumberofbytesdBASEIIIallowedinarecord?dBASEII?
4000bytes;1000bytes.
Whatform/typeofdatawasstoredintheoriginalxBASEDBFfile?
Character.Numericfieldswereconvertedtocharacterrepresentationbeforestoring.
CanyoustorevariablelengthrecordsinaDBFfile?
No.
DoesanxBASElibraryautomaticallyupdateallNDXfiles?
No.Itisonlyrequiredtoupdatethosewhicharebothopenedandattached.
WhatistheacceptedmaximumprecisionforaNumericfield?
15.9:Totalwidthof15with9digitsofprecision.
Whatisthemaximumlengthofafieldorcolumnname?
10characters
AnswerstoChapter1ReviewQuestions
Whattwosituationsforceauserorapplicationtophysicallyremovedeletedrecords?
1)TheDBFreachesthemaximumfilesize.
2)Thediskholdingthedatafilerunsoutoffreespace.
Bydefault,whatarestringandcharacterfieldspaddedwithwhenusingxBaseJ?
Nullbytes.
IfyouhaveaDBFopenwithNDXfilesattachedtoitthencallasubroutinewhichcreatesnew
NDXobjectsforthosesamefilesandcallsreIndex()onthem,willthechangestotheindexfilesbe
reflectedintheNDXobjectsyourDBFholds?Whyorwhynot?
No.
NDXobjectsloadtheentireBtreeintoRAManddonotmonitordatafilechanges.
WhattwoJavaclassesdoyouneedtousetobuildcreateareportlinemakingthedatalineupin
columns?
StringBuilderandFormatter.
HowdoesonetellxBaseJtopadstringandcharacterfieldswithspaces?
Util.setxBaseJProperty("fieldFilledWithSpaces","true");
WhatDBFclassmethodphysicallyremovesrecordsfromthedatabase?
pack()
WhatisthemaximumsizeofaDBFfile?
2GB
WhatDBFclassmethodisusedtoretrieveavaluefromadatabaseFieldregardlessoffieldtype?
get()
AftercreatingashinynewDBFobjectandcorrespondingdatafile,whatmethoddoyouuseto
actuallycreatecolumnsinthedatabase?
addField()
WhatDBFclassmethodisusedtoassignavaluetoadatabaseField?
put()
WhatDBFclassmethoddoyoucalltochangetheNDXkeyofrefernece?
useIndex()
WhatDBFclassmethodignoresallindexesandphysicallyreadsaspecificrecord?
gotoRecord()
Whenyoudeleteadatabaserecord,isitactuallydeleted?
No,itisflaggedasdeleted.
WhatDBFclassmethodsetsthecurrentrecordtozeroandresetsthecurrentindexpointertothe
rootofthecurrentindex?
startTop()
WhatisthemaindifferencebetweenreadNext()andfindNext)?
readNext()requiresakeyofreferencetohavebeenestablishedviasomeotherI/Ooperation
andfindNext()doesnot.
Whatfunctionormethodreturnsthenumberofrecordsonfile?
getRecordCount()
Whathappenswhenyouattempttostoreanumericvaluetoolargeforthecolumn?
Atruncatedversionofthevalueisstored
Whathappenswhenyouattempttostoreacharactervaluetoolargeforthecolumn?
Anexceptionisthrown
Whenaccessingviaanindex,howdoyouobtaintherecordoccurringbeforethecurrentrecord?
findPrev()orreadPrev()
WhatDBFmethodreturnsthenumberoffieldscurrentlyinthetable?
getFieldCount()
Whenretrievingdatafromadatabasecolumn,whatdatatypeisreturned?
String
WhatisthemaximumlengthofacolumnnameformostearlyxBASEformats?
10
Whatdoestheinstanceofoperatorreallytellyou?
Whetheranobjectcanbesafelycastfromonetypetoanother.
AredescendingkeysdirectlysupportedbyxBaseJ?
No.
WhatNDXmethodcanyoucalltorefreshindexvaluesstoredintheNDXfile?
reIndex()
WhatJava StringmethodallowsyoutosplitaStringintoanarrayofStringsbasedupona
delimitingString?
split()
DoNDXobjectsmonitordatabasechangesmadebyotherprogramsorusers?
No
Canyou"undelete"arecordinaDBFfile?Ifso,whyandforhowlong?
Yes.
Records are only flagged as deleted; they are not physically removed until a pack() is
performedonthedatabase.
WhenaNumericfieldisdeclaredwithawidthof6and3decimalplaces,howmanydigitscan
existtotheleftofthedecimalwhenthefieldcontainsanegativevalue?
1:youmustallowonespaceforthedecimalandonespaceforthenegativesign.
Whendoyouneedtocreateafinalize()methodforyourclass?
Wheneveryouallocatesystemresourceslikefilesorphysicalmemorydirectlyinsteadofby
theJVMorusingaclasswhichalreadyprovidesafinalize()method.
WhatJavaclassprovidesthereadLine()methodtoobtain alineofinputfromatextfileor
stream?
BufferedReader
DoxBASEdatafilesprovideanybuiltinmethodofdataintegrity?
No.
Whatmustexist,nomatterhowthedataisstored,toprovidedataintegrity?
Anengineorotherservicethroughwhichalldataaccessisroutedwithoutexception.That
engineorserviceistheonlymethodofenforcingdatarules.
AnswerstoChapter2ReviewQuestions
WhatdoesCUAstandfor?
CommonUserAccess
WhatisthedefaultlookandfeelforJavaapplications?
Metal
WhatDBFmethodtellsyouifarecordhasbeendeleted?
deleted()
UnderwhatconditionsisitokaytoloadDBFcontentsintoaspreadsheet?
Whenthedataislocalandbeingloadedinreadonlymode.
AfteropeninganexistingDBFandattachingoneormoreexistingNDXfiles,whatshouldyou
do?
reIndex()
Are the various Field variable names required to match their corresponding xBASE column
names?
No
WhatinterfacemustaclassimplementinorderforittobeusedwithanArrays.sort()call?
Comparator
Doesthestatement:
MegaXDueElmsd_elms[]=newMegaXDueElms[ELM_COUNT];
completelyallocateanarrayofMegaXDueElmsordoyoustillhavetocreateeachindividual
element?
Create
Ifcreate,whatisthesyntaxtocreateanelement?
d_elms[i]=newMegaXDueElms();
WhatStringmethodmustbeusedwhenattemptingtoconverttheresultofaget()foraNumField
toanInteger()?why?
trim()
BecauseparseInt()cannothandlenonnumericcharacterslikespaces.
Whatjavaccommandlineoptionrestrictsthecontentofyoursourcecode?
source
For your own Unlimited Reading and FREE eBooks today, visit:
http://www.Free-eBooks.net
Share this eBook with anyone and everyone automatically by selecting any of the
options below:
COPYRIGHT INFORMATION
Free-eBooks.net respects the intellectual property of others. When a book's copyright owner submits their work to Free-eBooks.net, they are granting us permission to distribute such material. Unless
otherwise stated in this book, this permission is not passed onto others. As such, redistributing this book without the copyright owner's permission can constitute copyright infringement. If you
believe that your work has been used in a manner that constitutes copyright infringement, please follow our Notice and Procedure for Making Claims of Copyright Infringement as seen in our Terms
of Service here:
http://www.free-ebooks.net/tos.html