1. Trang chủ
  2. » Công Nghệ Thông Tin

More Java Pitfalls 50 New Time-Saving Solutions and Workarounds phần 7 pps

48 189 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 48
Dung lượng 1,18 MB

Nội dung

A new regular expression pattern is used to strip out additional links in the HTML pages to spider on subsequent levels. The <a href></a> pattern is the target expres- sion to be parsed from the text. The (a|A) groupings are used so that both lowercase and uppercase expressions are matched. Pattern pattern = Pattern.compile(“<(a|A) href+[^<]*</(a|A)>”); Matcher match = pattern.matcher(pageOutput); %> <tr bgcolor=”#eeeeee”> <td align=”center”> Links for next Level: <%= filename %></td> </tr> <% // display all the references found in the URI while (match.find()) { // split words String[] sw = match.group(0).split(“[\”]”); if ((sw.length > 1) && (sw[1].startsWith(“http://”)) && Æ (sw[1].endsWith(“html”))) { %> <tr><td> <% out.println(“webpage=” + sw[1]); vRef.addElement(sw[1]); %> </td></tr> <% } } The Web page displayed in Figure 30.2 is the result of the spidering action of the code snippet above, which resides in the regexpTest.jsp application. The results shown below the Submit button are the links parsed from the Web page requested in the URI field. Java Regular Expressions are a powerful new language construct that strengthens string manipulation activities for developers. With Java Regular Expressions, Java developers can realize in their text processing activities what Perl programmers have been lauding about for years. 268 Item 30 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Figure 30.2 Spider results. Item 31: Instance Variables in Servlets A common trap that new servlet developers find themselves in revolves around the use of instance variables. Unfortunately, the symptoms of this problem are not easy to diagnose until the last minute. The developer writes the servlet, and it goes through standalone testing just fine. When it is load-tested (or when it goes into production with many concurrent users), however, strange things start to occur on an ad hoc basis: garbled strings of nonsense begin appearing in Web browsers, users of the enterprise Web system begin receiving other users’ information, and seemingly “random” errors appear in the application. What went wrong? A simple example of this situation can be seen in Listing 31.1, where we have an example application that serves as a library of technical resources. Our fictional “Online Technobabble Library” is a document repository where multiple users can check out, check in, and read multiple documents with a lot of technobabble. The servlet takes a parameter, userid, which tells the servlet where to get the user’s information. Instance Variables in Servlets 269 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 001: package org.javapitfalls.item31; 002: import java.io.*; 003: import java.text.*; 004: import java.util.*; 005: import javax.servlet.*; 006: import javax.servlet.http.*; 007: /** 008: * This example demonstrates using instance variables 009: * in a servlet The example features a fictional 010: * “TechnoBabble Library”, where users can check out 011: * and check in technical documentation. 012: */ 013: public class BadTechnobabbleLibraryServlet 014: extends HttpServlet 015: { 016: 017: PrintWriter m_out = null; 018: String m_useridparam = null; 019: 020: 021: /** 022: * doGet() method for a HTTP GET 023: * 024: * @param request the HttpServletRequest object 025: * @param response the HttpServletResponse object 026: */ 027: public void doGet(HttpServletRequest request, 028: HttpServletResponse response) 029: throws ServletException, IOException 030: { 031: String title = “Online Technobabble Library”; 032: response.setContentType(“text/html”); 033: m_out = response.getWriter(); 034: m_useridparam = request.getParameter(“userid”); 035: 036: m_out.println(“<HTML>”); 037: m_out.println(“<TITLE>” + title + “</TITLE>”); 038: m_out.println(“<BODY BGCOLOR=’WHITE’>”); 039: m_out.println(“<CENTER><H1>” + title + 040: “</H1></CENTER>”); 041: m_out.println(“<HR>”); 042: 043: //This will put the user’s personal page in 044: putInUserData(); 045: m_out.println(“<HR>”); 046: m_out.println(“</BODY></HTML>”); 047: } 048: 049: Listing 31.1 A bad example! 270 Item 31 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 050: /** 051: * doPost() method for a HTTP PUT 052: * 053: * @param request the HttpServletRequest Object 054: * @param response the HttpServletResponse Object 055: */ 056: public void doPost(HttpServletRequest request, 057: HttpServletResponse response) 058: throws ServletException, IOException 059: { 060: doGet(request, response); 061: } 062: 063: 064: /** 065: * This method reads the user’s data from the filesystem 066: * and writes the data to the browser screen. 067: */ 068: private void putInUserData() throws IOException 069: { 070: 071: BufferedReader br = null; 072: String fn = m_useridparam + “.html”; 073: String htmlfile = 074: getServletContext().getRealPath(fn); 075: 076: System.out.println(“debug: Trying to open “ 077: + htmlfile); 078: 079: File htmlSnippetFile = new File(htmlfile); 080: try 081: { 082: String line; 083: 084: //Check to see if it exists first 085: if (!htmlSnippetFile.exists()) 086: { 087: m_out.println(“File “ + fn + “not found!”); 088: return; 089: } 090: 091: br = new BufferedReader(new FileReader(htmlfile)); 092: 093: /* 094: * Now, let’s read it 095: * Since finding the bad behavior in this pitfall 096: * revolves around timing, we will only read 2 097: * characters at a time so that the bad behavior 098: * can be easily seen. Listing 31.1 (continued) Instance Variables in Servlets 271 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 099: */ 100: 101: char[] buffer = new char[2]; 102: int count = 0; 103: do 104: { 105: m_out.write(buffer, 0, count); 106: m_out.flush(); 107: count = br.read(buffer, 0, buffer.length); 108: } 109: while (count != -1); 110: } 111: catch (Exception e) 112: { 113: m_out.println( 114: “Error in reading file!!” 115: ); 116: e.printStackTrace(System.err); 117: } 118: finally 119: { 120: if (br != null) 121: br.close(); 122: } 123: 124: } 125: } 126: 127: Listing 31.1 (continued) Looking at the code in lines 17 and 18 of Listing 31.1, we have two instance vari- ables. The PrintWriter m_out and the String m_useridparam are assigned in the doGet() method on lines 33 and 34. After the doGet() method initializes these variables, the putInUserData() method is called to read the user-specific HTML files and print these out to the browser screen. Tested alone, a screen capture of the browser window looks fine, as shown in Figure 31.1. However, during load testing, multiple users log in and many see the screen shown in Figure 31.2. The result seems like a combination of many screens and looks like non- sense. What happened? Because instance variables are set in the doGet() method in Listing 31.1 and are used later in the servlet in the putInUserData() method, the servlet is not thread-safe. Because many users access the servlet at the same time, and because the instance vari- ables are written to and referenced by multiple areas of the servlet, the values of the m_out variable and the m_useridparams variables have the potential to be clobbered! 272 Item 31 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Figure 31.1 Our example with one concurrent user. For example, when one user runs his servlet, the servlet could be setting the m_out vari- able for his session while another user’s session is writing with the m_out variable. Figure 31.3 shows us a time line of how this strange behavior occurred in our example from Listing 31.1. In the time line, we have two fictitious users of the system, Alice and Bob. At time t0, the servlet engine first instantiates the servlet, where the instance vari- ables are declared in lines 17 and 18 of Listing 31.1. At time t1, the servlet engine calls the servlet’s init() method. At time t2, Alice loads the servlet, which calls the servlet’s doGet() method. At time t3, the instance variables m_out and m_useridparam are set just for Alice. At the same time, Bob loads the servlet, which calls the servlet’s doGet() method. At time t4, Alice’s servlet gets to the point where the putInUserData() method is called, which loads her information and begins printing to the PrintWriter variable, m_out. At the same time, Bob’s servlet is in the execution of doGet(), where the instance variables m_out and m_useridparam are set. Time t5 in Figure 31.3 is where everything seems to go nuts. Since Bob reset the servlet’s instance variable m_out, Alice continues to print her information, but it goes to Bob’s browser! When Bob also begins printing to m_out, he sees a combination of his information and Alice’s information. The result is something like the screen shot that we showed in Figure 31.2. Instance Variables in Servlets 273 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Figure 31.2 Chaos: Our example with concurrent users. In fact, we chose the example so that this strange behavior could be shown easily. Each servlet client (or user Web browser) will need its own PrintWriter, and because each servlet is a thread in the server’s virtual machine, m_out can be trampled on whenever a new user loads the servlet, producing scary output. In practice, these types of errors can be difficult to detect until load testing, because errors occur with timing when multiple clients hit the server at once. In fact, we couldn’t see any tangi- ble ramifications of assigning the variable m_useridparam, because the timing has to be right to actually see the effects. We have seen one situation where a customer’s requirements were to provide sensitive and confidential data to its users. The software developers used instance variables in their servlets for printing information gathered from each user’s database connection. When the developers were testing it alone, the system seemed to work fine. When the system went in for load testing with several dif- ferent users, the testers saw the other users’ confidential data. 274 Item 31 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Figure 31.3 Time line of data corruption. servlet instantiated servlet's init() method is called Alice loads up a servlet, calling the servlet's doGet() method in doGet(), the m_out and m_useridparam variables are set to Alice's settings Alice's servlet calls the putInUserData() method which loads the file based on m_useridparam, and begins printing that file to Alice's browser t4based on m_out During printing in putUserData(), Alice begins printing to the m_out variable set by Bob, which goes to Bob's browser Alice is not happy, because she did not receive her entire document. If she reloads at this point, she may even get some of Bob's information Bob loads up the servlet, calling the servlet's doGet() method in doGet(), the m_out and m_useridparam variables are set to the settings of Bob's info Bob's servlet calls the putInUserData() method, which starts printing Bob's info, which also go to Bob's browser, in addition to Alice's information Bob is not happy, because he received a combination of his information AND Alice's information t0 t1 t2 t3 t4 t5 t6 Instance Variables in Servlets 275 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com What if you use instance variables but only set them at instantiation? In this case, you may not run into any concurrency issues. However, this could lead to other pitfalls if you do not keep the lifecycle of the servlet in mind. Here is a bad example that we saw recently: //Here Is an Instance variable that we will be using later ServletContext m_sc = getServletContext(); The programmer who wrote that snippet of code assumed that since the variable was set at instantiation and never set again, no concurrency issues would arise. That is true. Unfortunately, because the init() method sets the servlet’s ServletContext object after instantiation, the servlet ran into a big problem: The value of the instance variable m_sc was null, resulting in a NullPointerException later on in the servlet. Because the instance variable was set at instantiation of the servlet, and not after the init() method was called, the servlet had big problems. So what is the best solution to this pitfall? Be very hesitant in using instance vari- ables in servlets. Certainly, you could continue to use instance variables and synchro- nize them whenever you need to access or set the instance variable, but that could create code that is very complex-looking, inflexible, and ugly. Instead, try to pass the variables and objects that you will need to your other methods. If it gets to the point where you believe that you have too many variables to pass around, create a class that serves as a container for these variables. Instantiate the class with the variables you need, and pass the object around. Listing 31.2 shows a better approach to our earlier “Online Technobabble Library” example. Instead of having instance variables, we create the variables that we need in the doGet() method in lines 32 and 33, and we pass them to the putInUserData() method. The result is code that is thread-safe. 001: package org.javapitfalls.item31; 002: import java.io.*; 003: import java.text.*; 004: import java.util.*; 005: import javax.servlet.*; 006: import javax.servlet.http.*; 007: /** 008: * This example demonstrates using instance variables 009: * in a servlet The example features a fictional 010: * “TechnoBabble Library”, where users can check out 011: * and check in technical documentation. 012: */ 013: public class GoodTechnobabbleLibraryServlet extends 014: HttpServlet 015: { 016: 017: /** 018: * doGet() method for a HTTP GET Listing 31.2 A better application solution 276 Item 31 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 019: * 020: * @param request the HttpServletRequest object 021: * @param response the HttpServletResponse object 022: */ 023: public void doGet(HttpServletRequest request, 024: HttpServletResponse response) 025: throws ServletException, IOException 026: { 027: PrintWriter out; 028: String userid; 029: String title = “Online Technobabble Library”; 030: 031: response.setContentType(“text/html”); 032: out = response.getWriter(); 033: userid = request.getParameter(“userid”); 034: 035: out.println(“<HTML>”); 036: out.println(“<TITLE>” + title + “</TITLE>”); 037: out.println(“<BODY BGCOLOR=’WHITE’>”); 038: out.println(“<CENTER><H1>” + title + 039: “</H1></CENTER>”); 040: out.println(“<HR>”); 041: 042: //This will put the user’s personal page in 043: putInUserData(out, userid); 044: out.println(“<HR>”); 045: out.println(“</BODY></HTML>”); 046: } 047: 048: 049: /** 050: * doPost() method for a HTTP PUT 051: * 052: * @param request the HttpServletRequest Object 053: * @param response the HttpServletResponse Object 054: */ 055: public void doPost(HttpServletRequest request, 056: HttpServletResponse response) 057: throws ServletException, IOException 058: { 059: doGet(request, response); 060: } 061: 062: 063: /** 064: * This method reads the user’s data from the filesystem 065: * and writes the data to the browser screen. 066: * 067: * @param out the printwriter we are using Listing 31.2 (continued) Instance Variables in Servlets 277 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com [...]... Amount”); 46: 47: //Load the inventory from the database 48: 49: try 50: { Listing 32.1 Specifying connection in a servlet Simpo PDF Merge Design Flaws with Creating Database Connections within Servlets 51: 52: 53: and Split 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70 : 71 : 72 : 73 : 74 : 75 : 76 : 77 : 78 : 79 : 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: } 90: 91: 92:} Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver”);... 283 284 Simpo PDF Item 32 049: 050: 051: Merge and 052: 053: 054: 055: 056: 0 57: 058: 059: 060: 061: 062: 063: 064: 065: 066: 0 67: 068: 069: 070 : 071 : 072 : 073 : 074 : 075 : 076 : 077 : 078 : 079 : 080: 081: 082: 083: 084: 085: 086: 0 87: 088: 089: 090: 091: 092: 093: 094: 095: 096: 0 97: HttpServletResponse response) throws IOException, ServletException { SplitdoPost(request,response); - http://www.simpopdf.com... 278 Simpo PDF Item 31 068: * @param userid the userid of the accessing user 069: */ 070 : private void putInUserData(PrintWriter out, Merge and Split Unregistered Version - http://www.simpopdf.com 071 : String userid) 072 : throws IOException 073 : { 074 : BufferedReader br = null; 075 : String fn = userid + “.html”; 076 : String htmlfile = 077 : getServletContext().getRealPath(fn); 078 : 079 : System.out.println(“debug:... usage of the Web application, the database begins refusing new connections What happened? 279 280 Simpo PDF Item 32 01: package org.javapitfalls.item32; 02: import java. io.*; 03: import java. sql.*; Merge and Split Unregistered Version - http://www.simpopdf.com 04: import java. text.*; 05: import java. util.*; 06: import javax.servlet.*; 07: import javax.servlet.http.*; 08: public class BadQueryServlet extends... 0 67: //Load the inventory from the database 068: 069: try 070 : { 071 : 072 : Connection con = m_dbsingleton.getConnection(); 073 : if (con == null) Listing 32.4 (continued) 289 290 Simpo PDF Item 32 074 : { 075 : out.println(“There are currently database problems “ + 076 : “Please see your administrator for details.”); Merge and Split Unregistered Version - http://www.simpopdf.com 077 : return; 078 :... getPollOfTheDay() method on the VoterApp object 01: 02: 03: 04: 05: 06: 07: 08: 09: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: package org.javapitfalls.item33; import java. io.*; import java. text.*; import java. util.*; import javax.servlet.*; import javax.servlet.http.*; /* Bad Voter Servlet Example */ public class BadVoterServlet... Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Figure 34.2 Loading with file protocol misapplied 01: java. net.UnknownHostException: D 02: at java. net.InetAddress.getAllByName0(InetAddress .java: 571 ) 03: at java. net.InetAddress.getAllByName0(InetAddress .java: 540) 04: at java. net.InetAddress.getByName(InetAddress .java: 449) 05: at java. net.Socket.(Socket .java: 100) 06: at... Connection broker!”); 75 : } 76 : return (m_broker.getConnection()); 77 : } 78 : 79 : /* Listing 32.3 (continued) 2 87 288 Simpo PDF Item 32 80: * frees the connection from the broker class 81: */ 82: public synchronized void freeConnection(Connection con) Merge and Split Unregistered Version - http://www.simpopdf.com 83: throws Exception 84: { 85: if (m_broker == null ) 86: { 87: throw new Exception(“Can’t... the VM 56: */ 57: public synchronized static LavenderDBSingleton getInstance() 58: { 59: if (m_singleton == null) 60: { 61: m_singleton = new LavenderDBSingleton(); 62: } 63: 64: return (m_singleton); 65: } 66: 67: /* 68: * calls getConnection() on the broker class 69: */ 70 : public synchronized Connection getConnection() throws Exception 71 : { 72 : if (m_broker == null) 73 : { 74 : throw new Exception(“Can’t... creating connections for every client 001: 002: 003: 004: 005: 006: 0 07: 008: 009: 010: 011: 012: 013: 014: 015: 016: 0 17: 018: 019: 020: 021: 022: 023: package org.javapitfalls.item32; import import import import import import java. io.*; java. sql.*; java. text.*; java. util.*; javax.servlet.*; javax.servlet.http.*; public class BestQueryServlet extends HttpServlet { //only set in the init() method, so concurrency . getConnection() throws Exception 71 : { 72 : if (m_broker == null) 73 : { 74 : throw new Exception(“Can’t get Connection broker!”); 75 : } 76 : return (m_broker.getConnection()); 77 : } 78 : 79 : /* Listing 32.3. (“EEE, MMM d, yyyy h:mm a”); 077 : java. util.Date newdate = 078 : new java. util.Date(Calendar.getInstance().getTime().getTime()); 079 : String datestring = sdf.format(newdate); 080: 081: out.println(“<H3>Inventory. “.html”; 073 : String htmlfile = 074 : getServletContext().getRealPath(fn); 075 : 076 : System.out.println(“debug: Trying to open “ 077 : + htmlfile); 078 : 079 : File htmlSnippetFile = new File(htmlfile); 080:

Ngày đăng: 13/08/2014, 12:21