1 24 package edu.rice.rubis.client; 25 26 import java.io.BufferedInputStream ; 27 import java.io.IOException ; 28 import java.io.InputStream ; 29 import java.net.URL ; 30 import java.util.Random ; 31 import java.util.Vector ; 32 33 41 public class UserSession extends Thread 42 { 43 private RUBiSProperties rubis = null; private URLGenerator urlGen = null; private TransitionTable transition = null; private String lastHTMLReply = null; private Random rand = new Random (); private int userId; private String username = null; private String password = null; private URL lastURL = null; private int lastItemId = -1; private int lastUserId = -1; private Stats stats; private int debugLevel = 0; 76 81 89 public UserSession(String threadId, URLGenerator URLGen, 90 RUBiSProperties RUBiS, Stats statistics) 91 { 92 super(threadId); 93 urlGen = URLGen; 94 rubis = RUBiS; 95 stats = statistics; 96 debugLevel = rubis.getMonitoringDebug(); 102 transition = new TransitionTable(rubis.getNbOfColumns(), rubis 103 .getNbOfRows(), statistics, rubis.useTPCWThinkTime()); 104 if (!transition.ReadExcelTextFile(rubis.getTransitionTable())) 105 Runtime.getRuntime().exit(1); 106 } 107 108 114 private String callHTTPServer(URL url) 115 { 116 String HTMLReply = ""; 117 BufferedInputStream in = null; 118 InputStream urlStream = null; 119 int retry = 0; 120 121 try 122 { 123 while (retry < 5) 124 { 125 try 127 { 128 urlStream = url.openStream(); 129 in = new BufferedInputStream (urlStream, 4096); 130 } 132 catch (IOException ioe) 133 { 134 if (debugLevel > 0) 135 System.err.println("Thread " + this.getName() 136 + ": Unable to open URL " + url + " (" + ioe.getMessage() 137 + ")<br>"); 138 retry++; 139 try 140 { 141 Thread.sleep(1000L); 142 } 143 catch (InterruptedException i) 144 { 145 if (debugLevel > 0) 146 System.err.println("Thread " + this.getName() 147 + ": Interrupted in callHTTPServer()<br>"); 148 return null; 149 } 150 continue; 151 } 152 153 try 155 { 156 byte[] buffer = new byte[4096]; 157 int read; 158 159 while ((read = in.read(buffer, 0, buffer.length)) != -1) 160 { 161 if (read > 0) 162 HTMLReply = HTMLReply + new String (buffer, 0, read); 163 } 164 } 165 catch (IOException ioe) 166 { 167 if (debugLevel > 0) 168 System.err.println("Thread " + this.getName() 169 + ": Unable to read from URL " + url + " (" + ioe.getMessage() 170 + ")<br>"); 171 return null; 172 } 173 174 break; 176 } 177 } 178 catch (Exception ignore) 179 { 180 } 181 finally 182 { 183 try 184 { 185 if (in != null) 186 in.close(); 187 } 188 catch (IOException ioe) 189 { 190 if (debugLevel > 0) 191 System.err.println("Thread " + this.getName() 192 + ": Unable to close URL " + url + " (" + ioe.getMessage() 193 + ")<br>"); 194 } 195 try 196 { 197 if (urlStream != null) 198 urlStream.close(); 199 } 200 catch (IOException ioe) 201 { 202 if (debugLevel > 0) 203 System.err.println("Thread " + this.getName() 204 + ": Unable to close URL " + url + " (" + ioe.getMessage() 205 + ")<br>"); 206 } 207 208 } 209 if (retry == 5) 210 return null; 211 212 Vector images = new Vector (); 214 int index = HTMLReply.indexOf("<IMG SRC=\""); 215 while (index != -1) 216 { 217 int startQuote = index + 10; int endQuote = HTMLReply.indexOf("\"", startQuote + 1); 219 images.add(HTMLReply.substring(startQuote, endQuote)); 220 index = HTMLReply.indexOf("<IMG SRC=\"", endQuote); 221 } 222 223 byte[] buffer = new byte[4096]; 225 while (images.size() > 0) 226 { 227 URL imageURL = urlGen.genericHTMLFile((String ) images.elementAt(0)); 228 try 229 { 230 InputStream imageStream = imageURL.openStream(); 231 BufferedInputStream inImage = new BufferedInputStream (imageStream, 4096); 232 while (inImage.read(buffer, 0, buffer.length) != -1) 233 ; inImage.close(); 235 imageStream.close(); 236 } 237 catch (IOException ioe) 238 { 239 if (debugLevel > 0) 240 System.err.println("Thread " + this.getName() 241 + ": Error while downloading image " + imageURL + " (" 242 + ioe.getMessage() + ")<br>"); 243 } 244 images.removeElementAt(0); 245 } 246 247 return HTMLReply; 248 } 249 250 258 private int isMin(int last_index, int x) 259 { 260 if (x == -1) 261 return last_index; 262 if (last_index <= x) 263 return last_index; 264 else 265 return x; 266 } 267 268 274 private int extractItemIdFromHTML() 275 { 276 if (lastHTMLReply == null) 277 { 278 if (debugLevel > 0) 279 System.err.println("Thread " + this.getName() 280 + ": There is no previous HTML reply<br>"); 281 return -1; 282 } 283 284 int count = 0; 286 int keyIndex = lastHTMLReply.indexOf("itemId="); 287 while (keyIndex != -1) 288 { 289 count++; 290 keyIndex = lastHTMLReply.indexOf("itemId=", keyIndex + 7); } 293 if (count == 0) 294 { 295 if (lastItemId >= 0) 296 return lastItemId; 297 if (debugLevel > 0) 298 System.err.println("Thread " + this.getName() 299 + ": Cannot found item id in last HTML reply<br>"); 300 if (debugLevel > 1) 301 System.err.println("Thread " + this.getName() 302 + ": Last HTML reply is: " + lastHTMLReply + "<br>"); 303 return -1; 304 } 305 306 count = rand.nextInt(count) + 1; 308 keyIndex = -7; 309 while (count > 0) 310 { 311 keyIndex = lastHTMLReply.indexOf("itemId=", keyIndex + 7); count--; 314 } 315 int lastIndex = isMin(Integer.MAX_VALUE, lastHTMLReply.indexOf('\"', 316 keyIndex + 7)); 317 lastIndex = isMin(lastIndex, lastHTMLReply.indexOf('?', keyIndex + 7)); 318 lastIndex = isMin(lastIndex, lastHTMLReply.indexOf('&', keyIndex + 7)); 319 lastIndex = isMin(lastIndex, lastHTMLReply.indexOf('>', keyIndex + 7)); 320 Integer foo = new Integer (lastHTMLReply.substring(keyIndex + 7, lastIndex)); 321 lastItemId = foo.intValue(); 322 return lastItemId; 323 } 324 325 331 private int extractPageFromHTML() 332 { 333 if (lastHTMLReply == null) 334 return 0; 335 336 int firstPageIndex = lastHTMLReply.indexOf("&page="); 337 if (firstPageIndex == -1) 338 return 0; 339 int secondPageIndex = lastHTMLReply.indexOf("&page=", firstPageIndex + 6); int chosenIndex = 0; 344 if (secondPageIndex == -1) 345 chosenIndex = firstPageIndex; else 348 { if (rand.nextInt(100000) < 50000) 350 chosenIndex = firstPageIndex; 351 else 352 chosenIndex = secondPageIndex; 353 } 354 int lastIndex = isMin(Integer.MAX_VALUE, lastHTMLReply.indexOf('\"', 355 chosenIndex + 6)); 356 lastIndex = isMin(lastIndex, lastHTMLReply.indexOf('?', chosenIndex + 6)); 357 lastIndex = isMin(lastIndex, lastHTMLReply.indexOf('&', chosenIndex + 6)); 358 lastIndex = isMin(lastIndex, lastHTMLReply.indexOf('>', chosenIndex + 6)); 359 Integer foo = new Integer (lastHTMLReply.substring(chosenIndex + 6, 360 lastIndex)); 361 return foo.intValue(); 362 } 363 364 381 private int extractIntFromHTML(String key) 382 { 383 if (lastHTMLReply == null) 384 { 385 if (debugLevel > 0) 386 System.err.println("Thread " + this.getName() 387 + ": There is no previous HTML reply"); 388 return -1; 389 } 390 391 int keyIndex = lastHTMLReply.indexOf(key); 393 if (keyIndex == -1) 394 { 395 if ((key.compareTo("userId=") == 0) && (lastUserId >= 0)) 397 return lastUserId; 398 if (debugLevel > 0) 399 System.err.println("Thread " + this.getName() + ": Cannot found " + key 400 + " in last HTML reply<br>"); 401 if (debugLevel > 1) 402 System.err.println("Thread " + this.getName() 403 + ": Last HTML reply is: " + lastHTMLReply + "<br>"); 404 return -1; 405 } 406 int lastIndex = isMin(Integer.MAX_VALUE, lastHTMLReply.indexOf('\"', 407 keyIndex + key.length())); 408 lastIndex = isMin(lastIndex, lastHTMLReply.indexOf('?', keyIndex 409 + key.length())); 410 lastIndex = isMin(lastIndex, lastHTMLReply.indexOf('&', keyIndex 411 + key.length())); 412 lastIndex = isMin(lastIndex, lastHTMLReply.indexOf('>', keyIndex 413 + key.length())); 414 Integer foo = new Integer (lastHTMLReply.substring(keyIndex + key.length(), 415 lastIndex)); 416 if (key.compareTo("userId=") == 0) 418 lastUserId = foo.intValue(); 419 return foo.intValue(); 420 } 421 422 439 private float extractFloatFromHTML(String key) 440 { 441 if (lastHTMLReply == null) 442 { 443 if (debugLevel > 0) 444 System.err.println("Thread " + this.getName() 445 + ": There is no previous HTML reply"); 446 return -1; 447 } 448 449 int keyIndex = lastHTMLReply.indexOf(key); 451 if (keyIndex == -1) 452 { 453 if (debugLevel > 0) 454 System.err.println("Thread " + this.getName() + ": Cannot found " + key 455 + " in last HTML reply<br>"); 456 if (debugLevel > 1) 457 System.err.println("Thread " + this.getName() 458 + ": Last HTML reply is: " + lastHTMLReply + "<br>"); 459 return -1; 460 } 461 int lastIndex = isMin(Integer.MAX_VALUE, lastHTMLReply.indexOf('\"', 462 keyIndex + key.length())); 463 lastIndex = isMin(lastIndex, lastHTMLReply.indexOf('?', keyIndex 464 + key.length())); 465 lastIndex = isMin(lastIndex, lastHTMLReply.indexOf('&', keyIndex 466 + key.length())); 467 lastIndex = isMin(lastIndex, lastHTMLReply.indexOf('>', keyIndex 468 + key.length())); 469 Float foo = new Float (lastHTMLReply.substring(keyIndex + key.length(), 470 lastIndex)); 471 return foo.floatValue(); 472 } 473 474 481 public URL computeURLFromState(int state) 482 { 483 if (lastHTMLReply != null) 484 { 485 if (lastHTMLReply.indexOf("Sorry") != -1) state = transition.backToPreviousState(); 488 } 489 switch (state) 490 { 491 case -1 : 492 transition.resetToInitialState(); 494 case 0 : 495 return urlGen.homePage(); 497 case 1 : 498 return urlGen.register(); 500 case 2 : 501 { int i = rubis.getNbOfUsers() + rand.nextInt(1000000) + 1; 504 String firstname = "Great" + i; 505 String lastname = "User" + i; 506 String nickname = "user" + i; 507 String email = firstname + "." + lastname + "@rubis.com"; 508 String password = "password" + i; 509 String regionName = (String ) rubis.getRegions().elementAt( 510 i % rubis.getNbOfRegions()); 511 512 return urlGen.registerUser(firstname, lastname, nickname, email, 513 password, regionName); 514 } 515 case 3 : 516 return urlGen.browse(); 518 case 4 : 519 return urlGen.browseCategories(); 521 case 5 : 522 { int categoryId = rand.nextInt(rubis.getNbOfCategories()); 526 String categoryName = (String ) rubis.getCategories().elementAt( 527 categoryId); 528 return urlGen.browseItemsInCategory(categoryId, categoryName, 529 extractPageFromHTML(), rubis.getNbOfItemsPerPage()); 530 } 531 case 6 : 532 return urlGen.browseRegions(); 534 case 7 : 535 String regionName = (String ) rubis.getRegions().elementAt( 537 rand.nextInt(rubis.getNbOfRegions())); 538 return urlGen.browseCategoriesInRegion(regionName); 539 case 8 : 540 { int categoryId = rand.nextInt(rubis.getNbOfCategories()); 544 String categoryName = (String ) rubis.getCategories().elementAt( 545 categoryId); 546 int regionId = rand.nextInt(rubis.getNbOfRegions()); 547 return urlGen.browseItemsInRegion(categoryId, categoryName, regionId, 548 extractPageFromHTML(), rubis.getNbOfItemsPerPage()); 549 } 550 case 9 : 551 { 553 int itemId = extractItemIdFromHTML(); 554 if (itemId == -1) 555 return computeURLFromState(transition.backToPreviousState()); else 559 return urlGen.viewItem(itemId); 560 } 561 case 10 : 562 { 564 int userId = extractIntFromHTML("userId="); 565 if (userId == -1) 566 return computeURLFromState(transition.backToPreviousState()); else 570 return urlGen.viewUserInformation(userId); 571 } 572 case 11 : 573 return urlGen.viewBidHistory(extractItemIdFromHTML()); 575 case 12 : 576 return urlGen.buyNowAuth(extractItemIdFromHTML()); 578 case 13 : 579 return urlGen.buyNow(extractItemIdFromHTML(), username, password); 581 case 14 : 582 { 584 int maxQty = extractIntFromHTML("name=maxQty value="); 585 if (maxQty < 1) 586 maxQty = 1; 587 int qty = rand.nextInt(maxQty) + 1; 588 return urlGen.storeBuyNow(extractItemIdFromHTML(), userId, qty, 589 maxQty); 590 } 591 case 15 : 592 return urlGen.putBidAuth(extractItemIdFromHTML()); 594 case 16 : 595 { 597 int itemId = extractItemIdFromHTML(); 598 if (itemId == -1) 599 return computeURLFromState(transition.backToPreviousState()); else 603 return urlGen.putBid(itemId, username, password); 604 } 605 case 17 : 606 { 611 int maxQty = extractIntFromHTML("name=maxQty value="); 612 if (maxQty < 1) 613 maxQty = 1; 614 int qty = rand.nextInt(maxQty) + 1; 615 float minBid = extractFloatFromHTML("name=minBid value="); 616 float addBid = rand.nextInt(10) + 1; 617 float bid = minBid + addBid; 618 float maxBid = minBid + addBid * 2; 619 return urlGen.storeBid(extractItemIdFromHTML(), userId, minBid, bid, 620 maxBid, qty, maxQty); 621 } 622 case 18 : 623 return urlGen.putCommentAuth(extractItemIdFromHTML(), 625 extractIntFromHTML("to=")); 626 case 19 : 627 return urlGen.putComment(extractItemIdFromHTML(), 629 extractIntFromHTML("to="), username, password); 630 case 20 : 631 { String [] staticComment = { 634 "This is a very bad comment. Stay away from this seller !!<br>", 635 "This is a comment below average. I don't recommend this user !!<br>", 636 "This is a neutral comment. It is neither a good or a bad seller !!<br>", 637 "This is a comment above average. You can trust this seller even if it is not the best deal !!<br>", 638 "This is an excellent comment. You can make really great deals with this seller !!<br>"}; 639 int[] staticCommentLength = {staticComment[0].length(), 640 staticComment[1].length(), staticComment[2].length(), 641 staticComment[3].length(), staticComment[4].length()}; 642 int[] ratingValue = {-5, -3, 0, 3, 5}; 643 int rating; 644 String comment; 645 646 rating = rand.nextInt(5); 647 int commentLength = rand.nextInt(rubis.getCommentMaxLength()) + 1; 648 comment = ""; 649 while (staticCommentLength[rating] < commentLength) 650 { 651 comment = comment + staticComment[rating]; 652 commentLength -= staticCommentLength[rating]; 653 } 654 comment = staticComment[rating].substring(0, commentLength); 655 656 return urlGen.storeComment(extractItemIdFromHTML(), 657 extractIntFromHTML("name=to value="), userId, 658 ratingValue[rating], comment); 659 } 660 case 21 : 661 return urlGen.sell(); 663 case 22 : 664 return urlGen.selectCategoryToSellItem(username, password); 666 case 23 : 667 { 668 int categoryId = rand.nextInt(rubis.getNbOfCategories()); 669 return urlGen.sellItemForm(categoryId, userId); 670 } 671 case 24 : 672 { 674 String name; 675 String description; 676 float initialPrice; 677 float reservePrice; 678 float buyNow; 679 int duration; 680 int quantity; 681 int categoryId; 682 String staticDescription = "This incredible item is exactly what you need !<br>It has a lot of very nice features including " 683 + "a coffee option.<br>It comes with a free license for the free RUBiS software, that's really cool. But RUBiS even if it " 684 + "is free, is <B>(C) Rice University/INRIA 2001</B>. It is really hard to write an interesting generic description for " 685 + "automatically generated items, but who will really read this <br>You can also check some cool software available on " 686 + "http://sci-serv.inrialpes.fr. There is a very cool DSM system called SciFS for SCI clusters, but you will need some " 687 + "SCI adapters to be able to run it ! Else you can still try CART, the amazing 'Cluster Administration and Reservation " 688 + "Tool'. All those software are open source, so don't hesitate ! If you have a SCI Cluster you can also try the Whoops! " 689 + "clustered web server. Actually Whoops! stands for something ! Yes, it is a Web cache with tcp Handoff, On the fly " 690 + "cOmpression, parallel Pull-based lru for Sci clusters !! Ok, that was a lot of fun but now it is starting to be quite late " 691 + "and I'll have to go to bed very soon, so I think if you need more information, just go on <h1>http://sci-serv.inrialpes.fr</h1> " 692 + "or you can even try http://www.cs.rice.edu and try to find where Emmanuel Cecchet or Julie Marguerite are and you will " 693 + "maybe get fresh news about all that !!<br>"; 694 int staticDescriptionLength = staticDescription.length(); 695 int totalItems = rubis.getTotalActiveItems() 696 + rubis.getNbOfOldItems(); 697 int i = totalItems + rand.nextInt(1000000) + 1; 698 699 name = "RUBiS automatically generated item #" + i; 700 int descriptionLength = rand 701 .nextInt(rubis.getItemDescriptionLength()) + 1; 702 description = ""; 703 while (staticDescriptionLength < descriptionLength) 704 { 705 description = description + staticDescription; 706 descriptionLength -= staticDescriptionLength; 707 } 708 description = staticDescription.substring(0, descriptionLength); 709 initialPrice = rand.nextInt(5000) + 1; 710 if (rand.nextInt(totalItems) < rubis.getPercentReservePrice() 711 * totalItems / 100) 712 reservePrice = rand.nextInt(1000) + initialPrice; 713 else 714 reservePrice = 0; 715 if (rand.nextInt(totalItems) < rubis.getPercentBuyNow() * totalItems 716 / 100) 717 buyNow = rand.nextInt(1000) + initialPrice + reservePrice; 718 else 719 buyNow = 0; 720 duration = rand.nextInt(7) + 1; 721 if (rand.nextInt(totalItems) < rubis.getPercentUniqueItems() 722 * totalItems / 100) 723 quantity = 1; 724 else 725 quantity = rand.nextInt(rubis.getMaxItemQty()) + 1; 726 categoryId = rand.nextInt(rubis.getNbOfCategories()); 727 return urlGen.registerItem(name, description, initialPrice, 728 reservePrice, buyNow, duration, quantity, userId, categoryId); 729 } 730 case 25 : 731 return urlGen.aboutMe(); 733 case 26 : 734 return urlGen.aboutMe(username, password); 736 default : 737 if (debugLevel > 0) 738 System.err.println("Thread " + this.getName() 739 + ": This state is not supported (" + state + ")<br>"); 740 return null; 741 } 742 } 743 744 747 public void run() 748 { 749 int nbOfTransitions = 0; 750 int next = 0; 751 long time = 0; 752 long startSession = 0; 753 long endSession = 0; 754 755 while (!ClientEmulator.isEndOfSimulation()) 756 { 757 userId = rand.nextInt(rubis.getNbOfUsers()); 759 username = "user" + (userId + 1); 760 password = "password" + (userId + 1); 761 nbOfTransitions = rubis.getMaxNbOfTransitions(); 762 if (debugLevel > 2) 763 System.out.println("Thread " + this.getName() 764 + ": Starting a new user session for " + username + " ...<br>"); 765 startSession = System.currentTimeMillis(); 766 transition.resetToInitialState(); 768 next = transition.getCurrentState(); 769 while (!ClientEmulator.isEndOfSimulation() 770 && !transition.isEndOfSession() && (nbOfTransitions > 0)) 771 { 772 lastURL = computeURLFromState(next); 775 time = System.currentTimeMillis(); 776 lastHTMLReply = callHTTPServer(lastURL); 777 stats.updateTime(next, System.currentTimeMillis() - time); 778 if (lastHTMLReply == null) 779 { 780 if (debugLevel > 0) 781 System.out.println("Thread "+this.getName()+": Cannot connect to HTTP server."); 782 transition.resetToInitialState(); 783 next = transition.getCurrentState(); 784 } 785 786 else if (lastHTMLReply.indexOf("ERROR") != -1) 788 { 789 if (debugLevel > 0) 790 System.out.println("Thread " + this.getName() 791 + ": Error returned from access to " + lastURL + "<br>"); 792 stats.incrementError(next); 793 if (debugLevel > 1) 794 System.out.println("Thread " + this.getName() 795 + ": HTML reply was: " + lastHTMLReply + "<br>"); 796 transition.resetToInitialState(); 797 next = transition.getCurrentState(); 798 } 799 else 800 next = transition.nextState(); 801 nbOfTransitions--; 802 } 803 if ((transition.isEndOfSession()) || (nbOfTransitions == 0)) 804 { 805 if (debugLevel > 2) 806 System.out.println("Thread " + this.getName() + ": Session of " 807 + username + " successfully ended<br>"); 808 endSession = System.currentTimeMillis(); 809 long sessionTime = endSession - startSession; 810 stats.addSessionTime(sessionTime); 811 } 812 else 813 { 814 if (debugLevel > 2) 815 System.out.println("Thread " + this.getName() + ": Session of " 816 + username + " aborted<br>"); 817 } 818 } 819 } 820 821 } 822 | Popular Tags |