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

Last change on this file since 8084 was 8084, checked in by mdewsnip, 20 years ago

Fixed the help file loading so it works with the stand-alone version of the GLI as well as with the applet version.

  • Property svn:keywords set to Author Date Id Revision
File size: 54.5 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 */
37package org.greenstone.gatherer.util;
38
39import java.awt.*;
40import java.io.*;
41import java.net.*;
42import java.util.*;
43import java.util.zip.*;
44import javax.swing.*;
45import javax.swing.tree.*;
46import org.apache.xerces.parsers.*;
47import org.apache.xml.serialize.*;
48import org.greenstone.gatherer.Dictionary;
49import org.greenstone.gatherer.Gatherer;
50import org.greenstone.gatherer.util.HTMLStringTokenizer;
51import org.w3c.dom.*;
52import org.xml.sax.*;
53
54/** To provide a library of common methods, in a static context, for use in the Gatherer.
55 * @author John Thompson, Greenstone Digital Library, University of Waikato
56 * @version 2.3b
57 */
58public class Utility {
59 static final public Dimension BUTTON_SIZE = new Dimension(160, 35);
60 static final public Dimension DOUBLE_IMAGE_BUTTON_SIZE = new Dimension(190, 35);
61 static final public Dimension LABEL_SIZE = new Dimension(150, 25);
62 /** The default size of a gatherer progress bar, in either the download view or the build view. */
63 static final public Dimension PROGRESS_BAR_SIZE = new Dimension(580,65);
64 /** The number of kilobytes to use as a io buffer. */
65 static final public int FACTOR = 1;
66 /** The size of the io buffer, calculated as FACTOR * 1024. */
67 static final public int BUFFER_SIZE = FACTOR * 1024;
68 /** Definition of an important directory name, in this case the archives directory of the collection. */
69 static final public String ARCHIVES_DIR = "archives" + File.separator;
70 /** Definition of an important directory name, in this case the base dir, or the working directory of the Gatherer. */
71 static public String BASE_DIR = System.getProperty("user.dir") + File.separator;
72 static final public String BUILD_CFG_FILENAME = "build.cfg";
73 /** Definition of an important directory name, in this case the building directory for the collection. */
74 static final public String BUILD_DIR = "building" + File.separator;
75 /** Definition of an important directory name, in this case the public web cache for the Gatherer. */
76 static public String CACHE_DIR = BASE_DIR + "cache" + File.separator;
77 static final public String CFG_COLLECTIONMETA_COLLECTIONNAME = "collectionmeta\tcollectionname";
78 static final public String CFG_COLLECTIONMETA_COLLECTIONEXTRA = "collectionmeta\tcollectionextra";
79 static final public String CFG_COLLECTIONMETA_ICONCOLLECTION = "collectionmeta\ticoncollection";
80 static final public String CFG_CLASSIFY = "classify";
81 static final public String CFG_CLASSIFY_BUTTONNAME = "-buttonname";
82 static final public String CFG_CLASSIFY_HFILE = "-hfile";
83 static final public String CFG_CLASSIFY_METADATA = "-metadata";
84 static final public String CFG_CLASSIFY_SORT = "-sort";
85 static final public String CFG_CREATOR = "creator";
86 static final public String CFG_FORMAT = "format";
87 static final public String CFG_MAINTAINER = "maintainer";
88 /** Definition of an important directory name, in this case the parent directory of all the collections in the gsdl. */
89 static final public String COL_DIR = "collect" + File.separator;
90 static final public String COLLECTION_TREE = "Collection";
91 /** Definition of an important directory name, in this case the file the collection configuration is expect to be in. */
92 static final public String CONFIG_FILE = "etc" + File.separator + "collect.cfg";
93 /** The default file name for the urls missing any file. */
94 static final public String DEFAULT_FILE = "index.html";
95 /** The default protocol header for those urls missing any protocol. */
96 static final public String DEFAULT_PROTOCOL = "http://";
97 /** The default dictionary to load. */
98 static final public String DICTIONARY = "dictionary";
99 static final public String ENCODING = "UTF-8";
100 static final public String ENGLISH_VALUE = "en";
101 /** Definition of an important directory name, in this case the etc (or extra information) directory for the collection. */
102 static final public String ETC_DIR = "etc" + File.separator;
103 static final public String EXTRACTED_METADATA_NAMESPACE = "ex";
104 /** The location of the default greenstone metadata file. */
105 static final public String GREENSTONEDIRECTORYMETADATA_TEMPLATE = "xml/metadata.xml";
106 /** Definition of an important directory name, in this case the private web cache directory for the collection. */
107 static final public String GCACHE_DIR = "cache" + File.separator;
108 static final public String GLI_ARCHIVE = "GLI.jar";
109 static final public String GLI_EXTENSION = ".col";
110 /** Definition of an important directory name, in this case the location of help documentation. */
111 static public String HELP_DIR = BASE_DIR + "help" + File.separator;
112 /** Definition of an important directory name, in this case the images directory for the collection. */
113 static final public String IMAGES_DIR = "images" + File.separator;
114 /** Definition of an important directory name, in this case the import directory for the collection. */
115 static final public String IMPORT_DIR = "import" + File.separator;
116 /** Definition of an important directory name, in this case the backup import directory for the collection. */
117 static final public String IMPORT_BAK_DIR = "import.bak" + File.separator;
118 /** Definition of an important directory name, in this case the index directory for the collection. */
119 static final public String INDEX_DIR = "index" + File.separator;
120 static final public String LANGUAGE_ATTRIBUTE = "language";
121 /** Definition of an important directory name, in this case the log directory for the collection. */
122 static final public String LOG_DIR = "log" + File.separator;
123 /** Definition of an important directory name, in this case the macros directory for the collection. */
124 static final public String MACROS_DIR = "macros" + File.separator;
125 /** Definition of an important directory name, in this case the location of the expected collection metadata sets.. */
126 static final public String META_DIR = "metadata" + File.separator; // Col. Copy
127 /** Definition of an important directory name, in this case the location of the default metadata sets. */
128 static public String METADATA_DIR = BASE_DIR + "metadata" + File.separator;
129 /** Definition of an important zip file, in this case zipped up version of metadata file stored in JAR file */
130 static final public String METADATA_ZIP = "metadata.zip";
131 /** The location the gatherer expects to find metadata set information. */
132 static final public String METADATA_SET_TEMPLATE = "xml/template.mds";
133 static final public String METADATA_VALUE_TEMPLATE = "xml/template.mdv";
134 static final public String METADATA_XML = "metadata.xml";
135 static final public String NAME_ELEMENT = "Name";
136 /** The default name of the perl executable under unix. */
137 static final public String PERL_EXECUTABLE_UNIX = "perl";
138 /** The default name of the perl executable under windows. */
139 static final public String PERL_EXECUTABLE_WINDOWS = "Perl.exe";
140 /** The default profile file */
141 static final public String PROFILE_TEMPLATE = "xml/protemp.xml";
142 /** The name of the Gatherer. */
143 static final public String PROGRAM_NAME = "Greenstone Librarian Interface";
144 /** The current version of the Gatherer. */
145 static final public String PROGRAM_VERSION = "v2.51";
146 /** Definition of an important directory name, in this case the location of the recycled files location. */
147 static public String RECYCLE = BASE_DIR + "recycle" + File.separator;
148 /** Definition of an important directory name, in this case the location of image and other resources. */
149 static public String RES_DIR = BASE_DIR + "resource" + File.separator;
150 static final public String SERVER_EXE = "server.exe";
151 /** Definition of an important directory name, in this case the location of opening (or welcome) screen html. */
152 static public String WELCOME_DIR = BASE_DIR + "welcome" + File.separator;
153 static final public String WORKSPACE_TREE = "Workspace";
154 static final public String XML_DIRECTORY = "xml" + File.separator;
155
156 // These are out of alphabetic order to avoid forward reference error.
157 /** The default icon to produce a 'help-icon' sized blank space before a menu entry. */
158 static public Class base = null;
159 static public ImageIcon BLANK_ICON = null;
160 /** The default error icon image. */
161 static public ImageIcon ERROR_ICON = null;
162 static public ImageIcon HELP_ICON = null;
163 /** The image for a toggle button whose state is 'on'. */
164 static public ImageIcon ON_ICON = null;
165 /** The image for a toggle button whose state is 'off'. */
166 static public ImageIcon OFF_ICON = null;
167
168 /** Decodes a string of text so its safe to use in a Greenstone configuration file. Esentially replaces "\n" with a newline.
169 * @param raw The <strong>String</strong> before decoding, read from the configuration file..
170 * @return A <strong>String</strong> ready to be placed in a component.
171 */
172 static public String decodeGreenstone(String raw) {
173 raw = raw.replaceAll("&apos;", "\'");
174 raw = raw.replaceAll("&gt;", ">");
175 raw = raw.replaceAll("&lt;", "<");
176 raw = raw.replaceAll("&quot;", "\"");
177 raw = raw.replaceAll("&#39;", "\'");
178 raw = raw.replaceAll("\\\\n", "\n");
179 return raw;
180 }
181
182 /** Takes a rfc2616 'safe' String and translates it back into its 'unsafe' form. Basically the native c wget decode_string() function, but without pointer stuff. If searches through the String looking for the pattern %xy where x and y are hexidecimal digits and where xy maps to a character.<BR> If x or y are not hexidecimal or % is followed by a \0 then the pattern is left as is.
183 * @param encoded The url-safe <strong>String</strong> to be decoded.
184 * @return The decoded <strong>String</strong>.
185 */
186 /* private static String decodeString(String encoded) {
187 String decoded = "";
188 for(int i = 0; i < encoded.length(); i++) {
189 if(encoded.charAt(i) == '%') {
190 if(hexidecimal(encoded.charAt(i+1)) != -1
191 && hexidecimal(encoded.charAt(i+2)) != -1) {
192 char unsafe_chr = (char)
193 ((hexidecimal(encoded.charAt(i+1)) * 16) +
194 hexidecimal(encoded.charAt(i+2)));
195 decoded = decoded + unsafe_chr;
196 i = i + 2;
197 }
198 }
199 else {
200 decoded = decoded + encoded.charAt(i);
201 }
202 }
203 return decoded;
204 } */
205
206 /** It turns out that in Java you have to make sure a directory is empty before you delete it (much like unix I suppose), and so just like unix I'll have to set up a recursive delete function.
207 * @param file The <strong>File</strong> you want to delete.
208 * @return A <i>boolean</i> which is <i>true</i> if the file specified was successfully deleted, <i>false</i> otherwise.
209 */
210 static public boolean delete(File file) {
211 boolean result = true;
212 // If file is a directory, delete the file's children.
213 if(file.isDirectory()) {
214 File files[] = file.listFiles();
215 for(int i = 0; files != null && result && i < files.length; i++) {
216 result = delete(files[i]);
217 }
218 }
219 if(result) {
220 // Delete file.
221 return file.delete();
222 }
223 return result;
224 }
225
226 static public boolean delete(String filename) {
227 return delete(new File(filename));
228 }
229
230
231 /** Using this method we can request that a certain document be written, as valid XML, to a certain output stream. This makes use of the Xerces Serialization suite, which should in no way be confused with the usual method of Serialization used by Java. */
232 static public boolean export(Document document, String filename) {
233 return export(document, new File(filename));
234 }
235
236 static public boolean export(Document document, File file) {
237 try {
238 OutputStream os = new FileOutputStream(file);
239 // Create an output format for our document.
240 OutputFormat f = new OutputFormat(document);
241 f.setEncoding(ENCODING);
242 f.setIndenting(true);
243 f.setLineWidth(0); // Why isn't this working!
244 f.setPreserveSpace(false);
245 // Create the necessary writer stream for serialization.
246 OutputStreamWriter osw = new OutputStreamWriter(os, ENCODING);
247 Writer w = new BufferedWriter(osw);
248 // Generate a new serializer from the above.
249 XMLSerializer s = new XMLSerializer(w, f);
250 s.asDOMSerializer();
251 // Finally serialize the document to file.
252 s.serialize(document);
253 // And close.
254 os.close();
255 return true;
256 }
257 // A file not found exception is most likely thrown because the directory the metadata.xml file is attempting to be written to no longer has any files in it. I'll add a test in MetadataXMLFile to test for this, but if it still happens ignore it (a non-existant directory can't really have metadata added to it any way.
258 catch (Exception exception) {
259 if(!file.getName().endsWith(METADATA_XML)) {
260 Gatherer.printStackTrace(exception);
261 return false;
262 }
263 return true;
264 }
265 }
266
267 /** Convert a long, detailing the length of a file in bytes, into a nice human readable string using b, kb, Mb and Gb. */
268 static final public String BYTE_SUFFIX = " b";
269 static final public long GIGABYTE = 1024000000l;
270 static final public String GIGABYTE_SUFFIX = " Gb";
271 static final public long KILOBYTE = 1024l;
272 static final public String KILOBYTE_SUFFIX = " kb";
273 static final public long MEGABYTE = 1024000l;
274 static final public String MEGABYTE_SUFFIX = " mb";
275 static final public String formatFileLength(long length) {
276 StringBuffer result = new StringBuffer("");
277 float number = 0f;
278 String suffix = null;
279 // Determine the floating point number and the suffix (radix) used.
280 if(length >= GIGABYTE) {
281 number = (float) length / (float) GIGABYTE;
282 suffix = GIGABYTE_SUFFIX;
283 }
284 else if(length >= MEGABYTE) {
285 number = (float) length / (float) MEGABYTE;
286 suffix = MEGABYTE_SUFFIX;
287 }
288 else if(length >= KILOBYTE) {
289 number = (float) length / (float) KILOBYTE;
290 suffix = KILOBYTE_SUFFIX;
291 }
292 else {
293 // Don't need to do anything fancy if the file is smaller than a kilobyte
294 return length + BYTE_SUFFIX;
295 }
296 // 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.
297 String number_str = Float.toString(number);
298 char number_char[] = number_str.toCharArray();
299 int pos = 0;
300 // Print the characters up to the '.'
301 while(number_char != null && pos < number_char.length && number_char[pos] != '.') {
302 result.append(number_char[pos]);
303 pos++;
304 }
305 if(pos < number_char.length) {
306 // Print the '.' and at most two characters after it
307 result.append(number_char[pos]);
308 pos++;
309 for(int i = 0; i < 2 && pos < number_char.length; i++, pos++) {
310 result.append(number_char[pos]);
311 }
312 // Search through the remaining string for 'E'
313 while(pos < number_char.length && number_char[pos] != 'E') {
314 pos++;
315 }
316 // If we still have string then we found an E. Copy the remaining string.
317 while(pos < number_char.length) {
318 result.append(number_char[pos]);
319 pos++;
320 }
321 }
322 // Add suffix
323 result.append(suffix);
324 // Done
325 return result.toString();
326 }
327
328 /** This method formats a given string, using HTML markup, so its width does not exceed the given width and its appearance if justified.
329 * @param text The <strong>String</strong> requiring formatting.
330 * @param width The maximum width per line as an <i>int</i>.
331 * @return A <strong>String</strong> formatted so as to have no line longer than the specified width.
332 * 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.
333 */
334 static public String formatHTMLWidth(String text, int width) {
335 if(text == null) {
336 return "Error";
337 }
338 HTMLStringTokenizer html = new HTMLStringTokenizer(text);
339 int current_width = 0;
340 int threshold = width / 2;
341 Stack lines = new Stack();
342 String line = "";
343 while(html.hasMoreTokens()) {
344 String token = html.nextToken();
345 while(token != null) {
346 if(html.isTag()) {
347 // Insert smart HTML tag code here.
348 token = null;
349 }
350 else {
351 // If the token is bigger than two thirds width, before we've even started break it down.
352 if(current_width + 1 + token.length() > width && token.length() > threshold) {
353 if(width == current_width) {
354 lines.push(line);
355 line = token;
356 current_width = token.length();
357 }
358 else {
359 String prefix = token.substring(0, width - 1 - current_width);
360 token = token.substring(prefix.length());
361 if(current_width == 0) {
362 line = line + prefix;
363 }
364 else {
365 line = line + " " + prefix;
366 }
367 lines.push(line);
368 line = "";
369 current_width = 0;
370 }
371 }
372 // If adding the next token would push us over the maximum line width.
373 else if(current_width + 1 + token.length() > width) {
374 line = space(line, width, current_width);
375 lines.push(line);
376 line = token;
377 current_width = token.length();
378 token = null;
379 }
380 // Otherwise we should be able to just add the token, give or take.
381 else {
382 if(current_width == 0) {
383 line = line + token;
384 current_width = token.length();
385 }
386 else {
387 // Special case for standard punctuation which may exist after a tag like so:
388 // My name is <scratchy>Slim Shady</scratchy>. <-- Annoying punctuation.
389 if(token.equals(".") || token.equals(",") || token.equals("!") || token.equals("?")) {
390 line = line + token;
391 current_width = current_width + 1;
392 }
393 else {
394 line = line + " " + token;
395 current_width = current_width + 1 + token.length();
396 }
397 }
398 token = null;
399 }
400 }
401 }
402 }
403 String result = line;
404 while(!lines.empty()) {
405 result = (String)lines.pop() + "<BR>" + result;
406 }
407 // Replace ' ' with "&nbsp;"
408 boolean tag = false;
409 int pos = 0;
410 while(pos < result.length()) {
411 if(result.charAt(pos) == '<') {
412 tag = true;
413 }
414 else if(result.charAt(pos) == '>') {
415 tag = false;
416 }
417 else if(result.charAt(pos) == ' ' && !tag) {
418 String prefix = result.substring(0, pos);
419 String suffix = result.substring(pos + 1);
420 result = prefix + "&nbsp;" + suffix;
421 }
422 pos++;
423 }
424 result = "<HTML>" + result + "</HTML>";
425 return result;
426 }
427 /** Format the given filename path string so that it is no longer than the given width. If it is wider replace starting directories with ...
428 * @param key The key <strong>String</Strong> used to retrieve a phrase from the dictionary for this item.
429 * @param raw The raw filename path <strong>String</strong>.
430 * @param width The maximum width as an <i>int</i>.
431 * @return A path <strong>String</strong> no longer than width.
432 */
433 static public String formatPath(String key, String raw, int width) {
434 JLabel label = new JLabel(Dictionary.get(key, raw));
435 int position = -1;
436 while(label.getPreferredSize().width > width && (position = raw.indexOf(File.separator)) != -1) {
437 raw = "..." + raw.substring(position + 1);
438 label.setText(Dictionary.get(key, raw));
439 }
440 if(raw.indexOf(File.separator) == -1 && raw.startsWith("...")) {
441 raw = raw.substring(3);
442 }
443 return raw;
444 }
445
446 /** Method which constructs the archive directory given a certain collection.
447 * @param gsdl_path The location of the collection directory as a <strong>String</strong>.
448 * @return The location of the given collections archive directory, also as a <strong>String</strong>.
449 */
450 static public String getArchiveDir(String col_dir) {
451 return col_dir + ARCHIVES_DIR;
452 }
453
454 /** Method which constructs the build directory given a certain collection.
455 * @param col_dir The location of the collection directory as a <strong>String</strong>.
456 * @return The location of the given collections build directory, also as a <strong>String</strong>.
457 */
458 static public String getBuildDir(String col_dir) {
459 if(col_dir == null) {
460 return BASE_DIR + BUILD_DIR;
461 }
462 return col_dir + BUILD_DIR;
463 }
464 /** Builds the cache dir by appending the user path and 'cache'.
465 * @return a File representing the path to the private file cache within the current collection.
466 */
467 public static File getCacheDir() {
468 return new File(getGLIUserFolder(), StaticStrings.CACHE_FOLDER);
469 }
470 /** Method which constructs the collect directory for Greenstone.
471 * @param gsdl_path The location of the gsdl installation directory as a <strong>String</strong>.
472 * @return The location of the collection directory, also as a <strong>String</strong>.
473 */
474 public static String getCollectDir(String gsdl_path) {
475 return gsdl_path + COL_DIR;
476 }
477 static public String getCollectDir(String gsdl3_path, String site_name) {
478 return getSitesDir(gsdl3_path) + site_name + File.separator + COL_DIR;
479 }
480
481
482 /** Method which constructs a collection's top level directory
483 * @@param gsdl_path The location of the gsdl installation directory as a <strong>String</strong>.
484 * @param The name of the collection as a <strong>String</strong>.
485 * @return The location of the collection's base directory
486 */
487 public static String getCollectionDir(String gsdl_path, String coll_name) {
488 return getCollectDir(gsdl_path) + coll_name + File.separator;
489 }
490 public static String getCollectionDir(String gsdl3_path, String site_name, String coll_name) {
491 return getCollectDir(gsdl3_path, site_name) + coll_name + File.separator;
492 }
493
494 public static String getCollectionDir() {
495 String this_col_dir;
496
497 String col_name = Gatherer.c_man.getCollection().getName();
498
499 if (Gatherer.GS3) {
500 this_col_dir = getCollectionDir(Gatherer.config.gsdl3_path, Gatherer.config.site_name, col_name);
501 } else {
502 this_col_dir = getCollectionDir(Gatherer.config.gsdl_path, col_name);
503
504 }
505
506 return this_col_dir;
507 }
508
509
510 /** Method which constructs the configuration file given a certain collection.
511 * @param col_dir The location of the collection directory as a <strong>String</strong>.
512 * @return The location of the given collections configuration file, also as a <strong>String</strong>.
513 */
514 static public String getConfigFile(String col_dir) {
515 return col_dir + CONFIG_FILE;
516 }
517
518 static public String getDateString() {
519 Calendar current = Calendar.getInstance();
520 String day_name = null;
521 switch(current.get(Calendar.DAY_OF_WEEK)) {
522 case Calendar.MONDAY: day_name = "Dates.Mon"; break;
523 case Calendar.TUESDAY: day_name = "Dates.Tue"; break;
524 case Calendar.WEDNESDAY: day_name = "Dates.Wed"; break;
525 case Calendar.THURSDAY: day_name = "Dates.Thu"; break;
526 case Calendar.FRIDAY: day_name = "Dates.Fri"; break;
527 case Calendar.SATURDAY: day_name = "Dates.Sat"; break;
528 case Calendar.SUNDAY: day_name = "Dates.Sun"; break;
529 default: day_name = "";
530 }
531 String month_name = null;
532 switch(current.get(Calendar.MONTH)) {
533 case Calendar.JANUARY: month_name = "Dates.Jan"; break;
534 case Calendar.FEBRUARY: month_name = "Dates.Feb"; break;
535 case Calendar.MARCH: month_name = "Dates.Mar"; break;
536 case Calendar.APRIL: month_name = "Dates.Apr"; break;
537 case Calendar.MAY: month_name = "Dates.May"; break;
538 case Calendar.JUNE: month_name = "Dates.Jun"; break;
539 case Calendar.JULY: month_name = "Dates.Jul"; break;
540 case Calendar.AUGUST: month_name = "Dates.Aug"; break;
541 case Calendar.SEPTEMBER: month_name = "Dates.Sep"; break;
542 case Calendar.OCTOBER: month_name = "Dates.Oct"; break;
543 case Calendar.NOVEMBER: month_name = "Dates.Nov"; break;
544 case Calendar.DECEMBER: month_name = "Dates.Dec"; break;
545 default: month_name = "";
546 }
547 int day = current.get(Calendar.DAY_OF_MONTH);
548 int hour = current.get(Calendar.HOUR_OF_DAY);
549 int minute = current.get(Calendar.MINUTE);
550 int second = current.get(Calendar.SECOND);
551 int year = current.get(Calendar.YEAR);
552
553 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);
554 }
555
556
557 /** Method which constructs the etc directory given a certain collection.
558 * @param col_dir The location of the collection directory as a <strong>String</strong>.
559 * @return The location of the given collections etc directory, also as a <strong>String</strong>.
560 */
561 public static String getEtcDir(String col_dir) {
562 return col_dir + ETC_DIR;
563 }
564
565 static final private String APPLICATION_DATA_FOLDER = "Application Data";
566 static final private String UNIX_GLI_CONFIG_FOLDER = ".gli";
567 static final private String USER_HOME_PROPERTY = "user.home";
568 static final private String WIN_GLI_CONFIG_FOLDER = "Greenstone" + File.separator + "GLI";
569
570 static public File getGLIUserFolder() {
571 File gli_user_folder = null;
572 if(Utility.isWindows()) {
573 gli_user_folder = new File(System.getProperty(USER_HOME_PROPERTY) + File.separator + APPLICATION_DATA_FOLDER + File.separator + WIN_GLI_CONFIG_FOLDER + File.separator);
574 }
575 else {
576 gli_user_folder = new File(System.getProperty(USER_HOME_PROPERTY) + File.separator + UNIX_GLI_CONFIG_FOLDER + File.separator);
577 }
578 return gli_user_folder;
579 }
580
581 /** Retrieve the full file path to the help index xml file.
582 * @return the full path as a String
583 */
584 static public String getHelpFolder() {
585
586 String help_folder = "help/" + Gatherer.config.getLanguage() + "/";
587
588 // Try in the JAR/classes directory first
589 URL help_folder_url = base.getResource("/" + help_folder);
590 if (help_folder_url != null) {
591 return help_folder;
592 }
593
594 // Look in the base directory next
595 File help_folder_file = new File(help_folder);
596 if (help_folder_file.exists()) {
597 return help_folder;
598 }
599
600 // Resort to English
601 return "help/" + StaticStrings.ENGLISH_LANGUAGE_STR + "/";
602 }
603
604 /** Method to retrieve an image icon with the given filename found in classpath or the resouces directory.
605 * @return The specified <strong>ImageIcon</strong>, or an error image replacement if no such images exists.
606 */
607 static public ImageIcon getImage(String filename) {
608 return getImage(filename, false);
609 }
610
611 static public ImageIcon getImage(String filename, boolean wait_until_complete) {
612 ImageIcon image = null;
613 try {
614 image = new ImageIcon(base.getResource("/images/" + Dictionary.get("Version") + "/" + filename));
615 }
616 catch(NullPointerException exception) {
617 image = new ImageIcon(base.getResource("/images/" + filename));
618 }
619 if(image == null) {
620 image = ERROR_ICON;
621 }
622
623 if(wait_until_complete) {
624 int load_status;
625 do {
626 load_status = image.getImageLoadStatus();
627 }
628 while(load_status != MediaTracker.ABORTED && load_status != MediaTracker.ERRORED && load_status != MediaTracker.COMPLETE);
629 }
630 return image;
631 }
632
633 /** Method which constructs the images directory given a certain collection.
634 * @param col_dir The location of the collection directory as a <strong>String</strong>.
635 * @return The location of the given collections images directory, also as a <strong>String</strong>.
636 */
637 public static String getImagesDir(String col_dir) {
638 return col_dir + IMAGES_DIR;
639 }
640 /** Method which constructs the import directory given a certain collection.
641 * @param col_dir The location of the collection directory as a <strong>String</strong>.
642 * @return The location of the given collections import directory, also as a <strong>String</strong>.
643 */
644 public static String getImportDir(String col_dir) {
645 return col_dir + IMPORT_DIR;
646 }
647 /** Method which constructs the index directory given a certain collection.
648 * @param col_dir The location of the collection directory as a <strong>String</strong>.
649 * @return The location of the given collections index directory, also as a <strong>String</strong>.
650 */
651 static public String getIndexDir(String col_dir) {
652 return col_dir + INDEX_DIR;
653 }
654 /** Method which constructs the log directory given a certain collection.
655 * @param col_dir The location of the collection directory as a <strong>String</strong>.
656 * @return The location of the given collections log directory, also as a <strong>String</strong>.
657 */
658 public static String getLogDir(String col_dir) {
659 if(col_dir != null) {
660 return col_dir + LOG_DIR;
661 }
662 else {
663 return getGLIUserFolder().getAbsolutePath() + File.separator + LOG_DIR;
664 }
665 }
666 /** Determine this machines name.
667 * @return The name as a <strong>String</strong>.
668 */
669 static public String getMachineName() {
670 try {
671 return InetAddress.getLocalHost().getHostName();
672 }
673 catch(UnknownHostException ex) {
674 }
675 return "Unknown Machine";
676 }
677 /** Method which constructs the metadata directory given a certain collection.
678 * @param col_dir The location of the collection directory as a <strong>String</strong>.
679 * @return The location of the given collections metadata directory, also as a <strong>String</strong>.
680 */
681 static public String getMetadataDir(String col_dir) {
682 return col_dir + META_DIR;
683 }
684
685 static public void extractFromJar(String filename, String dst_dir, boolean must_be_present)
686 {
687 try {
688 // setup input stream for slurping out file
689 InputStream fis = base.getResourceAsStream("/"+filename);
690 BufferedInputStream fbis = new BufferedInputStream(fis);
691 DataInputStream fdbis = new DataInputStream(fbis);
692
693 // set up output stream for writing to disk
694 String ofname = dst_dir + filename;
695 FileOutputStream fos = new FileOutputStream(ofname);
696 BufferedOutputStream bfos = new BufferedOutputStream(fos);
697
698 byte[] buf = new byte[1024];
699 int len;
700 int total_bytes = 0;
701 while ((len = fdbis.read(buf)) >= 0) {
702 bfos.write(buf,0,len);
703 total_bytes += len;
704 }
705
706 fdbis.close();
707 bfos.close();
708 }
709 catch (Exception error) {
710 if (must_be_present) {
711 error.printStackTrace();
712 }
713 }
714 }
715
716
717 /** Method which unzips a given metadata resoure
718 * @param zip_fname The name of the zip file as a <strong>String</strong>.
719 * @param dst_dir The destination directory for unzipping, also as a <strong>String</strong>.
720 * @param use_classloader Used to determine whether or not to look in resource bundle.
721 */
722 static public void unzipFromJar(String jar_zip_fname, String dst_dir) {
723
724 File file = null;
725 if (!dst_dir.endsWith(File.separator)) {
726 dst_dir += File.separator;
727 }
728
729 extractFromJar(jar_zip_fname,dst_dir,true);
730
731 String zip_ofname = dst_dir + jar_zip_fname;
732 File zip_file = new File(zip_ofname);
733
734 try {
735 ZipFile zipfile = new ZipFile(zip_file);
736
737 Enumeration e = zipfile.entries();
738 while (e.hasMoreElements()) {
739 ZipEntry zipentry = (ZipEntry) e.nextElement();
740 String zentryname = dst_dir + zipentry.getName();
741 Gatherer.println(" Unzipping: " + zentryname);
742
743 if (zipentry.isDirectory()) {
744 // Create named directory
745 boolean success = (new File(zentryname)).mkdir();
746 if (!success) {
747 System.err.println("Error: unable to create directory '"+zentryname+"'");
748 }
749 }
750 else {
751 // Write out file to disk
752
753 // set up input stream
754 InputStream zis = zipfile.getInputStream(zipentry);
755 BufferedInputStream bzis = new BufferedInputStream(zis);
756 DataInputStream dbzis = new DataInputStream(bzis);
757
758 // set up output stream
759 FileOutputStream fzos = new FileOutputStream(zentryname);
760 BufferedOutputStream bfzos = new BufferedOutputStream(fzos);
761
762 byte[] buf = new byte[1024];
763 int len;
764 while ((len = dbzis.read(buf)) >= 0) {
765 bfzos.write(buf,0,len);
766 }
767
768 dbzis.close();
769 bfzos.close();
770 }
771 }
772 }
773 catch (ZipException error) {
774 System.err.println("Error: Unable to open '"+zip_file.getAbsolutePath()+"'");
775 Gatherer.printStackTrace(error);
776 }
777
778 catch (Exception error) {
779 error.printStackTrace();
780 }
781 }
782
783
784 static public void download_url_zip(String col_name, String dir)
785 {
786 try {
787 String download_cgi = Gatherer.cgiBase + "download";
788
789 // Send col_name and dir arguments to download cgi
790
791 String col_name_encoded = URLEncoder.encode(col_name,"UTF-8");
792 String dir_encoded = URLEncoder.encode(dir,"UTF-8");
793 String cgi_args = "c=" + col_name_encoded;
794 cgi_args += "&dir=" + dir_encoded;
795
796 URL download_url = new URL(download_cgi);
797
798 System.err.println("**** download cgi = '" + download_cgi + "'");
799 System.err.println("**** cgi args = '" + cgi_args + "'");
800
801 URLConnection dl_connection = download_url.openConnection();
802 dl_connection.setDoOutput(true);
803 OutputStream dl_os = dl_connection.getOutputStream();
804
805 PrintWriter dl_out = new PrintWriter(dl_os);
806 dl_out.println(cgi_args);
807 dl_out.close();
808
809 // Download result from running cgi script
810 InputStream dl_is = dl_connection.getInputStream();
811 BufferedInputStream dl_bis = new BufferedInputStream(dl_is);
812 DataInputStream dl_dbis = new DataInputStream(dl_bis);
813
814 // set up output stream for zip download
815 String col_dir = Utility.getCollectDir(Gatherer.config.gsdl_path);
816 String zip_fname = col_dir + col_name + ".zip";
817 FileOutputStream zip_fos = new FileOutputStream(zip_fname);
818 BufferedOutputStream zip_bfos = new BufferedOutputStream(zip_fos);
819
820 byte[] buf = new byte[1024];
821 int len;
822
823 while ((len = dl_dbis.read(buf)) >= 0) {
824 zip_bfos.write(buf,0,len);
825 }
826
827 dl_dbis.close();
828 zip_bfos.close();
829
830 }
831 catch (Exception error) {
832 error.printStackTrace();
833 }
834 }
835
836
837 static public void upload_url_zip(String col_name, String dir)
838 {
839 final String lineEnd = "\r\n";
840 final String twoHyphens = "--";
841 final String boundary = "*****";
842 final int maxBufferSize = 1024;
843
844 String col_dir = Utility.getCollectDir(Gatherer.config.gsdl_path);
845 String zip_fname = col_dir + col_name + ".zip";
846 String upload_cgi = Gatherer.cgiBase + "upload";
847
848 HttpURLConnection conn = null;
849
850 try {
851 // Send zip file to server
852
853 File file = new File(zip_fname) ;
854 FileInputStream fileInputStream = new FileInputStream(file);
855
856 // open a URL connection to the Servlet
857 URL url = new URL(upload_cgi);
858 System.err.println("**** Uploading to: " + upload_cgi);
859
860 // Open a HTTP connection to the URL
861 conn = (HttpURLConnection) url.openConnection();
862
863 conn.setDoInput(true); // Allow Inputs
864 conn.setDoOutput(true); // Allow Outputs
865 conn.setUseCaches(false); // Don't use a cached copy.
866 conn.setRequestMethod("POST"); // Use a post method.
867
868 conn.setRequestProperty("Connection", "Keep-Alive");
869 conn.setRequestProperty("Content-Type", "multipart/form-data;boundary="+boundary);
870
871 DataOutputStream dos = new DataOutputStream( conn.getOutputStream() );
872
873 dos.writeBytes(twoHyphens + boundary + lineEnd);
874 dos.writeBytes("Content-Disposition: form-data; name=\"c\"" + lineEnd + lineEnd);
875 dos.writeBytes(col_name + lineEnd);
876 System.err.println("**** c="+col_name);
877
878 dos.writeBytes(twoHyphens + boundary + lineEnd);
879 dos.writeBytes("Content-Disposition: form-data; name=\"dir\"" + lineEnd + lineEnd);
880 dos.writeBytes(dir + lineEnd);
881 System.err.println("**** dir="+dir);
882
883 dos.writeBytes(twoHyphens + boundary + lineEnd);
884 dos.writeBytes("Content-Disposition: form-data; name=\"zip\";"
885 + " filename=\"" + zip_fname +"\"" + lineEnd);
886 dos.writeBytes(lineEnd);
887 System.err.println("**** zip (filename)="+zip_fname);
888
889 // create a buffer of maximum size
890 int bytesAvailable = fileInputStream.available();
891 int bufferSize = Math.min(bytesAvailable, maxBufferSize);
892 byte[] buffer = new byte[bufferSize];
893
894 // read file and write it into form...
895 int bytesRead = fileInputStream.read(buffer, 0, bufferSize);
896
897 while (bytesRead > 0) {
898 dos.write(buffer, 0, bufferSize);
899 bytesAvailable = fileInputStream.available();
900 bufferSize = Math.min(bytesAvailable, maxBufferSize);
901 bytesRead = fileInputStream.read(buffer, 0, bufferSize);
902 }
903
904 // send multipart form data necesssary after file data...
905
906 dos.writeBytes(lineEnd);
907 dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
908
909 // close streams
910
911 fileInputStream.close();
912 dos.flush();
913 dos.close();
914
915
916 }
917 catch (MalformedURLException ex) {
918 System.err.println("Failed on: "+ex);
919 }
920
921 catch (IOException ioe) {
922 System.err.println("Failed on: "+ioe);
923 }
924
925 // Read server response
926
927 try {
928 InputStreamReader isr = new InputStreamReader(conn.getInputStream() );
929 BufferedReader bisr = new BufferedReader (isr);
930 String str;
931 while (( str = bisr.readLine()) != null) {
932 System.err.println(str);
933 }
934 bisr.close();
935
936 }
937 catch (IOException ioex) {
938 System.err.println("From (ServerResponse): "+ioex);
939 }
940 }
941
942 static protected String unixStylePath(String path)
943 {
944 String unix_path = path.replace('\\','/');
945 return unix_path;
946 }
947
948 static protected void zipFunc (ZipOutputStream zos, String file_path, int prefix_strip)
949 {
950 // Using try is required because of file io.
951 try {
952 // Create a Zip Entry and put it into the archive (no data yet).
953
954 // Strip off col_dir prefix
955 String zip_path = file_path.substring(prefix_strip);
956 // Zip files use '/' for directory separator
957 String unix_style_path = unixStylePath(zip_path);
958 ZipEntry fileEntry = new ZipEntry(unix_style_path);
959 zos.putNextEntry(fileEntry);
960
961 // Create a file input stream and a buffered input stream.
962 FileInputStream fis = new FileInputStream(file_path);
963 BufferedInputStream bis = new BufferedInputStream(fis);
964
965 // Create a byte array object named data and declare byte count variable.
966 byte[] data = new byte[1024];
967 int byteCount;
968 // Create a loop that reads from the buffered input stream and writes
969 // to the zip output stream until the bis has been entirely read.
970 while ((byteCount = bis.read(data, 0, 1024)) > -1) {
971 zos.write(data, 0, byteCount);
972 }
973 }
974 catch (IOException e) {
975 e.printStackTrace();
976 }
977
978 Gatherer.println(" Zipping up: " + file_path);
979 }
980
981 static protected void dirFunc (ZipOutputStream zos, String dir_name, int prefix_strip)
982 {
983 File dirObj = new File(dir_name);
984
985 if (dirObj.exists() == true) {
986 if (dirObj.isDirectory() == true) {
987 // Create an array of File objects, one for each file or directory in dirObj.
988 File [] fileList = dirObj.listFiles();
989
990 // Loop through File array and display.
991 for (int i = 0; i < fileList.length; i++) {
992 File file = fileList[i];
993 if (file.isDirectory()) {
994 String dir_path = file.getPath();
995 String zip_path = dir_path.substring(prefix_strip);
996 // Zip files use '/' for directory separator
997 String unix_style_path
998 = unixStylePath(zip_path+File.separator);
999 ZipEntry dirEntry = new ZipEntry(unix_style_path);
1000
1001 try {
1002 zos.putNextEntry(dirEntry);
1003 }
1004 catch (IOException e) {
1005 e.printStackTrace();
1006 }
1007
1008 dirFunc(zos,dir_path,prefix_strip);
1009 } else if (file.isFile()) {
1010 // Call the zipFunc function
1011 String file_path = fileList[i].getPath();
1012 zipFunc(zos,file_path,prefix_strip);
1013 }
1014 }
1015 }
1016 else {
1017 System.err.println (dir_name+" is not a directory.");
1018 }
1019 }
1020 else {
1021 System.err.println ("Directory "+dir_name+" does not exist.");
1022 }
1023 }
1024
1025
1026
1027 static public void zipup(String col_name, String dir_or_file)
1028 {
1029 String col_dir = Utility.getCollectDir(Gatherer.config.gsdl_path);
1030 int prefix_strip = col_dir.length();
1031
1032 String zip_fname = col_dir + col_name + ".zip";
1033 String zip_dir_or_file = col_dir + col_name + File.separator + dir_or_file;
1034 File zip_dof = new File(zip_dir_or_file);
1035
1036 try {
1037 FileOutputStream fos = new FileOutputStream(zip_fname);
1038 ZipOutputStream zos = new ZipOutputStream(fos);
1039
1040 if (zip_dof.exists()) {
1041 if (zip_dof.isDirectory()) {
1042 String zip_dir = zip_dir_or_file;
1043 dirFunc(zos,zip_dir,prefix_strip);
1044 }
1045 else {
1046 String zip_full_file = zip_dir_or_file;
1047
1048 String zip_path = zip_full_file.substring(prefix_strip);
1049
1050 for (int i=1; i<zip_path.length(); i++) {
1051 String ch = String.valueOf(zip_path.charAt(i));
1052
1053 if (ch.equals(File.separator)) {
1054 String dir_path = zip_path.substring(0,i);
1055 // Zip files use '/' for directory separator
1056 String unix_style_path
1057 = unixStylePath(dir_path+File.separator);
1058 ZipEntry dirEntry = new ZipEntry(unix_style_path);
1059 zos.putNextEntry(dirEntry);
1060 }
1061 }
1062 zipFunc(zos,zip_full_file,prefix_strip);
1063 }
1064 }
1065 else {
1066 System.err.println("Warning: " + zip_dir_or_file + " does not exist!");
1067 }
1068
1069 // Close the file output streams for both the file and the zip.
1070 zos.flush();
1071 zos.close();
1072 fos.close();
1073 }
1074 catch (IOException e) {
1075 e.printStackTrace();
1076 }
1077 }
1078
1079
1080 static public void unzip(String col_name)
1081 {
1082 String col_dir = Utility.getCollectDir(Gatherer.config.gsdl_path);
1083 String zip_fname = col_dir + col_name + ".zip";
1084 int zip_mode = ZipFile.OPEN_READ | ZipFile.OPEN_DELETE;
1085
1086 try {
1087 ZipFile zipfile = new ZipFile(new File(zip_fname), zip_mode);
1088
1089 Enumeration e = zipfile.entries();
1090 while (e.hasMoreElements()) {
1091 ZipEntry zipentry = (ZipEntry) e.nextElement();
1092 String zentryname = col_dir + zipentry.getName();
1093 Gatherer.println(" Unzipping: " + zentryname);
1094
1095 if (zipentry.isDirectory()) {
1096 // Create named directory
1097 boolean success = (new File(zentryname)).mkdir();
1098 if (!success) {
1099 System.err.println("Error: unable to create directory '"+zentryname+"'");
1100 }
1101 }
1102 else {
1103 // Write out file to disk
1104
1105 // set up input stream
1106 InputStream zis = zipfile.getInputStream(zipentry);
1107 BufferedInputStream bzis = new BufferedInputStream(zis);
1108 DataInputStream dbzis = new DataInputStream(bzis);
1109
1110 // set up output stream
1111 FileOutputStream fzos = new FileOutputStream(zentryname);
1112 BufferedOutputStream bfzos = new BufferedOutputStream(fzos);
1113
1114 byte[] buf = new byte[1024];
1115 int len;
1116 while ((len = dbzis.read(buf)) >= 0) {
1117 bfzos.write(buf,0,len);
1118 }
1119
1120 dbzis.close();
1121 bfzos.close();
1122 }
1123 }
1124 }
1125 catch (ZipException error) {
1126 System.err.println("Error: Unable to open '"+zip_fname+"'");
1127 Gatherer.printStackTrace(error);
1128 }
1129
1130 catch (Exception error) {
1131 error.printStackTrace();
1132 }
1133 }
1134
1135
1136
1137
1138
1139 /* static private File getRecycleDirectory() {
1140 return new File(RECYCLE);
1141 } */
1142
1143
1144 static public String getSitesDir(String gsdl3_path) {
1145 return gsdl3_path + File.separator + "web"
1146 + File.separator + "sites" + File.separator;
1147
1148 }
1149 /** Determine whether a character is a hexidecimal one.
1150 * @param chr The <i>char</i> in question.
1151 * @return An <i>int</i> representing the value of the hexidecimal character or -1 if not a hexidecimal.
1152 */
1153// static private int hexidecimal(char chr) {
1154// switch(chr) {
1155// case '0':
1156// return 0;
1157// case '1':
1158// return 1;
1159// case '2':
1160// return 2;
1161// case '3':
1162// return 3;
1163// case '4':
1164// return 4;
1165// case '5':
1166// return 5;
1167// case '6':
1168// return 6;
1169// case '7':
1170// return 7;
1171// case '8':
1172// return 8;
1173// case '9':
1174// return 9;
1175// case 'A':
1176// return 10;
1177// case 'B':
1178// return 11;
1179// case 'C':
1180// return 12;
1181// case 'D':
1182// return 13;
1183// case 'E':
1184// return 14;
1185// case 'F':
1186// return 15;
1187// default:
1188// return -1;
1189// }
1190// }
1191
1192 /** returns the path to the greenstone version of wget */
1193 static public String getWGetPath(String gsdl_path) {
1194 if (isWindows()) {
1195 return gsdl_path + "bin" + File.separator +
1196 "windows" + File.separator +"wget.exe";
1197 }
1198 // is it the same for macs??
1199 return gsdl_path + "bin" + File.separator +
1200 "linux" + File.separator + "wget";
1201 }
1202
1203 /** A string is a valid hierarchy index if it matches '[0-9](\.[0-9])*' */
1204 static public boolean isIndex(String raw) {
1205 boolean result = true;
1206 for(int i = 0; result && i < raw.length(); i++) {
1207 char c = raw.charAt(i);
1208 if(Character.isDigit(c) || (c == '.' && (i != 0 || i != raw.length() - 1))) {
1209 // Valid index
1210 }
1211 else {
1212 result = false;
1213 }
1214 }
1215 return result;
1216 }
1217
1218 /** Method to determine if the host system is MacOS based.
1219 * @return a boolean which is true if the platform is MacOS, false otherwise
1220 */
1221 public static boolean isMac() {
1222 Properties props = System.getProperties();
1223 String os_name = props.getProperty("os.name","");
1224 if(os_name.startsWith("Mac OS")) {
1225 return true;
1226 }
1227 return false;
1228 }
1229
1230 /** Determines if the given file is a descendant of the folder described.
1231 * @param pos_parent the possible parent folder as a String
1232 * @param child the child File which we are checking
1233 * @return true if the child is a descendant of the pos_parent, false otherwise
1234 */
1235 static public boolean isParentFolderOf(String pos_parent, File child) {
1236 while(child != null) {
1237 if(pos_parent.equals(child.getAbsolutePath())) {
1238 return true;
1239 }
1240 // Just keep looping checking each of childs parent folders. Not a brilliantly efficient algorithm, but it should still be pretty fast compared to the algorithm for merging elements.
1241 child = child.getParentFile();
1242 }
1243 return false;
1244 }
1245
1246 /** Method to determine if the host system is Microsoft Windows based.
1247 * @return A <i>boolean</i> which is <i>true</i> if the platform is Windows, <i>false</i> otherwise.
1248 */
1249 public static boolean isWindows() {
1250 Properties props = System.getProperties();
1251 String os_name = props.getProperty("os.name","");
1252 if(os_name.startsWith("Windows")) {
1253 return true;
1254 }
1255 return false;
1256 }
1257
1258 public static boolean isWindows9x() {
1259 Properties props = System.getProperties();
1260 String os_name = props.getProperty("os.name","");
1261 if(os_name.startsWith("Windows") && os_name.indexOf("9") != -1) {
1262 return true;
1263 }
1264 return false;
1265 }
1266 /** Takes a string and a desired length and pads out the string to the length by adding spaces to the left.
1267 * @param str The target <strong>String</strong> that needs to be padded.
1268 * @param length The desired length of the string as an <i>int</i>.
1269 * @return A <strong>String</strong> made from appending space characters with the string until it has a length equal to length.
1270 */
1271 public static String pad(String str, int length) {
1272 return pad(str, length, ' ', true);
1273 }
1274 public static String pad(String str_raw, int length, char fill, boolean end) {
1275 StringBuffer str = new StringBuffer(str_raw);
1276 while(str.length() < length) {
1277 if(end) {
1278 str.insert(0, fill);
1279 }
1280 else {
1281 str.append(fill);
1282 }
1283 }
1284 return str.toString();
1285 }
1286
1287
1288 /** Parse in a xml document from a given filename. Note that this filename may need to be resolved by the class loader, especially for template files within a jar. */
1289 static public Document parse(String filename, boolean use_classloader)
1290 {
1291 // Try the class loader if desired (for the applet JAR file)
1292 if (use_classloader) {
1293 InputStream is = base.getResourceAsStream("/" + filename);
1294 if (is != null) {
1295 return parse(is, true);
1296 }
1297 }
1298
1299 // Try the file outside the classes directory
1300 return parse(new File(filename), true);
1301 }
1302
1303 /** Parse in a xml document from a given file. */
1304 static public Document parse(File file) {
1305 return parse(file, true);
1306 }
1307
1308 /** Parse in a xml document from a given file. */
1309 static public Document parse(File file, boolean noisey)
1310 {
1311 Document document = null;
1312 try {
1313 Gatherer.println("Parsing XML file: " + file);
1314 FileInputStream fis = new FileInputStream(file);
1315 document = parse(fis,noisey);
1316 file = null;
1317 }
1318 catch (Exception error) {
1319 if(noisey) {
1320 error.printStackTrace();
1321 Gatherer.println("Exception in Utility.parse() - Unexpected");
1322 }
1323 else {
1324 Gatherer.println("Exception in Utility.parse() - Expected");
1325 Gatherer.printStackTrace(error);
1326 }
1327 }
1328
1329 return document;
1330 }
1331
1332 /** Parse in a xml document from a given URL. */
1333 static public Document parse(URL url, boolean noisey)
1334 {
1335 Document document = null;
1336 try {
1337
1338 URLConnection connection = url.openConnection();
1339 InputStream is = connection.getInputStream();
1340 document = parse(is,noisey);
1341 }
1342 catch (Exception error) {
1343 if(noisey) {
1344 error.printStackTrace();
1345 Gatherer.println("Exception in Utility.parse() - Unexpected");
1346 }
1347 else {
1348 Gatherer.println("Exception in Utility.parse() - Expected");
1349 Gatherer.printStackTrace(error);
1350 }
1351 }
1352
1353 return document;
1354 }
1355
1356 /** Parse in a xml document from a given file. */
1357 static public Document parse(InputStream is, boolean noisey) {
1358 Document document = null;
1359 try {
1360 InputStreamReader isr = new InputStreamReader(is, ENCODING);
1361 Reader r = new BufferedReader(isr);
1362 InputSource isc = new InputSource(r);
1363 DOMParser parser = new DOMParser();
1364 parser.setFeature("http://xml.org/sax/features/validation", false);
1365 parser.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
1366 // May or may not be ignored, the documentation for Xerces is contradictory. If it works then parsing -should- be faster.
1367 parser.setFeature("http://apache.org/xml/features/dom/defer-node-expansion", true);
1368 parser.setFeature("http://apache.org/xml/features/dom/include-ignorable-whitespace", false);
1369 parser.parse(isc);
1370 document = parser.getDocument();
1371 isr.close();
1372 is.close();
1373 parser = null;
1374 isc = null;
1375 r = null;
1376 isr = null;
1377 is = null;
1378 }
1379 catch (Exception error) {
1380 if(noisey) {
1381 error.printStackTrace();
1382 Gatherer.println("Exception in Utility.parse() - Unexpected");
1383 }
1384 else {
1385 Gatherer.println("Exception in Utility.parse() - Expected");
1386 }
1387 Gatherer.printStackTrace(error);
1388 }
1389 return document;
1390 }
1391
1392
1393 static public StringBuffer readXMLStream(InputStream input_stream)
1394 {
1395 StringBuffer xml = new StringBuffer("");
1396
1397 try {
1398 InputStreamReader isr = new InputStreamReader(input_stream, "UTF-8");
1399 BufferedReader buffered_in = new BufferedReader(isr);
1400
1401 String line = "";
1402 boolean xml_content = false;
1403 while((line = buffered_in.readLine()) != null) {
1404 if(xml_content) {
1405 xml.append(line);
1406 xml.append("\n");
1407 }
1408 else if(line.trim().startsWith("<?xml")) {
1409 xml_content = true;
1410 xml.append(line);
1411 xml.append("\n");
1412 }
1413 }
1414 buffered_in = null;
1415 }
1416 catch (Exception error) {
1417 System.err.println("Failed when trying to parse XML stream");
1418 error.printStackTrace();
1419 }
1420
1421 return xml;
1422 }
1423
1424
1425 static public Document XMLStringToDOM(StringBuffer xml, String form)
1426 {
1427 Document document = null;
1428
1429 // If something has gone horribly wrong then xml will be empty.
1430 if(xml.length() > 0) {
1431 try {
1432 // Then read the xml from the piped input stream.
1433 StringReader xml_sr = new StringReader(xml.toString());
1434 InputSource source = new InputSource(xml_sr);
1435 DOMParser parser = new DOMParser();
1436 parser.parse(source);
1437 document = parser.getDocument();
1438 }
1439 catch (Exception error) {
1440 System.err.println("Failed when trying to parse XML stream ");
1441 error.printStackTrace();
1442 }
1443 }
1444 else {
1445 //Gatherer.println("Zero length argument xml detected for: " + form);
1446 String[] margs = new String[1];
1447 margs[0] = form;
1448 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CDM.PlugInManager.PlugIn_XML_Parse_Failed", margs), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1449 }
1450
1451 return document;
1452 }
1453
1454
1455
1456 /** Method to spread out a line of text so that is is justified to the given width, by attempting to widen white-spacing in a balanced way.
1457 * @param original The <strong>String</strong> to justify.
1458 * @param width The desired width as an <i>int</i>.
1459 * @param current_width An <i>int</i> representing the current width of the string, which takes into account special characters.
1460 * @return The newly justified <strong>String</strong>.
1461 */
1462 static private String space(String original, int width, int current_width) {
1463 // Strip trailing whitespace.
1464 while(original.charAt(original.length() - 1) == ' ') {
1465 original = original.substring(0, original.length() - 2);
1466 }
1467 int diff = width - current_width;
1468 // Now add diff spaces, one at each existing space.
1469 int pos = 0;
1470 while(diff > 0) {
1471 if(pos == original.length()) {
1472 pos = 0;
1473 }
1474 if(original.charAt(pos) == ' ') {
1475 // Insert a space.
1476 String prefix = original.substring(0, pos);
1477 String suffix = original.substring(pos);
1478 original = prefix + " " + suffix;
1479 pos = pos + 2;
1480 diff--;
1481 }
1482 pos++;
1483 }
1484 return original;
1485 }
1486
1487
1488 /** I think this works a bit better on Unicode strings. */
1489 static public String stripNL(String raw_string)
1490 {
1491 String stripped_string = new String();
1492 for (int i = 0; i < raw_string.length(); i++) {
1493 char raw_character = raw_string.charAt(i);
1494 if (raw_character != '\n' && raw_character != '\t') {
1495 stripped_string = stripped_string + raw_character;
1496 }
1497 }
1498 return stripped_string;
1499 }
1500
1501
1502 static public String trimCenter(String text, int length) {
1503 if(text.length() > length) {
1504 int half = (length - 3) / 2;
1505 StringBuffer temp = new StringBuffer(text.substring(0, half));
1506 temp.append("...");
1507 temp.append(text.substring(text.length() - half));
1508 text = temp.toString();
1509 }
1510 return text;
1511 }
1512}
Note: See TracBrowser for help on using the repository browser.