PrimeNumbers.java Servlet that processes a request to generate n prime numbers, each with at least m digits. If these results are not complete, it sends a Refresh header instructing the browser to ask for new results a little while later. Uses the Primes, PrimeList, and ServletUtilities classes.
package cwp; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; import java.util.*; /** Servlet that processes a request to generate n * prime numbers, each with at least m digits. * It performs the calculations in a low-priority background * thread, returning only the results it has found so far. * If these results are not complete, it sends a Refresh * header instructing the browser to ask for new results a * little while later. It also maintains a list of a * small number of previously calculated prime lists * to return immediately to anyone who supplies the * same n and m as a recent completed computation. * * Taken from Core Web Programming Java 2 Edition * from Prentice Hall and Sun Microsystems Press, * . * May be freely used or adapted. */ public class PrimeNumbers extends HttpServlet { private Vector primeListVector = new Vector(); private int maxPrimeLists = 30; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { int numPrimes = ServletUtilities.getIntParameter(request, "numPrimes", 50); int numDigits = ServletUtilities.getIntParameter(request, "numDigits", 120); PrimeList primeList = findPrimeList(primeListVector, numPrimes, numDigits); if (primeList == null) { primeList = new PrimeList(numPrimes, numDigits, true); // Multiple servlet request threads share the instance // variables (fields) of PrimeNumbers. So // synchronize all access to servlet fields. synchronized(primeListVector) { if (primeListVector.size() >= maxPrimeLists) primeListVector.removeElementAt(0); primeListVector.addElement(primeList); } } Vector currentPrimes = primeList.getPrimes(); int numCurrentPrimes = currentPrimes.size(); int numPrimesRemaining = (numPrimes - numCurrentPrimes); boolean isLastResult = (numPrimesRemaining == 0); if (!isLastResult) { response.setHeader("Refresh", "5"); } response.setContentType("text/html"); PrintWriter out = response.getWriter(); String title = "Some " + numDigits + "-Digit Prime Numbers"; out.println(ServletUtilities.headWithTitle(title) + "\n" + " " + title + " \n" + " Primes found with " + numDigits + " or more digits: " + numCurrentPrimes + ". "); if (isLastResult) out.println("Done searching."); else out.println("Still looking for " + numPrimesRemaining + " more..."); out.println(" "); for(int i=0; i" + currentPrimes.elementAt(i)); } out.println(" "); out.println(""); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } // See if there is an existing ongoing or completed // calculation with the same number of primes and number // of digits per prime. If so, return those results instead // of starting a new background thread. Keep this list // small so that the Web server doesn't use too much memory. // Synchronize access to the list since there may be // multiple simultaneous requests. private PrimeList findPrimeList(Vector primeListVector, int numPrimes, int numDigits) { synchronized(primeListVector) { for(int i=0; i * Taken from Core Web Programming Java 2 Edition * from Prentice Hall and Sun Microsystems Press, * . * May be freely used or adapted. */ public class Primes { // Note that BigInteger.ZERO was new in JDK 1.2, and 1.1 // code is being used to support the most servlet engines. private static final BigInteger ZERO = new BigInteger("0"); private static final BigInteger ONE = new BigInteger("1"); private static final BigInteger TWO = new BigInteger("2"); // Likelihood of false prime is less than 1/2^ERR_VAL // Assumedly BigInteger uses the Miller-Rabin test or // equivalent, and thus is NOT fooled by Carmichael numbers. // See section 33.8 of Cormen et al's Introduction to // Algorithms for details. private static final int ERR_VAL = 100; public static BigInteger nextPrime(BigInteger start) { if (isEven(start)) start = start.add(ONE); else start = start.add(TWO); if (start.isProbablePrime(ERR_VAL)) return(start); else return(nextPrime(start)); } private static boolean isEven(BigInteger n) { return(n.mod(TWO).equals(ZERO)); } private static StringBuffer[] digits = { new StringBuffer("0"), new StringBuffer("1"), new StringBuffer("2"), new StringBuffer("3"), new StringBuffer("4"), new StringBuffer("5"), new StringBuffer("6"), new StringBuffer("7"), new StringBuffer("8"), new StringBuffer("9") }; private static StringBuffer randomDigit() { int index = (int)Math.floor(Math.random() * 10); return(digits[index]); } public static BigInteger random(int numDigits) { StringBuffer s = new StringBuffer(""); for(int i=0; i 0) numDigits = Integer.parseInt(args[0]); else numDigits = 150; BigInteger start = random(numDigits); for(int i=0; i<50; i++) { start = nextPrime(start); System.out.println("Prime " + i + " = " + start); } } } PrimeList.java package cwp; import java.util.*; import java.math.BigInteger; /** Creates a Vector of large prime numbers, usually in * a low-priority background thread. Provides a few small * thread-safe access methods. * * Taken from Core Web Programming Java 2 Edition * from Prentice Hall and Sun Microsystems Press, * . * May be freely used or adapted. */ public class PrimeList implements Runnable { private Vector primesFound; private int numPrimes, numDigits; /** Finds numPrimes prime numbers, each of which are * numDigits long or longer. You can set it to only * return when done, or have it return immediately, * and you can later poll it to see how far it * has gotten. */ public PrimeList(int numPrimes, int numDigits, boolean runInBackground) { // Using Vector instead of ArrayList // to support JDK 1.1 servlet engines primesFound = new Vector(numPrimes); this.numPrimes = numPrimes; this.numDigits = numDigits; if (runInBackground) { Thread t = new Thread(this); // Use low priority so you don't slow down server. t.setPriority(Thread.MIN_PRIORITY); t.start(); } else { run(); } } public void run() { BigInteger start = Primes.random(numDigits); for(int i=0; i * Taken from Core Web Programming Java 2 Edition * from Prentice Hall and Sun Microsystems Press, * . * May be freely used or adapted. */ public class ServletUtilities { public static final String DOCTYPE = ""; public static String headWithTitle(String title) { return(DOCTYPE + "\n" + "\n" + "\n"); } /** Read a parameter with the specified name, convert it * to an int, and return it. Return the designated default * value if the parameter doesn't exist or if it is an * illegal integer format. */ public static int getIntParameter(HttpServletRequest request, String paramName, int defaultValue) { String paramString = request.getParameter(paramName); int paramValue; try { paramValue = Integer.parseInt(paramString); } catch(NumberFormatException nfe) { // null or bad format paramValue = defaultValue; } return(paramValue); } /** Given an array of Cookies, a name, and a default value, * this method tries to find the value of the cookie with * the given name. If there is no cookie matching the name * in the array, then the default value is returned instead. */ public static String getCookieValue(Cookie[] cookies, String cookieName, String defaultValue) { if (cookies != null) { for(int i=0; i' with * '>', and (to handle cases that occur inside attribute * values), all occurrences of double quotes with * '"' and all occurrences of '&' with '&'. * Without such filtering, an arbitrary string * could not safely be inserted in a Web page. */ public static String filter(String input) { StringBuffer filtered = new StringBuffer(input.length()); char c; for(int i=0; i') { filtered.append(">"); } else if (c == '"') { filtered.append("""); } else if (c == '&') { filtered.append("&"); } else { filtered.append(c); } } return(filtered.toString()); } }