source: main/trunk/gli/src/org/greenstone/gatherer/util/Utility.java@ 33777

Last change on this file since 33777 was 33777, checked in by ak19, 4 years ago

Forgot to document a link, with sample code to use nativecall jar file to get Windows short file names, may be helpful in future, though the work towards it on Friday had led to nowhere and I had to opt for a different solution from online in the end, one that used a DOS process to work out the windows short file name.

  • Property svn:keywords set to Author Date Id Revision
File size: 28.9 KB
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 * <BR><BR>
9 *
10 * Author: John Thompson, Greenstone Digital Library, University of Waikato
11 *
12 * <BR><BR>
13 *
14 * Copyright (C) 1999 New Zealand Digital Library Project
15 *
16 * <BR><BR>
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * <BR><BR>
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * <BR><BR>
31 *
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 *########################################################################
36 */
37
38package org.greenstone.gatherer.util;
39
40
41// Don't even think about adding import java.awt.* here!
42// The functions in this class should not use any graphical classes. Put your function somewhere else buster!
43import java.io.*;
44import java.net.*;
45import java.util.*;
46// Don't even think about adding import javax.swing.* here!
47// The functions in this class should not use any graphical classes. Put your function somewhere else buster!
48import org.greenstone.gatherer.Dictionary;
49// Don't even think about adding import org.greenstone.gatherer.Gatherer in here!
50// The functions in this class should be independent of the Gatherer class. Put your function somewhere else buster!
51import org.greenstone.gatherer.util.SafeProcess; // for the closeResource() static method
52
53/** To provide a library of common methods, in a static context, for use in the Gatherer.
54 * @author John Thompson, Greenstone Digital Library, University of Waikato
55 * @version 2.3b
56 */
57public class Utility
58{
59 /** Definition of an important directory name, in this case the file the collection configuration is expect to be in. */
60 static final public String CONFIG_FILE = "etc" + File.separator + "collect.cfg";
61 static final public String CONFIG_GS3_FILE = "etc" + File.separator + "collectionConfig.xml";
62 static final public String COLLECT_CFG = "collect.cfg";
63 static final public String COLLECT_BAK = "collect.bak";
64 static final public String COLLECTION_CONFIG_XML = "collectionConfig.xml";
65 static final public String COLLECTION_CONFIG_BAK = "collectionConfig.bak";
66 static final public String GS3MODE_ARGUMENT = "-gs3mode";
67 static final public String BUILD_CFG = "build.cfg";
68 static final public String BUILD_CONFIG_XML = "buildConfig.xml";
69
70 /** The default name of the perl executable under unix. */
71 static final public String PERL_EXECUTABLE_UNIX = "perl";
72 /** The default name of the perl executable under windows. */
73 static final public String PERL_EXECUTABLE_WINDOWS = "Perl.exe";
74
75 /** Platform independent NEWLINE character */
76 public static final String NEWLINE;
77
78 // NEWLINE related code copied across from GS3 src code
79 // Before Java 7, no System.lineSeparator() or System.getProperty("line.separator")
80 // And on local linux, am compiling with JDK 6, so need this.
81 // http://stackoverflow.com/questions/207947/how-do-i-get-a-platform-dependent-new-line-character
82 // http://stackoverflow.com/questions/2591083/getting-java-version-at-runtime
83 // https://www.tutorialspoint.com/java/lang/package_getspecificationversion.htm
84 // https://docs.oracle.com/javase/tutorial/essential/environment/sysprop.html
85 // Can initialise static final vars on declaration or in static initialisation code block
86 // http://stackoverflow.com/questions/2339932/java-can-final-variables-be-initialized-in-static-initialization-block
87 // Initialise object member final vars on declaration or in constructors
88 static {
89 double java_version = Double.parseDouble(System.getProperty("java.specification.version"));
90 if(java_version >= 1.7) {
91 NEWLINE = System.getProperty("line.separator");
92 } else {
93 NEWLINE = isWindows() ? "\r\n" : "\n";
94 }
95 }
96
97 // Copied from GS3 main java code at GSDL3SRCHOME\src\java\org\greenstone/util\Misc.java
98 // Debugging function to print a string's non-basic chars in hex, so stringToHex on all non-basic and non-printable ASCII
99 // Dr Bainbridge said that printing anything with charCode over 128 in hex is okay, but I'd already made extra allowances for non-printable ASCII
100 // Based on https://stackoverflow.com/questions/923863/converting-a-string-to-hexadecimal-in-java
101 public static String debugUnicodeString(String str) {
102 String result = "";
103 for(int i = 0; i < str.length(); i++) {
104 int charCode = str.codePointAt(i); // unicode codepoint / ASCII code
105
106 // ASCII table: https://cdn.sparkfun.com/assets/home_page_posts/2/1/2/1/ascii_table_black.png
107 // If the unicode character code pt is less than the ASCII code for space and greater than for tilda, let's display the char in hex (x0000 format)
108 if((charCode >= 20 && charCode <= 126) || charCode == 9 || charCode == 10 || charCode == 13) { // space, tilda, TAB, LF, CR are printable, leave them in for XML element printing
109 result += str.charAt(i);
110 } else {
111 result += "x{" + String.format("%04x", charCode) + "}"; // looks like: x{4-char-codepoint}
112 }
113 }
114
115 return result;
116 }
117
118 /**
119 * returns the short filename (8.3) for a file in Windows
120 *
121 * @param longFileName - must be the full path to an actual existing file
122 * @return a string with the short filename, or null if an error occurred or the
123 * file does not exist.
124 */
125 public static String getWindowsShortFileName(String longFileName) throws Exception {
126 if(!Utility.isWindows()) {
127 return longFileName;
128 } else {
129 //return WindowsNativeFunctions.getEightPointThree(longFileName);
130 return getMSDOSName(longFileName);
131 }
132 }
133
134 /*
135 * The means of getting a Windows Short FileName described at
136 * http://dolf.trieschnigg.nl/eightpointthree/eightpointthree.html looked ideal
137 * as it uses the non-JNI NativeCall jar file with imports of com.eaio.nativecall.*
138 * However, after trying this solution and making all the changes necessary for it,
139 * I wasn't able to use it after all, because when I finally could run it, the NativeCall.dll
140 * included in the jar file was of 32 bit and didn't match my 64 bit Windows OS.
141 * I tried the newer jar NativeCal.jar file and it wasn't compatible with the sample code
142 * and things wouldn't compile. In the end, I opted for plan B below, as it at least works.
143 */
144 /**
145 * getMSDOSName() and its helper function getAbsolutePath(fileName)
146 * are from https://stackoverflow.com/questions/18893284/how-to-get-short-filenames-in-windows-using-java
147 * getMSDOSName() modified to use our SafeProcess class.
148 *
149 * @param fileName - the regular fileName to be converted. Must be the full path to an actual existing file
150 * @return Windows shortfile name for the fileName parameter given.
151 */
152 public static String getMSDOSName(String fileName)
153 throws IOException, InterruptedException {
154
155 String path = getAbsolutePath(fileName);
156
157 SafeProcess process = new SafeProcess("cmd /c for %I in (\"" + path + "\") do @echo %~fsI");
158 int returnVal = process.runProcess();
159 if(returnVal != 0) {
160 return null;
161 }
162
163 String data = process.getStdOutput();
164 if(data == null) {
165 return null;
166 }
167 else return data.replaceAll("\\r\\n", "");
168 }
169 public static String getAbsolutePath(String fileName)
170 throws IOException {
171 File file = new File(fileName);
172 String path = file.getAbsolutePath();
173
174 if (file.exists() == false)
175 file = new File(path);
176
177 path = file.getCanonicalPath();
178
179 if (file.isDirectory() && (path.endsWith(File.separator) == false))
180 path += File.separator;
181
182 return path;
183 }
184
185 /**
186 * Handy function to display the list of calling functions by
187 * printing out the stack trace even when you don't have an exception
188 */
189 static public void printStackTrace() {
190 // https://stackoverflow.com/questions/1069066/get-current-stack-trace-in-java
191
192 //Thread.dumpStack(); // looks too much like an exception, though the newlines separating each function call is handy
193 //new Exception().printStackTrace(); // outputs in the format of an exception too
194 //System.err.println("\n@@@@ stacktrace:\n" + Arrays.toString(Thread.currentThread().getStackTrace()) + "\n"); // outputs all in one line
195
196 System.err.println("\n@@@@ stacktrace:");
197 StackTraceElement[] els = new Throwable().getStackTrace(); // starts at index 1, which is this function
198 //StackTraceElement[] els = Thread.currentThread().getStackTrace(); starts at index 0, "java.lang.Thread.getStackTrace()"
199 for(StackTraceElement ste : els) {
200 System.err.println(" " + ste);
201 }
202 }
203
204 /**
205 * Handy function to display the parent of the calling function
206 * (the function that called the function that called printCaller())
207 */
208 static public void printCaller() {
209 //int parent = 1;
210 // this function printCaller() itself adds another layer on the callstack since
211 // it calls the overloaded method, so need to add 1 more to parent
212 //printCaller(parent++);
213
214 StackTraceElement[] callstack = Thread.currentThread().getStackTrace();
215 StackTraceElement requestor = callstack[2]; // the calling function, the function that called this one
216 if(callstack.length > 3) {
217 StackTraceElement caller_requested = callstack[3]; // the function requested
218 System.err.println("\n@@@ Function " + requestor + " called by:\n "
219 + caller_requested + " at 1 ancestors back\n");
220 } else {
221 StackTraceElement caller_requested = callstack[callstack.length-1]; // the function requested
222 System.err.println("\n@@@ Don't have callers beyond requestor function " + requestor + "\n");
223 }
224 }
225
226 /**
227 * Handy function to display the nth ancestor of the calling function
228 * where ancestor=0 would be the calling function itself
229 */
230 static public void printCaller(int ancestor) {
231 // https://stackoverflow.com/questions/1069066/get-current-stack-trace-in-java
232
233 // Thread.currentThread().getStackTrace() starts at index 0: "java.lang.Thread.getStackTrace()"
234 // index 1 will be this method (printCaller) and index 2 will be the calling function itself who wants
235 // to know who called it. So need to at least start at index 3 to get informative caller information
236
237 StackTraceElement[] callstack = Thread.currentThread().getStackTrace();
238 StackTraceElement requestor = callstack[2]; // the calling function, the function that called this one
239 if(callstack.length > (ancestor+3)) {
240 StackTraceElement caller_requested = callstack[ancestor+3]; // the function requested
241 System.err.println("\n@@@ Function " + requestor + " called by:\n "
242 + caller_requested + " at " + ancestor + " ancestors back\n");
243 } else {
244 StackTraceElement caller_requested = callstack[callstack.length-1]; // the function requested
245 System.err.println("\n@@@ Don't have " + ancestor + " ancestor callers. Function " + requestor + " called by:\n "
246 + caller_requested + " at max " + (callstack.length-1) + " ancestors back\n");
247 }
248 }
249
250 /**
251 * Reads in a text file and returns the contents as a String
252 */
253 static public String readFile(File file) {
254 BufferedReader fin = null;
255 StringBuffer contents = new StringBuffer();
256
257 try {
258 fin = new BufferedReader(new FileReader(file));
259 String line = null;
260 while((line = fin.readLine()) != null) {
261 contents.append(line);
262 contents.append("\n");
263 }
264 } catch(IOException e) {
265 System.err.println("*** Could not read in file: " + file.toString());
266 System.err.println("*** Exception occurred: " + e.getMessage());
267 } finally {
268 SafeProcess.closeResource(fin);
269 }
270
271 return contents.toString();
272 }
273
274 /**
275 * Delete a file or directory
276 * @param file The <strong>File</strong> you want to delete.
277 * @return A <i>boolean</i> which is <i>true</i> if the file specified was successfully deleted, <i>false</i> otherwise.
278 */
279 static public boolean delete(File file)
280 {
281 // Nothing to do if it doesn't exist
282 if (!file.exists()) {
283 return true;
284 }
285
286 return deleteInternal(file);
287 }
288
289
290 /** Convenience function. */
291 static public boolean delete(String filename)
292 {
293 return delete(new File(filename));
294 }
295
296
297 /** In Java you have to make sure a directory is empty before you delete it, so recursively delete. */
298 static private boolean deleteInternal(File file)
299 {
300 // If file is a directory, we have to recursively delete its contents first
301 if (file.isDirectory()) {
302 File files[] = file.listFiles();
303 for (int i = 0; i < files.length; i++) {
304 if (deleteInternal(files[i]) == false) {
305 System.err.println("Error: Could not delete folder " + file);
306 return false;
307 }
308 }
309 }
310
311 // Delete file
312 if (file.delete() == false) {
313 System.err.println("Error: Could not delete file " + file);
314 return false;
315 }
316
317 return true;
318 }
319
320
321 /** Convert a long, detailing the length of a file in bytes, into a nice human readable string using b, kb, Mb and Gb. */
322 static final public String BYTE_SUFFIX = " b";
323 static final public long GIGABYTE = 1024000000l;
324 static final public String GIGABYTE_SUFFIX = " Gb";
325 static final public long KILOBYTE = 1024l;
326 static final public String KILOBYTE_SUFFIX = " kb";
327 static final public long MEGABYTE = 1024000l;
328 static final public String MEGABYTE_SUFFIX = " Mb";
329 static final public String formatFileLength(long length) {
330 StringBuffer result = new StringBuffer("");
331 float number = 0f;
332 String suffix = null;
333 // Determine the floating point number and the suffix (radix) used.
334 if(length >= GIGABYTE) {
335 number = (float) length / (float) GIGABYTE;
336 suffix = GIGABYTE_SUFFIX;
337 }
338 else if(length >= MEGABYTE) {
339 number = (float) length / (float) MEGABYTE;
340 suffix = MEGABYTE_SUFFIX;
341 }
342 else if(length >= KILOBYTE) {
343 number = (float) length / (float) KILOBYTE;
344 suffix = KILOBYTE_SUFFIX;
345 }
346 else {
347 // Don't need to do anything fancy if the file is smaller than a kilobyte
348 return length + BYTE_SUFFIX;
349 }
350 // Create the formatted string remembering to round the number to 2.d.p. To do this copy everything in the number string from the start to the first occurance of '.' then copy two more digits. Finally search for and print anything that appears after (and including) the optional 'E' delimter.
351 String number_str = Float.toString(number);
352 char number_char[] = number_str.toCharArray();
353 int pos = 0;
354 // Print the characters up to the '.'
355 while(number_char != null && pos < number_char.length && number_char[pos] != '.') {
356 result.append(number_char[pos]);
357 pos++;
358 }
359 if(pos < number_char.length) {
360 // Print the '.' and at most two characters after it
361 result.append(number_char[pos]);
362 pos++;
363 for(int i = 0; i < 2 && pos < number_char.length; i++, pos++) {
364 result.append(number_char[pos]);
365 }
366 // Search through the remaining string for 'E'
367 while(pos < number_char.length && number_char[pos] != 'E') {
368 pos++;
369 }
370 // If we still have string then we found an E. Copy the remaining string.
371 while(pos < number_char.length) {
372 result.append(number_char[pos]);
373 pos++;
374 }
375 }
376 // Add suffix
377 result.append(suffix);
378 // Done
379 return result.toString();
380 }
381
382 /** This method formats a given string, using HTML markup, so its width does not exceed the given width and its appearance if justified.
383 * @param text The <strong>String</strong> requiring formatting.
384 * @param width The maximum width per line as an <i>int</i>.
385 * @return A <strong>String</strong> formatted so as to have no line longer than the specified width.
386 * TODO Currently HTML formatting tags are simply removed from the text, as the effects of spreading HTML tags over a break are undetermined. To solve this we need to associate tags with a certain text token so if it gets broken on to the next line the tags go with it, or if the tags cover a sequence of words that are broken we need to close then reopen the tags. However all this is a major task and well beyond anything I have time to 'muck-round' on.
387 */
388 static public String formatHTMLWidth(String text, int width) {
389 if(text == null) {
390 return "Error";
391 }
392 HTMLStringTokenizer html = new HTMLStringTokenizer(text);
393 int current_width = 0;
394 int threshold = width / 2;
395 Stack lines = new Stack();
396 String line = "";
397 while(html.hasMoreTokens()) {
398 String token = html.nextToken();
399 while(token != null) {
400 if(html.isTag()) {
401 // Insert smart HTML tag code here.
402 token = null;
403 }
404 else {
405 // If the token is bigger than two thirds width, before we've even started break it down.
406 if(current_width + 1 + token.length() > width && token.length() > threshold) {
407 if(width == current_width) {
408 lines.push(line);
409 line = token;
410 current_width = token.length();
411 }
412 else {
413 String prefix = token.substring(0, width - 1 - current_width);
414 token = token.substring(prefix.length());
415 if(current_width == 0) {
416 line = line + prefix;
417 }
418 else {
419 line = line + " " + prefix;
420 }
421 lines.push(line);
422 line = "";
423 current_width = 0;
424 }
425 }
426 // If adding the next token would push us over the maximum line width.
427 else if(current_width + 1 + token.length() > width) {
428 lines.push(line);
429 line = token;
430 current_width = token.length();
431 token = null;
432 }
433 // Otherwise we should be able to just add the token, give or take.
434 else {
435 if(current_width == 0) {
436 line = line + token;
437 current_width = token.length();
438 }
439 else {
440 // Special case for standard punctuation which may exist after a tag like so:
441 // My name is <scratchy>Slim Shady</scratchy>. <-- Annoying punctuation.
442 if(token.equals(".") || token.equals(",") || token.equals("!") || token.equals("?")) {
443 line = line + token;
444 current_width = current_width + 1;
445 }
446 else {
447 line = line + " " + token;
448 current_width = current_width + 1 + token.length();
449 }
450 }
451 token = null;
452 }
453 }
454 }
455 }
456 String result = line;
457 while(!lines.empty()) {
458 result = (String)lines.pop() + "<BR>" + result;
459 }
460 // Replace ' ' with "&nbsp;"
461 boolean tag = false;
462 int pos = 0;
463 while(pos < result.length()) {
464 if(result.charAt(pos) == '<') {
465 tag = true;
466 }
467 else if(result.charAt(pos) == '>') {
468 tag = false;
469 }
470 else if(result.charAt(pos) == ' ' && !tag) {
471 String prefix = result.substring(0, pos);
472 String suffix = result.substring(pos + 1);
473 result = prefix + "&nbsp;" + suffix;
474 }
475 pos++;
476 }
477 result = "<HTML>" + result + "</HTML>";
478 return result;
479 }
480
481
482 static public String getDateString() {
483 Calendar current = Calendar.getInstance();
484 String day_name = null;
485 switch(current.get(Calendar.DAY_OF_WEEK)) {
486 case Calendar.MONDAY: day_name = "Dates.Mon"; break;
487 case Calendar.TUESDAY: day_name = "Dates.Tue"; break;
488 case Calendar.WEDNESDAY: day_name = "Dates.Wed"; break;
489 case Calendar.THURSDAY: day_name = "Dates.Thu"; break;
490 case Calendar.FRIDAY: day_name = "Dates.Fri"; break;
491 case Calendar.SATURDAY: day_name = "Dates.Sat"; break;
492 case Calendar.SUNDAY: day_name = "Dates.Sun"; break;
493 default: day_name = "";
494 }
495 String month_name = null;
496 switch(current.get(Calendar.MONTH)) {
497 case Calendar.JANUARY: month_name = "Dates.Jan"; break;
498 case Calendar.FEBRUARY: month_name = "Dates.Feb"; break;
499 case Calendar.MARCH: month_name = "Dates.Mar"; break;
500 case Calendar.APRIL: month_name = "Dates.Apr"; break;
501 case Calendar.MAY: month_name = "Dates.May"; break;
502 case Calendar.JUNE: month_name = "Dates.Jun"; break;
503 case Calendar.JULY: month_name = "Dates.Jul"; break;
504 case Calendar.AUGUST: month_name = "Dates.Aug"; break;
505 case Calendar.SEPTEMBER: month_name = "Dates.Sep"; break;
506 case Calendar.OCTOBER: month_name = "Dates.Oct"; break;
507 case Calendar.NOVEMBER: month_name = "Dates.Nov"; break;
508 case Calendar.DECEMBER: month_name = "Dates.Dec"; break;
509 default: month_name = "";
510 }
511 int day = current.get(Calendar.DAY_OF_MONTH);
512 int hour = current.get(Calendar.HOUR_OF_DAY);
513 int minute = current.get(Calendar.MINUTE);
514 int second = current.get(Calendar.SECOND);
515 int year = current.get(Calendar.YEAR);
516
517 return Dictionary.get(day_name) + " " + Dictionary.get(month_name) + " " + day + " " + year + " " + Utility.pad(String.valueOf(hour), 2, '0', true) + ":" + Utility.pad(String.valueOf(minute), 2, '0', true) + ":" + Utility.pad(String.valueOf(second), 2, '0', true);
518 }
519
520
521 /** Determine this machines name.
522 * @return The name as a <strong>String</strong>.
523 */
524 static public String getMachineName() {
525 try {
526 return InetAddress.getLocalHost().getHostName();
527 }
528 catch(UnknownHostException ex) {
529 }
530 return "Unknown Machine";
531 }
532
533
534 static public String getSitesDir(String gsdl3_path) {
535 return gsdl3_path + "sites" + File.separator;
536
537 }
538
539 /** @return the OSdir foldername: windows, linux or darwin */
540 public static String getOSdirName() {
541 if(Utility.isWindows()) {
542 return "windows";
543 }
544 if(Utility.isMac()) {
545 return "darwin";
546 }
547 return "linux"; // else assume it's a linux machine, OSdirname = linux
548 }
549
550
551 /** Method to determine if the host system is MacOS based.
552 * @return a boolean which is true if the platform is MacOS, false otherwise
553 */
554 public static boolean isMac() {
555 Properties props = System.getProperties();
556 String os_name = props.getProperty("os.name","");
557 if(os_name.startsWith("Mac OS")) {
558 return true;
559 }
560 return false;
561 }
562
563
564 /** Method to determine if the host system is Microsoft Windows based.
565 * @return A <i>boolean</i> which is <i>true</i> if the platform is Windows, <i>false</i> otherwise.
566 */
567 public static boolean isWindows() {
568 Properties props = System.getProperties();
569 String os_name = props.getProperty("os.name","");
570 if(os_name.startsWith("Windows")) {
571 return true;
572 }
573 return false;
574 }
575
576 public static boolean isWindows9x() {
577 Properties props = System.getProperties();
578 String os_name = props.getProperty("os.name","");
579 if(os_name.startsWith("Windows") && os_name.indexOf("9") != -1) {
580 return true;
581 }
582 return false;
583 }
584 /** Takes a string and a desired length and pads out the string to the length by adding spaces to the left.
585 * @param str The target <strong>String</strong> that needs to be padded.
586 * @param length The desired length of the string as an <i>int</i>.
587 * @return A <strong>String</strong> made from appending space characters with the string until it has a length equal to length.
588 */
589 static private String pad(String str_raw, int length, char fill, boolean end) {
590 StringBuffer str = new StringBuffer(str_raw);
591 while(str.length() < length) {
592 if(end) {
593 str.insert(0, fill);
594 }
595 else {
596 str.append(fill);
597 }
598 }
599 return str.toString();
600 }
601
602
603 /** Builds the cache dir by appending the user path and 'cache'.
604 * @return a File representing the path to the private file cache within the current collection.
605 */
606 public static File getCacheDir() {
607 return new File(getGLIUserFolder(), StaticStrings.CACHE_FOLDER);
608 }
609
610 /** Method which constructs the log directory given a certain collection.
611 * @param col_dir The location of the collection directory as a <strong>String</strong>.
612 * @return The location of the given collections log directory, also as a <strong>String</strong>.
613 */
614 public static String getLogDir(String col_dir) {
615 if(col_dir != null) {
616 return col_dir + LOG_DIR;
617 }
618 else {
619 return getGLIUserFolder().getAbsolutePath() + File.separator + LOG_DIR;
620 }
621 }
622
623 static final private String APPLICATION_DATA_FOLDER = "Application Data";
624 static final private String UNIX_GLI_CONFIG_FOLDER = ".gli";
625 static final private String USER_HOME_PROPERTY = "user.home";
626 static final private String WIN_GLI_CONFIG_FOLDER = "Greenstone" + File.separator + "GLI";
627 /** Definition of an important directory name, in this case the log directory for the collection. */
628 static final public String LOG_DIR = "log" + File.separator;
629
630 static public File getGLIUserFolder()
631 {
632 if (Utility.isWindows()) {
633 return new File(System.getProperty(USER_HOME_PROPERTY) + File.separator + APPLICATION_DATA_FOLDER + File.separator + WIN_GLI_CONFIG_FOLDER + File.separator);
634 }
635 else {
636 return new File(System.getProperty(USER_HOME_PROPERTY) + File.separator + UNIX_GLI_CONFIG_FOLDER + File.separator);
637 }
638 }
639
640 static private HashMap plugin_map = null;
641
642 static private void setUpPluginNameMap() {
643 plugin_map = new HashMap();
644 plugin_map.put("GAPlug", "GreenstoneXMLPlugin");
645 plugin_map.put("RecPlug", "DirectoryPlugin");
646 plugin_map.put("ArcPlug","ArchivesInfPlugin");
647 plugin_map.put("TEXTPlug","TextPlugin");
648 plugin_map.put("XMLPlug","ReadXMLFile");
649 plugin_map.put("EMAILPlug","EmailPlugin");
650 plugin_map.put("SRCPlug","SourceCodePlugin");
651 plugin_map.put("NULPlug","NulPlugin");
652 plugin_map.put("W3ImgPlug","HTMLImagePlugin");
653 plugin_map.put("PagedImgPlug","PagedImagePlugin");
654 plugin_map.put("METSPlug", "GreenstoneMETSPlugin");
655 plugin_map.put("DBPlug", "DatabasePlugin");
656 plugin_map.put("PPTPlug", "PowerPointPlugin");
657 plugin_map.put("PSPlug", "PostScriptPlugin");
658 }
659
660 static public String ensureNewPluginName(String plugin) {
661 if (plugin.endsWith("Plugin")) return plugin;
662 if (plugin_map == null) {
663 setUpPluginNameMap();
664 }
665 String new_name = (String)plugin_map.get(plugin);
666 if (new_name != null) return new_name;
667 new_name = plugin.replaceAll("Plug", "Plugin");
668 return new_name;
669 }
670
671
672 /** Write out a property line--a (property, value) pair--to the gsdl(3)site.cfg file.
673 * If the file already contains the line as-is, it is not re-written.
674 * If the file doesn't contain the line, it is appended.
675 * If the file contained a different value for the property, the line is corrected
676 * and the file is written out.
677 * If the propertyValue parameter is null, the property line is removed from the file.
678 * Not using the Properties class, as we want to keep the file's contents in the
679 * same order and preserve all the comments in as they're meant to help the user.
680 * Return the old value for the property, if it existed, else "".
681 */
682 public static String updatePropertyConfigFile(
683 String filename, String propertyName, String propertyValue)
684 {
685 File propFile = new File(filename);
686 String oldValue = "";
687 if(!propFile.exists()) {
688 System.err.println("*** Unable to update property " + propertyName + " in file "
689 + filename + " to\n" + propertyValue + ". File does not (yet) exist.\n");
690 return oldValue;
691 }
692 BufferedReader fin = null;
693 BufferedWriter fout = null;
694 StringBuffer contents = new StringBuffer();
695 String insertLine = null;
696 if(propertyValue != null) {
697 insertLine = propertyName+"\t"+propertyValue+"\n"; // new line after every propertyLine
698 }
699 boolean found = false;
700 try {
701 fin = new BufferedReader(new FileReader(filename));
702 String line = "";
703 while((line = fin.readLine()) != null) {
704 line = line.trim(); // remove any preceding (surrounding) whitespace
705 if(line.startsWith(propertyName)) { // won't match comment
706 found = true;
707 // store the previous value for the property
708 oldValue = line;
709 oldValue = oldValue.substring(propertyName.length());
710 oldValue = oldValue.trim();
711
712 if(propertyValue != null) { // line should be removed if propertyValue == null
713 if(line.equals(insertLine)) { // file is already correct, nothing to do
714 fin.close();
715 fin = null;
716 break;
717 } else {
718 contents.append(insertLine);
719 }
720 }
721 } else { // any other line
722 contents.append(line);
723 contents.append("\n"); // ensures the required new line at end of file
724 }
725 }
726
727 if(fin != null) { // need to write something out to the file
728 fin.close();
729 fin = null;
730
731 // if collecthome/property wasn't already specified in the file, append it
732 // but only if we have a value to write out to the file
733 if(!found && propertyValue != null) {
734 fout = new BufferedWriter(new FileWriter(filename, true)); // append mode
735 fout.write(insertLine, 0, insertLine.length());
736 } else {
737 fout = new BufferedWriter(new FileWriter(filename)); // hopefully this will overwrite
738 fout.write(contents.toString(), 0, contents.length());
739 }
740
741 fout.close();
742 fout = null;
743
744 } // else the file is fine
745 } catch(IOException e) {
746 System.err.println("*** Could not update file: " + filename);
747 System.err.println("with the " + propertyName + " property set to " + propertyValue);
748 System.err.println("Exception occurred: " + e.getMessage());
749 } finally {
750 SafeProcess.closeResource(fin);
751 SafeProcess.closeResource(fout);
752
753 }
754 return oldValue;
755 }
756}
Note: See TracBrowser for help on using the repository browser.