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

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

More GLI applet improvements, by Matthew Whyte. Now uploads only metadata when only metadata has been changed, and only the source files when only the source files have been changed.

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