~vcs-imports/xena/trunk

« back to all changes in this revision

Viewing changes to ext/src/javahelp/jhMaster/JavaHelp/src/new/javax/help/search/.svn/text-base/MergingSearchEngine.java.svn-base

  • Committer: matthewoliver
  • Date: 2009-12-10 03:18:07 UTC
  • Revision ID: vcs-imports@canonical.com-20091210031807-l086qguzdlljtkl9
Merged Xena Testing into Xena Stable for the Xena 5 release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * @(#)MergingSearchEngine.java 1.8 06/10/30
 
3
 * 
 
4
 * Copyright (c) 2006 Sun Microsystems, Inc.  All Rights Reserved.
 
5
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 
6
 * 
 
7
 * This code is free software; you can redistribute it and/or modify it
 
8
 * under the terms of the GNU General Public License version 2 only, as
 
9
 * published by the Free Software Foundation.  Sun designates this
 
10
 * particular file as subject to the "Classpath" exception as provided
 
11
 * by Sun in the LICENSE file that accompanied this code.
 
12
 * 
 
13
 * This code is distributed in the hope that it will be useful, but WITHOUT
 
14
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
15
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 
16
 * version 2 for more details (a copy is included in the LICENSE file that
 
17
 * accompanied this code).
 
18
 * 
 
19
 * You should have received a copy of the GNU General Public License version
 
20
 * 2 along with this work; if not, write to the Free Software Foundation,
 
21
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 
22
 * 
 
23
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 
24
 * CA 95054 USA or visit www.sun.com if you need additional information or
 
25
 * have any questions.
 
26
 */
 
27
 
 
28
package javax.help.search;
 
29
 
 
30
import java.util.Hashtable;
 
31
import java.util.Vector;
 
32
import java.util.Enumeration;
 
33
import java.util.Locale;
 
34
import java.net.URL;
 
35
import java.lang.reflect.Constructor;
 
36
import java.lang.reflect.InvocationTargetException;
 
37
import javax.help.HelpSet;
 
38
import javax.help.HelpUtilities;
 
39
import javax.help.NavigatorView;
 
40
import javax.help.search.SearchListener;
 
41
import javax.help.search.SearchEvent;
 
42
import javax.help.search.SearchEngine;
 
43
import javax.help.search.SearchQuery;
 
44
 
 
45
/*
 
46
 * A class that provides a merging/removing layer for the search.
 
47
 */
 
48
public class MergingSearchEngine extends SearchEngine {
 
49
    
 
50
    private Vector engines;
 
51
    private Hashtable enginePerView = new Hashtable();
 
52
    private boolean stopQuery = false;
 
53
 
 
54
    public MergingSearchEngine(NavigatorView view) {
 
55
        if (view == null) {
 
56
            throw new IllegalArgumentException("view must not be null");
 
57
        }
 
58
        engines = new Vector();
 
59
        // HERE - the makeEngine() should be delayed until the actual query
 
60
        SearchEngine engine = makeEngine(view);
 
61
        engines.addElement(engine);
 
62
    }
 
63
        
 
64
    public MergingSearchEngine(SearchEngine engine) {
 
65
        if (engine == null) {
 
66
            throw new IllegalArgumentException("engine must not be null");
 
67
        }
 
68
        engines = new Vector();
 
69
        engines.addElement(engine);
 
70
    }
 
71
 
 
72
    /**
 
73
     * Creates the query for this helpset.
 
74
     */
 
75
    public SearchQuery createQuery() {
 
76
        return new MergingSearchQuery(this);
 
77
    }
 
78
 
 
79
    /**
 
80
     * Adds/Removes a Search Engine to/from list.
 
81
     *
 
82
     * Possibly the makeEngine should be delayed until the actual query.
 
83
     */
 
84
 
 
85
    public void merge(NavigatorView view) {
 
86
        if (view == null) {
 
87
            throw new IllegalArgumentException("view must not be null");
 
88
        }
 
89
        SearchEngine engine = makeEngine(view);
 
90
        if (engine == null) {
 
91
            throw new IllegalArgumentException("view is invalid");
 
92
        }
 
93
        engines.addElement(engine);
 
94
        enginePerView.put(view, engine);
 
95
    }
 
96
 
 
97
    /*
 
98
     * Remove a Navigator View
 
99
     * Throws an IllegalArgumentException if view is null or if there
 
100
     * is no search engine for a view.
 
101
     */
 
102
    public void remove(NavigatorView view) {
 
103
        if (view == null) {
 
104
            throw new IllegalArgumentException("view is either null or invalid");
 
105
        }
 
106
        SearchEngine engine = (SearchEngine) enginePerView.get(view);
 
107
        if (engine != null) {
 
108
            engines.removeElement(engine);
 
109
            enginePerView.remove(engine);
 
110
        } else {
 
111
            throw new IllegalArgumentException("view is either null or invalid");
 
112
        }
 
113
 
 
114
    }
 
115
 
 
116
    public Enumeration getEngines() {
 
117
        return engines.elements();
 
118
    }
 
119
 
 
120
    private SearchEngine makeEngine(NavigatorView view) {
 
121
        Hashtable params = view.getParameters();
 
122
 
 
123
        // if there were no parameters or there were parameters but
 
124
        // no data then return a null SearchEngine
 
125
        if (params == null || 
 
126
            (params != null && !params.containsKey("data"))) {
 
127
            return null;
 
128
        }
 
129
        String engineName = (String) params.get("engine");
 
130
        HelpSet hs = view.getHelpSet();
 
131
        URL base = hs.getHelpSetURL();
 
132
        ClassLoader loader = hs.getLoader();
 
133
 
 
134
        if (engineName == null) {
 
135
            engineName = HelpUtilities.getDefaultQueryEngine();
 
136
            params.put("engine", engineName);
 
137
        }
 
138
        
 
139
        SearchEngine back = null;
 
140
 
 
141
        Constructor konstructor;
 
142
        Class types[] = {URL.class, Hashtable.class};
 
143
        Object args[] = {base, params};
 
144
        Class klass;
 
145
 
 
146
        debug("makeEngine");
 
147
        debug("  base: "+base);
 
148
        debug("  params: "+params);
 
149
 
 
150
        try {
 
151
            if (loader == null) {
 
152
                klass = Class.forName(engineName);
 
153
            } else {
 
154
                klass = loader.loadClass(engineName);
 
155
            }
 
156
        } catch (Throwable t) {
 
157
            throw new Error("Could not load engine named "+engineName+" for view: "+view);
 
158
        }
 
159
 
 
160
        try {
 
161
            konstructor = klass.getConstructor(types);
 
162
        } catch (Throwable t) {
 
163
            throw new Error("Could not find constructor for "+engineName+". For view: "+view);
 
164
        }
 
165
        try {
 
166
            back = (SearchEngine) konstructor.newInstance(args);
 
167
        } catch (InvocationTargetException e) {
 
168
            System.err.println("Exception while creating engine named "+engineName+" for view: "+view);
 
169
            e.printStackTrace();
 
170
        } catch (Throwable t) {
 
171
            throw new Error("Could not create engine named "+engineName+" for view: "+view);
 
172
        }
 
173
        return back;
 
174
    }
 
175
 
 
176
    private class MergingSearchQuery extends SearchQuery implements SearchListener {
 
177
 
 
178
        private MergingSearchEngine mhs;
 
179
        private Vector queries;
 
180
        private String searchparams;
 
181
 
 
182
        public MergingSearchQuery(SearchEngine hs) {
 
183
            super(hs);
 
184
            if (hs instanceof MergingSearchEngine) {
 
185
                this.mhs = (MergingSearchEngine) hs;
 
186
            }
 
187
        }
 
188
 
 
189
        // Start all the search engines
 
190
        public synchronized void start(String searchparams, Locale l)
 
191
            throws IllegalArgumentException, IllegalStateException
 
192
        {
 
193
            MergingSearchEngine.this.debug("startSearch()");
 
194
 
 
195
            // if we're already alive you can't start again
 
196
            if (isActive()) {
 
197
                throw new IllegalStateException();
 
198
            }
 
199
 
 
200
            stopQuery = false;
 
201
 
 
202
            // setup everthing to get started
 
203
            super.start(searchparams, l);
 
204
            queries = new Vector();
 
205
                
 
206
                // Get a query for each engine
 
207
            for (Enumeration e = mhs.getEngines();
 
208
                 e.hasMoreElements(); ) {
 
209
                SearchEngine engine = (SearchEngine) e.nextElement();
 
210
                if (engine != null) {
 
211
                    queries.addElement(engine.createQuery());
 
212
                }
 
213
            }
 
214
                
 
215
            // Set the listener to this class and start the query
 
216
            for (Enumeration e = queries.elements(); e.hasMoreElements(); ) {
 
217
                SearchQuery query = (SearchQuery) e.nextElement();
 
218
                query.addSearchListener(this);
 
219
                query.start(searchparams, l);
 
220
            }
 
221
        }
 
222
 
 
223
        // Stop all the search engines
 
224
        // This is an override of the SearchQuery.stop
 
225
        // Donnot call super.stop in this method as an
 
226
        // extra fireSearchStopped will be genertated
 
227
        public synchronized void stop() throws IllegalStateException {
 
228
            // Can't stop what is already stopped silly
 
229
            if (queries == null) {
 
230
                return;
 
231
            }
 
232
 
 
233
            stopQuery = true;
 
234
 
 
235
            // Loop through all the queries and and make sure they have
 
236
            // all inActive. If any query is active wait a small period of
 
237
            // time 
 
238
            boolean queriesActive = true;
 
239
            while (queriesActive) {
 
240
                queriesActive = false;
 
241
 
 
242
                // Throughout this process the queries will disappear so
 
243
                // protect against a null pointer
 
244
                if (queries == null) {
 
245
                    continue;
 
246
                }
 
247
                for (Enumeration e = queries.elements();
 
248
                     e.hasMoreElements(); ) {
 
249
                    SearchQuery query = (SearchQuery) e.nextElement();
 
250
                    if (query.isActive()) {
 
251
                        debug ("queries are active waiting to stop");
 
252
                        queriesActive = true;
 
253
                    }
 
254
                }
 
255
                if (queriesActive) {
 
256
                    try {
 
257
                        wait(250);
 
258
                    } catch (InterruptedException ex) {
 
259
                        ex.printStackTrace();
 
260
                    }
 
261
                }
 
262
            }
 
263
 
 
264
            queries = null;
 
265
        }
 
266
 
 
267
        public boolean isActive() {
 
268
 
 
269
            // if there aren't any queries we aren't alive
 
270
            if (queries == null) {
 
271
                return false;
 
272
            }
 
273
 
 
274
            // Loop through all the queries and see if anyone is alive
 
275
            for (Enumeration e = queries.elements();
 
276
                 e.hasMoreElements(); ) {
 
277
                SearchQuery query = (SearchQuery) e.nextElement();
 
278
                if (query.isActive()) {
 
279
                    return true;
 
280
                }
 
281
            }
 
282
 
 
283
            // Didn't find anyone alive so we're not alive
 
284
            return false;
 
285
        }
 
286
 
 
287
        public SearchEngine getSearchEngine() {
 
288
            return mhs;
 
289
        }
 
290
 
 
291
        public synchronized void itemsFound(SearchEvent e) {
 
292
            SearchQuery queryin = (SearchQuery) e.getSource();
 
293
 
 
294
            if (stopQuery) {
 
295
                return;
 
296
            }
 
297
 
 
298
            // Loop through all the queries and match this one
 
299
            if (queries != null) {
 
300
                Enumeration enum1 = queries.elements();
 
301
                while (enum1.hasMoreElements()) {
 
302
                    SearchQuery query = (SearchQuery) enum1.nextElement();
 
303
                    if (query == queryin) {
 
304
                        // Redirect any Events as if they were from me
 
305
                        fireItemsFound(e);
 
306
                    }
 
307
                }
 
308
            }
 
309
        }
 
310
 
 
311
        public void searchStarted(SearchEvent e) {
 
312
            // Ignore these events as this class already informed
 
313
            // the listeners the search was started so we don't have 
 
314
            // to do anything else
 
315
        }
 
316
 
 
317
        public synchronized void searchFinished(SearchEvent e) {
 
318
            SearchQuery queryin = (SearchQuery) e.getSource();
 
319
                
 
320
            // Loop through all the queries and match this one
 
321
            if (queries != null) {
 
322
                Enumeration enum1 = queries.elements();
 
323
                while (enum1.hasMoreElements()) {
 
324
                    SearchQuery query = (SearchQuery) enum1.nextElement();
 
325
                    if (query == queryin) {
 
326
                        queryin.removeSearchListener(this);
 
327
                        queries.removeElement(query);
 
328
                    }
 
329
                }
 
330
                // If all the queries are done then send a searchFinished
 
331
                if (queries.isEmpty()) {
 
332
                    queries = null;
 
333
                    if (!stopQuery) {
 
334
                        fireSearchFinished();
 
335
                    }
 
336
                }
 
337
            }
 
338
                
 
339
        }
 
340
 
 
341
    }    // This needs to be public to deal with inner classes...
 
342
 
 
343
    private static final boolean debug = false;
 
344
    private static void debug(String msg) {
 
345
        if (debug) {
 
346
            System.err.println("MergineSearchEngine: "+msg);
 
347
        }
 
348
    }
 
349
 
 
350
}