<?xml version="1.0"?><st-source><!-- Name: WebMVCExamplesBundleName: WebMVCExamplesDevelopmentPrerequisites: #(#(#any 'WebMVC' '') #(#any 'OmniBase' '') #(#parcel 'SMTP' ''))Parcel: #('WebMVCExamples')ParcelName: WebMVCExamplesPrerequisiteParcels: #(#('WebMVC' '') #('OmniBase' '') #('SMTP' ''))Date: 3:20:32 am July 15, 2003 --><time-stamp>From VisualWorks® NonCommercial, Release 7 of March 21, 2003 on July 15, 2003 at 3:20:32 am</time-stamp><do-it>(Dialog confirm: 'You are filing-in a Parcel source file!\\While this is possible it will not have\the same effect as loading the parcel.\None of the Parcel''s prerequisites will\be loaded and none of its load actions\will be performed.\\Are you sure you want to file-in?' withCRs) ifFalse: [self error: 'Parcel file-in abandoned.  Choose terminate or close.']</do-it><name-space><name>Tutorial</name><environment>Smalltalk</environment><private>false</private><imports>			VisualWave.VeryBasicServlet			VisualWave.Redirect			private Smalltalk.*			private WebMVC.*			</imports><category>CounterApp</category><attributes><package>Tutorial</package></attributes></name-space><name-space><name>Grocery</name><environment>Smalltalk</environment><private>false</private><imports>			VisualWave.Redirect			private Smalltalk.*			private WebMVC.*			</imports><category>Grocery</category><attributes><package>Grocery</package></attributes></name-space><name-space><name>Test</name><environment>Grocery</environment><private>false</private><imports>			private Smalltalk.Grocery.*			private Smalltalk.*			</imports><category>Grocery-Tests</category><attributes><package>Grocery-Tests</package></attributes></name-space><class><name>PersonBean</name><environment>Tutorial</environment><super>Core.Object</super><private>false</private><indexed-type>none</indexed-type><inst-vars>name age address </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>CounterApp</category><attributes><package>Tutorial</package></attributes></class><class><name>ChangeCommand</name><environment>Tutorial</environment><super>Core.Object</super><private>false</private><indexed-type>none</indexed-type><inst-vars></inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>CounterApp</category><attributes><package>Tutorial</package></attributes></class><class><name>PundleBrowserApp</name><environment>Tutorial</environment><super>Core.Object</super><private>false</private><indexed-type>none</indexed-type><inst-vars>pundleList selectedPundle </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>PundleBrowser</category><attributes><package>PundleBrowser</package></attributes></class><class><name>InertOrderedItem</name><environment>Grocery.Test</environment><super>Core.Object</super><private>false</private><indexed-type>none</indexed-type><inst-vars>item quantity </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-Tests</category><attributes><package>Grocery-Tests</package></attributes></class><class><name>SessionTag</name><environment>Grocery</environment><super>VisualWave.BodyTag</super><private>false</private><indexed-type>none</indexed-type><inst-vars>needsList requiredUserPattern </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-Tags</category><attributes><package>Grocery-Tags</package></attributes></class><class><name>InertOrder</name><environment>Grocery.Test</environment><super>Core.Object</super><private>false</private><indexed-type>none</indexed-type><inst-vars>customer items </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-Tests</category><attributes><package>Grocery-Tests</package></attributes></class><class><name>Counter</name><environment>Tutorial</environment><super>Core.Object</super><private>false</private><indexed-type>none</indexed-type><inst-vars>count </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>CounterApp</category><attributes><package>Tutorial</package></attributes></class><class><name>UserAlreadyExistsError</name><environment>Grocery</environment><super>Core.Error</super><private>false</private><indexed-type>none</indexed-type><inst-vars></inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-Exceptions</category><attributes><package>Grocery-Exceptions</package></attributes></class><class><name>PersistentCounter</name><environment>Grocery</environment><super>Core.Object</super><private>false</private><indexed-type>none</indexed-type><inst-vars>lastValue </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-DB</category><attributes><package>Grocery-DB</package></attributes></class><class><name>LoginForm</name><environment>Grocery</environment><super>WebMVC.ValidatingModel</super><private>false</private><indexed-type>none</indexed-type><inst-vars>username password </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-Forms</category><attributes><package>Grocery-Forms</package></attributes></class><class><name>UserList</name><environment>Grocery</environment><super>UI.ApplicationModel</super><private>false</private><indexed-type>none</indexed-type><inst-vars>userList requestList db transaction </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-Tools</category><attributes><package>Grocery-Tools</package></attributes></class><class><name>NewAccountForm</name><environment>Grocery</environment><super>WebMVC.ValidatingModel</super><private>false</private><indexed-type>none</indexed-type><inst-vars>lastName firstName gender emailAddress password1 password2 sendUpdates street city state zip referral comments </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-Forms</category><attributes><package>Grocery-Forms</package></attributes></class><class><name>PersistentObjectHolder</name><environment>Grocery</environment><super>UI.ValueModel</super><private>false</private><indexed-type>none</indexed-type><inst-vars>persistentObject </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-Form Actions</category><attributes><package>Grocery-Form Actions</package></attributes></class><class><name>PersistentObject</name><environment>Grocery</environment><super>Core.Object</super><private>false</private><indexed-type>none</indexed-type><inst-vars>transaction </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-Domain</category><attributes><package>Grocery-Domain</package></attributes></class><class><name>Aisle</name><environment>Grocery</environment><super>Grocery.PersistentObject</super><private>false</private><indexed-type>none</indexed-type><inst-vars>name sections features </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-Domain</category><attributes><package>Grocery-Domain</package></attributes></class><class><name>Section</name><environment>Grocery</environment><super>Grocery.PersistentObject</super><private>false</private><indexed-type>none</indexed-type><inst-vars>name items </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-Domain</category><attributes><package>Grocery-Domain</package></attributes></class><class><name>ShoppingDBTest</name><environment>Grocery.Test</environment><super>XProgramming.SUnit.TestCase</super><private>false</private><indexed-type>none</indexed-type><inst-vars>db </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-Tests</category><attributes><package>Grocery-Tests</package></attributes></class><class><name>ShoppingTestResource</name><environment>Grocery.Test</environment><super>Core.Object</super><private>false</private><indexed-type>none</indexed-type><inst-vars></inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-Tests</category><attributes><package>Grocery-Tests</package></attributes></class><class><name>ShoppingList</name><environment>Grocery</environment><super>Grocery.PersistentObject</super><private>false</private><indexed-type>none</indexed-type><inst-vars>items store name </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-Domain</category><attributes><package>Grocery-Domain</package></attributes></class><class><name>CachedCountRange</name><environment>Grocery</environment><super>Core.Object</super><private>false</private><indexed-type>none</indexed-type><inst-vars>cachedRange </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-DB</category><attributes><package>Grocery-DB</package></attributes></class><class><name>DecrementCommand</name><environment>Tutorial</environment><super>Core.Object</super><private>false</private><indexed-type>none</indexed-type><inst-vars></inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>CounterApp</category><attributes><package>Tutorial</package></attributes></class><class><name>SimpleShoppingTest</name><environment>Grocery.Test</environment><super>XProgramming.SUnit.TestCase</super><private>false</private><indexed-type>none</indexed-type><inst-vars>shopper store </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-Tests</category><attributes><package>Grocery-Tests</package></attributes></class><class><name>ShopperContactInfo</name><environment>Grocery</environment><super>Grocery.PersistentObject</super><private>false</private><indexed-type>none</indexed-type><inst-vars>name address emailAddress phoneNumber </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-Domain</category><attributes><package>Grocery-Domain</package></attributes></class><class><name>TagBrowserApp</name><environment>Tutorial</environment><super>Core.Object</super><private>false</private><indexed-type>none</indexed-type><inst-vars>tagLibraries selectedLibrary </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>TagBrowser</category><attributes><package>TagBrowser</package></attributes></class><class><name>OrderedItem</name><environment>Grocery</environment><super>Grocery.PersistentObject</super><private>false</private><indexed-type>none</indexed-type><inst-vars>item amount </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-Domain</category><attributes><package>Grocery-Domain</package></attributes></class><class><name>FirstServlet</name><environment>WebMVC</environment><super>VisualWave.SingleThreadModelServlet</super><private>false</private><indexed-type>none</indexed-type><inst-vars></inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Tutorial</category><attributes><package>Tutorial</package></attributes></class><class><name>IncrementCommand</name><environment>Tutorial</environment><super>Core.Object</super><private>false</private><indexed-type>none</indexed-type><inst-vars></inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>CounterApp</category><attributes><package>Tutorial</package></attributes></class><class><name>SuccessOnlyCommand</name><environment>Tutorial</environment><super>Core.Object</super><private>false</private><indexed-type>none</indexed-type><inst-vars></inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Tutorial</category><attributes><package>Tutorial</package></attributes></class><class><name>ConfirmationRedirectionTag</name><environment>Grocery</environment><super>VisualWave.Tag</super><private>false</private><indexed-type>none</indexed-type><inst-vars></inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-Tags</category><attributes><package>Grocery-Tags</package></attributes></class><class><name>SelectStoreForm</name><environment>Grocery</environment><super>WebMVC.ValidatingModel</super><private>false</private><indexed-type>none</indexed-type><inst-vars>storeId </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-Forms</category><attributes><package>Grocery-Forms</package></attributes></class><class><name>DBManager</name><environment>Grocery</environment><super>Core.Object</super><private>false</private><indexed-type>none</indexed-type><inst-vars>db transaction </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-DB</category><attributes><package>Grocery-DB</package></attributes></class><class><name>SMTPError</name><environment>Net</environment><super>Core.Error</super><private>false</private><indexed-type>none</indexed-type><inst-vars></inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>SMTP</category><attributes><package>Grocery-Extensions</package></attributes></class><class><name>UnitPrice</name><environment>Grocery</environment><super>Grocery.PersistentObject</super><private>false</private><indexed-type>none</indexed-type><inst-vars>perUnit dollars inexactUnit </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-Domain</category><attributes><package>Grocery-Domain</package></attributes></class><class><name>NewUserRequest</name><environment>Grocery</environment><super>Grocery.PersistentObject</super><private>false</private><indexed-type>none</indexed-type><inst-vars>user requestKey </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-Domain</category><attributes><package>Grocery-Domain</package></attributes></class><class><name>Order</name><environment>Grocery</environment><super>Grocery.PersistentObject</super><private>false</private><indexed-type>none</indexed-type><inst-vars>orderedItems complete shopper </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-Domain</category><attributes><package>Grocery-Domain</package></attributes></class><class><name>InertCustomer</name><environment>Grocery.Test</environment><super>Core.Object</super><private>false</private><indexed-type>none</indexed-type><inst-vars>orders </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-Tests</category><attributes><package>Grocery-Tests</package></attributes></class><class><name>User</name><environment>Grocery</environment><super>Grocery.PersistentObject</super><private>false</private><indexed-type>none</indexed-type><inst-vars>id username password active </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-Domain</category><attributes><package>Grocery-Domain</package></attributes></class><class><name>Shopper</name><environment>Grocery</environment><super>Grocery.User</super><private>false</private><indexed-type>none</indexed-type><inst-vars>contactInfo cart shoppingLists defaultStore </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-Domain</category><attributes><package>Grocery-Domain</package></attributes></class><class><name>Store</name><environment>Grocery</environment><super>Grocery.PersistentObject</super><private>false</private><indexed-type>none</indexed-type><inst-vars>name aisles id administrators specials </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-Domain</category><attributes><package>Grocery-Domain</package></attributes></class><class><name>OmniBaseAssumptionTest</name><environment>Grocery.Test</environment><super>XProgramming.SUnit.TestCase</super><private>false</private><indexed-type>none</indexed-type><inst-vars></inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-Tests</category><attributes><package>Grocery-Tests</package></attributes></class><class><name>ShoppingCart</name><environment>Grocery</environment><super>Grocery.PersistentObject</super><private>false</private><indexed-type>none</indexed-type><inst-vars>shopper store orderedItems </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-Domain</category><attributes><package>Grocery-Domain</package></attributes></class><class><name>InertItem</name><environment>Grocery.Test</environment><super>Core.Object</super><private>false</private><indexed-type>none</indexed-type><inst-vars>description </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-Tests</category><attributes><package>Grocery-Tests</package></attributes></class><class><name>DatabaseCommand</name><environment>Grocery</environment><super>Core.Object</super><private>false</private><indexed-type>none</indexed-type><inst-vars>db </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-Form Actions</category><attributes><package>Grocery-Form Actions</package></attributes></class><class><name>SelectStoreCommand</name><environment>Grocery</environment><super>Grocery.DatabaseCommand</super><private>false</private><indexed-type>none</indexed-type><inst-vars></inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-Form Actions</category><attributes><package>Grocery-Form Actions</package></attributes></class><class><name>CreateAccount</name><environment>Grocery</environment><super>Grocery.DatabaseCommand</super><private>false</private><indexed-type>none</indexed-type><inst-vars></inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-Form Actions</category><attributes><package>Grocery-Form Actions</package></attributes></class><class><name>ConfirmAccount</name><environment>Grocery</environment><super>Grocery.DatabaseCommand</super><private>false</private><indexed-type>none</indexed-type><inst-vars></inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-Form Actions</category><attributes><package>Grocery-Form Actions</package></attributes></class><class><name>CreateAccountStep1</name><environment>Grocery</environment><super>Grocery.DatabaseCommand</super><private>false</private><indexed-type>none</indexed-type><inst-vars></inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-Form Actions</category><attributes><package>Grocery-Form Actions</package></attributes></class><class><name>LoginCommand</name><environment>Grocery</environment><super>Grocery.DatabaseCommand</super><private>false</private><indexed-type>none</indexed-type><inst-vars>model user </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-Servlets</category><attributes><package>Grocery-Form Actions</package></attributes></class><class><name>ConfirmationForm</name><environment>Grocery</environment><super>WebMVC.ValidatingModel</super><private>false</private><indexed-type>none</indexed-type><inst-vars>username requestKey </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-Forms</category><attributes><package>Grocery-Forms</package></attributes></class><class><name>Address</name><environment>Tutorial</environment><super>Core.Object</super><private>false</private><indexed-type>none</indexed-type><inst-vars>street city state zip </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Tutorial</category><attributes><package>Tutorial</package></attributes></class><class><name>StockItem</name><environment>Grocery</environment><super>Grocery.PersistentObject</super><private>false</private><indexed-type>none</indexed-type><inst-vars>id description name unitPrice </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Grocery-Domain</category><attributes><package>Grocery-Domain</package></attributes></class><shared-variable><name>TestStoreExists</name><environment>Grocery.Test.ShoppingDBTest</environment><private>false</private><constant>false</constant><category>As yet unclassified</category><attributes><package>Grocery-Tests</package></attributes></shared-variable><shared-variable><name>ShopperInfo1</name><environment>Grocery.Test.ShoppingTestResource</environment><private>false</private><constant>false</constant><category>As yet unclassified</category><attributes><package>Grocery-Tests</package></attributes></shared-variable><shared-variable><name>ShopperInfo2</name><environment>Grocery.Test.ShoppingTestResource</environment><private>false</private><constant>false</constant><category>As yet unclassified</category><attributes><package>Grocery-Tests</package></attributes></shared-variable><shared-variable><name>Caches</name><environment>Grocery.PersistentCounter</environment><private>false</private><constant>false</constant><category>caching</category><initializer>Dictionary new</initializer><attributes><package>Grocery-DB</package></attributes></shared-variable><methods><class-id>Tutorial.PersonBean</class-id> <category>accessing</category><body package="Tutorial">address	^address</body><body package="Tutorial">address: anObject	address := anObject</body><body package="Tutorial">age	^age</body><body package="Tutorial">age: anObject	age := anObject</body><body package="Tutorial">name	^name</body><body package="Tutorial">name: anObject	name := anObject</body></methods><methods><class-id>Tutorial.ChangeCommand</class-id> <category>api</category><body package="Tutorial">executeWithModel: aCounter controller: aController	"The controller already filled in the model"	^aController findForward: 'success'</body></methods><methods><class-id>Tutorial.PundleBrowserApp</class-id> <category>accessing</category><body package="PundleBrowser">pundleList	^pundleList ifNil: [pundleList := self updatePundleList]</body><body package="PundleBrowser">selectedPundle	^selectedPundle</body><body package="PundleBrowser">selectedPundleName: aName	selectedPundle := pundleList detect: [:each | each name = aName] ifNone: []</body><body package="PundleBrowser">updatePundleList	| bundles packages |	bundles := Store.Bundle allBundles.	packages := Store.Package allPackages.	^(OrderedCollection withAll: bundles) addAll: packages</body></methods><methods><class-id>Grocery.Test.InertOrderedItem</class-id> <category>accessing</category><body package="Grocery-Tests">item	^item</body><body package="Grocery-Tests">item: anObject	item := anObject</body><body package="Grocery-Tests">quantity	^quantity</body><body package="Grocery-Tests">quantity: anObject	quantity := anObject</body></methods><methods><class-id>Grocery.SessionTag</class-id> <category>api</category><body package="Grocery-Tags">doAfterBody	| db |	db := DBManager openSample.		[	[self checkUser.	self addNeededRoots.	pageContext out nextPutAll: bodyContent string] 			evaluateAndCommitIn: db newTransaction] 			ensure: [db close].	^self class SKIP_BODY</body><body package="Grocery-Tags">doStartTag	^self class EVAL_BODY_INCLUDE</body></methods><methods><class-id>Grocery.SessionTag</class-id> <category>accessing</category><body package="Grocery-Tags">needsList	^needsList ifNil: [needsList := OrderedCollection new]</body></methods><methods><class-id>Grocery.SessionTag</class-id> <category>private</category><body package="Grocery-Tags">addNeededRoots	self needsList do: 			[:needs | 			pageContext handler attributeAt: needs				put: (self getNeededRoot: needs)]</body><body package="Grocery-Tags">checkUser	| currentUser |	requiredUserPattern isNil ifTrue: [^nil].	currentUser := (pageContext session at: 'user' ifAbsent: [nil]) value.	(currentUser notNil and: [(requiredUserPattern match: currentUser username)])		ifFalse: [pageContext redirectTo: '/shopping/login.jsp']</body><body package="Grocery-Tags">getNeededRoot: aRoot	^DBManager getRootObject: aRoot</body></methods><methods><class-id>Grocery.Test.InertOrder</class-id> <category>accessing</category><body package="Grocery-Tests">customer	^customer</body><body package="Grocery-Tests">customer: anObject	customer := anObject</body><body package="Grocery-Tests">items	^items isNil		ifTrue: [items := OrderedCollection new]		ifFalse: [items]</body></methods><methods><class-id>Grocery.Test.InertOrder</class-id> <category>items</category><body package="Grocery-Tests">addItem: anItem	self items add: anItem</body></methods><methods><class-id>Tutorial.Counter</class-id> <category>accessing</category><body package="Tutorial">count	^count ifNil: [count := 0]</body><body package="Tutorial">count: anObject	count := anObject asNumber</body></methods><methods><class-id>Tutorial.Counter</class-id> <category>actions</category><body package="Tutorial">decrement	count := self count -1</body><body package="Tutorial">double	count := self count * 2</body><body package="Tutorial">increment	count := self count + 1</body></methods><methods><class-id>Grocery.PersistentCounter</class-id> <category>initialization</category><body package="Grocery-DB">initialize	lastValue := 0</body></methods><methods><class-id>Grocery.PersistentCounter</class-id> <category>accessing</category><body package="Grocery-DB">newValue	^lastValue := lastValue + 1</body><body package="Grocery-DB">newValue: aCount	| result |	result := lastValue + 1 to: lastValue + aCount.	lastValue := lastValue + aCount.	^result</body></methods><methods><class-id>Grocery.PersistentCounter class</class-id> <category>instance creation</category><body package="Grocery-DB">new	^super new initialize</body></methods><methods><class-id>Grocery.PersistentCounter class</class-id> <category>incrementing</category><body package="Grocery-DB">caches	^Caches</body><body package="Grocery-DB">getNewValueFor: counterName inDatabase: aDatabase 	"This method uses a cache to grab more counter values than you might need.  This improves efficiency for programs which	request one counter value at a time but do so in rapid succession."	| counterCache |	counterCache := Caches at: counterName ifAbsent: [].	(counterCache isNil or: [counterCache hasCachedValue not]) 		ifTrue: 			[Caches at: counterName				put: (self loadCounterCacheFor: counterName inDatabase: aDatabase)].	counterCache := Caches at: counterName ifAbsent: [].	^counterCache newValue</body><body package="Grocery-DB">loadCounterCacheFor: counterName inDatabase: aDatabase 	| transaction counter result |		[	[transaction := aDatabase newTransaction.	counter := transaction root at: counterName.	transaction lock: counter] 			whileFalse: 				[transaction abort.				(Delay forMilliseconds: 50) wait].	result := CachedCountRange forCounter: counter.	transaction		markDirty: counter;		commit] 			ifCurtailed: [transaction abort].	^result</body><body package="Grocery-DB">resetCaches	"self resetCaches"	Caches := Dictionary new.</body></methods><methods><class-id>Grocery.LoginForm</class-id> <category>accessing</category><body package="Grocery-Forms">password	^password</body><body package="Grocery-Forms">password: anObject	password := anObject</body><body package="Grocery-Forms">username	^username</body><body package="Grocery-Forms">username: anObject	username := anObject</body></methods><methods><class-id>Grocery.LoginForm class</class-id> <category>field specs</category><body package="Grocery-Forms">passwordFieldSpec	^FieldSpec name: 'password' validator: RequiredFieldValidator new converter: StringConverter new</body><body package="Grocery-Forms">usernameFieldSpec	^FieldSpec name: 'username' validator: RequiredFieldValidator new converter: StringConverter new</body></methods><methods><class-id>Grocery.UserList</class-id> <category>actions</category><body package="Grocery-Tools">inspectRequest	self requestList selection ifNil: 			[Dialog warn: 'Select NewUserRequest to inspect fist.'.			^nil].	self requestList selection inspect</body><body package="Grocery-Tools">inspectUser	self userList selection ifNil: 			[Dialog warn: 'Select User to inspect fist.'.			^nil].	self userList selection inspect</body><body package="Grocery-Tools">removeRequest	| request |	self requestList selection ifNil: 			[Dialog warn: 'Select Request to delete fist.'.			^nil].	request := self requestList selection.	request removeIn: transaction.	transaction commit.	self updateLists</body><body package="Grocery-Tools">removeUser	self userList selection ifNil: 			[Dialog warn: 'Select User to delete fist.'.			^nil].	User deleteByUsername: self userList selection username in: transaction.	transaction commit.	self updateLists</body><body package="Grocery-Tools">updateLists	transaction abort.	transaction := db newTransaction.	self updateRequestList.	self updateUserList</body></methods><methods><class-id>Grocery.UserList</class-id> <category>aspects</category><body package="Grocery-Tools">requestList	"This method was generated by UIDefiner.  Any edits made here	may be lost whenever methods are automatically defined.  The	initialization provided below may have been preempted by an	initialize method."	^requestList isNil		ifTrue:			[requestList := SelectionInList new]		ifFalse:			[requestList]</body><body package="Grocery-Tools">userList	"This method was generated by UIDefiner.  Any edits made here	may be lost whenever methods are automatically defined.  The	initialization provided below may have been preempted by an	initialize method."	^userList isNil		ifTrue:			[userList := SelectionInList new]		ifFalse:			[userList]</body></methods><methods><class-id>Grocery.UserList</class-id> <category>interface opening</category><body package="Grocery-Tools">postOpenWith: aBuilder	super postOpenWith: aBuilder.	self openDatabase.	self updateUserList.	self updateRequestList</body></methods><methods><class-id>Grocery.UserList</class-id> <category>closing</category><body package="Grocery-Tools">changeRequest	self closeDatabase.	ObjectMemory removeDependent: self.	^true</body></methods><methods><class-id>Grocery.UserList</class-id> <category>private</category><body package="Grocery-Tools">closeDatabase	db close</body><body package="Grocery-Tools">openDatabase	ObjectMemory removeDependent: self.	ObjectMemory addDependent: self.	db := DBManager openSample.	transaction := db newTransaction</body><body package="Grocery-Tools">updateRequestList	self requestList 		list: (NewUserRequest userRequestListIn: transaction)</body><body package="Grocery-Tools">updateUserList	self userList list: (User allUsersIn: transaction)</body></methods><methods><class-id>Grocery.UserList</class-id> <category>update</category><body package="Grocery-Tools">aboutToQuitCleanup	[self closeDatabase] on: Error do: []</body><body package="Grocery-Tools">returnFromSnapshot	[self openDatabase.	self updateLists] on: Error do: [Transcript show: 'UserList: error opening database'; cr]</body><body package="Grocery-Tools">update: anAspectSymbol with: aParameter 	anAspectSymbol == #aboutToQuit ifTrue: [		self aboutToQuitCleanup.	].	anAspectSymbol ==#returnFromSnapshot ifTrue: [		self returnFromSnapshot	].</body></methods><methods><class-id>Grocery.NewAccountForm</class-id> <category>accessing</category><body package="Grocery-Forms">city	^city</body><body package="Grocery-Forms">city: anObject	city := anObject</body><body package="Grocery-Forms">comments	^comments</body><body package="Grocery-Forms">comments: anObject	comments := anObject</body><body package="Grocery-Forms">emailAddress	^emailAddress</body><body package="Grocery-Forms">emailAddress: anObject	emailAddress := anObject</body><body package="Grocery-Forms">firstName	^firstName</body><body package="Grocery-Forms">firstName: anObject	firstName := anObject</body><body package="Grocery-Forms">gender	^gender</body><body package="Grocery-Forms">gender: anObject	gender := anObject</body><body package="Grocery-Forms">lastName	^lastName</body><body package="Grocery-Forms">lastName: anObject	lastName := anObject</body><body package="Grocery-Forms">password1	^password1</body><body package="Grocery-Forms">password1: anObject	password1 := anObject</body><body package="Grocery-Forms">password2	^password2</body><body package="Grocery-Forms">password2: anObject	password2 := anObject</body><body package="Grocery-Forms">referral	^referral</body><body package="Grocery-Forms">referral: anObject	referral := anObject</body><body package="Grocery-Forms">sendUpdates	^sendUpdates</body><body package="Grocery-Forms">sendUpdates: anObject	sendUpdates := anObject</body><body package="Grocery-Forms">state	^state</body><body package="Grocery-Forms">state: anObject	state := anObject</body><body package="Grocery-Forms">street	^street</body><body package="Grocery-Forms">street: anObject	street := anObject</body><body package="Grocery-Forms">zip	^zip</body><body package="Grocery-Forms">zip: anObject	zip := anObject</body></methods><methods><class-id>Grocery.NewAccountForm</class-id> <category>validating/assigning</category><body package="Grocery-Forms">validateAndAssignFor: aController formData: formData 	^(super validateAndAssignFor: aController formData: formData) 		ifTrue: [self validatePasswordFor: aController]		ifFalse: [false]</body><body package="Grocery-Forms">validatePasswordFor: aController 	^self password1 = self password2 		ifFalse: 			[aController addError: (ValidationError forVariable: 'password2'						description: 'The passwords do not match').			false]		ifTrue: [true]</body></methods><methods><class-id>Grocery.NewAccountForm class</class-id> <category>field specs</category><body package="Grocery-Forms">cityFieldSpec	^FieldSpec name: 'city' validator: nil converter: StringConverter new</body><body package="Grocery-Forms">commentsFieldSpec	^FieldSpec name: 'city' validator: nil converter: StringConverter new</body><body package="Grocery-Forms">emailAddressFieldSpec	^FieldSpec name: 'emailAddress' validator: EMailAddressFormatValidator new converter: StringConverter new</body><body package="Grocery-Forms">firstNameFieldSpec	^FieldSpec name: 'firstName' validator: RequiredFieldValidator new converter: StringConverter new</body><body package="Grocery-Forms">genderFieldSpec	^FieldSpec name: 'gender' validator: nil converter: StringConverter new</body><body package="Grocery-Forms">lastNameFieldSpec	^FieldSpec name: 'lastName' validator: RequiredFieldValidator new converter: StringConverter new</body><body package="Grocery-Forms">password1FieldSpec	^FieldSpec name: 'password1' validator: RequiredFieldValidator new converter: StringConverter new</body><body package="Grocery-Forms">password2FieldSpec	^FieldSpec name: 'password2' validator: RequiredFieldValidator new converter: StringConverter new</body><body package="Grocery-Forms">referralFieldSpec	| fs |	fs := FieldSpec name: 'referral' validator: nil converter: StringConverter new.	fs acceptsList: true.	^fs</body><body package="Grocery-Forms">sendUpdatesFieldSpec	^FieldSpec name: 'sendUpdates' validator: nil converter: StringConverter new</body><body package="Grocery-Forms">stateFieldSpec	^FieldSpec name: 'state' validator: nil converter: StringConverter new</body><body package="Grocery-Forms">streetFieldSpec	^FieldSpec name: 'street' validator: nil converter: StringConverter new</body><body package="Grocery-Forms">zipFieldSpec	^FieldSpec name: 'zip' validator: nil converter: StringConverter new</body></methods><methods><class-id>Grocery.PersistentObjectHolder</class-id> <category>private</category><body package="Grocery-Form Actions">persistentObject	^persistentObject</body><body package="Grocery-Form Actions">persistentObject: anObject	persistentObject := anObject</body><body package="Grocery-Form Actions">reloadObject	self setValue: (persistentObject class load: persistentObject inTransaction: OmniBase currentTransaction)</body></methods><methods><class-id>Grocery.PersistentObjectHolder</class-id> <category>accessing</category><body package="Grocery-Form Actions">setValue: aPersistentObject	persistentObject := aPersistentObject</body><body package="Grocery-Form Actions">value	| t |	t := OmniBase currentTransaction.	t = persistentObject transaction		ifFalse: [self reloadObject].	^persistentObject</body></methods><methods><class-id>Grocery.PersistentObjectHolder class</class-id> <category>instance creation</category><body package="Grocery-Form Actions">withValue: aValue	^self new value: aValue; yourself</body></methods><methods><class-id>Grocery.PersistentObject</class-id> <category>public</category><body package="Grocery-Domain">database	^self transaction isNil		ifTrue: [nil]		ifFalse: [self transaction environment]</body><body package="Grocery-Domain">lock    "Sets a write-lock on the object. Answer &lt;true&gt; if successful or if object is transient."    ^transaction isNil or: [transaction lock: self]</body><body package="Grocery-Domain">makePersistent: anObject    transaction notNil ifTrue: [        transaction makePersistent: anObject ]</body><body package="Grocery-Domain">markDirty    "Informs transaction that the object has changed and     has to be written into the database when transaction commits."    transaction notNil ifTrue: [        transaction markDirty: self    ]</body><body package="Grocery-Domain">objectId    "Answer object id of a persistent object. This method works only if    a persistent object was already stored i.e. if transaction in which it    was made persistent already received #commit or #checkpoint."    ^self transaction getObjectID: self</body><body package="Grocery-Domain">transaction	"Answer an OmniBase transaction in which the object was loaded or &lt;nil&gt; if object is not persistent."	^transaction</body><body package="Grocery-Domain">unlock    "Removes a write-lock on the object."    transaction notNil ifTrue: [        transaction unlock: self    ]</body></methods><methods><class-id>Grocery.PersistentObject</class-id> <category>initialize / release</category><body package="Grocery-Domain">initialize	^self</body></methods><methods><class-id>Grocery.PersistentObject</class-id> <category>private</category><body package="Grocery-Domain">odbLoadedIn: anOmniBaseTransaction 	"This method is sent when the object is loaded from the database."	transaction := anOmniBaseTransaction</body><body package="Grocery-Domain">odbMadePersistentIn: anOmniBaseTransaction 	"This method is sent when the object is made persistent."	transaction := anOmniBaseTransaction</body></methods><methods><class-id>Grocery.PersistentObject</class-id> <category>comparing</category><body package="Grocery-Domain">= other	^self isIdenticalTo: other</body></methods><methods><class-id>Grocery.PersistentObject class</class-id> <category>instance creation</category><body package="Grocery-Domain">new    ^super new initialize</body><body package="Grocery-Domain">newInTxn: aTransaction	| instance |	instance := super new initialize.	aTransaction ifNotNil: [aTransaction makePersistent: instance].	^instance</body></methods><methods><class-id>Grocery.PersistentObject class</class-id> <category>private</category><body package="Grocery-Domain">odbTransientInstanceVariables	"This method tells OmniBase which instance variables should not be stored into the database."	^OrderedCollection with: 'transaction'</body></methods><methods><class-id>Grocery.PersistentObject class</class-id> <category>utility</category><body package="Grocery-Domain">lock: anObject in: aTransaction orGiveUpInMilliseconds: anInteger 	"repeatedly try to lock the supplied object until successful and return true.  Give up if unsuccessful for rougly anInteger milliseconds and return false."	| roughTime gotLock |	roughTime := 0.	gotLock := false.		[gotLock := aTransaction lock: anObject.	gotLock not &amp; (roughTime &lt;= anInteger)] 			whileTrue: 				[roughTime := roughTime + 100.				(Delay forMilliseconds: 100) wait].	^gotLock</body></methods><methods><class-id>Grocery.Aisle</class-id> <category>items</category><body package="Grocery-Domain">items	^(self sections collect: [:section | section items]) flatten</body></methods><methods><class-id>Grocery.Aisle</class-id> <category>accessing</category><body package="Grocery-Domain">name	"return the value of the instance variable 'name' (automatically generated)"	^name</body><body package="Grocery-Domain">name: something 	"set the value of the instance variable 'name' (automatically generated)"	name := something.	self markDirty</body></methods><methods><class-id>Grocery.Aisle</class-id> <category>sections</category><body package="Grocery-Domain">addSection: aSection 	self sections add: aSection.	self markDirty</body><body package="Grocery-Domain">sections	^sections ifNil: 			[sections := OrderedCollection new.			self markDirty.			sections]</body></methods><methods><class-id>Grocery.Aisle</class-id> <category>features</category><body package="Grocery-Domain">featureItem: aStockItem 	self features add: aStockItem</body><body package="Grocery-Domain">features	^features ifNil: 			[features := OrderedCollection new.			self markDirty.			features]</body></methods><methods><class-id>Grocery.Aisle class</class-id> <category>instance creation</category><body package="Grocery-Domain">newWithName: aString    ^self new name: aString; yourself</body><body package="Grocery-Domain">newWithName: aString inTxn: aTransaction 	^(self newInTxn: aTransaction)		name: aString;		yourself</body></methods><methods><class-id>Grocery.Section</class-id> <category>items</category><body package="Grocery-Domain">addItem: anItem 	self items add: anItem.	self markDirty.</body><body package="Grocery-Domain">items	^items ifNil: [		items := OrderedCollection new.		self markDirty.		items]</body></methods><methods><class-id>Grocery.Section</class-id> <category>accessing</category><body package="Grocery-Domain">name	"return the value of the instance variable 'name' (automatically generated)"	^name</body><body package="Grocery-Domain">name: something 	"set the value of the instance variable 'name' (automatically generated)"	name := something.	self markDirty</body></methods><methods><class-id>Grocery.Section class</class-id> <category>instance creation</category><body package="Grocery-Domain">newWithName: aString    ^self new name: aString; yourself</body><body package="Grocery-Domain">newWithName: aString inTxn: aTransaction    ^(self newInTxn: aTransaction) name: aString; yourself</body></methods><methods><class-id>Grocery.Test.ShoppingDBTest</class-id> <category>running</category><body package="Grocery-Tests">tearDown	db := nil</body></methods><methods><class-id>Grocery.Test.ShoppingDBTest</class-id> <category>creating db</category><body package="Grocery-Tests">createAisles	| txn s |	txn := db newTransaction.	s := txn root at: 'SevenEleven'.	1 to: 2		do: 			[:i | 			| a |			a := Aisle newWithName: 'aisle ' , i printString inTxn: txn.			s addAisle: a].	txn commit</body><body package="Grocery-Tests">createSections	| txn s |	txn := db newTransaction.	s := txn root at: 'SevenEleven'.	s aisles do: 			[:aisle | 			| section |			1 to: 2				do: 					[:i | 					section := Section 								newWithName: 'section ' , i printString , ' of ' , aisle name inTxn: txn.					aisle addSection: section]].	txn commit</body><body package="Grocery-Tests">createShopper	| txn  |	txn := db newTransaction.	[Shopper 		newUser: 'Bob Smith'		password: 'shit'		contactInfo: ShoppingTestResource shopperInfo1		inTxn: txn] 			ensure: [txn commit].</body><body package="Grocery-Tests">createStockItems	| txn s |	txn := db newTransaction.	s := txn root at: 'SevenEleven'.	s aisles do: 			[:aisle | 			aisle sections do: 					[:section | 					| stockItem |					1 to: 5						do: 							[:i | 							stockItem := StockItem 										newWithName: 'stock item ' , i printString , ' in ' , section name , ' of ' 												, aisle name inTxn: txn.							section addItem: stockItem]]].	txn commit</body><body package="Grocery-Tests">createTestStore	self defaultDatabasePath asFilename exists 		ifTrue: [self defaultDatabasePath asFilename recursiveRemove].	db := OmniBase createOn: self defaultDatabasePath.		[| txn |	txn := db newTransaction.	self initIndicesAndCountersIn: txn.	Grocery.Store newWithId: 'SevenEleven' name: 'SevenEleven' inTxn: txn.	txn commit] 			ensure: [db close]</body><body package="Grocery-Tests">defaultDatabasePath	OSHandle currentOS = #unix 		ifTrue: [^'/tmp/Grocery-test']		ifFalse: [^'c:\temp\Grocery-test']</body><body package="Grocery-Tests">initIndicesAndCountersIn: txn 	"This method creates primary key index and id counter for persistent instances of Person."	User initDatabaseIn: txn.	StockItem initDatabaseIn: txn.	Grocery.PersistentCounter resetCaches.	Grocery.Store initDatabaseIn: txn.</body></methods><methods><class-id>Grocery.Test.ShoppingDBTest</class-id> <category>tests</category><body package="Grocery-Tests">testAddToCart	| theItem txn store shopper |	self createTestStore.	db := OmniBase openOn: self defaultDatabasePath.	self createAisles.	self createSections.	self createStockItems.	self createShopper.	txn := db newTransaction.		[store := Grocery.Store withId: 'SevenEleven' inTxn: txn.	theItem := store stockItems first.	shopper := Shopper findByUsername: 'Bob Smith' in: txn.  "if I create the shopper here his cart has identity problems"	shopper enterStore: store.	shopper purchaseItem: theItem amount: 10.	self assert: shopper cart orderedItems size = 1.	shopper purchaseItem: theItem amount: 5.	self assert: shopper cart = shopper cart. " test object identity "	self assert: shopper cart orderedItems size = 1.	"only keep last order for this item"	self assert: shopper cart orderedItems first amount = 5.	theItem := store stockItems at: 2.	shopper purchaseItem: theItem amount: 3.	self assert: shopper cart orderedItems size = 2.	self assert: (shopper cart orderedItems at: 2) amount = 3.	self 		assert: (shopper cart amountOrderedOfItem: store stockItems first) = 5.	self 		assert: (shopper cart amountOrderedOfItem: (store stockItems at: 2)) = 3.	self 		assert: (shopper cart amountOrderedOfItem: (store stockItems at: 3)) = 0] 			ensure: [txn abort. db close]</body><body package="Grocery-Tests">testAddToCartNoShopper	| theItem txn store cart |	self createTestStore.	db := OmniBase openOn: self defaultDatabasePath.	self createAisles.	self createSections.	self createStockItems.	txn := db newTransaction.		[store := Grocery.Store withId: 'SevenEleven' inTxn: txn.	theItem := store stockItems first.	cart := ShoppingCart newForShopper: nil inTxn: txn.	cart moveToStore: store.	cart acceptItem: theItem amount: 10.	self assert: cart orderedItems size = 1.	cart acceptItem: theItem amount: 5.	self assert: cart = cart.	" test object identity "	self assert: cart orderedItems size = 2.	"cart keeps all items"	self assert: (cart orderedItems first) amount = 10.	theItem := store stockItems at: 2.	cart acceptItem: theItem amount: 3.	self assert: cart orderedItems size = 3.	self assert: (cart orderedItems at: 3) amount = 3.	self assert: (cart amountOrderedOfItem: (store stockItems at: 1)) = 15.	self assert: (cart amountOrderedOfItem: (store stockItems at: 2)) = 3.	self assert: (cart amountOrderedOfItem: (store stockItems at: 3)) = 0] 			ensure: 				[txn abort.				db close]</body><body package="Grocery-Tests">testCartToShoppingList	| theItem txn store shopper list |	self createTestStore.	db := OmniBase openOn: self defaultDatabasePath.	self createAisles.	self createSections.	self createStockItems.	self createShopper.	txn := db newTransaction.		[store := Grocery.Store withId: 'SevenEleven' inTxn: txn.	theItem := store stockItems first.	shopper := Shopper findByUsername: 'Bob Smith' in: txn.	"if I create the shopper here his cart has identity problems"	shopper enterStore: store.	theItem := store stockItems first.	shopper purchaseItem: theItem amount: 5.	theItem := store stockItems at: 2.	shopper purchaseItem: theItem amount: 3.	list := shopper newShoppingListNamed: 'Weekly list'.	list getItemsFromCart: shopper cart.	self assert: list items size = 2.	self assert: (list items at: 1) item = (store stockItems at: 1).	self assert: (list items at: 2) item = (store stockItems at: 2)] 			ensure: 				[txn abort.				db close]</body><body package="Grocery-Tests">testCheckout	| theItem txn store shopper order |	self createTestStore.	db := OmniBase openOn: self defaultDatabasePath.	self createAisles.	self createSections.	self createStockItems.	self createShopper.	txn := db newTransaction.		[store := Grocery.Store withId: 'SevenEleven' inTxn: txn.	theItem := store stockItems first.	shopper := Shopper findByUsername: 'Bob Smith' in: txn.	"if I create the shopper here his cart has identity problems"	shopper enterStore: store.	theItem := store stockItems first.	shopper purchaseItem: theItem amount: 10.	self assert: shopper cart orderedItems size = 1.	shopper purchaseItem: theItem amount: 5.	self assert: shopper cart orderedItems size = 1.	"only keeps last amount for this item"	order := shopper cart createOrderForItems.	self assert: order orderedItems size = 1.	order completeOrder.	self assert: shopper cart orderedItems isEmpty.	self assert: order isComplete] 			ensure: 				[txn abort.				db close]</body><body package="Grocery-Tests">testOrderToShoppingList	| theItem txn store shopper order list |	self createTestStore.	db := OmniBase openOn: self defaultDatabasePath.	self createAisles.	self createSections.	self createStockItems.	self createShopper.	txn := db newTransaction.		[store := Grocery.Store withId: 'SevenEleven' inTxn: txn.	theItem := store stockItems first.	shopper := Shopper findByUsername: 'Bob Smith' in: txn.	"if I create the shopper here his cart has identity problems"	shopper enterStore: store.	theItem := store stockItems at: 1.	shopper purchaseItem: theItem amount: 5.	theItem := store stockItems at: 2.	shopper purchaseItem: theItem amount: 3.	order := shopper cart createOrderForItems.	self assert: order orderedItems size = 2.	order completeOrder.	list := shopper newShoppingListNamed: 'Weekly list'.	list getItemsFromOrder: order.	self assert: list items size = 2.	self assert: (list items at: 1) item = (store stockItems at: 1).	self assert: (list items at: 2) item = (store stockItems at: 2)] 			ensure: 				[txn abort.				db close]</body><body package="Grocery-Tests">testShoppers	| txn s |	self createTestStore.	db := OmniBase openOn: self defaultDatabasePath.	txn := db newTransaction.		[Shopper 		newUser: 'Bob Smith'		password: 'shit'		contactInfo: ShoppingTestResource shopperInfo1		inTxn: txn] 			ensure: [txn commit].	txn := db newTransaction.		[s := Shopper findById: 1 in: txn.	self assert: s notNil.	self assert: s username = 'Bob Smith'.	self assert: s password = 'shit'] 			ensure: [txn abort].	txn := db newTransaction.		[s := Shopper findByUsername: 'Bob Smith' in: txn.	self assert: s notNil.	self assert: s username = 'Bob Smith'.	self assert: s password = 'shit'] 			ensure: 				[txn abort.				db close]</body><body package="Grocery-Tests">testShoppingListToCart	| theItem txn store shopper order list |	self createTestStore.	db := OmniBase openOn: self defaultDatabasePath.	self createAisles.	self createSections.	self createStockItems.	self createShopper.	txn := db newTransaction.		[store := Grocery.Store withId: 'SevenEleven' inTxn: txn.	theItem := store stockItems first.	shopper := Shopper findByUsername: 'Bob Smith' in: txn.  "if I create the shopper here his cart has identity problems"	shopper enterStore: store.    theItem := store stockItems at: 1.    shopper purchaseItem: theItem amount: 5.    theItem := store stockItems at: 2.    shopper purchaseItem: theItem amount: 3.    order := shopper cart createOrderForItems.    self assert:order orderedItems size = 2.    order completeOrder.    self assert: shopper cart orderedItems size = 0.    list := shopper newShoppingListNamed: 'Weekly list'.    list getItemsFromOrder: order.    self assert: list items size = 2.    list := shopper shoppingListNamed: 'Weekly list'.    list placeItemsInCart: shopper cart.    self assert: shopper cart orderedItems size = 2.    self assert: (shopper cart orderedItems at: 1) amount = 5.    self assert: (shopper cart orderedItems at: 2) amount = 3.    self assert: (shopper cart orderedItems at: 1) item = (store stockItems at: 1).    self assert: (shopper cart orderedItems at: 2) item = (store stockItems at: 2)] ensure: [txn abort. db close]</body><body package="Grocery-Tests">testStockItemIndex	| txn item idx |	self createTestStore.	db := OmniBase openOn: self defaultDatabasePath.	self createAisles.	self createSections.	self createStockItems.	txn := db newTransaction.		[item := StockItem findById: 1 in: txn.	self assert: item notNil.	self assert: (item name startsWith: 'stock item 1').	item := StockItem findById: 20 in: txn.	self assert: item notNil.	self assert: item id = 20.	idx := StockItem primaryKeyIndexIn: txn.	item := idx getFirst value.	self assert: idx size = 20.	1 to: idx size		do: 			[:i | 			self assert: item id = i.			item := idx getNext value]] 			ensure: 				[txn abort.				db close]</body></methods><methods><class-id>Grocery.Test.ShoppingTestResource class</class-id> <category>resources</category><body package="Grocery-Tests">shopperInfo1    ^ShopperInfo1</body><body package="Grocery-Tests">shopperInfo2    ^ShopperInfo2</body></methods><methods><class-id>Grocery.Test.ShoppingTestResource class</class-id> <category>class initialization</category><body package="Grocery-Tests">initialize	"self initialize"	ShopperInfo1 := (ShopperContactInfo new)				name: 'Joe Grocery Shopper';				emailAddress: 'cdshaffer@acm.org';				address: '1234 Gateway Lane';				phoneNumber: '(123)555-1212';				yourself.	"Later a ShopperAddress instance?"	ShopperInfo2 := (ShopperContactInfo new)				name: 'Jane Grocery Shopper';				emailAddress: 'cdshaffer@acm.org';				address: '555 Star Road';				phoneNumber: '(654)111-9988';				yourself	"Later a ShopperAddress instance?"</body></methods><methods><class-id>Grocery.ShoppingList</class-id> <category>items</category><body package="Grocery-Domain">addItem: anItem 	self items add: anItem.	self markDirty</body><body package="Grocery-Domain">getItemsFromCart: aCart 	aCart orderedItems do: [:item | self addItem: item]</body><body package="Grocery-Domain">getItemsFromOrder: anOrder 	anOrder orderedItems do: [:item | self addItem: item]</body></methods><methods><class-id>Grocery.ShoppingList</class-id> <category>accessing</category><body package="Grocery-Domain">items	^items ifNil: 			[items := OrderedCollection new.			self markDirty.			items]</body><body package="Grocery-Domain">name    "return the value of the instance variable 'name' (automatically generated)"    ^ name</body><body package="Grocery-Domain">name: something 	"set the value of the instance variable 'name' (automatically generated)"	name := something.	self markDirty</body><body package="Grocery-Domain">store    "return the value of the instance variable 'store' (automatically generated)"    ^ store</body><body package="Grocery-Domain">store: something 	"set the value of the instance variable 'store' (automatically generated)"	store := something.	self markDirty</body></methods><methods><class-id>Grocery.ShoppingList</class-id> <category>shopping</category><body package="Grocery-Domain">placeItemsInCart: aCart 	self items do: [:item | aCart acceptOrderedItem: item copy]</body></methods><methods><class-id>Grocery.ShoppingList class</class-id> <category>instance creation</category><body package="Grocery-Domain">newWithName: aString    ^self new name: aString; yourself</body><body package="Grocery-Domain">newWithName: aString inTxn: aTransaction    ^(self newInTxn: aTransaction) name: aString; yourself</body></methods><methods><class-id>Grocery.CachedCountRange</class-id> <category>accessing</category><body package="Grocery-DB">cachedRange	^cachedRange</body><body package="Grocery-DB">cachedRange: anObject	cachedRange := anObject</body><body package="Grocery-DB">newValue	self hasCachedValue ifFalse: [self error: 'I''m empty.'].	cachedRange := cachedRange first + 1 to: cachedRange last.	^cachedRange first - 1</body></methods><methods><class-id>Grocery.CachedCountRange</class-id> <category>testing</category><body package="Grocery-DB">hasCachedValue	^self cachedRange isEmpty not</body></methods><methods><class-id>Grocery.CachedCountRange class</class-id> <category>instance creation</category><body package="Grocery-DB">forCounter: aPersistentCounter	^self new cachedRange: (aPersistentCounter newValue: self cacheSize)</body></methods><methods><class-id>Grocery.CachedCountRange class</class-id> <category>accessing</category><body package="Grocery-DB">cacheSize	"Default number of counter entries to take whenever I run out.  Making this number too large can result in wasted counter values.  	If you absolutely need no gaps in your counters, use a PersistentCounter without caching (although performance will suffer if you	try to get a bunch of counter values, one at a time, for example)."	^10</body></methods><methods><class-id>Tutorial.DecrementCommand</class-id> <category>api</category><body package="Tutorial">defaultModelClass	^Counter</body><body package="Tutorial">executeWithModel: aCounter controller: aController	"(aController session at: 'counter' ifAbsentPut: [Counter new count: 0; yourself]) decrement."	aCounter decrement.	^aController findForward: 'success'</body></methods><methods><class-id>Grocery.Test.SimpleShoppingTest</class-id> <category>building</category><body package="Grocery-Tests">buildStoreInventory    |si c s|    c := Aisle newWithName: 'Paper products'.    s := Section newWithName: 'Tissues'.    c addSection: s.    si := (StockItem newWithName: 'Kleenex') description: '100Ct 2ply tissues'; yourself.    si unitPrice: (UnitPrice dollarsPerPackage: 3.5).    s addItem: si.    store addAisle: c.    c := Aisle newWithName: 'Beverages'.    s := Section newWithName: 'Coffee'.    c addSection: s.    si := (StockItem newWithName: 'Starbucks Espresso') description: '1Lb of excellent beans'; yourself.    si unitPrice: (UnitPrice dollarsPerPackage: 8.0). "packaged in exactly one pound bags"    s addItem: si.    si := (StockItem newWithName: 'Here''s How Coffee -- Columbian blend') description: '1Lb of Columbian blend'; yourself.    si unitPrice: (UnitPrice dollarsPerPound: 7.50).    s addItem: si.    store addAisle: c.    c := Aisle newWithName: 'Bakery'.    s := Section newWithName: 'Fresh baked bulk items'.    c addSection: s.    si := (StockItem newWithName: 'Hard sandwich rolls') description: '4in. round sandwhich roll'; yourself.    si unitPrice: (UnitPrice dollars: 5 perUnit: 'roll').    s addItem: si.    store addAisle: c.</body></methods><methods><class-id>Grocery.Test.SimpleShoppingTest</class-id> <category>tests</category><body package="Grocery-Tests">testAddToCart    |theItem|    self buildStoreInventory.    theItem := store stockItems at: 1.    shopper purchaseItem: theItem amount: 10.    self assert: shopper cart orderedItems size = 1.    shopper purchaseItem: theItem amount: 5.    self assert: shopper cart orderedItems size = 1. "only keep last order for this item"    self assert: (shopper cart orderedItems at: 1) amount = 5.    theItem := store stockItems at: 2.    shopper purchaseItem: theItem amount: 3.    self assert: shopper cart orderedItems size = 2.    self assert: (shopper cart orderedItems at: 2) amount = 3.    self assert: (shopper cart amountOrderedOfItem: (store stockItems at: 1)) = 5.    self assert: (shopper cart amountOrderedOfItem: (store stockItems at: 2)) = 3.    self assert: (shopper cart amountOrderedOfItem: (store stockItems at: 3)) = 0.</body><body package="Grocery-Tests">testCartToShoppingList    |theItem list|    self buildStoreInventory.    theItem := store stockItems at: 1.    shopper purchaseItem: theItem amount: 5.    theItem := store stockItems at: 2.    shopper purchaseItem: theItem amount: 3.    list := shopper newShoppingListNamed: 'Weekly list'.    list getItemsFromCart: shopper cart.    self assert: list items size = 2.    self assert: (list items at: 1) item = (store stockItems at: 1).    self assert: (list items at: 2) item = (store stockItems at: 2).</body><body package="Grocery-Tests">testCheckout	| theItem order |	self buildStoreInventory.	theItem := store stockItems first.	shopper purchaseItem: theItem amount: 10.	self assert: shopper cart orderedItems size = 1.	shopper purchaseItem: theItem amount: 5.	self assert: shopper cart orderedItems size = 1.	"only keeps last amount for this item"	order := shopper cart createOrderForItems.	self assert: order orderedItems size = 1.	order completeOrder.	self assert: shopper cart orderedItems isEmpty.	self assert: order isComplete</body><body package="Grocery-Tests">testOrderToShoppingList    |theItem list order|    self buildStoreInventory.    theItem := store stockItems at: 1.    shopper purchaseItem: theItem amount: 5.    theItem := store stockItems at: 2.    shopper purchaseItem: theItem amount: 3.    order := shopper cart createOrderForItems.    self assert:order orderedItems size = 2.    order completeOrder.    list := shopper newShoppingListNamed: 'Weekly list'.    list getItemsFromOrder: order.    self assert: list items size = 2.    self assert: (list items at: 1) item = (store stockItems at: 1).    self assert: (list items at: 2) item = (store stockItems at: 2).</body><body package="Grocery-Tests">testShoppingListToCart    |theItem list order|    self buildStoreInventory.    theItem := store stockItems at: 1.    shopper purchaseItem: theItem amount: 5.    theItem := store stockItems at: 2.    shopper purchaseItem: theItem amount: 3.    order := shopper cart createOrderForItems.    self assert:order orderedItems size = 2.    order completeOrder.    self assert: shopper cart orderedItems size = 0.    list := shopper newShoppingListNamed: 'Weekly list'.    list getItemsFromOrder: order.    self assert: list items size = 2.    list := shopper shoppingListNamed: 'Weekly list'.    list placeItemsInCart: shopper cart.    self assert: shopper cart orderedItems size = 2.    self assert: (shopper cart orderedItems at: 1) amount = 5.    self assert: (shopper cart orderedItems at: 2) amount = 3.    self assert: (shopper cart orderedItems at: 1) item = (store stockItems at: 1).    self assert: (shopper cart orderedItems at: 2) item = (store stockItems at: 2)</body><body package="Grocery-Tests">testStoreSetup    self buildStoreInventory.    self assert: store aisles size = 3.    self assert: store stockItems size = 4.</body></methods><methods><class-id>Grocery.Test.SimpleShoppingTest</class-id> <category>running</category><body package="Grocery-Tests">setUp    shopper := Shopper newUser: 'Shopper 1' password: 'fickle' contactInfo: ShoppingTestResource shopperInfo1.    store := Grocery.Store newWithId: 'testStore' name: 'test'.    shopper enterStore: store</body></methods><methods><class-id>Grocery.ShopperContactInfo</class-id> <category>accessing</category><body package="Grocery-Domain">address    "return the value of the instance variable 'address' (automatically generated)"    ^ address</body><body package="Grocery-Domain">address: something 	"set the value of the instance variable 'address' (automatically generated)"	address := something.	self markDirty</body><body package="Grocery-Domain">emailAddress    "return the value of the instance variable 'emailAddress' (automatically generated)"    ^ emailAddress</body><body package="Grocery-Domain">emailAddress: something 	"set the value of the instance variable 'emailAddress' (automatically generated)"	emailAddress := something.	self markDirty</body><body package="Grocery-Domain">name    "return the value of the instance variable 'name' (automatically generated)"    ^ name</body><body package="Grocery-Domain">name: something 	"set the value of the instance variable 'name' (automatically generated)"	name := something.	self markDirty</body><body package="Grocery-Domain">phoneNumber    "return the value of the instance variable 'phoneNumber' (automatically generated)"    ^ phoneNumber</body><body package="Grocery-Domain">phoneNumber: something 	"set the value of the instance variable 'phoneNumber' (automatically generated)"	phoneNumber := something.	self markDirty</body></methods><methods><class-id>Tutorial.TagBrowserApp</class-id> <category>accessing</category><body package="TagBrowser">libraries	tagLibraries ifNil: [self updateLibraryList].	^tagLibraries</body><body package="TagBrowser">libraryName: aValue	selectedLibrary := self libraries detect: [:each | each name = aValue] ifNone: []</body><body package="TagBrowser">selectedLibrary	^selectedLibrary</body></methods><methods><class-id>Tutorial.TagBrowserApp</class-id> <category>actions</category><body package="TagBrowser">updateLibraryList	tagLibraries := WebMVC.TagLibrary allTagDefinitions values asOrderedCollection</body><body package="TagBrowser">viewLibraryFor: aController	^aController findForward: 'success'</body></methods><methods><class-id>Grocery.OrderedItem</class-id> <category>accessing</category><body package="Grocery-Domain">amount	"return the value of the instance variable 'amount' (automatically generated)"	^amount</body><body package="Grocery-Domain">item	"return the value of the instance variable 'item' (automatically generated)"	^item</body></methods><methods><class-id>Grocery.OrderedItem</class-id> <category>initialize / release</category><body package="Grocery-Domain">item: anItem amount: anAmount 	item := anItem.	amount := anAmount.	self markDirty</body></methods><methods><class-id>Grocery.OrderedItem class</class-id> <category>instance creation</category><body package="Grocery-Domain">item: anItem amount: anAmount inTxn: aTransaction    ^(self newInTxn: aTransaction) item: anItem amount: anAmount; yourself</body></methods><methods><class-id>WebMVC.FirstServlet</class-id> <category>servlet api</category><body package="Tutorial">doGet	self doProcessForMethod: 'doGet'</body><body package="Tutorial">doPost	self doProcessForMethod: 'doPost'</body><body package="Tutorial">doProcessForMethod: methodName 	response		write: '&lt;html&gt;&lt;body&gt;';		write: '&lt;h1&gt;' , methodName , '&lt;/h1&gt;';		write: 'Query value: ';		write: (request anyQueryValueAt: 'name');		write: '&lt;br&gt;';		write: 'Form value: ';		write: (request anyFormValueAt: 'name');		write: '&lt;br&gt;';		write: 'Any value: ';		write: (request anyParameterValueAt: 'name');		write: '&lt;br&gt;&lt;br&gt;';		write: 'PATH_INFO: ';		write: request webRequest PATH_INFO;		write: '&lt;br&gt;';		write: 'QUERY_STRING: ';		write: request webRequest QUERY_STRING;		write: '&lt;br&gt;Cookies: '; write: request cookies printString;		write: '&lt;/body&gt;&lt;/html&gt;'</body></methods><methods><class-id>Tutorial.IncrementCommand</class-id> <category>api</category><body package="Tutorial">defaultModelClass	^Counter</body><body package="Tutorial">executeWithModel: aCounter controller: aController	aCounter increment.	^aController findForward: 'success'</body></methods><methods><class-id>Tutorial.SuccessOnlyCommand</class-id> <category>api</category><body package="Tutorial">defaultModelClass	^nil</body><body package="Tutorial">executeWithModel: aCounter controller: aController	^Forwarder fromString: '/login.jsp'</body></methods><methods><class-id>Grocery.ConfirmationRedirectionTag</class-id> <category>api</category><body package="Grocery-Tags">doStartTag	| page |	(self request getParameter: 'username') isNil 		| (self request getParameter: 'requestKey') isNil ifTrue: [^nil].	page := '/shopping/servlet/WebMVCController/Grocery.ConfirmAccount?_WEBMVC_FORMCLASS=Grocery.ConfirmationForm&amp;_WEBMVC_FORMSCOPE=request&amp;_WEBMVC_FORWARD_SUCCESS=/login.jsp&amp;_WEBMVC_FORWARD_FAILURE=/problem.jsp&amp;username='.	page := page , (self request getParameter: 'username') , '&amp;requestKey='.	page := page , (self request getParameter: 'requestKey').	(pageContext getRequestDispatcher: page) forward: pageContext request		response: pageContext response</body></methods><methods><class-id>Grocery.SelectStoreForm</class-id> <category>accessing</category><body package="Grocery-Forms">storeId	^storeId</body><body package="Grocery-Forms">storeId: anObject	storeId := anObject</body></methods><methods><class-id>Grocery.SelectStoreForm class</class-id> <category>field specs</category><body package="Grocery-Forms">storeIdFieldSpec	^FieldSpec name: 'storeId' validator: RequiredFieldValidator new converter: StringConverter new</body></methods><methods><class-id>Grocery.DBManager class</class-id> <category>instance creation</category><body package="Grocery-DB">open	^self new open; yourself</body><body package="Grocery-DB">openSample	^OmniBase openOn: self sampleDatabasePath</body></methods><methods><class-id>Grocery.DBManager class</class-id> <category>sample db</category><body package="Grocery-DB">createAisles	| txn s db |	db := DBManager openSample.	[txn := db newTransaction.	s := Store withId: 'SampleStore' inTxn: txn.	1 to: 5		do: 			[:i | 			| a |			a := Aisle newWithName: 'aisle ' , i printString inTxn: txn.			s addAisle: a].	txn commit] ensure: [db close]</body><body package="Grocery-DB">createSampleDatabase	"self createSampleDatabase"	DBManager createSampleStore.	DBManager createAisles.	DBManager createSections.	DBManager createStockItems.	DBManager createShopper.</body><body package="Grocery-DB">createSampleStore	| db |	self sampleDatabasePath asFilename exists 		ifTrue: [self sampleDatabasePath asFilename recursiveRemove].	db := OmniBase createOn: self sampleDatabasePath.		[| txn |	txn := db newTransaction.	self initIndicesAndCountersIn: txn.	Grocery.Store newWithId: 'SampleStore' name: 'Sample Store (Development Only)' inTxn: txn.	txn commit] 			ensure: [db close]</body><body package="Grocery-DB">createSections	| txn s db |	db := DBManager openSample.	[txn := db newTransaction.	s := Store withId: 'SampleStore' inTxn: txn.	s aisles do: 			[:aisle | 			| section |			1 to: 5				do: 					[:i | 					section := Section 								newWithName: 'section ' , i printString , ' of ' , aisle name inTxn: txn.					aisle addSection: section]].	txn commit] ensure: [db close]</body><body package="Grocery-DB">createShopper	| txn  db |	db := DBManager openSample.	txn := db newTransaction.	[Shopper 		newUser: 'jones'		password: 'test'		contactInfo: Grocery.Test.ShoppingTestResource shopperInfo1		inTxn: txn] 			ensure: [txn commit. db close].</body><body package="Grocery-DB">createStockItems	| txn s db |	db := DBManager openSample.	[txn := db newTransaction.	s := Store withId: 'SampleStore' inTxn: txn.	s aisles do: 			[:aisle | 			aisle sections do: 					[:section | 					| stockItem |					1 to: 5						do: 							[:i | 							stockItem := StockItem 										newWithName: 'stock item ' , i printString , ' in ' , section name , ' of ' 												, aisle name inTxn: txn.							section addItem: stockItem]]].	txn commit] ensure: [db close]</body><body package="Grocery-DB">initIndicesAndCountersIn: txn 	"This method creates primary key index and id counter for persistent instances of Person."	User initDatabaseIn: txn.	StockItem initDatabaseIn: txn.	PersistentCounter resetCaches.	NewUserRequest initDatabaseIn: txn.	Store initDatabaseIn: txn.</body></methods><methods><class-id>Grocery.DBManager class</class-id> <category>constants</category><body package="Grocery-DB">defaultDatabasePath    (OSHandle currentOS = #unix) ifTrue: [        ^ '/tmp/Grocery'    ] ifFalse: [        ^ 'c:\temp\Grocery'    ]</body><body package="Grocery-DB">sampleDatabasePath	^'./sampledb'</body></methods><methods><class-id>Grocery.DBManager class</class-id> <category>root objects</category><body package="Grocery-DB">getRootObject: objectName	objectName = 'users' 		ifTrue: [^User allUsersIn: OmniBase currentTransaction].	objectName = 'stores'		ifTrue: [^Store storesListIn: OmniBase currentTransaction]</body></methods><methods><class-id>Grocery.UnitPrice</class-id> <category>accessing</category><body package="Grocery-Domain">dollars    "return the value of the instance variable 'dollars' (automatically generated)"    ^ dollars</body><body package="Grocery-Domain">dollars: something 	"set the value of the instance variable 'dollars' (automatically generated)"	dollars := something.	self markDirty</body><body package="Grocery-Domain">isInexactUnit    ^inexactUnit isNil        ifTrue: [inexactUnit := false]        ifFalse: [inexactUnit]</body><body package="Grocery-Domain">perUnit    "return the value of the instance variable 'perUnit' (automatically generated)"    ^ perUnit</body><body package="Grocery-Domain">perUnit: something 	"set the value of the instance variable 'perUnit' (automatically generated)"	perUnit := something.	self markDirty</body><body package="Grocery-Domain">unitIsInexact    inexactUnit := true.</body></methods><methods><class-id>Grocery.UnitPrice</class-id> <category>initialize / release</category><body package="Grocery-Domain">dollars: aNumber perUnit: aUnit 	dollars := aNumber.	perUnit := aUnit.	self markDirty</body></methods><methods><class-id>Grocery.UnitPrice class</class-id> <category>instance creation</category><body package="Grocery-Domain">dollars: aNumber perUnit: aUnit    ^self new dollars: aNumber perUnit: aUnit; yourself</body><body package="Grocery-Domain">dollarsPerPackage: aNumber    ^self dollars: aNumber perUnit: self packageUnit</body><body package="Grocery-Domain">dollarsPerPound: aNumber    ^(self dollars: aNumber perUnit: self poundUnit) unitIsInexact; yourself</body></methods><methods><class-id>Grocery.UnitPrice class</class-id> <category>constants</category><body package="Grocery-Domain">packageUnit    ^'pkg'</body><body package="Grocery-Domain">poundUnit    ^'Lb'</body></methods><methods><class-id>Grocery.NewUserRequest</class-id> <category>accessing</category><body package="Grocery-Domain">requestKey	^requestKey</body><body package="Grocery-Domain">requestKey: anObject	requestKey := anObject.	self markDirty</body><body package="Grocery-Domain">user	^user</body><body package="Grocery-Domain">user: anObject	user := anObject.	self markDirty</body></methods><methods><class-id>Grocery.NewUserRequest</class-id> <category>removing</category><body package="Grocery-Domain">confirmed	self user activate.	self removeIn: OmniBase currentTransaction</body><body package="Grocery-Domain">removeIn: aTransaction 	"Remove me from the list"	| l |	l := self class userRequestListIn: aTransaction.	(self class 		lock: l		in: aTransaction		orGiveUpInMilliseconds: 1000) 			ifFalse: [self error: 'couldn''t lock request list'].	l remove: self.	aTransaction markDirty: l</body></methods><methods><class-id>Grocery.NewUserRequest class</class-id> <category>master collection</category><body package="Grocery-Domain">initDatabaseIn: txn 	"This method creates the master collection of new user requests."	(txn root)		at: 'list.NewUserRequest' put: OrderedCollection new</body><body package="Grocery-Domain">userRequestListIn: aTransaction 	^aTransaction root at: 'list.NewUserRequest'</body></methods><methods><class-id>Grocery.NewUserRequest class</class-id> <category>instance creation</category><body package="Grocery-Domain">newRequestFor: user requestKey: key in: aTransaction 	| instance l |	l := self userRequestListIn: aTransaction.	(self 		lock: l		in: aTransaction		orGiveUpInMilliseconds: 1000) 			ifFalse: [self error: 'Unable to lock request list'].	instance := self newInTxn: aTransaction.	instance user: user.	instance requestKey: key.	l add: instance.	aTransaction markDirty: l.	^instance</body></methods><methods><class-id>Grocery.Order</class-id> <category>initialize-release</category><body package="Grocery-Domain">initialize	super initialize.	complete := false.	^self</body></methods><methods><class-id>Grocery.Order</class-id> <category>shopping</category><body package="Grocery-Domain">completeOrder	complete := true.	self shopper checkoutCompleteForOrder: self.	self markDirty</body></methods><methods><class-id>Grocery.Order</class-id> <category>accessing</category><body package="Grocery-Domain">isComplete	"return the value of the instance variable 'complete' (automatically generated)"	^complete</body><body package="Grocery-Domain">orderedItems	^orderedItems ifNil: 			[orderedItems := OrderedCollection new.			self markDirty.			orderedItems].</body><body package="Grocery-Domain">shopper	"return the value of the instance variable 'shopper' (automatically generated)"	^shopper</body><body package="Grocery-Domain">shopper: something 	"set the value of the instance variable 'shopper' (automatically generated)"	shopper := something.	self markDirty</body></methods><methods><class-id>Grocery.Order</class-id> <category>items</category><body package="Grocery-Domain">addAllItems: aCollection 	self orderedItems addAll: aCollection.	self markDirty</body></methods><methods><class-id>Grocery.Order class</class-id> <category>instance creation</category><body package="Grocery-Domain">newForShopper: aShopper withItems: aCollection    ^self new shopper: aShopper; addAllItems: aCollection; yourself</body><body package="Grocery-Domain">newForShopper: aShopper withItems: aCollection inTxn: aTransaction    ^(self newInTxn: aTransaction) shopper: aShopper; addAllItems: aCollection; yourself</body></methods><methods><class-id>Grocery.Test.InertCustomer</class-id> <category>orders</category><body package="Grocery-Tests">addOrder: anOrder	self orders add: anOrder</body><body package="Grocery-Tests">addToFirstOrder: anOrderedItem	self orders first addItem: anOrderedItem</body></methods><methods><class-id>Grocery.Test.InertCustomer</class-id> <category>accessing</category><body package="Grocery-Tests">orders	^orders isNil ifTrue: [orders := OrderedCollection new] ifFalse: [orders]</body></methods><methods><class-id>Grocery.User</class-id> <category>accessing</category><body package="Grocery-Domain">activate	active := true.	self markDirty</body><body package="Grocery-Domain">deactivate	active := false.	self markDirty</body><body package="Grocery-Domain">id	"return the value of the instance variable 'id' (automatically generated)"	^id</body><body package="Grocery-Domain">id: something 	id = something 		ifFalse: 			[self markDirty.			self updateIndexesFor: [id := something]]</body><body package="Grocery-Domain">isActive	^active		ifNil: [active := false]</body><body package="Grocery-Domain">password	"return the value of the instance variable 'password' (automatically generated)"	^password</body><body package="Grocery-Domain">password: something 	"set the value of the instance variable 'password' (automatically generated)"	password := something.	self markDirty</body><body package="Grocery-Domain">username	"return the value of the instance variable 'username' (automatically generated)"	^username</body><body package="Grocery-Domain">username: something 	"set the value of the instance variable 'username' (automatically generated)"	username = something 		ifFalse: 			[self markDirty.			self updateIndexesFor: [username := something]]</body></methods><methods><class-id>Grocery.User</class-id> <category>password</category><body package="Grocery-Domain">validatePassword: anAttempt 	"answer true if I am an active user and anAttempt is a valid password, false otherwise"	^self password = anAttempt &amp; self isActive</body></methods><methods><class-id>Grocery.User</class-id> <category>private</category><body package="Grocery-Domain">odbMadePersistentIn: anOmniBaseTransaction 	"Private - This method is sent when the object is made persistent."	| index |	super odbMadePersistentIn: anOmniBaseTransaction.	id notNil 		ifTrue: 			[index := self class primaryKeyIndexIn: anOmniBaseTransaction.			(index includesKey: id) 				ifTrue: [self error: 'Primary key is already taken by another object'].			index at: id put: self].	"update also its name index"	(id notNil and:  [self usernameIndexKey notNil])		ifTrue: 			[(self class usernameIndexIn: self transaction) at: self usernameIndexKey put: self]</body></methods><methods><class-id>Grocery.User</class-id> <category>managing indices</category><body package="Grocery-Domain">updateIndexesFor: aBlock 	"This method will remember old index values, evaluate aBlock and                 in case that index values have changed it will update all indexes that                 need to be updated."	"ignore indexes if object is transient"	| oldId oldName newValue index |	transaction isNil ifTrue: [^aBlock value].	"get old index values"	oldId := id.	oldName := oldId isNil ifTrue: [nil] ifFalse: [self usernameIndexKey].	"evaluate aBlock which will change attribute values"	aBlock value.	"check if primary key index needs to be updated"	id = oldId 		ifFalse: 			[index := self class primaryKeyIndexIn: transaction.			oldId notNil ifTrue: [index removeKey: oldId].			id notNil 				ifTrue: 					[(index includesKey: id) 						ifTrue: [self error: 'Primary key is already taken by another object'].					index at: id put: self]].	"check if name index needs to be updated"	(newValue := self usernameIndexKey) = oldName 		ifFalse: 			[index := self class usernameIndexIn: transaction.			oldName isNil ifFalse: [index removeKey: oldName].			newValue isNil ifFalse: [index at: newValue put: self]]</body><body package="Grocery-Domain">usernameIndexKey	"Private - Answer the secondary key size for name."	| name |	name := username asBtreeKeyOfSize: 30.	^name</body></methods><methods><class-id>Grocery.User</class-id> <category>printing</category><body package="Grocery-Domain">printOn: aStream 	super printOn: aStream.	username ifNotNil: 			[aStream nextPut: $&lt;.			aStream nextPutAll: self username.			aStream nextPut: $&gt;]</body></methods><methods><class-id>Grocery.User class</class-id> <category>managing indices</category><body package="Grocery-Domain">allUsersIn: aTransaction 	| idx result assoc |	idx := self primaryKeyIndexIn: aTransaction.	result := OrderedCollection new.	assoc := idx getFirst.	[assoc notNil] whileTrue: [result add: assoc value. assoc := idx getNext].	^result</body><body package="Grocery-Domain">deleteByUsername: username in: t	| u idx |	u := self findByUsername: username in: t.	u ifNil: [^nil].	idx := self primaryKeyIndexIn: t.	idx removeKey: u id.	idx := self usernameIndexIn: t.	idx removeKey: u username</body><body package="Grocery-Domain">findById: anInteger in: aTransaction 	"Answer an instance of person with id anInteger or &lt;nil&gt; if not found.      The answered object will be fetcher in the given transaction."	^(self primaryKeyIndexIn: aTransaction) at: anInteger ifAbsent: []</body><body package="Grocery-Domain">findByUsername: aString in: aTransaction 	^(self usernameIndexIn: aTransaction) at: aString ifAbsent: []</body><body package="Grocery-Domain">getNewIdForDB: aDatabase 	"Get new unique StockItem identifier. Try to lock the counter first to ensure      that nobody else can get the same identifier. Waits until the lock is obtained."	^PersistentCounter getNewValueFor: 'counter.User'		inDatabase: aDatabase</body><body package="Grocery-Domain">initDatabaseIn: txn 	"This method creates primary key index and id counter for persistent instances of Person."	(txn root)		at: 'counter.User' put: PersistentCounter new;		at: 'index.User' put: (OmniBase newBTreeDictionary: 10);		at: 'index.User.username' put: (OmniBase newBTreeDictionary: 30)</body><body package="Grocery-Domain">load: aUser inTransaction: aTransaction	"Used to get a new copy of the supplied object in the specified transaction"	^self findById: aUser id in: aTransaction</body><body package="Grocery-Domain">primaryKeyIndexIn: aTransaction 	^aTransaction root at: 'index.User'</body><body package="Grocery-Domain">usernameIndexIn: aTransaction 	^aTransaction root at: 'index.User.username'</body></methods><methods><class-id>Grocery.User class</class-id> <category>instance creation</category><body package="Grocery-Domain">newUser: username password: password contactInfo: contactInfo 	| instance |	instance := self new.	instance username: username.	instance password: password.	instance contactInfo: contactInfo.	^instance</body><body package="Grocery-Domain">newUser: username password: password contactInfo: contactInfo inTxn: aTransaction	| instance |	instance := self newInTxn: aTransaction.	instance username: username.	instance password: password.	instance contactInfo: contactInfo.	instance id: (self getNewIdForDB: aTransaction environment).	^instance</body></methods><methods><class-id>Grocery.Shopper</class-id> <category>accessing</category><body package="Grocery-Domain">cart	^cart</body><body package="Grocery-Domain">cart: something 	cart := something.	self markDirty</body><body package="Grocery-Domain">contactInfo    "return the value of the instance variable 'contactInfo' (automatically generated)"    ^ contactInfo</body><body package="Grocery-Domain">contactInfo: something 	contactInfo := something.	self markDirty</body><body package="Grocery-Domain">currentStore	^self cart		ifNotNil: [self cart store]		ifNil: [self defaultStore]</body><body package="Grocery-Domain">defaultStore    "return the value of the instance variable 'defaultStore' (automatically generated)"    ^ defaultStore</body><body package="Grocery-Domain">defaultStore: something 	defaultStore := something.	self markDirty</body><body package="Grocery-Domain">shoppingLists	^shoppingLists ifNil: 			[shoppingLists := OrderedCollection new.			self markDirty.			shoppingLists]</body></methods><methods><class-id>Grocery.Shopper</class-id> <category>shopping</category><body package="Grocery-Domain">checkoutCompleteForOrder:anOrder     ^ self cart checkoutComplete</body><body package="Grocery-Domain">enterStore: aStore    self cart moveToStore: aStore</body><body package="Grocery-Domain">purchaseItem: item amount: amount 	"If the shopper has already purchased this item, the new order superceeds it"	(self cart containsItem: item) ifTrue: [self cart removeItem: item].	self cart acceptItem: item amount: amount</body></methods><methods><class-id>Grocery.Shopper</class-id> <category>shopping lists</category><body package="Grocery-Domain">newShoppingListNamed: aString 	"answers the ShoppingList that was added"	| result |	result := self shoppingLists add: (ShoppingList newWithName: aString inTxn: self transaction).	self markDirty.	^result</body><body package="Grocery-Domain">shoppingListNamed: aName    ^self shoppingLists detect: [ :list | list name = aName] ifNone: []</body></methods><methods><class-id>Grocery.Shopper</class-id> <category>initialize / release</category><body package="Grocery-Domain">createCart	cart := ShoppingCart newForShopper: self inTxn: self transaction.	self markDirty</body><body package="Grocery-Domain">createCartInStore: aStore 	self createCart.	cart store: aStore</body></methods><methods><class-id>Grocery.Shopper class</class-id> <category>instance creation</category><body package="Grocery-Domain">newUser: username password: password contactInfo: contactInfo 	| instance |	instance := super newUser: username password: password contactInfo: contactInfo.	instance createCartInStore: nil.	^instance</body><body package="Grocery-Domain">newUser: username password: password contactInfo: contactInfo inTxn: aTransaction	| instance |	instance := super newUser: username password: password contactInfo: contactInfo inTxn: aTransaction.	instance createCartInStore: nil.	^instance</body></methods><methods><class-id>Grocery.Store</class-id> <category>accessing</category><body package="Grocery-Domain">administrators	^administrators ifNil: 			[administrators := OrderedCollection new.			self markDirty.			administrators]</body><body package="Grocery-Domain">aisles	^aisles ifNil: 			[aisles := OrderedCollection new.			self markDirty.			aisles]</body><body package="Grocery-Domain">id    "return the value of the instance variable 'id' (automatically generated)"    ^ id</body><body package="Grocery-Domain">id: something 	"set the value of the instance variable 'id' (automatically generated)"	id := something.	self markDirty</body><body package="Grocery-Domain">name	^name</body><body package="Grocery-Domain">name: something 	name := something.	self markDirty</body></methods><methods><class-id>Grocery.Store</class-id> <category>administrators</category><body package="Grocery-Domain">addAdministrator: aStoreAdministrator 	self administrators add: aStoreAdministrator.</body><body package="Grocery-Domain">administratorWithUsername: aUsername    ^self administrators detect: [:each | each username = aUsername] ifNone: []</body></methods><methods><class-id>Grocery.Store</class-id> <category>items</category><body package="Grocery-Domain">stockItems    ^(self aisles collect: [ :aisle | aisle items ]) flatten</body></methods><methods><class-id>Grocery.Store</class-id> <category>categories</category><body package="Grocery-Domain">addAisle: anAisle 	self aisles add: anAisle.	self markDirty</body><body package="Grocery-Domain">specials	^specials ifNil: 			[specials := OrderedCollection new.			self markDirty.			specials]</body></methods><methods><class-id>Grocery.Store class</class-id> <category>instance creation</category><body package="Grocery-Domain">newWithId: aString name: aName    ^self new name: aName; id: aString; yourself</body><body package="Grocery-Domain">newWithId: aString name: aName inTxn: aTransaction 	| instance l |	l := self storesListIn: aTransaction.	(self 		lock: l		in: aTransaction		orGiveUpInMilliseconds: 1000) 			ifFalse: [self error: 'Unable to lock request list'].	instance := (self newInTxn: aTransaction)				name: aName;				id: aString;				yourself.	aTransaction ifNotNil: [aTransaction root at: aString put: instance].	l add: instance.	aTransaction markDirty: l.	^instance</body></methods><methods><class-id>Grocery.Store class</class-id> <category>accessing</category><body package="Grocery-Domain">withId: aName inTxn: aTransaction	^aTransaction root at: aName</body></methods><methods><class-id>Grocery.Store class</class-id> <category>master collection</category><body package="Grocery-Domain">initDatabaseIn: txn 	"This method creates the master collection of new user requests."	(txn root)		at: 'list.Stores' put: OrderedCollection new</body><body package="Grocery-Domain">load: aStore inTransaction: aTransaction	"Used to get a new copy of the supplied object in the specified transaction"	^(self storesListIn: aTransaction) detect: [ :each | each id = aStore id] ifNone: []</body><body package="Grocery-Domain">storesListIn: aTransaction 	^aTransaction root at: 'list.Stores'</body></methods><methods><class-id>Grocery.Test.OmniBaseAssumptionTest</class-id> <category>accessing</category><body package="Grocery-Tests">defaultDatabasePath	OSHandle currentOS = #unix 		ifTrue: [^'/tmp/Grocery-test']		ifFalse: [^'c:\temp\Grocery-test']</body></methods><methods><class-id>Grocery.Test.OmniBaseAssumptionTest</class-id> <category>tests</category><body package="Grocery-Tests">test1	"Notice that if I don't makePersistent: to the orders collection then I can't mark it dirty later (since it is considered a composite object)"	| db customer |	db := OmniBase createOn: self defaultDatabasePath.		[	[customer := InertCustomer new.	OmniBase currentTransaction root at: 'customer' put: customer.	customer addOrder: InertOrder new] 			evaluateAndCommitIn: db newTransaction.	"this order won't be saved b/c the collection was not marked dirty"		[customer := OmniBase currentTransaction root at: 'customer'.	customer addOrder: InertOrder new] 			evaluateAndCommitIn: db newTransaction.		[customer := OmniBase currentTransaction root at: 'customer'.	self assert: customer orders size = 1] 			evaluateAndCommitIn: db newTransaction.		[customer := OmniBase currentTransaction root at: 'customer'.	customer addOrder: InertOrder new.	OmniBase currentTransaction markDirty: customer] 			evaluateAndCommitIn: db newTransaction.		[customer := OmniBase currentTransaction root at: 'customer'.	self assert: customer orders size = 2] 			evaluateAndCommitIn: db newTransaction] 			ensure: [db close]</body><body package="Grocery-Tests">test2	"Notice here that I use a composite object (the orders collection is not separate from the customer)"	| db customer |	db := OmniBase createOn: self defaultDatabasePath.		[	[customer := InertCustomer new.	OmniBase currentTransaction root at: 'customer' put: customer.	customer addOrder: InertOrder new] 			evaluateAndCommitIn: db newTransaction.	"this order won't be saved b/c the collection was not marked dirty"		[customer := OmniBase currentTransaction root at: 'customer'.	customer addOrder: InertOrder new] 			evaluateAndCommitIn: db newTransaction.		[customer := OmniBase currentTransaction root at: 'customer'.	self assert: customer orders size = 1] 			evaluateAndCommitIn: db newTransaction.		[customer := OmniBase currentTransaction root at: 'customer'.	customer addOrder: InertOrder new.	customer markDirty] 			evaluateAndCommitIn: db newTransaction.		[customer := OmniBase currentTransaction root at: 'customer'.	self assert: customer orders size = 2] 			evaluateAndCommitIn: db newTransaction] 			ensure: [db close]</body><body package="Grocery-Tests">test3	"Object identity test"	| db customer order item orderedItem |	db := OmniBase createOn: self defaultDatabasePath.		[	[customer := InertCustomer new.	customer orders.	"force creation of collection"	OmniBase currentTransaction root at: 'customer' put: customer] 			evaluateAndCommitIn: db newTransaction.		[customer := OmniBase currentTransaction root at: 'customer'.	order := InertOrder newPersistent.	"if this is just new then we get error"	item := InertItem newPersistent.	orderedItem := InertOrderedItem newPersistent.	"if this is just new then we get error"	orderedItem item: item.	orderedItem markDirty.	order addItem: orderedItem.	order markDirty.	customer addOrder: order.	customer markDirty.	self assert: customer orders first == order.	self assert: customer orders first items first item == item] 			evaluateAndCommitIn: db newTransaction.		[customer := OmniBase currentTransaction root at: 'customer'.	order := customer orders first.	item := order items first.	orderedItem := InertOrderedItem newPersistent.	orderedItem item: item.	orderedItem markDirty.	self assert: (customer orders first isIdenticalTo: customer orders first).	" using = these might be different "	customer addToFirstOrder: orderedItem.	self assert: (order items at: 2) item == item] 			evaluateAndCommitIn: db newTransaction] 			ensure: [db close]</body></methods><methods><class-id>Grocery.Test.OmniBaseAssumptionTest</class-id> <category>Running</category><body package="Grocery-Tests">setUp	self defaultDatabasePath asFilename exists 		ifTrue: [self defaultDatabasePath asFilename recursiveRemove].</body></methods><methods><class-id>Grocery.ShoppingCart</class-id> <category>shopping</category><body package="Grocery-Domain">acceptItem: anItem amount: amount 	self acceptOrderedItem: (OrderedItem 				item: anItem				amount: amount				inTxn: self transaction)</body><body package="Grocery-Domain">acceptOrderedItem: anOrderedItem 	self store isNil ifTrue: [self error: 'store not set yet'].	orderedItems add: anOrderedItem.	self markDirty</body><body package="Grocery-Domain">amountOrderedOfItem: anItem 	^self orderedItems inject: 0		into: 			[:sum :orderedItem | 			orderedItem item = anItem ifTrue: [sum + orderedItem amount] ifFalse: [sum]]</body><body package="Grocery-Domain">checkoutComplete	^self removeAllItems</body><body package="Grocery-Domain">containsItem: anItem 	^self orderedItems anySatisfy: [:orderedItem | orderedItem item = anItem]</body><body package="Grocery-Domain">createOrderForItems	^Order 		newForShopper: self shopper		withItems: self orderedItems		inTxn: self transaction</body><body package="Grocery-Domain">moveToStore: aStore 	store = aStore ifFalse: [self initOrderedItems].	store := aStore</body><body package="Grocery-Domain">removeItem: anItem 	| orderedItem |	orderedItem := self orderedItems detect: [:i | i item = anItem] ifNone: [].	orderedItem notNil 		ifTrue: 			[self orderedItems remove: orderedItem.			self markDirty]</body></methods><methods><class-id>Grocery.ShoppingCart</class-id> <category>private</category><body package="Grocery-Domain">removeAllItems	self initOrderedItems</body></methods><methods><class-id>Grocery.ShoppingCart</class-id> <category>accessing</category><body package="Grocery-Domain">orderedItems	"return the value of the instance variable 'orderedItems' (automatically generated)"	^orderedItems</body><body package="Grocery-Domain">shopper	"return the value of the instance variable 'shopper' (automatically generated)"	^shopper</body><body package="Grocery-Domain">store	"return the value of the instance variable 'store' (automatically generated)"	^store</body><body package="Grocery-Domain">store: something 	store := something.	self markDirty</body></methods><methods><class-id>Grocery.ShoppingCart</class-id> <category>initialize / release</category><body package="Grocery-Domain">initOrderedItems	orderedItems := OrderedCollection new.	self markDirty</body><body package="Grocery-Domain">initShopper: aShopper 	shopper := aShopper.	self initOrderedItems</body></methods><methods><class-id>Grocery.ShoppingCart class</class-id> <category>instance creation</category><body package="Grocery-Domain">newForShopper: aShopper inTxn: aTransaction    |instance|    instance := self newInTxn: aTransaction.    instance initShopper: aShopper.    ^instance</body></methods><methods><class-id>Grocery.Test.InertItem</class-id> <category>accessing</category><body package="Grocery-Tests">description	^description</body><body package="Grocery-Tests">description: anObject	description := anObject</body></methods><methods><class-id>Grocery.DatabaseCommand</class-id> <category>private</category><body package="Grocery-Form Actions">userExists: aUsername	^(self userWithUsername: aUsername) notNil</body><body package="Grocery-Form Actions">userWithUsername: aString	^User findByUsername: aString in: OmniBase currentTransaction</body></methods><methods><class-id>Grocery.DatabaseCommand</class-id> <category>database</category><body package="Grocery-Form Actions">closeDatabase	db ifNotNil: [db close. db := nil]</body><body package="Grocery-Form Actions">executeInTransaction: aBlock 	^self 		executeWithDatabase: [aBlock evaluateIn: db newTransaction]</body><body package="Grocery-Form Actions">executeWithDatabase: aBlock	db := DBManager openSample.	^[aBlock value] ensure: [db close]</body><body package="Grocery-Form Actions">newTransaction	db ifNil: [self openDatabase].	^db newTransaction</body><body package="Grocery-Form Actions">openDatabase	self closeDatabase.	db := Grocery.DBManager openSample</body></methods><methods><class-id>Grocery.SelectStoreCommand</class-id> <category>api</category><body package="Grocery-Form Actions">defaultModelClass	^SelectStoreForm</body><body package="Grocery-Form Actions">executeWithModel: model controller: aController	self executeInTransaction:		[|store user|		store := Store withId: model storeId inTxn: OmniBase currentTransaction.		store ifNil: [^aController findForward: 'failure'].		user := (aController session at: 'user') value.		user enterStore: store.		user defaultStore ifNil: [user defaultStore: store].		aController session at: 'store' put: (PersistentObjectHolder withValue: store).		OmniBase commit.		^aController findForward: 'success']</body></methods><methods><class-id>Grocery.CreateAccount</class-id> <category>api</category><body package="Grocery-Form Actions">executeWithModel: model controller: aController 	self executeInTransaction: 			[| request |			(self userExists: model emailAddress) 				ifTrue: 					[aController addError: (GenericError 								withMessage: 'A user with this email address already exists.').					^aController findForward: 'failure'].			request := self makeUserFromFormModel: model.			[self sendConfirmationEMailForRequest: request] on: Net.SMTPError				do: 					[:ex | 					OmniBase rollback.					aController addError: (GenericError 								withMessage: 'An error occurred while sending an e-mail to the address that you specified.').					^aController findForward: 'startover'].			OmniBase commit.			aController removeModel.			^aController findForward: 'success']</body><body package="Grocery-Form Actions">makeUserFromFormModel: form	| ci u |	ci := ShopperContactInfo newInTxn: OmniBase currentTransaction.	ci name: form lastName , ', ' , form firstName.	ci 		address: form street , (String with: Character cr) , form city , ' ' 				, form state , ' ' 				, form zip.	ci emailAddress: form emailAddress.	u := Shopper 				newUser: form emailAddress				password: form password1				contactInfo: ci				inTxn: OmniBase currentTransaction.	u deactivate.	^NewUserRequest newRequestFor: u requestKey: 'abcdefg' in: OmniBase currentTransaction</body></methods><methods><class-id>Grocery.CreateAccount</class-id> <category>email</category><body package="Grocery-Form Actions">sendConfirmationEMailForRequest: aRequest	| mm s |	mm := Net.MailMessage newTextPlain.	mm text: 'url is http://localhost:8008/shopping/servlet/WebMVCController/Grocery.ConfirmAccount?username=' , aRequest user username , '&amp;requestKey=' , aRequest requestKey.	mm from: 'cdshaffer@acm.org'.	s := Net.SimpleSMTPClient new.	s hostName: 'localhost'.	s sendMessage: mm toAll: (Array with: aRequest user contactInfo emailAddress)</body></methods><methods><class-id>Grocery.ConfirmAccount</class-id> <category>api</category><body package="Grocery-Form Actions">confirmCreation: formData 	self executeInTransaction: 			[| user request |			user := self userWithUsername: formData username.			user ifNil: [^false].			request := (NewUserRequest userRequestListIn: OmniBase currentTransaction) 						detect: [:each | each user = user]						ifNone: [].			request ifNil: [^false].			^request requestKey = formData requestKey 				ifTrue: 					[request confirmed.					OmniBase commit.					true]				ifFalse: [false]]</body><body package="Grocery-Form Actions">defaultModelClass	^ConfirmationForm</body><body package="Grocery-Form Actions">executeWithModel: model controller: aController 	(self confirmCreation: model) 		ifFalse: 			[aController addError: (GenericError 						withMessage: 'An error occurred activating your account.  Please contact the system adminstrators for further assistance.').			^aController findForward: 'failure'].	^Forwarder fromString: '/shopping/confirmationForwarder.jsp'</body></methods><methods><class-id>Grocery.CreateAccountStep1</class-id> <category>api</category><body package="Grocery-Form Actions">executeWithModel: model controller: aController 	self executeInTransaction: 			[(self userExists: model emailAddress) 				ifTrue: 					[aController addError: (GenericError 								withMessage: 'A user with this email address already exists').					^aController findForward: 'failure']].	^aController findForward: 'success'</body></methods><methods><class-id>Grocery.LoginCommand</class-id> <category>api</category><body package="Grocery-Form Actions">defaultModelClass	^LoginForm</body><body package="Grocery-Form Actions">executeWithModel: theModel controller: aController 	"Change to store current user instead of current user name"	model := theModel.	^self executeWithDatabase: [self privateExecuteFor: aController]</body></methods><methods><class-id>Grocery.LoginCommand</class-id> <category>accessing</category><body package="Grocery-Form Actions">formModel	^model</body></methods><methods><class-id>Grocery.LoginCommand</class-id> <category>private</category><body package="Grocery-Form Actions">privateExecuteFor: aController 	^	[self validateLoginData 		ifTrue: 			[aController session at: 'user'				put: (PersistentObjectHolder withValue: user).			user currentStore ifNotNil: 					[aController session at: 'store'						put: (PersistentObjectHolder withValue: user currentStore).					aController findForward: 'hasStore']				ifNil: [aController findForward: 'needsStore']]		ifFalse: 			[aController addError: LoginError new.			aController findForward: 'failure']] 			evaluateIn: db newReadOnlyTransaction</body><body package="Grocery-Form Actions">validateLoginData	| un pw |	un := self formModel username.	pw := self formModel password.	(un isNil | pw isNil or: [un isEmpty | pw isEmpty]) ifTrue: [^false].	user := self userWithUsername: self formModel username.	^user notNil and: [user validatePassword: pw].</body></methods><methods><class-id>Grocery.ConfirmationForm</class-id> <category>accessing</category><body package="Grocery-Forms">requestKey	^requestKey</body><body package="Grocery-Forms">requestKey: anObject	requestKey := anObject</body><body package="Grocery-Forms">username	^username</body><body package="Grocery-Forms">username: anObject	username := anObject</body></methods><methods><class-id>Grocery.ConfirmationForm class</class-id> <category>field specs</category><body package="Grocery-Forms">requestKeyFieldSpec	^FieldSpec name: 'requestKey' validator: RequiredFieldValidator new converter: StringConverter new</body><body package="Grocery-Forms">usernameFieldSpec	^FieldSpec name: 'username' validator: RequiredFieldValidator new converter: StringConverter new</body></methods><methods><class-id>Tutorial.Address</class-id> <category>initialize-release</category><body package="Tutorial">initialize	city := 'Toronto'.	street := 'Nowhere lane'.	^self</body></methods><methods><class-id>Tutorial.Address</class-id> <category>accessing</category><body package="Tutorial">city	^city</body><body package="Tutorial">city: anObject	city := anObject</body><body package="Tutorial">state	^state</body><body package="Tutorial">state: anObject	state := anObject</body><body package="Tutorial">street	^street</body><body package="Tutorial">street: anObject	street := anObject</body><body package="Tutorial">zip	^zip</body><body package="Tutorial">zip: anObject	zip := anObject</body></methods><methods><class-id>Tutorial.Address class</class-id> <category>instance creation</category><body package="Tutorial">new	^super new initialize</body></methods><methods><class-id>Grocery.StockItem</class-id> <category>accessing</category><body package="Grocery-Domain">description    "return the value of the instance variable 'description' (automatically generated)"    ^ description</body><body package="Grocery-Domain">description: something 	"set the value of the instance variable 'description' (automatically generated)"	description := something.	self markDirty</body><body package="Grocery-Domain">id    "return the value of the instance variable 'id' (automatically generated)"    ^ id</body><body package="Grocery-Domain">id: anInteger 	"Setter method for instance variable id (also primary key attribute in case the object is persistent).     Since this object can be either persistent or transient this method will inform transaction that the      object has been changed and update its primary key index dictionary."	id = anInteger 		ifFalse: 			[self markDirty.			self updateIndexesFor: [id := anInteger]]</body><body package="Grocery-Domain">name    "return the value of the instance variable 'name' (automatically generated)"    ^ name</body><body package="Grocery-Domain">name: something 	"set the value of the instance variable 'name' (automatically generated)"	name := something.	self markDirty</body><body package="Grocery-Domain">unitPrice    "return the value of the instance variable 'unitPrice' (automatically generated)"    ^ unitPrice</body><body package="Grocery-Domain">unitPrice: something 	"set the value of the instance variable 'unitPrice' (automatically generated)"	unitPrice := something.	self markDirty</body></methods><methods><class-id>Grocery.StockItem</class-id> <category>managing indices</category><body package="Grocery-Domain">updateIndexesFor: aBlock     "This method will remember old index values, evaluate aBlock and     in case that index values have changed it will update all indexes that     need to be updated."    |oldId index |    transaction isNil ifTrue: [        ^ aBlock value    ]"get old index values".    oldId := id.    aBlock value.    "evaluate aBlock which will change attribute values"    id = oldId ifFalse: [        index := self class primaryKeyIndexIn: transaction.        oldId notNil ifTrue: [            index removeKey: oldId        ].        id notNil ifTrue: [            (index includesKey: id) ifTrue: [                self error: 'Primary key is already taken by another object'            ].            index at: id put: self.        ]    ]</body></methods><methods><class-id>Grocery.StockItem</class-id> <category>private</category><body package="Grocery-Domain">odbMadePersistentIn: anOmniBaseTransaction     "Private - This method is sent when the object is made persistent."    |index|    super odbMadePersistentIn: anOmniBaseTransaction.    id notNil ifTrue: [        index := self class primaryKeyIndexIn: anOmniBaseTransaction.        (index includesKey: id) ifTrue: [            self error: 'Primary key is already taken by another object'        ].        index at: id put: self.    ]</body></methods><methods><class-id>Grocery.StockItem class</class-id> <category>instance creation</category><body package="Grocery-Domain">newWithName: aName    ^self new name: aName; yourself</body><body package="Grocery-Domain">newWithName: aName inTxn: aTransaction 	| instance |	instance := (self newInTxn: aTransaction)				name: aName;				yourself.	instance id: (self getNewIdForDB: aTransaction environment).	^instance</body></methods><methods><class-id>Grocery.StockItem class</class-id> <category>indices</category><body package="Grocery-Domain">findById: anInteger in: aTransaction 	"Answer an instance of StockItem with id anInteger or &lt;nil&gt; if not found."	^(self primaryKeyIndexIn: aTransaction) at: anInteger ifAbsent: []</body><body package="Grocery-Domain">getNewIdForDB: aDatabase 	"Get new unique StockItem identifier. Try to lock the counter first to ensure      that nobody else can get the same identifier. Waits until the lock is obtained."	^PersistentCounter getNewValueFor: 'counter.StockItem'		inDatabase: aDatabase</body><body package="Grocery-Domain">initDatabaseIn: txn 	(txn root)		at: 'counter.StockItem' put: PersistentCounter new;		at: 'index.StockItem' put: (OmniBase newBTreeDictionary: 10)</body><body package="Grocery-Domain">primaryKeyIndexIn: aTransaction 	^aTransaction root at: 'index.StockItem'</body></methods><methods><class-id>Net.SimpleSMTPClient</class-id> <category>private</category><body package="Grocery-Extensions">serverErrorCheck	"Raise an error if the last response from the SMTP server has an error."		| replyCode |	replyCode := (self serverResponse copyUpTo: Character space) asNumber.	replyCode &gt;= 500 ifTrue: 		[^SMTPError new raiseSignal: ('SMTP Error &lt;1s&gt;' expandMacrosWith: self serverResponse)].</body></methods><methods><class-id>Core.Collection</class-id> <category>cds extensions</category><body package="Grocery-Extensions">flatten	| c |	c := OrderedCollection new.	self flattenInto: c.	^self species withAll: c</body><body package="Grocery-Extensions">flattenInto: aCollection	self do: [ :each |		each isSequenceable			ifTrue: [ each flattenInto: aCollection ]			ifFalse: [ aCollection add: each ]]</body></methods><methods><class-id>Core.CharacterArray</class-id> <category>auto complete</category><body package="Grocery-Extensions">startsWith: aPrefixString 	| sz |	sz := aPrefixString size.	self size &gt; sz ifFalse: [^false].	1 to: sz do: [:i | (self at: i)			= (aPrefixString at: i) ifFalse: [^false]].	^true</body></methods><methods><class-id>Core.Object</class-id> <category>webmvc extensions</category><body package="Grocery-Extensions">needsWork: anObject	"Just a marker for methods which need work"</body></methods><methods><class-id>OS.Filename</class-id> <category>cds extensions</category><body package="Grocery-Extensions">recursiveRemove	self isDirectory 		ifTrue: 			[self directoryContents 				do: [:each | (self construct: each) recursiveRemove]].	self delete</body></methods><methods><class-id>Grocery.SessionTag</class-id> <category>jsp accessing</category><body package="Grocery-Tags">setNeeds: aString	"Since the needs parameter may occur multiple times, we add it to our list each time this method is invoked"	&lt;required: false description: 'root object needed for this session (tag may appear multiple times)'&gt;	self needsList add: aString</body><body package="Grocery-Tags">setRequireUser: aString	&lt;required: false description: 'wildcard pattern for username required to use this form (failure of current user to match this causes redirection to the login form'&gt;	requiredUserPattern := aString</body></methods><methods><class-id>Grocery.SessionTag class</class-id> <category>pragma</category><body package="Grocery-Tags">tagDefinition	&lt;tagLibrary: 'grocery.tld' name: 'session' bodyContent: 'JSP'&gt;</body></methods><methods><class-id>Grocery.UserList class</class-id> <category>interface specs</category><body package="Grocery-Tools">windowSpec	"Tools.UIPainter new openOnClass: self andSelector: #windowSpec"	&lt;resource: #canvas&gt;	^#(#{UI.FullSpec} 		#window: 		#(#{UI.WindowSpec} 			#properties: #(#{UI.PropertyListDictionary} #sizeType #specifiedSize #positionType #positionSystemDefault #openType #advanced ) 			#label: 			#(#{Kernel.UserMessage} 				#key: #UnlabeledCanvas 				#defaultString: 'User List' 				#catalogID: #labels ) 			#min: #(#{Core.Point} 399 125 ) 			#max: #(#{Core.Point} 1024 768 ) 			#bounds: #(#{Graphics.Rectangle} 840 525 1357 859 ) ) 		#component: 		#(#{UI.SpecCollection} 			#collection: #(				#(#{UI.ActionButtonSpec} 					#layout: #(#{Graphics.LayoutFrame} -31 0.25 -40 1 32 0.25 -10 1 ) 					#name: #ActionButton2 					#model: #removeUser 					#label: 'Remove' 					#defaultable: true ) 				#(#{UI.ActionButtonSpec} 					#layout: #(#{Graphics.LayoutFrame} -73 1 -40 1 -10 1 -10 1 ) 					#name: #ActionButton6 					#model: #inspectRequest 					#label: 'Inspect' 					#defaultable: true ) 				#(#{UI.ActionButtonSpec} 					#layout: #(#{Graphics.LayoutFrame} -73 0.5 -40 1 -10 0.5 -10 1 ) 					#name: #ActionButton5 					#model: #inspectUser 					#label: 'Inspect' 					#defaultable: true ) 				#(#{UI.SequenceViewSpec} 					#layout: #(#{Graphics.LayoutFrame} 11 0 16 0 -10 0.5 -50 1 ) 					#name: #List1 					#model: #userList 					#callbacksSpec: 					#(#{UI.UIEventCallbackSubSpec} 						#doubleClickSelector: #inspectUser ) 					#style: #large 					#useModifierKeys: true 					#selectionType: #highlight ) 				#(#{UI.SequenceViewSpec} 					#layout: #(#{Graphics.LayoutFrame} 10 0.5 16 0 -10 1 -50 1 ) 					#name: #List2 					#model: #requestList 					#callbacksSpec: 					#(#{UI.UIEventCallbackSubSpec} 						#doubleClickSelector: #inspectRequest ) 					#useModifierKeys: true 					#selectionType: #highlight ) 				#(#{UI.ActionButtonSpec} 					#layout: #(#{Graphics.LayoutFrame} 10 0.5 -40 1 73 0.5 -10 1 ) 					#name: #ActionButton3 					#model: #updateLists 					#label: 'Update' 					#isDefault: false 					#defaultable: true ) 				#(#{UI.ActionButtonSpec} 					#layout: #(#{Graphics.LayoutFrame} 10 0 -40 1 75 0 -10 1 ) 					#name: #ActionButton1 					#model: #updateLists 					#label: 'Update' 					#isDefault: true 					#defaultable: true ) 				#(#{UI.ActionButtonSpec} 					#layout: #(#{Graphics.LayoutFrame} -31 0.75 -40 1 41 0.75 -9 1 ) 					#name: #ActionButton4 					#model: #removeRequest 					#label: 'Remove' 					#defaultable: true ) ) ) )</body></methods><methods><class-id>Grocery.ConfirmationRedirectionTag class</class-id> <category>pragma</category><body package="Grocery-Tags">tagDefinition	&lt;tagLibrary: 'grocery.tld' name: 'confirmationRedirection' bodyContent: 'EMPTY'&gt;</body></methods><initialize><class-id>Grocery.Test.ShoppingTestResource</class-id></initialize><do-it>"Imported Classes:"</do-it><do-it>self error: 'Attempting to file-in parcel imports.  Choose terminate or close'</do-it><class><name>Object</name><environment>Core</environment><super></super><private>false</private><indexed-type>none</indexed-type><inst-vars></inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Kernel-Objects</category><attributes><package>Kernel-Objects</package></attributes></class><class><name>Tag</name><environment>VisualWave</environment><super>Core.Object</super><private>false</private><indexed-type>none</indexed-type><inst-vars>parent pageContext bodyContent allAttributes </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Web Toolkit-JSP</category><attributes><package>JSP</package></attributes></class><class><name>Filename</name><environment>OS</environment><super>Core.Object</super><private>false</private><indexed-type>none</indexed-type><inst-vars>osName publicName logicalName </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>OS-Support</category><attributes><package>OS-Support</package></attributes></class><class><name>ValidatingModel</name><environment>WebMVC</environment><super>Core.Object</super><private>false</private><indexed-type>none</indexed-type><inst-vars></inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>WebMVC-Servlets</category><attributes><package>WebMVC-Servlets</package></attributes></class><class><name>ValueModel</name><environment>UI</environment><super>UI.Model</super><private>false</private><indexed-type>none</indexed-type><inst-vars></inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Interface-Support</category><attributes><package>Interface-Support</package></attributes></class><class><name>TestCase</name><environment>XProgramming.SUnit</environment><super>Core.Object</super><private>false</private><indexed-type>none</indexed-type><inst-vars>testSelector </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>SUnit</category><attributes><package>SUnit</package></attributes></class><class><name>SimpleSMTPClient</name><environment>Net</environment><super>Net.NetClient</super><private>false</private><indexed-type>none</indexed-type><inst-vars>server connection stream serverResponse </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Net-SMTP-Support</category><attributes><package>SMTP</package></attributes></class><class><name>Collection</name><environment>Core</environment><super>Core.Object</super><private>false</private><indexed-type>none</indexed-type><inst-vars></inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Collections-Abstract</category><attributes><package>Collections-Abstract</package></attributes></class><class><name>CharacterArray</name><environment>Core</environment><super>Core.ArrayedCollection</super><private>false</private><indexed-type>none</indexed-type><inst-vars></inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Collections-Text</category><attributes><package>Collections-Text</package></attributes></class><class><name>SingleThreadModelServlet</name><environment>VisualWave</environment><super>VisualWave.HttpServlet</super><private>false</private><indexed-type>none</indexed-type><inst-vars>request response session </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Web Toolkit-Servlet</category><attributes><package>Servlet</package></attributes></class><class><name>Error</name><environment>Core</environment><super>Core.Exception</super><private>false</private><indexed-type>none</indexed-type><inst-vars></inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Kernel-Exception Handling</category><attributes><package>Kernel-Exception Handling</package></attributes></class><class><name>BodyTag</name><environment>VisualWave</environment><super>VisualWave.Tag</super><private>false</private><indexed-type>none</indexed-type><inst-vars></inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Web Toolkit-JSP</category><attributes><package>JSP</package></attributes></class><class><name>ApplicationModel</name><environment>UI</environment><super>UI.Model</super><private>false</private><indexed-type>none</indexed-type><inst-vars>builder uiSession eventHandlers </inst-vars><class-inst-vars>savedWindowInformation </class-inst-vars><imports></imports><category>UIBuilder-Framework</category><attributes><package>UIBuilder-Framework</package></attributes></class></st-source>
