// ============================================================================
// Java servlet example for the G-WAN Web App. Server (http://trustleap.ch/)
// ----------------------------------------------------------------------------
// loan.java: G-WAN's version of the Java loan http://gwan.ch/source/loan.jsp
// written for GlassFish (follow the link above for details).
// ----------------------------------------------------------------------------
// This Java code is served very quickly by G-WAN (despite C/Java conversions).
// See below (the " -t 6" option setups 6 client worker threads for 6 Cores):
//
// weighttp -n 1000000 -c 300 -t 6 -k -H "Accept-Encoding: gzip" \
// "http://127.0.0.1:80/?loan.java&name=Eva&amount=10000&rate=3.5&term=1"
// finished in 1 sec, 748 millisec, 571778 req/s, 1286500 kbyte/s
// requests: 1000000 total/started/done/succeeded, 0 failed/errored
// status codes: 1000000 2xx, 0 3xx, 0 4xx, 0 5xx
// traffic: 2303999915 bytes total, 276999915 bytes http, 2027000000 bytes data
//
// On the same machine, Tomcat's HelloWorld example does:
// (installation: https://help.ubuntu.com/11.04/serverguide/C/tomcat.html)
// (administration https://help.ubuntu.com/community/ApacheTomcat5)
//
// weighttp -n 1000000 -c 300 -t 6 -k -H "Accept-Encoding: gzip" \
// "http://127.0.0.1:8080/examples/servlets/servlet/HelloWorldExample"
// finished in 12 sec, 278 millisec, 81441 req/s, 39024 kbyte/s
// requests: 1000000 total/started/done/succeeded, 0 failed/errored
// status codes: 1000000 2xx, 0 3xx, 0 4xx, 0 5xx
// traffic: 490671704 bytes total, 131671704 bytes http, 359000000 bytes data
//
// Server bytes sent kbyte/sec requests/sec servlet time
// ------ -------------- --------- ------------ ---------- ------
// G-WAN 2,303,999,915 1,286,500 571,778 loan.java 1 sec
// Tomcat 490,671,704 39,024 81,441 hello.java 12 sec
//
// The next best Web servers do not even reach 571,778 req/s when serving mere
// static contents. G-WAN is making dynamic contents fly (high).
// ----------------------------------------------------------------------------
import api.Gwan;
public class loan // the class name MUST match the script *.java filename
{
public static int jmain(long env, String[] args)
{
String m_out = "";
// ---- requests without parameters trigger a redirect to the input form
if(args.length == 0)
{
m_out = "HTTP/1.1 302 Found\r\n"
+ "Content-type:text/html\r\n"
+ "Location: /csp_loan.html\r\n\r\n"
+ ""
+ "
Redirect "
+ "Click HERE for redirect."
+ "";
}
else
{
// ---- process a GET query with parameters
long start = Gwan.getUs();
double payment, interest, principal, cost, amount, rate, term;
int month=0, year=1, lastpayment=1;
String[] Months={"January","February","March","April","May","June",
"July", "August","September","October","November","December"};
// the form field "names" we want to find values for
String szName="-", Name="", Amount="0.0", Rate="0.0", Term="0.0";
// anyone volunter to write a Java equivalent for G-WAN's get_arg()?
switch(args[0].charAt(0))
{
case 'a': Amount = args[0].substring(args[0].indexOf('=') + 1); break;
case 'n': Name = args[0].substring(args[0].indexOf('=') + 1); break;
case 'r': Rate = args[0].substring(args[0].indexOf('=') + 1); break;
case 't': Term = args[0].substring(args[0].indexOf('=') + 1); break;
}
switch(args[1].charAt(0))
{
case 'a': Amount = args[1].substring(args[1].indexOf('=') + 1); break;
case 'n': Name = args[1].substring(args[1].indexOf('=') + 1); break;
case 'r': Rate = args[1].substring(args[1].indexOf('=') + 1); break;
case 't': Term = args[1].substring(args[1].indexOf('=') + 1); break;
}
switch(args[2].charAt(0))
{
case 'a': Amount = args[2].substring(args[2].indexOf('=') + 1); break;
case 'n': Name = args[2].substring(args[2].indexOf('=') + 1); break;
case 'r': Rate = args[2].substring(args[2].indexOf('=') + 1); break;
case 't': Term = args[2].substring(args[2].indexOf('=') + 1); break;
}
switch(args[3].charAt(0))
{
case 'a': Amount = args[3].substring(args[3].indexOf('=') + 1); break;
case 'n': Name = args[3].substring(args[3].indexOf('=') + 1); break;
case 'r': Rate = args[3].substring(args[3].indexOf('=') + 1); break;
case 't': Term = args[3].substring(args[3].indexOf('=') + 1); break;
}
// set default values if a parameter is missing
if(Name == null) Name ="-";
if(Amount == null) Amount ="100000.0";
if(Rate == null) Rate ="3.5";
if(Term == null) Term ="10.0";
// all litteral strings provided by a client must be escaped this way
// if you inject them into an HTML page
//public static String escape_html(String Name)
{
int len = Name.length();
StringBuffer sb = new StringBuffer(len);
int c;
for(int i = 0; i < len; i++)
{
c = Name.charAt(i);
if(c == ' ') sb.append(" "); else
if(c == '"') sb.append("""); else
if(c == '&') sb.append("&"); else
if(c == '<') sb.append("<"); else
if(c == '>') sb.append(">"); else
if(c == '\n') sb.append("<br/>");
else
{
c = c&0xffff; // unicode
if(c < 32 || c > 127)
{
sb.append("");
sb.append(new Integer(c).toString());
sb.append(';');
}
else
sb.append(c);
}
}
//return sb.toString();
szName = sb.toString();
}
// filter input data to avoid all the useless or nasty cases
amount = Double.parseDouble(Amount);
if(amount < 1.0)
amount = 1.0;
rate = Double.parseDouble(Rate);
if(rate > 19.0)
rate = 20.0;
if(rate > 1.0)
rate = rate/100.0;
else
if(rate < 1.0)
rate = 1.0/100.0;
term = Double.parseDouble(Term);
if(term < 0.1)
term = 1.0/12.0;
// do not do this in production...
//else
//if(term > 90.0)
// term = 90.0;
// calculate the monthly payment amount
payment = amount*rate/12*Math.pow(1+rate/12, term*12)
/ (Math.pow(1+rate/12, term*12)-1);
cost = (term*12*payment)-amount;
// build the top of our HTML page
m_out += String.format(
""
+ "Loan Calculator "
+ " "
+ ""
+ "Dear %s, your loan goes as follows: ",
(Name.length() < 2 || Name.charAt(0) == '-') ? "client" : Name);
// the HTML escaping needs a fix, any volunteer?
//(szName.length() < 2 || szName.charAt(0) == '-') ? "client" : szName);
m_out += String.format(
""
+"loan details "
+"Amount %,.2f"
+" Rate "
+"%,.2f%% Term "
+"%d %s(s) Cost "
+"%,.2f (%3.2f%%)
",
amount,
rate * 100,
(int)(((int)term>0)?term:Math.ceil(12*term)),
((int)term>0)?"year":"month",
cost,
100/(amount/cost));
m_out += String.format(
" "
+""
+"month payment interest "
+"principal balance ",
year);
// output monthly payments
for(;;)
{
month = month+1;
interest = (amount*rate)/12;
if(amount>payment)
{
amount = (amount-payment)+interest;
principal = payment-interest;
}
else
{
// calculate last payment
if(lastpayment>0)
{
lastpayment = 0;
payment = amount;
principal = amount-interest;
amount = 0;
}
else
{
// all payments are done, just padd the table
amount = 0;
payment = 0;
interest = 0;
principal = 0;
}
}
m_out += String.format(
"%s %,.2f %,.2f"
+" %,.2f %,.2f ",
month & 1, Months[month - 1],
payment,
interest,
principal,
amount);
if(month==12)
{
if(amount>0)
{
month=0; year=year+1;
m_out += String.format(
"
"
+""
+"month payment interest"
+" principal balance ",
year);
}
else
{
break;
}
}
}
// time the process and close the HTML page
m_out += String.format(
"
This page was generated in %,.2f ms."
+" (on a 3GHz CPU 1 ms = 3,000,000 cycles)"
+" ", (Gwan.getUs() - start)/1000.0);
}
Gwan.xbufCat(Gwan.getReply(env), m_out);
return 200;
}
}
// ============================================================================
// End of Source Code
// ============================================================================