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 |
|
---|
38 | package 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!
|
---|
43 | import java.io.*;
|
---|
44 | import java.net.*;
|
---|
45 | import 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!
|
---|
48 | import 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!
|
---|
51 |
|
---|
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 | */
|
---|
57 | public class Utility
|
---|
58 | {
|
---|
59 | /** The size of the io buffer, in bytes. */
|
---|
60 | static final public int BUFFER_SIZE = 1024;
|
---|
61 | static final public String CFG_CLASSIFY = "classify";
|
---|
62 | static final public String CFG_CLASSIFY_BUTTONNAME = "-buttonname";
|
---|
63 | static final public String CFG_CLASSIFY_HFILE = "-hfile";
|
---|
64 | static final public String CFG_CLASSIFY_METADATA = "-metadata";
|
---|
65 | static final public String CFG_CLASSIFY_SORT = "-sort";
|
---|
66 | static final public String CFG_FORMAT = "format";
|
---|
67 | static final public String COLLECTION_TREE = "Collection";
|
---|
68 | /** Definition of an important directory name, in this case the file the collection configuration is expect to be in. */
|
---|
69 | static final public String CONFIG_FILE = "etc" + File.separator + "collect.cfg";
|
---|
70 | static final public String GLI_EXTENSION = ".col";
|
---|
71 |
|
---|
72 | /** Definition of an important directory name, in this case the import directory for the collection. */
|
---|
73 | static final public String IMPORT_DIR = "import" + File.separator;
|
---|
74 | /** Definition of an important directory name, in this case the macros directory for the collection. */
|
---|
75 | static final public String MACROS_DIR = "macros" + File.separator;
|
---|
76 | /** Definition of an important directory name, in this case the location of the expected collection metadata sets.. */
|
---|
77 | static final public String META_DIR = "metadata" + File.separator; // Col. Copy
|
---|
78 | /** The default name of the perl executable under unix. */
|
---|
79 | static final public String PERL_EXECUTABLE_UNIX = "perl";
|
---|
80 | /** The default name of the perl executable under windows. */
|
---|
81 | static final public String PERL_EXECUTABLE_WINDOWS = "Perl.exe";
|
---|
82 | /** The name of the GLI. */
|
---|
83 | static final public String PROGRAM_NAME = "Greenstone Librarian Interface";
|
---|
84 | /** The current version of the GLI. */
|
---|
85 | static final public String PROGRAM_VERSION = "v2.70u";
|
---|
86 | static final public String WORKSPACE_TREE = "Workspace";
|
---|
87 |
|
---|
88 |
|
---|
89 | /**
|
---|
90 | * Delete a file or directory
|
---|
91 | * @param file The <strong>File</strong> you want to delete.
|
---|
92 | * @return A <i>boolean</i> which is <i>true</i> if the file specified was successfully deleted, <i>false</i> otherwise.
|
---|
93 | */
|
---|
94 | static public boolean delete(File file)
|
---|
95 | {
|
---|
96 | // Nothing to do if it doesn't exist
|
---|
97 | if (!file.exists()) {
|
---|
98 | return true;
|
---|
99 | }
|
---|
100 |
|
---|
101 | return deleteInternal(file);
|
---|
102 | }
|
---|
103 |
|
---|
104 |
|
---|
105 | /** Convenience function. */
|
---|
106 | static public boolean delete(String filename)
|
---|
107 | {
|
---|
108 | return delete(new File(filename));
|
---|
109 | }
|
---|
110 |
|
---|
111 |
|
---|
112 | /** In Java you have to make sure a directory is empty before you delete it, so recursively delete. */
|
---|
113 | static private boolean deleteInternal(File file)
|
---|
114 | {
|
---|
115 | // If file is a directory, we have to recursively delete its contents first
|
---|
116 | if (file.isDirectory()) {
|
---|
117 | File files[] = file.listFiles();
|
---|
118 | for (int i = 0; i < files.length; i++) {
|
---|
119 | if (deleteInternal(files[i]) == false) {
|
---|
120 | System.err.println("Error: Could not delete folder " + file);
|
---|
121 | return false;
|
---|
122 | }
|
---|
123 | }
|
---|
124 | }
|
---|
125 |
|
---|
126 | // Delete file
|
---|
127 | if (file.delete() == false) {
|
---|
128 | System.err.println("Error: Could not delete file " + file);
|
---|
129 | return false;
|
---|
130 | }
|
---|
131 |
|
---|
132 | return true;
|
---|
133 | }
|
---|
134 |
|
---|
135 |
|
---|
136 | /** Convert a long, detailing the length of a file in bytes, into a nice human readable string using b, kb, Mb and Gb. */
|
---|
137 | static final public String BYTE_SUFFIX = " b";
|
---|
138 | static final public long GIGABYTE = 1024000000l;
|
---|
139 | static final public String GIGABYTE_SUFFIX = " Gb";
|
---|
140 | static final public long KILOBYTE = 1024l;
|
---|
141 | static final public String KILOBYTE_SUFFIX = " kb";
|
---|
142 | static final public long MEGABYTE = 1024000l;
|
---|
143 | static final public String MEGABYTE_SUFFIX = " Mb";
|
---|
144 | static final public String formatFileLength(long length) {
|
---|
145 | StringBuffer result = new StringBuffer("");
|
---|
146 | float number = 0f;
|
---|
147 | String suffix = null;
|
---|
148 | // Determine the floating point number and the suffix (radix) used.
|
---|
149 | if(length >= GIGABYTE) {
|
---|
150 | number = (float) length / (float) GIGABYTE;
|
---|
151 | suffix = GIGABYTE_SUFFIX;
|
---|
152 | }
|
---|
153 | else if(length >= MEGABYTE) {
|
---|
154 | number = (float) length / (float) MEGABYTE;
|
---|
155 | suffix = MEGABYTE_SUFFIX;
|
---|
156 | }
|
---|
157 | else if(length >= KILOBYTE) {
|
---|
158 | number = (float) length / (float) KILOBYTE;
|
---|
159 | suffix = KILOBYTE_SUFFIX;
|
---|
160 | }
|
---|
161 | else {
|
---|
162 | // Don't need to do anything fancy if the file is smaller than a kilobyte
|
---|
163 | return length + BYTE_SUFFIX;
|
---|
164 | }
|
---|
165 | // 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.
|
---|
166 | String number_str = Float.toString(number);
|
---|
167 | char number_char[] = number_str.toCharArray();
|
---|
168 | int pos = 0;
|
---|
169 | // Print the characters up to the '.'
|
---|
170 | while(number_char != null && pos < number_char.length && number_char[pos] != '.') {
|
---|
171 | result.append(number_char[pos]);
|
---|
172 | pos++;
|
---|
173 | }
|
---|
174 | if(pos < number_char.length) {
|
---|
175 | // Print the '.' and at most two characters after it
|
---|
176 | result.append(number_char[pos]);
|
---|
177 | pos++;
|
---|
178 | for(int i = 0; i < 2 && pos < number_char.length; i++, pos++) {
|
---|
179 | result.append(number_char[pos]);
|
---|
180 | }
|
---|
181 | // Search through the remaining string for 'E'
|
---|
182 | while(pos < number_char.length && number_char[pos] != 'E') {
|
---|
183 | pos++;
|
---|
184 | }
|
---|
185 | // If we still have string then we found an E. Copy the remaining string.
|
---|
186 | while(pos < number_char.length) {
|
---|
187 | result.append(number_char[pos]);
|
---|
188 | pos++;
|
---|
189 | }
|
---|
190 | }
|
---|
191 | // Add suffix
|
---|
192 | result.append(suffix);
|
---|
193 | // Done
|
---|
194 | return result.toString();
|
---|
195 | }
|
---|
196 |
|
---|
197 | /** This method formats a given string, using HTML markup, so its width does not exceed the given width and its appearance if justified.
|
---|
198 | * @param text The <strong>String</strong> requiring formatting.
|
---|
199 | * @param width The maximum width per line as an <i>int</i>.
|
---|
200 | * @return A <strong>String</strong> formatted so as to have no line longer than the specified width.
|
---|
201 | * 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.
|
---|
202 | */
|
---|
203 | static public String formatHTMLWidth(String text, int width) {
|
---|
204 | if(text == null) {
|
---|
205 | return "Error";
|
---|
206 | }
|
---|
207 | HTMLStringTokenizer html = new HTMLStringTokenizer(text);
|
---|
208 | int current_width = 0;
|
---|
209 | int threshold = width / 2;
|
---|
210 | Stack lines = new Stack();
|
---|
211 | String line = "";
|
---|
212 | while(html.hasMoreTokens()) {
|
---|
213 | String token = html.nextToken();
|
---|
214 | while(token != null) {
|
---|
215 | if(html.isTag()) {
|
---|
216 | // Insert smart HTML tag code here.
|
---|
217 | token = null;
|
---|
218 | }
|
---|
219 | else {
|
---|
220 | // If the token is bigger than two thirds width, before we've even started break it down.
|
---|
221 | if(current_width + 1 + token.length() > width && token.length() > threshold) {
|
---|
222 | if(width == current_width) {
|
---|
223 | lines.push(line);
|
---|
224 | line = token;
|
---|
225 | current_width = token.length();
|
---|
226 | }
|
---|
227 | else {
|
---|
228 | String prefix = token.substring(0, width - 1 - current_width);
|
---|
229 | token = token.substring(prefix.length());
|
---|
230 | if(current_width == 0) {
|
---|
231 | line = line + prefix;
|
---|
232 | }
|
---|
233 | else {
|
---|
234 | line = line + " " + prefix;
|
---|
235 | }
|
---|
236 | lines.push(line);
|
---|
237 | line = "";
|
---|
238 | current_width = 0;
|
---|
239 | }
|
---|
240 | }
|
---|
241 | // If adding the next token would push us over the maximum line width.
|
---|
242 | else if(current_width + 1 + token.length() > width) {
|
---|
243 | lines.push(line);
|
---|
244 | line = token;
|
---|
245 | current_width = token.length();
|
---|
246 | token = null;
|
---|
247 | }
|
---|
248 | // Otherwise we should be able to just add the token, give or take.
|
---|
249 | else {
|
---|
250 | if(current_width == 0) {
|
---|
251 | line = line + token;
|
---|
252 | current_width = token.length();
|
---|
253 | }
|
---|
254 | else {
|
---|
255 | // Special case for standard punctuation which may exist after a tag like so:
|
---|
256 | // My name is <scratchy>Slim Shady</scratchy>. <-- Annoying punctuation.
|
---|
257 | if(token.equals(".") || token.equals(",") || token.equals("!") || token.equals("?")) {
|
---|
258 | line = line + token;
|
---|
259 | current_width = current_width + 1;
|
---|
260 | }
|
---|
261 | else {
|
---|
262 | line = line + " " + token;
|
---|
263 | current_width = current_width + 1 + token.length();
|
---|
264 | }
|
---|
265 | }
|
---|
266 | token = null;
|
---|
267 | }
|
---|
268 | }
|
---|
269 | }
|
---|
270 | }
|
---|
271 | String result = line;
|
---|
272 | while(!lines.empty()) {
|
---|
273 | result = (String)lines.pop() + "<BR>" + result;
|
---|
274 | }
|
---|
275 | // Replace ' ' with " "
|
---|
276 | boolean tag = false;
|
---|
277 | int pos = 0;
|
---|
278 | while(pos < result.length()) {
|
---|
279 | if(result.charAt(pos) == '<') {
|
---|
280 | tag = true;
|
---|
281 | }
|
---|
282 | else if(result.charAt(pos) == '>') {
|
---|
283 | tag = false;
|
---|
284 | }
|
---|
285 | else if(result.charAt(pos) == ' ' && !tag) {
|
---|
286 | String prefix = result.substring(0, pos);
|
---|
287 | String suffix = result.substring(pos + 1);
|
---|
288 | result = prefix + " " + suffix;
|
---|
289 | }
|
---|
290 | pos++;
|
---|
291 | }
|
---|
292 | result = "<HTML>" + result + "</HTML>";
|
---|
293 | return result;
|
---|
294 | }
|
---|
295 |
|
---|
296 |
|
---|
297 | static public String getDateString() {
|
---|
298 | Calendar current = Calendar.getInstance();
|
---|
299 | String day_name = null;
|
---|
300 | switch(current.get(Calendar.DAY_OF_WEEK)) {
|
---|
301 | case Calendar.MONDAY: day_name = "Dates.Mon"; break;
|
---|
302 | case Calendar.TUESDAY: day_name = "Dates.Tue"; break;
|
---|
303 | case Calendar.WEDNESDAY: day_name = "Dates.Wed"; break;
|
---|
304 | case Calendar.THURSDAY: day_name = "Dates.Thu"; break;
|
---|
305 | case Calendar.FRIDAY: day_name = "Dates.Fri"; break;
|
---|
306 | case Calendar.SATURDAY: day_name = "Dates.Sat"; break;
|
---|
307 | case Calendar.SUNDAY: day_name = "Dates.Sun"; break;
|
---|
308 | default: day_name = "";
|
---|
309 | }
|
---|
310 | String month_name = null;
|
---|
311 | switch(current.get(Calendar.MONTH)) {
|
---|
312 | case Calendar.JANUARY: month_name = "Dates.Jan"; break;
|
---|
313 | case Calendar.FEBRUARY: month_name = "Dates.Feb"; break;
|
---|
314 | case Calendar.MARCH: month_name = "Dates.Mar"; break;
|
---|
315 | case Calendar.APRIL: month_name = "Dates.Apr"; break;
|
---|
316 | case Calendar.MAY: month_name = "Dates.May"; break;
|
---|
317 | case Calendar.JUNE: month_name = "Dates.Jun"; break;
|
---|
318 | case Calendar.JULY: month_name = "Dates.Jul"; break;
|
---|
319 | case Calendar.AUGUST: month_name = "Dates.Aug"; break;
|
---|
320 | case Calendar.SEPTEMBER: month_name = "Dates.Sep"; break;
|
---|
321 | case Calendar.OCTOBER: month_name = "Dates.Oct"; break;
|
---|
322 | case Calendar.NOVEMBER: month_name = "Dates.Nov"; break;
|
---|
323 | case Calendar.DECEMBER: month_name = "Dates.Dec"; break;
|
---|
324 | default: month_name = "";
|
---|
325 | }
|
---|
326 | int day = current.get(Calendar.DAY_OF_MONTH);
|
---|
327 | int hour = current.get(Calendar.HOUR_OF_DAY);
|
---|
328 | int minute = current.get(Calendar.MINUTE);
|
---|
329 | int second = current.get(Calendar.SECOND);
|
---|
330 | int year = current.get(Calendar.YEAR);
|
---|
331 |
|
---|
332 | 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);
|
---|
333 | }
|
---|
334 |
|
---|
335 |
|
---|
336 | /** Determine this machines name.
|
---|
337 | * @return The name as a <strong>String</strong>.
|
---|
338 | */
|
---|
339 | static public String getMachineName() {
|
---|
340 | try {
|
---|
341 | return InetAddress.getLocalHost().getHostName();
|
---|
342 | }
|
---|
343 | catch(UnknownHostException ex) {
|
---|
344 | }
|
---|
345 | return "Unknown Machine";
|
---|
346 | }
|
---|
347 |
|
---|
348 |
|
---|
349 | static public String getSitesDir(String gsdl3_path) {
|
---|
350 | return gsdl3_path + "sites" + File.separator;
|
---|
351 |
|
---|
352 | }
|
---|
353 |
|
---|
354 |
|
---|
355 | /** Method to determine if the host system is MacOS based.
|
---|
356 | * @return a boolean which is true if the platform is MacOS, false otherwise
|
---|
357 | */
|
---|
358 | public static boolean isMac() {
|
---|
359 | Properties props = System.getProperties();
|
---|
360 | String os_name = props.getProperty("os.name","");
|
---|
361 | if(os_name.startsWith("Mac OS")) {
|
---|
362 | return true;
|
---|
363 | }
|
---|
364 | return false;
|
---|
365 | }
|
---|
366 |
|
---|
367 |
|
---|
368 | /** Method to determine if the host system is Microsoft Windows based.
|
---|
369 | * @return A <i>boolean</i> which is <i>true</i> if the platform is Windows, <i>false</i> otherwise.
|
---|
370 | */
|
---|
371 | public static boolean isWindows() {
|
---|
372 | Properties props = System.getProperties();
|
---|
373 | String os_name = props.getProperty("os.name","");
|
---|
374 | if(os_name.startsWith("Windows")) {
|
---|
375 | return true;
|
---|
376 | }
|
---|
377 | return false;
|
---|
378 | }
|
---|
379 |
|
---|
380 | public static boolean isWindows9x() {
|
---|
381 | Properties props = System.getProperties();
|
---|
382 | String os_name = props.getProperty("os.name","");
|
---|
383 | if(os_name.startsWith("Windows") && os_name.indexOf("9") != -1) {
|
---|
384 | return true;
|
---|
385 | }
|
---|
386 | return false;
|
---|
387 | }
|
---|
388 | /** Takes a string and a desired length and pads out the string to the length by adding spaces to the left.
|
---|
389 | * @param str The target <strong>String</strong> that needs to be padded.
|
---|
390 | * @param length The desired length of the string as an <i>int</i>.
|
---|
391 | * @return A <strong>String</strong> made from appending space characters with the string until it has a length equal to length.
|
---|
392 | */
|
---|
393 | static private String pad(String str_raw, int length, char fill, boolean end) {
|
---|
394 | StringBuffer str = new StringBuffer(str_raw);
|
---|
395 | while(str.length() < length) {
|
---|
396 | if(end) {
|
---|
397 | str.insert(0, fill);
|
---|
398 | }
|
---|
399 | else {
|
---|
400 | str.append(fill);
|
---|
401 | }
|
---|
402 | }
|
---|
403 | return str.toString();
|
---|
404 | }
|
---|
405 |
|
---|
406 |
|
---|
407 | static public StringBuffer readXMLStream(InputStream input_stream)
|
---|
408 | {
|
---|
409 | StringBuffer xml = new StringBuffer("");
|
---|
410 |
|
---|
411 | try {
|
---|
412 | InputStreamReader isr = new InputStreamReader(input_stream, "UTF-8");
|
---|
413 | BufferedReader buffered_in = new BufferedReader(isr);
|
---|
414 |
|
---|
415 | String line = "";
|
---|
416 | boolean xml_content = false;
|
---|
417 | while((line = buffered_in.readLine()) != null) {
|
---|
418 | if(xml_content) {
|
---|
419 | xml.append(line);
|
---|
420 | xml.append("\n");
|
---|
421 | }
|
---|
422 | else if(line.trim().startsWith("<?xml")) {
|
---|
423 | xml_content = true;
|
---|
424 | xml.append(line);
|
---|
425 | xml.append("\n");
|
---|
426 | }
|
---|
427 | }
|
---|
428 | buffered_in = null;
|
---|
429 | }
|
---|
430 | catch (Exception error) {
|
---|
431 | System.err.println("Failed when trying to parse XML stream");
|
---|
432 | error.printStackTrace();
|
---|
433 | }
|
---|
434 |
|
---|
435 | return xml;
|
---|
436 | }
|
---|
437 |
|
---|
438 |
|
---|
439 | /** I think this works a bit better on Unicode strings. */
|
---|
440 | static public String stripNL(String raw_string)
|
---|
441 | {
|
---|
442 | String stripped_string = new String();
|
---|
443 | for (int i = 0; i < raw_string.length(); i++) {
|
---|
444 | char raw_character = raw_string.charAt(i);
|
---|
445 | if (raw_character != '\n' && raw_character != '\t') {
|
---|
446 | stripped_string = stripped_string + raw_character;
|
---|
447 | }
|
---|
448 | }
|
---|
449 | return stripped_string;
|
---|
450 | }
|
---|
451 | }
|
---|