/** *######################################################################### * 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; public static final int SELECT = 0; public static final int GREENSTONE = 1; public 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 + "\n" + response); // The following line when uncommented will output all response // msgs coming back from the web services //System.out.println(debugPrefix + "\n" + 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 }, new String[] {"all"}); 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 }, new String[] {"descendants"}, new String[]{""}); 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[] classifierNames = { classifier.name }; String response = dlAPIA.retrieveBrowseStructure( this.colName, this.serviceName, classifierNames, new String[]{"entire"}, new String[]{""}); // structure and info 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, new String[]{"all"}); 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, new String[] {"all"}); 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(); } public int getActiveDL() { return dlChooser.getSelectedIndex(); // SELECT, GREENSTONE, or FEDORA } /** 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").toLowerCase().contains("windows")) { d.setSize(d.getWidth()-100, d.getHeight()-100); } client.setSize(d); client.setVisible(true); client.setDefaultCloseOperation(EXIT_ON_CLOSE); } }