/**
*#########################################################################
* GS3JavaClient.java - part of the demo-client for Greenstone 3, of the
* Greenstone digital library suite from the New Zealand Digital Library
* Project at the * University of Waikato, New Zealand.
*
* Copyright (C) 2008 New Zealand Digital Library Project
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*########################################################################
*/
package org.greenstone.gs3client;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.greenstone.gs3client.BrowseDisplay.ClassifierData;
import org.greenstone.gs3client.data.BrowseResponseData;
import org.greenstone.gs3client.data.CollectionData;
import org.greenstone.gs3client.data.DocumentNodeData;
import org.greenstone.gs3client.data.ClassifierNodeData;
import org.greenstone.gs3client.data.NodeData;
import org.greenstone.gs3client.data.ParseUtil;
import org.greenstone.gs3client.data.QueryResponseData;
import org.greenstone.gs3client.data.ResponseData;
//By importing this *static* inner class of CollectionData, can refer
//to it by its unqualified name 'ServiceData'. (Learnt this from
//http://today.java.net/pub/a/today/2006/03/23/multi-split-pane.html)
import org.greenstone.gs3client.data.CollectionData.ServiceData;
import org.greenstone.gs3client.dlservices.DigitalLibraryServicesAPIA;
import org.greenstone.gs3client.dlservices.FedoraServicesAPIA;
import org.greenstone.gs3client.dlservices.GS3ServicesAPIA;
import javax.swing.*;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.Container;
import java.awt.Toolkit; // for making this JFrame client fullsize
import java.net.Authenticator;
import java.net.PasswordAuthentication;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import java.util.Vector;
import java.util.HashMap;
import java.io.StringReader;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import org.xml.sax.InputSource;
import org.greenstone.gsdl3.util.GSXML;
import java.awt.Cursor;
/*
To make this class compile with Java 5/Java 1.5 need to rename the file
xalan.jar.tmp (located in $GS3_HOME/web/WEB-INF/lib) to xalan.jar
Without doing that, it will complain (unless compiled with Java 1.4.2).
RUNTIME Configuration of this class:
- this client needs the jar files:
log4j, xercesImpl, mail, lucene, javagdbm,
And possibly: xml-apis, activation, axis, mg, mgpp
- VM arguments: -Djava.library.path=/research/ak19/greenstone3/lib/jni
COMPILE Configuration of this class:
- BUILD PATH needs the jar files:
gsdl3 (or just the class GSXML), jaxrpc, axis
*/
/**
* The main Javaclient class. Creates the main window containing:
* - the radio button group for making either Greenstone 3 or Fedora the active DL.
* - the comboboxes for selecting the collection and the service therein
* - three panes - for executing queries, viewing search results and browsing.
* @author ak19
*/
public class GS3JavaClient extends JFrame implements ActionListener {
// static final long serialVersionUID = 1; //eclipse keeps warning
/** The Logger for this class */
static Logger LOG = Logger.getLogger(GS3JavaClient.class);
/** The value of the SEARCHING activity */
public static int SEARCHING = 0;
/** The value of the BROWSING activity */
public static int BROWSING = 1;
/** we want to display a drop-down box for the services available,
* but only Services that can be executed (searching and browsing) */
protected static final boolean executableServicesOnly = true;
/** To keep track of whether we are searching or browsing.
* Value of activity can be SEARCHING OR BROWSING */
protected int activity = 0; //
/** Reference to a digital library instance (Greenstone 3 or Fedora) that
* allows this client to execute services offered by the digital library */
protected DigitalLibraryServicesAPIA dlAPIA = null;
/** Reference to the object that interacts with Greenstone3's web services */
protected GS3ServicesAPIA greenstoneDL = null;
/** Reference to the object that interacts with the FedoraGS3.jar component */
protected FedoraServicesAPIA fedoraDL = null;
/** Object that stores the data of a query response XML message */
protected QueryResponseData queryResponseObj = null;
/** Object that stores the data of a browse response XML message
* (response for classification hierarchies) */
protected BrowseResponseData browseResponseObject = null;
/** Preferred language of display items in responses.
* "" or "en" for English */
protected String lang = "";
/** The currently selected collection */
protected String colName = "";
/** The currently selected service */
protected String serviceName = "";
/* The always-visible GUI objects of this main window */
protected JComboBox dlChooser = null;
protected JTextField proxyhostField = null;
protected JTextField proxyportField = null;
protected JTextField nonProxyHostNamesField = null;
protected JButton setProxySettings = null;
protected JComboBox serviceBox = null;
protected JComboBox collBox = null;
protected JButton collInfoButton = null;
protected JButton searchButton = null;
protected JTabbedPane tabbedPane = null;
protected static final int SELECT = 0;
protected static final int GREENSTONE = 1;
protected static final int FEDORA = 2;
protected static final String[] dlOptions = {"select", "greenstone", "fedora"};
/* Components of the query tab */
protected QueryForm queryPanel = null;
protected JTextField collectionNameField = null;
/* Components of the search tab */
protected SearchResultsDisplay searchResultsDisplay = null;
protected JPanel searchPanel = null;
protected JTextArea searchSummary = null;
/* Components of the browse tab */
protected BrowseDisplay browsePanel = null;
/** @return the language of the display items */
public String getLanguage() { return lang; }
/** Set the preferred language of the display items
* @param lang - the preferred language for display values */
public void setLanguage(String lang) { this.lang = lang; }
/** Inner class that handles authentication for any sites (urls, etc.)
* that require it. A dialog pops up to request username and password
* details from the user for each site's realm that needs authentication.
*/
static class PasswordAuthenticator extends Authenticator {
protected PasswordAuthentication getPasswordAuthentication() {
JTextField username = new JTextField();
JTextField password = new JPasswordField();
JPanel panel = new JPanel(new GridLayout(2,2));
panel.add(new JLabel("User Name"));
panel.add(username);
panel.add(new JLabel("Password") );
panel.add(password);
int option = JOptionPane.showConfirmDialog(null, new Object[] {
"Site: "+getRequestingHost(),
"Realm: "+getRequestingPrompt(), panel},
"Enter Network Password",
JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
if ( option == JOptionPane.OK_OPTION ) {
return new PasswordAuthentication(
username.getText(), password.getText().toCharArray());
} else {
return null;
}
}
}
/** Default constructor that creates and initialises this main
* window and its internal GUI components */
public GS3JavaClient() {
super();
this.setTitle("Greenstone 3 web services demo-client");
// digital library panel lets the user choose the digital library
// repository to access and to set the proxy settings
JPanel dlPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
dlChooser = new JComboBox(dlOptions);
dlPanel.add(new JLabel("Use digital library:"));
dlPanel.add(dlChooser);
dlChooser.addActionListener(this);
dlPanel.setBorder(BorderFactory.createTitledBorder(
"Digital library settings"));
this.proxyhostField = new JTextField(15);
this.proxyportField = new JTextField(4);
this.nonProxyHostNamesField = new JTextField(20);
this.setProxySettings = new JButton("Set");
nonProxyHostNamesField.setToolTipText("The hosts for which no proxies are required "
+ "(separate hosts with |, * wildcard allowed)");
JPanel topProxyPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
topProxyPanel.add(new JLabel("Proxy host:"));
topProxyPanel.add(proxyhostField);
topProxyPanel.add(new JLabel("Proxy port:"));
topProxyPanel.add(proxyportField);
JPanel bottomProxyPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
bottomProxyPanel.add(new JLabel("No proxy for:"));
bottomProxyPanel.add(nonProxyHostNamesField);
bottomProxyPanel.add(setProxySettings);
setProxySettings.addActionListener(this);
JPanel proxyPanel = new JPanel(new BorderLayout());
proxyPanel.add(topProxyPanel, BorderLayout.CENTER);
proxyPanel.add(bottomProxyPanel, BorderLayout.SOUTH);
proxyPanel.setBorder(BorderFactory.createTitledBorder(
"Connection settings"));
// Add the dlPanel and proxyPanel next to each other at the top
JPanel topPanel = new JPanel(new BorderLayout());
topPanel.add(dlPanel, BorderLayout.CENTER);
topPanel.add(proxyPanel, BorderLayout.EAST);
// Setting up the GUI of this client
// create a JComboBox, and an item in it for each collection
collBox = new JComboBox();
serviceBox = new JComboBox();
JPanel collPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
collPanel.add(new JLabel("Choose collection:"));
collPanel.add(collBox);
// displayName
collPanel.add(new JLabel("Full name:"));
collectionNameField = new JTextField(18);
collectionNameField.setEditable(false);
collectionNameField.setCaretPosition(0);
collPanel.add(collectionNameField);
// detailed information button, shows collection's description
collInfoButton = new JButton("Info");
collInfoButton.addActionListener(this);
collPanel.add(collInfoButton);
JPanel servicePanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
servicePanel.add(new JLabel("Available services:"));
servicePanel.add(serviceBox);
JPanel collServicesPanel = new JPanel(new BorderLayout());
collServicesPanel.add(collPanel, BorderLayout.NORTH);
collServicesPanel.add(servicePanel, BorderLayout.SOUTH);
tabbedPane = new JTabbedPane(); // tabs on top
queryPanel = new QueryForm(this);
tabbedPane.add("Query", queryPanel);
searchResultsDisplay = new SearchResultsDisplay(this);
searchResultsDisplay.setOpaque(true); //necessary for JTree
JScrollPane searchView = new JScrollPane(searchResultsDisplay);
searchSummary = new JTextArea();
searchSummary.setEditable(false);
searchPanel = new JPanel(new BorderLayout());
searchPanel.add(searchView, BorderLayout.CENTER);
searchPanel.add(searchSummary, BorderLayout.NORTH);
tabbedPane.add("Search Results", searchPanel);
JPanel activityPanel = new JPanel(new BorderLayout());
activityPanel.add(collServicesPanel, BorderLayout.NORTH);
activityPanel.add(tabbedPane, BorderLayout.CENTER);
Container c = this.getContentPane();
c.setLayout(new BorderLayout()); // new BoxLayout(c, BoxLayout.Y_AXIS));
c.add(topPanel, BorderLayout.NORTH);
c.add(activityPanel, BorderLayout.CENTER);
// browse panel
browsePanel = new BrowseDisplay(this);
tabbedPane.add("Browse", browsePanel);
// add actionlisteners
collBox.addActionListener(this);
serviceBox.addActionListener(this);
// GUI DONE, now instantiate the DATA and DIGITAL LIBRARY objects
// instantiate the objects that deal with storing query response data
// and browse response data
queryResponseObj = new QueryResponseData();
browseResponseObject = new BrowseResponseData();
// The java.net.Authenticator can be used to send user credentials
// when needed. When no username/password are provided then a popup
// is shown to ask for the credentials. *Only* when a site/realm
// requires password and username does the Authenticator show the
// dialog. For example, the dialog will appear when pwd & username
// are needed for proxy authorisation.
Authenticator.setDefault(new PasswordAuthenticator());
changeDL(null); // no dl selected
// Set the selection colours that will be uniform for all DLs
UIManager.put("Tree.textBackground", ColourCombo.transparent);
// Instead of the white tree text background, set it to transparent
UIManager.put("Tree.selectionBackground", ColourCombo.yellow);
UIManager.put("TabbedPane.selected", ColourCombo.yellow);
UIManager.put("TabbedPane.selected", ColourCombo.yellow);
UIManager.put("ComboBox.selectionBackground", ColourCombo.yellow);
UIManager.put("List.selectionBackground", ColourCombo.yellow);
UIManager.put("TextArea.selectionBackground", ColourCombo.yellow);
UIManager.put("TextField.selectionBackground", ColourCombo.yellow);
// force the UI to load these new UIManager defaults
javax.swing.SwingUtilities.updateComponentTreeUI(this);
// We can't change the UIManager defaults (properly) throughout GUI
// display-time, only upon creation and first display. This is
// because updateComponentTreeUI() has no effect once components
// have been displayed. For this reason, the various changeUIColor()
// methods and class ColourCombo have been written.
}
/** Attempts to establish a connection to GS3 Web services and instantiate
* a GS3ServicesAPIA object and store it in the member variable greenstoneDL.
* If it was unsuccessful, then this variable remains at null and an error
* message is displayed. */
protected boolean createGreenstoneDLConnection()
{
// store the old choice of dl, if there was any
int oldSetting = (dlAPIA == null) ? SELECT : FEDORA;
// try instantiating a GS3 dl handle
try {
greenstoneDL = new GS3ServicesAPIA();
return true; // success
} catch(DigitalLibraryServicesAPIA.CancelException e){
// The user pressed cancel in the gs3 services instantiation dialog
// Set the dl drop-down list option back to whatever it was
} catch(Exception e) {
// still unable to instantiate greenstone, but show
// the error for what went wrong
JOptionPane.showMessageDialog(
null,
"Error connecting to Greenstone 3 QBRSOAPServer web services.\n"
+ "When attempting to process its wsdl file, encountered the problem:\n"
+ e,
"Fatal error instantiating Digital Library Services interface. Exiting...",
JOptionPane.ERROR_MESSAGE
);
//e.printStackTrace(System.err);
LOG.error("Error connecting to Greenstone 3 web services:\n" + e);
}
// We'd be here if an exception occurred. Need to back to the old dl
// settings
dlChooser.setSelectedIndex(oldSetting);
return false;
}
/** Attempts to establish a connection to FedoraGS3.jar and instantiate
* a FedoraServicesAPIA object and store it in the member variable fedoraDL.
* If it was unsuccessful, then this variable remains at null and an error
* message is displayed. */
protected boolean createFedoraDLConnection()
{
// store the old choice of dl, if there was any
int oldSetting = oldSetting = (dlAPIA == null) ? SELECT : GREENSTONE;
// Try to instantiate a Fedora dl handle
try {
fedoraDL = new FedoraServicesAPIA();
return true; // success
} catch(
org.greenstone.fedora.services.FedoraGS3Exception.CancelledException e)
{
// The user pressed cancel in the fedora services instantiation dlg
// Set the dl drop-down list option back to whatever it was
} catch(Exception e) {
JOptionPane.showMessageDialog(
null,
"Error instantiating the interface to the Fedora Repository\n"+ e,
"Unable to connect to Fedora's digital library services.",
JOptionPane.ERROR_MESSAGE
);
//e.printStackTrace(System.err);
LOG.error(
"Error instantiating the interface to the Fedora Repository:\n"+ e);
}
// We'd be here if an exception occurred. Need to go back to the old dl
// settings
dlChooser.setSelectedIndex(oldSetting);
return false;
}
/** Method that is called when the user chooses to change the active
* digital library (between Greenstone3 and Fedora).
* @param dl is the new active digital library (the
* DigitalLibraryServicesAPIA object to change to). */
protected void changeDL(DigitalLibraryServicesAPIA dl) {
// change the colour of the interface
this.changeUIColour(dlChooser.getSelectedIndex());
// clear up remnants of previously selected digital library's
// processing
browsePanel.clear();
searchResultsDisplay.clear();
this.searchSummary.setText("");
browseResponseObject.clear();
queryResponseObj.clear();
// set current digital library to selected one
dlAPIA = dl;
if(dlAPIA == null) {
// clear some panels so the user can't do anything
this.queryPanel.clear();
collBox.removeAllItems();
collBox.setEnabled(false);
serviceBox.removeAllItems();
serviceBox.setEnabled(false);
this.collectionNameField.setText("");
this.collInfoButton.setEnabled(false);
return;
}
// start retrieving the information related to the chosen dl
String response = dlAPIA.describe();
if(response == null) {
LOG.error("Error: no response from dlAPIA.describe() of "
+ dlAPIA.getDisplayName());
System.exit(1);
}
Element responseXML = getResponseAsDOM(
"DESCRIBE RESPONSE:\n", response);
// Get the collectionList element of the response
// from the default messageRouter-describe:
Element collectionList = ParseUtil.getFirstDescElementCalled(
responseXML, // (, "collectionList")
GSXML.COLLECTION_ELEM+GSXML.LIST_MODIFIER
);
if(collectionList == null)
LOG.error("collectionList is null!");
// Next, create a CollectionData object for each collection using
// its name
CollectionData[] collData = null;
Vector v = ParseUtil.getAllChildElementsCalled(collectionList,
GSXML.COLLECTION_ELEM); // (, "collection")
if(v == null)
LOG.error("collections are null!");
if(v != null) {
StringBuffer buf = new StringBuffer("Collections:\n");
collData = new CollectionData[v.size()];
for(int i = 0; i < v.size(); i++){
collData[i] = new CollectionData((Element)v.get(i));
buf.append(collData[i].name + ", ");
}
}
// Now send a describe request to each collection
// And set the fields for each collData using the response
for(int i = 0; i < collData.length; i++){
response = dlAPIA.describeCollection(collData[i].name);
responseXML = getResponseAsDOM(
"describeCollection "+collData[i].name+":", response);
Element collectionTag = ParseUtil.getFirstDescElementCalled(
responseXML, GSXML.COLLECTION_ELEM);
// set the other fields of the CollectionData object using
// the collectionTag of the response from Collection-describe:
collData[i].setFields(collectionTag);
}
if(collData == null) {
LOG.debug("No collections in the chosen repository");
return;
} else {
this.collInfoButton.setEnabled(true);
collBox.setEnabled(true);
serviceBox.setEnabled(true);
}
// fill in the combobox containing the collections and the one
// containing the services
collBox.removeAllItems();
for(int i = 0; i < collData.length; i++)
collBox.addItem(collData[i]);
collBox.setSelectedItem(collData[0]);
this.serviceBox.removeAllItems();
ServiceData[] serviceData = collData[0].getServiceList(
executableServicesOnly);
for(int i = 0; i < serviceData.length; i++)
serviceBox.addItem(serviceData[i]);
serviceBox.setSelectedIndex(0); // whichever might be the first
}
/** Given an XML response string, returns the root document (element)
* representing its DOM form.
* @param response - the XML response string to be converted into
* its DOM form
* @return the response as an XML DOM Element */
protected Element getResponseAsDOM(String debugPrefix, String response) {
if(response == null) // will not be the case, because an empty
return null; // response message will be sent instead
// First let's print out the response to the LOG
// Note that the response is XML and will start on new line already
LOG.debug(debugPrefix + response);
// The following line when uncommented will output all response
// msgs coming back from the web services
//System.out.println(debugPrefix + response);
// At present, assuming response is okay - later need to first look
// for element and process this meaningfully before returning
// XML DOM version of response. Example error:
//
//
//
// IOException during connection to http://infominehelper.ucr.edu/cgi-bin/canned_search?theme=gsdl3&query=water&fields=kw,au,su,ti,de,fu,&no_of_records_per_page=10&start_page_no=1: java.net.ConnectException: Connection refused
//
//
Element message = null;
try{
// turn the String xml response into a DOM tree:
DocumentBuilder builder
= DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc
= builder.parse(new InputSource(new StringReader(response)));
message = doc.getDocumentElement();
} catch(Exception e){
if(response == null) {
response = "";
}
JOptionPane.showMessageDialog(this,
"An error occurred while trying to parse the response:\n"
+ response
+ "\nException message:\n" + e.getMessage(),
"Parse error", JOptionPane.ERROR_MESSAGE);
e.printStackTrace();
}
NodeList errorList = message.getElementsByTagName(GSXML.ERROR_ELEM);
if(errorList.getLength() == 0)
return message;
// else we have one (or more?) error(s):
Element error = (Element)errorList.item(0);
String errorMessage = ParseUtil.getBodyTextValue(error);
String errorType = error.getAttribute("type");
// no need to display error message if it was a query that was
// just executed and no results were found
if(//errorType.equals(GSXML.ERROR_TYPE_SYNTAX) &&
errorMessage.toLowerCase().indexOf("no documentnode found") != -1)
{
// if we're in here, we know that a search/query was performed
// That means we are dealing with the searchResultsDisplay
// and can clear it.
this.searchResultsDisplay.clear();
this.searchSummary.setText("");
}
else { // display error message
final int numLetters = 60; // number of letters per line
String[] words = errorMessage.split(" "); //get the individual words
String line = words[0];
errorMessage = "";
// go through all the words and build up lines where none is
// longer than the specified number of letters
for(int i = 1; i < words.length; i++) { // append the word
// and a space to the same line unless the line is too long
if(numLetters > line.length() + words[i].length()) {
if(line.equals(""))
line = words[i];
else line = line + " " + words[i];
// check if line is full after adding new word
if(line.length() == numLetters) { // finish the line
errorMessage = errorMessage + line + "\n";
line = "";
}
} // else the word has to go on the next line
else { //finish the line and move on:
errorMessage = errorMessage + line + "\n";
line = words[i];
}
if(i == (words.length-1)) { // extra word on last line
errorMessage = errorMessage + line;
}
}
LOG.debug("errorMessage:\n" + errorMessage);
JOptionPane.showMessageDialog(this, errorMessage, "Error: "+errorType,
JOptionPane.ERROR_MESSAGE);
}
return message;
}
/** Event handler for actionEvents such as a change in the active digital
* library, a collection being selected in the dropdown box or the collection
* -Info button being pressed, or a service being selected in the service
* dropdown box (browsing or searching). */
public void actionPerformed(ActionEvent e) {
if(e.getSource() == dlChooser) {
// We need to change to a Wait cursor while we do the switch
Container c = this.getContentPane();
c.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
boolean success = true;
// Change the dlAPIA handle to the chosen digital library,
// instantiating DigitalLibraryServicesAPIA objects when necessary:
// if they haven't yet been created
switch(dlChooser.getSelectedIndex())
{
case GREENSTONE:
if(this.greenstoneDL == null) {
success = createGreenstoneDLConnection();
}
// no need to do anything if the user chose
// the same DL again
if(success && dlAPIA!=this.greenstoneDL) {
// current DL not already set to greenstoneDL
// so set it
this.changeDL(greenstoneDL);
}
break;
case FEDORA:
if(this.fedoraDL == null) {
success = createFedoraDLConnection();
}
// no need to do anything if the user chose
// the same DL again
if(success && dlAPIA!=this.fedoraDL) {
// current DL not already set to fedoraDL
// so set it
this.changeDL(fedoraDL);
}
break;
case SELECT:
default:
this.changeDL(null); // no dl, so default colours
break;
}
// set the cursor back
c.setCursor(Cursor.getDefaultCursor());
} else if(e.getSource() == collBox) {
CollectionData collDataEl
= (CollectionData)collBox.getSelectedItem();
if(collDataEl == null) // need to check for this here, because
return; // removing all items from collBox fires actionPerformed
// display the collection's full name
this.collectionNameField.setText(collDataEl.getDisplayName());
this.collectionNameField.setCaretPosition(0);
// display the services in the selected collection
serviceBox.removeAllItems();
ServiceData[] servicelist = collDataEl.getServiceList(
executableServicesOnly);
for(int i = 0; i < servicelist.length; i++)
serviceBox.addItem(servicelist[i]);
} else if(e.getSource() == serviceBox) {
ServiceData selService = (ServiceData)serviceBox.getSelectedItem();
if(selService == null || selService.type == null)
return; // nothing valid chosen
if(selService.type.equals(GSXML.SERVICE_TYPE_QUERY)) {
// Make sure we can't accidentally work with already deallocated
// data objects in the browsePanel
browsePanel.clear();
searchSummary.setText(""); // empty any text in the search summary
this.activity = SEARCHING; // ensures the components are
// displayed and shown again, whereas a call to repaint()
// did not do the trick
tabbedPane.setSelectedComponent(this.queryPanel);
// send off a describe request to the service
// in that collection
CollectionData selColl
= (CollectionData)collBox.getSelectedItem();
colName = selColl.name;
serviceName = selService.name;
String response = dlAPIA.describeCollectionService(
colName, serviceName);
Element serviceResponseXML = getResponseAsDOM(
"DescribeCollectionService "+colName+"/"+serviceName,
response);
// generate the appropriate query form as per how the
// query has described itself
queryPanel.formFromQueryServiceDescribe(serviceResponseXML);
} else if(selService.type.equals(GSXML.SERVICE_TYPE_BROWSE)) {
LOG.debug("Browse option chosen");
this.searchResultsDisplay.clear();
this.searchSummary.setText("");
this.queryPanel.clear(); // can't do any searching either
this.activity = BROWSING;
tabbedPane.setSelectedComponent(this.browsePanel);
CollectionData selColl
= (CollectionData)collBox.getSelectedItem();
colName = selColl.name;
serviceName = selService.name;
// first send a request for the browse service's metadata
// see manual pp.37 and 48
String response = dlAPIA.describeCollectionService(
colName, serviceName);
Element responseMsg = getResponseAsDOM(
colName+"/"+serviceName+":", response);
browsePanel.displayBrowseOptions(responseMsg);
} else { // clicked on non-query, non-browse option, remove form
queryPanel.clear();
}
} else if(e.getSource() == collInfoButton){
CollectionData collDataEl
= (CollectionData)collBox.getSelectedItem();
// Create the HTML viewing pane.
JEditorPane information = new JEditorPane();
information.setEditable(false);
information.setContentType("text/html");
information.setText(collDataEl.info());
// Display the dialog with the information in a scrollpane
JDialog dialog = new JDialog(this, collDataEl.toString());
dialog.getContentPane().add(new JScrollPane(information));
dialog.setDefaultCloseOperation(DISPOSE_ON_CLOSE); // not EXIT!
dialog.pack();
dialog.setSize(400, 300);
dialog.setVisible(true);
}
else if(e.getSource() == setProxySettings) { // proxy settings button
// Sthe proxy settings as given in the fields
String proxyHost = this.proxyhostField.getText();
String proxyPort = this.proxyportField.getText();
if(proxyHost.equals("") && proxyPort.equals("")) {
return;
} else {
// Handle proxy settings
// (don't need to write to propertiesFile, since proxy
// settings are System properties)
java.util.Properties systemSettings = System.getProperties();
systemSettings.put("http.proxyHost", proxyHost);
systemSettings.put("http.proxyPort", proxyPort);
// give the hosts for which no proxies are required:
systemSettings.put("http.nonProxyHosts",
this.nonProxyHostNamesField.getText());
System.setProperties(systemSettings);
}
}
}
/** Called by the instance of the QueryForm class when the user has
* pressed the queryPanel's search button to execute a query. Based on
* the user-entered values (stored in the parameter HashMap) this
* method will call Greenstone to process the query.
* @param nameValParamsMap - the query form control names with the values
* the user has entered for them. Example, the pair (fqv, the query string),
* where fqv is the form control name for the query term. */
public void performSearch(HashMap nameValParamsMap) {
//Container c = this.getContentPane();
//c.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
// (1) Now let's process this query request - passing the
// currently selected collection and service:
String responseXML = dlAPIA.query(
colName, serviceName, nameValParamsMap);
// (2) The search results: document identifiers are returned,
// use these to construct a QueryResponseData object
Element responseMessage
= getResponseAsDOM("Search response:", responseXML);
queryResponseObj.setResponseData(responseMessage);
LOG.debug(queryResponseObj);
DocumentNodeData[] doclist = queryResponseObj.getDocumentNodeList();
// (3) To retrieve Title metadata, need to call with "Title"!!!!
// (1st letter in caps)
// Retrieving just metadata name=Title for ALL docs (=all docIDs)
String metaResponseXML = dlAPIA.retrieveTitleMetadata(this.colName,
queryResponseObj.getDocumentNodeIDs());
Element metaResponse
= getResponseAsDOM("Meta response:", metaResponseXML);
queryResponseObj.setMetadataForDocuments(metaResponse);
// doclist should now have been updated with title metadata for
// each doc (docNode)
//for(int i = 0; i < doclist.length; i++)
//LOG.debug(doclist[i].show());
// (4) Display this in the search results TreeView
tabbedPane.setSelectedComponent(searchPanel);
searchResultsDisplay.setResults(doclist);
searchSummary.setText(queryResponseObj.toString());
searchResultsDisplay.validate();
this.searchPanel.validate();
this.searchPanel.repaint();
// set the cursor back
//c.setCursor(Cursor.getDefaultCursor());
this.setCursor(Cursor.getDefaultCursor());
}
/* SEARCH RELATED METHODS */
/** Performs a docMetadataRetrieve message request for the docNode
* iff the metadata for that docNode is not already set.
* @param docNode is the DocumentNodeData object for which all the
* metadata is to be retrieved. */
public void retrieveAllMetadataFor(DocumentNodeData docNode) {
// Lazy retrieval: only retrieve metadata of docNode when required
// and if metadata not already set
if(docNode.getMetadataList() == null
|| docNode.getMetadataList().size() <= 1)
{ // not set yet or only title set,
// so do a docMetadataRetrieve for the docNode (all
// metadata fields retrieved):
String metaResponseXML = dlAPIA.retrieveDocumentMetadata(
this.colName, new String[] { docNode.nodeID });
Element metaResponse
= getResponseAsDOM("Meta response", metaResponseXML);
// Set the metadata for the docNode
if(this.activity == SEARCHING)
queryResponseObj.setMetadataForDocuments(metaResponse);
else if(this.activity == BROWSING)
browseResponseObject.setMetadataForDocuments(metaResponse);
} //else docNode's list of metadata already set
}
/** Performs a docMetadataRetrieve message request for the docNode
* iff the nodeContent for that docNode is not already set.
* @param docNode is the DocumentNodeData object for which the content
* is to be retrieved. */
public void retrieveContentFor(DocumentNodeData docNode) {
// Lazy retrieval: only retrieve content when required.
// If it is not yet set, then we do the retrieval, else
// our work here is done
if(docNode.getContent() == null) { // not set yet, so
// retrieve the content for the docNode
String contentResponseXML = dlAPIA.retrieveDocumentContent(
this.colName, new String[] { docNode.nodeID });
Element contentResponse = getResponseAsDOM(
"Content response:", contentResponseXML);
// probably when infomine is down
// Set the content for the docNode
if(this.activity==SEARCHING)
queryResponseObj.setContentForDocs(contentResponse);
else if(this.activity==BROWSING)
browseResponseObject.setContentForDocs(contentResponse);
}
}
/** Performs a structureRetrieve and title metadata retrieve message-
* request for the docNode, but only iff the structure and title for
* that docNode is not already set.
* @param docNode is the DocumentNodeData object for which the title
* is to be retrieved along with the titles of all its descendants. */
public void retrieveTitledStructureFor(DocumentNodeData docNode) {
DocumentNodeData root = docNode.getRoot();
if(root == null) { //then its structure has not yet been set
// do a structure retrieve for this document:
String structureResponseXML = dlAPIA.retrieveDocumentStructure(
this.colName, new String[] { docNode.nodeID });
Element structureResponse = getResponseAsDOM(
"STRUCTURE: ", structureResponseXML);
// Get the nodeStructure of this docNode, find its root and
// from there set all the descendents
// Instead of the following 2 statements can also do:
// queryResponseObj.setStructureForDocs(structureResponse);
Element nodeStructure = ParseUtil.getFirstDescElementCalled(
structureResponse, GSXML.NODE_STRUCTURE_ELEM);
// now we set the root and its descendents using whatever
ResponseData responseObject = browseResponseObject;
// true if(this.activity == BROWSING)
if(this.activity == SEARCHING)
responseObject = queryResponseObj;
root = docNode.setDescendentsOfRootNode(nodeStructure,
responseObject.getIDToNodeMapping());
// Now get only the DocumentNodeData elements in the root's
// descendents whose titles have not yet been set
String[] setTitleForTheseNodeIDs = root.getDescNodeIDsAsList(true);
// Will be null if all titles already set! But this should not be
// the case if we have just set the descendents of the root node
if(setTitleForTheseNodeIDs != null) {
// Retrieve the title metadata for these and set their titles
// with the response:
String titleMetaResponseXML = dlAPIA.retrieveTitleMetadata(
this.colName, setTitleForTheseNodeIDs);
Element titleMetaResponse = getResponseAsDOM(
"titleMetaResponseXML:", titleMetaResponseXML);
// Use whatever responseObject is active to set the metadata
responseObject.setMetadataForDocuments(titleMetaResponse);
}
}
}
/* BROWSE RELATED METHODS */
/** Given a ClassifierData object indicating what browsing category
* was chosen, this method will retrieve all its descendants in the
* hierarchy. Only the top-level descendents (children) of the
* classification will be set initially.
* @param classifier is the ClassifierData object whose children are
* to be retrieved. */
public void doBrowse(ClassifierData classifier) {
String response = dlAPIA.retrieveBrowseStructure(
this.colName, this.serviceName, classifier.name);
browseResponseObject.clear();
Element responseMsgTag = this.getResponseAsDOM(
"browseResponse:", response);
browseResponseObject.setResponseData(responseMsgTag); //classifier.name
LOG.debug(browseResponseObject.show());
this.browsePanel.displayBrowseResults(browseResponseObject,
classifier.displayName);
this.browsePanel.validate();
}
/** Given a ClassifierNodeData object for browsing, this method will
* set the classNode's children (previously retrieved) and retrieve
* all the children's metadata including the title.
* @param classNode is the ClassifierNodeData object whose title is to
* be retrieved along with the titles for its children. */
public void retrieveTitledStructureFor(ClassifierNodeData classNode) {
// we will only be setting the children in this method and retrieving
// the names for them, as it concerns a classifierNodeData (and not
// a documentNodeData).
classNode.setChildren(browseResponseObject.getIDToNodeMapping());
//String rootID = browseResponseObject.getRootClassifier().nodeID;
NodeData[] children = classNode.getChildren();
Vector docNodeChildren = new Vector(children.length);
Vector classNodeChildren = new Vector(children.length);
//String nodeIDs[] = new String[children.length];
for(int i = 0; i < children.length; i++) {
// don't bother setting the metadata if it was
// already set (check for empty metadata
if(children[i].getMetadataList() == null) {
if(children[i] instanceof ClassifierNodeData)
classNodeChildren.add(children[i]);
else if(children[i] instanceof DocumentNodeData)
docNodeChildren.add(children[i]);
}
}
String[] nodeIDs = null;
// First set the metadata for any classifiers:
if(classNodeChildren.size() > 0) {
nodeIDs = new String[classNodeChildren.size()];
for(int i = 0; i < nodeIDs.length; i++)
nodeIDs[i] = ((NodeData)classNodeChildren.get(i)).nodeID;
// let's just retrieve all the metadata - need to display it
// soon anyway
String response = dlAPIA.retrieveBrowseMetadata(this.colName,
this.serviceName, nodeIDs);
Element responseXML = this.getResponseAsDOM(
"MetadataRetrieve response: ", response);
browseResponseObject.setMetadataForClassifiers(responseXML);
for(int i = 0; i < nodeIDs.length; i++)
LOG.debug("Title: "
+ ((NodeData)classNodeChildren.get(i)).getTitle());
}
nodeIDs = null;
// Now set the metadata for any documentNodes for which metadata
// has not been set yet
if(docNodeChildren.size() > 0) {
nodeIDs = new String[docNodeChildren.size()];
for(int i = 0; i < nodeIDs.length; i++)
nodeIDs[i] = ((NodeData)docNodeChildren.get(i)).nodeID;
// let's just retrieve all the metadata - need to display it
// soon anyway
String response = dlAPIA.retrieveDocumentMetadata(
this.colName, nodeIDs);
Element responseXML = this.getResponseAsDOM(
"MetadataRetrieve response: ", response);
browseResponseObject.setMetadataForDocuments(responseXML);
for(int i = 0; i < nodeIDs.length; i++)
LOG.debug("Title: "
+ ((NodeData)docNodeChildren.get(i)).getTitle());
}
}
/** @return the baseURL of the active digital library interface object */
public String getBaseURL() {
return this.dlAPIA.getAssocFileBaseURL();
}
/** @return the filepath of the documentNode in the active digital library */
public String getFilePath(DocumentNodeData docNode) {
return this.dlAPIA.getAssocFileBaseURL(docNode);
}
/**
* Changes the background colours of the client's user interface
* based on what the active digital library is.
* See files greenstone3/gli/classes/xml/config.xml and
* greenstone3/gli/src/org/greenstone/gatherer/Configuration.java
* @param DL indicates whether the active digital library is Greenstone or
* Fedora (or neither, in which case the GUI defaults to the usual grey).
* @see Java UIManager tutorial
*/
public void changeUIColour(int DL)
{
ColourCombo.setColour(DL);
ColourCombo.changeColor(this.collBox);
ColourCombo.changeColor(this.collectionNameField);
ColourCombo.changeColor(this.serviceBox);
// change anonymous super panels' colours:
ColourCombo.changeAncestorColor(this.collBox);
ColourCombo.changeAncestorColor(this.serviceBox);
// change tab pane panels and their colouring
this.queryPanel.changeUIColour();
this.browsePanel.changeUIColour();
this.searchResultsDisplay.changeUIColour();
}
/** The main method of the GS3 java-client application. It instantiates
* an instance of the GS3JavaClient main window and makes it visible. */
public static void main(String[] args) {
// set it up for logging
final String logPropsFile = "log4j.properties";
PropertyConfigurator.configure(logPropsFile);
GS3JavaClient client = new GS3JavaClient();
client.pack();
// make the main window fullscreen (except for on Windows,
// where it disappears under the bar at the bottom)
java.awt.Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
if(System.getProperty("os.name").equalsIgnoreCase("Windows")) {
d.setSize(d.getWidth()-100, d.getHeight()-100);
}
client.setSize(d);
client.setVisible(true);
client.setDefaultCloseOperation(EXIT_ON_CLOSE);
}
}