Some reader favorites:
EJB fundamentals and session beans
Create a scrollable virtual desktop in Swing
Wizard API updated!
Tim Boudreau has released a new version of the Swing Wizard library (version 0.997) that fixes the WizardException bug reported in JavaWorld's recent Open Source Java Project profile. The article's examples have been reworked to test out the new, improved WizardException. Thanks, Tim, for this helpful fix!
Open Source Java Projects: The Wizard API
All is well if you are the developer and know the system inside and out. Unfortunately, if someone else takes over, that person will experience a learning curve -- so by the time the change is rolled out, your business may have lost many customers.
The solution I propose is to isolate parts of the Java code that are likely to change and implement them in a scripting language -- Tcl, in this case -- that is easy to read, understand, and modify. If properly done, I believe even your manager could perform certain changes without paging you in the middle of the night.
Tcl was developed by UC Berkeley professor John Ousterhout as a cross-platform scripting language that is easy to read and understand, and is easily extensible and embeddable. You can extend it by writing your own extensions and commands. This article will show you how, if want your application to interface with a Tcl script, you can easily embed a Tcl interpreter to process your script.
Since its creation, Tcl has empowered hundreds of thousands of users in a wide range of applications such as rapid prototyping, unit testing, and the task of tying together applications that were never meant to work together.
Not too long ago, considerable efforts had been spent integrating Java with Tcl (previously only extensible and embeddable in C). The TclBlend project, led by Moses Dejong, is an extension to the existing Tcl interpreter written in C, which allows a Tcl script to instantiate and call methods in Java objects, on top of the existing extensions written in C/C++. You can also create new commands or extensions in Java. The other project, Jacl (Java Command Language), is a total rewrite of the existing Tcl script interpreter in Java that will make it easy to embed into a Java application. I will explain in this article how, by embedding Jacl into your existing application, you will make your app more dynamic and configurable.
Let's take a typical scenario in which you're developing a business-to-consumer Website. To attract customers during a certain period, you sometimes need to offer perks, such as holiday discounts. During one such promotional period, the company might want to give first-time customers a discount on any purchase above 0.
// The result of the code will calculate the miscellaneous
// deduction to be to the purchase price and the discount
// percent to award to the customer
double miscDeduction=0.0;
double discountPercent=0.0;
// if this is a new customer, give a discount
// if he/she spents above 0
if (customer.isFirstTimeCustomer()) {
if (shoppingCart.getValue()>=10.0) {
miscDeduction=5;
}
}
// get the amount of money this customer
// already spent on this site
double dollarSpent=customer.getShoppingHistory().getDollarSpent();
// decides the percentage discount to award to the customer
// based on his/her past spendings
if (dollarSpent>100.0) {
discountPercent=5.0;
} else if (dollarSpent>500) {
discountPercent=7.0;
}
System.out.println("Discount awarded: "+discountPercent+"%");
System.out.println("Additional discount: $"+miscDeduction);
The code first initializes miscDeduction and discountPercent to zero. The variable miscDeduction will hold the amount of deduction to the purchase price and the variable discountPercent is the discount to be awarded to the customer.
The code then checks whether the customer is a first-timer by calling the method isFirstTimeCustomer() from the customer object. Then the purchase price of the customer's shopping cart is obtained by calling the method getvalue() from the shoppingCart object. The creation of the shoppingCart and customer objects is not shown because they are generic enough and not important for our discussion here.
Next the dollarSpent variable is initialized with the purchase amount the customer has made since registration. Finally, the discount awarded
to the customer will be determined by the dollarSpent variable.
// DiscountSetting is an interface that allows you to query an external
// XML file or database for the amount of discounts to award to
// a customer
DiscountSettings discountSettings=new MyDiscountSettings();
// The result of the code will calculate the miscellaneous
// deduction to be to the purchase price and the discount
// percent to award to the customer
double miscDeduction=0.0;
double discountPercent=0.0;
// if this is a new customer, give a discount
// if he/she spents above 0
if (customer.isFirstTimeCustomer()) {
if (shoppingCart.value()>=discountSettings.get("First time purchase")) {
miscDeduction=discountSettings.get("First time deduction");
}
}
// get the amount of money this customer
// already spent on this site
double dollarSpent=customer.getShoppingHistory().getDollarSpent();
// decides the percentage discount to award to the customer
// based on his/her past spendings
if (dollarSpent>discountSettings.get("First level spending")) {
discountPercent=discountSettings.get("First level discount percent");
} else if (dollarSpent>discountSettings.get("Second level spending")) {
discountPercent=discountSettings.get("Second level discount percent");
}
System.out.println("Discount awarded: "+discountPercent+"%");
System.out.println("Additional discount: $"+miscDeduction);
The code first creates a discountSettings object. This is an interface that exposes a single method to obtain a double value based on a String input:
public interface DiscountSettings {
public double get(String valueToRetrieve);
}
Implementation of the DiscountSettings interface will be responsible for retrieving the actual information from a data source, such as an XML data file or a database
table.
As in the previous example, the code will award a discount to first-time customers whose purchase values exceed 0. Instead
of hard coding the cash value, the code now uses the discountSettings object to look up the value based on fixed string constants, "First time purchase" and "First time deduction".
The code then goes on to award additional discounts to customers who have spent a certain amount of money. As in the above
case, the discountSettings object now finds out the percentage of discount to be awarded based on how much each customer has spent.
Solution 2 solves our problem when the reward structure is the same and the only values that change are the discount amounts. Unfortunately, we have somehow hard coded our logic and structure here. If management decides to terminate the first customer rewards, or introduce customer coupons, we would have to go back to our code once again.
// Creates the Tcl interpreter object
Interp interp=new Interp();
// The result of the code will calculate the miscellaneous
// deduction to be to the purchase price and the discount
// percent to award to the customer
double miscDeduction=0.0;
double discountPercent=0.0;
try {
// the file name of the script
String scriptFileName="discount_decision.tcl";
// get the amount of money this customer
// already spent on this site
double dollarSpent=customer.getShoppingHistory().getDollarSpent();
double shoppingCartValue=shoppingCart.getValue();
// set the dollarspent variable in the Tcl script
interp.setVar(
"dollarspent",
TclDouble.newInstance(dollarSpent),
0);
// set the firsttimecustomer variable in the Tcl script
interp.setVar(
"firsttimecustomer",
TclBoolean.newInstance(customer.isFirstTimeCustomer()),
0);
// set the shoppingcartvalue variable in the Tcl script
interp.setVar(
"shoppingcartvalue",
TclDouble.newInstance(shoppingCartValue),
0);
// execute the script within the script file
interp.evalFile(scriptFileName);
// retrieve the values that are evaluated in the script
String tclMiscDeduction=
interp.getVar("miscdeduction",0).toString();
String tclDiscountPercent=
interp.getVar("discount",0).toString();
miscDeduction=new Double(tclMiscDeduction).doubleValue();
discountPercent=new Double(tclDiscountPercent).doubleValue();
// free up resources used by the interpreter
interp.dispose();
// output the results to console
System.out.println("Discount awarded: "+discountPercent+"%");
System.out.println("Additional discount: $"+miscDeduction);
} catch (TclException e) {
e.printStackTrace();
}
The following Tcl script evaluates the result:
# first time customer gets off for all purchases > 0
set miscdeduction 0
if {$firsttimecustomer} {
if {$shoppingcartvalue>10} {
set miscdeduction 5
}
}
# determines the amount of discount to award to the customer
# based on spending history
set discount 0
if {$dollarspent > 100} {
set discount 5
} elseif {$dollarspent > 500} {
set discount 7
}
Let's first take a look at the Java code. We create a Tcl interpreter object called interp to parse our Tcl script and then, as usual, set up the miscDeduction and discountPercent variables. Next, we initialize shoppingCartValue and dollarSpent.
From this point onward, things start to get interesting. We create three Tcl variables for our interp object -- dollarspent, shoppingcartvalue, and firsttimecustomer -- by calling setVar of the interpreter object, and initialize them to appropriate values. These variables will then be accessed from our Tcl script.
The method signature for setVar of our interp object is:
public void setVar(String name, TclObject value, int flags) throws TclException
The first argument is the name of the variable that we want to create.
The second argument is a TclObject that contains the initial value of the variable. To create this TclObject to contain our value, we call a factory method newInstance() of a Tcl data class corresponding to the type we want to create. For example, to create a TclObject representation of type double with a value of 2.0, we call TclDouble.newInstance(2.0). Similarly, to create a TclObject representation of type boolean with a value of true, we call TclBoolean.newInstance(true). The API also provides us with TclString and TclInteger to generate a TclObject representation of strings and integers.
Free Download - 5 Minute Product Review. When slow equals Off: Manage the complexity of Web applications - Symphoniq
![]()
Free Download - 5 Minute Product Review. Realize the benefits of real user monitoring in less than an hour. - Symphoniq