| RentProcess |
import sale.*;
import sale.stdforms.*;
import data.*;
import data.ooimpl.*;
import data.stdforms.*;
import users.*;
import log.*;
import java.util.*;
import java.text.*;
import java.lang.*;
import java.io.*;
import javax.swing.JTextField;
import javax.swing.JPanel;
import javax.swing.JOptionPane;
import javax.swing.BoxLayout;
import javax.swing.JLabel;
/**
* Verkaufs- bzw. Verleihprozess, der von einem registrierten Kunden
* am Automaten durchgeführt werden kann.
*/
public class RentProcess extends SaleProcess
{
//// attributes ////////////////////////////////////////////////////////////
// Gates
protected UIGate capabilityGate;
protected UIGate selectionGate;
protected UIGate rentGate;
protected Gate decisionGate;
protected UIGate getChangeGate;
// Transitions
protected Transition toSelectionTransition;
protected Transition toPayingTransition;
protected Transition toDecisionTransition;
protected Transition toGetChangeTransition;
// verwendete Waehrung
private Currency myCurrency;
// zu zahlender Betrag
private IntegerValue toPayValue;
// gezahlter Betrag
private IntegerValue paidValue;
// Bewertung der Relation zwischen zu zahlendem und gezahltem Betrag
private int payAssessment;
// Kunde, der ausleihen moechte
private Customer customer;
// der Iterator ueber die geliehenen Videos
private transient Iterator videoIterator;
//// constructor ///////////////////////////////////////////////////////////
/**
* Erzeugt ein neues Objekt der Klasse RentProcess.
*/
public RentProcess()
{
super ("RentProcess");
}
//// protected methods /////////////////////////////////////////////////////
/**
* Baut die Oberfläche für den Verleihvorgang auf.
*/
protected void setupMachine()
{
// verwendete Waehrung ermitteln
myCurrency = (Currency)Shop.getTheShop().getCatalog("DM");
// zu verwendenden Datenkorb ermitteln
final DataBasket db = getBasket();
// zu verwendenden Bestand ermitteln
final CountingStockImpl cs =
(CountingStockImpl)Shop.getTheShop().getStock("Video-Countingstock");
//////////////////////////////////////////////////
/// Capability-Gate //////////////////////////////
//////////////////////////////////////////////////
// Formsheet fuer Eingabe der Kundennummer
// tif ist final, damit in der anonymen Klasse des FSCC auf Attribute des tif zugegriffen werden kann
final TextInputForm tif = new TextInputForm("Customer-ID",
"Customer-ID",
"");
// FormSheetContentCreator fuer Capability-Gate implementieren
tif.addContentCreator(
new FormSheetContentCreator()
{
protected void createFormSheetContent(FormSheet fs)
{
// "OK"-Button neu definieren
fs.getButton(FormSheet.BTNID_OK).
setAction(
new sale.Action()
{
public void doAction (SaleProcess p, SalesPoint sp)
{
// Eingabe ueberpruefen
String customerID = tif.getText();
boolean isNotAnInteger = true;
try {
new Integer(customerID);
isNotAnInteger = false;
}
catch(NumberFormatException nfe) {
isNotAnInteger = true;
}
// Eingabe korrekt -> selectionGate
if (!isNotAnInteger && (new Integer(customerID)).intValue() > 0)
{
// existiert der Kunde?
try {
customer = new Customer(customerID);
// nein, dann neu anlegen und der Liste reg. Kunden hinzufuegen
VideoMachine.addCustomer(customer);
}
// ja, dann diesen holen
catch (DuplicateKeyException dke) {
customer = VideoMachine.getCustomerByID(customerID);
}
capabilityGate.setNextTransition(toSelectionTransition);
}
// Eingabe falsch -> Kunden informieren und
// Eingabe wiederholen
else {
JOptionPane.showMessageDialog(null,
"CustomerID must be a positive Number!");
capabilityGate.setNextTransition(
new GateChangeTransition(capabilityGate));
}
}
}
);
// "Cancel"-Button neu definieren
fs.getButton(FormSheet.BTNID_CANCEL).
setAction(
new sale.Action()
{
public void doAction (SaleProcess p, SalesPoint sp)
{
// Transition zum Rollback-Gate als naechste Transition setzen
capabilityGate.setNextTransition(
GateChangeTransition.CHANGE_TO_ROLLBACK_GATE);
}
}
);
}
}
);
// Gate zur Kundennummer-Abfrage mit erstellter TextInputForm anlegen
capabilityGate = new UIGate((FormSheet) tif,
(MenuSheet) null);
//////////////////////////////////////////////////
/// Selection-Gate ///////////////////////////////
//////////////////////////////////////////////////
// Auswahl-Gate anlegen
// Das FormSheet wird durch die Transition waehrend der Laufzeit erzeugt
selectionGate = new UIGate((FormSheet) null, (MenuSheet) null);
// Transition zum Selection Gate
toSelectionTransition =
new Transition()
{
public Gate perform(SaleProcess pOwner, User usr)
{
// am Gate darzustellendes FormSheet
TwoTableFormSheet ttfs =
TwoTableFormSheet.create("Make your selection", // Titel des FormSheets
cs, // Quell-CountingStock
db, // Ziel-DataBasket
selectionGate, // Gate, an dem das FormSheet darzustellen ist
null, // Comparator fuer Quelltabelle
null, // Comparator furr Ziel-Tabelle
false, // Zeilen mit Anzahl == 0 in der Quelltabelle anzeigen?
new OfferTED(true), // TableEntryDescriptor furr Quelltabelle
null, // TableEntryDescriptor furr Zieltabelle
null // Transferstrategie
);
// FormSheetContentCreator am Auswahl-Gate anmelden
ttfs.addContentCreator(
new FormSheetContentCreator()
{
protected void createFormSheetContent(FormSheet fs)
{
// "OK"-Button neu definieren
fs.getButton(FormSheet.BTNID_OK).
setAction(
new sale.Action()
{
public void doAction (SaleProcess p, SalesPoint sp)
{
// Transition zum Bezahlen als naechste Transition setzen
selectionGate.setNextTransition(toPayingTransition);
}
}
);
// "Cancel"-Button neu definieren
fs.getButton(FormSheet.BTNID_CANCEL).
setAction(
new sale.Action()
{
public void doAction (SaleProcess p, SalesPoint sp)
{
// Transition zum Rollback-Gate als naechste Transition setzen
selectionGate.setNextTransition(
GateChangeTransition.CHANGE_TO_ROLLBACK_GATE);
}
}
);
}
}
);
// erstelltes FormSheet am zu betretenden Gate setzen
selectionGate.setFormSheet(ttfs);
// als naechstes zu betretendes Gate zurueckgeben
return selectionGate;
}
};
//////////////////////////////////////////////////
/// Rent-Gate ////////////////////////////////////
//////////////////////////////////////////////////
// Gate zum Ausleihen/Bezahlen anlegen
// Das FormSheet wird durch die Transition waehrend der Laufzeit erzeugt
rentGate = new UIGate(null, null);
// Transition zum Gate, an dem zu bezahlen ist
toPayingTransition =
new Transition()
{
public Gate perform(SaleProcess pOwner, User usr)
{
// Parameter zum Aufsummieren des Datenkorbes festlegen
final DataBasketCondition dbc =
DataBasketConditionImpl.allStockItemsWithSource(cs);
BasketEntryValue bev = BasketEntryValues.ONLY_STOCK_ITEMS;
QuoteValue qvSum = new QuoteValue(new IntegerValue(0), new IntegerValue(0));
// ...und Datenkorb damit aufsummieren
pOwner.getBasket().sumBasket (dbc, bev, qvSum);
// zu zahlenden Betrag ermitteln
toPayValue = (IntegerValue)qvSum.getBid();
// FormSheet für das naechste Gate erstellen
FormSheet tif = new TextInputForm("Paying",
"You have to pay " +
myCurrency.toString (toPayValue) + ".",
myCurrency.toString (toPayValue)
);
// FormSheetContentCreator zum Einbauen der Buttons anmelden
tif.addContentCreator(
new FormSheetContentCreator()
{
protected void createFormSheetContent(FormSheet fs)
{
// als 'final' markierte Version des FormSheets anlegen
final TextInputForm tifFinal = (TextInputForm)fs;
// der Cancel-Button steht im Weg und wird zunaechst entfernt
fs.removeButton(FormSheet.BTNID_CANCEL);
// "OK"-Button neu definieren
fs.getButton(FormSheet.BTNID_OK).
setAction(
new sale.Action()
{
public void doAction (SaleProcess p, SalesPoint sp)
{
try {
// eingegebenen Text verarbeiten
paidValue = (IntegerValue)myCurrency.parse(tifFinal.getText());
// Der Iterator ueber die zu leihenden Videos wird initialisiert
videoIterator = db.iterator(dbc);
// ...und naechste Transition setzen
rentGate.setNextTransition(toDecisionTransition);
}
catch(ParseException pexc) {
// eingegebener Text konnte nicht verarbeitet werden
// Meldung erzeugen und ausgeben
MsgForm mf = new MsgForm ("Error",
"The specified amount does " +
"not have an appropriate format.");
try {
p.getContext().popUpFormSheet (p, mf);
}
catch(InterruptedException iexc) {
}
}
}
}
);
// "Back"-Button einbauen
fs.addButton ("Back", 101,
new sale.Action()
{
public void doAction (SaleProcess p, SalesPoint sp)
{
// naechste Transition setzen, fuehrt ohne weitere Aktionen
// zum Auswahl-Gate
rentGate.setNextTransition(
new GateChangeTransition(selectionGate));
}
}
);
// "Cancel"-Button wieder einbauen
fs.addButton ("Cancel", 102,
new sale.Action()
{
public void doAction (SaleProcess p, SalesPoint sp)
{
// naechste Transition setzen, fuehrt zum Rollback-Gate
rentGate.setNextTransition(
GateChangeTransition.CHANGE_TO_ROLLBACK_GATE);
}
}
);
}
}
);
// FormSheet am entsprechenden Gate setzen
rentGate.setFormSheet(tif);
// ...und naechstes zu betretendes Gate zurueckgeben
return rentGate;
}
};
//////////////////////////////////////////////////
/// Decision-Gate ////////////////////////////////
//////////////////////////////////////////////////
// Transition zum Entscheidungsgate
toDecisionTransition =
new Transition()
{
public Gate perform (SaleProcess pOwner, User usr)
{
// ausreichend Geld gegeben?
if (paidValue.compareTo (toPayValue) >= 0)
{
// zu zahlenden Betrag im Safe der Videomaschine ablegen, wenn
// ueberhaupt etwas zu bezahlen ist
if (toPayValue.getValue().intValue() > 0)
((CountingStock)Shop.getTheShop().
getStock("coin slot")).add(CurrencyImpl.PFENNIG_STCK_1,
toPayValue.getValue().intValue(), pOwner.getBasket());
// Genau richtig gezahlt? - payAssessment entsprechend belegen
if (paidValue.compareTo(toPayValue) == 0)
payAssessment = 0;
else
payAssessment = 1;
}
// nein, zuwenig bezahlt - payAssessment entsprechend belegen
else
payAssessment = -1;
// Entscheidungsgate als naechstes zu betretendes Gate zurueckgeben
return decisionGate;
}
};
// Gate anlegen, das entscheidet, ob Wechselgeld gegeben, zum Bezahlen
// oder zum Commit-Gate gegangen wird
decisionGate =
new Gate()
{
public Transition getNextTransition(SaleProcess pOwner, User usr)
throws InterruptedException
{
switch(payAssessment)
{
// zuwenig bezahlt - Message anzeigen und zurueck zum Bezahlen
case -1:
// FehlerFormSheet erzeugen
FormSheet mf = new MsgForm("Error",
"You have to pay more!",
false);
// mit Hilfe des ProcessContext das FormSheet anzeigen
pOwner.getContext().popUpFormSheet(pOwner, mf);
return new GateChangeTransition(rentGate);
// genau richtig bezahlt - Transaktion ausfuehren - zum Commit-Gate
case 0:
// Ausleihvorgang ausfuehren
commitTransfer();
return GateChangeTransition.CHANGE_TO_COMMIT_GATE;
// zuviel bezahlt - zur Wechselgeldausgabe
case 1:
// Ausleihvorgang ausfuehren
commitTransfer();
return toGetChangeTransition;
// falscher Wert in payAssessment - Fehlermeldung und Abbruch
default:
FormSheet mf2 = new MsgForm("Error",
"Internal error at Decision Gate. " +
"Will quit process.",
false);
pOwner.getContext().popUpFormSheet (pOwner, mf2);
return GateChangeTransition.CHANGE_TO_QUIT_GATE;
}
}
public void commitTransfer()
{
// aktuelles Datum holen
Object date = Shop.getTheShop().getTimer().getTime();
while (videoIterator.hasNext())
{
CountingStockItemDBEntry cassetteItem =
(CountingStockItemDBEntry)videoIterator.next();
int number = cassetteItem.count();
for (; number > 0; number --)
{
// Videos in den Bestand des Kunden uebernehmen
customer.addVideoCassette(new
CassetteStoringStockItem(cassetteItem.getSecondaryKey(), date));
// Vorgang in Logdatei eintragen
try {
Log.getGlobalLog().log(new MyLoggable(cassetteItem.getSecondaryKey(),
customer.getCustomerID(),
date));
}
catch (LogNoOutputStreamException lnose) {
}
catch (IOException ioe) {
}
}
}
}
};
//////////////////////////////////////////////////
/// GetChange-Gate ///////////////////////////////
//////////////////////////////////////////////////
// Gate zum Ausgeben des Wechselgeldes anlegen
// Das FormSheet wird durch die Transition waehrend der Laufzeit erzeugt
getChangeGate = new UIGate(null, null);
// Transition zum Wechselgeld-Gate
toGetChangeTransition =
new Transition()
{
public Gate perform(SaleProcess pOwner, User usr)
{
// am Gate darzustellendes FormSheet
MsgForm mf = new MsgForm("Get Change",
"You get " +
myCurrency.toString((IntegerValue)paidValue.subtract(toPayValue)) +
" Change.");
// ContentCreator zur Neubelegung des "OK"-Buttons hinzufuegen
mf.addContentCreator(
new FormSheetContentCreator()
{
public void createFormSheetContent(FormSheet fs)
{
// neue Aktion setzen
fs.getButton(FormSheet.BTNID_OK).setAction(
new Action()
{
public void doAction(SaleProcess p, SalesPoint sp)
{
// zum Commit-Gate fuehrende Transition als
// naechste Transition setzen
getChangeGate.setNextTransition(
GateChangeTransition.CHANGE_TO_COMMIT_GATE);
}
}
);
}
}
);
// erstelltes FormSheet am zu betretenden Gate setzen
getChangeGate.setFormSheet(mf);
// als naechstes zu betretendes Gate zurueckgeben
return getChangeGate;
}
};
}
//// public methods ////////////////////////////////////////////////////////
/**
* Gibt das Startgate des Prozesses zurück.
*/
public Gate getInitialGate()
{
// Automat aufbauen
setupMachine();
// ...und Capability-Gate als Startgate zurueckgeben
return capabilityGate;
}
/**
* Übergibt das Log-Gate. Hier das Stop-Gate, da beim Beenden des
* Prozesses kein Log-Eintrag geschrieben werden soll.
*/
public Gate getLogGate()
{
return getStopGate();
}
}| RentProcess |