Previous Table of Contents Next


After the necessary parameters have been retrieved from the client request, the method tries to load the index. All of the indices are managed by the IndexManager class discussed later in this section. An index is requested based on the directory it searches, and IndexManager returns either the index object or null if the directory is not indexed. Because indexing takes a while, don’t make the user wait for it. However, do make the first user to search a directory wait for the index to be loaded. In other words, the first user to search a directory that is not indexed receives an error message telling them that the index is not available. But that user also triggers the creation of the index. The first person to access a directory with an index will wait for the index to load, before his or her query is processed. Once loaded, IndexManager keeps track of the index and returns it when requested. The indexes are thread safe once loaded, because IndexManager is used to protect them during loading and to allow index sharing, which improves performance. If you try this example from the CD-ROM, notice that the first search can be slow due to the load, but subsequent searches are nearly immediate.

The following code in the handleQuery method logs a status message to the log and then attempts to load the index for the current directory.

    logger.log("Requesting index for: "+dir);

    index = IndexManager.indexForDirectory(fullDir,dir);

In this code, IndexManager is given both the relative and absolute paths to the directory so that the index can be found on disk and so that it returns file paths relative to the servers document root, instead of real file paths.

The next section discusses how to check whether the index was returned or whether the manager returned null.

Handling Non-Query Requests

The preceding code attempted to load the index. The following code shows how handleQuery works in case the index is unavailable. If the index is unavailable, an attempt is made to redirect the client to the no-index page indicated by the configuration parameters. If this page is unavailable, an error code is sent to the client, indicating that the service is unavailable.

    if(index == null)
    {
     logger.log("Index not available for: "+fullDir);
     
     if(noIndexPage != null)
         response.sendRedirect(noIndexPage);
     else
     response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
    }
    else
    {
     ...

These error codes are a poor choice for communicating the situation to the user. The error codes should be used as a last resort. Another consideration is that the HTMLIndex class has a main method that will build an index for a directory. This means that you can build the initial directory early instead of waiting for a user request. The builder will also rebuild the index if any files in the directory or subdirectories are newer than the existing index. You might want to update the indices regularly, although the servlet will do this automatically. If the update interval configuration parameter is set, the servlet will check the index after the specified number of seconds pass and update it if necessary.

If the index described is not null, a query is performed. The next section describes the code executed in this case (under the else condition) in the handleQuery method.

Handling Queries

When a query request arrives, the servlet’s first step is to ask the index for the files associated with that query. The index parses the query for “and,” “or,” and “not,” searches its hash table, and returns the matching files in a vector called results. The servlet then uses this vector to determine the number of hits.

     results = index.filesForQuery(query);
     
     if(results != null) resultCount = results.size();

     logger.log("Got "+resultCount+" results for query: "+query);

Next, write the header for the results page using the writer of the response object. The following code shows how the handleQuery method does this by first writing the header, which wraps the results in a centered table to make them more readable. The results themselves will be displayed as links.

     writer.println("<HTML>");
     writer.println("<HEAD>");
     writer.println("<TITLE>");
     writer.println("Search Results");
     writer.println("</TITLE>");
     writer.println("</HEAD>");
     writer.println("<BODY TEXT=\"#000000\" BGCOLOR=\"#FFFFFF\""
          +" LINK=\"#0000EE\" VLINK=\"#551A8B\""
          +" ALINK=\"#FF0000\">");
 
     writer.println("<CENTER>");
     writer.println("<TABLE>");
     writer.println("<TR>");
     writer.println("<TD>");

Once the header is written, figure out whether there were any result hits. If there were no hits, an appropriate message is displayed. If there are hits, determine whether the number of results exceeds the maximum hits to display by comparing the maxHits to the resultCount minus the numeric index of the curHitStart. The variable curHitStart contains the counter for the first element to display. In other words, you could have counted 100 items indexed from 0 to 99, but if you start by displaying the element at index 95, there are only five elements to display. The actual number of hits to display on this page is stored in the local variable max. Before displaying the results, a message is displayed that tells the user how many hits occurred and which ones are displayed on this page.

     if(resultCount > 0)
     {
         writer.println("<H1>Your search results are:</H1>");
         max = Math.min(resultCount-curHitStart
                   ,maxHits);
      
         //inc printout by one to make it 1-25 not 0-25
         writer.println("<CENTER>"+(curHitStart+1)+"-"
                   +(curHitStart+max)
                   +" of "+resultCount
                   +" matches</CENTER>");
      
         outputHitsNavigator(maxHits,curHitStart,resultCount
                    ,query,myURL,writer);
                    
         writer.println("<BLOCKQUOTE>");
      
         try
         {
          
          for(i=0;i<max;i++)
          {
              curFileName = (String)
                 results.elementAt(curHitStart+i);
              outputFile(curFileName,dir,writer);
          }
         }
         catch(Exception exp)
         {
          logger.log("Bad file name: "+curFileName);
         }
          
         writer.println("</BLOCKQUOTE>");
      
         outputHitsNavigator(maxHits,curHitStart
                    ,resultCount
                    ,query,myURL,writer);
     }
     else
     {
         writer.println("<H1>No files matched your "
                    +"query.</H1>");
     }

After all of the files are displayed, the result page’s footer is printed to the client, and the handleQuery method concludes as defined in the code that follows.

     writer.println("</TD>");
     writer.println("</TR>");
     writer.println("</TABLE>");
     writer.println("</CENTER>");
     writer.println("</BODY>");
     writer.println("</HTML>");
    }
}

Each of the results in the preceding code is displayed using a method called outputFile. This method displays a link for each file, with the link’s text equal to the file’s name. The code for outputFile is as follows.

protected void outputFile(String file,String dir,PrintWriter w)
{
    String fileName = file.substring(dir.length());
    w.print("<A HREF=\"");
    w.print(file.replace('\\','/'));//make sure the URL is valid
    w.print("\">");
    w.print(fileName.replace('\\','/'));
    w.println("</A><BR>");
}


Previous Table of Contents Next