home *** CD-ROM | disk | FTP | other *** search
/ com!online 2002 April / comcd0402.iso / homepage / javaspecial / 03_01 / sitesearcher / AdvSiteSearcher / DocSearcher.java < prev    next >
Encoding:
Java Source  |  2000-08-18  |  9.4 KB  |  299 lines

  1. //AdvSiteSearcher c1999 The Gilbert Post by David Faden
  2. //The applet and code are distributed as linkware...
  3. //If you use this applet or a variant on its code,
  4. //include a link to The Gilbert Post, 
  5. //http://www.geocities.com/Athens/Parthenon/1911
  6. //The Gilbert Post and David Faden take no responsibility
  7. //for anything bad that happens as a result of using this applet
  8. //or a derivative based on its code. USE AT YOUR OWN RISK. (big letters)
  9. //Please send reports of problems to gilbertnews@hotmail.com, anyway, though.
  10.  
  11. //begin DocSearcher.java
  12. import java.io.*;
  13. import java.net.*;
  14. import java.util.*;
  15.  
  16. // A bug fix:
  17. //
  18. // 4/12/2000 fixed a "Y2K bug reported by several alert users...  I am not sure what 
  19. // I was thinking when I wrote the portion of code calling Date.getYear()... Perhaps that it
  20. // returns the decade? Anyway, in reality, getYear() returns the number of years
  21. // since 1900. Files with modification dates beyond 1999 were listed with dates greater than
  22. // 99 (100 for 2000).
  23. // Note: the whole Date class is deprecated in JDK 1.1
  24. // The code actually changed is found in HDocSearcher.java.
  25. // 
  26. // 4/12/2000 added code that causes the DocSearcher's runner Thread to wait
  27. // when it is not "doing anything." This should be more efficient than in the
  28. // previous incarnation, where runner would sleep, then periodically wake up to 
  29. // see if there was anything to search.
  30.  
  31. class DocSearcher implements Runnable {
  32.   private static final String[] months ={"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
  33.   private BufferedInputStream bis=null;
  34.   private AdvSiteSearcher parent;
  35.   
  36.   private volatile boolean searching;
  37.   private volatile boolean running=false;//should the main loop be running?
  38.   //if there is a horrible error such as a MalformedURLException
  39.   //or a SecurityException refuse to search anymore...
  40.   private volatile boolean noHorribleError;
  41.   
  42.   private URL url;
  43.   private int index;//our index according to parent
  44.   private SearchSieve[] searchers;
  45.   private boolean addedinfo=false;
  46.   private Thread runner;//this DocSearcher's Thread
  47.   private char[] cache;
  48.   private int cachelength=0;
  49.   private boolean allCached=false;//Is the whole file stored?
  50.   private boolean cutHTML=false;
  51.   private boolean bexact=false;
  52.   private int cachesize;
  53.   private long filelength=0;//Do not rely on what the server says
  54.   
  55.   /**
  56.    * Used to synchronize search methods.
  57.    */
  58.   private final Object searchLock=new Object();
  59.   
  60.   public DocSearcher(AdvSiteSearcher parent,URL url,int index,int cachesize) {
  61.     searching=false;
  62.     this.parent=parent;
  63.     this.url=url;
  64.     noHorribleError=true;
  65.     this.index=index;
  66.     this.cachesize=cachesize;
  67.   }
  68.   
  69.   public void searchFor(String[] s, boolean bexact, boolean cutHTML) {
  70.     if(!noHorribleError)
  71.         return;
  72.     stopSearch();
  73.     synchronized (searchLock) { //wait for runner to wait
  74.         this.bexact=bexact;
  75.         this.cutHTML=cutHTML;
  76.         
  77.         //It's not efficient to create new SearchSieves each time.
  78.         //SearchSieve already provides a method, setKey(char[],boolean),
  79.         //but I'm not sure how I'd like to implement the SearchSieve pool.
  80.         searchers=new SearchSieve[s.length];
  81.         for(int i=0;i<s.length;i++) {
  82.            searchers[i]=new SearchSieve(s[i].toLowerCase().toCharArray(),bexact);
  83.         }
  84.         
  85.         if(cache==null && cachesize>0) 
  86.             cache=new char[cachesize];
  87.         searching=true;
  88.         if(!running) {
  89.           running=true;
  90.           runner=new Thread(this,"DocSearcher"+index+" runner");
  91.           runner.start();
  92.         }
  93.         try {
  94.             searchLock.notify();
  95.         }
  96.         catch (IllegalMonitorStateException imse) {
  97.             imse.printStackTrace(System.err);
  98.         }
  99.     }
  100.   }
  101.   
  102.   //do not use this method
  103.   //it is a crutch to deal with a problem in the Applet's init
  104.   public void setErrored() {
  105.     noHorribleError=false;
  106.     //System.out.println("Errored");
  107.   }
  108.   
  109.   public boolean isErrored() {
  110.     return !noHorribleError;
  111.   }
  112.   
  113.   //This might not lead to a graceful close of bis.
  114.   //I think I've fixed the above problem, though.
  115.   public void stopSearch() {
  116.     searching=false;
  117.   }
  118.   
  119.  
  120.   
  121.   public void stopRunning() {
  122.       stopSearch();
  123.       synchronized (searchLock) {
  124.          try {
  125.             searchLock.notify(); //runner will be free to run once we
  126.             //the calling Thread exits this synchronized block
  127.          }
  128.          catch (IllegalMonitorStateException imse) {
  129.             imse.printStackTrace(System.err);
  130.          }
  131.          running=false;
  132.       }
  133.   }
  134.   
  135.   //this could cause NullPointerException if called while a search is in progress
  136.   public void trashCache() {
  137.     stopSearch();
  138.     synchronized (searchLock) {
  139.         cache=null;
  140.     }
  141.     //Here were are assuming that only one Thread at a time is calling the public
  142.     //methods of DocSearcher.
  143.     //Otherwise, it would be possible for another search to start in the interval
  144.     //between the two lines of this method
  145.   }
  146.   
  147.   
  148.   public void run() {
  149.       synchronized (searchLock) {
  150.           while (running && noHorribleError) {
  151.              if (searching) {
  152.                  dosearch();
  153.                  searching=false;
  154.              }
  155.              try { 
  156.                  searchLock.wait();
  157.              }
  158.              catch (InterruptedException e) { 
  159.                  e.printStackTrace(System.err);
  160.                  running=false;
  161.              }
  162.           } //end of while
  163.       } //end of synchronized block
  164.   }
  165.   
  166.   private boolean openConnection() {
  167.       //setup connection
  168.     try{
  169.        URLConnection uc=url.openConnection();
  170.        if(!addedinfo) {
  171.          addedinfo=true;
  172.          Date d=new Date(uc.getLastModified());
  173.          int length=uc.getContentLength()/1024;
  174.          parent.addInfo(index,new String(length+"k  "+months[d.getMonth()]+" "+
  175.                                             d.getDate()+" "+(d.getYear()+1900)));
  176.        }
  177.        bis=new BufferedInputStream(uc.getInputStream());
  178.     }
  179.     catch(FileNotFoundException fnfe) {
  180.       System.out.println(fnfe);
  181.       closeConnection();
  182.       noHorribleError=false;
  183.       parent.foundNoMatch(index);
  184.       return false;
  185.     }
  186.     catch(IOException e) {
  187.       System.out.println(e);
  188.       closeConnection();
  189.       parent.foundNoMatch(index);
  190.       return false;
  191.     }
  192.     catch(SecurityException se) {
  193.       System.out.println(se);
  194.       noHorribleError=false;
  195.       closeConnection();
  196.       parent.foundNoMatch(index);
  197.       return false;
  198.     }
  199.     return true;
  200.   }
  201.   
  202.   private void closeConnection() {
  203.         try {
  204.             if (bis!=null) 
  205.                 bis.close(); 
  206.             bis=null;
  207.         }
  208.         catch (IOException e) {
  209.             System.err.println(e);
  210.         }
  211.   }
  212.   
  213.   
  214.   //dosearch should only be called from active run
  215.   private void dosearch() {
  216.     //search loop
  217.     char c;
  218.     boolean cacheFullyRead=false;//stop cache from being read
  219.     //twice in one session...otherwise it will be filled with itself
  220.     boolean inTag=false;
  221.     boolean connected=false;
  222.     int cnumread=0;//number of characters read from cache
  223.     for(;;) {
  224.        if(!searching) break;
  225.        if(cache!=null && cnumread<cachelength && !cacheFullyRead) {
  226.          c=cache[cnumread];
  227.          cnumread++;
  228.          if (cnumread==cachelength) 
  229.              cacheFullyRead=true;
  230.        }
  231.        else {
  232.          if(allCached) c=(char)-1;//This will only get called if
  233.          //the cache was an exact fit for the file being searched.
  234.          else if(!connected) {
  235.            if (!openConnection()) 
  236.                return;
  237.            else {
  238.              connected=true;
  239.              //throw away cachelength chars
  240.              try {
  241.                for (int i=0;i<cachelength;i++) bis.read();
  242.              }
  243.              catch (IOException ewera) {
  244.                parent.foundNoMatch(index); 
  245.                closeConnection(); 
  246.                return;
  247.              }
  248.              continue;
  249.            }
  250.          }
  251.          else {
  252.            try {
  253.                c=Character.toLowerCase((char)bis.read());
  254.                if(cachelength==0) cacheFullyRead=true;
  255.                if(cachelength<cachesize && !allCached) {
  256.                   cache[cachelength]=c;
  257.                   cachelength++;
  258.                   if(c==(char)-1) allCached=true;  
  259.                }
  260.            }
  261.            catch(IOException e67) {
  262.              System.out.println(e67);
  263.              parent.foundNoMatch(index); 
  264.              closeConnection(); 
  265.              return;
  266.            }
  267.          }
  268.        }
  269.        //JavaScripts and comments might louse up this
  270.        //current cheesy method for cutting HTML tags.
  271.        if (c=='<') 
  272.            inTag=true;
  273.        else if (c=='>') {
  274.            if (cutHTML && inTag) {
  275.                inTag=false;
  276.                continue;
  277.            }
  278.            inTag=false;
  279.        }
  280.        
  281.        if(cutHTML && inTag) {/*nada*/}
  282.        else {
  283.          for(int i=0;i<searchers.length;i++) {
  284.             if(searchers[i].addChar(c)) {
  285.               if(searching) parent.foundMatch(index);
  286.               closeConnection();
  287.               return;
  288.             }
  289.          }
  290.        }
  291.        if(c==(char)-1) break;
  292.     }
  293.     //tell the parent the bad news
  294.     parent.foundNoMatch(index);
  295.     closeConnection();
  296.   }
  297.   
  298. }//end DocSearcher.java
  299.