This appendix provides an example of the implementation of OCL expressions as explained in Chapter 4. The class CustomerCard , together with all OCL expressions given as examples in this book, is implemented by the following Java code: package royalAndLoyal; import java.util.HashSet; import java.util.Iterator; import java.util.Set; public class CustomerCard /**************************************************************** * Attributes, and their get and set operations * ****************************************************************/ boolean valid = true; // implements initial value // definition from page 24 Date validFrom; Date goodThru; Color color; public void setValid(boolean v) { valid = v; } public boolean getValid() { return valid; } public void setValidFrom(Date d) { validFrom = d; } public Date getValidFrom() { return validFrom; } public void setGoodThru(Date d) { goodThru = d; } public Date getGoodThru() { return goodThru; } public void setColor(Color c) { color = c; } public Color getColor() { return color; } /**************************************************************** * Associations, and their get and set operations * ****************************************************************/ Customer owner; HashSet transactions = new HashSet(); // implements initial // value definition // Set from page 112 Membership membership; public void setOwner(Customer c) { owner = c; } public Customer getOwner() { return owner; } public void addTransaction(Transaction t) { transactions.add(t); } public HashSet getTransactions() { return transactions; } public void setMembership(Membership m) { membership = m; } public Membership getMembership() { return membership; } /**************************************************************** * Derived attributes, and their get and set operations * ****************************************************************/ /* implements from page 25: context CustomerCard::printedName derive: owner.title.concat(' ').concat(owner.name) */ String getPrintedName() { return owner.getTitle() + " " + owner.getName(); } /* implements from page 112: context CustomerCard::myLevel : ServiceLevel derive: Membership.currentLevel */ ServiceLevel getMyLevel() { return membership.getCurrentLevel(); } /**************************************************************** * Invariants * Operations to be called when an invariant needs to be checked * ****************************************************************/ /* implements from page 27: inv: validFrom.isBefore(goodThru) */ boolean invCorrectValidFrom() { return validFrom.isBefore(goodThru); } /* implements from page 28: inv: owner.age >= 18 */ boolean invCorrectAge() { return owner.age >= 18; } /* implements from page 36: inv: let correctDate : Boolean = self.validFrom.isBefore(Date::now) and self.goodThru.isAfter(Date::now) in if valid then correctDate = false else correctDate = true endif */ boolean invValidMatchesDates() { boolean correctDate = this.validFrom.isBefore(Date.now) && this.goodThru.isAfter(Date.now); if (valid) { return correctDate == false; } else { return correctDate == true; } } /* implements from page 130: inv: goodThru.isAfter( Date::now ) */ boolean invCorrectGoodThru() { return goodThru.isBefore( Date.now ); } /* implements from page 131: inv: self.owner.dateOfBirth.isBefore( Date::now ) */ boolean invCorrectDateOfBirth() { return this.getOwner().getDateOfBirth().isBefore( Date.now ); } /* implements from page 131: inv: self.owner.programs->size() > 0 */ boolean invCorrectNumberOfPrograms() { return this.getOwner().getPrograms().size() > 0; } /* implements from page 149: inv: self.transactions->select( points > 100 )->notEmpty() */ boolean invCorrectNrHighTransactions() { boolean result = false; Iterator it = this.getTransactions().iterator(); Set selectResult = new HashSet(); while( it.hasNext() ){ Transaction t = (Transaction) it.next(); if (t.getPoints() > 100 ) { selectResult.add( t ); } } result = ! selectResult.isEmpty(); return result; } /* implements from page 184, using different OCL syntax: inv: exists t: Transaction in transactions where t.date.isBefore( Date::now ) */ boolean invCorrectDateOfTransactions() { return this.getOwner().getDateOfBirth().isBefore( Date.now ); } /* implements from page 184, using different OCL syntax: inv: iterate t: Transaction over transactions result myResult : Integer initialValue 0 nextValue myResult + points > 0 */ boolean invCorrectPoints() { Iterator it = transactions.iterator(); int myResult = 0; while( it.hasNext() ) { Transaction t = (Transaction) it.next(); myResult = myResult + t.getPoints(); } return myResult > 0; } /* convenience operation that checks all invariants * could also be implemented to return an error code, * exception, or error message */ boolean checkAllInvariants() { return invCorrectValidFrom()& invCorrectAge() && invValidMatchesDates() && invCorrectGoodThru() && invCorrectDateOfBirth() && invCorrectNumberOfPrograms() && invCorrectNrHighTransactions() && invCorrectDateOfTransactions() && invCorrectPoints(); } /**************************************************************** * Definitions * ****************************************************************/ /* implements from page 113: context CustomerCard::getTransactions(from : Date, until: Date ) : Set(Transaction) body: transactions->select( date.isAfter( from ) and date.isBefore( until ) ) */ Set getTransactions( Date from, Date until ) { Set result = new HashSet(); Iterator it = this.getTransactions().iterator(); while( it.hasNext() ) Transaction t = (Transaction) it.next(); if (t.getDate().isAfter(from) && t.getDate().isBefore(until) ){ result.add( t ); } } return result; } /* implements from page 111: context CustomerCard def: getTotalPoints( d: Date ) : Integer = transactions->select( date.isAfter(d) ).points->sum() */ int getTotalPoints( Date d ) { int result = 0; Iterator it = this.getTransactions().iterator(); while( it.hasNext() ){ Transaction t = (Transaction) it.next(); if (t.getDate().isAfter(d) ) { result = result + t.points; } } return result; } } // end class CustomerCard |