Grinding Java - Searching the WWW in Java:grinding1.java

 import java.awt.*; import java.awt.event.*; import java.net.*; import java.lang.*; import java.util.Vector;

/** * The WWWUtility class is the main part of the WWWUtility. * its responsibility is the UI and the execution of the * first instance of the SearchEngine class. * Normally I would hold the UI as a separate class to keep it * more abstracted from the program and thus more generic but * for simplicity I kept it here. public class WWWUtility extends Frame implements URLLocatedListener, // this interface contains a method that // will be fired if the search engine locates // a URL fitting the criteria. WindowListener, ActionListener {  public static void main(String argv[]) {     new WWWUtility; }

/**   * The constructor calls the superclass with the string for the windows * title. **/  public WWWUtility {     super("WWW utility"); loadUserInterface; }

/**   * This method is called by the user through the UI, and it creates * the first instance of the SearchEngine class. * it accepts the following parameters: * url - the url to search. You can use a url to refer to a file on your HD too. * stringToSearch - the search string. You could improve here by accepting a search * structure which will support advanced boolean searches. It should be very * simple to implement. * numberOfServersToBranchTo - if this equals 0 then every link that is not in this * domain will be ignored. If this number is above 0 then every link that is not * on this server will be branched to with numberOfServersToBranchTo - 1 as a    * branching factor. This feature gives us a feel of distance. * The concept of distance can be expanded to include length of URL string or   * number of pages from the source page rather than servers. **/  public void beginSearch(URL url,String stringToSearch,int numberOfServersToBranchTo) {     progressIndicator = new ProgressIndicator(this); // create a progress // indicator for the advance of the search. (ProgressIndicator.java)

progressIndicator.addActionListener(this); // Listen to the progress // indicators actions. If the user presses the stop // search button an event will be fired.

searchEngine = new SearchEngine(progressIndicator, url,                             numberOfServersToBranchTo, stringToSearch); // create an instance of the search engine.

searchEngine.addFoundListener(this); // Each search engine will send // an event to this class if it finds something.

Thread t = new Thread(searchEngine); // put the search engine on a                                          // new thread. t.start; // launch the thread. }

/**   * the method defined in URLLocatedListener. This method gets called when a   * url is found or with a null parameter when it is time to end the search. **/  synchronized public void searchStringFoundInURL(URL url) {     if(url != null) outputView.add(url.toString); else progressIndicator.dispose; }

/**   * Invoked when actions occur. * This method is a part of the ActionListener interface. **/  public void actionPerformed(ActionEvent e)   { // listening to menu commands. if((e.getSource == searchMenu) &&        (e.getActionCommand.equals("Begin search"))) new SearchDialog(this);

if((e.getSource == fileMenu) &&        (e.getActionCommand.equals("Exit"))) System.exit(0);

if(e.getSource == progressIndicator) {        searchEngine.stopSearching; }  }

/**   * Invoked when a window has been opened. * This method was created by the WindowListener interface. **/  public void windowOpened(WindowEvent e)   { }

/**   * Invoked when a window is in the process of being closed. * The close operation can be overridden at this point. * This method was created by the WindowListener interface. **/  public void windowClosing(WindowEvent e)   { System.exit(0); }

/**   * Invoked when a window has been closed. * This method was created by the WindowListener interface. **/  public void windowClosed(WindowEvent e)   { }

/**   * Invoked when a window is iconified. * This method was created by the WindowListener interface. **/  public void windowIconified(WindowEvent e)   { }

/**   * Invoked when a window is de-iconified. * This method was created by the WindowListener interface. **/  public void windowDeiconified(WindowEvent e)   { }

/**   * Invoked when a window is activated. * This method was created by the WindowListener interface. **/  public void windowActivated(WindowEvent e)   { }

/**   * Invoked when a window is de-activated. * This method was created by the WindowListener interface. **/  public void windowDeactivated(WindowEvent e)   { }

/**   * this method sets up the pulldown menu and the list of the URLs that were found. * In the AWT one of the most important concepts is the avoidance of using exact * sizes to define the size of a menu, that is why I added a line at the bottom of the * window. That line would cause the window to be big enough to contain a line of this * size without me specifying the actual size. * This is a slight hack, I could have gotten the size of the font and resized the window * according to that. **/  private void loadUserInterface {     addWindowListener(this); // so I will know when the windows close // button is pressed.

setLayout(new BorderLayout);

setMenuBar(menuBar); // attach the menu bar.

menuBar.add(fileMenu); fileMenu.add("Exit"); menuBar.add(searchMenu); searchMenu.add("Begin search"); searchMenu.add("Stop search"); // not implemented...

searchMenu.addActionListener(this); // so we can tell when a menu // option is selected. helpMenu.addActionListener(this); fileMenu.addActionListener(this);

add("Center",outputView); add("South",statusLine); pack; show; }

public static Runtime runtimeInformation = Runtime.getRuntime; // the // runtime class is a very important part of the VM. // Checkout the notes I made of it below.

private Label statusLine = new Label ("Mini HTML search engine, written by Shai Almog 5/97"); private ProgressIndicator progressIndicator; // a dialog for the search's progress. private SearchEngine searchEngine; // the Search engine in this class. private List outputView = new List(20,false); // the results of the search appear here.

private Menu fileMenu = new Menu("File"); // the menu items in this program. private Menu searchMenu = new Menu("Search"); private MenuBar menuBar = new MenuBar; }

/** * this internal class implements a dialog for selecting the search options. * this way I avoided concentrating to much logic into one black box (the * WWWUtility class). class SearchDialog extends Dialog implements ActionListener {  SearchDialog(WWWUtility owner) {     super(owner,"Search dialog"); this.owner = owner; loadUserInterface; }

/**   * Invoked when actions occur. * This method is a part of the ActionListener interface. **/  public void actionPerformed(ActionEvent e)   { if(e.getSource == beginSearch) {        // if the begin search button was pressed then check the validity of the // data in the fields and run the begin search method in the WWWUtility. dispose; Integer serverHops; try {           // convert the server hops to an integer. serverHops = Integer.decode(numberOfServersToBranchTo.getText); owner.beginSearch(new URL(URLToSearch.getText),              searchString.getText,               serverHops.intValue); }        catch (MalformedURLException err) {           System.out.println("Error in the URL syntax: " + err.getMessage); }        catch(NumberFormatException err) {           System.out.println("Error in reading the number of the maximum server hops."); }     }      if(e.getSource == cancelSearch) {        // if cancel was pressed then get rid of this fialog. dispose; }     if(e.getSource == browseFiles) {        // if browse was pressed then load a file dialog and run set the // results to the search url field. FileDialog fileNameToSearch = new FileDialog(owner,"Select file to search",FileDialog.LOAD); fileNameToSearch.show; URLToSearch.setText("file://"+fileNameToSearch.getDirectory +                    fileNameToSearch.getFile); }  }

/**   * this method sets up the UI for the dialog. * notice the creation of panels to group the objects. * BTW The dialog still looks ugly because I have no design taste whatsoever **/  private void loadUserInterface {     setLayout(new GridLayout(4,1)); // the grid layout tries to put the // objects on a grid similar to a spreadsheet.

beginSearch.addActionListener(this); // listen to when one of the buttons gets pressed. cancelSearch.addActionListener(this); browseFiles.addActionListener(this);

// set the three entry fields and their labels. // each entry field is grouped with its label in one panel so they // will not get away from one another. Panel p = new Panel; p.setLayout(new BorderLayout); add(p); p.add("West",new Label("URL:")); p.add("East",URLToSearch);

p = new Panel; p.setLayout(new BorderLayout); add(p); p.add("West",new Label("Search string:")); p.add("East",searchString);

p = new Panel; p.setLayout(new BorderLayout); add(p); p.add("West",new Label("Maximum server hops:")); p.add("East",numberOfServersToBranchTo);

// put the buttons on the bottom of the dialog one after the other. p = new Panel; p.setLayout(new FlowLayout); p.add(cancelSearch); p.add(browseFiles); p.add(beginSearch); add(p);

pack; show; }

private WWWUtility owner; // pointer to the WWWUtility both as a                            // frame owning this and so we can call // the search method.

// The entries and buttons to map the search. private TextField numberOfServersToBranchTo = new TextField("0",40); private TextField searchString = new TextField("",40); private TextField URLToSearch = new TextField("http://www.edm2.com/",40); private Button beginSearch = new Button("Begin search"); private Button browseFiles = new Button("Browse"); private Button cancelSearch = new Button("Cancel"); } 