1 | package org.greenstone.fedora.installer;
|
---|
2 |
|
---|
3 | import java.util.*;
|
---|
4 | import java.util.Map.Entry;
|
---|
5 | import java.io.File;
|
---|
6 | import java.io.InputStream;
|
---|
7 | import java.io.OutputStream;
|
---|
8 | import java.io.FileOutputStream;
|
---|
9 | import java.io.IOException;
|
---|
10 | import java.io.ByteArrayInputStream;
|
---|
11 | import java.net.HttpURLConnection;
|
---|
12 | import java.net.URL;
|
---|
13 |
|
---|
14 | import java.io.StringWriter;
|
---|
15 | import javax.xml.parsers.DocumentBuilderFactory;
|
---|
16 | import javax.xml.parsers.DocumentBuilder;
|
---|
17 | import org.w3c.dom.Element;
|
---|
18 | import org.w3c.dom.Document;
|
---|
19 | import org.w3c.dom.NodeList;
|
---|
20 | import org.w3c.dom.Node;
|
---|
21 | import javax.xml.transform.OutputKeys;
|
---|
22 | import javax.xml.transform.Transformer;
|
---|
23 | import javax.xml.transform.TransformerFactory;
|
---|
24 | import javax.xml.transform.dom.DOMSource;
|
---|
25 | import javax.xml.transform.stream.StreamResult;
|
---|
26 | import org.xml.sax.InputSource;
|
---|
27 | import org.xml.sax.SAXException;
|
---|
28 | import org.xml.sax.EntityResolver;
|
---|
29 |
|
---|
30 | import javax.swing.*;
|
---|
31 | import java.awt.*;
|
---|
32 |
|
---|
33 | /**
|
---|
34 | * This class essentially follows the instructions at
|
---|
35 | * http://drama.ramp.org.au/cgi-bin/trac.cgi/wiki/InstallingFedoraGSearch
|
---|
36 | * in order to install Fedora Generic Search from their optimised
|
---|
37 | * fedoragsearch.war file. (I've also tested it on the original war file
|
---|
38 | * fedoragsearch.war available from http://defxws2006.cvt.dk/fedoragsearch/
|
---|
39 | * and it works.)
|
---|
40 | * It then does a few minor extra things in order to make Fedora Generic
|
---|
41 | * Search work specifically with a Fedora repository of Greenstone documents.
|
---|
42 | * @author ak19
|
---|
43 | */
|
---|
44 | public class GSearchInstaller {
|
---|
45 |
|
---|
46 | /** This EntityResolver allows the XML parser to ignore validating
|
---|
47 | * against the DTD specified in the XML since it is pointing to the
|
---|
48 | * wrong location. After parsing, we will put the DTD back in.
|
---|
49 | * (Package class, only used here.)
|
---|
50 | * See http://forum.java.sun.com/thread.jspa?threadID=284209&forumID=34
|
---|
51 | */
|
---|
52 | static class IgnoreDTDEntityResolver implements EntityResolver {
|
---|
53 | public final String systemID;
|
---|
54 |
|
---|
55 | /** Constructor that 'resolves' (by ignoring) DTDs for the given
|
---|
56 | * systemID.
|
---|
57 | * @param systemID is the DTD path to be ignored, given
|
---|
58 | * in the XML file as a SYSTEM property. */
|
---|
59 | public IgnoreDTDEntityResolver(String systemID) {
|
---|
60 | this.systemID = systemID;
|
---|
61 | }
|
---|
62 |
|
---|
63 | /** If the systemId matches the one this IgnoreDTDEntityResolver
|
---|
64 | * was created for, then the specified DTD is skipped.
|
---|
65 | * @param publicId the public ID in the DOCTYPE (not used here).
|
---|
66 | * @param systemId is the SYSTEM id in the DOCTYPE that specifies
|
---|
67 | * the DTD which is to be checked against this
|
---|
68 | * IgnoreDTDEntityResolver object's systemID. */
|
---|
69 | public InputSource resolveEntity(String publicId, String systemId)
|
---|
70 | throws SAXException, java.io.IOException
|
---|
71 | {
|
---|
72 | // The systemId passed in is the entire local file path, which is
|
---|
73 | // wrong. So we extract just the filename first and then make the
|
---|
74 | // comparison
|
---|
75 | int index = systemId.lastIndexOf(File.separator);
|
---|
76 | if(index == -1) {
|
---|
77 | index = systemId.lastIndexOf("/"); // tends to be / even on Windows
|
---|
78 | }
|
---|
79 | systemId = systemId.substring(index+1, systemId.length());
|
---|
80 |
|
---|
81 | if(systemId.equals(this.systemID)) {
|
---|
82 | // this deactivates the DTD
|
---|
83 | return new InputSource(new ByteArrayInputStream(
|
---|
84 | "<?xml version='1.0' encoding='UTF-8'?>".getBytes()));
|
---|
85 | }
|
---|
86 | else return null;
|
---|
87 | }
|
---|
88 | }
|
---|
89 |
|
---|
90 | // Some String class constants
|
---|
91 | public static final String FEDORAGSEARCH = "fedoragsearch";
|
---|
92 | public static final String TOMCAT = "tomcat";
|
---|
93 |
|
---|
94 | // Custom constants for important and much-used environment variables
|
---|
95 | public final String FEDORA_HOME;
|
---|
96 | public final String CATALINA_HOME;
|
---|
97 | public final String scriptExtension; // .bat for Windows and .sh for Linux
|
---|
98 |
|
---|
99 | /** Reads from gsearch.properties file which contains default
|
---|
100 | * directory paths (using variables like FEDORA_HOME and
|
---|
101 | * CATALINA_HOME) and HOST and PORT, and sets these to custom values.
|
---|
102 | * Some of the keys in the properties file include executable
|
---|
103 | * processes (such as for starting and stopping tomcat).
|
---|
104 | */
|
---|
105 | protected Properties gSearchProperties;
|
---|
106 |
|
---|
107 | // custom values
|
---|
108 | public final String indexName;
|
---|
109 | public final String repositoryName;
|
---|
110 | public final String host;
|
---|
111 | public final String port;
|
---|
112 | public final String fedoraUsername; // username of fedoraServer
|
---|
113 | public final String fedoraPassword; // password of fedoraServer
|
---|
114 | public final String gsearchWarFileName; // the path to the fedorgsearch warfile
|
---|
115 |
|
---|
116 | // some internal class constants
|
---|
117 | protected static String PROP_REPOS = "repository";
|
---|
118 | protected static String PROP_INDEX = "index";
|
---|
119 | protected static String PROP_UNAME = "username";
|
---|
120 | protected static String PROP_PASSW = "password";
|
---|
121 | protected static String PROP_HOST = "host";
|
---|
122 | protected static String PROP_PORT = "port";
|
---|
123 | protected static String PROP_FILE = "file";
|
---|
124 | /** Default initialisation/customisation values. In case the Installer
|
---|
125 | * was not provided all parameters, these are used as fallback values */
|
---|
126 | protected static final Properties defaults = new Properties();
|
---|
127 | static {
|
---|
128 | defaults.setProperty(PROP_REPOS, "Fedora");
|
---|
129 | defaults.setProperty(PROP_INDEX, "FedoraIndex");
|
---|
130 | defaults.setProperty(PROP_UNAME, "fedoraAdmin");
|
---|
131 | defaults.setProperty(PROP_PASSW, "");
|
---|
132 | defaults.setProperty(PROP_HOST, "localhost");
|
---|
133 | defaults.setProperty(PROP_PORT, "8080");
|
---|
134 | defaults.setProperty(PROP_FILE, "fedoragsearch.war");
|
---|
135 | }
|
---|
136 |
|
---|
137 | /** GSearchInstaller constructor sets all custom values to defaults */
|
---|
138 | public GSearchInstaller() throws Exception {
|
---|
139 | this(defaults); // use the default options
|
---|
140 | }
|
---|
141 |
|
---|
142 | /** GSearchInstaller constructor sets the custom values */
|
---|
143 | public GSearchInstaller(Properties options) throws Exception
|
---|
144 | {
|
---|
145 | System.out.println(
|
---|
146 | "Preparing for installation of Fedora Generic Search...");
|
---|
147 |
|
---|
148 | // for those options not set, we use the fallbacks in
|
---|
149 | // the defaults Properties
|
---|
150 | this.repositoryName = options.getProperty(PROP_REPOS,
|
---|
151 | defaults.getProperty(PROP_REPOS));
|
---|
152 | this.indexName = options.getProperty(PROP_INDEX,
|
---|
153 | defaults.getProperty(PROP_INDEX));
|
---|
154 | this.fedoraUsername = options.getProperty(PROP_UNAME,
|
---|
155 | defaults.getProperty(PROP_UNAME));
|
---|
156 | this.fedoraPassword = options.getProperty(PROP_PASSW,
|
---|
157 | defaults.getProperty(PROP_PASSW));
|
---|
158 | this.host = options.getProperty(PROP_HOST,
|
---|
159 | defaults.getProperty(PROP_HOST));
|
---|
160 | this.port = options.getProperty(PROP_PORT,
|
---|
161 | defaults.getProperty(PROP_PORT));
|
---|
162 | this.gsearchWarFileName = options.getProperty(PROP_FILE,
|
---|
163 | defaults.getProperty(PROP_FILE));
|
---|
164 |
|
---|
165 | // don't need options anymore
|
---|
166 | options.clear();
|
---|
167 | options = null;
|
---|
168 |
|
---|
169 | // Set the script extension to .sh or .bat depending on the OS
|
---|
170 | if(System.getProperty("os.name").toLowerCase().contains("windows")) {
|
---|
171 | // can be "Windows XP" or something
|
---|
172 | scriptExtension = ".bat";
|
---|
173 | } else { // "Linux", which would also be for Mac
|
---|
174 | scriptExtension = ".sh";
|
---|
175 | }
|
---|
176 |
|
---|
177 | // Set the environment variables
|
---|
178 | FEDORA_HOME = System.getenv("FEDORA_HOME");
|
---|
179 | if(FEDORA_HOME == null) {
|
---|
180 | throw new Exception("Environment variable FEDORA_HOME not set."
|
---|
181 | + " Unable to proceed");
|
---|
182 | }
|
---|
183 |
|
---|
184 | String catalina = System.getenv("CATALINA_HOME");
|
---|
185 | if(catalina != null) {
|
---|
186 | CATALINA_HOME = catalina;
|
---|
187 | } else {
|
---|
188 | // set it to FEDORA_HOME/tomcat
|
---|
189 | CATALINA_HOME = FEDORA_HOME+System.getProperty("file.separator")+TOMCAT;
|
---|
190 | System.err.println("Environment variable CATALINA_HOME "
|
---|
191 | + "not set...\nSetting it to FEDORA_HOME/tomcat: " + CATALINA_HOME);
|
---|
192 | }
|
---|
193 |
|
---|
194 | // User information
|
---|
195 | System.out.println("\tFEDORA_HOME:\t" + this.FEDORA_HOME);
|
---|
196 | System.out.println("\tCATALINA_HOME:\t" + this.CATALINA_HOME);
|
---|
197 | System.out.println("\tFedora host:\t" + this.host);
|
---|
198 | System.out.println("\tFedora port:\t" + this.port);
|
---|
199 | System.out.println("\tRepository name:\t" + this.repositoryName);
|
---|
200 | System.out.println("\tIndex name:\t" + this.indexName);
|
---|
201 |
|
---|
202 | // Load the all important gsearchProperties first and
|
---|
203 | // customise them using the environment variables just set
|
---|
204 | System.out.println("Customising properties for installation:");
|
---|
205 | gSearchProperties = customiseProperties("gsearch.properties", true);
|
---|
206 | }
|
---|
207 |
|
---|
208 | public void install() throws Exception {
|
---|
209 | System.out.println(
|
---|
210 | "Beginning installation of Fedora Generic Search...");
|
---|
211 | // (1) Now we will try moving the fedoragsearch.war file into
|
---|
212 | // fedora tomcat's webapps folder and unpack it there
|
---|
213 | // TODO: check gsearchWarFileName's filename is fedoragsearch.war
|
---|
214 | File gsearchWarFile = new File(gsearchWarFileName);
|
---|
215 | moveUnpackWarFile(gsearchWarFile);
|
---|
216 |
|
---|
217 | // (2) Ensure that lucene.indexes directory exists inside FEDORA_HOME
|
---|
218 | // (not inside FedoraGSearch)
|
---|
219 | createLuceneIndexDir();
|
---|
220 |
|
---|
221 | System.out.println("Customising files for installation...");
|
---|
222 | // (3) Editing $CATALINA_HOME/webapps/fedoragsearch/WEB-INF/classes/log4j.xml
|
---|
223 | // Changing tag <param name="File" value="LOGPATH/fedoragsearch.log"/>
|
---|
224 | // to <param name="File" value="FEDORA_HOME/server/logs/fedoragsearch.log"/>
|
---|
225 | String xmlFileName="log4j.xml";
|
---|
226 | String dtdFileName="log4j.dtd";
|
---|
227 | InputStream xmlSource = ClassLoader.getSystemResourceAsStream(
|
---|
228 | xmlFileName);
|
---|
229 | // We want to read the XML file but as there is a doctype
|
---|
230 | // referring to a dtd file located elsewhere, we need
|
---|
231 | // to temporarily ignore the dtd while reading the XML
|
---|
232 | Document doc = readXML(xmlSource, dtdFileName, xmlFileName);
|
---|
233 |
|
---|
234 | // Now make the necessary changes to the file:
|
---|
235 | // Find the element <param value="xxxLOGPATHxxx"/>
|
---|
236 | // and replace just the LOGPATH bit with FEDORA_HOME
|
---|
237 | String logPath = FEDORA_HOME + "/server/logs/fedoragsearch.log";
|
---|
238 | logPath = logPath.replace(File.separator, "/"); // xml requires the "/"
|
---|
239 | if(!this.replaceElementWithAttrValue(doc, "param", "value",
|
---|
240 | "LOGPATH", logPath, true, false)) {
|
---|
241 | // try again, the element may not contain variable LOGPATH
|
---|
242 | // but it will contain "fedoragsearch.log"
|
---|
243 | this.replaceElementWithAttrValue(doc, "param", "value",
|
---|
244 | "fedoragsearch.log", logPath+"/fedoragsearch.log", true, true);
|
---|
245 | }
|
---|
246 |
|
---|
247 | // Finally write out the file to the correct location, and put the
|
---|
248 | // doctype containing the dtd back in.
|
---|
249 | File xmlFile = new File(gSearchProperties.getProperty("classes.dir"),
|
---|
250 | xmlFileName);
|
---|
251 | writeXML(doc, xmlFile, dtdFileName);
|
---|
252 |
|
---|
253 | // (4) Copy and customise default property file fedoragsearch.properties
|
---|
254 | // Read from properties file with defaults, replacing placeholders
|
---|
255 | // in the default properties with the custom (environment) variables
|
---|
256 | // specified
|
---|
257 | String propFileName = "fedoragsearch.properties";
|
---|
258 | Properties properties = customiseProperties(propFileName, false);
|
---|
259 | copyPropFile(properties, // the customised properties
|
---|
260 | propFileName, // defaults file to customise
|
---|
261 | new File(gSearchProperties.getProperty("config.dir")) // output path
|
---|
262 | );
|
---|
263 |
|
---|
264 | // (5) Rename $CATALINA_HOME/webapps/fedoragsearch/WEB-INF/classes/config/repository/REPOSNAME
|
---|
265 | // as "repositoryName", since we want to reuse some of the files
|
---|
266 | if(!replaceDir(gSearchProperties.getProperty("repository.dir"),
|
---|
267 | "REPOSNAME", repositoryName))
|
---|
268 | {
|
---|
269 | if(!replaceDir(gSearchProperties.getProperty("repository.dir"),
|
---|
270 | "DemoAtDtu", repositoryName)) {
|
---|
271 | replaceDir(gSearchProperties.getProperty("repository.dir"),
|
---|
272 | "Fedora", repositoryName);
|
---|
273 | }
|
---|
274 | }
|
---|
275 |
|
---|
276 | // (6) Copy and customise repositoryProperties
|
---|
277 | propFileName = "repository.properties";
|
---|
278 | properties = customiseProperties(propFileName, false);
|
---|
279 | // add fedora server username and password properties
|
---|
280 | properties.setProperty("fgsrepository.fedoraUser", this.fedoraUsername);
|
---|
281 | properties.setProperty("fgsrepository.fedoraPass", this.fedoraPassword);
|
---|
282 | copyPropFile(properties, // the customised properties
|
---|
283 | propFileName, // the output file name (same as input file)
|
---|
284 | new File(gSearchProperties.getProperty("repository.dir"),
|
---|
285 | repositoryName) // output file path
|
---|
286 | );
|
---|
287 |
|
---|
288 | // (7) Initially, make an as-is copy of the repositoryInfo file
|
---|
289 | // Later can get user input on customising it
|
---|
290 | File reposInfoXML = new File(gSearchProperties.getProperty("repository.dir")
|
---|
291 | +File.separator+repositoryName, "repositoryInfo.xml");
|
---|
292 | // We need to replace the existing reposInfoXML with the customised one
|
---|
293 | copyTemplateFile("repositoryInfo.xml", reposInfoXML, true);
|
---|
294 | // true="replace"
|
---|
295 |
|
---|
296 | // (8) Rename $CATALINA_HOME/webapps/fedoragsearch/WEB-INF/classes/config/index/DemoOnLucene
|
---|
297 | // to "indexName", since it contains other files that are to be used
|
---|
298 | // and will remain unchanged
|
---|
299 | if(!replaceDir(gSearchProperties.getProperty("index.dir"),
|
---|
300 | "DemoOnLucene", indexName)) {
|
---|
301 | replaceDir(gSearchProperties.getProperty("index.dir"),
|
---|
302 | "FedoraIndex", indexName);
|
---|
303 | }
|
---|
304 |
|
---|
305 | // (9) Copy and customise indexProperties
|
---|
306 | propFileName = "index.properties";
|
---|
307 | properties = customiseProperties(propFileName, false);
|
---|
308 | // add fedora server username and password properties
|
---|
309 | copyPropFile(properties, // the customised properties
|
---|
310 | propFileName, // the output file name (same as input file)
|
---|
311 | new File(gSearchProperties.getProperty("index.dir"),
|
---|
312 | indexName) // output file path
|
---|
313 | );
|
---|
314 |
|
---|
315 | // (10) Editing $CATALINA_HOME/webapps/fedoragsearch/WEB-INF/
|
---|
316 | // classes/config/index/FedoraIndex/indexInfo.xml
|
---|
317 | // Customising tags <resultPage indexName="INDEX_NAME">
|
---|
318 | // and <IndexShortName>INDEX_NAME</IndexShortName>
|
---|
319 | xmlFileName="indexInfo.xml";
|
---|
320 | xmlSource = ClassLoader.getSystemResourceAsStream(
|
---|
321 | xmlFileName);
|
---|
322 | // Read the XML file. There is no doctype
|
---|
323 | // referring to any dtd file in indexInfo.xml
|
---|
324 | doc = readXML(xmlSource, "", xmlFileName);
|
---|
325 | // Now make the necessary changes to the file:
|
---|
326 | // Find the element <resultPage indexName="xxxINDEX_NAMExxx"/>
|
---|
327 | // and replace just the INDEX_NAME bit with indexName
|
---|
328 | replaceElementWithAttrValue(doc, "resultPage", "indexName",
|
---|
329 | "INDEX_NAME", indexName, true, false);
|
---|
330 | // Find the element <IndexShortName>xxxINDEX_NAMExxx</IndexShortName>
|
---|
331 | // and replace just the INDEX_NAME bit with indexName
|
---|
332 | replaceElementWithValue(doc,
|
---|
333 | "IndexShortName", "INDEX_NAME", indexName, true, false);
|
---|
334 |
|
---|
335 | // Finally write out the file to the correct location.
|
---|
336 | // Output location should include indexName:
|
---|
337 | xmlFile = new File(
|
---|
338 | gSearchProperties.getProperty("index.dir")+File.separator+indexName,
|
---|
339 | xmlFileName);
|
---|
340 | writeXML(doc, xmlFile, ""); // no dtd to add back in this time.
|
---|
341 |
|
---|
342 | // (11) Enter $CATALINA_HOME/webapps/fedoragsearch/WEB-INF/classes/config/rest.
|
---|
343 | // (12) Edit the stylesheets in here to set the path to your fedora/tomcat.
|
---|
344 | String restPath = gSearchProperties.getProperty("rest.dir");
|
---|
345 | String[] xsltFiles = { "demoBrowseIndexToHtml.xslt",
|
---|
346 | "demoGetIndexInfoToHtml.xslt", "demoGetRepositoryInfoToHtml.xslt",
|
---|
347 | "demoGfindObjectsToHtml.xslt", "demoUpdateIndexToHtml.xslt" };
|
---|
348 | for(int i = 0; i < xsltFiles.length; i++) {
|
---|
349 | File outputFile = null;
|
---|
350 | // File demoBrowseIndexToHtml.xslt will be customised from
|
---|
351 | // a template. Otherwise, the input file we read the DOM from
|
---|
352 | // will later be the file we write it out to
|
---|
353 | if(xsltFiles[i].equals("demoBrowseIndexToHtml.xslt")) { //if(i == 0) {
|
---|
354 | // Then don't read from restPath, read local template
|
---|
355 | xmlSource = ClassLoader.getSystemResourceAsStream(
|
---|
356 | xsltFiles[i]); // get template demoBrowseIndexToHtml
|
---|
357 | // Write to restPath
|
---|
358 | outputFile = new File(restPath, xsltFiles[i]);
|
---|
359 | // Read the XML stream (no dtd to worry about)
|
---|
360 | doc = readXML(xmlSource, "", xsltFiles[i]);
|
---|
361 | } else {
|
---|
362 | // Output file written to the same location
|
---|
363 | xmlFile = new File(restPath, xsltFiles[i]);
|
---|
364 | outputFile = xmlFile;
|
---|
365 | // Read the XML file (no dtd to worry about)
|
---|
366 | doc = readXML(xmlFile, "", xmlFile.getAbsolutePath());
|
---|
367 | }
|
---|
368 |
|
---|
369 | // Now make the necessary changes to the file:
|
---|
370 | // Find the element <xsl:include href="xxxWEBSERVERPATHxxx"/>
|
---|
371 | // and replace just the WEBSERVERPATH bit with CATALINA_HOME
|
---|
372 | if(!replaceElementWithAttrValue(doc, "xsl:include", "href",
|
---|
373 | "WEBSERVERPATH", CATALINA_HOME, true, false)) {
|
---|
374 | // try again, the element may not contain variable LOGPATH
|
---|
375 | // but it will contain "fedoragsearch.log"
|
---|
376 | replaceElementWithAttrValue(doc, "xsl:include", "href",
|
---|
377 | "demoCommon.xslt",
|
---|
378 | CATALINA_HOME+"/webapps/fedoragsearch/WEB-INF/classes/config/rest/demoCommon.xslt",
|
---|
379 | true, true);
|
---|
380 | }
|
---|
381 |
|
---|
382 | // (13) Edit the file demoBrowseIndexToHtml.xslt and replace the
|
---|
383 | // occurrences of indexName in <select name="index">...</select>
|
---|
384 | if(xsltFiles[i].equals("demoBrowseIndexToHtml.xslt")) { //if(i == 0) {
|
---|
385 | replaceElementWithAttrValue(doc,
|
---|
386 | "xsl:when", "test", "INDEX_NAME", indexName, true, false);
|
---|
387 | // two occurrences of the following, so pass false
|
---|
388 | // to ensure it's not a onceOnly replacement, but
|
---|
389 | // replace as often as it occurs.
|
---|
390 | replaceElementWithAttrValue(doc, "option",
|
---|
391 | "value", "INDEX_NAME", indexName, false, false);
|
---|
392 | // again, two occurrences, so replace multiple times
|
---|
393 | replaceElementWithValue(doc, "option",
|
---|
394 | "INDEX_NAME", indexName, false, false);
|
---|
395 | }
|
---|
396 |
|
---|
397 | // Finally write out the XML to the specified output file
|
---|
398 | this.writeXML(doc, outputFile, ""); // no dtd to add back in
|
---|
399 | outputFile = null;
|
---|
400 | }
|
---|
401 |
|
---|
402 | // (14) Edit the fedora.fcfg file to configure Fedora for automatic
|
---|
403 | // updates to notify notify Fedora GSearch of object changes
|
---|
404 | // for reindexing. Also checks that "greenstone" is in the list of
|
---|
405 | // Fedora-recognised PIDs
|
---|
406 | customiseFedoraConfigFile();
|
---|
407 |
|
---|
408 | // (New) Now finish off the installation with the steps described in
|
---|
409 | // gs3-webservices-democlient/docs/HowToFiles/4InstallingFedoraGSearch.html
|
---|
410 | // We're further customising it for greenstone here: only PIDS=greenstone
|
---|
411 | // get indexed
|
---|
412 | // Copy the demoFoxmlToLucene.xslt template into the indexName dir.
|
---|
413 | String demoFoxmlToLucene = "demoFoxmlToLucene.xslt";
|
---|
414 | // output file path is in the indexName directory:
|
---|
415 | File dest = new File(
|
---|
416 | gSearchProperties.getProperty("index.dir")+File.separator+indexName,
|
---|
417 | demoFoxmlToLucene);
|
---|
418 | // copy the template and replace the existing file:
|
---|
419 | this.copyTemplateFile(demoFoxmlToLucene, dest, true);
|
---|
420 | dest = null;
|
---|
421 |
|
---|
422 | System.out.println("Customising done.");
|
---|
423 |
|
---|
424 | // (15) Restart the tomcat server
|
---|
425 | final String stopFedora
|
---|
426 | = gSearchProperties.getProperty("fedora.stop")+scriptExtension;
|
---|
427 | final String startFedora
|
---|
428 | = gSearchProperties.getProperty("fedora.start")+scriptExtension;
|
---|
429 |
|
---|
430 | this.runProcess(new String[]{stopFedora}, false);
|
---|
431 | // wait for fedora to stop before restarting
|
---|
432 | waitForServerToStop();
|
---|
433 | this.runProcess(new String[]{startFedora}, false);
|
---|
434 |
|
---|
435 |
|
---|
436 | // This time, no way to test whether fedora server (and gsearch) are ready
|
---|
437 | System.out.print("Waiting for the fedora server to become ready...");
|
---|
438 | waitForFedoraServer();
|
---|
439 |
|
---|
440 | // Finished installation
|
---|
441 | System.out.println("\nFinished installing Fedora Generic Search.");
|
---|
442 | }
|
---|
443 |
|
---|
444 | /** Indexes the contents of the repository(name) specified during Fedora
|
---|
445 | * Generic Search installation. To do so, it runs the FedoraGenericSearch's
|
---|
446 | * runSOAPClient.sh with "host:port updateIndex fromFoxmlFiles".
|
---|
447 | * @param emptyFirst means the index will be created from scratch by first
|
---|
448 | * executing runSOAPClient.sh with the arguments
|
---|
449 | * "host:port updateIndex createEmpty" before updating from FOXML files.*/
|
---|
450 | public void indexGreenstoneContents(boolean emptyFirst) throws Exception {
|
---|
451 | System.out.println("\nBeginning indexing of repository \""
|
---|
452 | + this.repositoryName + "\"...");
|
---|
453 |
|
---|
454 | // There is a problem running the runSOAPClient script that is part of
|
---|
455 | // the fedoragsearch installation: it has relative paths in its classpaths.
|
---|
456 | // This means we have to cd into the folder and execute the script from
|
---|
457 | // within the folder containing the script. cd would be a process, then
|
---|
458 | // executing the script would be another, independent process by which time
|
---|
459 | // we're no longer in the correct folder again.
|
---|
460 | // Therefore, this method works with a template file for the script: the
|
---|
461 | // place-holder path will be replaced with the absolute path to the LIB
|
---|
462 | // files needed by the script. And then the script can be executed from
|
---|
463 | // wherever.
|
---|
464 |
|
---|
465 | try {
|
---|
466 | // We're going to replace the place-holders in the template script,
|
---|
467 | // and put a modified copy of the script in folder soap.client.dir
|
---|
468 | java.io.BufferedReader in = new java.io.BufferedReader(
|
---|
469 | new java.io.InputStreamReader(
|
---|
470 | ClassLoader.getSystemResourceAsStream("runSOAPClient"
|
---|
471 | +this.scriptExtension)));
|
---|
472 |
|
---|
473 | File soapClientScript = new File(
|
---|
474 | gSearchProperties.getProperty("soap.client.dir"),
|
---|
475 | "runSOAPClient" +this.scriptExtension);
|
---|
476 | OutputStream out = new FileOutputStream(soapClientScript);
|
---|
477 |
|
---|
478 | // Placeholder's replacement value: denotes the classpath
|
---|
479 | // directory for the LIB folder mentioned in the script.
|
---|
480 | final String FEDORA_GSEARCH
|
---|
481 | = gSearchProperties.getProperty("fedoragsearch.dir");
|
---|
482 | // Read the contents of the template file line by line.
|
---|
483 | // Do the replacements and write the lines out to the file.
|
---|
484 | String line = null;
|
---|
485 | while((line = in.readLine()) != null) {
|
---|
486 | line = line.replace("FEDORA_GSEARCH", FEDORA_GSEARCH);
|
---|
487 | line += "\n"; // append new line at the end of each line
|
---|
488 | out.write(line.getBytes());
|
---|
489 | }
|
---|
490 | in.close();
|
---|
491 | out.close();
|
---|
492 | in = null;
|
---|
493 | out = null;
|
---|
494 |
|
---|
495 | // need to make the script executable on Linux
|
---|
496 | if(System.getProperty("os.name").equalsIgnoreCase("Linux")) {
|
---|
497 | this.runProcess(new String[]{"chmod", "u+x",
|
---|
498 | soapClientScript.getAbsolutePath()}, true);
|
---|
499 | }
|
---|
500 |
|
---|
501 | // Now run the two steps of the script:
|
---|
502 | // "updateIndex createEmpty"
|
---|
503 | if(emptyFirst) {
|
---|
504 | this.runProcess(new String[]{ soapClientScript.getAbsolutePath(),
|
---|
505 | host+":"+port, "updateIndex", "createEmpty" }, true);
|
---|
506 | }
|
---|
507 |
|
---|
508 | // "updateIndex fromFoxmlFiles"
|
---|
509 | this.runProcess(new String[]{ soapClientScript.getAbsolutePath(),
|
---|
510 | host+":"+port, "updateIndex", "fromFoxmlFiles" }, false);
|
---|
511 |
|
---|
512 | soapClientScript = null;
|
---|
513 |
|
---|
514 | System.out.println("Finished indexing repository \""
|
---|
515 | + this.repositoryName + "\".");
|
---|
516 | System.out.println("Try visiting the Fedora Generic Search REST url"
|
---|
517 | + "\n\t(http://"+host+":"+port+"/fedoragsearch/rest"
|
---|
518 | + "\n\tor https://"+host+":"+port+"/fedoragsearch/rest)");
|
---|
519 | } catch(IOException e){
|
---|
520 | System.out.println("Error when copying runSOAPClient template file.");
|
---|
521 | throw(e);
|
---|
522 | } catch(Exception e){
|
---|
523 | System.out.println("Error when executing updateIndex.");
|
---|
524 | throw(e);
|
---|
525 | }
|
---|
526 | }
|
---|
527 |
|
---|
528 |
|
---|
529 | //****************************HELPER METHODS****************************/
|
---|
530 | /** Method that will run the process associated with the gSearchProperties key.
|
---|
531 | * Waits until the process is executed.
|
---|
532 | * @param args signify the executable process and its arguments. The first element
|
---|
533 | * must be the key into gSearchProperties whose value denotes the executable process
|
---|
534 | * that is to be run. Subsequent elements are the actual arguments to that process.
|
---|
535 | * @param ignoreWindows if true will not plug the cmd /c start "" at the start of
|
---|
536 | * the arguments. If false, and only of the OS is windows, then these additional
|
---|
537 | * arguments get prepended to those already in the args array. */
|
---|
538 | protected int runProcess(String[] args, boolean ignoreWindows) throws Exception {
|
---|
539 | // for Windows, we need to prepend extra arguments to launch a process
|
---|
540 | // (Question remains: how to get rid of cmd consoles of child processes?)
|
---|
541 | if(!ignoreWindows && System.getProperty("os.name").toLowerCase().contains("windows")) {
|
---|
542 | String[] tmp = args;
|
---|
543 | args = new String[args.length+4];
|
---|
544 | args[0] = "cmd";
|
---|
545 | args[1] = "/c";
|
---|
546 | args[2] = "start";
|
---|
547 | args[3] = "/MIN"; // launches console minimised
|
---|
548 | int j = 4;
|
---|
549 | for(int i = 0; i < tmp.length; i++) {
|
---|
550 | args[j++] = tmp[i];
|
---|
551 | }
|
---|
552 | tmp = null;
|
---|
553 | }
|
---|
554 | System.out.print("Running processCommand: ");
|
---|
555 | for(int i = 0; i < args.length; i++) {
|
---|
556 | System.out.print(args[i] + " ");
|
---|
557 | }
|
---|
558 |
|
---|
559 | Process process = Runtime.getRuntime().exec(args);
|
---|
560 | int exitValue = process.waitFor();
|
---|
561 | System.out.println("\n\tExit value is: " + exitValue);
|
---|
562 | // set local reference to null in case args was dynamically allocated
|
---|
563 | args = null;
|
---|
564 |
|
---|
565 | process.destroy();
|
---|
566 | return exitValue;
|
---|
567 | }
|
---|
568 |
|
---|
569 | /**
|
---|
570 | * Loads properties from the property file denoted by propFileName
|
---|
571 | * and replaces all place-holders (such as FEDORA_HOME, CATALINA_HOME,
|
---|
572 | * HOST, PORT) with the custom values specified for this installation.
|
---|
573 | * These customised properties are returned in the Properties map.
|
---|
574 | * Never overwrite the property file given by propFileName!
|
---|
575 | * They are defaults, meant to be customised elsewhere.
|
---|
576 | *
|
---|
577 | * @param propFileName is the name of the template properties file
|
---|
578 | * to be opened and read from. (Keep it read-only!)
|
---|
579 | * @param display - if true, then prints the contents of the properties
|
---|
580 | * if false, does not.
|
---|
581 | * @return the properties in the template properties file
|
---|
582 | * customised with the values provided during installation.
|
---|
583 | */
|
---|
584 | protected Properties customiseProperties(
|
---|
585 | String propFileName, boolean display) throws Exception
|
---|
586 | {
|
---|
587 | Properties defaultProps = new Properties();
|
---|
588 | InputStream in
|
---|
589 | = GSearchInstaller.class.getClassLoader().getResourceAsStream(
|
---|
590 | propFileName);
|
---|
591 | if(in == null) {
|
---|
592 | throw new Exception(
|
---|
593 | "Unable to locate " + propFileName
|
---|
594 | +".properties file. Cannot proceed.");
|
---|
595 | }
|
---|
596 | defaultProps.load(in);
|
---|
597 | // Create properties that will contain customised values based on
|
---|
598 | // default values
|
---|
599 | Properties properties = new Properties();
|
---|
600 | Set entries = defaultProps.entrySet();
|
---|
601 | Iterator i = entries.iterator();
|
---|
602 | while (i.hasNext()) {
|
---|
603 | Entry e = (Entry)i.next();
|
---|
604 | String key = (String)e.getKey();
|
---|
605 | String value = (String)e.getValue();
|
---|
606 | if(value.startsWith("FEDORA_HOME")) {
|
---|
607 | value = value.replace("FEDORA_HOME", FEDORA_HOME);
|
---|
608 | value = value.replace("/", File.separator);
|
---|
609 | } else if(value.startsWith("CATALINA_HOME")) {
|
---|
610 | value = value.replace("CATALINA_HOME", CATALINA_HOME);
|
---|
611 | value = value.replace("/", File.separator);
|
---|
612 | }
|
---|
613 |
|
---|
614 | // now check for any property *containing* placeholder strings
|
---|
615 | // that need to be replaced. Separate if stmts: check each
|
---|
616 | if(value.contains("HOST:PORT")) {
|
---|
617 | value = value.replace("HOST:PORT", host+":"+port);
|
---|
618 | }
|
---|
619 | if(value.contains("REPOSITORY_NAME")) {
|
---|
620 | value = value.replace("REPOSITORY_NAME", repositoryName);
|
---|
621 | }
|
---|
622 | if(value.contains("INDEX_NAME")) {
|
---|
623 | value = value.replace("INDEX_NAME", indexName);
|
---|
624 | }
|
---|
625 | // except for URLs, File path separators have to be system independent
|
---|
626 | /*if(replacePaths && !value.startsWith("http")) {
|
---|
627 | value = value.replace("/", File.separator);
|
---|
628 | }*/
|
---|
629 |
|
---|
630 | // Now overwrite the property
|
---|
631 | properties.setProperty(key, value);
|
---|
632 |
|
---|
633 |
|
---|
634 | // if instructed to print some information:
|
---|
635 | if(display) {
|
---|
636 | System.out.println("\tkey: " + key + "\tvalue: " + value);
|
---|
637 | }
|
---|
638 | }
|
---|
639 | // we're not going to use the default properties anymore
|
---|
640 | defaultProps.clear();
|
---|
641 | defaultProps = null;
|
---|
642 |
|
---|
643 | return properties;
|
---|
644 | }
|
---|
645 |
|
---|
646 |
|
---|
647 | /** Waits for the fedora server to stop */
|
---|
648 | public void waitForServerToStop() throws Exception {
|
---|
649 | URL fedoraServerURL = new URL(gSearchProperties.getProperty("gsearch.base"));
|
---|
650 | boolean running = true;
|
---|
651 | // try the server for 60s tops or until it finally stops running
|
---|
652 | for(int i = 1; running && i <= 60; i++) {
|
---|
653 | try{
|
---|
654 | // now try to connect - if this fails, we know the server has stopped
|
---|
655 | fedoraServerURL.getContent();
|
---|
656 | System.out.print(".");
|
---|
657 | Thread.sleep(1000);
|
---|
658 | }catch(IOException e) {
|
---|
659 | // means we have stopped running, good
|
---|
660 | System.out.println(" Server stopped.");
|
---|
661 | running = false;
|
---|
662 | }
|
---|
663 | }
|
---|
664 | System.out.println();
|
---|
665 | }
|
---|
666 |
|
---|
667 | /** Waits for the fedora server to be ready after a server start. */
|
---|
668 | public void waitForFedoraServer() throws Exception {
|
---|
669 | URL fedoraServerURL = new URL(gSearchProperties.getProperty("gsearch.base"));
|
---|
670 | boolean ready = false;
|
---|
671 | for(int i = 1; !ready && i <= 60; i++) { // try the server for 60s tops
|
---|
672 | try{
|
---|
673 | // now try to connect, if it succeeds, then we know the server is ready
|
---|
674 | fedoraServerURL.getContent();
|
---|
675 | ready = true;
|
---|
676 | System.out.println(" Server ready.");
|
---|
677 | }catch(IOException e) {
|
---|
678 | // if an IOException occurs, then it means the server is not yet ready
|
---|
679 | System.out.print(".");
|
---|
680 | Thread.sleep(1000);
|
---|
681 | }
|
---|
682 | }
|
---|
683 | fedoraServerURL = null;
|
---|
684 | System.out.println();
|
---|
685 | }
|
---|
686 |
|
---|
687 | /** Method that renames folder src in outputPath to dest.
|
---|
688 | * @param outputPath is the directory in which src resides.
|
---|
689 | * @param src is the name of the folder in outputPath that is
|
---|
690 | * to be renamed.
|
---|
691 | * @param dest is what src is to be renamed to. */
|
---|
692 | protected boolean replaceDir(String outputPath, String src, String dest)
|
---|
693 | {
|
---|
694 | // renaming folder located in outputPath from src to dest
|
---|
695 | File srcDir = new File(outputPath, src);
|
---|
696 | File destDir = new File(outputPath, dest);
|
---|
697 |
|
---|
698 | srcDir.renameTo(destDir);
|
---|
699 | if(!destDir.exists()) {
|
---|
700 | System.out.println("Unable to create directory: "
|
---|
701 | + destDir.getAbsolutePath());
|
---|
702 | srcDir = destDir = null;
|
---|
703 | return false;
|
---|
704 | }
|
---|
705 |
|
---|
706 | srcDir = destDir = null;
|
---|
707 | return true;
|
---|
708 | }
|
---|
709 |
|
---|
710 | /** Stores the given properties in the file outputPath/propFileName.
|
---|
711 | * @param properties is the Properties map to be written out to a file.
|
---|
712 | * @param propFileName is the name of the output properties file.
|
---|
713 | * @param outputPath is the directory into which the properties file
|
---|
714 | * is to be written.
|
---|
715 | * */
|
---|
716 | protected void copyPropFile(Properties properties,
|
---|
717 | String propFileName, File outputPath)
|
---|
718 | throws Exception
|
---|
719 | {
|
---|
720 | // Write the customised properties to an output file of the same
|
---|
721 | // name but in the given outputPath location
|
---|
722 | FileOutputStream out = new FileOutputStream(
|
---|
723 | new File(outputPath, propFileName));
|
---|
724 | properties.store(out, propFileName + " based on "
|
---|
725 | + "Muradora's \"Installing Fedora GSearch for Full Text Search\"");
|
---|
726 | // make sure we close it, since Properties.store() does not close it
|
---|
727 | out.close();
|
---|
728 | outputPath = null; // if no one else has a ref to it, will end up in gc
|
---|
729 | }
|
---|
730 |
|
---|
731 | /** Copies internal template src file (in executable jar) to dest file.
|
---|
732 | * If replace is true, then if the dest file exists, it will be overwritten.
|
---|
733 | * From http://exampledepot.com/egs/java.io/CopyFile.html
|
---|
734 | * @param src is the internal file (internal to the jar) to be copied
|
---|
735 | * its inputStream is obtained and copied.
|
---|
736 | * @param dest is the file into which the contents of src are to be copied
|
---|
737 | * @param replace indicates whether dest is to be replaced if it already
|
---|
738 | * exists. If replace is true, then any existing dest is replaced with the
|
---|
739 | * copied output file of the same name. If false, the copy operation does
|
---|
740 | * not take place
|
---|
741 | * @throws IOException if the copying failed.
|
---|
742 | */
|
---|
743 | protected void copyTemplateFile(String src, File dest, boolean replace)
|
---|
744 | throws IOException
|
---|
745 | {
|
---|
746 | if(!replace && dest.exists()) {
|
---|
747 | System.err.println(src + " already exists, not overwritten.");
|
---|
748 | return;
|
---|
749 | }
|
---|
750 | //FileInputStream in = new FileInputStream(src);
|
---|
751 | InputStream in = ClassLoader.getSystemResourceAsStream(src);
|
---|
752 | FileOutputStream out = new FileOutputStream(dest);
|
---|
753 |
|
---|
754 | // Transfer bytes from in to out
|
---|
755 | byte[] buf = new byte[1024];
|
---|
756 | int len;
|
---|
757 | try {
|
---|
758 | while ((len = in.read(buf)) > 0) {
|
---|
759 | out.write(buf, 0, len);
|
---|
760 | }
|
---|
761 | } catch(IOException e) {
|
---|
762 | throw e;
|
---|
763 | } finally { // just make sure the file streams are closed
|
---|
764 | in.close();
|
---|
765 | out.close();
|
---|
766 | dest = null;
|
---|
767 | in = null;
|
---|
768 | out = null;
|
---|
769 | }
|
---|
770 | }
|
---|
771 |
|
---|
772 | /** Reads from an xmlFile. If dtd_SystemId is not an empty String,
|
---|
773 | * then the XMLFile is not validated against the doctype statement it
|
---|
774 | * contains (the dtd_SystemId entity in the xmlFile is ignored) so
|
---|
775 | * that parsing still succeeds. However, if the DOM Structure returned
|
---|
776 | * by this method is written back out to a file, then make sure that
|
---|
777 | * this doctype is added back into the output file.
|
---|
778 | * @param xmlSource is either an xmlFile or xml InputStream (of a jarred
|
---|
779 | * file, for example) to be read into a DOM structure.
|
---|
780 | * @param dtd_SystemId - if specified, validation against the given DTD
|
---|
781 | * is ignored. The DOM structure returned will not contain the DOCTYPE
|
---|
782 | * entity with the given dtd file reference. If writing the DOM out to
|
---|
783 | * a file later on, then it is advised that this DOC_TYPE is added back
|
---|
784 | * in. If there is no dtd to be validated or whose validation is to be
|
---|
785 | * ignored, pass the empty string for dtd_SystemId.
|
---|
786 | * @param sourceFileName is the name of the (possibly internal) file
|
---|
787 | * that is to be read.
|
---|
788 | * @throws Exception if an error occurred during parsing.
|
---|
789 | * */
|
---|
790 | protected Document readXML(Object xmlSource, String dtd_SystemId,
|
---|
791 | String sourceFileName) throws Exception
|
---|
792 | {
|
---|
793 | Document doc = null;
|
---|
794 | try {
|
---|
795 | DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
---|
796 | factory.setValidating(false); // doesn't help
|
---|
797 | DocumentBuilder builder = factory.newDocumentBuilder();
|
---|
798 |
|
---|
799 | // If dtd is specified, then to ignore the dtd which is/may be
|
---|
800 | // pointing to the wrong location and will therefore invalidate the
|
---|
801 | // parsing effort, we ignore the DTD for the moment. We will add
|
---|
802 | // this back in later when we write the customised xmlFile back out.
|
---|
803 | // (e.g. in <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
|
---|
804 | // the template log4j.xml has log4j.dtd pointing to local filesystem
|
---|
805 | // and that won't work. In this example, log4j.dtd is the dtd_SystemId)
|
---|
806 | // See http://forum.java.sun.com/thread.jspa?threadID=284209&forumID=34
|
---|
807 | if(!dtd_SystemId.equals("")) {
|
---|
808 | builder.setEntityResolver(
|
---|
809 | new IgnoreDTDEntityResolver(dtd_SystemId));
|
---|
810 | }
|
---|
811 | if(xmlSource instanceof java.io.InputStream) {
|
---|
812 | doc = builder.parse((InputStream)xmlSource);
|
---|
813 | } else { // xml source is a file
|
---|
814 | doc = builder.parse((File)xmlSource);
|
---|
815 | }
|
---|
816 |
|
---|
817 | // normalize text representation, so that the saved-and-
|
---|
818 | // reloaded version is the same as the DOM constructed
|
---|
819 | doc.getDocumentElement().normalize();
|
---|
820 |
|
---|
821 | //System.out.println("xmlFile contents:\n"
|
---|
822 | //+ this.elementToFormattedString(doc.getDocumentElement(), ""));
|
---|
823 | } catch (javax.xml.parsers.ParserConfigurationException e) {
|
---|
824 | throw new Exception ("Error reading XML document "
|
---|
825 | + sourceFileName + " into DOM structure\n" + e);
|
---|
826 | } catch (IOException e) {
|
---|
827 | throw new Exception ("Error parsing XML document "
|
---|
828 | + sourceFileName + " into DOM structure\n" + e);
|
---|
829 | }
|
---|
830 | xmlSource = null;
|
---|
831 | return doc;
|
---|
832 | }
|
---|
833 |
|
---|
834 | /**
|
---|
835 | * Writes out a DOM structure to a file.
|
---|
836 | * @param doc is the DOM to be written out to a file
|
---|
837 | * @param xmlFile is the file to write the XML out to
|
---|
838 | * @param dtdToAddBackIn is "" if there's no special DTD to add
|
---|
839 | * back into the DOCTYPE. If not "", it specifies the dtd file to
|
---|
840 | * be added in the DOCTYPE of the XML output file.
|
---|
841 | */
|
---|
842 | protected void writeXML(Document doc, File xmlFile,
|
---|
843 | String dtdToAddBackIn) throws Exception
|
---|
844 | {
|
---|
845 | try {
|
---|
846 | OutputStream out = new FileOutputStream(xmlFile);
|
---|
847 | out.write(elementToFormattedString(
|
---|
848 | doc.getDocumentElement(), dtdToAddBackIn).getBytes());
|
---|
849 | out.close();
|
---|
850 | out = null;
|
---|
851 | xmlFile = null; // local reference not used anymore
|
---|
852 | } catch(Exception e){
|
---|
853 | throw new Exception("Exception when writing out XML to file "
|
---|
854 | + xmlFile.getAbsolutePath() + "\n" + e.getMessage());
|
---|
855 | }
|
---|
856 | }
|
---|
857 |
|
---|
858 | /** Given a DOM document, finds the first element where nodeName=tagName
|
---|
859 | * where one of the attributes has the name attrName and whose value
|
---|
860 | * contains attrValueContent. The <b>portion</b> of the attribute value
|
---|
861 | * that matches is then replaced by replacementContent.
|
---|
862 | * If onceOnly is true, the first replacement is made and the method
|
---|
863 | * returns. If false, all matching replacements are made.
|
---|
864 | * @param doc is the DOM Document object in which to search for
|
---|
865 | * the element to be replaced
|
---|
866 | * @param tagName is the name of the element to search for
|
---|
867 | * @param attrName is the name of the attribute of the element to search for
|
---|
868 | * @param attrValueContent is the portion of the attribute value that will
|
---|
869 | * be replaced by replacementContent.
|
---|
870 | * @param replacementContent is the replacement string that will overwrite
|
---|
871 | * the part of the attrName attribute's value that matched attrValueContent
|
---|
872 | * @param onceOnly - if true will look for the first match and perform the
|
---|
873 | * replacement once. If false, it will replace all matches found.
|
---|
874 | * @param wholeItem - if true, the entire string containing attrValueContent
|
---|
875 | * will be replaced by the string replacementContent. If false, only the
|
---|
876 | * attrValueContent portion of the original string will be replaced.
|
---|
877 | * @return true if any replacements have been made.
|
---|
878 | */
|
---|
879 | protected boolean replaceElementWithAttrValue(Document doc, String tagName,
|
---|
880 | String attrName, String attrValueContent, String replacementContent,
|
---|
881 | boolean onceOnly, boolean wholeItem)
|
---|
882 | {
|
---|
883 | boolean found = false;
|
---|
884 | //System.out.println("Searching for:"+tagName+" "+attrName+" "+attrValuePrefix);
|
---|
885 | // Also need to check documentElement (root) itself for a match:
|
---|
886 | NodeList elements = doc.getElementsByTagName(tagName);
|
---|
887 | for(int i = 0; i < elements.getLength(); i++) {
|
---|
888 | Element e = (Element)elements.item(i);
|
---|
889 | String oldVal = e.getAttribute(attrName);
|
---|
890 | if(oldVal.indexOf(attrValueContent) != -1) {
|
---|
891 | String newVal = (wholeItem) ? replacementContent
|
---|
892 | : oldVal.replace(attrValueContent, replacementContent);
|
---|
893 | e.setAttribute(attrName, newVal);
|
---|
894 | if(i == 0) { // print message for user information
|
---|
895 | System.out.println(
|
---|
896 | "\tUpdating: " + oldVal + " To: " + newVal);
|
---|
897 | found = true;
|
---|
898 | }
|
---|
899 | if(onceOnly) {
|
---|
900 | // finished match-and-replace, so
|
---|
901 | // get out of this loop and method
|
---|
902 | return found;
|
---|
903 | }
|
---|
904 | }
|
---|
905 | }
|
---|
906 | return found;
|
---|
907 | }
|
---|
908 |
|
---|
909 | /** Given a DOM document, finds the first element where nodeName=tagName
|
---|
910 | * and where the element's inner text contains the string contentValue.
|
---|
911 | * Once found, the <b>entire</b> textnode contents of the matching element
|
---|
912 | * is then replaced with the replacement string.
|
---|
913 | * @param doc is the DOM Document object in which to search for
|
---|
914 | * the element to be replaced
|
---|
915 | * @param tagName is the name of the element to search for
|
---|
916 | * @param contentValue is the portion of the textual content of the
|
---|
917 | * element that should match for the replacement to happen
|
---|
918 | * @param replacement is value that will overwrite the matching portion
|
---|
919 | * of the element's textual content (it will overwrite contentValue).
|
---|
920 | * @param onceOnly - if true will look for the first match and perform the
|
---|
921 | * replacement once. If false, it will replace all matches found.
|
---|
922 | * @param wholeItem - if true, the entire string containing attrValueContent
|
---|
923 | * will be replaced by the string replacementContent. If false, only the
|
---|
924 | * attrValueContent portion of the original string will be replaced.
|
---|
925 | * @return true if any replacements have been made.
|
---|
926 | */
|
---|
927 | protected boolean replaceElementWithValue(Document doc, String tagName,
|
---|
928 | String contentValue, String replacement, boolean onceOnly, boolean wholeItem)
|
---|
929 | {
|
---|
930 | boolean found = false;
|
---|
931 | // Also need to check documentElement (root) itself for a match:
|
---|
932 | NodeList elements = doc.getElementsByTagName(tagName);
|
---|
933 | for(int i = 0; i < elements.getLength(); i++) {
|
---|
934 | Element e = (Element)elements.item(i);
|
---|
935 | String textNodeContent = getValue(e);
|
---|
936 | if(textNodeContent.indexOf(contentValue) != -1) {
|
---|
937 | // overwrite the matching portion
|
---|
938 | String newVal = (wholeItem) ? replacement
|
---|
939 | : textNodeContent.replace(contentValue, replacement);
|
---|
940 | // Put it back into the text node of the element
|
---|
941 | e.setTextContent(newVal);
|
---|
942 | if(i == 0) { // print message for user information
|
---|
943 | System.out.println("\tUpdating: " + textNodeContent
|
---|
944 | + " To: " + newVal);
|
---|
945 | found = true;
|
---|
946 | }
|
---|
947 | // we're now finished if we only wanted to search
|
---|
948 | // for the first occurrence
|
---|
949 | if(onceOnly) {
|
---|
950 | return found;
|
---|
951 | }
|
---|
952 | }
|
---|
953 | }
|
---|
954 | return found;
|
---|
955 | }
|
---|
956 |
|
---|
957 | /** Extract the text from an element, if any.
|
---|
958 | * @return the text that's nested in an element's body or ""
|
---|
959 | * if there's none.
|
---|
960 | * @param e is the element whose value is to be extracted.
|
---|
961 | */
|
---|
962 | public static String getValue(Element e) {
|
---|
963 | Node child = e.getFirstChild();
|
---|
964 | return (child == null) ? "" : child.getNodeValue();
|
---|
965 | }
|
---|
966 |
|
---|
967 |
|
---|
968 | /** Given an Element, this will return its String representation properly
|
---|
969 | * indented for display. (The XML declaration will be added at the top
|
---|
970 | * since this method will be used here to write proper XML out to a file.)
|
---|
971 | * @return a string representation of e, formatted for display.
|
---|
972 | * @param e is the element to be converted to its string representation.
|
---|
973 | * @param dtd_SystemId (if not "") is any DOCTYPE with systemId that needs
|
---|
974 | * to be added back into the file. If "", then no new DOCTYPE entity is
|
---|
975 | * added into the DOM structure represented by Element e.
|
---|
976 | */
|
---|
977 | public static String elementToFormattedString(Element e, String dtd_SystemId)
|
---|
978 | throws Exception
|
---|
979 | {
|
---|
980 | DOMSource domSource = new DOMSource(e);
|
---|
981 | Transformer transformer = TransformerFactory.newInstance().newTransformer();
|
---|
982 | // Do not set transformer to OMIT_XML_DECLARATION! We're doing
|
---|
983 | // a straightforward copy here
|
---|
984 | transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
|
---|
985 | transformer.setOutputProperty(OutputKeys.INDENT, "yes");
|
---|
986 |
|
---|
987 | if(!dtd_SystemId.equals("")) {
|
---|
988 | // put the docType (systemID) back in:
|
---|
989 | transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "log4j.dtd");
|
---|
990 | }
|
---|
991 |
|
---|
992 | StringWriter sw = new StringWriter();
|
---|
993 | transformer.transform(domSource, new StreamResult(sw));
|
---|
994 | return sw.toString();
|
---|
995 | }
|
---|
996 |
|
---|
997 | //***************HELPER METHODS USED ONLY ONCE********************/
|
---|
998 | /**
|
---|
999 | * Moves the (fedoragsearch.war) war file from the given location
|
---|
1000 | * into FEDORA_HOME's tomcat folder (i.e. into CATALINA_HOME) and
|
---|
1001 | * unpacks it there. Unpacking is achieved by starting the fedora
|
---|
1002 | * server after the move. If a fedoragsearch is already unpacked
|
---|
1003 | * in CATALINA_HOME, this method will not move the given
|
---|
1004 | * fedoragsearch.war file.
|
---|
1005 | * This method does more than merely move fedoragsearch.war:
|
---|
1006 | * regardless of whether the war file exists and is moved or not,
|
---|
1007 | * the fedora server is first stopped and at the end it is started.
|
---|
1008 | * @param gsearchWarFile the fedoragsearch.war file to be moved and
|
---|
1009 | * unpacked.
|
---|
1010 | * @throws Exception if an unpacked fedoragsearch does not exist
|
---|
1011 | * in the CATALINA_HOME/webapps folder at the end.
|
---|
1012 | */
|
---|
1013 | protected void moveUnpackWarFile(File gsearchWarFile) throws Exception {
|
---|
1014 | final String stopFedora
|
---|
1015 | = gSearchProperties.getProperty("fedora.stop")+scriptExtension;
|
---|
1016 | final String startFedora
|
---|
1017 | = gSearchProperties.getProperty("fedora.start")+scriptExtension;
|
---|
1018 |
|
---|
1019 | // shut down fedora server
|
---|
1020 | //this.runProcess(new String[]{"cmd & " + stopFedora + " & exit"});
|
---|
1021 | this.runProcess(new String[]{stopFedora}, false);
|
---|
1022 |
|
---|
1023 | File dest = null;
|
---|
1024 | File webapps = new File(CATALINA_HOME,"webapps");
|
---|
1025 | // we don't want to overwrite any existing fedoraGSearch folder
|
---|
1026 | File unpackedFedoraGSearch = new File(webapps, FEDORAGSEARCH);
|
---|
1027 |
|
---|
1028 | if(!gsearchWarFile.exists()) {
|
---|
1029 | if(!unpackedFedoraGSearch.exists()) {
|
---|
1030 | // neither war file nor unpacked version exist
|
---|
1031 | throw new Exception(
|
---|
1032 | "Neither the war file " + gsearchWarFile.getAbsolutePath()
|
---|
1033 | + "\nnor " + unpackedFedoraGSearch.getAbsolutePath()
|
---|
1034 | + " exist. Cannot proceed.");
|
---|
1035 | } else { // only gsearchWarFile does not exist
|
---|
1036 | System.out.println("fedoragsearch.war file: "
|
---|
1037 | + gsearchWarFile + " does not exist!");
|
---|
1038 | }
|
---|
1039 | }
|
---|
1040 |
|
---|
1041 | if(unpackedFedoraGSearch.exists() && unpackedFedoraGSearch.isDirectory())
|
---|
1042 | {
|
---|
1043 | System.err.println(unpackedFedoraGSearch
|
---|
1044 | + " exists. Not overwriting with war file " + gsearchWarFile);
|
---|
1045 | } else {
|
---|
1046 | // perform the move: whatever the original war file was called,
|
---|
1047 | // make sure the destination file has the name fedoragsearch.war
|
---|
1048 | dest = new File(webapps, "fedoragsearch.war");
|
---|
1049 | System.out.println("Moving " + gsearchWarFile + "\nto " + dest);
|
---|
1050 | boolean success = gsearchWarFile.renameTo(dest);
|
---|
1051 | if(!success) {
|
---|
1052 | System.out.println("gsearchWarFile could not be moved."
|
---|
1053 | + " Trying an OS move command.");
|
---|
1054 | // happens on Linux, try moving it in a different way:
|
---|
1055 | this.runProcess(new String[] {"mv",
|
---|
1056 | gsearchWarFile.getAbsolutePath(),
|
---|
1057 | dest.getAbsolutePath()}, true);
|
---|
1058 | }
|
---|
1059 | }
|
---|
1060 |
|
---|
1061 | if(dest != null && !dest.exists()) {
|
---|
1062 | // don't check 'success', as it doesn't return true (fast enough)
|
---|
1063 | throw new Exception("Could not move " + gsearchWarFile
|
---|
1064 | + "\nto " + dest);
|
---|
1065 | }
|
---|
1066 | // Start the fedora server, and let it unpack fedoragsearch if
|
---|
1067 | // it has been freshly copied. Else restart the server all the same
|
---|
1068 | this.runProcess(new String[]{startFedora}, false);
|
---|
1069 | //this.runProcess(new String[]{"cmd & " + startFedora + " & exit"});
|
---|
1070 |
|
---|
1071 |
|
---|
1072 | // We'll wait until unpacking of fedoragsearch has finished,
|
---|
1073 | // otherwise installation fails. The way we check is by seeing
|
---|
1074 | // whether the fedoragsearch/WEB-INF/classes folder has been created.
|
---|
1075 | // If not, we continue waiting and output "." to the screen
|
---|
1076 | System.out.print("Waiting for fedoragsearch to finish unpacking...");
|
---|
1077 | waitForFedoraServer();
|
---|
1078 | }
|
---|
1079 |
|
---|
1080 | /** Makes changes to the fedora.fcfg file located inside FEDORA_HOME.
|
---|
1081 | * It changes the fedora.server.storage.DOManager to the GSearchDOManager
|
---|
1082 | * and sets the gSearchRESTURL to the specific fedora host and port values
|
---|
1083 | * specified for installation.
|
---|
1084 | * This method also checks that "greenstone" is in the list of PIDs that
|
---|
1085 | * Fedora recognises. If it's not in the list already, it is added in
|
---|
1086 | * there.
|
---|
1087 | */
|
---|
1088 | protected void customiseFedoraConfigFile() throws Exception
|
---|
1089 | {
|
---|
1090 | try{
|
---|
1091 | File fedoraConfigFile = new File(
|
---|
1092 | gSearchProperties.getProperty("fedora.config.dir"), "fedora.fcfg");
|
---|
1093 |
|
---|
1094 | Document doc = this.readXML(fedoraConfigFile, "", fedoraConfigFile.getAbsolutePath());
|
---|
1095 |
|
---|
1096 | // (1) Change class to "fedora.server.storage.GSearchDOManager" in
|
---|
1097 | // <module role="fedora.server.storage.DOManager" class="insert-here">
|
---|
1098 | Element module = null;
|
---|
1099 | NodeList nodes = doc.getElementsByTagName("module");
|
---|
1100 | for(int i = 0; i < nodes.getLength(); i++) {
|
---|
1101 | Element e = (Element)nodes.item(i);
|
---|
1102 | // getAttr will return "" if no match found
|
---|
1103 | if(e.getAttribute("role").equals("fedora.server.storage.DOManager")) {
|
---|
1104 | module = e;
|
---|
1105 | }
|
---|
1106 | }
|
---|
1107 | if(module == null) {
|
---|
1108 | // can't do anymore, because the rest is dependent on finding module
|
---|
1109 | System.err.println(
|
---|
1110 | "Unable to find fedora.server.storage.DOManager module element in "
|
---|
1111 | + fedoraConfigFile);
|
---|
1112 | return;
|
---|
1113 | }
|
---|
1114 | module.setAttribute("class", "fedora.server.storage.GSearchDOManager");
|
---|
1115 | nodes = null;
|
---|
1116 |
|
---|
1117 | // (2) Set the FedoraGSearch rest url inside the module element found:
|
---|
1118 | // <param name="gSearchRESTURL" value="http://?host:?port/fedoragsearch/rest">
|
---|
1119 | // And now that we are here and looking for params, might as well
|
---|
1120 | // ensure that "greenstone" is one of the PIDs that Fedora recognises.
|
---|
1121 | // Checking for:
|
---|
1122 | // <param name="retainPIDs" value="demo test changeme fedora-bdef fedora-bmech tutorial greenstone">
|
---|
1123 | nodes = module.getElementsByTagName("param");
|
---|
1124 | for(int i = 0; i < nodes.getLength(); i++) {
|
---|
1125 | Element e = (Element)nodes.item(i);
|
---|
1126 | // getAttr will return "" if no match found
|
---|
1127 | String nameAttr = e.getAttribute("name");
|
---|
1128 | if(nameAttr.equals("gSearchRESTURL")) {
|
---|
1129 | e.setAttribute("value",
|
---|
1130 | gSearchProperties.getProperty("gsearch.base")
|
---|
1131 | +File.separator+"rest"
|
---|
1132 | //"http://"+this.host+":"+this.port+"/fedoragsearch/rest");
|
---|
1133 | );
|
---|
1134 | } else if(nameAttr.equals("retainPIDs")) {
|
---|
1135 | String valAttr = e.getAttribute("value");
|
---|
1136 | // Check if greenstone not yet in list of pids
|
---|
1137 | if(valAttr.indexOf("greenstone") == -1) {
|
---|
1138 | // Need to append greenstone to the list of pids
|
---|
1139 | // don't forget to precede it by a space!
|
---|
1140 | valAttr = valAttr + " greenstone";
|
---|
1141 | // put the attribute back
|
---|
1142 | e.setAttribute("value", valAttr);
|
---|
1143 | } else {
|
---|
1144 | System.out.println("\"greenstone\" is already in"
|
---|
1145 | + " the list of fedora-recognised PIDs");
|
---|
1146 | }
|
---|
1147 | }
|
---|
1148 | }
|
---|
1149 |
|
---|
1150 | // Now we've updated the necessary Elements, need to write the
|
---|
1151 | // it back into the same file
|
---|
1152 | OutputStream out = new FileOutputStream(fedoraConfigFile);
|
---|
1153 | out.write(elementToFormattedString(
|
---|
1154 | doc.getDocumentElement(),"").getBytes());
|
---|
1155 | out.close();
|
---|
1156 | out = null;
|
---|
1157 | fedoraConfigFile = null;
|
---|
1158 | } catch(Exception e) {
|
---|
1159 | throw new Exception("Tried to parse "
|
---|
1160 | + gSearchProperties.getProperty("fedora.config.dir")
|
---|
1161 | + File.separator+"fedora.fcfg"
|
---|
1162 | + "\nand then modify it and write it out the same file."
|
---|
1163 | + " But an exception occurred:\n" + e.getMessage());
|
---|
1164 | }
|
---|
1165 | }
|
---|
1166 |
|
---|
1167 | /**
|
---|
1168 | * Creates the Lucene index directory in the right location inside
|
---|
1169 | * FEDORA_HOME into which FedoraGSearch will store the indexes for
|
---|
1170 | * the Greenstone contents in the Fedora repository.
|
---|
1171 | * If it already exists, the Lucene index directory is not created.
|
---|
1172 | * @throws Exception if the Lucene index directory cannot be created
|
---|
1173 | * in the appropriate location inside FEDORA_HOME
|
---|
1174 | */
|
---|
1175 | protected void createLuceneIndexDir() throws Exception {
|
---|
1176 | File luceneIndexesDir = new File(gSearchProperties.getProperty(
|
---|
1177 | "lucene.indexes.dir"), indexName);
|
---|
1178 | if(!luceneIndexesDir.exists()) {
|
---|
1179 | System.out.println("Creating directory for the Lucene index: "
|
---|
1180 | + luceneIndexesDir);
|
---|
1181 | if(!luceneIndexesDir.mkdirs()) {
|
---|
1182 | throw new Exception("Unable to create Lucene index dir: "
|
---|
1183 | + luceneIndexesDir);
|
---|
1184 | }
|
---|
1185 | } else {
|
---|
1186 | System.err.println("Lucene index directory " + luceneIndexesDir
|
---|
1187 | + " exists.\nNot creating it.");
|
---|
1188 | }
|
---|
1189 | }
|
---|
1190 |
|
---|
1191 | //******************STATIC METHODS USED BY MAIN**********************/
|
---|
1192 | /** Displays a dialog to get user input for
|
---|
1193 | * - fedora server host, port, username and password,
|
---|
1194 | * - the names for the fedora generic search index and repository
|
---|
1195 | * that are to be created, and
|
---|
1196 | * - for the location of fedoragenericsearch.war (the installer is
|
---|
1197 | * meant to work specifically with Muradora's fedoragenericsearch.war
|
---|
1198 | * since they have edited various property and xml files to make it
|
---|
1199 | * all easier).
|
---|
1200 | * The dialog displays the default values to the user.
|
---|
1201 | * @return a Properties map containing the values entered by the
|
---|
1202 | * user for the various initialisation parameters required by the
|
---|
1203 | * Fedora Generic Search Installer GSearchInstaller. */
|
---|
1204 | public static Properties showInputDialog()
|
---|
1205 | {
|
---|
1206 | final JTextField fileField = new JTextField(defaults.getProperty(PROP_FILE));
|
---|
1207 | JTextField hostField = new JTextField(defaults.getProperty(PROP_HOST));
|
---|
1208 | JTextField portField = new JTextField(defaults.getProperty(PROP_PORT));
|
---|
1209 | JTextField unameField = new JTextField(defaults.getProperty(PROP_UNAME));
|
---|
1210 | JTextField passwField = new JPasswordField(defaults.getProperty(PROP_PASSW));
|
---|
1211 | JTextField reposField = new JTextField(defaults.getProperty(PROP_REPOS));
|
---|
1212 | JTextField indexField = new JTextField(defaults.getProperty(PROP_INDEX));
|
---|
1213 |
|
---|
1214 | // Arrange the controls
|
---|
1215 | JPanel serverPanel = new JPanel(new GridLayout(4,2));
|
---|
1216 | serverPanel.setBorder(
|
---|
1217 | BorderFactory.createTitledBorder("Fedora server details"));
|
---|
1218 | serverPanel.add(new JLabel(PROP_HOST));
|
---|
1219 | serverPanel.add(hostField);
|
---|
1220 | serverPanel.add(new JLabel(PROP_PORT));
|
---|
1221 | serverPanel.add(portField);
|
---|
1222 | serverPanel.add(new JLabel(PROP_UNAME));
|
---|
1223 | serverPanel.add(unameField);
|
---|
1224 | serverPanel.add(new JLabel(PROP_PASSW));
|
---|
1225 | serverPanel.add(passwField);
|
---|
1226 |
|
---|
1227 | JPanel gSearchPanel = new JPanel(new GridLayout(2,2));
|
---|
1228 | gSearchPanel.setBorder(BorderFactory.createTitledBorder(
|
---|
1229 | "Customise Fedora Generic Search properties"));
|
---|
1230 | gSearchPanel.add(new JLabel(PROP_REPOS + " name"));
|
---|
1231 | gSearchPanel.add(reposField);
|
---|
1232 | gSearchPanel.add(new JLabel(PROP_INDEX + " name"));
|
---|
1233 | gSearchPanel.add(indexField);
|
---|
1234 |
|
---|
1235 | JButton browseButton = new JButton("Browse");
|
---|
1236 | JPanel filePanel = new JPanel(new FlowLayout());
|
---|
1237 | filePanel.setBorder(BorderFactory.createTitledBorder(
|
---|
1238 | "Locate the fedoragenericsearch.war file"));
|
---|
1239 | filePanel.add(new JLabel(PROP_FILE));
|
---|
1240 | filePanel.add(fileField);
|
---|
1241 | filePanel.add(browseButton);
|
---|
1242 |
|
---|
1243 | // Now we're going to handle click events on the browseButton:
|
---|
1244 | // a fileChooser dialog for opening files displays
|
---|
1245 | // First we set up a FileFilter for filtering only war files
|
---|
1246 | // FIXME: Do we allow all *.war files to be visible or only
|
---|
1247 | // fedoragsearch.war? Advantage: wrong war files can't be chosen;
|
---|
1248 | // disadvantage: if fedoragsearch.war was renamed it won't show up.
|
---|
1249 | final javax.swing.filechooser.FileFilter warFileFilter
|
---|
1250 | = new javax.swing.filechooser.FileFilter() {
|
---|
1251 | public boolean accept(File f) {
|
---|
1252 | if(f.isDirectory()) {
|
---|
1253 | return true;
|
---|
1254 | }
|
---|
1255 | // f.getName().equalsIgnoreCase("fedoragsearch.war")) {
|
---|
1256 | if(f.getName().endsWith(".war") &&
|
---|
1257 | f.getName().toLowerCase().contains("fedoragsearch"))
|
---|
1258 | {
|
---|
1259 | return true;
|
---|
1260 | } else {
|
---|
1261 | return false;
|
---|
1262 | }
|
---|
1263 | }
|
---|
1264 | public String getDescription() {
|
---|
1265 | return "fedora generic search *.war file";
|
---|
1266 | //return "Tomcat server *.war files";
|
---|
1267 | }
|
---|
1268 | };
|
---|
1269 | // Add the ActionListener to the browseButton to display the FileChooser
|
---|
1270 | browseButton.addActionListener(
|
---|
1271 | new java.awt.event.ActionListener() {
|
---|
1272 | public void actionPerformed(java.awt.event.ActionEvent e) {
|
---|
1273 | JFileChooser chooser = new JFileChooser();
|
---|
1274 | chooser.setFileFilter(warFileFilter);
|
---|
1275 | int returnVal = chooser.showOpenDialog(null);
|
---|
1276 |
|
---|
1277 | if (returnVal == JFileChooser.APPROVE_OPTION) {
|
---|
1278 | File file = chooser.getSelectedFile();
|
---|
1279 | fileField.setText(file.getAbsolutePath());
|
---|
1280 | } else { //CANCEL_OPTION or ERROR_OPTION
|
---|
1281 | fileField.setText(defaults.getProperty(PROP_FILE));
|
---|
1282 | }
|
---|
1283 | }
|
---|
1284 | }
|
---|
1285 | );
|
---|
1286 |
|
---|
1287 | // Display the dialog - we'll just use the usual confirmDialog
|
---|
1288 | // (the different panels are combined on top of each other)
|
---|
1289 | // Then we get automatic behaviour on OK and CANCEL
|
---|
1290 | int option = JOptionPane.showConfirmDialog(null,
|
---|
1291 | new Object[]{serverPanel, gSearchPanel, filePanel},
|
---|
1292 | "Fedora Generic Search Installer - uses Muradora's FGS work",
|
---|
1293 | JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
|
---|
1294 |
|
---|
1295 | // if ok was pressed, we return the values the user entered
|
---|
1296 | Properties inputs = new Properties();
|
---|
1297 | if (option == JOptionPane.OK_OPTION) {
|
---|
1298 | inputs.setProperty(PROP_UNAME, getSafeValue(unameField, PROP_UNAME));
|
---|
1299 | inputs.setProperty(PROP_PASSW, passwField.getText());
|
---|
1300 | inputs.setProperty(PROP_HOST, getSafeValue(hostField, PROP_HOST));
|
---|
1301 | inputs.setProperty(PROP_PORT, getSafeValue(portField, PROP_PORT));
|
---|
1302 | inputs.setProperty(PROP_REPOS, getSafeValue(reposField, PROP_REPOS));
|
---|
1303 | inputs.setProperty(PROP_INDEX, getSafeValue(indexField, PROP_HOST));
|
---|
1304 | inputs.setProperty(PROP_FILE, getSafeValue(fileField, PROP_FILE));
|
---|
1305 | } else { // Cancel option
|
---|
1306 | System.exit(0);
|
---|
1307 | }
|
---|
1308 | return inputs;
|
---|
1309 | }
|
---|
1310 |
|
---|
1311 | /** This method returns the value of the textfield for the given
|
---|
1312 | * GSearchInstaller initialiser property, if this is not the empty string.
|
---|
1313 | * If it is the empty string, the default value for this property is
|
---|
1314 | * returned.
|
---|
1315 | * @param field is the TextField whose value is being extracted
|
---|
1316 | * @param property is the GSearchInstaller property that the TextField
|
---|
1317 | * value maps to.
|
---|
1318 | * @return the contents of the textfield for the property or the defaults
|
---|
1319 | * value for the property if the textfield contained "".
|
---|
1320 | */
|
---|
1321 | protected static String getSafeValue(JTextField field, String property)
|
---|
1322 | {
|
---|
1323 | String value = field.getText();
|
---|
1324 | if(value.equals("")) {
|
---|
1325 | return defaults.getProperty(property, "");
|
---|
1326 | }
|
---|
1327 | return value;
|
---|
1328 | }
|
---|
1329 |
|
---|
1330 | /** @return a string specifying the requirements of this program. */
|
---|
1331 | public static String info() {
|
---|
1332 | StringBuffer info = new StringBuffer(GSearchInstaller.class.getSimpleName()
|
---|
1333 | + " is based on the installation instructions at\n");
|
---|
1334 | info.append("http://drama.ramp.org.au/cgi-bin/trac.cgi/wiki/InstallingFedoraGSearch");
|
---|
1335 | info.append("\n\nBefore running this program, you need to have Fedora installed");
|
---|
1336 | info.append("\nand the environment variables FEDORA_HOME and CATALINA_HOME set.\n");
|
---|
1337 | info.append("(These would have had to have been set when installing Fedora.)");
|
---|
1338 | info.append("\nRun with -help to see the command-line options.\n");
|
---|
1339 | return info.toString();
|
---|
1340 | }
|
---|
1341 |
|
---|
1342 | /** If the program is run from the command line and the user executed
|
---|
1343 | * it with -help or help, then this usage String is displayed.
|
---|
1344 | * @return String describing how to use this program when running it
|
---|
1345 | * from the command line. */
|
---|
1346 | public static String usage() {
|
---|
1347 | StringBuffer usage = new StringBuffer(info());
|
---|
1348 | String progName = GSearchInstaller.class.getSimpleName();
|
---|
1349 |
|
---|
1350 | usage.append("\nRun:\n");
|
---|
1351 | usage.append(progName + " -help");
|
---|
1352 | usage.append("\n\tTo see this usage message again.");
|
---|
1353 |
|
---|
1354 | usage.append("\n\n" + progName);
|
---|
1355 | usage.append("\n\tTo see a GUI dialog requesting input.");
|
---|
1356 |
|
---|
1357 | usage.append("\n\n" + progName + " [options]");
|
---|
1358 | usage.append("\n\tFor command-line use. (For all unspecified options--except the");
|
---|
1359 | usage.append("\n\tfedora server password--default values will be used.)");
|
---|
1360 | usage.append("\n\n\tOptions:");
|
---|
1361 |
|
---|
1362 | usage.append("\n\t-file <fedoragsearch.war file>");
|
---|
1363 | usage.append("\n\t\tThe full path to the fedoragsearch.war file (default: fedoragsearch.war)");
|
---|
1364 | usage.append("\n\t\tThis file is ignored if folder CATALINA_HOME/webapps/fedoragsearch exists.");
|
---|
1365 | usage.append("\n\t\thttp://drama.ramp.org.au/software/fedoragsearch.war has the Muradora version.");
|
---|
1366 |
|
---|
1367 | usage.append("\n\t-host <fedora server host>");
|
---|
1368 | usage.append("\n\t\tThe host at which the fedora server is listening (default: localhost)");
|
---|
1369 | usage.append("\n\t-port <fedora server port>");
|
---|
1370 | usage.append("\n\t\tThe port on which the fedora server is listening (default: 8080)");
|
---|
1371 |
|
---|
1372 | usage.append("\n\t-username <fedora server username>");
|
---|
1373 | usage.append("\n\t\tThe username for accessing the fedora server (default: fedoraAdmin)");
|
---|
1374 | usage.append("\n\t-password <fedora server password>");
|
---|
1375 | usage.append("\n\t\tThe password for accessing the fedora server (default: '')");
|
---|
1376 |
|
---|
1377 | usage.append("\n\t-repository <repository name>");
|
---|
1378 | usage.append("\n\t\tA name for the repository that is to be indexed (default: Fedora)");
|
---|
1379 | usage.append("\n\t-index <index name>");
|
---|
1380 | usage.append("\n\t\tA name for the repository index to be created (default: FedoraIndex)\n");
|
---|
1381 |
|
---|
1382 | return usage.toString();
|
---|
1383 | }
|
---|
1384 |
|
---|
1385 | /** Called to process multiple command line arguments where these
|
---|
1386 | * arguments are GSearchInstaller constructor options followed by
|
---|
1387 | * their values.
|
---|
1388 | * @param args are the command-line arguments received by main
|
---|
1389 | * which consist of one or more multiple "-option value" pairs.
|
---|
1390 | * @return a Properties map containing (option, value) pairs
|
---|
1391 | * that will be used by GSearchInstaller to install Muradora's
|
---|
1392 | * Fedora Generic Search. Empty strings for recognised options
|
---|
1393 | * are replaced by defaults.
|
---|
1394 | * */
|
---|
1395 | public static Properties parseInstallationArgs(String[] args) {
|
---|
1396 | Properties inputs = new Properties();
|
---|
1397 | // add pairs of arguments as Property(option, value) pairs
|
---|
1398 | // i+=2: processed two arguments in one go (the option and value)
|
---|
1399 | for(int i = 1; i < args.length; i+=2) {
|
---|
1400 | if(args[i-1].startsWith("-")) {
|
---|
1401 | // remove any starting hypen from the options
|
---|
1402 | args[i-1] = args[i-1].substring(1);
|
---|
1403 | } // else the option didn't start with a hyphen.
|
---|
1404 |
|
---|
1405 | // If the values are empty strings, use default for
|
---|
1406 | // that option if it exists (if it does not exist, it
|
---|
1407 | // will be ignored by GSearchInstaller anyway).
|
---|
1408 | if(args[i].equals("")) {
|
---|
1409 | args[i] = defaults.getProperty(args[i-1], "");
|
---|
1410 | }
|
---|
1411 | // add the (option, value) pair
|
---|
1412 | inputs.setProperty(args[i-1], args[i]);
|
---|
1413 | }
|
---|
1414 |
|
---|
1415 | // display any user provided properties
|
---|
1416 | Set entries = inputs.entrySet();
|
---|
1417 | Iterator i = entries.iterator();
|
---|
1418 | while(i.hasNext()) {
|
---|
1419 | Map.Entry entry = (Map.Entry)i.next();
|
---|
1420 | System.out.print("\tkey: " + entry.getKey() + "\t value: ");
|
---|
1421 | if(entry.getKey().equals(PROP_PASSW)) {
|
---|
1422 | String value = (String)entry.getValue();
|
---|
1423 | for(int j = 0; j < value.length(); j++) {
|
---|
1424 | System.out.print("*");
|
---|
1425 | }
|
---|
1426 | System.out.println();
|
---|
1427 | } else {
|
---|
1428 | System.out.println(entry.getValue());
|
---|
1429 | }
|
---|
1430 | }
|
---|
1431 |
|
---|
1432 | return inputs;
|
---|
1433 | }
|
---|
1434 |
|
---|
1435 |
|
---|
1436 | /**
|
---|
1437 | * The main method creates a GSearchInstaller to install Fedora Generic
|
---|
1438 | * Search from a (Muradora) fedoragsearch.war file.
|
---|
1439 | * The program can be run in one of two ways:
|
---|
1440 | * - with no arguments: a dialog is displayed requesting inputs for the
|
---|
1441 | * parameters used by the GSearchInstaller initialisation.
|
---|
1442 | * - with arguments for command-line invocation. (Run with -help or help
|
---|
1443 | * to find out what parameter options are there.)
|
---|
1444 | */
|
---|
1445 | public static void main(String[] args) {
|
---|
1446 | GSearchInstaller installer = null;
|
---|
1447 | try {
|
---|
1448 |
|
---|
1449 | Properties inputs = null;
|
---|
1450 | if(args.length < 1) { // 0 args
|
---|
1451 | inputs = GSearchInstaller.showInputDialog();
|
---|
1452 | } else { // one or more arguments
|
---|
1453 | if(args[0].equalsIgnoreCase("-help")
|
---|
1454 | || args[0].equalsIgnoreCase("help"))
|
---|
1455 | {
|
---|
1456 | System.out.println(GSearchInstaller.usage());
|
---|
1457 | System.exit(1); // help message exits with 1
|
---|
1458 | }
|
---|
1459 | else // process the multiple arguments
|
---|
1460 | {
|
---|
1461 | inputs = GSearchInstaller.parseInstallationArgs(args);
|
---|
1462 | }
|
---|
1463 | }
|
---|
1464 | // Now we have the input Properties and can instantiate the
|
---|
1465 | // GSearchInstaller (if "help" option, then it would have exited)
|
---|
1466 | installer = new GSearchInstaller(inputs);
|
---|
1467 | // try installing
|
---|
1468 | installer.install();
|
---|
1469 | } catch(Exception e) {
|
---|
1470 | System.out.println(e.getMessage());
|
---|
1471 | e.printStackTrace();
|
---|
1472 | System.out.println("\n" + info());
|
---|
1473 | // -1 exit value means an exception occurred during
|
---|
1474 | // Fedora Generic Search Installation
|
---|
1475 | System.exit(-1);
|
---|
1476 | }
|
---|
1477 |
|
---|
1478 | // No exception so far, so now we can index the repository contents.
|
---|
1479 | try {
|
---|
1480 | installer.indexGreenstoneContents(true);// empty existing index first
|
---|
1481 | } catch(Exception e) {
|
---|
1482 | System.out.println(e.getMessage());
|
---|
1483 | e.printStackTrace();
|
---|
1484 | System.out.println("\n" + info());
|
---|
1485 | // Exit with -2 if exception during updateIndex
|
---|
1486 | System.exit(-2);
|
---|
1487 | }
|
---|
1488 |
|
---|
1489 | // If we're here, then we finished with no exceptions
|
---|
1490 | System.out.println("Installation and indexing completed.");
|
---|
1491 | System.exit(0);
|
---|
1492 | }
|
---|
1493 | }
|
---|