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    }