source: other-projects/trunk/gs3-webservices-democlient/src/GS3DemoClient/org/greenstone/gs3client/GS3JavaClient.java@ 15383

Last change on this file since 15383 was 15383, checked in by ak19, 16 years ago

Moved an out-of-place comment

File size: 41.7 KB
Line 
1/**
2 *#########################################################################
3 * GS3JavaClient.java - part of the demo-client for Greenstone 3, of the
4 * Greenstone digital library suite from the New Zealand Digital Library
5 * Project at the * University of Waikato, New Zealand.
6 * <BR><BR>
7 * Copyright (C) 2008 New Zealand Digital Library Project
8 * <BR><BR>
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 * <BR><BR>
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 */
20
21package org.greenstone.gs3client;
22
23
24import org.apache.log4j.Logger;
25import org.apache.log4j.PropertyConfigurator;
26import org.greenstone.gs3client.BrowseDisplay.ClassifierData;
27
28import org.greenstone.gs3client.data.BrowseResponseData;
29import org.greenstone.gs3client.data.CollectionData;
30import org.greenstone.gs3client.data.DocumentNodeData;
31import org.greenstone.gs3client.data.ClassifierNodeData;
32import org.greenstone.gs3client.data.NodeData;
33import org.greenstone.gs3client.data.ParseUtil;
34import org.greenstone.gs3client.data.QueryResponseData;
35import org.greenstone.gs3client.data.ResponseData;
36//By importing this *static* inner class of CollectionData, can refer
37//to it by its unqualified name 'ServiceData'. (Learnt this from
38//http://today.java.net/pub/a/today/2006/03/23/multi-split-pane.html)
39import org.greenstone.gs3client.data.CollectionData.ServiceData;
40import org.greenstone.gs3client.dlservices.DigitalLibraryServicesAPIA;
41import org.greenstone.gs3client.dlservices.FedoraServicesAPIA;
42import org.greenstone.gs3client.dlservices.GS3ServicesAPIA;
43
44import javax.swing.*;
45import java.awt.BorderLayout;
46import java.awt.GridLayout;
47import java.awt.FlowLayout;
48import java.awt.event.ActionListener;
49import java.awt.event.ActionEvent;
50import java.awt.Container;
51import java.awt.Toolkit; // for making this JFrame client fullsize
52
53import java.net.Authenticator;
54import java.net.PasswordAuthentication;
55
56import org.w3c.dom.Document;
57import org.w3c.dom.Element;
58import org.w3c.dom.NodeList;
59
60import java.util.Vector;
61import java.util.HashMap;
62
63import java.io.StringReader;
64import javax.xml.parsers.DocumentBuilderFactory;
65import javax.xml.parsers.DocumentBuilder;
66import org.xml.sax.InputSource;
67
68import org.greenstone.gsdl3.util.GSXML;
69import java.awt.Cursor;
70
71/*
72 To make this class compile with Java 5/Java 1.5 need to rename the file
73 xalan.jar.tmp (located in $GS3_HOME/web/WEB-INF/lib) to xalan.jar
74 Without doing that, it will complain (unless compiled with Java 1.4.2).
75
76 RUNTIME Configuration of this class:
77 - this client needs the jar files:
78 log4j, xercesImpl, mail, lucene, javagdbm,
79 And possibly: xml-apis, activation, axis, mg, mgpp
80 - VM arguments: -Djava.library.path=/research/ak19/greenstone3/lib/jni
81
82 COMPILE Configuration of this class:
83 - BUILD PATH needs the jar files:
84 gsdl3 (or just the class GSXML), jaxrpc, axis
85 */
86/**
87 * The main Javaclient class. Creates the main window containing:
88 * - the radio button group for making either Greenstone 3 or Fedora the active DL.
89 * - the comboboxes for selecting the collection and the service therein
90 * - three panes - for executing queries, viewing search results and browsing.
91 * @author ak19
92*/
93public class GS3JavaClient extends JFrame implements ActionListener {
94 // static final long serialVersionUID = 1; //eclipse keeps warning
95 /** The Logger for this class */
96 static Logger LOG = Logger.getLogger(GS3JavaClient.class);
97
98 /** The value of the SEARCHING activity */
99 public static int SEARCHING = 0;
100 /** The value of the BROWSING activity */
101 public static int BROWSING = 1;
102 /** we want to display a drop-down box for the services available,
103 * but only Services that can be executed (searching and browsing) */
104 protected static final boolean executableServicesOnly = true;
105
106 /** To keep track of whether we are searching or browsing.
107 * Value of activity can be SEARCHING OR BROWSING */
108 protected int activity = 0; //
109
110 /** Reference to a digital library instance (Greenstone 3 or Fedora) that
111 * allows this client to execute services offered by the digital library */
112 protected DigitalLibraryServicesAPIA dlAPIA = null;
113 /** Reference to the object that interacts with Greenstone3's web services */
114 protected GS3ServicesAPIA greenstoneDL = null;
115 /** Reference to the object that interacts with the FedoraGS3.jar component */
116 protected FedoraServicesAPIA fedoraDL = null;
117
118 /** Object that stores the data of a query response XML message */
119 protected QueryResponseData queryResponseObj = null;
120
121 /** Object that stores the data of a browse response XML message
122 * (response for classification hierarchies) */
123 protected BrowseResponseData browseResponseObject = null;
124
125 /** Preferred language of display items in responses.
126 * "" or "en" for English */
127 protected String lang = "";
128
129 /** The currently selected collection */
130 protected String colName = "";
131 /** The currently selected service */
132 protected String serviceName = "";
133
134 /* The always-visible GUI objects of this main window */
135 protected JComboBox dlChooser = null;
136 protected JTextField proxyhostField = null;
137 protected JTextField proxyportField = null;
138 protected JTextField nonProxyHostNamesField = null;
139 protected JButton setProxySettings = null;
140
141 protected JComboBox serviceBox = null;
142 protected JComboBox collBox = null;
143 protected JButton collInfoButton = null;
144 protected JButton searchButton = null;
145 protected JTabbedPane tabbedPane = null;
146
147 protected static final int SELECT = 0;
148 protected static final int GREENSTONE = 1;
149 protected static final int FEDORA = 2;
150 protected static final String[] dlOptions = {"select", "greenstone", "fedora"};
151
152 /* Components of the query tab */
153 protected QueryForm queryPanel = null;
154 protected JTextField collectionNameField = null;
155
156 /* Components of the search tab */
157 protected SearchResultsDisplay searchResultsDisplay = null;
158 protected JPanel searchPanel = null;
159 protected JTextArea searchSummary = null;
160
161 /* Components of the browse tab */
162 protected BrowseDisplay browsePanel = null;
163
164 /** @return the language of the display items */
165 public String getLanguage() { return lang; }
166 /** Set the preferred language of the display items
167 * @param lang - the preferred language for display values */
168 public void setLanguage(String lang) { this.lang = lang; }
169
170 /** Inner class that handles authentication for any sites (urls, etc.)
171 * that require it. A dialog pops up to request username and password
172 * details from the user for each site's realm that needs authentication.
173 */
174 static class PasswordAuthenticator extends Authenticator {
175 protected PasswordAuthentication getPasswordAuthentication() {
176 JTextField username = new JTextField();
177 JTextField password = new JPasswordField();
178 JPanel panel = new JPanel(new GridLayout(2,2));
179 panel.add(new JLabel("User Name"));
180 panel.add(username);
181 panel.add(new JLabel("Password") );
182 panel.add(password);
183 int option = JOptionPane.showConfirmDialog(null, new Object[] {
184 "Site: "+getRequestingHost(),
185 "Realm: "+getRequestingPrompt(), panel},
186 "Enter Network Password",
187 JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
188 if ( option == JOptionPane.OK_OPTION ) {
189 return new PasswordAuthentication(
190 username.getText(), password.getText().toCharArray());
191 } else {
192 return null;
193 }
194 }
195 }
196
197 /** Default constructor that creates and initialises this main
198 * window and its internal GUI components */
199 public GS3JavaClient() {
200 super();
201 this.setTitle("Greenstone 3 web services demo-client");
202
203 // digital library panel lets the user choose the digital library
204 // repository to access and to set the proxy settings
205 JPanel dlPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
206 dlChooser = new JComboBox(dlOptions);
207 dlPanel.add(new JLabel("Use digital library:"));
208 dlPanel.add(dlChooser);
209 dlChooser.addActionListener(this);
210 dlPanel.setBorder(BorderFactory.createTitledBorder(
211 "Digital library settings"));
212
213 this.proxyhostField = new JTextField(15);
214 this.proxyportField = new JTextField(4);
215 this.nonProxyHostNamesField = new JTextField(20);
216 this.setProxySettings = new JButton("Set");
217 nonProxyHostNamesField.setToolTipText("The hosts for which no proxies are required "
218 + "(separate hosts with |, * wildcard allowed)");
219 JPanel topProxyPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
220 topProxyPanel.add(new JLabel("Proxy host:"));
221 topProxyPanel.add(proxyhostField);
222 topProxyPanel.add(new JLabel("Proxy port:"));
223 topProxyPanel.add(proxyportField);
224 JPanel bottomProxyPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
225 bottomProxyPanel.add(new JLabel("No proxy for:"));
226 bottomProxyPanel.add(nonProxyHostNamesField);
227 bottomProxyPanel.add(setProxySettings);
228 setProxySettings.addActionListener(this);
229 JPanel proxyPanel = new JPanel(new BorderLayout());
230 proxyPanel.add(topProxyPanel, BorderLayout.CENTER);
231 proxyPanel.add(bottomProxyPanel, BorderLayout.SOUTH);
232 proxyPanel.setBorder(BorderFactory.createTitledBorder(
233 "Connection settings"));
234
235 // Add the dlPanel and proxyPanel next to each other at the top
236 JPanel topPanel = new JPanel(new BorderLayout());
237 topPanel.add(dlPanel, BorderLayout.CENTER);
238 topPanel.add(proxyPanel, BorderLayout.EAST);
239
240 // Setting up the GUI of this client
241 // create a JComboBox, and an item in it for each collection
242 collBox = new JComboBox();
243 serviceBox = new JComboBox();
244
245 JPanel collPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
246 collPanel.add(new JLabel("Choose collection:"));
247 collPanel.add(collBox);
248 // displayName
249 collPanel.add(new JLabel("Full name:"));
250 collectionNameField = new JTextField(18);
251 collectionNameField.setEditable(false);
252 collectionNameField.setCaretPosition(0);
253 collPanel.add(collectionNameField);
254 // detailed information button, shows collection's description
255 collInfoButton = new JButton("Info");
256 collInfoButton.addActionListener(this);
257 collPanel.add(collInfoButton);
258
259 JPanel servicePanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
260 servicePanel.add(new JLabel("Available services:"));
261 servicePanel.add(serviceBox);
262
263 JPanel collServicesPanel = new JPanel(new BorderLayout());
264 collServicesPanel.add(collPanel, BorderLayout.NORTH);
265 collServicesPanel.add(servicePanel, BorderLayout.SOUTH);
266
267 tabbedPane = new JTabbedPane(); // tabs on top
268 queryPanel = new QueryForm(this);
269 tabbedPane.add("Query", queryPanel);
270 searchResultsDisplay = new SearchResultsDisplay(this);
271 searchResultsDisplay.setOpaque(true); //necessary for JTree
272
273 JScrollPane searchView = new JScrollPane(searchResultsDisplay);
274 searchSummary = new JTextArea();
275 searchSummary.setEditable(false);
276
277 searchPanel = new JPanel(new BorderLayout());
278 searchPanel.add(searchView, BorderLayout.CENTER);
279 searchPanel.add(searchSummary, BorderLayout.NORTH);
280 tabbedPane.add("Search Results", searchPanel);
281
282 JPanel activityPanel = new JPanel(new BorderLayout());
283 activityPanel.add(collServicesPanel, BorderLayout.NORTH);
284 activityPanel.add(tabbedPane, BorderLayout.CENTER);
285
286 Container c = this.getContentPane();
287 c.setLayout(new BorderLayout()); // new BoxLayout(c, BoxLayout.Y_AXIS));
288 c.add(topPanel, BorderLayout.NORTH);
289 c.add(activityPanel, BorderLayout.CENTER);
290
291 // browse panel
292 browsePanel = new BrowseDisplay(this);
293 tabbedPane.add("Browse", browsePanel);
294
295 // add actionlisteners
296 collBox.addActionListener(this);
297 serviceBox.addActionListener(this);
298
299 // GUI DONE, now instantiate the DATA and DIGITAL LIBRARY objects
300 // instantiate the objects that deal with storing query response data
301 // and browse response data
302 queryResponseObj = new QueryResponseData();
303 browseResponseObject = new BrowseResponseData();
304
305 // The java.net.Authenticator can be used to send user credentials
306 // when needed. When no username/password are provided then a popup
307 // is shown to ask for the credentials. *Only* when a site/realm
308 // requires password and username does the Authenticator show the
309 // dialog. For example, the dialog will appear when pwd & username
310 // are needed for proxy authorisation.
311 Authenticator.setDefault(new PasswordAuthenticator());
312
313 changeDL(null); // no dl selected
314
315 // Set the selection colours that will be uniform for all DLs
316 UIManager.put("Tree.textBackground", ColourCombo.transparent);
317 // Instead of the white tree text background, set it to transparent
318 UIManager.put("Tree.selectionBackground", ColourCombo.yellow);
319 UIManager.put("TabbedPane.selected", ColourCombo.yellow);
320 UIManager.put("TabbedPane.selected", ColourCombo.yellow);
321 UIManager.put("ComboBox.selectionBackground", ColourCombo.yellow);
322 UIManager.put("List.selectionBackground", ColourCombo.yellow);
323 UIManager.put("TextArea.selectionBackground", ColourCombo.yellow);
324 UIManager.put("TextField.selectionBackground", ColourCombo.yellow);
325 // force the UI to load these new UIManager defaults
326 javax.swing.SwingUtilities.updateComponentTreeUI(this);
327 // We can't change the UIManager defaults (properly) throughout GUI
328 // display-time, only upon creation and first display. This is
329 // because updateComponentTreeUI() has no effect once components
330 // have been displayed. For this reason, the various changeUIColor()
331 // methods and class ColourCombo have been written.
332 }
333
334 /** Attempts to establish a connection to GS3 Web services and instantiate
335 * a GS3ServicesAPIA object and store it in the member variable greenstoneDL.
336 * If it was unsuccessful, then this variable remains at null and an error
337 * message is displayed. */
338 protected boolean createGreenstoneDLConnection()
339 {
340 // store the old choice of dl, if there was any
341 int oldSetting = (dlAPIA == null) ? SELECT : FEDORA;
342 // try instantiating a GS3 dl handle
343 try {
344 greenstoneDL = new GS3ServicesAPIA();
345 return true; // success
346 } catch(DigitalLibraryServicesAPIA.CancelException e){
347 // The user pressed cancel in the gs3 services instantiation dialog
348 // Set the dl drop-down list option back to whatever it was
349 } catch(Exception e) {
350 // still unable to instantiate greenstone, but show
351 // the error for what went wrong
352 JOptionPane.showMessageDialog(
353 null,
354 "Error connecting to Greenstone 3 QBRSOAPServer web services.\n"
355 + "When attempting to process its wsdl file, encountered the problem:\n"
356 + e,
357 "Fatal error instantiating Digital Library Services interface. Exiting...",
358 JOptionPane.ERROR_MESSAGE
359 );
360 //e.printStackTrace(System.err);
361 LOG.error("Error connecting to Greenstone 3 web services:\n" + e);
362 }
363 // We'd be here if an exception occurred. Need to back to the old dl
364 // settings
365 dlChooser.setSelectedIndex(oldSetting);
366 return false;
367 }
368
369 /** Attempts to establish a connection to FedoraGS3.jar and instantiate
370 * a FedoraServicesAPIA object and store it in the member variable fedoraDL.
371 * If it was unsuccessful, then this variable remains at null and an error
372 * message is displayed. */
373 protected boolean createFedoraDLConnection()
374 {
375 // store the old choice of dl, if there was any
376 int oldSetting = oldSetting = (dlAPIA == null) ? SELECT : GREENSTONE;
377 // Try to instantiate a Fedora dl handle
378 try {
379 fedoraDL = new FedoraServicesAPIA();
380 return true; // success
381 } catch(
382 org.greenstone.fedora.services.FedoraGS3Exception.CancelledException e)
383 {
384 // The user pressed cancel in the fedora services instantiation dlg
385 // Set the dl drop-down list option back to whatever it was
386 } catch(Exception e) {
387 JOptionPane.showMessageDialog(
388 null,
389 "Error instantiating the interface to the Fedora Repository\n"+ e,
390 "Unable to connect to Fedora's digital library services.",
391 JOptionPane.ERROR_MESSAGE
392 );
393 //e.printStackTrace(System.err);
394 LOG.error(
395 "Error instantiating the interface to the Fedora Repository:\n"+ e);
396 }
397 // We'd be here if an exception occurred. Need to go back to the old dl
398 // settings
399 dlChooser.setSelectedIndex(oldSetting);
400 return false;
401 }
402
403 /** Method that is called when the user chooses to change the active
404 * digital library (between Greenstone3 and Fedora).
405 * @param dl is the new active digital library (the
406 * DigitalLibraryServicesAPIA object to change to). */
407 protected void changeDL(DigitalLibraryServicesAPIA dl) {
408 // change the colour of the interface
409 this.changeUIColour(dlChooser.getSelectedIndex());
410
411 // clear up remnants of previously selected digital library's
412 // processing
413 browsePanel.clear();
414 searchResultsDisplay.clear();
415 this.searchSummary.setText("");
416 browseResponseObject.clear();
417 queryResponseObj.clear();
418
419 // set current digital library to selected one
420 dlAPIA = dl;
421
422 if(dlAPIA == null) {
423 // clear some panels so the user can't do anything
424 this.queryPanel.clear();
425 collBox.removeAllItems();
426 collBox.setEnabled(false);
427 serviceBox.removeAllItems();
428 serviceBox.setEnabled(false);
429 this.collectionNameField.setText("");
430 this.collInfoButton.setEnabled(false);
431 return;
432 }
433
434 // start retrieving the information related to the chosen dl
435 String response = dlAPIA.describe();
436 if(response == null) {
437 LOG.error("Error: no response from dlAPIA.describe() of "
438 + dlAPIA.getDisplayName());
439 System.exit(1);
440 }
441
442 Element responseXML = getResponseAsDOM(
443 "DESCRIBE RESPONSE:\n", response);
444
445 // Get the collectionList element of the response
446 // from the default messageRouter-describe:
447 Element collectionList = ParseUtil.getFirstDescElementCalled(
448 responseXML, // (<message>, "collectionList")
449 GSXML.COLLECTION_ELEM+GSXML.LIST_MODIFIER
450 );
451 if(collectionList == null)
452 LOG.error("collectionList is null!");
453
454 // Next, create a CollectionData object for each collection using
455 // its name
456 CollectionData[] collData = null;
457 Vector v = ParseUtil.getAllChildElementsCalled(collectionList,
458 GSXML.COLLECTION_ELEM); // (<collectionList>, "collection")
459 if(v == null)
460 LOG.error("collections are null!");
461
462 if(v != null) {
463 StringBuffer buf = new StringBuffer("Collections:\n");
464 collData = new CollectionData[v.size()];
465 for(int i = 0; i < v.size(); i++){
466 collData[i] = new CollectionData((Element)v.get(i));
467 buf.append(collData[i].name + ", ");
468 }
469 }
470
471 // Now send a describe request to each collection
472 // And set the fields for each collData using the response
473 for(int i = 0; i < collData.length; i++){
474 response = dlAPIA.describeCollection(collData[i].name);
475 responseXML = getResponseAsDOM(
476 "describeCollection "+collData[i].name+":", response);
477 Element collectionTag = ParseUtil.getFirstDescElementCalled(
478 responseXML, GSXML.COLLECTION_ELEM);
479
480 // set the other fields of the CollectionData object using
481 // the collectionTag of the response from Collection-describe:
482 collData[i].setFields(collectionTag);
483 }
484
485 if(collData == null) {
486 LOG.debug("No collections in the chosen repository");
487 return;
488 } else {
489 this.collInfoButton.setEnabled(true);
490 collBox.setEnabled(true);
491 serviceBox.setEnabled(true);
492 }
493
494 // fill in the combobox containing the collections and the one
495 // containing the services
496 collBox.removeAllItems();
497 for(int i = 0; i < collData.length; i++)
498 collBox.addItem(collData[i]);
499 collBox.setSelectedItem(collData[0]);
500
501 this.serviceBox.removeAllItems();
502 ServiceData[] serviceData = collData[0].getServiceList(
503 executableServicesOnly);
504 for(int i = 0; i < serviceData.length; i++)
505 serviceBox.addItem(serviceData[i]);
506 serviceBox.setSelectedIndex(0); // whichever might be the first
507 }
508
509 /** Given an XML response string, returns the root document (element)
510 * representing its DOM form.
511 * @param response - the XML response string to be converted into
512 * its DOM form
513 * @return the response as an XML DOM Element */
514 protected Element getResponseAsDOM(String debugPrefix, String response) {
515 if(response == null) // will not be the case, because an empty
516 return null; // response message will be sent instead
517
518 // First let's print out the response to the LOG
519 // Note that the response is XML and will start on new line already
520 LOG.debug(debugPrefix + response);
521 // The following line when uncommented will output all response
522 // msgs coming back from the web services
523 //System.out.println(debugPrefix + response);
524
525 // At present, assuming response is okay - later need to first look
526 // for element <error> and process this meaningfully before returning
527 // XML DOM version of response. Example error:
528 // <message>
529 // <response from="infomine/TextQuery" type="process">
530 // <documentNodeList />
531 // <error type="other">IOException during connection to http://infominehelper.ucr.edu/cgi-bin/canned_search?theme=gsdl3&amp;query=water&amp;fields=kw,au,su,ti,de,fu,&amp;no_of_records_per_page=10&amp;start_page_no=1: java.net.ConnectException: Connection refused</error>
532 // </response>
533 // </message>
534
535 Element message = null;
536 try{
537 // turn the String xml response into a DOM tree:
538 DocumentBuilder builder
539 = DocumentBuilderFactory.newInstance().newDocumentBuilder();
540 Document doc
541 = builder.parse(new InputSource(new StringReader(response)));
542 message = doc.getDocumentElement();
543 } catch(Exception e){
544 if(response == null) {
545 response = "";
546 }
547 JOptionPane.showMessageDialog(this,
548 "An error occurred while trying to parse the response:\n"
549 + response
550 + "\nException message:\n" + e.getMessage(),
551 "Parse error", JOptionPane.ERROR_MESSAGE);
552 e.printStackTrace();
553 }
554
555 NodeList errorList = message.getElementsByTagName(GSXML.ERROR_ELEM);
556 if(errorList.getLength() == 0)
557 return message;
558
559 // else we have one (or more?) error(s):
560 Element error = (Element)errorList.item(0);
561 String errorMessage = ParseUtil.getBodyTextValue(error);
562 String errorType = error.getAttribute("type");
563
564 // no need to display error message if it was a query that was
565 // just executed and no results were found
566 if(//errorType.equals(GSXML.ERROR_TYPE_SYNTAX) &&
567 errorMessage.toLowerCase().indexOf("no documentnode found") != -1)
568 {
569 // if we're in here, we know that a search/query was performed
570 // That means we are dealing with the searchResultsDisplay
571 // and can clear it.
572 this.searchResultsDisplay.clear();
573 this.searchSummary.setText("");
574 }
575 else { // display error message
576 // number of letters per line
577 final int numLetters = 40;
578 String[] words = errorMessage.split(" "); //get the individual words
579 String line = words[0];
580 errorMessage = "";
581 // go through all the words and build up lines where none is
582 // longer than the specified number of letters
583 for(int i = 1; i < words.length; i++) { // append the word
584 // and a space to the same line unless the line is too long
585 if(numLetters > line.length() + words[i].length()) {
586 if(line.equals(""))
587 line = words[i];
588 else line = line + " " + words[i];
589
590 // check if line is full after adding new word
591 if(line.length() == numLetters) { // finish the line
592 errorMessage = errorMessage + line + "\n";
593 line = "";
594 }
595 } // else the word has to go on the next line
596 else { //finish the line and move on:
597 errorMessage = errorMessage + line + "\n";
598 line = words[i];
599 }
600 }
601 LOG.debug("errorMessage:\n" + errorMessage);
602
603 JOptionPane.showMessageDialog(this, errorMessage, "Error: "+errorType,
604 JOptionPane.ERROR_MESSAGE);
605 }
606 return message;
607 }
608
609 /** Event handler for actionEvents such as a change in the active digital
610 * library, a collection being selected in the dropdown box or the collection
611 * -Info button being pressed, or a service being selected in the service
612 * dropdown box (browsing or searching). */
613 public void actionPerformed(ActionEvent e) {
614 if(e.getSource() == dlChooser) {
615 // We need to change to a Wait cursor while we do the switch
616 Container c = this.getContentPane();
617 c.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
618
619 boolean success = true;
620 // Change the dlAPIA handle to the chosen digital library,
621 // instantiating DigitalLibraryServicesAPIA objects when necessary:
622 // if they haven't yet been created
623 switch(dlChooser.getSelectedIndex())
624 {
625 case GREENSTONE:
626 if(this.greenstoneDL == null) {
627 success = createGreenstoneDLConnection();
628 }
629 // no need to do anything if the user chose
630 // the same DL again
631 if(success && dlAPIA!=this.greenstoneDL) {
632 // current DL not already set to greenstoneDL
633 // so set it
634 this.changeDL(greenstoneDL);
635 }
636 break;
637 case FEDORA:
638 if(this.fedoraDL == null) {
639 success = createFedoraDLConnection();
640 }
641 // no need to do anything if the user chose
642 // the same DL again
643 if(success && dlAPIA!=this.fedoraDL) {
644 // current DL not already set to fedoraDL
645 // so set it
646 this.changeDL(fedoraDL);
647 }
648 break;
649 case SELECT:
650 default:
651 this.changeDL(null); // no dl, so default colours
652 break;
653 }
654 // set the cursor back
655 c.setCursor(Cursor.getDefaultCursor());
656 } else if(e.getSource() == collBox) {
657 CollectionData collDataEl
658 = (CollectionData)collBox.getSelectedItem();
659
660 if(collDataEl == null) // need to check for this here, because
661 return; // removing all items from collBox fires actionPerformed
662
663 // display the collection's full name
664 this.collectionNameField.setText(collDataEl.getDisplayName());
665 this.collectionNameField.setCaretPosition(0);
666
667 // display the services in the selected collection
668 serviceBox.removeAllItems();
669 ServiceData[] servicelist = collDataEl.getServiceList(
670 executableServicesOnly);
671 for(int i = 0; i < servicelist.length; i++)
672 serviceBox.addItem(servicelist[i]);
673
674 } else if(e.getSource() == serviceBox) {
675 ServiceData selService = (ServiceData)serviceBox.getSelectedItem();
676 if(selService == null || selService.type == null)
677 return; // nothing valid chosen
678
679 if(selService.type.equals(GSXML.SERVICE_TYPE_QUERY)) {
680 // Make sure we can't accidentally work with already deallocated
681 // data objects in the browsePanel
682 browsePanel.clear();
683 searchSummary.setText(""); // empty any text in the search summary
684
685 this.activity = SEARCHING; // ensures the components are
686 // displayed and shown again, whereas a call to repaint()
687 // did not do the trick
688
689 tabbedPane.setSelectedComponent(this.queryPanel);
690
691 // send off a describe request to the service
692 // in that collection
693 CollectionData selColl
694 = (CollectionData)collBox.getSelectedItem();
695 colName = selColl.name;
696 serviceName = selService.name;
697
698 String response = dlAPIA.describeCollectionService(
699 colName, serviceName);
700 Element serviceResponseXML = getResponseAsDOM(
701 "DescribeCollectionService "+colName+"/"+serviceName,
702 response);
703
704 // generate the appropriate query form as per how the
705 // query has described itself
706 queryPanel.formFromQueryServiceDescribe(serviceResponseXML);
707 } else if(selService.type.equals(GSXML.SERVICE_TYPE_BROWSE)) {
708 LOG.debug("Browse option chosen");
709 this.searchResultsDisplay.clear();
710 this.searchSummary.setText("");
711 this.queryPanel.clear(); // can't do any searching either
712 this.activity = BROWSING;
713 tabbedPane.setSelectedComponent(this.browsePanel);
714
715 CollectionData selColl
716 = (CollectionData)collBox.getSelectedItem();
717 colName = selColl.name;
718 serviceName = selService.name;
719
720 // first send a request for the browse service's metadata
721 // see manual pp.37 and 48
722 String response = dlAPIA.describeCollectionService(
723 colName, serviceName);
724 Element responseMsg = getResponseAsDOM(
725 colName+"/"+serviceName+":", response);
726 browsePanel.displayBrowseOptions(responseMsg);
727 } else { // clicked on non-query, non-browse option, remove form
728 queryPanel.clear();
729 }
730 } else if(e.getSource() == collInfoButton){
731 CollectionData collDataEl
732 = (CollectionData)collBox.getSelectedItem();
733
734 // Create the HTML viewing pane.
735 JEditorPane information = new JEditorPane();
736 information.setEditable(false);
737 information.setContentType("text/html");
738 information.setText(collDataEl.info());
739
740 // Display the dialog with the information in a scrollpane
741 JDialog dialog = new JDialog(this, collDataEl.toString());
742 dialog.getContentPane().add(new JScrollPane(information));
743 dialog.setDefaultCloseOperation(DISPOSE_ON_CLOSE); // not EXIT!
744 dialog.pack();
745 dialog.setSize(400, 300);
746 dialog.setVisible(true);
747 }
748 else if(e.getSource() == setProxySettings) { // proxy settings button
749 // Sthe proxy settings as given in the fields
750 String proxyHost = this.proxyhostField.getText();
751 String proxyPort = this.proxyportField.getText();
752 if(proxyHost.equals("") && proxyPort.equals("")) {
753 return;
754 } else {
755 // Handle proxy settings
756 // (don't need to write to propertiesFile, since proxy
757 // settings are System properties)
758 java.util.Properties systemSettings = System.getProperties();
759 systemSettings.put("http.proxyHost", proxyHost);
760 systemSettings.put("http.proxyPort", proxyPort);
761 // give the hosts for which no proxies are required:
762 systemSettings.put("http.nonProxyHosts",
763 this.nonProxyHostNamesField.getText());
764 System.setProperties(systemSettings);
765 }
766 }
767 }
768
769 /** Called by the instance of the QueryForm class when the user has
770 * pressed the queryPanel's search button to execute a query. Based on
771 * the user-entered values (stored in the parameter HashMap) this
772 * method will call Greenstone to process the query.
773 * @param nameValParamsMap - the query form control names with the values
774 * the user has entered for them. Example, the pair (fqv, the query string),
775 * where fqv is the form control name for the query term. */
776 public void performSearch(HashMap nameValParamsMap) {
777 //Container c = this.getContentPane();
778 //c.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
779 this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
780
781 // (1) Now let's process this query request - passing the
782 // currently selected collection and service:
783 String responseXML = dlAPIA.query(
784 colName, serviceName, nameValParamsMap);
785
786 // (2) The search results: document identifiers are returned,
787 // use these to construct a QueryResponseData object
788 Element responseMessage
789 = getResponseAsDOM("Search response:", responseXML);
790 queryResponseObj.setResponseData(responseMessage);
791 LOG.debug(queryResponseObj);
792
793 DocumentNodeData[] doclist = queryResponseObj.getDocumentNodeList();
794
795 // (3) To retrieve Title metadata, need to call with "Title"!!!!
796 // (1st letter in caps)
797 // Retrieving just metadata name=Title for ALL docs (=all docIDs)
798 String metaResponseXML = dlAPIA.retrieveTitleMetadata(this.colName,
799 queryResponseObj.getDocumentNodeIDs());
800 Element metaResponse
801 = getResponseAsDOM("Meta response:", metaResponseXML);
802 queryResponseObj.setMetadataForDocuments(metaResponse);
803
804 // doclist should now have been updated with title metadata for
805 // each doc (docNode)
806 //for(int i = 0; i < doclist.length; i++)
807 //LOG.debug(doclist[i].show());
808
809 // (4) Display this in the search results TreeView
810 tabbedPane.setSelectedComponent(searchPanel);
811 searchResultsDisplay.setResults(doclist);
812 searchSummary.setText(queryResponseObj.toString());
813 searchResultsDisplay.validate();
814 this.searchPanel.validate();
815 this.searchPanel.repaint();
816
817 // set the cursor back
818 //c.setCursor(Cursor.getDefaultCursor());
819 this.setCursor(Cursor.getDefaultCursor());
820 }
821
822
823 /* SEARCH RELATED METHODS */
824 /** Performs a docMetadataRetrieve message request for the docNode
825 * iff the metadata for that docNode is not already set.
826 * @param docNode is the DocumentNodeData object for which all the
827 * metadata is to be retrieved. */
828 public void retrieveAllMetadataFor(DocumentNodeData docNode) {
829 // Lazy retrieval: only retrieve metadata of docNode when required
830 // and if metadata not already set
831 if(docNode.getMetadataList() == null
832 || docNode.getMetadataList().size() <= 1)
833 { // not set yet or only title set,
834 // so do a docMetadataRetrieve for the docNode (all
835 // metadata fields retrieved):
836 String metaResponseXML = dlAPIA.retrieveDocumentMetadata(
837 this.colName, new String[] { docNode.nodeID });
838 Element metaResponse
839 = getResponseAsDOM("Meta response", metaResponseXML);
840
841 // Set the metadata for the docNode
842 if(this.activity == SEARCHING)
843 queryResponseObj.setMetadataForDocuments(metaResponse);
844 else if(this.activity == BROWSING)
845 browseResponseObject.setMetadataForDocuments(metaResponse);
846 } //else docNode's list of metadata already set
847 }
848
849 /** Performs a docMetadataRetrieve message request for the docNode
850 * iff the nodeContent for that docNode is not already set.
851 * @param docNode is the DocumentNodeData object for which the content
852 * is to be retrieved. */
853 public void retrieveContentFor(DocumentNodeData docNode) {
854 // Lazy retrieval: only retrieve content when required.
855 // If it is not yet set, then we do the retrieval, else
856 // our work here is done
857 if(docNode.getContent() == null) { // not set yet, so
858 // retrieve the content for the docNode
859 String contentResponseXML = dlAPIA.retrieveDocumentContent(
860 this.colName, new String[] { docNode.nodeID });
861 Element contentResponse = getResponseAsDOM(
862 "Content response:", contentResponseXML);
863 // probably when infomine is down
864 // Set the content for the docNode
865 if(this.activity==SEARCHING)
866 queryResponseObj.setContentForDocs(contentResponse);
867 else if(this.activity==BROWSING)
868 browseResponseObject.setContentForDocs(contentResponse);
869 }
870 }
871
872 /** Performs a structureRetrieve and title metadata retrieve message-
873 * request for the docNode, but only iff the structure and title for
874 * that docNode is not already set.
875 * @param docNode is the DocumentNodeData object for which the title
876 * is to be retrieved along with the titles of all its descendants. */
877 public void retrieveTitledStructureFor(DocumentNodeData docNode) {
878 DocumentNodeData root = docNode.getRoot();
879 if(root == null) { //then its structure has not yet been set
880 // do a structure retrieve for this document:
881 String structureResponseXML = dlAPIA.retrieveDocumentStructure(
882 this.colName, new String[] { docNode.nodeID });
883 Element structureResponse = getResponseAsDOM(
884 "STRUCTURE: ", structureResponseXML);
885
886 // Get the nodeStructure of this docNode, find its root and
887 // from there set all the descendents
888 // Instead of the following 2 statements can also do:
889 // queryResponseObj.setStructureForDocs(structureResponse);
890
891 Element nodeStructure = ParseUtil.getFirstDescElementCalled(
892 structureResponse, GSXML.NODE_STRUCTURE_ELEM);
893
894 // now we set the root and its descendents using whatever
895 ResponseData responseObject = browseResponseObject;
896 // true if(this.activity == BROWSING)
897 if(this.activity == SEARCHING)
898 responseObject = queryResponseObj;
899
900 root = docNode.setDescendentsOfRootNode(nodeStructure,
901 responseObject.getIDToNodeMapping());
902
903 // Now get only the DocumentNodeData elements in the root's
904 // descendents whose titles have not yet been set
905 String[] setTitleForTheseNodeIDs = root.getDescNodeIDsAsList(true);
906 // Will be null if all titles already set! But this should not be
907 // the case if we have just set the descendents of the root node
908 if(setTitleForTheseNodeIDs != null) {
909 // Retrieve the title metadata for these and set their titles
910 // with the response:
911 String titleMetaResponseXML = dlAPIA.retrieveTitleMetadata(
912 this.colName, setTitleForTheseNodeIDs);
913 Element titleMetaResponse = getResponseAsDOM(
914 "titleMetaResponseXML:", titleMetaResponseXML);
915
916 // Use whatever responseObject is active to set the metadata
917 responseObject.setMetadataForDocuments(titleMetaResponse);
918 }
919 }
920 }
921
922 /* BROWSE RELATED METHODS */
923 /** Given a ClassifierData object indicating what browsing category
924 * was chosen, this method will retrieve all its descendants in the
925 * hierarchy. Only the top-level descendents (children) of the
926 * classification will be set initially.
927 * @param classifier is the ClassifierData object whose children are
928 * to be retrieved. */
929 public void doBrowse(ClassifierData classifier) {
930 String response = dlAPIA.retrieveBrowseStructure(
931 this.colName, this.serviceName, classifier.name);
932
933 browseResponseObject.clear();
934 Element responseMsgTag = this.getResponseAsDOM(
935 "browseResponse:", response);
936 browseResponseObject.setResponseData(responseMsgTag); //classifier.name
937
938 LOG.debug(browseResponseObject.show());
939
940 this.browsePanel.displayBrowseResults(browseResponseObject,
941 classifier.displayName);
942 this.browsePanel.validate();
943 }
944
945 /** Given a ClassifierNodeData object for browsing, this method will
946 * set the classNode's children (previously retrieved) and retrieve
947 * all the children's metadata including the title.
948 * @param classNode is the ClassifierNodeData object whose title is to
949 * be retrieved along with the titles for its children. */
950 public void retrieveTitledStructureFor(ClassifierNodeData classNode) {
951 // we will only be setting the children in this method and retrieving
952 // the names for them, as it concerns a classifierNodeData (and not
953 // a documentNodeData).
954
955 classNode.setChildren(browseResponseObject.getIDToNodeMapping());
956
957 //String rootID = browseResponseObject.getRootClassifier().nodeID;
958
959 NodeData[] children = classNode.getChildren();
960 Vector docNodeChildren = new Vector(children.length);
961 Vector classNodeChildren = new Vector(children.length);
962 //String nodeIDs[] = new String[children.length];
963 for(int i = 0; i < children.length; i++) {
964 // don't bother setting the metadata if it was
965 // already set (check for empty metadata
966 if(children[i].getMetadataList() == null) {
967 if(children[i] instanceof ClassifierNodeData)
968 classNodeChildren.add(children[i]);
969 else if(children[i] instanceof DocumentNodeData)
970 docNodeChildren.add(children[i]);
971 }
972 }
973 String[] nodeIDs = null;
974
975 // First set the metadata for any classifiers:
976 if(classNodeChildren.size() > 0) {
977 nodeIDs = new String[classNodeChildren.size()];
978 for(int i = 0; i < nodeIDs.length; i++)
979 nodeIDs[i] = ((NodeData)classNodeChildren.get(i)).nodeID;
980
981 // let's just retrieve all the metadata - need to display it
982 // soon anyway
983 String response = dlAPIA.retrieveBrowseMetadata(this.colName,
984 this.serviceName, nodeIDs);
985 Element responseXML = this.getResponseAsDOM(
986 "MetadataRetrieve response: ", response);
987 browseResponseObject.setMetadataForClassifiers(responseXML);
988
989 for(int i = 0; i < nodeIDs.length; i++)
990 LOG.debug("Title: "
991 + ((NodeData)classNodeChildren.get(i)).getTitle());
992 }
993
994 nodeIDs = null;
995 // Now set the metadata for any documentNodes for which metadata
996 // has not been set yet
997 if(docNodeChildren.size() > 0) {
998 nodeIDs = new String[docNodeChildren.size()];
999 for(int i = 0; i < nodeIDs.length; i++)
1000 nodeIDs[i] = ((NodeData)docNodeChildren.get(i)).nodeID;
1001
1002 // let's just retrieve all the metadata - need to display it
1003 // soon anyway
1004 String response = dlAPIA.retrieveDocumentMetadata(
1005 this.colName, nodeIDs);
1006 Element responseXML = this.getResponseAsDOM(
1007 "MetadataRetrieve response: ", response);
1008 browseResponseObject.setMetadataForDocuments(responseXML);
1009
1010 for(int i = 0; i < nodeIDs.length; i++)
1011 LOG.debug("Title: "
1012 + ((NodeData)docNodeChildren.get(i)).getTitle());
1013 }
1014 }
1015
1016 /** @return the baseURL of the active digital library interface object */
1017 public String getBaseURL() {
1018 return this.dlAPIA.getAssocFileBaseURL();
1019 }
1020
1021 /** @return the filepath of the documentNode in the active digital library */
1022 public String getFilePath(DocumentNodeData docNode) {
1023 return this.dlAPIA.getAssocFileBaseURL(docNode);
1024 }
1025
1026 /**
1027 * Changes the background colours of the client's user interface
1028 * based on what the active digital library is.
1029 * See files greenstone3/gli/classes/xml/config.xml and
1030 * greenstone3/gli/src/org/greenstone/gatherer/Configuration.java
1031 * @param DL indicates whether the active digital library is Greenstone or
1032 * Fedora (or neither, in which case the GUI defaults to the usual grey).
1033 * @see <a href="http://www.java2s.com/Code/Java/Swing-JFC/UIManagerresourcestotweakthelookofapplications.htm">Java UIManager tutorial</a>
1034 */
1035 public void changeUIColour(int DL)
1036 {
1037 ColourCombo.setColour(DL);
1038 ColourCombo.changeColor(this.collBox);
1039 ColourCombo.changeColor(this.collectionNameField);
1040 ColourCombo.changeColor(this.serviceBox);
1041
1042 // change anonymous super panels' colours:
1043 ColourCombo.changeAncestorColor(this.collBox);
1044 ColourCombo.changeAncestorColor(this.serviceBox);
1045
1046 // change tab pane panels and their colouring
1047 this.queryPanel.changeUIColour();
1048 this.browsePanel.changeUIColour();
1049 this.searchResultsDisplay.changeUIColour();
1050 }
1051
1052 /** The main method of the GS3 java-client application. It instantiates
1053 * an instance of the GS3JavaClient main window and makes it visible. */
1054 public static void main(String[] args) {
1055 // set it up for logging
1056 final String logPropsFile = "log4j.properties";
1057 PropertyConfigurator.configure(logPropsFile);
1058
1059 GS3JavaClient client = new GS3JavaClient();
1060 client.pack();
1061 // make the main window fullscreen
1062 client.setSize(Toolkit.getDefaultToolkit().getScreenSize());
1063 client.setVisible(true);
1064 client.setDefaultCloseOperation(EXIT_ON_CLOSE);
1065 }
1066}
Note: See TracBrowser for help on using the repository browser.