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

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

Greenstone3 web services demo-clientadded to GS3's other-projects

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