source: main/trunk/release-kits/shared/core/uninstaller/Uninstaller.java@ 23242

Last change on this file since 23242 was 23242, checked in by sjm84, 14 years ago

A few minor updates to the uninstaller

File size: 18.2 KB
RevLine 
[17805]1import java.util.ResourceBundle;
[17236]2import java.awt.*;
3import java.awt.event.*;
4import javax.swing.JFrame;
5import javax.swing.JPanel;
6import javax.swing.JCheckBox;
7import javax.swing.JLabel;
8import javax.swing.JButton;
9import javax.swing.BoxLayout;
10import javax.swing.JTextArea;
11import javax.swing.JScrollPane;
12import javax.swing.border.EmptyBorder;
13import javax.swing.JOptionPane;
14import javax.swing.Box;
15import javax.swing.JDialog;
[17805]16import javax.swing.JMenuItem;
17import javax.swing.JPopupMenu;
18
[17236]19import java.io.File;
20import java.io.BufferedReader;
21import java.io.FileReader;
[17805]22import java.io.FileNotFoundException;
23import java.io.FileWriter;
24import java.io.IOException;
25
[17236]26import java.util.regex.Pattern;
27import java.util.regex.Matcher;
[17435]28import java.util.ArrayList;
[17236]29
[17805]30import javax.swing.SwingUtilities;
[17792]31
[18042]32import java.util.Enumeration;
33import java.awt.Font;
34import javax.swing.plaf.FontUIResource;
35import javax.swing.UIManager;
[17805]36
[18042]37
38
[17236]39public class Uninstaller {
40
41 public static int SCREEN_WIDTH = 600;
42 public static int SCREEN_HEIGHT = 450;
43
[17685]44 public static final ResourceBundle bundle = ResourceBundle.getBundle("resources.LanguagePack");
[17236]45
[23210]46 public static final File gs2InstallProps = new File("../etc/installation.properties");
47 public static final File gs3InstallProps = new File("../installation.properties");
[17236]48
49 boolean keepCollections = true;
50 //boolean keepModifiedFiles = false;
51 boolean ignoreReadOnlys = false;
52
53 JFrame frame;
54 JCheckBox keepCollectionsCheckbox;
55 //JCheckBox keepModifiedFilesCheckbox;
[17685]56
57 //panels
[17236]58 JPanel progressPanel;
59 JPanel introPanel;
[17685]60
61 //toolbars
62 JPanel initialToolbar;
63 JPanel finishToolbar;
64
65
[17792]66 JScrollPane logPane;
[17805]67 FollowingJTextArea log;
[17236]68 JButton uninstallButton;
[17828]69 JButton finishButton;
[17805]70
71 boolean confirmationGiven = false;
72 Thread mainThread = null;
[17236]73
74 public static void main( String[] args ) {
75 (new Uninstaller()).go();
76 }
77
78 public void go() {
79
[18042]80 //set font
81 String new_default_font_str = null;
82 if ( System.getProperty("os.name").equals("Linux") ) {
83 new_default_font_str = "Bitstream Cyberbit";
84 } else if ( System.getProperty("os.name").startsWith("Windows") ) {
85 new_default_font_str = "Arial Unicode MS";
86 }
87
88 if ( new_default_font_str != null ) {
89
90 FontUIResource default_font = new FontUIResource(new_default_font_str, Font.PLAIN, 12);
91 Enumeration keys = UIManager.getDefaults().keys();
92 while (keys.hasMoreElements()) {
93 Object key = keys.nextElement();
94 Object value = UIManager.get(key);
95 if (value instanceof FontUIResource) {
96 UIManager.put(key, default_font);
97 }
98 }
99
100 }
101
102
[17805]103 mainThread = Thread.currentThread();
104
[17236]105 frame = new JFrame();
106 frame.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
107 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
108 frame.setLocation(screenSize.width/2 - frame.getWidth()/2, screenSize.height/2 - frame.getHeight()/2);
109
[17685]110 //The panel to introduce and ask for options
111 introPanel = new JPanel(new BorderLayout());
112 JPanel innerPanel = new JPanel();
113 innerPanel.setLayout( new BoxLayout(innerPanel,BoxLayout.Y_AXIS) );
114 innerPanel.setBorder( new EmptyBorder(10, 10, 5, 10) );
115 introPanel.add( BorderLayout.WEST, innerPanel );
116
[17236]117 //The panel to be displayed while the uninstall is happening
118 progressPanel = new JPanel(new BorderLayout());
[17792]119 log = new FollowingJTextArea();
120 log.setEditable(false);
121 logPane = new JScrollPane(log);
[17236]122 logPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
123 logPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
124 progressPanel.add( BorderLayout.NORTH, new JLabel("Progress") );
[17805]125 progressPanel.add( BorderLayout.CENTER, logPane );
[17236]126
127 //initial toolbar
128 initialToolbar = new JPanel();
[17685]129 uninstallButton = new JButton(bundle.getString("uninstaller.uninstall"));
130 uninstallButton.addActionListener( new StartUninstallListener() );
131 JButton cancelButton = new JButton(bundle.getString("uninstaller.cancel"));
[17236]132 cancelButton.addActionListener( new CancelListener() );
[17685]133 initialToolbar.add(uninstallButton);
[17236]134 initialToolbar.add(cancelButton);
135
136 //finish toolbar
137 finishToolbar = new JPanel();
[17828]138 finishButton = new JButton(bundle.getString("uninstaller.finish"));
[17236]139 finishButton.addActionListener( new FinishListener() );
[17828]140 finishButton.setEnabled( false );
[17236]141 finishToolbar.add( finishButton );
142
[17685]143
[17236]144 String pwd = (new File(".")).getAbsolutePath();
145 if ( pwd.endsWith("/.") ) {
146 pwd = pwd.substring( 0, pwd.length()-2 );
147 }
148
149 JLabel l;
150
[17685]151 l = new JLabel(bundle.getString("uninstaller.will.uninstall.from"));
[17236]152 innerPanel.add( l );
153 innerPanel.add( Box.createRigidArea(new Dimension(5,5)) );
154
155 l = new JLabel(" " + pwd);
156 l.setFont( new Font( "Monospaced", Font.BOLD, 14 ) );
157 innerPanel.add( l );
158 innerPanel.add( Box.createRigidArea(new Dimension(5,20)) );
159
[17685]160 l = new JLabel(bundle.getString("uninstaller.uninstall.options"));
[17236]161 innerPanel.add( l );
162
[17685]163 keepCollectionsCheckbox = new JCheckBox(bundle.getString("uninstaller.keep.collections"));
[17236]164 keepCollectionsCheckbox.setSelected(true);
165 innerPanel.add( keepCollectionsCheckbox );
166
167 //keepModifiedFilesCheckbox = new JCheckBox("Keep Modified Files");
168 //innerPanel.add( keepModifiedFilesCheckbox );
169
[17685]170 frame.setTitle( bundle.getString("uninstaller.greenstone.uninstaller") );
[17236]171 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
[17685]172
173 //the initial screen
[17792]174 frame.getContentPane().add( BorderLayout.CENTER, introPanel );
[17685]175 frame.getContentPane().add( BorderLayout.SOUTH, initialToolbar );
176
[17236]177 frame.setVisible(true);
178
179 boolean ready = precheck();
180 if ( !ready ) {
181 System.exit(0);
182 }
183
[17805]184 //block and wait for signal to do the uninstall
185 do {
186 try {
187 Thread.sleep( Long.MAX_VALUE );
188 } catch ( InterruptedException ie ) {
189 }
190 } while ( !confirmationGiven );
191
192 doUninstall();
[17828]193 finishButton.setEnabled( true );
[17805]194
[17236]195 }
196
197 class CancelListener implements ActionListener {
198 public void actionPerformed( ActionEvent e ) {
199 System.exit(0);
200 }
201 }
202
203 class FinishListener implements ActionListener {
204 public void actionPerformed( ActionEvent e ) {
205 System.exit(0);
206 }
207 }
208
209 class StartUninstallListener implements ActionListener {
210 public void actionPerformed( ActionEvent e ) {
211
212 //The dialog to ask "are you sure"
[17685]213 Object[] options = { bundle.getString("uninstaller.uninstall"), bundle.getString("uninstaller.cancel") };
[17236]214 int n = JOptionPane.showOptionDialog(
215 frame,
[17685]216 bundle.getString("uninstaller.are.you.sure"),
217 bundle.getString("uninstaller.confirmation"),
[17236]218 JOptionPane.YES_NO_CANCEL_OPTION,
219 JOptionPane.QUESTION_MESSAGE,
220 null,
221 options,
222 options[0]
223 );
[17685]224 if ( n == 1 ) {
[17236]225 return;
226 }
227
228 keepCollections = keepCollectionsCheckbox.isSelected();
229 //keepModifiedFiles = keepModifiedFilesCheckbox.isSelected();
230
231 //confirm delete of collections
232 if ( !keepCollections ) {
[17685]233 options[0] = bundle.getString("uninstaller.continue");
234 options[1] = bundle.getString("uninstaller.cancel");
[17236]235 n = JOptionPane.showOptionDialog(
236 frame,
[17685]237 bundle.getString("uninstaller.are.you.sure.collections"),
238 bundle.getString("uninstaller.confirmation"),
[17236]239 JOptionPane.YES_NO_CANCEL_OPTION,
240 JOptionPane.WARNING_MESSAGE,
241 null,
242 options,
243 options[0]
244 );
[17685]245 if ( n == 1 ) {
[17236]246 return;
247 }
248 }
249
[17685]250
251 introPanel.setVisible( false );
[17236]252 frame.getContentPane().remove(introPanel);
[17685]253 frame.getContentPane().add( BorderLayout.CENTER, progressPanel );
[17236]254
[17805]255 initialToolbar.setVisible( false );
256 frame.getContentPane().remove( initialToolbar );
257 frame.getContentPane().add( BorderLayout.SOUTH, finishToolbar);
258
259 confirmationGiven = true;
260 mainThread.interrupt();
[17236]261 }
262 }
263
264 /**
265 * Do some checks
266 */
267 public boolean precheck() {
268
269 if ( !gs2InstallProps.exists() && !gs3InstallProps.exists() ) {
[17805]270 log( bundle.getString("uninstaller.error.couldnt.find.install.props") + "\n" );
[17685]271 JOptionPane.showMessageDialog(frame, bundle.getString("uninstaller.error.couldnt.find.install.props"), bundle.getString("uninstaller.error"), 0);
[17236]272 return false;
273 }
274 return true;
275
276 }
277
[17805]278 public void log( String s ) {
279 SwingUtilities.invokeLater( new LogAppender( s ) );
280 //log.append( s );
281
282 }
283
[17236]284 /**
285 * Does the uninstall
286 */
287 public void doUninstall() {
288
289 File startMenuPath = null;
290
291 //delete the start menu group if present
292
293 if ( gs2InstallProps.exists() ) {
294 String smp = null;
295 try {
[17846]296 smp = getPropertyValue( "installed.startmenu.path", gs2InstallProps );
[17839]297 } catch ( Exception e ) {
298 System.err.println( e.getMessage() );
299 }
[17236]300 if ( smp != null ) {
301 startMenuPath = new File( smp );
302 }
303 } else if ( gs3InstallProps.exists() ) {
304 String smp = null;
305 try {
[17846]306 smp = getPropertyValue( "installed.startmenu.path", gs3InstallProps );
[17839]307 } catch ( Exception e ) {
308 System.err.println( e.getMessage() );
309 }
[17236]310 if ( smp != null ) {
311 startMenuPath = new File( smp );
312 }
313 }
314
315 if ( startMenuPath == null ) {
[17805]316
317 log( bundle.getString("uninstaller.info.no.startmenu") + "\n" );
318
[17236]319 } else {
[17805]320 log( "StartMenu Path: " + startMenuPath.getAbsolutePath() + "\n" );
321
[17236]322 try {
323 recursiveDelete( startMenuPath, null );
324 } catch ( CancelledException ce ) {
[17805]325 log( bundle.getString("uninstaller.cancelled") + "\n" );
[17236]326 changeToFinishToolbar();
[17685]327 JOptionPane.showMessageDialog(frame, bundle.getString("uninstaller.cancelled"), bundle.getString("uninstaller.complete"), 1);
[17236]328 return;
329 }
330 }
331
332 //delete the files
333 try {
[17435]334 ArrayList exceptions = new ArrayList();
[17434]335
336 //never delete the things we are currently running
[23210]337 exceptions.add( new File("../bin/search4j.exe") );
338 exceptions.add( new File("../bin/search4j") );
[17792]339
[23210]340 exceptions.add( new File("../bin/windows/search4j.exe") );
341 exceptions.add( new File("../bin/linux/search4j") );
342 exceptions.add( new File("../bin/darwin/search4j") );
[17792]343
[23210]344 exceptions.add( new File("../packages/jre") );
345 exceptions.add( new File("../uninstall") );
[17434]346
[17236]347 if ( keepCollections ) {
[23210]348 exceptions.add( new File("../web/sites/localsite/collect") );
349 exceptions.add( new File("../collect") );
[17236]350 }
351
[17434]352
[17236]353 File cd = null;
354 try {
355 cd = new File( new File(".").getCanonicalPath() );
356 } catch ( Exception e ) {
[17685]357 JOptionPane.showMessageDialog(frame, bundle.getString("uninstaller.failed.to.figure.cd"), bundle.getString("uninstaller.error") , 0);
[17236]358 System.exit(0);
359 }
[17435]360
361 File[] ex = new File[exceptions.size()];
362 for ( int i=0; i<exceptions.size(); i++ ) {
363 ex[i] = (File)exceptions.get(i);
364 }
365
[23210]366 //recursiveDelete( cd , ex );
367 selectiveDelete ( cd, ex );
[17236]368 } catch ( CancelledException ce ) {
[17805]369 log( bundle.getString("uninstaller.cancelled") + "\n" );
[17685]370 JOptionPane.showMessageDialog(frame, bundle.getString("uninstaller.cancelled"), bundle.getString("uninstaller.complete"), 1);
[17236]371 changeToFinishToolbar();
372 return;
373 }
[17426]374
375 //create the flag file to indicate the uninstaller wants jre and uninst.jar to be deleted
376 try {
377 (new File("uninst.flag")).createNewFile();
378 } catch (Exception e) {
[17805]379 log( bundle.getString("uninstaller.couldnt-create-flagfile") + "\n" );
[17426]380 }
381
[17236]382 changeToFinishToolbar();
[17805]383 log( bundle.getString("uninstaller.finished") );
[17685]384 JOptionPane.showMessageDialog(frame, bundle.getString("uninstaller.finished"), bundle.getString("uninstaller.complete"), 1);
[17236]385 }
386
[17805]387 class LogAppender implements Runnable {
388 String s;
389
390 public LogAppender( String s ) {
391 this.s = s;
392 }
393
394 public void run() {
395 log.append( s );
396 }
397
398 }
399
[17236]400 public String getPropertyValue( String propertyName, File file ) throws Exception {
[17839]401
[17236]402 String regex = "^" + propertyName.replaceAll("\\.","\\\\.") + "[:=]\\s*(.*)$";
403 Pattern wantedLine = Pattern.compile( regex );
404 BufferedReader in = null;
405 try {
406 in = new BufferedReader(new FileReader( file ));
407 } catch ( Exception e ) {
408 throw new Exception( "Error - couldn't open the properties file " + file );
409 }
410
411 String line, value = null;
412
413 try {
414 boolean found = false;
415 while ( (line = in.readLine()) != null && !found ) {
416
417 Matcher matcher = wantedLine.matcher( line );
418 if ( matcher.matches() ) {
419 //found the property
420 //System.err.println( "found the property" );
421 value = matcher.group(1);
422 value = value.replaceAll( "#.*", "" ).trim();
423 return value;
424 }
425
426 }
427
428 //close the input stream
429 //System.err.println( "close the input stream" );
430 in.close();
431
432 } catch ( Exception e ) {
433 throw new Exception( "Error - couldn't read from the properties file" );
434 }
435 return null;
436
437 }
[23210]438
439 public void selectiveDelete( File f, File[] exceptions ) throws CancelledException {
440
441 File[] files = (new File(".")).listFiles();
442
443 for ( int i=0; i < files.length; i++) {
444 if( files[i].getAbsolutePath().endsWith(".uninstall") ) {
[23242]445 String[] paths = getPathsFromUninstallFile(files[i]);
[23210]446
447 for(int j=0; j < paths.length; j++) {
448 recursiveDelete( new File(".." + File.separator + paths[j]), exceptions );
449 }
450 }
451 }
452 }
453
454 public String[] getRelevantPathsFromUninstallFile ( File uninstallFile ) {
455
456 ArrayList paths = new ArrayList();
457 try {
458 BufferedReader in = new BufferedReader(new FileReader(uninstallFile));
459
460 String line;
461 while ( (line = in.readLine()) != null ) {
462 int separatorIndex = line.indexOf(File.separator);
463
464 if ( separatorIndex == -1 && line.length() > 0 && !paths.contains(line)) {
465 paths.add(line);
466 }
467 else if ( separatorIndex > -1 && line.length() > 0) {
468 String path = line.substring(0, separatorIndex);
469 if ( !paths.contains(path) ) {
470 paths.add(path);
471 }
472 }
473 }
474
475 in.close();
476 }
477 catch( Exception ex ) {
478 ex.printStackTrace();
479 return null;
480 }
481 return (String[]) paths.toArray(new String[0]);
482 }
[23242]483
484 public String[] getPathsFromUninstallFile ( File uninstallFile ) {
485
486 ArrayList paths = new ArrayList();
487 try {
488 BufferedReader in = new BufferedReader(new FileReader(uninstallFile));
489
490 String line;
491 while ( (line = in.readLine()) != null ) {
492 if (line.length() > 0 && !paths.contains(line)) {
493 paths.add(line);
494 }
495 }
496
497 in.close();
498 }
499 catch( Exception ex ) {
500 ex.printStackTrace();
501 return null;
502 }
503 return (String[]) paths.toArray(new String[0]);
504 }
[17236]505
506 public void recursiveDelete( File f, File[] exceptions ) throws CancelledException {
507
508 //log.append( "Processing: " + f.getAbsolutePath() + "\n" );
509
510 // if this is an exception, return
511 if ( exceptions != null ) {
512 for ( int i=0; i<exceptions.length; i++ ) {
513 //System.out.println( "Comparing '" + f.getAbsolutePath() + "' with '" + exceptions[i].getAbsolutePath() + "'" );
514 try {
515 if ( f.equals( exceptions[i] ) || f.getCanonicalPath().equals(exceptions[i].getCanonicalPath()) ) {
[17805]516 log( Strings.replaceAll( bundle.getString("uninstaller.info.skipping"), "{file}", f.getAbsolutePath() ) + "\n" );
[17236]517 return;
518 }
519 } catch ( Exception e ) {
520 System.err.println("ERROR: Failed to resolve a path");
521 return;
522 }
523 }
524 }
525
526 //if it is a directory, recurse
527 if (f.isDirectory()) {
528 File[] files = f.listFiles();
[17251]529 if ( files != null && files.length > 0) {
[17236]530 for ( int i=0; i<files.length; i++ ) {
531 try {
532 recursiveDelete( files[i], exceptions );
533 } catch ( CancelledException ce ) {
534 throw new CancelledException();
535 }
536 }
537 }
538 }
539
540 //if this is now an empty directory, or a file, delete it
541 boolean doDelete = true;
542 if ( f.isDirectory() ) {
543 File[] files = f.listFiles();
[17251]544 doDelete = ( files == null || files.length == 0 );
[17236]545 }
546
547 if ( doDelete ) {
548
[17805]549 log( Strings.replaceAll( bundle.getString("uninstaller.deleting"), "{file}", f.getAbsolutePath() ) + "\n" );
[17792]550
[17805]551 if ( !f.delete() ) {
552 log( "*********\n" + Strings.replaceAll( bundle.getString("uninstaller.warning.couldnt.delete"), "{file}", f.getAbsolutePath() ) + "\n*********\n" );
553 return;
[17236]554 }
555 }
556
557 }
558
559 class CancelledException extends Exception {}
560
561 public void changeToFinishToolbar() {
562 initialToolbar.setVisible(false);
563 frame.getContentPane().remove(initialToolbar);
564 frame.getContentPane().add( BorderLayout.SOUTH, finishToolbar );
565 finishToolbar.setVisible(true);
566 }
567
568}
[17254]569
570class Strings {
571 static String replaceAll( String s, String nugget, String replacement ) {
572 StringBuffer string = new StringBuffer(s);
573 StringBuffer r = new StringBuffer();
574
575 int io = 0;
576 while ( (io=string.toString().indexOf(nugget)) != -1 ) {
577 r.append( string.toString().substring( 0, io ) );
578 r.append( replacement );
579 string.delete( 0, io + nugget.length() );
580 }
581 r.append( string.toString() );
582 return r.toString();
583 }
584}
585
[17805]586class FollowingJTextArea extends JTextArea {
[17792]587
588 private boolean follow = true;
589
590 public FollowingJTextArea() {
591 jInit();
592 }
593
594
595 private void jInit(){
596 final JPopupMenu popUp = getPopupMenu();
597 this.add(popUp);
598 this.addMouseListener(new MouseAdapter(){
599 public void mouseClicked(MouseEvent e) {
600 if (e.getButton() == e.BUTTON3) {
601 popUp.show(FollowingJTextArea.this,e.getX(),e.getY());
602 }
603 }
604 });
605 }
606
607 public boolean isFollow() {
608 return follow;
609 }
610 public void setFollow(boolean follow) {
611 this.follow = follow;
612 }
613
614 private void scrollToEnd(){
615 setCaretPosition(getDocument().getLength());
616 }
617 private void toggleFollow(){
618 setFollow(!isFollow());
619 }
620
621 /**
622 * Appends the given text to the end of the document.
623 *
624 * @param str the text to insert
625 * @todo Implement this javax.swing.JTextArea method
626 */
627 public void append(String str) {
628 super.append(str);
629 if(follow)scrollToEnd();
630 }
631 private JPopupMenu getPopupMenu() {
632 JPopupMenu contextMenu = new JPopupMenu("Options");
633
634 JMenuItem toggleFollowMenu = new JMenuItem("Toggle Follow");
635 toggleFollowMenu.addActionListener(new ActionListener() {
636 public void actionPerformed(ActionEvent e) {
637 toggleFollow();
638 }
639 });
640 contextMenu.add(toggleFollowMenu);
641
642 JMenuItem jumpToEndMenu = new JMenuItem("Jump To End");
643 jumpToEndMenu.addActionListener(new ActionListener() {
644 public void actionPerformed(ActionEvent e) {
645 setCaretPosition(getDocument().getLength());
646 }
647 });
648 contextMenu.add(toggleFollowMenu);
649
650 JMenuItem clearTextMenu = new JMenuItem("Clear Text");
651 clearTextMenu.addActionListener(new ActionListener() {
652 public void actionPerformed(ActionEvent e) {
653 setText("");
654 }
655 });
656 contextMenu.add(clearTextMenu);
657 return contextMenu;
658 }
659}
Note: See TracBrowser for help on using the repository browser.