root/main/trunk/gli/src/org/greenstone/gatherer/greenstone/Plugins.java @ 31776

Revision 31776, 12.7 KB (checked in by ak19, 4 months ago)

Kathy described a problem on the mailing list about the AutoLoadConverters? msg appearing before XML content when connecting with a client-GLI to a remote GS3, which breaks parsing of the XML. (I found it was present in my GS3 installation from 4 May 2016.) I've narrowed it down to running client-gli with the debug flag turned on, which seemed related to the same problem I'd seen when running gli -debug after the change to SafeProcess? in Plugins.java, which I fixed by removing lines preceding XML content before parsing the XML. For client-gli, SafeProcess? isn't used which is also why the problem with client-gli is much older, but I'm now using a common and existing solution for both: doing what Plugins.java used to do before the change to SafeProcess?, which is call XMLTools.readXMLStream(), which would parse out content before XML. The RemoteGreenstoneServer? should only call this method if it actually has some XML content it's dealing with. Could have solved this in RemoteGreenstoneServerAction?.java's GetScriptOptions?, but am solving it in RemoteGreenstoneServer?'s sendCommandToServerInternal, since there may be many Actions returning XML, not just GetScriptOptions?.

  • Property svn:keywords set to Author Date Id Revision
Line 
1/**
2 *#########################################################################
3 *
4 * A component of the Gatherer application, part of the Greenstone digital
5 * library suite from the New Zealand Digital Library Project at the
6 * University of Waikato, New Zealand.
7 *
8 * Author: Michael Dewsnip, NZDL Project, University of Waikato
9 *
10 * Copyright (C) 2006 New Zealand Digital Library Project
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *########################################################################
26 */
27package org.greenstone.gatherer.greenstone;
28
29import java.io.*;
30import java.util.*;
31import javax.swing.*;
32import org.greenstone.gatherer.Configuration;
33import org.greenstone.gatherer.DebugStream;
34import org.greenstone.gatherer.Dictionary;
35import org.greenstone.gatherer.Gatherer;
36import org.greenstone.gatherer.cdm.Argument;
37import org.greenstone.gatherer.cdm.Plugin;
38import org.greenstone.gatherer.remote.RemoteGreenstoneServer;
39import org.greenstone.gatherer.util.SafeProcess;
40import org.greenstone.gatherer.util.StaticStrings;
41import org.greenstone.gatherer.util.Utility;
42import org.greenstone.gatherer.util.XMLTools;
43import org.w3c.dom.*;
44import org.xml.sax.*;
45
46
47/** This class is for maintaining a list of known plug-ins, and importing new plugins using the parser. */
48public class Plugins
49{
50    // A list of all the plugins in the core Greenstone "perllib/plugins" folder (arguments may not be loaded)
51    static private ArrayList core_greenstone_plugins_list = null;
52    // The name of the loaded collection
53    static private String collection_name = null;
54    // A list of all the plugins in the loaded collection's "perllib/plugins" folder (arguments may not be loaded)
55    static private ArrayList collection_specific_plugins_list = new ArrayList();
56
57
58    static public Plugin getPlugin(String plugin_name, boolean arguments_required)
59    {
60    Plugin plugin = null;
61    boolean collection_specific = false;
62
63    // Check the collection-specific plugins first
64    for (int i = 0; i < collection_specific_plugins_list.size(); i++) {
65        Plugin collection_specific_plugin = (Plugin) collection_specific_plugins_list.get(i);
66        if (collection_specific_plugin.getName().equals(plugin_name)) {
67        plugin = collection_specific_plugin;
68        collection_specific = true;
69        break;
70        }
71    }
72
73    // Try the core Greenstone plugins if necessary
74    if (plugin == null) {
75        for (int i = 0; i < core_greenstone_plugins_list.size(); i++) {
76        Plugin core_greenstone_plugin = (Plugin) core_greenstone_plugins_list.get(i);
77        if (core_greenstone_plugin.getName().equals(plugin_name)) {
78            plugin = core_greenstone_plugin;
79            break;
80        }
81        }
82    }
83
84    // If we've found the plugin, load its arguments now, if required
85    if (plugin != null && arguments_required) {
86        if (!plugin.hasLoadedOptions()) {
87        loadPluginInfo(plugin, collection_specific);
88        }
89        else {
90        DebugStream.println("Already loaded arguments for " + plugin_name + "!");
91        }
92    }
93
94    return plugin;
95    }
96
97
98    /** Returns a new list from merging the collection-specific and the core Greenstone plugins. */
99    static public ArrayList getPluginsList()
100    {
101    ArrayList plugins_list = new ArrayList();
102    plugins_list.addAll(collection_specific_plugins_list);
103
104    // Add in the core Greenstone plugins, taking care not to overwrite any collection-specific ones
105    for (int i = 0; i < core_greenstone_plugins_list.size(); i++) {
106        Plugin core_greenstone_plugin = (Plugin) core_greenstone_plugins_list.get(i);
107
108        boolean found = false;
109        for (int j = 0; j < collection_specific_plugins_list.size(); j++) {
110        Plugin collection_specific_plugin = (Plugin) collection_specific_plugins_list.get(j);
111        if (core_greenstone_plugin.getName().equals(collection_specific_plugin.getName())) {
112            found = true;
113            break;
114        }
115        }
116
117        if (!found) {
118        plugins_list.add(core_greenstone_plugin);
119        }
120    }
121
122    return plugins_list;
123    }
124
125
126    static private void loadPluginInfo(Plugin plugin, boolean collection_specific)
127    {
128    DebugStream.println("Loading arguments for " + plugin.getName() + "...");
129
130    // Run pluginfo.pl to get the list of plugins
131    try {
132        String pluginfo_xml = null;
133        if (Gatherer.isGsdlRemote) {
134        String pluginfo_options = "&plugin=" + plugin;
135        if (collection_specific) {
136            pluginfo_options += "&collection=" + collection_name;
137        }
138        pluginfo_xml = Gatherer.remoteGreenstoneServer.getScriptOptions("pluginfo.pl", pluginfo_options);
139        }
140        else {
141        ArrayList args = new ArrayList();
142        args.add(Configuration.perl_path);
143        args.add("-S");
144        args.add(LocalGreenstone.getBinScriptDirectoryPath() + "pluginfo.pl");
145        args.add("-gs_version");
146        if (Gatherer.GS3) {
147            args.add("3");
148        } else {
149            args.add("2");
150        }
151        if (collection_specific) {
152            args.add("-collection");
153            args.add(collection_name);
154            if (Gatherer.GS3) {
155              args.add("-site");
156              args.add(Configuration.site_name);
157            }           
158        }
159        args.add("-xml");
160        args.add("-language");
161        args.add(Configuration.getLanguage());
162        args.add(plugin.getName());
163
164        // Run the pluginfo.pl process:
165        // Create the process.
166        SafeProcess process = new SafeProcess((String[]) args.toArray(new String[] { }));
167        process.setSplitStdErrorNewLines(true);
168
169        // run the SafeProcess
170        int exitVal = process.runProcess();
171        if(exitVal != 0) {
172            throw new Exception("*** Error running pluginfo.pl loadPlugInfo, process exited with: "
173                    + exitVal);
174        }
175        // get the result: We expect XML to have come out of the process std error stream.
176        pluginfo_xml = process.getStdError();
177        // make sure to have parsed out any lines preceding the XML content
178        pluginfo_xml = XMLTools.readXMLStream(pluginfo_xml).toString();
179        ///System.err.println("*********\nPluginInfo, got:\n" + pluginfo_xml + "\n**********\n");
180        }
181
182        // Check the XML output was obtained successfully
183        if (pluginfo_xml == null || pluginfo_xml.length() == 0) {
184        plugin.setHasLoadedOptions(false); // failure to load options
185        JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CDM.PlugInManager.PlugIn_XML_Parse_Failed", plugin.getName()), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
186        return;
187        } else {
188        plugin.setHasLoadedOptions(true);
189        }
190
191        parsePluginInfoXML(plugin, pluginfo_xml);
192    }
193    catch (Exception exception) {
194        DebugStream.printStackTrace(exception);
195    }
196    }
197
198
199    static public void loadPluginsList(String collection_name_arg)
200    {
201    DebugStream.println("In loadPluginsList()...");
202
203    // If we're getting the collection-specific plugins, clear the old list no matter what
204    if (collection_name_arg != null) {
205        collection_name = collection_name_arg;
206        collection_specific_plugins_list = new ArrayList();
207    }
208
209    // Run pluginfo.pl to get the list of plugins
210    try {
211        String xml = null;
212        if (Gatherer.isGsdlRemote) {
213        String pluginfo_options = "&listall";
214        if (collection_name != null) {
215            pluginfo_options += "&collection=" + collection_name;
216        }
217        String pluginfo_output = Gatherer.remoteGreenstoneServer.getScriptOptions("pluginfo.pl", pluginfo_options);
218        xml = pluginfo_output;
219        }
220        else {
221        ArrayList args = new ArrayList();
222        args.add(Configuration.perl_path);
223        args.add("-S");     
224        args.add(LocalGreenstone.getBinScriptDirectoryPath() + "pluginfo.pl");
225        args.add("-gs_version");
226        if (Gatherer.GS3) {
227            args.add("3");
228        } else {
229            args.add("2");
230        }
231        if (collection_name != null) {
232            args.add("-collection");
233            args.add(collection_name);
234            if (Gatherer.GS3) {
235              args.add("-site");
236              args.add(Configuration.site_name);
237            }
238        }
239        args.add("-listall");
240        args.add("-xml");
241       
242        // Run the pluginfo.pl process:
243        // Create the process.
244        SafeProcess process = new SafeProcess((String[]) args.toArray(new String[] { }));
245        process.setSplitStdErrorNewLines(true);
246
247        // run the SafeProcess
248        int exitVal = process.runProcess();
249        if(exitVal != 0) {
250            throw new Exception("*** Error running pluginfo.pl loadPluginsList, process exited with: "
251                    + exitVal);
252        }
253        // get the result: We expect XML to have come out of the process std error stream. 
254        xml = process.getStdError();
255        // make sure to parse out any lines before the XML content, else running "gli -debug" results in an XML error:
256        // for pluginfo.pl -listall, we see a "AutoloadConverters" (PDFBox) message
257        // before actual XML output, which breaks XML parsing.
258        // This gets rid of output before "<?xml" in the way that the code did before the change to SafeProcess
259        // Then we can call the same from method RemoteGreenstoneServer.java, so that running "client-gli -debug"
260        // will work too.
261        xml = XMLTools.readXMLStream(xml).toString();
262       
263        ///System.err.println("*********\nPluginsList, got:\n" + xml + "\n**********\n");
264        }
265
266        // Check the XML output was obtained successfully
267        if (xml == null || xml.length() == 0) {
268        JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CDM.PluginManager.Plugin_List_XML_Parse_Failed"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
269        return;
270        }
271
272        if (collection_name != null) {
273        collection_specific_plugins_list = parsePluginsListXML(xml);
274        }
275        else {
276        core_greenstone_plugins_list = parsePluginsListXML(xml);
277        }
278    }
279    catch (Exception exception) {
280        DebugStream.printStackTrace(exception);
281    }
282    }
283
284
285    static private void parsePluginInfoXML(Plugin plugin, String xml)
286    {
287    Document document = XMLTools.parseXML(new StringReader(xml));
288    if (document == null) {
289        plugin.setHasLoadedOptions(false); // failure to load the options/failed plugin
290        JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CDM.PlugInManager.PlugIn_XML_Parse_Failed", plugin.getName()), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
291        return;
292    } else {
293        plugin.setHasLoadedOptions(true);
294    }
295
296    parsePluginInfoXMLNode(plugin, document.getDocumentElement());
297    }
298
299
300    static private void parsePluginInfoXMLNode(Plugin plugin, Node root_node)
301    {
302    for (Node node = root_node.getFirstChild(); node != null; node = node.getNextSibling()) {
303        String node_name = node.getNodeName();
304
305        if (node_name.equalsIgnoreCase("Name")) {
306        plugin.setName(XMLTools.getValue(node));
307        }
308        else if (node_name.equals("Desc")) {
309        plugin.setDescription(XMLTools.getValue(node));
310        }
311        else if (node_name.equals("Abstract")) {
312        plugin.setIsAbstract(XMLTools.getValue(node).equalsIgnoreCase(StaticStrings.YES_STR));
313        }
314        else if (node_name.equalsIgnoreCase("Explodes")) {
315        plugin.setDoesExplodeMetadataDatabases(XMLTools.getValue(node).equalsIgnoreCase(StaticStrings.YES_STR));
316        }
317        else if (node_name.equalsIgnoreCase("SourceReplaceable")) { // looking for <SourceReplaceable> tag
318        plugin.setDoesReplaceSrcDocsWithHtml(XMLTools.getValue(node).equalsIgnoreCase(StaticStrings.YES_STR));
319        }
320        else if (node_name.equalsIgnoreCase("Processes")) {
321        plugin.setDefaultProcessExpression(XMLTools.getValue(node));
322        }
323        else if (node_name.equalsIgnoreCase("Blocks")) {
324        plugin.setDefaultBlockExpression(XMLTools.getValue(node));
325        }
326        // Parse the plugin arguments
327        else if (node_name.equalsIgnoreCase("Arguments")) {
328        for (Node argument_node = node.getFirstChild(); argument_node != null; argument_node = argument_node.getNextSibling()) {
329            // An option
330            if (argument_node.getNodeName().equalsIgnoreCase("Option")) {
331            Argument argument = new Argument();
332            argument.parseXML((Element) argument_node);
333            plugin.addArgument(argument);
334            }
335        }
336        }
337        // A super plugin class
338        else if (node_name.equalsIgnoreCase("PlugInfo")) {
339        Plugin super_plugin = new Plugin();
340        parsePluginInfoXMLNode(super_plugin, node);
341        plugin.setSuper(super_plugin);
342        }
343    }
344    }
345
346
347    static private ArrayList parsePluginsListXML(String xml)
348    {
349    ArrayList plugins_list = new ArrayList();
350   
351    Document document = XMLTools.parseXML(new StringReader(xml));
352    Node root = document.getDocumentElement();
353    for (Node node = root.getFirstChild(); node != null; node = node.getNextSibling()) {
354        String node_name = node.getNodeName();
355
356        if (node_name.equals("PlugInfo")) {
357        Plugin plugin = new Plugin();
358        parsePluginInfoXMLNode(plugin, node);
359        plugins_list.add(plugin);
360        }
361    }
362
363    return plugins_list;
364    }
365}
Note: See TracBrowser for help on using the browser.