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

Last change on this file since 33757 was 33757, checked in by ak19, 4 years ago
  1. Windows bugfix for getting exMeta to be loaded into GLI where there are subdirs involved in the Gather pane, or there are non-ASCII filenames, or the file rename method is set to base64. 2. Bugfix for Linux and Windows: Using Base64 to rename files was still a problem despite the previous commit (which was supposed to have fixed all GLI exMeta loading issues on Linux) in the special case where a subfolder was pure ASCII. The perl code wouldn't base64 encode such subdirs. However, GLI won't know which part of a relative file path to decode based on the file rename method used and which parts are not to be decoded. So GLI uniformly decoded them, and ASCII named subfolders that were not base64 encoded (but contained files that were to be renamed with base64) got base64 decoded into garbage, so that exMeta still did not get attached. 3. This commit contains debug stmts.
  • Property svn:keywords set to Author Date Id Revision
File size: 29.0 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 * The following calls a method in WindowsNativeFunctions.java to retrieve Windows short file names
120 * taken from http://dolf.trieschnigg.nl/eightpointthree/eightpointthree.html
121 * which uses the the non-JNI NativeCall jar file for which WindowsNativeFunctions imports com.eaio.nativecall.*
122 *
123 * returns the short filename (8.3) for a file in Windows
124 *
125 * @param longFileName - must be the full path to an actual existing file
126 * @return a string with the short filename, or null if an error occurred or the
127 * file does not exist.
128 */
129 public static String getWindowsShortFileName(String longFileName) throws Exception {
130 if(!Utility.isWindows()) {
131 return longFileName;
132 } else {
133 //return WindowsNativeFunctions.getEightPointThree(longFileName);
134 return getMSDOSName(longFileName);
135 }
136 }
137
138 /**
139 * getMSDOSName() and its helper function getAbsolutePath(fileName)
140 * are from https://stackoverflow.com/questions/18893284/how-to-get-short-filenames-in-windows-using-java
141 * getMSDOSName() modified to use our SafeProcess class.
142 *
143 * @param fileName - the regular fileName to be converted. Must be the full path to an actual existing file
144 * @return Windows shortfile name for the fileName parameter given.
145 */
146 public static String getMSDOSName(String fileName)
147 throws IOException, InterruptedException {
148
149 /*
150 String path = getAbsolutePath(fileName);
151
152 changed "+ fileName.toUpperCase() +" to "path"
153 Process process =
154 Runtime.getRuntime().exec(
155 "cmd /c for %I in (\"" + path + "\") do @echo %~fsI");
156
157 process.waitFor();
158
159 byte[] data = new byte[65536];
160 int size = process.getInputStream().read(data);
161
162 if (size <= 0) {
163 return null;
164 }
165
166 return new String(data, 0, size).replaceAll("\\r\\n", "");
167 */
168 String path = getAbsolutePath(fileName);
169
170 SafeProcess process = new SafeProcess("cmd /c for %I in (\"" + path + "\") do @echo %~fsI");
171 int returnVal = process.runProcess();
172 if(returnVal != 0) {
173 return null;
174 }
175
176 String data = process.getStdOutput();
177 if(data == null) {
178 return null;
179 }
180 else return data.replaceAll("\\r\\n", "");
181 }
182 public static String getAbsolutePath(String fileName)
183 throws IOException {
184 File file = new File(fileName);
185 String path = file.getAbsolutePath();
186
187 if (file.exists() == false)
188 file = new File(path);
189
190 path = file.getCanonicalPath();
191
192 if (file.isDirectory() && (path.endsWith(File.separator) == false))
193 path += File.separator;
194
195 return path;
196 }
197
198 /**
199 * Handy function to display the list of calling functions by
200 * printing out the stack trace even when you don't have an exception
201 */
202 static public void printStackTrace() {
203 // https://stackoverflow.com/questions/1069066/get-current-stack-trace-in-java
204
205 //Thread.dumpStack(); // looks too much like an exception, though the newlines separating each function call is handy
206 //new Exception().printStackTrace(); // outputs in the format of an exception too
207 //System.err.println("\n@@@@ stacktrace:\n" + Arrays.toString(Thread.currentThread().getStackTrace()) + "\n"); // outputs all in one line
208
209 System.err.println("\n@@@@ stacktrace:");
210 StackTraceElement[] els = new Throwable().getStackTrace(); // starts at index 1, which is this function
211 //StackTraceElement[] els = Thread.currentThread().getStackTrace(); starts at index 0, "java.lang.Thread.getStackTrace()"
212 for(StackTraceElement ste : els) {
213 System.err.println(" " + ste);
214 }
215 }
216
217 /**
218 * Handy function to display the parent of the calling function
219 * (the function that called the function that called printCaller())
220 */
221 static public void printCaller() {
222 //int parent = 1;
223 // this function printCaller() itself adds another layer on the callstack since
224 // it calls the overloaded method, so need to add 1 more to parent
225 //printCaller(parent++);
226
227 StackTraceElement[] callstack = Thread.currentThread().getStackTrace();
228 StackTraceElement requestor = callstack[2]; // the calling function, the function that called this one
229 if(callstack.length > 3) {
230 StackTraceElement caller_requested = callstack[3]; // the function requested
231 System.err.println("\n@@@ Function " + requestor + " called by:\n "
232 + caller_requested + " at 1 ancestors back\n");
233 } else {
234 StackTraceElement caller_requested = callstack[callstack.length-1]; // the function requested
235 System.err.println("\n@@@ Don't have callers beyond requestor function " + requestor + "\n");
236 }
237 }
238
239 /**
240 * Handy function to display the nth ancestor of the calling function
241 * where ancestor=0 would be the calling function itself
242 */
243 static public void printCaller(int ancestor) {
244 // https://stackoverflow.com/questions/1069066/get-current-stack-trace-in-java
245
246 // Thread.currentThread().getStackTrace() starts at index 0: "java.lang.Thread.getStackTrace()"
247 // index 1 will be this method (printCaller) and index 2 will be the calling function itself who wants
248 // to know who called it. So need to at least start at index 3 to get informative caller information
249
250 StackTraceElement[] callstack = Thread.currentThread().getStackTrace();
251 StackTraceElement requestor = callstack[2]; // the calling function, the function that called this one
252 if(callstack.length > (ancestor+3)) {
253 StackTraceElement caller_requested = callstack[ancestor+3]; // the function requested
254 System.err.println("\n@@@ Function " + requestor + " called by:\n "
255 + caller_requested + " at " + ancestor + " ancestors back\n");
256 } else {
257 StackTraceElement caller_requested = callstack[callstack.length-1]; // the function requested
258 System.err.println("\n@@@ Don't have " + ancestor + " ancestor callers. Function " + requestor + " called by:\n "
259 + caller_requested + " at max " + (callstack.length-1) + " ancestors back\n");
260 }
261 }
262
263 /**
264 * Reads in a text file and returns the contents as a String
265 */
266 static public String readFile(File file) {
267 BufferedReader fin = null;
268 StringBuffer contents = new StringBuffer();
269
270 try {
271 fin = new BufferedReader(new FileReader(file));
272 String line = null;
273 while((line = fin.readLine()) != null) {
274 contents.append(line);
275 contents.append("\n");
276 }
277 } catch(IOException e) {
278 System.err.println("*** Could not read in file: " + file.toString());
279 System.err.println("*** Exception occurred: " + e.getMessage());
280 } finally {
281 SafeProcess.closeResource(fin);
282 }
283
284 return contents.toString();
285 }
286
287 /**
288 * Delete a file or directory
289 * @param file The <strong>File</strong> you want to delete.
290 * @return A <i>boolean</i> which is <i>true</i> if the file specified was successfully deleted, <i>false</i> otherwise.
291 */
292 static public boolean delete(File file)
293 {
294 // Nothing to do if it doesn't exist
295 if (!file.exists()) {
296 return true;
297 }
298
299 return deleteInternal(file);
300 }
301
302
303 /** Convenience function. */
304 static public boolean delete(String filename)
305 {
306 return delete(new File(filename));
307 }
308
309
310 /** In Java you have to make sure a directory is empty before you delete it, so recursively delete. */
311 static private boolean deleteInternal(File file)
312 {
313 // If file is a directory, we have to recursively delete its contents first
314 if (file.isDirectory()) {
315 File files[] = file.listFiles();
316 for (int i = 0; i < files.length; i++) {
317 if (deleteInternal(files[i]) == false) {
318 System.err.println("Error: Could not delete folder " + file);
319 return false;
320 }
321 }
322 }
323
324 // Delete file
325 if (file.delete() == false) {
326 System.err.println("Error: Could not delete file " + file);
327 return false;
328 }
329
330 return true;
331 }
332
333
334 /** Convert a long, detailing the length of a file in bytes, into a nice human readable string using b, kb, Mb and Gb. */
335 static final public String BYTE_SUFFIX = " b";
336 static final public long GIGABYTE = 1024000000l;
337 static final public String GIGABYTE_SUFFIX = " Gb";
338 static final public long KILOBYTE = 1024l;
339 static final public String KILOBYTE_SUFFIX = " kb";
340 static final public long MEGABYTE = 1024000l;
341 static final public String MEGABYTE_SUFFIX = " Mb";
342 static final public String formatFileLength(long length) {
343 StringBuffer result = new StringBuffer("");
344 float number = 0f;
345 String suffix = null;
346 // Determine the floating point number and the suffix (radix) used.
347 if(length >= GIGABYTE) {
348 number = (float) length / (float) GIGABYTE;
349 suffix = GIGABYTE_SUFFIX;
350 }
351 else if(length >= MEGABYTE) {
352 number = (float) length / (float) MEGABYTE;
353 suffix = MEGABYTE_SUFFIX;
354 }
355 else if(length >= KILOBYTE) {
356 number = (float) length / (float) KILOBYTE;
357 suffix = KILOBYTE_SUFFIX;
358 }
359 else {
360 // Don't need to do anything fancy if the file is smaller than a kilobyte
361 return length + BYTE_SUFFIX;
362 }
363 // 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.
364 String number_str = Float.toString(number);
365 char number_char[] = number_str.toCharArray();
366 int pos = 0;
367 // Print the characters up to the '.'
368 while(number_char != null && pos < number_char.length && number_char[pos] != '.') {
369 result.append(number_char[pos]);
370 pos++;
371 }
372 if(pos < number_char.length) {
373 // Print the '.' and at most two characters after it
374 result.append(number_char[pos]);
375 pos++;
376 for(int i = 0; i < 2 && pos < number_char.length; i++, pos++) {
377 result.append(number_char[pos]);
378 }
379 // Search through the remaining string for 'E'
380 while(pos < number_char.length && number_char[pos] != 'E') {
381 pos++;
382 }
383 // If we still have string then we found an E. Copy the remaining string.
384 while(pos < number_char.length) {
385 result.append(number_char[pos]);
386 pos++;
387 }
388 }
389 // Add suffix
390 result.append(suffix);
391 // Done
392 return result.toString();
393 }
394
395 /** This method formats a given string, using HTML markup, so its width does not exceed the given width and its appearance if justified.
396 * @param text The <strong>String</strong> requiring formatting.
397 * @param width The maximum width per line as an <i>int</i>.
398 * @return A <strong>String</strong> formatted so as to have no line longer than the specified width.
399 * 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.
400 */
401 static public String formatHTMLWidth(String text, int width) {
402 if(text == null) {
403 return "Error";
404 }
405 HTMLStringTokenizer html = new HTMLStringTokenizer(text);
406 int current_width = 0;
407 int threshold = width / 2;
408 Stack lines = new Stack();
409 String line = "";
410 while(html.hasMoreTokens()) {
411 String token = html.nextToken();
412 while(token != null) {
413 if(html.isTag()) {
414 // Insert smart HTML tag code here.
415 token = null;
416 }
417 else {
418 // If the token is bigger than two thirds width, before we've even started break it down.
419 if(current_width + 1 + token.length() > width && token.length() > threshold) {
420 if(width == current_width) {
421 lines.push(line);
422 line = token;
423 current_width = token.length();
424 }
425 else {
426 String prefix = token.substring(0, width - 1 - current_width);
427 token = token.substring(prefix.length());
428 if(current_width == 0) {
429 line = line + prefix;
430 }
431 else {
432 line = line + " " + prefix;
433 }
434 lines.push(line);
435 line = "";
436 current_width = 0;
437 }
438 }
439 // If adding the next token would push us over the maximum line width.
440 else if(current_width + 1 + token.length() > width) {
441 lines.push(line);
442 line = token;
443 current_width = token.length();
444 token = null;
445 }
446 // Otherwise we should be able to just add the token, give or take.
447 else {
448 if(current_width == 0) {
449 line = line + token;
450 current_width = token.length();
451 }
452 else {
453 // Special case for standard punctuation which may exist after a tag like so:
454 // My name is <scratchy>Slim Shady</scratchy>. <-- Annoying punctuation.
455 if(token.equals(".") || token.equals(",") || token.equals("!") || token.equals("?")) {
456 line = line + token;
457 current_width = current_width + 1;
458 }
459 else {
460 line = line + " " + token;
461 current_width = current_width + 1 + token.length();
462 }
463 }
464 token = null;
465 }
466 }
467 }
468 }
469 String result = line;
470 while(!lines.empty()) {
471 result = (String)lines.pop() + "<BR>" + result;
472 }
473 // Replace ' ' with "&nbsp;"
474 boolean tag = false;
475 int pos = 0;
476 while(pos < result.length()) {
477 if(result.charAt(pos) == '<') {
478 tag = true;
479 }
480 else if(result.charAt(pos) == '>') {
481 tag = false;
482 }
483 else if(result.charAt(pos) == ' ' && !tag) {
484 String prefix = result.substring(0, pos);
485 String suffix = result.substring(pos + 1);
486 result = prefix + "&nbsp;" + suffix;
487 }
488 pos++;
489 }
490 result = "<HTML>" + result + "</HTML>";
491 return result;
492 }
493
494
495 static public String getDateString() {
496 Calendar current = Calendar.getInstance();
497 String day_name = null;
498 switch(current.get(Calendar.DAY_OF_WEEK)) {
499 case Calendar.MONDAY: day_name = "Dates.Mon"; break;
500 case Calendar.TUESDAY: day_name = "Dates.Tue"; break;
501 case Calendar.WEDNESDAY: day_name = "Dates.Wed"; break;
502 case Calendar.THURSDAY: day_name = "Dates.Thu"; break;
503 case Calendar.FRIDAY: day_name = "Dates.Fri"; break;
504 case Calendar.SATURDAY: day_name = "Dates.Sat"; break;
505 case Calendar.SUNDAY: day_name = "Dates.Sun"; break;
506 default: day_name = "";
507 }
508 String month_name = null;
509 switch(current.get(Calendar.MONTH)) {
510 case Calendar.JANUARY: month_name = "Dates.Jan"; break;
511 case Calendar.FEBRUARY: month_name = "Dates.Feb"; break;
512 case Calendar.MARCH: month_name = "Dates.Mar"; break;
513 case Calendar.APRIL: month_name = "Dates.Apr"; break;
514 case Calendar.MAY: month_name = "Dates.May"; break;
515 case Calendar.JUNE: month_name = "Dates.Jun"; break;
516 case Calendar.JULY: month_name = "Dates.Jul"; break;
517 case Calendar.AUGUST: month_name = "Dates.Aug"; break;
518 case Calendar.SEPTEMBER: month_name = "Dates.Sep"; break;
519 case Calendar.OCTOBER: month_name = "Dates.Oct"; break;
520 case Calendar.NOVEMBER: month_name = "Dates.Nov"; break;
521 case Calendar.DECEMBER: month_name = "Dates.Dec"; break;
522 default: month_name = "";
523 }
524 int day = current.get(Calendar.DAY_OF_MONTH);
525 int hour = current.get(Calendar.HOUR_OF_DAY);
526 int minute = current.get(Calendar.MINUTE);
527 int second = current.get(Calendar.SECOND);
528 int year = current.get(Calendar.YEAR);
529
530 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);
531 }
532
533
534 /** Determine this machines name.
535 * @return The name as a <strong>String</strong>.
536 */
537 static public String getMachineName() {
538 try {
539 return InetAddress.getLocalHost().getHostName();
540 }
541 catch(UnknownHostException ex) {
542 }
543 return "Unknown Machine";
544 }
545
546
547 static public String getSitesDir(String gsdl3_path) {
548 return gsdl3_path + "sites" + File.separator;
549
550 }
551
552 /** @return the OSdir foldername: windows, linux or darwin */
553 public static String getOSdirName() {
554 if(Utility.isWindows()) {
555 return "windows";
556 }
557 if(Utility.isMac()) {
558 return "darwin";
559 }
560 return "linux"; // else assume it's a linux machine, OSdirname = linux
561 }
562
563
564 /** Method to determine if the host system is MacOS based.
565 * @return a boolean which is true if the platform is MacOS, false otherwise
566 */
567 public static boolean isMac() {
568 Properties props = System.getProperties();
569 String os_name = props.getProperty("os.name","");
570 if(os_name.startsWith("Mac OS")) {
571 return true;
572 }
573 return false;
574 }
575
576
577 /** Method to determine if the host system is Microsoft Windows based.
578 * @return A <i>boolean</i> which is <i>true</i> if the platform is Windows, <i>false</i> otherwise.
579 */
580 public static boolean isWindows() {
581 Properties props = System.getProperties();
582 String os_name = props.getProperty("os.name","");
583 if(os_name.startsWith("Windows")) {
584 return true;
585 }
586 return false;
587 }
588
589 public static boolean isWindows9x() {
590 Properties props = System.getProperties();
591 String os_name = props.getProperty("os.name","");
592 if(os_name.startsWith("Windows") && os_name.indexOf("9") != -1) {
593 return true;
594 }
595 return false;
596 }
597 /** Takes a string and a desired length and pads out the string to the length by adding spaces to the left.
598 * @param str The target <strong>String</strong> that needs to be padded.
599 * @param length The desired length of the string as an <i>int</i>.
600 * @return A <strong>String</strong> made from appending space characters with the string until it has a length equal to length.
601 */
602 static private String pad(String str_raw, int length, char fill, boolean end) {
603 StringBuffer str = new StringBuffer(str_raw);
604 while(str.length() < length) {
605 if(end) {
606 str.insert(0, fill);
607 }
608 else {
609 str.append(fill);
610 }
611 }
612 return str.toString();
613 }
614
615
616 /** Builds the cache dir by appending the user path and 'cache'.
617 * @return a File representing the path to the private file cache within the current collection.
618 */
619 public static File getCacheDir() {
620 return new File(getGLIUserFolder(), StaticStrings.CACHE_FOLDER);
621 }
622
623 /** Method which constructs the log directory given a certain collection.
624 * @param col_dir The location of the collection directory as a <strong>String</strong>.
625 * @return The location of the given collections log directory, also as a <strong>String</strong>.
626 */
627 public static String getLogDir(String col_dir) {
628 if(col_dir != null) {
629 return col_dir + LOG_DIR;
630 }
631 else {
632 return getGLIUserFolder().getAbsolutePath() + File.separator + LOG_DIR;
633 }
634 }
635
636 static final private String APPLICATION_DATA_FOLDER = "Application Data";
637 static final private String UNIX_GLI_CONFIG_FOLDER = ".gli";
638 static final private String USER_HOME_PROPERTY = "user.home";
639 static final private String WIN_GLI_CONFIG_FOLDER = "Greenstone" + File.separator + "GLI";
640 /** Definition of an important directory name, in this case the log directory for the collection. */
641 static final public String LOG_DIR = "log" + File.separator;
642
643 static public File getGLIUserFolder()
644 {
645 if (Utility.isWindows()) {
646 return new File(System.getProperty(USER_HOME_PROPERTY) + File.separator + APPLICATION_DATA_FOLDER + File.separator + WIN_GLI_CONFIG_FOLDER + File.separator);
647 }
648 else {
649 return new File(System.getProperty(USER_HOME_PROPERTY) + File.separator + UNIX_GLI_CONFIG_FOLDER + File.separator);
650 }
651 }
652
653 static private HashMap plugin_map = null;
654
655 static private void setUpPluginNameMap() {
656 plugin_map = new HashMap();
657 plugin_map.put("GAPlug", "GreenstoneXMLPlugin");
658 plugin_map.put("RecPlug", "DirectoryPlugin");
659 plugin_map.put("ArcPlug","ArchivesInfPlugin");
660 plugin_map.put("TEXTPlug","TextPlugin");
661 plugin_map.put("XMLPlug","ReadXMLFile");
662 plugin_map.put("EMAILPlug","EmailPlugin");
663 plugin_map.put("SRCPlug","SourceCodePlugin");
664 plugin_map.put("NULPlug","NulPlugin");
665 plugin_map.put("W3ImgPlug","HTMLImagePlugin");
666 plugin_map.put("PagedImgPlug","PagedImagePlugin");
667 plugin_map.put("METSPlug", "GreenstoneMETSPlugin");
668 plugin_map.put("DBPlug", "DatabasePlugin");
669 plugin_map.put("PPTPlug", "PowerPointPlugin");
670 plugin_map.put("PSPlug", "PostScriptPlugin");
671 }
672
673 static public String ensureNewPluginName(String plugin) {
674 if (plugin.endsWith("Plugin")) return plugin;
675 if (plugin_map == null) {
676 setUpPluginNameMap();
677 }
678 String new_name = (String)plugin_map.get(plugin);
679 if (new_name != null) return new_name;
680 new_name = plugin.replaceAll("Plug", "Plugin");
681 return new_name;
682 }
683
684
685 /** Write out a property line--a (property, value) pair--to the gsdl(3)site.cfg file.
686 * If the file already contains the line as-is, it is not re-written.
687 * If the file doesn't contain the line, it is appended.
688 * If the file contained a different value for the property, the line is corrected
689 * and the file is written out.
690 * If the propertyValue parameter is null, the property line is removed from the file.
691 * Not using the Properties class, as we want to keep the file's contents in the
692 * same order and preserve all the comments in as they're meant to help the user.
693 * Return the old value for the property, if it existed, else "".
694 */
695 public static String updatePropertyConfigFile(
696 String filename, String propertyName, String propertyValue)
697 {
698 File propFile = new File(filename);
699 String oldValue = "";
700 if(!propFile.exists()) {
701 System.err.println("*** Unable to update property " + propertyName + " in file "
702 + filename + " to\n" + propertyValue + ". File does not (yet) exist.\n");
703 return oldValue;
704 }
705 BufferedReader fin = null;
706 BufferedWriter fout = null;
707 StringBuffer contents = new StringBuffer();
708 String insertLine = null;
709 if(propertyValue != null) {
710 insertLine = propertyName+"\t"+propertyValue+"\n"; // new line after every propertyLine
711 }
712 boolean found = false;
713 try {
714 fin = new BufferedReader(new FileReader(filename));
715 String line = "";
716 while((line = fin.readLine()) != null) {
717 line = line.trim(); // remove any preceding (surrounding) whitespace
718 if(line.startsWith(propertyName)) { // won't match comment
719 found = true;
720 // store the previous value for the property
721 oldValue = line;
722 oldValue = oldValue.substring(propertyName.length());
723 oldValue = oldValue.trim();
724
725 if(propertyValue != null) { // line should be removed if propertyValue == null
726 if(line.equals(insertLine)) { // file is already correct, nothing to do
727 fin.close();
728 fin = null;
729 break;
730 } else {
731 contents.append(insertLine);
732 }
733 }
734 } else { // any other line
735 contents.append(line);
736 contents.append("\n"); // ensures the required new line at end of file
737 }
738 }
739
740 if(fin != null) { // need to write something out to the file
741 fin.close();
742 fin = null;
743
744 // if collecthome/property wasn't already specified in the file, append it
745 // but only if we have a value to write out to the file
746 if(!found && propertyValue != null) {
747 fout = new BufferedWriter(new FileWriter(filename, true)); // append mode
748 fout.write(insertLine, 0, insertLine.length());
749 } else {
750 fout = new BufferedWriter(new FileWriter(filename)); // hopefully this will overwrite
751 fout.write(contents.toString(), 0, contents.length());
752 }
753
754 fout.close();
755 fout = null;
756
757 } // else the file is fine
758 } catch(IOException e) {
759 System.err.println("*** Could not update file: " + filename);
760 System.err.println("with the " + propertyName + " property set to " + propertyValue);
761 System.err.println("Exception occurred: " + e.getMessage());
762 } finally {
763 SafeProcess.closeResource(fin);
764 SafeProcess.closeResource(fout);
765
766 }
767 return oldValue;
768 }
769}
Note: See TracBrowser for help on using the repository browser.