001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.geronimo.samples.daytrader.web; 018 019 import javax.servlet.*; 020 import javax.servlet.http.*; 021 022 import org.apache.geronimo.samples.daytrader.util.*; 023 024 import java.util.Collection; 025 import java.util.Iterator; 026 import java.io.IOException; 027 import java.io.PrintWriter; 028 import org.apache.geronimo.samples.daytrader.*; 029 030 /** 031 * TradeScenarioServlet emulates a population of web users by generating a specific Trade operation 032 * for a randomly chosen user on each access to the URL. Test this servlet by clicking Trade Scenario 033 * and hit "Reload" on your browser to step through a Trade Scenario. To benchmark using this URL aim 034 * your favorite web load generator (such as AKStress) at the Trade Scenario URL and fire away. 035 */ 036 public class TradeScenarioServlet extends HttpServlet { 037 038 /** 039 * Servlet initialization method. 040 */ 041 public void init(ServletConfig config) throws ServletException 042 { 043 super.init(config); 044 java.util.Enumeration en = config.getInitParameterNames(); 045 while ( en.hasMoreElements() ) 046 { 047 String parm = (String) en.nextElement(); 048 String value = config.getInitParameter(parm); 049 TradeConfig.setConfigParam(parm, value); 050 } 051 } 052 053 /** 054 * Returns a string that contains information about TradeScenarioServlet 055 * 056 * @return The servlet information 057 */ 058 public java.lang.String getServletInfo() 059 { 060 return "TradeScenarioServlet emulates a population of web users"; 061 } 062 063 064 065 /** 066 * Process incoming HTTP GET requests 067 * 068 * @param request Object that encapsulates the request to the servlet 069 * @param response Object that encapsulates the response from the servlet 070 */ 071 public void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) 072 throws ServletException, IOException 073 { 074 performTask(request,response); 075 } 076 077 /** 078 * Process incoming HTTP POST requests 079 * 080 * @param request Object that encapsulates the request to the servlet 081 * @param response Object that encapsulates the response from the servlet 082 */ 083 public void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) 084 throws ServletException, IOException 085 { 086 performTask(request,response); 087 } 088 089 /** 090 * Main service method for TradeScenarioServlet 091 * 092 * @param request Object that encapsulates the request to the servlet 093 * @param response Object that encapsulates the response from the servlet 094 */ 095 public void performTask(HttpServletRequest req, HttpServletResponse resp) 096 throws ServletException, IOException { 097 098 // Scenario generator for Trade2 099 char action = ' '; 100 String userID = null; 101 102 // String to create full dispatch path to TradeAppServlet w/ request Parameters 103 String dispPath = null; // Dispatch Path to TradeAppServlet 104 105 String scenarioAction = (String) req.getParameter("action"); 106 if ((scenarioAction != null) && (scenarioAction.length() >= 1)) 107 { 108 action = scenarioAction.charAt(0); 109 if (action == 'n') 110 { //null; 111 try 112 { 113 resp.setContentType("text/html"); 114 PrintWriter out = new PrintWriter(resp.getOutputStream()); 115 out.println("<HTML><HEAD>TradeScenarioServlet</HEAD><BODY>Hello</BODY></HTML>"); 116 out.close(); 117 return; 118 119 } 120 catch (Exception e) 121 { 122 Log.error( 123 "trade_client.TradeScenarioServlet.service(...)" + 124 "error creating printwriter from responce.getOutputStream", e); 125 126 resp.sendError( 127 500, 128 "trade_client.TradeScenarioServlet.service(...): erorr creating and writing to PrintStream created from response.getOutputStream()"); 129 } //end of catch 130 131 } //end of action=='n' 132 } 133 134 135 ServletContext ctx = null; 136 HttpSession session = null; 137 try 138 { 139 ctx = getServletConfig().getServletContext(); 140 // These operations require the user to be logged in. Verify the user and if not logged in 141 // change the operation to a login 142 session = req.getSession(true); 143 userID = (String) session.getAttribute("uidBean"); 144 } 145 catch (Exception e) 146 { 147 Log.error( 148 "trade_client.TradeScenarioServlet.service(...): performing " + scenarioAction + 149 "error getting ServletContext,HttpSession, or UserID from session" + 150 "will make scenarioAction a login and try to recover from there", e); 151 userID = null; 152 action = 'l'; 153 } 154 155 if (userID == null) 156 { 157 action = 'l'; // change to login 158 TradeConfig.incrementScenarioCount(); 159 } 160 else if (action == ' ') { 161 //action is not specified perform a random operation according to current mix 162 // Tell getScenarioAction if we are an original user or a registered user 163 // -- sellDeficits should only be compensated for with original users. 164 action = TradeConfig.getScenarioAction( 165 userID.startsWith(TradeConfig.newUserPrefix)); 166 } 167 switch (action) 168 { 169 170 case 'q' : //quote 171 dispPath = tasPathPrefix + "quotes&symbols=" + TradeConfig.rndSymbols(); 172 ctx.getRequestDispatcher(dispPath).include(req, resp); 173 break; 174 case 'a' : //account 175 dispPath = tasPathPrefix + "account"; 176 ctx.getRequestDispatcher(dispPath).include(req, resp); 177 break; 178 case 'u' : //update account profile 179 dispPath = tasPathPrefix + "account"; 180 ctx.getRequestDispatcher(dispPath).include(req, resp); 181 182 String fullName = "rnd" + System.currentTimeMillis(); 183 String address = "rndAddress"; 184 String password = "xxx"; 185 String email = "rndEmail"; 186 String creditcard = "rndCC"; 187 dispPath = tasPathPrefix + "update_profile&fullname=" + fullName + 188 "&password=" + password + "&cpassword=" + password + 189 "&address=" + address + "&email=" + email + 190 "&creditcard=" + creditcard; 191 ctx.getRequestDispatcher(dispPath).include(req, resp); 192 break; 193 case 'h' : //home 194 dispPath = tasPathPrefix + "home"; 195 ctx.getRequestDispatcher(dispPath).include(req, resp); 196 break; 197 case 'l' : //login 198 userID = TradeConfig.getUserID(); 199 String password2 = "xxx"; 200 dispPath = tasPathPrefix + "login&inScenario=true&uid=" + userID + "&passwd=" + password2; 201 ctx.getRequestDispatcher(dispPath).include(req, resp); 202 203 // login is successful if the userID is written to the HTTP session 204 if (session.getAttribute("uidBean") == null) { 205 System.out.println("TradeScenario login failed. Reset DB between runs"); 206 } 207 break; 208 case 'o' : //logout 209 dispPath = tasPathPrefix + "logout"; 210 ctx.getRequestDispatcher(dispPath).include(req, resp); 211 break; 212 case 'p' : //portfolio 213 dispPath = tasPathPrefix + "portfolio"; 214 ctx.getRequestDispatcher(dispPath).include(req, resp); 215 break; 216 case 'r' : //register 217 //Logout the current user to become a new user 218 // see note in TradeServletAction 219 req.setAttribute("TSS-RecreateSessionInLogout", Boolean.TRUE); 220 dispPath = tasPathPrefix + "logout"; 221 ctx.getRequestDispatcher(dispPath).include(req, resp); 222 223 userID = TradeConfig.rndNewUserID(); 224 String passwd = "yyy"; 225 fullName = TradeConfig.rndFullName(); 226 creditcard = TradeConfig.rndCreditCard(); 227 String money = TradeConfig.rndBalance(); 228 email = TradeConfig.rndEmail(userID); 229 String smail = TradeConfig.rndAddress(); 230 dispPath = tasPathPrefix + "register&Full Name=" + fullName + "&snail mail=" + smail + 231 "&email=" + email + "&user id=" + userID + "&passwd=" + passwd + 232 "&confirm passwd=" + passwd + "&money=" + money + 233 "&Credit Card Number=" + creditcard; 234 ctx.getRequestDispatcher(dispPath).include(req, resp); 235 break; 236 case 's' : //sell 237 dispPath = tasPathPrefix + "portfolioNoEdge"; 238 ctx.getRequestDispatcher(dispPath).include(req, resp); 239 240 Collection holdings = (Collection) req.getAttribute("holdingDataBeans"); 241 int numHoldings = holdings.size(); 242 if (numHoldings > 0) 243 { 244 //sell first available security out of holding 245 246 Iterator it = holdings.iterator(); 247 boolean foundHoldingToSell = false; 248 while (it.hasNext()) 249 { 250 HoldingDataBean holdingData = (HoldingDataBean) it.next(); 251 if ( !(holdingData.getPurchaseDate().equals(new java.util.Date(0))) ) 252 { 253 Integer holdingID = holdingData.getHoldingID(); 254 255 dispPath = tasPathPrefix + "sell&holdingID="+holdingID; 256 ctx.getRequestDispatcher(dispPath).include(req, resp); 257 foundHoldingToSell = true; 258 break; 259 } 260 } 261 if (foundHoldingToSell) break; 262 if (Log.doTrace()) 263 Log.trace("TradeScenario: No holding to sell -switch to buy -- userID = " + userID + " Collection count = " + numHoldings); 264 265 } 266 // At this point: A TradeScenario Sell was requested with No Stocks in Portfolio 267 // This can happen when a new registered user happens to request a sell before a buy 268 // In this case, fall through and perform a buy instead 269 270 /* Trade 2.037: Added sell_deficit counter to maintain correct buy/sell mix. 271 * When a users portfolio is reduced to 0 holdings, a buy is requested instead of a sell. 272 * This throws off the buy/sell mix by 1. This results in unwanted holding table growth 273 * To fix this we increment a sell deficit counter to maintain the correct ratio in getScenarioAction 274 * The 'z' action from getScenario denotes that this is a sell action that was switched from a buy 275 * to reduce a sellDeficit 276 */ 277 if (userID.startsWith(TradeConfig.newUserPrefix) == false) 278 { 279 TradeConfig.incrementSellDeficit(); 280 } 281 case 'b' : //buy 282 String symbol = TradeConfig.rndSymbol(); 283 String amount = TradeConfig.rndQuantity() + ""; 284 285 dispPath = tasPathPrefix + "quotes&symbols=" + symbol; 286 ctx.getRequestDispatcher(dispPath).include(req, resp); 287 288 dispPath = tasPathPrefix + "buy&quantity=" + amount + "&symbol=" + symbol; 289 ctx.getRequestDispatcher(dispPath).include(req, resp); 290 break; 291 } //end of switch statement 292 } 293 294 // URL Path Prefix for dispatching to TradeAppServlet 295 private final static String tasPathPrefix = "/app?action="; 296 297 }