The R Project SVN R

Rev

Rev 6608 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1230 leisch 1
/*==============================================================================
2
 
3
  Project: Simple JAVA Search Engine for Keyword Search
4
 
5
  JAVA Source file for the class SearchEngine
6
 
7
  COPYRIGHT (C), 1998, Thomas Baier
3765 leisch 8
 
9
 *  This program is free software; you can redistribute it and/or modify
10
 *  it under the terms of the GNU General Public License as published by
11
 *  the Free Software Foundation; either version 2 of the License, or
12
 *  (at your option) any later version.
13
 *
14
 *  This program is distributed in the hope that it will be useful,
15
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 *  GNU General Public License for more details.
18
 *
19
 *  You should have received a copy of the GNU General Public License
20
 *  along with this program; if not, write to the Free Software
5458 ripley 21
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22
 
1230 leisch 23
  $Source: /scratch/CVS-ARCHIVE/R/doc/html/search/SearchEngine.java,v $
24
 
6608 leisch 25
  $Revision: 1.4 $
1230 leisch 26
 
6608 leisch 27
  $Date: 1999/11/18 12:30:58 $
1230 leisch 28
 
6608 leisch 29
  $Author: leisch $
1230 leisch 30
 
31
==============================================================================*/
32
 
33
 
34
/* -------------------------------- Imports --------------------------------- */
35
 
36
import java.applet.*;
37
import java.awt.*;
38
import java.net.*;
39
import java.io.*;
40
import java.util.*;
41
 
42
 
43
/*==============================================================================
44
                          Interface of class SearchEngine
45
==============================================================================*/
46
 
47
/*------------------------------------------------------------------------------
48
  CLASS:    SearchEngine
49
  SUPER:    Applet
50
  CONF. TO: 
51
  PURPOSE:  
52
  NOTES:    
53
 
54
  HISTORY:  98-04-26: created 
3765 leisch 55
            98-05-15: new member for search mode
1230 leisch 56
------------------------------------------------------------------------------*/
57
public class SearchEngine extends Applet
58
{
59
  /*============================================================================
60
                                Public methods
61
  ============================================================================*/
62
 
63
  /*----------------------------------------------------------------------------
64
    INTERFACE: 
65
    PURPOSE:   default constructor
66
 
67
    NOTES:     
68
 
69
    PARAMS:    
70
    THROWS:    
71
    RETURNS:   void
72
 
73
    HISTORY:   98-04-26: created
74
               98-05-03: now reads the index file
3765 leisch 75
	       98-05-15: init new member
1230 leisch 76
  ----------------------------------------------------------------------------*/
77
  public SearchEngine ()
78
  {
79
    iIndexTable = null;
80
    iSearchTerm = null;
3765 leisch 81
    iSearchMode = 0;
1230 leisch 82
 
83
    Tracer.write ("SearchEngine initializing\n");
84
 
85
    return;
86
  }
87
 
88
 
89
  /*----------------------------------------------------------------------------
90
    INTERFACE: 
91
    PURPOSE:   return general information about the applet
92
 
93
    NOTES:     
94
 
95
    PARAMS:    
96
    THROWS:    
97
    RETURNS:   String: the information
98
 
99
    HISTORY:   98-04-26: created
100
  ----------------------------------------------------------------------------*/
101
  public String getAppletInfo ()
102
  {
103
    return "Name: SearchEngine\r\n" +
104
      "Author: Thomas Baier\r\n" +
105
      "(C) 1998 Thomas Baier, ALL RIGHTS RESERVED";
106
  }
107
 
108
 
109
  /*----------------------------------------------------------------------------
110
    INTERFACE: 
111
    PURPOSE:   perform initialization
112
 
113
    NOTES:     creates the controls
114
 
115
    PARAMS:    
116
    THROWS:    
117
    RETURNS:   void
118
 
119
    HISTORY:   98-04-26: created
120
               98-05-03: now a do-nothing
121
  ----------------------------------------------------------------------------*/
122
  public void init ()
123
  {
124
    resize(640, 240);
125
 
126
    // get the name of the index file
127
    String indexName = getParameter (cIndexKeyword);
128
    String searchTerm = getParameter (cSearchKeyword);
129
 
130
    Tracer.write ("Index file is \"" + indexName + "\"\n");
131
    Tracer.write ("Search term is \"" + searchTerm + "\"\n");
132
 
133
    // use a default index file if none specified
134
    if (indexName == null) {
135
      indexName = cIndexFile;
136
    }
137
 
138
    iSearchTerm = searchTerm;
139
 
140
    /*
141
     * examine the URL to get the search term...
142
     *
143
     * if the URL ends with ?SEARCHTERM=xxxxx we know, xxxxx is the search term
144
     */
145
    {
146
      URL url = getDocumentBase ();
147
      String urlString = url.toString ();
148
      int index = urlString.indexOf ("?" + cSearchKeyword + "=");
149
 
150
      Tracer.write ("URL is \"" + urlString + "\"\n");
151
 
152
      // if found, take the rest as the search string
153
      if (index >= 0) {
154
	iSearchTerm =
155
	  urlString.substring (index + 2 + cSearchKeyword.length ());
156
	Tracer.write ("found search term \"" + iSearchTerm + "\" in URL\n");
157
      }
158
    }
159
 
160
    readIndexFile (indexName);
161
 
162
    return;
163
  }
164
 
165
 
166
  /*----------------------------------------------------------------------------
167
    INTERFACE: 
168
    PURPOSE:   perform "destructor" code
169
 
170
    NOTES:     not required here
171
 
172
    PARAMS:    
173
    THROWS:    
174
    RETURNS:   void
175
 
176
    HISTORY:   98-04-26: created
177
  ----------------------------------------------------------------------------*/
178
  public void destroy ()
179
  {
180
    return;
181
  }
182
 
183
 
184
  /*----------------------------------------------------------------------------
185
    INTERFACE: 
186
    PURPOSE:   perform painting of the applet
187
 
188
    NOTES:     not required for our applet, controls do everything
189
 
190
    PARAMS:    Graphics g: the graphics context to draw on
191
    THROWS:    
192
    RETURNS:   void
193
 
194
    HISTORY:   98-04-26: created
195
  ----------------------------------------------------------------------------*/
196
  public void paint (Graphics g)
197
  {
198
 
199
    return;
200
  }
201
 
202
 
203
  /*----------------------------------------------------------------------------
204
    INTERFACE: 
205
    PURPOSE:   perform startup code everytime visiting the applet
206
 
207
    NOTES:     
208
 
209
    PARAMS:    
210
    THROWS:    
211
    RETURNS:   void
212
 
213
    HISTORY:   98-04-26: created
214
               98-05-10: start the tracer
215
  ----------------------------------------------------------------------------*/
216
  public void start ()
217
  {
218
    Tracer.start ();
219
    return;
220
  }
221
 
222
 
223
  /*----------------------------------------------------------------------------
224
    INTERFACE: 
225
    PURPOSE:   perform cleanup evertime the applet "loses" the focus
226
 
227
    NOTES:     
228
 
229
    PARAMS:    
230
    THROWS:    
231
    RETURNS:   void
232
 
233
    HISTORY:   98-04-26: created
234
               98-05-10: stop the tracer
235
  ----------------------------------------------------------------------------*/
236
  public void stop ()
237
  {
238
    Tracer.stop ();
239
    return;
240
  }
241
 
242
 
243
  /*----------------------------------------------------------------------------
244
    INTERFACE: 
245
    PURPOSE:   perform the search and return the search results as a string
246
 
247
    NOTES:     
248
 
249
    PARAMS:    
250
    THROWS:    
251
    RETURNS:   void
252
 
253
    HISTORY:   98-05-03: created
254
               98-05-08: new format for output
255
	       98-05-09: added trace
256
	       98-05-10: now a front-end for search()
3765 leisch 257
	       98-05-15: new parameter for search-mode
1230 leisch 258
  ----------------------------------------------------------------------------*/
3765 leisch 259
  public String search (String key,boolean searchTitles)
1230 leisch 260
  {
261
    iSearchTerm = key;
262
 
3765 leisch 263
    if (searchTitles) {
264
      iSearchMode = IndexTable.cSearchDescription;
265
    } else {
266
      iSearchMode = 0;
267
    }
268
 
1230 leisch 269
    return internalSearch ();
270
  }
271
 
272
 
273
  /*----------------------------------------------------------------------------
274
    INTERFACE: 
275
    PURPOSE:   perform the search (back-end)
276
 
277
    NOTES:     
278
 
279
    PARAMS:    
280
    THROWS:    
281
    RETURNS:   void
282
 
283
    HISTORY:   98-05-10: created
3765 leisch 284
               98-05-15: forward search-mode
1230 leisch 285
  ----------------------------------------------------------------------------*/
286
  public String internalSearch ()
287
  {
288
    Tracer.write ("Search for \"" + iSearchTerm + "\" started");
289
 
290
    Vector foundItems = null;
291
 
292
    if (iSearchTerm != null) {
3765 leisch 293
      foundItems = iIndexTable.search (iSearchTerm,iSearchMode);
1230 leisch 294
    } else {
295
      foundItems = null;
296
    }
297
 
298
    String result = null;
299
 
300
    // if nothing found, return a special string
301
    if (foundItems == null) {
302
      result = "No matches for <b>\"" + 
303
	iSearchTerm +
304
	"\"</b> have been found!<hr>";
305
    } else {
306
      Enumeration cursor = foundItems.elements ();
307
 
308
      result =
309
	"The search string was <b>\"" +
310
	iSearchTerm +
3765 leisch 311
	"</b>\"" +
1230 leisch 312
	"<hr>" +
313
	"<dl>";
314
 
315
      while (cursor.hasMoreElements ()) {
316
	IndexEntry entry = (IndexEntry) cursor.nextElement ();
317
 
318
	/*
319
	 * the format for every entry is
320
	 *
321
	 * title
322
	 *   description
323
	 */
324
 
325
	result +=
326
	  "<dt><a href=\"" +
327
	  entry.getURL () +
328
	  "\">" +
329
	  entry.getTitle () +
330
	  "</a></dt>\n";
331
	result += "<dd>" + entry.getDescription () + "</dd>\n";
332
      }
333
 
334
      result += "</dl>";
335
    }
336
 
337
    return result;
338
  }
339
 
340
 
341
  /*============================================================================
342
                              Protected methods
343
  ============================================================================*/
344
 
345
  /*============================================================================
346
                               Private methods
347
  ============================================================================*/
348
 
349
  /*----------------------------------------------------------------------------
350
    INTERFACE: 
351
    PURPOSE:   read the index file
352
 
353
    NOTES:     
354
 
355
    PARAMS:    
356
    THROWS:    
357
    RETURNS:   void
358
 
359
    HISTORY:   98-04-26: created
360
               98-05-08: now use an IndexStream
361
	       98-05-10: also use prefix and suffix, build URL from first key
3765 leisch 362
	       98-05-19: add "Alias:" entry to keywords
363
	       98-06-01: bugfix: don't null the variables
1230 leisch 364
  ----------------------------------------------------------------------------*/
365
  private void readIndexFile (String idxFile)
366
  {
367
    // create the index table
368
    iIndexTable = new IndexTable ();
369
 
370
    URL baseURL = getCodeBase ();
371
 
372
    // get the index file and parse its contents
373
    try {
374
      URL idxFileURL = new URL (baseURL,idxFile);
375
 
376
      // get an IndexStream object for ease of parsing
377
      IndexStream idxStream = new IndexStream (idxFileURL);
378
 
379
      // now start parsing...
380
 
381
      /*
382
       * An entry consists of a title, keywords, an URL and a description.
383
       * everything else is ignored. Every entry starts with the keyword
384
       * "Entry" (case is ignored)
385
       *
386
       * must-have entries are "Entry" and "Keywords"
3765 leisch 387
       *
388
       * 98-06-01: bugfix: don't null the variables
1230 leisch 389
       */
3765 leisch 390
      String entry = "";
391
      String keywords = "";
392
      String url = "";
1230 leisch 393
      String description = "";
394
      String prefix = "";
395
      String suffix = "";
396
 
397
      Value value = idxStream.popEntry ();
398
 
399
      while (value != null) {
400
	// parse the value now
401
	if (value.getKey ().equalsIgnoreCase ("entry")) {
402
	  // if a new entry is about to start, add the current one
403
	  addEntry (entry,keywords,description,url,prefix,suffix);
404
 
405
	  entry = value.getValue ();
3765 leisch 406
	  keywords = "";
407
	  url = "";
1230 leisch 408
	  description = "";
409
	} else if (value.getKey ().equalsIgnoreCase ("keywords")) {
3765 leisch 410
	  keywords += value.getValue ();
1230 leisch 411
	} else if (value.getKey ().equalsIgnoreCase ("url")) {
412
	  // use prefix and suffix
413
	  url = prefix + value.getValue () + suffix;
414
	} else if (value.getKey ().equalsIgnoreCase ("description")) {
415
	  description = value.getValue ();
416
	} else if (value.getKey ().equalsIgnoreCase ("prefix")) {
417
	  prefix = value.getValue ();
418
	  Tracer.write ("using new URL prefix \"" + prefix + "\"\n");
419
	} else if (value.getKey ().equalsIgnoreCase ("suffix")) {
420
	  suffix = value.getValue ();
421
	  Tracer.write ("using new URL suffix \"" + suffix + "\"\n");
6608 leisch 422
	} else if (value.getKey ().equalsIgnoreCase ("aliases")) {
3765 leisch 423
	  keywords += value.getValue ();
1230 leisch 424
	}
425
	value = idxStream.popEntry ();
426
      }
427
 
428
      // the final entry just read
429
      addEntry (entry,keywords,description,url,prefix,suffix);
430
    } catch (MalformedURLException exc) {
431
      // an error occured while reading...
432
    }
433
 
434
    return;
435
  }
436
 
437
 
438
  /*----------------------------------------------------------------------------
439
    INTERFACE: 
440
    PURPOSE:   
441
 
442
    NOTES:     
443
 
444
    PARAMS:    
445
    THROWS:    
446
    RETURNS:   void
447
 
448
    HISTORY:   98-05-10: created
3765 leisch 449
               98-06-01: value is "", not null if empty
1230 leisch 450
  ----------------------------------------------------------------------------*/
451
  private void addEntry (String entry,String keywords,
452
			 String description,String url,
453
			 String prefix,String suffix)
454
  {
455
    // the entry must be set
3765 leisch 456
    if (entry.length () == 0) {
1230 leisch 457
      return;
458
    }
459
 
460
    // the keywords must be set, else ignore it
3765 leisch 461
    if (keywords.length () != 0) {
462
      if (url.length () == 0) {
1230 leisch 463
	// if the URL is empty, construct one following the rule:
464
	// URL = prefix + first keyword + suffix
465
	int endOfFirstKeyword = keywords.indexOf (" ");
466
 
467
	// because we have trimmed the string, the first character must
468
	// not be a blank
469
	if (endOfFirstKeyword >= 0) {
470
	  url = keywords.substring (0,endOfFirstKeyword);
471
	  Tracer.write ("constructing URL, keywords=\"" +
472
			keywords + "\"" +
473
			"using \"" + 
474
			url +
475
			"\" (results in \"" +
476
			prefix + url + suffix + "\")\n");
477
	} else {
478
	  // just a single keyword
479
	  url = keywords;
480
	  Tracer.write ("constructing URL, using keyword \"" + 
481
			url +
482
			"\" (results in \"" +
483
			prefix + url + suffix + "\")\n");
484
	}
485
	// add prefix and suffix
486
	url = prefix + url + suffix;
487
      }
488
      IndexEntry idxEntry =
489
	new IndexEntry (entry,keywords,description,url);
490
      iIndexTable.addElement (idxEntry);
491
    }
492
 
493
    return;
494
  }
495
 
496
 
497
  /*============================================================================
498
                             Instance Variables
499
  ============================================================================*/
500
  private IndexTable iIndexTable;
501
  private String     iSearchTerm;
3765 leisch 502
  private int        iSearchMode;
1230 leisch 503
 
504
 
505
  /*============================================================================
506
                                Static Data
507
  ============================================================================*/
508
 
509
  private static final String cIndexFile = "index.txt";
510
  private static final String cIndexKeyword = "INDEXFILE";
511
  private static final String cSearchKeyword = "SEARCHTERM";
512
}
513
 
514
/*==============================================================================
515
 
516
  HISTORY:
517
 
518
  $Log: SearchEngine.java,v $
6608 leisch 519
  Revision 1.4  1999/11/18 12:30:58  leisch
520
  use seperate aliases field
521
 
5458 ripley 522
  Revision 1.3  1999/08/10 09:56:03  ripley
523
  change FSF address in copyrights
524
  add some copyrights in src/gnome and elsewhere
525
 
3765 leisch 526
  Revision 1.2  1999/03/04 17:15:18  leisch
527
  various bugfixes
1230 leisch 528
 
3765 leisch 529
  Revision 1.1.4.1  1999/03/02 15:19:57  leisch
530
  search used only kewords, no titles
531
 
532
  Revision 1.6  1998/05/19 20:23:13  baier
533
  added alias support
534
 
535
  Revision 1.5  1998/05/15 22:10:05  baier
536
  allow searching in description, fix bug in results list
537
 
1230 leisch 538
  Revision 1.4  1998/05/10 22:56:53  baier
539
  internal search function, parameter expansion
540
 
541
  Revision 1.3  1998/05/10 02:44:32  baier
542
  traces, output in HTML via JavaScript, new index generation
543
 
544
  Revision 1.2  1998/04/26 22:36:34  baier
545
  documentation changes
546
 
547
 
548
 
549
  Revision 1.1  1998/04/26 21:32:54  baier
550
  Initial revision
551
 
552
 
553
==============================================================================*/
554
 
555
 
556
// Local Variables:
557
// mode: Java
558
// mode: font-lock
559
// End: