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

Last change on this file since 9209 was 9209, checked in by mdewsnip, 19 years ago

Some tidy ups to the applet code.

  • Property svn:keywords set to Author Date Id Revision
File size: 36.9 KB
Line 
1/**
2 *#########################################################################
3 *
4 * A component of the Gatherer application, part of the Greenstone digital
5 * library suite from the New Zealand Digital Library Project at the
6 * University of Waikato, New Zealand.
7 *
8 * <BR><BR>
9 *
10 * Author: John Thompson, Greenstone Digital Library, University of Waikato
11 *
12 * <BR><BR>
13 *
14 * Copyright (C) 1999 New Zealand Digital Library Project
15 *
16 * <BR><BR>
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * <BR><BR>
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * <BR><BR>
31 *
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 *########################################################################
36 */
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.xerces.dom.DocumentImpl;
48import org.apache.xml.serialize.*;
49import org.greenstone.gatherer.Configuration;
50import org.greenstone.gatherer.DebugStream;
51import org.greenstone.gatherer.Dictionary;
52import org.greenstone.gatherer.shell.GShell;
53// Don't even think about adding import org.greenstone.gatherer.Gatherer in here!
54// The functions in this class should be independent of the Gatherer class. Put your function somewhere else buster!
55import org.w3c.dom.*;
56import org.xml.sax.*;
57
58/** To provide a library of common methods, in a static context, for use in the Gatherer.
59 * @author John Thompson, Greenstone Digital Library, University of Waikato
60 * @version 2.3b
61 */
62public class Utility {
63 static final public Dimension MINIMUM_BUTTON_SIZE = new Dimension(100, 25);
64 // static final public Dimension DOUBLE_IMAGE_BUTTON_SIZE = new Dimension(190, 35);
65 static final public Dimension LABEL_SIZE = new Dimension(150, 25);
66 /** The default size of a gatherer progress bar, in either the download view or the build view. */
67 static final public Dimension PROGRESS_BAR_SIZE = new Dimension(580,65);
68 /** The number of kilobytes to use as a io buffer. */
69 static final public int FACTOR = 1;
70 /** The size of the io buffer, calculated as FACTOR * 1024. */
71 static final public int BUFFER_SIZE = FACTOR * 1024;
72 /** Definition of an important directory name, in this case the base dir, or the working directory of the Gatherer. */
73
74 static public String BASE_DIR = System.getProperty("user.dir") + File.separator;
75 static final public String BUILD_CFG_FILENAME = "build.cfg";
76 static final public String CFG_COLLECTIONMETA_COLLECTIONNAME = "collectionmeta\tcollectionname";
77 static final public String CFG_COLLECTIONMETA_COLLECTIONEXTRA = "collectionmeta\tcollectionextra";
78 static final public String CFG_COLLECTIONMETA_ICONCOLLECTION = "collectionmeta\ticoncollection";
79 static final public String CFG_CLASSIFY = "classify";
80 static final public String CFG_CLASSIFY_BUTTONNAME = "-buttonname";
81 static final public String CFG_CLASSIFY_HFILE = "-hfile";
82 static final public String CFG_CLASSIFY_METADATA = "-metadata";
83 static final public String CFG_CLASSIFY_SORT = "-sort";
84 static final public String CFG_CREATOR = "creator";
85 static final public String CFG_FORMAT = "format";
86 static final public String CFG_MAINTAINER = "maintainer";
87 /** Definition of an important directory name, in this case the parent directory of all the collections in the gsdl. */
88 static final public String COL_DIR = "collect" + File.separator;
89 static final public String COLLECTION_TREE = "Collection";
90 /** Definition of an important directory name, in this case the file the collection configuration is expect to be in. */
91 static final public String CONFIG_FILE = "etc" + File.separator + "collect.cfg";
92 static final public String EXTRACTED_METADATA_NAMESPACE = "ex";
93 /** The location of the default greenstone metadata file. */
94 static final public String GREENSTONEDIRECTORYMETADATA_TEMPLATE = "xml/metadata.xml";
95 static final public String GLI_ARCHIVE = "GLI.jar";
96 static final public String GLI_EXTENSION = ".col";
97 /** Definition of an important directory name, in this case the images directory for the collection. */
98 static final public String IMAGES_DIR = "images" + File.separator;
99 /** Definition of an important directory name, in this case the import directory for the collection. */
100 static final public String IMPORT_DIR = "import" + File.separator;
101 /** Definition of an important directory name, in this case the backup import directory for the collection. */
102 static final public String IMPORT_BAK_DIR = "import.bak" + File.separator;
103 /** Definition of an important directory name, in this case the log directory for the collection. */
104 static final public String LOG_DIR = "log" + File.separator;
105 /** Definition of an important directory name, in this case the macros directory for the collection. */
106 static final public String MACROS_DIR = "macros" + File.separator;
107 /** Definition of an important directory name, in this case the location of the expected collection metadata sets.. */
108 static final public String META_DIR = "metadata" + File.separator; // Col. Copy
109 /** Definition of an important directory name, in this case the location of the default metadata sets. */
110 static public String METADATA_DIR = BASE_DIR + "metadata" + File.separator;
111 /** Definition of an important zip file, in this case zipped up version of metadata file stored in JAR file */
112 static final public String METADATA_ZIP = "metadata.zip";
113 /** The default name of the perl executable under unix. */
114 static final public String PERL_EXECUTABLE_UNIX = "perl";
115 /** The default name of the perl executable under windows. */
116 static final public String PERL_EXECUTABLE_WINDOWS = "Perl.exe";
117 /** The name of the Gatherer. */
118 static final public String PROGRAM_NAME = "Greenstone Librarian Interface";
119 /** The current version of the Gatherer. */
120 static final public String PROGRAM_VERSION = "v2.53";
121 static final public String WORKSPACE_TREE = "Workspace";
122 static final public String XML_DIRECTORY = "xml" + File.separator;
123
124 // These are out of alphabetic order to avoid forward reference error.
125 /** The default icon to produce a 'help-icon' sized blank space before a menu entry. */
126 static public Class base = null;
127 static public ImageIcon BLANK_ICON = null;
128 /** The default error icon image. */
129 static public ImageIcon ERROR_ICON = null;
130 static public ImageIcon HELP_ICON = null;
131
132
133 /** 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.
134 * @param file The <strong>File</strong> you want to delete.
135 * @return A <i>boolean</i> which is <i>true</i> if the file specified was successfully deleted, <i>false</i> otherwise.
136 */
137 static public boolean delete(File file)
138 {
139 // Nothing to do if it doesn't exist
140 if (!file.exists()) {
141 return true;
142 }
143
144 // If file is a directory, we have to recursively delete its contents first
145 if (file.isDirectory()) {
146 File files[] = file.listFiles();
147 for (int i = 0; i < files.length; i++) {
148 if (delete(files[i]) == false) {
149 System.err.println("Error: Could not delete folder " + file);
150 return false;
151 }
152 }
153 }
154
155 // Delete file
156 if (file.delete() == false) {
157 System.err.println("Error: Could not delete file " + file);
158 return false;
159 }
160
161 return true;
162 }
163
164
165 static public boolean delete(String filename) {
166 return delete(new File(filename));
167 }
168
169
170 /** Convert a long, detailing the length of a file in bytes, into a nice human readable string using b, kb, Mb and Gb. */
171 static final public String BYTE_SUFFIX = " b";
172 static final public long GIGABYTE = 1024000000l;
173 static final public String GIGABYTE_SUFFIX = " Gb";
174 static final public long KILOBYTE = 1024l;
175 static final public String KILOBYTE_SUFFIX = " kb";
176 static final public long MEGABYTE = 1024000l;
177 static final public String MEGABYTE_SUFFIX = " mb";
178 static final public String formatFileLength(long length) {
179 StringBuffer result = new StringBuffer("");
180 float number = 0f;
181 String suffix = null;
182 // Determine the floating point number and the suffix (radix) used.
183 if(length >= GIGABYTE) {
184 number = (float) length / (float) GIGABYTE;
185 suffix = GIGABYTE_SUFFIX;
186 }
187 else if(length >= MEGABYTE) {
188 number = (float) length / (float) MEGABYTE;
189 suffix = MEGABYTE_SUFFIX;
190 }
191 else if(length >= KILOBYTE) {
192 number = (float) length / (float) KILOBYTE;
193 suffix = KILOBYTE_SUFFIX;
194 }
195 else {
196 // Don't need to do anything fancy if the file is smaller than a kilobyte
197 return length + BYTE_SUFFIX;
198 }
199 // 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.
200 String number_str = Float.toString(number);
201 char number_char[] = number_str.toCharArray();
202 int pos = 0;
203 // Print the characters up to the '.'
204 while(number_char != null && pos < number_char.length && number_char[pos] != '.') {
205 result.append(number_char[pos]);
206 pos++;
207 }
208 if(pos < number_char.length) {
209 // Print the '.' and at most two characters after it
210 result.append(number_char[pos]);
211 pos++;
212 for(int i = 0; i < 2 && pos < number_char.length; i++, pos++) {
213 result.append(number_char[pos]);
214 }
215 // Search through the remaining string for 'E'
216 while(pos < number_char.length && number_char[pos] != 'E') {
217 pos++;
218 }
219 // If we still have string then we found an E. Copy the remaining string.
220 while(pos < number_char.length) {
221 result.append(number_char[pos]);
222 pos++;
223 }
224 }
225 // Add suffix
226 result.append(suffix);
227 // Done
228 return result.toString();
229 }
230
231 /** This method formats a given string, using HTML markup, so its width does not exceed the given width and its appearance if justified.
232 * @param text The <strong>String</strong> requiring formatting.
233 * @param width The maximum width per line as an <i>int</i>.
234 * @return A <strong>String</strong> formatted so as to have no line longer than the specified width.
235 * 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.
236 */
237 static public String formatHTMLWidth(String text, int width) {
238 if(text == null) {
239 return "Error";
240 }
241 HTMLStringTokenizer html = new HTMLStringTokenizer(text);
242 int current_width = 0;
243 int threshold = width / 2;
244 Stack lines = new Stack();
245 String line = "";
246 while(html.hasMoreTokens()) {
247 String token = html.nextToken();
248 while(token != null) {
249 if(html.isTag()) {
250 // Insert smart HTML tag code here.
251 token = null;
252 }
253 else {
254 // If the token is bigger than two thirds width, before we've even started break it down.
255 if(current_width + 1 + token.length() > width && token.length() > threshold) {
256 if(width == current_width) {
257 lines.push(line);
258 line = token;
259 current_width = token.length();
260 }
261 else {
262 String prefix = token.substring(0, width - 1 - current_width);
263 token = token.substring(prefix.length());
264 if(current_width == 0) {
265 line = line + prefix;
266 }
267 else {
268 line = line + " " + prefix;
269 }
270 lines.push(line);
271 line = "";
272 current_width = 0;
273 }
274 }
275 // If adding the next token would push us over the maximum line width.
276 else if(current_width + 1 + token.length() > width) {
277 lines.push(line);
278 line = token;
279 current_width = token.length();
280 token = null;
281 }
282 // Otherwise we should be able to just add the token, give or take.
283 else {
284 if(current_width == 0) {
285 line = line + token;
286 current_width = token.length();
287 }
288 else {
289 // Special case for standard punctuation which may exist after a tag like so:
290 // My name is <scratchy>Slim Shady</scratchy>. <-- Annoying punctuation.
291 if(token.equals(".") || token.equals(",") || token.equals("!") || token.equals("?")) {
292 line = line + token;
293 current_width = current_width + 1;
294 }
295 else {
296 line = line + " " + token;
297 current_width = current_width + 1 + token.length();
298 }
299 }
300 token = null;
301 }
302 }
303 }
304 }
305 String result = line;
306 while(!lines.empty()) {
307 result = (String)lines.pop() + "<BR>" + result;
308 }
309 // Replace ' ' with "&nbsp;"
310 boolean tag = false;
311 int pos = 0;
312 while(pos < result.length()) {
313 if(result.charAt(pos) == '<') {
314 tag = true;
315 }
316 else if(result.charAt(pos) == '>') {
317 tag = false;
318 }
319 else if(result.charAt(pos) == ' ' && !tag) {
320 String prefix = result.substring(0, pos);
321 String suffix = result.substring(pos + 1);
322 result = prefix + "&nbsp;" + suffix;
323 }
324 pos++;
325 }
326 result = "<HTML>" + result + "</HTML>";
327 return result;
328 }
329 /** Format the given filename path string so that it is no longer than the given width. If it is wider replace starting directories with ...
330 * @param key The key <strong>String</Strong> used to retrieve a phrase from the dictionary for this item.
331 * @param raw The raw filename path <strong>String</strong>.
332 * @param width The maximum width as an <i>int</i>.
333 * @return A path <strong>String</strong> no longer than width.
334 */
335 static public String formatPath(String key, String raw, int width) {
336 JLabel label = new JLabel(Dictionary.get(key, raw));
337 int position = -1;
338 while(label.getPreferredSize().width > width && (position = raw.indexOf(File.separator)) != -1) {
339 raw = "..." + raw.substring(position + 1);
340 label.setText(Dictionary.get(key, raw));
341 }
342 if(raw.indexOf(File.separator) == -1 && raw.startsWith("...")) {
343 raw = raw.substring(3);
344 }
345 return raw;
346 }
347
348
349 /** Builds the cache dir by appending the user path and 'cache'.
350 * @return a File representing the path to the private file cache within the current collection.
351 */
352 public static File getCacheDir() {
353 return new File(getGLIUserFolder(), StaticStrings.CACHE_FOLDER);
354 }
355
356
357 /** Method which constructs the configuration file given a certain collection.
358 * @param col_dir The location of the collection directory as a <strong>String</strong>.
359 * @return The location of the given collections configuration file, also as a <strong>String</strong>.
360 */
361 static public String getConfigFile(String col_dir) {
362 return col_dir + CONFIG_FILE;
363 }
364
365 static public String getDateString() {
366 Calendar current = Calendar.getInstance();
367 String day_name = null;
368 switch(current.get(Calendar.DAY_OF_WEEK)) {
369 case Calendar.MONDAY: day_name = "Dates.Mon"; break;
370 case Calendar.TUESDAY: day_name = "Dates.Tue"; break;
371 case Calendar.WEDNESDAY: day_name = "Dates.Wed"; break;
372 case Calendar.THURSDAY: day_name = "Dates.Thu"; break;
373 case Calendar.FRIDAY: day_name = "Dates.Fri"; break;
374 case Calendar.SATURDAY: day_name = "Dates.Sat"; break;
375 case Calendar.SUNDAY: day_name = "Dates.Sun"; break;
376 default: day_name = "";
377 }
378 String month_name = null;
379 switch(current.get(Calendar.MONTH)) {
380 case Calendar.JANUARY: month_name = "Dates.Jan"; break;
381 case Calendar.FEBRUARY: month_name = "Dates.Feb"; break;
382 case Calendar.MARCH: month_name = "Dates.Mar"; break;
383 case Calendar.APRIL: month_name = "Dates.Apr"; break;
384 case Calendar.MAY: month_name = "Dates.May"; break;
385 case Calendar.JUNE: month_name = "Dates.Jun"; break;
386 case Calendar.JULY: month_name = "Dates.Jul"; break;
387 case Calendar.AUGUST: month_name = "Dates.Aug"; break;
388 case Calendar.SEPTEMBER: month_name = "Dates.Sep"; break;
389 case Calendar.OCTOBER: month_name = "Dates.Oct"; break;
390 case Calendar.NOVEMBER: month_name = "Dates.Nov"; break;
391 case Calendar.DECEMBER: month_name = "Dates.Dec"; break;
392 default: month_name = "";
393 }
394 int day = current.get(Calendar.DAY_OF_MONTH);
395 int hour = current.get(Calendar.HOUR_OF_DAY);
396 int minute = current.get(Calendar.MINUTE);
397 int second = current.get(Calendar.SECOND);
398 int year = current.get(Calendar.YEAR);
399
400 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);
401 }
402
403
404 static final private String APPLICATION_DATA_FOLDER = "Application Data";
405 static final private String UNIX_GLI_CONFIG_FOLDER = ".gli";
406 static final private String USER_HOME_PROPERTY = "user.home";
407 static final private String WIN_GLI_CONFIG_FOLDER = "Greenstone" + File.separator + "GLI";
408
409 static public File getGLIUserFolder()
410 {
411 if (Utility.isWindows()) {
412 return new File(System.getProperty(USER_HOME_PROPERTY) + File.separator + APPLICATION_DATA_FOLDER + File.separator + WIN_GLI_CONFIG_FOLDER + File.separator);
413 }
414 else {
415 return new File(System.getProperty(USER_HOME_PROPERTY) + File.separator + UNIX_GLI_CONFIG_FOLDER + File.separator);
416 }
417 }
418
419
420 /** Retrieve the full file path to the help index xml file.
421 * @return the full path as a String
422 */
423 static public String getHelpFolder() {
424
425 String help_folder = "help/" + Configuration.getLanguage() + "/";
426
427 // Try in the JAR/classes directory first
428 URL help_folder_url = base.getResource("/" + help_folder);
429 if (help_folder_url != null) {
430 return help_folder;
431 }
432
433 // Look in the base directory next
434 File help_folder_file = new File(help_folder);
435 if (help_folder_file.exists()) {
436 return help_folder;
437 }
438
439 // Resort to English
440 return "help/" + StaticStrings.ENGLISH_LANGUAGE_STR + "/";
441 }
442
443 /** Method to retrieve an image icon with the given filename found in classpath or the resouces directory.
444 * @return The specified <strong>ImageIcon</strong>, or an error image replacement if no such images exists.
445 */
446 static public ImageIcon getImage(String filename) {
447 return getImage(filename, false);
448 }
449
450 static public ImageIcon getImage(String filename, boolean wait_until_complete) {
451 ImageIcon image = null;
452 try {
453 image = new ImageIcon(base.getResource("/images/" + Dictionary.get("Version") + "/" + filename));
454 }
455 catch(NullPointerException exception) {
456 image = new ImageIcon(base.getResource("/images/" + filename));
457 }
458 if(image == null) {
459 image = ERROR_ICON;
460 }
461
462 if(wait_until_complete) {
463 int load_status;
464 do {
465 load_status = image.getImageLoadStatus();
466 }
467 while(load_status != MediaTracker.ABORTED && load_status != MediaTracker.ERRORED && load_status != MediaTracker.COMPLETE);
468 }
469 return image;
470 }
471
472
473 /** Method which constructs the import directory given a certain collection.
474 * @param col_dir The location of the collection directory as a <strong>String</strong>.
475 * @return The location of the given collections import directory, also as a <strong>String</strong>.
476 */
477 public static String getImportDir(String col_dir) {
478 return col_dir + IMPORT_DIR;
479 }
480
481 /** Method which constructs the log directory given a certain collection.
482 * @param col_dir The location of the collection directory as a <strong>String</strong>.
483 * @return The location of the given collections log directory, also as a <strong>String</strong>.
484 */
485 public static String getLogDir(String col_dir) {
486 if(col_dir != null) {
487 return col_dir + LOG_DIR;
488 }
489 else {
490 return getGLIUserFolder().getAbsolutePath() + File.separator + LOG_DIR;
491 }
492 }
493 /** Determine this machines name.
494 * @return The name as a <strong>String</strong>.
495 */
496 static public String getMachineName() {
497 try {
498 return InetAddress.getLocalHost().getHostName();
499 }
500 catch(UnknownHostException ex) {
501 }
502 return "Unknown Machine";
503 }
504
505
506 static public void extractFromJar(String filename, String dst_dir, boolean must_be_present)
507 {
508 try {
509 // setup input stream for slurping out file
510 InputStream fis = base.getResourceAsStream("/"+filename);
511 BufferedInputStream fbis = new BufferedInputStream(fis);
512 DataInputStream fdbis = new DataInputStream(fbis);
513
514 // set up output stream for writing to disk
515 String ofname = dst_dir + filename;
516 FileOutputStream fos = new FileOutputStream(ofname);
517 BufferedOutputStream bfos = new BufferedOutputStream(fos);
518
519 byte[] buf = new byte[1024];
520 int len;
521 int total_bytes = 0;
522 while ((len = fdbis.read(buf)) >= 0) {
523 bfos.write(buf,0,len);
524 total_bytes += len;
525 }
526
527 fdbis.close();
528 bfos.close();
529 }
530 catch (Exception error) {
531 if (must_be_present) {
532 error.printStackTrace();
533 }
534 }
535 }
536
537
538 /** Method which unzips a given metadata resoure
539 * @param zip_fname The name of the zip file as a <strong>String</strong>.
540 * @param dst_dir The destination directory for unzipping, also as a <strong>String</strong>.
541 * @param use_classloader Used to determine whether or not to look in resource bundle.
542 */
543 static public void unzipFromJar(String jar_zip_fname, String dst_dir) {
544
545 File file = null;
546 if (!dst_dir.endsWith(File.separator)) {
547 dst_dir += File.separator;
548 }
549
550 extractFromJar(jar_zip_fname,dst_dir,true);
551
552 String zip_ofname = dst_dir + jar_zip_fname;
553 File zip_file = new File(zip_ofname);
554
555 try {
556 ZipFile zipfile = new ZipFile(zip_file);
557
558 Enumeration e = zipfile.entries();
559 while (e.hasMoreElements()) {
560 ZipEntry zipentry = (ZipEntry) e.nextElement();
561 String zentryname = dst_dir + zipentry.getName();
562 DebugStream.println(" Unzipping: " + zentryname);
563
564 if (zipentry.isDirectory()) {
565 // Create named directory, if it doesn't already exist
566 File zip_entry_file = new File(zentryname);
567 if (!zip_entry_file.exists() && !zip_entry_file.mkdirs()) {
568 System.err.println("Error: unable to create directory " + zip_entry_file);
569 }
570 }
571 else {
572 // Write out file to disk
573
574 // set up input stream
575 InputStream zis = zipfile.getInputStream(zipentry);
576 BufferedInputStream bzis = new BufferedInputStream(zis);
577 DataInputStream dbzis = new DataInputStream(bzis);
578
579 // set up output stream
580 FileOutputStream fzos = new FileOutputStream(zentryname);
581 BufferedOutputStream bfzos = new BufferedOutputStream(fzos);
582
583 byte[] buf = new byte[1024];
584 int len;
585 while ((len = dbzis.read(buf)) >= 0) {
586 bfzos.write(buf,0,len);
587 }
588
589 dbzis.close();
590 bfzos.close();
591 }
592 }
593 }
594 catch (ZipException error) {
595 System.err.println("Error: Unable to open '"+zip_file.getAbsolutePath()+"'");
596 DebugStream.printStackTrace(error);
597 }
598
599 catch (Exception error) {
600 error.printStackTrace();
601 }
602 }
603
604
605 static protected String unixStylePath(String path)
606 {
607 String unix_path = path.replace('\\','/');
608 return unix_path;
609 }
610
611 /*
612 Method to handle zipping up of a file. Called by zipup and dirFunc.
613
614 @param zos the zip output stream, as a <strong>ZipOutputStream</strong>
615 @param file_path the <strong>String</strong> containing the path to the file/directory tozip up
616 @param prefix_strip the <strong>int</strong> used to substring the file_path
617 @param source the <strong>GShell</strong> that is calling this method, so that we can check to see if the process has been cancelled. null if GShell is not the calling object.
618 @param accept_expr a <strong>String</strong> containing a regular expression of files to include in the archive. All other files will be excluded.
619 @param reject_expr a <strong>String</strong> containing a regular expression of files not to include in the archive.
620
621 @return boolean
622
623 @see dirFunc
624 @see zipup
625 */
626 static protected boolean zipFunc (ZipOutputStream zos, String file_path, int prefix_strip, GShell source, boolean encountered_file, String accept_expr, String reject_expr)
627 {
628 String new_file_path = file_path;
629
630 if((reject_expr != "") && (file_path.matches(reject_expr))) {
631 // matches reject expression
632 //DebugStream.println("File \'" + file_path + "\' matches the reject expression \'" + reject_expr + "\'");
633 return encountered_file;
634 }
635
636 if ((accept_expr != "") && (!file_path.matches(accept_expr))) {
637 // does not match accept expression
638 //DebugStream.println("File \'" + file_path + "\' doesn't match accept expression \'" + accept_expr + "\'");
639 return encountered_file;
640 }
641
642 //Special case: we only want the metadata. Parse the xml files.
643 if(accept_expr.compareTo(".*doc.xml") == 0) {
644 DebugStream.println("Only want to get metadata");
645 Document old_document = XMLTools.parseXMLFile(new File(file_path));
646 NodeList content = old_document.getElementsByTagName("Content");
647
648 try {
649 for(int i=content.getLength()-1; i >= 0; i--) {
650 //Remove all content - just leave the metadata.
651 content.item(i).getParentNode().removeChild(content.item(i));
652 }
653 }
654 catch (Exception ex) {
655 ex.printStackTrace();
656 }
657
658 new_file_path = file_path.substring(0, file_path.lastIndexOf(File.separator) + 1) + "new.xml";
659 //Is there any better way than writing out as a new file, then reading back in??
660 XMLTools.writeXMLFile(new File(new_file_path), old_document);
661 }
662
663 // Using try is required because of file io.
664 try {
665 // Exit if pressed cancel.
666 if (source != null && source.hasSignalledStop()) {
667 return false;
668 }
669
670 // Create a Zip Entry and put it into the archive (no data yet).
671
672 // Strip off col_dir prefix
673 String zip_path = file_path.substring(prefix_strip);
674 // Zip files use '/' for directory separator
675 String unix_style_path = unixStylePath(zip_path);
676
677 ZipEntry fileEntry = new ZipEntry(unix_style_path);
678 zos.putNextEntry(fileEntry);
679
680 // Create a file input stream and a buffered input stream.
681 FileInputStream fis = new FileInputStream(new_file_path);
682 BufferedInputStream bis = new BufferedInputStream(fis);
683
684 // Create a byte array object named data and declare byte count variable.
685 byte[] data = new byte[1024];
686 int byteCount;
687 // Create a loop that reads from the buffered input stream and writes
688 // to the zip output stream until the bis has been entirely read.
689 while ((byteCount = bis.read(data, 0, 1024)) > -1) {
690 //Check for cancell
691 if(source != null) {
692 if(source.hasSignalledStop()) {
693 break;
694 }
695 }
696 zos.write(data, 0, byteCount);
697 }
698 encountered_file = true;
699 }
700 catch (IOException e) {
701 e.printStackTrace();
702 }
703
704 DebugStream.println("Zipping up: " + file_path);
705 return encountered_file;
706 }
707
708 /*
709 Method to handle ziping up of a directory.
710
711 @param zos
712 @param dir_name
713 @param prefix_strip
714 @param source
715 @param encountered_file ??What's this??
716 @param accept_expr
717 @param reject_expr
718
719 @see zipup
720 @see zipFunc
721 */
722 static protected boolean dirFunc (ZipOutputStream zos, String dir_name, int prefix_strip, GShell source, boolean encountered_file, String accept_expr, String reject_expr)
723 {
724 File dirObj = new File(dir_name);
725
726 if (dirObj.exists() == true) {
727 if (dirObj.isDirectory() == true) {
728 // Create an array of File objects, one for each file or directory in dirObj.
729 File [] fileList = dirObj.listFiles();
730
731 // Loop through File array and display.
732 for (int i = 0; i < fileList.length; i++) {
733 if(source != null && source.hasSignalledStop()) { break; }
734 File file = fileList[i];
735 if (file.isDirectory()) {
736 String dir_path = file.getPath();
737 String zip_path = dir_path.substring(prefix_strip);
738 // Zip files use '/' for directory separator
739 String unix_style_path
740 = unixStylePath(zip_path+File.separator);
741 ZipEntry dirEntry = new ZipEntry(unix_style_path);
742
743 try {
744 zos.putNextEntry(dirEntry);
745 }
746 catch (IOException e) {
747 e.printStackTrace();
748 }
749
750 encountered_file = dirFunc(zos, dir_path, prefix_strip, source, encountered_file, accept_expr, reject_expr);
751 } else if (file.isFile()) {
752 // Call the zipFunc function
753 String file_path = fileList[i].getPath();
754 encountered_file = zipFunc(zos,file_path,prefix_strip, source, encountered_file, accept_expr, reject_expr);
755 }
756 }
757 }
758 else {
759 System.err.println (dir_name+" is not a directory.");
760 }
761 }
762 else {
763 System.err.println ("Directory "+dir_name+" does not exist.");
764 }
765 return encountered_file;
766 }
767
768 /**
769 Method to zip up a given file or directory
770
771 @param col_dir
772 @param col_name
773 @param dir_or_file
774 @param source
775 @param filter
776
777 @see zipFunc
778 @see dirFunc
779 */
780 static public boolean zipup(String col_dir, String col_name, String dir_or_file, GShell source, String accept_expr, String reject_expr)
781 {
782 int prefix_strip = col_dir.length();
783 boolean encountered_file = false;
784
785 String zip_fname = col_dir + col_name + ".zip";
786 String zip_dir_or_file = col_dir + col_name + File.separator + dir_or_file;
787 File zip_dof = new File(zip_dir_or_file);
788
789 try {
790 FileOutputStream fos = new FileOutputStream(zip_fname);
791 ZipOutputStream zos = new ZipOutputStream(fos);
792
793 if (zip_dof.exists()) {
794 if (zip_dof.isDirectory()) {
795 String zip_dir = zip_dir_or_file;
796 encountered_file = dirFunc(zos, zip_dir, prefix_strip, source, encountered_file, accept_expr, reject_expr);
797 }
798 else {
799 String zip_full_file = zip_dir_or_file;
800 String zip_path = zip_full_file.substring(prefix_strip);
801
802 for (int i=1; i<zip_path.length(); i++) {
803 String ch = String.valueOf(zip_path.charAt(i));
804
805 if (ch.equals(File.separator)) {
806 String dir_path = zip_path.substring(0,i);
807 // Zip files use '/' for directory separator
808 String unix_style_path
809 = unixStylePath(dir_path+File.separator);
810 ZipEntry dirEntry = new ZipEntry(unix_style_path);
811 zos.putNextEntry(dirEntry);
812 }
813 }
814 encountered_file = zipFunc(zos, zip_full_file, prefix_strip, source, encountered_file, accept_expr, reject_expr);
815 }
816 }
817 else {
818 System.err.println("Warning: " + zip_dir_or_file + " does not exist!");
819 }
820
821 // Close the file output streams for both the file and the zip.
822 zos.flush();
823 zos.close();
824 fos.close();
825 }
826 catch (IOException exception) {
827 DebugStream.printStackTrace(exception);
828 return false;
829 }
830 return encountered_file;
831 }
832
833
834 static public void unzip(String col_dir, String col_name)
835 {
836 String zip_fname = col_dir + col_name + ".zip";
837 int zip_mode = ZipFile.OPEN_READ | ZipFile.OPEN_DELETE;
838
839 try {
840 ZipFile zipfile = new ZipFile(new File(zip_fname), zip_mode);
841
842 Enumeration e = zipfile.entries();
843 while (e.hasMoreElements()) {
844 ZipEntry zipentry = (ZipEntry) e.nextElement();
845 String zentryname = col_dir + zipentry.getName();
846 File file = new File(zentryname);
847 DebugStream.println(" Unzipping: " + zentryname);
848
849 if (zipentry.isDirectory()) {
850 // Create named directory, if it doesn't already exist
851 if (!file.exists() && !file.mkdirs()) {
852 System.err.println("Error: unable to create directory " + file);
853 }
854 }
855 else {
856 // Write out file to disk
857
858 //Make sure it's parent directory exists.
859 File dir = new File(file.getParent());
860 dir.mkdirs();
861
862 // set up input stream
863 InputStream zis = zipfile.getInputStream(zipentry);
864 BufferedInputStream bzis = new BufferedInputStream(zis);
865 DataInputStream dbzis = new DataInputStream(bzis);
866
867 // set up output stream
868 FileOutputStream fzos = new FileOutputStream(zentryname);
869 BufferedOutputStream bfzos = new BufferedOutputStream(fzos);
870
871 byte[] buf = new byte[1024];
872 int len;
873 while ((len = dbzis.read(buf)) >= 0) {
874 bfzos.write(buf,0,len);
875 }
876
877 dbzis.close();
878 bfzos.close();
879 }
880 }
881 }
882 catch (ZipException error) {
883 System.err.println("Error: Unable to open '"+zip_fname+"'");
884 System.err.println("This maybe caused by the zip file being empty.");
885 DebugStream.printStackTrace(error);
886 }
887
888 catch (Exception error) {
889 error.printStackTrace();
890 }
891 }
892
893
894 static public String getSitesDir(String gsdl3_path) {
895 return gsdl3_path + File.separator + "web"
896 + File.separator + "sites" + File.separator;
897
898 }
899
900
901 /** returns the path to the greenstone version of wget */
902 static public String getWGetPath(String gsdl_path) {
903 if (isWindows()) {
904 return gsdl_path + "bin" + File.separator +
905 "windows" + File.separator +"wget.exe";
906 }
907 // is it the same for macs??
908 return gsdl_path + "bin" + File.separator +
909 "linux" + File.separator + "wget";
910 }
911
912
913 static public void initImages(Object base_object)
914 {
915 base = base_object.getClass();
916
917 BLANK_ICON = new ImageIcon(base.getResource("/images/blank.gif"));
918 ERROR_ICON = new ImageIcon(base.getResource("/images/error.gif"));
919 HELP_ICON = new ImageIcon(base.getResource("/images/help.gif"));
920 }
921
922
923 /** Method to determine if the host system is MacOS based.
924 * @return a boolean which is true if the platform is MacOS, false otherwise
925 */
926 public static boolean isMac() {
927 Properties props = System.getProperties();
928 String os_name = props.getProperty("os.name","");
929 if(os_name.startsWith("Mac OS")) {
930 return true;
931 }
932 return false;
933 }
934
935
936 /** Method to determine if the host system is Microsoft Windows based.
937 * @return A <i>boolean</i> which is <i>true</i> if the platform is Windows, <i>false</i> otherwise.
938 */
939 public static boolean isWindows() {
940 Properties props = System.getProperties();
941 String os_name = props.getProperty("os.name","");
942 if(os_name.startsWith("Windows")) {
943 return true;
944 }
945 return false;
946 }
947
948 public static boolean isWindows9x() {
949 Properties props = System.getProperties();
950 String os_name = props.getProperty("os.name","");
951 if(os_name.startsWith("Windows") && os_name.indexOf("9") != -1) {
952 return true;
953 }
954 return false;
955 }
956 /** Takes a string and a desired length and pads out the string to the length by adding spaces to the left.
957 * @param str The target <strong>String</strong> that needs to be padded.
958 * @param length The desired length of the string as an <i>int</i>.
959 * @return A <strong>String</strong> made from appending space characters with the string until it has a length equal to length.
960 */
961 static private String pad(String str_raw, int length, char fill, boolean end) {
962 StringBuffer str = new StringBuffer(str_raw);
963 while(str.length() < length) {
964 if(end) {
965 str.insert(0, fill);
966 }
967 else {
968 str.append(fill);
969 }
970 }
971 return str.toString();
972 }
973
974
975 /** 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. */
976 static public Document parse(String filename, boolean use_classloader)
977 {
978 // Try the class loader if desired (for the applet JAR file)
979 if (use_classloader) {
980 InputStream is = base.getResourceAsStream("/" + filename);
981 if (is != null) {
982 return XMLTools.parseXML(is);
983 }
984 }
985
986 // Try the file outside the classes directory
987 return XMLTools.parseXMLFile(new File(filename));
988 }
989
990
991 static public StringBuffer readXMLStream(InputStream input_stream)
992 {
993 StringBuffer xml = new StringBuffer("");
994
995 try {
996 InputStreamReader isr = new InputStreamReader(input_stream, "UTF-8");
997 BufferedReader buffered_in = new BufferedReader(isr);
998
999 String line = "";
1000 boolean xml_content = false;
1001 while((line = buffered_in.readLine()) != null) {
1002 if(xml_content) {
1003 xml.append(line);
1004 xml.append("\n");
1005 }
1006 else if(line.trim().startsWith("<?xml")) {
1007 xml_content = true;
1008 xml.append(line);
1009 xml.append("\n");
1010 }
1011 }
1012 buffered_in = null;
1013 }
1014 catch (Exception error) {
1015 System.err.println("Failed when trying to parse XML stream");
1016 error.printStackTrace();
1017 }
1018
1019 return xml;
1020 }
1021
1022
1023 /** I think this works a bit better on Unicode strings. */
1024 static public String stripNL(String raw_string)
1025 {
1026 String stripped_string = new String();
1027 for (int i = 0; i < raw_string.length(); i++) {
1028 char raw_character = raw_string.charAt(i);
1029 if (raw_character != '\n' && raw_character != '\t') {
1030 stripped_string = stripped_string + raw_character;
1031 }
1032 }
1033 return stripped_string;
1034 }
1035}
Note: See TracBrowser for help on using the repository browser.