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

Last change on this file since 21835 was 21835, checked in by ak19, 14 years ago

Browse takes a list of classifierIDs, not a single one.

File size: 42.1 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 + "\n" + response);
521 // The following line when uncommented will output all response
522 // msgs coming back from the web services
523 //System.out.println(debugPrefix + "\n" + 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 final int numLetters = 60; // number of letters per line
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 if(i == (words.length-1)) { // extra word on last line
600 errorMessage = errorMessage + line;
601 }
602 }
603 LOG.debug("errorMessage:\n" + errorMessage);
604 JOptionPane.showMessageDialog(this, errorMessage, "Error: "+errorType,
605 JOptionPane.ERROR_MESSAGE);
606 }
607 return message;
608 }
609
610 /** Event handler for actionEvents such as a change in the active digital
611 * library, a collection being selected in the dropdown box or the collection
612 * -Info button being pressed, or a service being selected in the service
613 * dropdown box (browsing or searching). */
614 public void actionPerformed(ActionEvent e) {
615 if(e.getSource() == dlChooser) {
616 // We need to change to a Wait cursor while we do the switch
617 Container c = this.getContentPane();
618 c.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
619
620 boolean success = true;
621 // Change the dlAPIA handle to the chosen digital library,
622 // instantiating DigitalLibraryServicesAPIA objects when necessary:
623 // if they haven't yet been created
624 switch(dlChooser.getSelectedIndex())
625 {
626 case GREENSTONE:
627 if(this.greenstoneDL == null) {
628 success = createGreenstoneDLConnection();
629 }
630 // no need to do anything if the user chose
631 // the same DL again
632 if(success && dlAPIA!=this.greenstoneDL) {
633 // current DL not already set to greenstoneDL
634 // so set it
635 this.changeDL(greenstoneDL);
636 }
637 break;
638 case FEDORA:
639 if(this.fedoraDL == null) {
640 success = createFedoraDLConnection();
641 }
642 // no need to do anything if the user chose
643 // the same DL again
644 if(success && dlAPIA!=this.fedoraDL) {
645 // current DL not already set to fedoraDL
646 // so set it
647 this.changeDL(fedoraDL);
648 }
649 break;
650 case SELECT:
651 default:
652 this.changeDL(null); // no dl, so default colours
653 break;
654 }
655 // set the cursor back
656 c.setCursor(Cursor.getDefaultCursor());
657 } else if(e.getSource() == collBox) {
658 CollectionData collDataEl
659 = (CollectionData)collBox.getSelectedItem();
660
661 if(collDataEl == null) // need to check for this here, because
662 return; // removing all items from collBox fires actionPerformed
663
664 // display the collection's full name
665 this.collectionNameField.setText(collDataEl.getDisplayName());
666 this.collectionNameField.setCaretPosition(0);
667
668 // display the services in the selected collection
669 serviceBox.removeAllItems();
670 ServiceData[] servicelist = collDataEl.getServiceList(
671 executableServicesOnly);
672 for(int i = 0; i < servicelist.length; i++)
673 serviceBox.addItem(servicelist[i]);
674
675 } else if(e.getSource() == serviceBox) {
676 ServiceData selService = (ServiceData)serviceBox.getSelectedItem();
677 if(selService == null || selService.type == null)
678 return; // nothing valid chosen
679
680 if(selService.type.equals(GSXML.SERVICE_TYPE_QUERY)) {
681 // Make sure we can't accidentally work with already deallocated
682 // data objects in the browsePanel
683 browsePanel.clear();
684 searchSummary.setText(""); // empty any text in the search summary
685
686 this.activity = SEARCHING; // ensures the components are
687 // displayed and shown again, whereas a call to repaint()
688 // did not do the trick
689
690 tabbedPane.setSelectedComponent(this.queryPanel);
691
692 // send off a describe request to the service
693 // in that collection
694 CollectionData selColl
695 = (CollectionData)collBox.getSelectedItem();
696 colName = selColl.name;
697 serviceName = selService.name;
698
699 String response = dlAPIA.describeCollectionService(
700 colName, serviceName);
701 Element serviceResponseXML = getResponseAsDOM(
702 "DescribeCollectionService "+colName+"/"+serviceName,
703 response);
704
705 // generate the appropriate query form as per how the
706 // query has described itself
707 queryPanel.formFromQueryServiceDescribe(serviceResponseXML);
708 } else if(selService.type.equals(GSXML.SERVICE_TYPE_BROWSE)) {
709 LOG.debug("Browse option chosen");
710 this.searchResultsDisplay.clear();
711 this.searchSummary.setText("");
712 this.queryPanel.clear(); // can't do any searching either
713 this.activity = BROWSING;
714 tabbedPane.setSelectedComponent(this.browsePanel);
715
716 CollectionData selColl
717 = (CollectionData)collBox.getSelectedItem();
718 colName = selColl.name;
719 serviceName = selService.name;
720
721 // first send a request for the browse service's metadata
722 // see manual pp.37 and 48
723 String response = dlAPIA.describeCollectionService(
724 colName, serviceName);
725 Element responseMsg = getResponseAsDOM(
726 colName+"/"+serviceName+":", response);
727 browsePanel.displayBrowseOptions(responseMsg);
728 } else { // clicked on non-query, non-browse option, remove form
729 queryPanel.clear();
730 }
731 } else if(e.getSource() == collInfoButton){
732 CollectionData collDataEl
733 = (CollectionData)collBox.getSelectedItem();
734
735 // Create the HTML viewing pane.
736 JEditorPane information = new JEditorPane();
737 information.setEditable(false);
738 information.setContentType("text/html");
739 information.setText(collDataEl.info());
740
741 // Display the dialog with the information in a scrollpane
742 JDialog dialog = new JDialog(this, collDataEl.toString());
743 dialog.getContentPane().add(new JScrollPane(information));
744 dialog.setDefaultCloseOperation(DISPOSE_ON_CLOSE); // not EXIT!
745 dialog.pack();
746 dialog.setSize(400, 300);
747 dialog.setVisible(true);
748 }
749 else if(e.getSource() == setProxySettings) { // proxy settings button
750 // Sthe proxy settings as given in the fields
751 String proxyHost = this.proxyhostField.getText();
752 String proxyPort = this.proxyportField.getText();
753 if(proxyHost.equals("") && proxyPort.equals("")) {
754 return;
755 } else {
756 // Handle proxy settings
757 // (don't need to write to propertiesFile, since proxy
758 // settings are System properties)
759 java.util.Properties systemSettings = System.getProperties();
760 systemSettings.put("http.proxyHost", proxyHost);
761 systemSettings.put("http.proxyPort", proxyPort);
762 // give the hosts for which no proxies are required:
763 systemSettings.put("http.nonProxyHosts",
764 this.nonProxyHostNamesField.getText());
765 System.setProperties(systemSettings);
766 }
767 }
768 }
769
770 /** Called by the instance of the QueryForm class when the user has
771 * pressed the queryPanel's search button to execute a query. Based on
772 * the user-entered values (stored in the parameter HashMap) this
773 * method will call Greenstone to process the query.
774 * @param nameValParamsMap - the query form control names with the values
775 * the user has entered for them. Example, the pair (fqv, the query string),
776 * where fqv is the form control name for the query term. */
777 public void performSearch(HashMap nameValParamsMap) {
778 //Container c = this.getContentPane();
779 //c.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
780 this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
781
782 // (1) Now let's process this query request - passing the
783 // currently selected collection and service:
784 String responseXML = dlAPIA.query(
785 colName, serviceName, nameValParamsMap);
786
787 // (2) The search results: document identifiers are returned,
788 // use these to construct a QueryResponseData object
789 Element responseMessage
790 = getResponseAsDOM("Search response:", responseXML);
791 queryResponseObj.setResponseData(responseMessage);
792 LOG.debug(queryResponseObj);
793
794 DocumentNodeData[] doclist = queryResponseObj.getDocumentNodeList();
795
796 // (3) To retrieve Title metadata, need to call with "Title"!!!!
797 // (1st letter in caps)
798 // Retrieving just metadata name=Title for ALL docs (=all docIDs)
799 String metaResponseXML = dlAPIA.retrieveTitleMetadata(this.colName,
800 queryResponseObj.getDocumentNodeIDs());
801 Element metaResponse
802 = getResponseAsDOM("Meta response:", metaResponseXML);
803 queryResponseObj.setMetadataForDocuments(metaResponse);
804
805 // doclist should now have been updated with title metadata for
806 // each doc (docNode)
807 //for(int i = 0; i < doclist.length; i++)
808 //LOG.debug(doclist[i].show());
809
810 // (4) Display this in the search results TreeView
811 tabbedPane.setSelectedComponent(searchPanel);
812 searchResultsDisplay.setResults(doclist);
813 searchSummary.setText(queryResponseObj.toString());
814 searchResultsDisplay.validate();
815 this.searchPanel.validate();
816 this.searchPanel.repaint();
817
818 // set the cursor back
819 //c.setCursor(Cursor.getDefaultCursor());
820 this.setCursor(Cursor.getDefaultCursor());
821 }
822
823
824 /* SEARCH RELATED METHODS */
825 /** Performs a docMetadataRetrieve message request for the docNode
826 * iff the metadata for that docNode is not already set.
827 * @param docNode is the DocumentNodeData object for which all the
828 * metadata is to be retrieved. */
829 public void retrieveAllMetadataFor(DocumentNodeData docNode) {
830 // Lazy retrieval: only retrieve metadata of docNode when required
831 // and if metadata not already set
832 if(docNode.getMetadataList() == null
833 || docNode.getMetadataList().size() <= 1)
834 { // not set yet or only title set,
835 // so do a docMetadataRetrieve for the docNode (all
836 // metadata fields retrieved):
837 String metaResponseXML = dlAPIA.retrieveDocumentMetadata(
838 this.colName, new String[] { docNode.nodeID });
839 Element metaResponse
840 = getResponseAsDOM("Meta response", metaResponseXML);
841
842 // Set the metadata for the docNode
843 if(this.activity == SEARCHING)
844 queryResponseObj.setMetadataForDocuments(metaResponse);
845 else if(this.activity == BROWSING)
846 browseResponseObject.setMetadataForDocuments(metaResponse);
847 } //else docNode's list of metadata already set
848 }
849
850 /** Performs a docMetadataRetrieve message request for the docNode
851 * iff the nodeContent for that docNode is not already set.
852 * @param docNode is the DocumentNodeData object for which the content
853 * is to be retrieved. */
854 public void retrieveContentFor(DocumentNodeData docNode) {
855 // Lazy retrieval: only retrieve content when required.
856 // If it is not yet set, then we do the retrieval, else
857 // our work here is done
858 if(docNode.getContent() == null) { // not set yet, so
859 // retrieve the content for the docNode
860 String contentResponseXML = dlAPIA.retrieveDocumentContent(
861 this.colName, new String[] { docNode.nodeID });
862 Element contentResponse = getResponseAsDOM(
863 "Content response:", contentResponseXML);
864 // probably when infomine is down
865 // Set the content for the docNode
866 if(this.activity==SEARCHING)
867 queryResponseObj.setContentForDocs(contentResponse);
868 else if(this.activity==BROWSING)
869 browseResponseObject.setContentForDocs(contentResponse);
870 }
871 }
872
873 /** Performs a structureRetrieve and title metadata retrieve message-
874 * request for the docNode, but only iff the structure and title for
875 * that docNode is not already set.
876 * @param docNode is the DocumentNodeData object for which the title
877 * is to be retrieved along with the titles of all its descendants. */
878 public void retrieveTitledStructureFor(DocumentNodeData docNode) {
879 DocumentNodeData root = docNode.getRoot();
880 if(root == null) { //then its structure has not yet been set
881 // do a structure retrieve for this document:
882 String structureResponseXML = dlAPIA.retrieveDocumentStructure(
883 this.colName, new String[] { docNode.nodeID });
884 Element structureResponse = getResponseAsDOM(
885 "STRUCTURE: ", structureResponseXML);
886
887 // Get the nodeStructure of this docNode, find its root and
888 // from there set all the descendents
889 // Instead of the following 2 statements can also do:
890 // queryResponseObj.setStructureForDocs(structureResponse);
891
892 Element nodeStructure = ParseUtil.getFirstDescElementCalled(
893 structureResponse, GSXML.NODE_STRUCTURE_ELEM);
894
895 // now we set the root and its descendents using whatever
896 ResponseData responseObject = browseResponseObject;
897 // true if(this.activity == BROWSING)
898 if(this.activity == SEARCHING)
899 responseObject = queryResponseObj;
900
901 root = docNode.setDescendentsOfRootNode(nodeStructure,
902 responseObject.getIDToNodeMapping());
903
904 // Now get only the DocumentNodeData elements in the root's
905 // descendents whose titles have not yet been set
906 String[] setTitleForTheseNodeIDs = root.getDescNodeIDsAsList(true);
907 // Will be null if all titles already set! But this should not be
908 // the case if we have just set the descendents of the root node
909 if(setTitleForTheseNodeIDs != null) {
910 // Retrieve the title metadata for these and set their titles
911 // with the response:
912 String titleMetaResponseXML = dlAPIA.retrieveTitleMetadata(
913 this.colName, setTitleForTheseNodeIDs);
914 Element titleMetaResponse = getResponseAsDOM(
915 "titleMetaResponseXML:", titleMetaResponseXML);
916
917 // Use whatever responseObject is active to set the metadata
918 responseObject.setMetadataForDocuments(titleMetaResponse);
919 }
920 }
921 }
922
923 /* BROWSE RELATED METHODS */
924 /** Given a ClassifierData object indicating what browsing category
925 * was chosen, this method will retrieve all its descendants in the
926 * hierarchy. Only the top-level descendents (children) of the
927 * classification will be set initially.
928 * @param classifier is the ClassifierData object whose children are
929 * to be retrieved. */
930 public void doBrowse(ClassifierData classifier) {
931 String[] classifierNames = { classifier.name };
932 String response = dlAPIA.retrieveBrowseStructure(
933 this.colName, this.serviceName, classifierNames);
934
935 browseResponseObject.clear();
936 Element responseMsgTag = this.getResponseAsDOM(
937 "browseResponse:", response);
938 browseResponseObject.setResponseData(responseMsgTag); //classifier.name
939
940 LOG.debug(browseResponseObject.show());
941
942 this.browsePanel.displayBrowseResults(browseResponseObject,
943 classifier.displayName);
944 this.browsePanel.validate();
945 }
946
947 /** Given a ClassifierNodeData object for browsing, this method will
948 * set the classNode's children (previously retrieved) and retrieve
949 * all the children's metadata including the title.
950 * @param classNode is the ClassifierNodeData object whose title is to
951 * be retrieved along with the titles for its children. */
952 public void retrieveTitledStructureFor(ClassifierNodeData classNode) {
953 // we will only be setting the children in this method and retrieving
954 // the names for them, as it concerns a classifierNodeData (and not
955 // a documentNodeData).
956
957 classNode.setChildren(browseResponseObject.getIDToNodeMapping());
958
959 //String rootID = browseResponseObject.getRootClassifier().nodeID;
960
961 NodeData[] children = classNode.getChildren();
962 Vector docNodeChildren = new Vector(children.length);
963 Vector classNodeChildren = new Vector(children.length);
964 //String nodeIDs[] = new String[children.length];
965 for(int i = 0; i < children.length; i++) {
966 // don't bother setting the metadata if it was
967 // already set (check for empty metadata
968 if(children[i].getMetadataList() == null) {
969 if(children[i] instanceof ClassifierNodeData)
970 classNodeChildren.add(children[i]);
971 else if(children[i] instanceof DocumentNodeData)
972 docNodeChildren.add(children[i]);
973 }
974 }
975 String[] nodeIDs = null;
976
977 // First set the metadata for any classifiers:
978 if(classNodeChildren.size() > 0) {
979 nodeIDs = new String[classNodeChildren.size()];
980 for(int i = 0; i < nodeIDs.length; i++)
981 nodeIDs[i] = ((NodeData)classNodeChildren.get(i)).nodeID;
982
983 // let's just retrieve all the metadata - need to display it
984 // soon anyway
985 String response = dlAPIA.retrieveBrowseMetadata(this.colName,
986 this.serviceName, nodeIDs);
987 Element responseXML = this.getResponseAsDOM(
988 "MetadataRetrieve response: ", response);
989 browseResponseObject.setMetadataForClassifiers(responseXML);
990
991 for(int i = 0; i < nodeIDs.length; i++)
992 LOG.debug("Title: "
993 + ((NodeData)classNodeChildren.get(i)).getTitle());
994 }
995
996 nodeIDs = null;
997 // Now set the metadata for any documentNodes for which metadata
998 // has not been set yet
999 if(docNodeChildren.size() > 0) {
1000 nodeIDs = new String[docNodeChildren.size()];
1001 for(int i = 0; i < nodeIDs.length; i++)
1002 nodeIDs[i] = ((NodeData)docNodeChildren.get(i)).nodeID;
1003
1004 // let's just retrieve all the metadata - need to display it
1005 // soon anyway
1006 String response = dlAPIA.retrieveDocumentMetadata(
1007 this.colName, nodeIDs);
1008 Element responseXML = this.getResponseAsDOM(
1009 "MetadataRetrieve response: ", response);
1010 browseResponseObject.setMetadataForDocuments(responseXML);
1011
1012 for(int i = 0; i < nodeIDs.length; i++)
1013 LOG.debug("Title: "
1014 + ((NodeData)docNodeChildren.get(i)).getTitle());
1015 }
1016 }
1017
1018 /** @return the baseURL of the active digital library interface object */
1019 public String getBaseURL() {
1020 return this.dlAPIA.getAssocFileBaseURL();
1021 }
1022
1023 /** @return the filepath of the documentNode in the active digital library */
1024 public String getFilePath(DocumentNodeData docNode) {
1025 return this.dlAPIA.getAssocFileBaseURL(docNode);
1026 }
1027
1028 /**
1029 * Changes the background colours of the client's user interface
1030 * based on what the active digital library is.
1031 * See files greenstone3/gli/classes/xml/config.xml and
1032 * greenstone3/gli/src/org/greenstone/gatherer/Configuration.java
1033 * @param DL indicates whether the active digital library is Greenstone or
1034 * Fedora (or neither, in which case the GUI defaults to the usual grey).
1035 * @see <a href="http://www.java2s.com/Code/Java/Swing-JFC/UIManagerresourcestotweakthelookofapplications.htm">Java UIManager tutorial</a>
1036 */
1037 public void changeUIColour(int DL)
1038 {
1039 ColourCombo.setColour(DL);
1040 ColourCombo.changeColor(this.collBox);
1041 ColourCombo.changeColor(this.collectionNameField);
1042 ColourCombo.changeColor(this.serviceBox);
1043
1044 // change anonymous super panels' colours:
1045 ColourCombo.changeAncestorColor(this.collBox);
1046 ColourCombo.changeAncestorColor(this.serviceBox);
1047
1048 // change tab pane panels and their colouring
1049 this.queryPanel.changeUIColour();
1050 this.browsePanel.changeUIColour();
1051 this.searchResultsDisplay.changeUIColour();
1052 }
1053
1054 /** The main method of the GS3 java-client application. It instantiates
1055 * an instance of the GS3JavaClient main window and makes it visible. */
1056 public static void main(String[] args) {
1057 // set it up for logging
1058 final String logPropsFile = "log4j.properties";
1059 PropertyConfigurator.configure(logPropsFile);
1060
1061 GS3JavaClient client = new GS3JavaClient();
1062 client.pack();
1063 // make the main window fullscreen (except for on Windows,
1064 // where it disappears under the bar at the bottom)
1065 java.awt.Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
1066 if(System.getProperty("os.name").toLowerCase().contains("windows")) {
1067 d.setSize(d.getWidth()-100, d.getHeight()-100);
1068 }
1069 client.setSize(d);
1070 client.setVisible(true);
1071 client.setDefaultCloseOperation(EXIT_ON_CLOSE);
1072 }
1073}
Note: See TracBrowser for help on using the repository browser.