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

Last change on this file since 32271 was 32271, checked in by ak19, 6 years ago

Some more handy functions to print calling methods and tidied up the method that printed the entire callstack, before I start on committing the PDFPlugin restructuring stuff.

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