001 import sale.*; 002 import sale.stdforms.*; 003 import data.*; 004 import data.ooimpl.*; 005 import data.stdforms.*; 006 import users.*; 007 import log.*; 008 009 import java.util.*; 010 import java.text.*; 011 import java.lang.*; 012 import java.io.*; 013 014 import javax.swing.JTextField; 015 import javax.swing.JPanel; 016 import javax.swing.JOptionPane; 017 import javax.swing.BoxLayout; 018 import javax.swing.JLabel; 019 020 021 022 /** 023 * Verkaufs- bzw. Verleihprozess, der von einem registrierten Kunden 024 * am Automaten durchgeführt werden kann. 025 */ 026 public class RentProcess extends SaleProcess 027 { 028 029 //// attributes //////////////////////////////////////////////////////////// 030 031 // Gates 032 protected UIGate capabilityGate; 033 protected UIGate selectionGate; 034 protected UIGate rentGate; 035 protected Gate decisionGate; 036 protected UIGate getChangeGate; 037 038 // Transitions 039 protected Transition toSelectionTransition; 040 protected Transition toPayingTransition; 041 protected Transition toDecisionTransition; 042 protected Transition toGetChangeTransition; 043 044 // verwendete Waehrung 045 private Currency myCurrency; 046 047 // zu zahlender Betrag 048 private IntegerValue toPayValue; 049 050 // gezahlter Betrag 051 private IntegerValue paidValue; 052 053 // Bewertung der Relation zwischen zu zahlendem und gezahltem Betrag 054 private int payAssessment; 055 056 // Kunde, der ausleihen moechte 057 private Customer customer; 058 059 // der Iterator ueber die geliehenen Videos 060 private transient Iterator videoIterator; 061 062 063 //// constructor /////////////////////////////////////////////////////////// 064 065 /** 066 * Erzeugt ein neues Objekt der Klasse RentProcess. 067 */ 068 public RentProcess() 069 { 070 super ("RentProcess"); 071 } 072 073 //// protected methods ///////////////////////////////////////////////////// 074 075 /** 076 * Baut die Oberfläche für den Verleihvorgang auf. 077 */ 078 protected void setupMachine() 079 { 080 // verwendete Waehrung ermitteln 081 myCurrency = (Currency)Shop.getTheShop().getCatalog("DM"); 082 083 // zu verwendenden Datenkorb ermitteln 084 final DataBasket db = getBasket(); 085 086 // zu verwendenden Bestand ermitteln 087 final CountingStockImpl cs = 088 (CountingStockImpl)Shop.getTheShop().getStock("Video-Countingstock"); 089 090 091 ////////////////////////////////////////////////// 092 /// Capability-Gate ////////////////////////////// 093 ////////////////////////////////////////////////// 094 095 096 // Formsheet fuer Eingabe der Kundennummer 097 // tif ist final, damit in der anonymen Klasse des FSCC auf Attribute des tif zugegriffen werden kann 098 final TextInputForm tif = new TextInputForm("Customer-ID", 099 "Customer-ID", 100 ""); 101 102 // FormSheetContentCreator fuer Capability-Gate implementieren 103 tif.addContentCreator( 104 new FormSheetContentCreator() 105 { 106 protected void createFormSheetContent(FormSheet fs) 107 { 108 // "OK"-Button neu definieren 109 fs.getButton(FormSheet.BTNID_OK). 110 setAction( 111 new sale.Action() 112 { 113 public void doAction (SaleProcess p, SalesPoint sp) 114 { 115 // Eingabe ueberpruefen 116 String customerID = tif.getText(); 117 boolean isNotAnInteger = true; 118 119 try { 120 new Integer(customerID); 121 isNotAnInteger = false; 122 } 123 catch(NumberFormatException nfe) { 124 isNotAnInteger = true; 125 } 126 127 // Eingabe korrekt -> selectionGate 128 if (!isNotAnInteger && (new Integer(customerID)).intValue() > 0) 129 { 130 // existiert der Kunde? 131 try { 132 customer = new Customer(customerID); 133 // nein, dann neu anlegen und der Liste reg. Kunden hinzufuegen 134 VideoMachine.addCustomer(customer); 135 } 136 // ja, dann diesen holen 137 catch (DuplicateKeyException dke) { 138 customer = VideoMachine.getCustomerByID(customerID); 139 } 140 capabilityGate.setNextTransition(toSelectionTransition); 141 } 142 // Eingabe falsch -> Kunden informieren und 143 // Eingabe wiederholen 144 else { 145 JOptionPane.showMessageDialog(null, 146 "CustomerID must be a positive Number!"); 147 capabilityGate.setNextTransition( 148 new GateChangeTransition(capabilityGate)); 149 } 150 } 151 } 152 ); 153 // "Cancel"-Button neu definieren 154 fs.getButton(FormSheet.BTNID_CANCEL). 155 setAction( 156 new sale.Action() 157 { 158 public void doAction (SaleProcess p, SalesPoint sp) 159 { 160 // Transition zum Rollback-Gate als naechste Transition setzen 161 capabilityGate.setNextTransition( 162 GateChangeTransition.CHANGE_TO_ROLLBACK_GATE); 163 } 164 } 165 ); 166 } 167 } 168 ); 169 170 // Gate zur Kundennummer-Abfrage mit erstellter TextInputForm anlegen 171 capabilityGate = new UIGate((FormSheet) tif, 172 (MenuSheet) null); 173 174 175 ////////////////////////////////////////////////// 176 /// Selection-Gate /////////////////////////////// 177 ////////////////////////////////////////////////// 178 179 180 // Auswahl-Gate anlegen 181 // Das FormSheet wird durch die Transition waehrend der Laufzeit erzeugt 182 selectionGate = new UIGate((FormSheet) null, (MenuSheet) null); 183 184 // Transition zum Selection Gate 185 toSelectionTransition = 186 new Transition() 187 { 188 public Gate perform(SaleProcess pOwner, User usr) 189 { 190 // am Gate darzustellendes FormSheet 191 TwoTableFormSheet ttfs = 192 TwoTableFormSheet.create("Make your selection", // Titel des FormSheets 193 cs, // Quell-CountingStock 194 db, // Ziel-DataBasket 195 selectionGate, // Gate, an dem das FormSheet darzustellen ist 196 null, // Comparator fuer Quelltabelle 197 null, // Comparator furr Ziel-Tabelle 198 false, // Zeilen mit Anzahl == 0 in der Quelltabelle anzeigen? 199 new OfferTED(true), // TableEntryDescriptor furr Quelltabelle 200 null, // TableEntryDescriptor furr Zieltabelle 201 null // Transferstrategie 202 ); 203 204 // FormSheetContentCreator am Auswahl-Gate anmelden 205 ttfs.addContentCreator( 206 new FormSheetContentCreator() 207 { 208 protected void createFormSheetContent(FormSheet fs) 209 { 210 // "OK"-Button neu definieren 211 fs.getButton(FormSheet.BTNID_OK). 212 setAction( 213 new sale.Action() 214 { 215 public void doAction (SaleProcess p, SalesPoint sp) 216 { 217 // Transition zum Bezahlen als naechste Transition setzen 218 selectionGate.setNextTransition(toPayingTransition); 219 } 220 } 221 ); 222 223 // "Cancel"-Button neu definieren 224 fs.getButton(FormSheet.BTNID_CANCEL). 225 setAction( 226 new sale.Action() 227 { 228 public void doAction (SaleProcess p, SalesPoint sp) 229 { 230 // Transition zum Rollback-Gate als naechste Transition setzen 231 selectionGate.setNextTransition( 232 GateChangeTransition.CHANGE_TO_ROLLBACK_GATE); 233 } 234 } 235 ); 236 } 237 } 238 ); 239 240 // erstelltes FormSheet am zu betretenden Gate setzen 241 selectionGate.setFormSheet(ttfs); 242 243 // als naechstes zu betretendes Gate zurueckgeben 244 return selectionGate; 245 } 246 }; 247 248 249 ////////////////////////////////////////////////// 250 /// Rent-Gate //////////////////////////////////// 251 ////////////////////////////////////////////////// 252 253 254 // Gate zum Ausleihen/Bezahlen anlegen 255 // Das FormSheet wird durch die Transition waehrend der Laufzeit erzeugt 256 rentGate = new UIGate(null, null); 257 258 // Transition zum Gate, an dem zu bezahlen ist 259 toPayingTransition = 260 new Transition() 261 { 262 public Gate perform(SaleProcess pOwner, User usr) 263 { 264 // Parameter zum Aufsummieren des Datenkorbes festlegen 265 final DataBasketCondition dbc = 266 DataBasketConditionImpl.allStockItemsWithSource(cs); 267 BasketEntryValue bev = BasketEntryValues.ONLY_STOCK_ITEMS; 268 QuoteValue qvSum = new QuoteValue(new IntegerValue(0), new IntegerValue(0)); 269 270 // ...und Datenkorb damit aufsummieren 271 pOwner.getBasket().sumBasket (dbc, bev, qvSum); 272 273 // zu zahlenden Betrag ermitteln 274 toPayValue = (IntegerValue)qvSum.getBid(); 275 276 // FormSheet für das naechste Gate erstellen 277 FormSheet tif = new TextInputForm("Paying", 278 "You have to pay " + 279 myCurrency.toString (toPayValue) + ".", 280 myCurrency.toString (toPayValue) 281 ); 282 283 // FormSheetContentCreator zum Einbauen der Buttons anmelden 284 tif.addContentCreator( 285 new FormSheetContentCreator() 286 { 287 protected void createFormSheetContent(FormSheet fs) 288 { 289 // als 'final' markierte Version des FormSheets anlegen 290 final TextInputForm tifFinal = (TextInputForm)fs; 291 292 // der Cancel-Button steht im Weg und wird zunaechst entfernt 293 fs.removeButton(FormSheet.BTNID_CANCEL); 294 295 // "OK"-Button neu definieren 296 fs.getButton(FormSheet.BTNID_OK). 297 setAction( 298 new sale.Action() 299 { 300 public void doAction (SaleProcess p, SalesPoint sp) 301 { 302 try { 303 // eingegebenen Text verarbeiten 304 paidValue = (IntegerValue)myCurrency.parse(tifFinal.getText()); 305 306 // Der Iterator ueber die zu leihenden Videos wird initialisiert 307 videoIterator = db.iterator(dbc); 308 309 // ...und naechste Transition setzen 310 rentGate.setNextTransition(toDecisionTransition); 311 } 312 catch(ParseException pexc) { 313 // eingegebener Text konnte nicht verarbeitet werden 314 // Meldung erzeugen und ausgeben 315 MsgForm mf = new MsgForm ("Error", 316 "The specified amount does " + 317 "not have an appropriate format."); 318 319 try { 320 p.getContext().popUpFormSheet (p, mf); 321 } 322 catch(InterruptedException iexc) { 323 } 324 } 325 } 326 } 327 ); 328 329 // "Back"-Button einbauen 330 fs.addButton ("Back", 101, 331 new sale.Action() 332 { 333 public void doAction (SaleProcess p, SalesPoint sp) 334 { 335 // naechste Transition setzen, fuehrt ohne weitere Aktionen 336 // zum Auswahl-Gate 337 rentGate.setNextTransition( 338 new GateChangeTransition(selectionGate)); 339 } 340 } 341 ); 342 343 // "Cancel"-Button wieder einbauen 344 fs.addButton ("Cancel", 102, 345 new sale.Action() 346 { 347 public void doAction (SaleProcess p, SalesPoint sp) 348 { 349 // naechste Transition setzen, fuehrt zum Rollback-Gate 350 rentGate.setNextTransition( 351 GateChangeTransition.CHANGE_TO_ROLLBACK_GATE); 352 } 353 } 354 ); 355 356 } 357 } 358 ); 359 360 // FormSheet am entsprechenden Gate setzen 361 rentGate.setFormSheet(tif); 362 363 // ...und naechstes zu betretendes Gate zurueckgeben 364 return rentGate; 365 } 366 }; 367 368 369 ////////////////////////////////////////////////// 370 /// Decision-Gate //////////////////////////////// 371 ////////////////////////////////////////////////// 372 373 374 // Transition zum Entscheidungsgate 375 toDecisionTransition = 376 new Transition() 377 { 378 public Gate perform (SaleProcess pOwner, User usr) 379 { 380 // ausreichend Geld gegeben? 381 if (paidValue.compareTo (toPayValue) >= 0) 382 { 383 // zu zahlenden Betrag im Safe der Videomaschine ablegen, wenn 384 // ueberhaupt etwas zu bezahlen ist 385 if (toPayValue.getValue().intValue() > 0) 386 ((CountingStock)Shop.getTheShop(). 387 getStock("coin slot")).add(CurrencyImpl.PFENNIG_STCK_1, 388 toPayValue.getValue().intValue(), pOwner.getBasket()); 389 390 // Genau richtig gezahlt? - payAssessment entsprechend belegen 391 if (paidValue.compareTo(toPayValue) == 0) 392 payAssessment = 0; 393 else 394 payAssessment = 1; 395 } 396 // nein, zuwenig bezahlt - payAssessment entsprechend belegen 397 else 398 payAssessment = -1; 399 400 // Entscheidungsgate als naechstes zu betretendes Gate zurueckgeben 401 return decisionGate; 402 } 403 }; 404 405 406 // Gate anlegen, das entscheidet, ob Wechselgeld gegeben, zum Bezahlen 407 // oder zum Commit-Gate gegangen wird 408 decisionGate = 409 new Gate() 410 { 411 public Transition getNextTransition(SaleProcess pOwner, User usr) 412 throws InterruptedException 413 { 414 switch(payAssessment) 415 { 416 // zuwenig bezahlt - Message anzeigen und zurueck zum Bezahlen 417 case -1: 418 // FehlerFormSheet erzeugen 419 FormSheet mf = new MsgForm("Error", 420 "You have to pay more!", 421 false); 422 // mit Hilfe des ProcessContext das FormSheet anzeigen 423 pOwner.getContext().popUpFormSheet(pOwner, mf); 424 425 return new GateChangeTransition(rentGate); 426 427 // genau richtig bezahlt - Transaktion ausfuehren - zum Commit-Gate 428 case 0: 429 // Ausleihvorgang ausfuehren 430 commitTransfer(); 431 432 return GateChangeTransition.CHANGE_TO_COMMIT_GATE; 433 434 // zuviel bezahlt - zur Wechselgeldausgabe 435 case 1: 436 // Ausleihvorgang ausfuehren 437 commitTransfer(); 438 439 return toGetChangeTransition; 440 441 // falscher Wert in payAssessment - Fehlermeldung und Abbruch 442 default: 443 FormSheet mf2 = new MsgForm("Error", 444 "Internal error at Decision Gate. " + 445 "Will quit process.", 446 false); 447 pOwner.getContext().popUpFormSheet (pOwner, mf2); 448 return GateChangeTransition.CHANGE_TO_QUIT_GATE; 449 } 450 } 451 452 public void commitTransfer() 453 { 454 // aktuelles Datum holen 455 Object date = Shop.getTheShop().getTimer().getTime(); 456 while (videoIterator.hasNext()) 457 { 458 CountingStockItemDBEntry cassetteItem = 459 (CountingStockItemDBEntry)videoIterator.next(); 460 int number = cassetteItem.count(); 461 for (; number > 0; number --) 462 { 463 // Videos in den Bestand des Kunden uebernehmen 464 customer.addVideoCassette(new 465 CassetteStoringStockItem(cassetteItem.getSecondaryKey(), date)); 466 467 // Vorgang in Logdatei eintragen 468 try { 469 Log.getGlobalLog().log(new MyLoggable(cassetteItem.getSecondaryKey(), 470 customer.getCustomerID(), 471 date)); 472 } 473 catch (LogNoOutputStreamException lnose) { 474 } 475 catch (IOException ioe) { 476 } 477 } 478 } 479 } 480 }; 481 482 483 ////////////////////////////////////////////////// 484 /// GetChange-Gate /////////////////////////////// 485 ////////////////////////////////////////////////// 486 487 488 // Gate zum Ausgeben des Wechselgeldes anlegen 489 // Das FormSheet wird durch die Transition waehrend der Laufzeit erzeugt 490 getChangeGate = new UIGate(null, null); 491 492 // Transition zum Wechselgeld-Gate 493 toGetChangeTransition = 494 new Transition() 495 { 496 public Gate perform(SaleProcess pOwner, User usr) 497 { 498 // am Gate darzustellendes FormSheet 499 MsgForm mf = new MsgForm("Get Change", 500 "You get " + 501 myCurrency.toString((IntegerValue)paidValue.subtract(toPayValue)) + 502 " Change."); 503 504 // ContentCreator zur Neubelegung des "OK"-Buttons hinzufuegen 505 mf.addContentCreator( 506 new FormSheetContentCreator() 507 { 508 public void createFormSheetContent(FormSheet fs) 509 { 510 // neue Aktion setzen 511 fs.getButton(FormSheet.BTNID_OK).setAction( 512 new Action() 513 { 514 public void doAction(SaleProcess p, SalesPoint sp) 515 { 516 // zum Commit-Gate fuehrende Transition als 517 // naechste Transition setzen 518 getChangeGate.setNextTransition( 519 GateChangeTransition.CHANGE_TO_COMMIT_GATE); 520 } 521 } 522 ); 523 } 524 } 525 ); 526 527 // erstelltes FormSheet am zu betretenden Gate setzen 528 getChangeGate.setFormSheet(mf); 529 530 // als naechstes zu betretendes Gate zurueckgeben 531 return getChangeGate; 532 } 533 }; 534 } 535 536 //// public methods //////////////////////////////////////////////////////// 537 538 /** 539 * Gibt das Startgate des Prozesses zurück. 540 */ 541 public Gate getInitialGate() 542 { 543 // Automat aufbauen 544 setupMachine(); 545 546 // ...und Capability-Gate als Startgate zurueckgeben 547 return capabilityGate; 548 } 549 550 /** 551 * Übergibt das Log-Gate. Hier das Stop-Gate, da beim Beenden des 552 * Prozesses kein Log-Eintrag geschrieben werden soll. 553 */ 554 public Gate getLogGate() 555 { 556 return getStopGate(); 557 } 558 }