Package org.exist.backup

Source Code of org.exist.backup.Main

/*
* eXist Open Source Native XML Database
* Copyright (C) 2001-2011 The eXist Project
* http://exist-db.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*  $Id$
*/
package org.exist.backup;

import java.util.concurrent.ExecutorService;
import org.apache.avalon.excalibur.cli.CLArgsParser;
import org.apache.avalon.excalibur.cli.CLOption;
import org.apache.avalon.excalibur.cli.CLOptionDescriptor;
import org.apache.avalon.excalibur.cli.CLUtil;

import org.xml.sax.SAXException;

import org.xmldb.api.DatabaseManager;
import org.xmldb.api.base.Collection;
import org.xmldb.api.base.Database;
import org.xmldb.api.base.XMLDBException;

import org.exist.util.ConfigurationHelper;
import org.exist.xmldb.DatabaseInstanceManager;
import org.exist.xmldb.XmldbURI;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

import java.net.URISyntaxException;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.prefs.Preferences;

import javax.swing.JFileChooser;
import javax.swing.JOptionPane;

import javax.xml.parsers.ParserConfigurationException;
import org.exist.backup.restore.listener.DefaultRestoreListener;
import org.exist.backup.restore.listener.GuiRestoreListener;
import org.exist.backup.restore.listener.RestoreListener;
import org.exist.client.ClientFrame;

/**
* Main.java
*
* @author Wolfgang Meier
*/
public class Main
{
    private final static int                  HELP_OPT       = 'h';
    private final static int                  USER_OPT       = 'u';
    private final static int                  PASS_OPT       = 'p';
    private final static int                  DBA_PASS_OPT   = 'P';
    private final static int                  BACKUP_OPT     = 'b';
    private final static int                  BACKUP_DIR_OPT = 'd';
    private final static int                  RESTORE_OPT    = 'r';
    private final static int                  OPTION_OPT     = 'o';
    private final static int                  GUI_OPT        = 'U';
    private final static int                  QUIET_OPT      = 'q';
    private final static int                  REBUILD_OPT    = 'R';

    private final static CLOptionDescriptor[] OPTIONS        = new CLOptionDescriptor[] {
        new CLOptionDescriptor( "help", CLOptionDescriptor.ARGUMENT_DISALLOWED, HELP_OPT, "print help on command line options and exit." ),
        new CLOptionDescriptor( "gui", CLOptionDescriptor.ARGUMENT_DISALLOWED, GUI_OPT, "start in GUI mode" ),
        new CLOptionDescriptor( "user", CLOptionDescriptor.ARGUMENT_REQUIRED, USER_OPT, "set user." ),
        new CLOptionDescriptor( "password", CLOptionDescriptor.ARGUMENT_REQUIRED, PASS_OPT, "set the password for connecting to the database." ),
        new CLOptionDescriptor( "dba-password", CLOptionDescriptor.ARGUMENT_REQUIRED, DBA_PASS_OPT, "if the backup specifies a different password for the admin/dba user, use this option " + "to specify the new password. Otherwise you will get a permission denied" ),
        new CLOptionDescriptor( "backup", CLOptionDescriptor.ARGUMENT_REQUIRED, BACKUP_OPT, "backup the specified collection." ),
        new CLOptionDescriptor( "dir", CLOptionDescriptor.ARGUMENT_REQUIRED, BACKUP_DIR_OPT, "specify the directory to use for backups." ),
        new CLOptionDescriptor( "restore", CLOptionDescriptor.ARGUMENT_REQUIRED, RESTORE_OPT, "read the specified restore file and restore the " + "resources described there." ),
        new CLOptionDescriptor( "option", CLOptionDescriptor.ARGUMENTS_REQUIRED_2 | CLOptionDescriptor.DUPLICATES_ALLOWED, OPTION_OPT, "specify extra options: property=value. For available properties see " + "client.properties." ),
        new CLOptionDescriptor( "quiet", CLOptionDescriptor.ARGUMENT_DISALLOWED, QUIET_OPT, "be quiet. Just print errors." ),
        new CLOptionDescriptor( "rebuild", CLOptionDescriptor.ARGUMENT_DISALLOWED, REBUILD_OPT, "rebuild the app repository after restore.")
    };

    /**
     * Constructor for Main.
     *
     * @param  args  DOCUMENT ME!
     */
    @SuppressWarnings( "unchecked" )
    public static void process( String[] args )
    {
        // read properties
        final Properties properties = new Properties();

        try {
            final File        propFile = ConfigurationHelper.lookup( "backup.properties" );
            InputStream pin;

            if( propFile.canRead() ) {
                pin = new FileInputStream( propFile );
            } else {
                pin = Main.class.getResourceAsStream( "backup.properties" );
            }

            if( pin != null ) {

                try {
                    properties.load( pin );
                }
                finally {
                    pin.close();
                }
            }

        }
        catch( final IOException ioe ) {
        }

        final Preferences        preferences = Preferences.userNodeForPackage( Main.class );

        // parse command-line options
        final CLArgsParser optParser   = new CLArgsParser( args, OPTIONS );

        if( optParser.getErrorString() != null ) {
            System.err.println( "ERROR: " + optParser.getErrorString() );
            return;
        }
        final List<CLOption> opts          = optParser.getArguments();
        String               optionBackup  = null;
        String               optionRestore = null;
        String               optionPass    = null;
        String               optionDbaPass = null;
        boolean              doBackup      = false;
        boolean              doRestore     = false;
        boolean              guiMode       = false;
        boolean              quiet         = false;
        boolean              rebuildRepo   = false;

        for( final CLOption option : opts ) {

            switch( option.getId() ) {

                case HELP_OPT: {
                    printUsage();
                    return;
                }

                case GUI_OPT: {
                    guiMode = true;
                    break;
                }

                case QUIET_OPT: {
                    quiet = true;
                    break;
                }
                case OPTION_OPT: {
                    properties.setProperty( option.getArgument( 0 ), option.getArgument( 1 ) );
                    break;
                }

                case USER_OPT: {
                    properties.setProperty( "user", option.getArgument() );
                    break;
                }

                case PASS_OPT: {
                    properties.setProperty( "password", option.getArgument() );
                    optionPass = option.getArgument(); //remove after change inside restore
                    break;
                }

                case DBA_PASS_OPT: {
                    optionDbaPass = option.getArgument();
                    break;
                }

                case BACKUP_OPT: {
                    if( option.getArgumentCount() == 1 ) {
                        optionBackup = option.getArgument();
                    } else {
                        optionBackup = null;
                    }
                    doBackup = true;
                    break;
                }

                case RESTORE_OPT: {
                    if( option.getArgumentCount() == 1 ) {
                        optionRestore = option.getArgument();
                    }
                    doRestore = true;
                    break;
                }

                case BACKUP_DIR_OPT: {
                    properties.setProperty( "backup-dir", option.getArgument() );
                    break;
                }

                case REBUILD_OPT: {
                    rebuildRepo = true;
                    break;
                }
            }
        }

        // initialize driver
        Database database;

        try {
            final Class<?> cl = Class.forName( properties.getProperty( "driver", "org.exist.xmldb.DatabaseImpl" ) );
            database = (Database)cl.newInstance();
            database.setProperty( "create-database", "true" );

            if( properties.containsKey( "configuration" ) ) {
                database.setProperty( "configuration", properties.getProperty( "configuration" ) );
            }
            DatabaseManager.registerDatabase( database );
        }
        catch( final ClassNotFoundException e ) {
            reportError( e );
            return;
        }
        catch( final InstantiationException e ) {
            reportError( e );
            return;
        }
        catch( final IllegalAccessException e ) {
            reportError( e );
            return;
        }
        catch( final XMLDBException e ) {
            reportError( e );
            return;
        }

        // process
        if( doBackup ) {

            if( optionBackup == null ) {

                if( guiMode ) {
                    final CreateBackupDialog dialog = new CreateBackupDialog( properties.getProperty( "uri", "xmldb:exist://" ), properties.getProperty( "user", "admin" ), properties.getProperty( "password", "" ), new File( preferences.get( "directory.backup", System.getProperty( "user.dir" ) ) ) );

                    if( JOptionPane.showOptionDialog( null, dialog, "Create Backup", JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, null, null ) == JOptionPane.YES_OPTION ) {
                        optionBackup = dialog.getCollection();
                        properties.setProperty( "backup-dir", dialog.getBackupTarget() );
                    }
                } else {
                    optionBackup = XmldbURI.ROOT_COLLECTION;
                }
            }

            if( optionBackup != null ) {

                try {
                    final Backup backup = new Backup( properties.getProperty( "user", "admin" ), properties.getProperty( "password", "" ), properties.getProperty( "backup-dir", "backup" ), XmldbURI.xmldbUriFor( properties.getProperty( "uri", "xmldb:exist://" ) + optionBackup ), properties );
                    backup.backup( guiMode, null );
                }
                catch( final Exception e ) {
                    reportError( e );
                }
            }
        }

        if( doRestore ) {

            if( ( optionRestore == null ) && guiMode ) {
                final JFileChooser chooser = new JFileChooser();
                chooser.setMultiSelectionEnabled( false );
                chooser.setFileSelectionMode( JFileChooser.FILES_ONLY );

                if( chooser.showDialog( null, "Select backup file for restore" ) == JFileChooser.APPROVE_OPTION ) {
                    final File f = chooser.getSelectedFile();
                    optionRestore = f.getAbsolutePath();
                }
            }

            if(optionRestore != null) {

                final String username = properties.getProperty( "user", "admin" );
                final File f = new File(optionRestore);
                final String uri = properties.getProperty( "uri", "xmldb:exist://");
               
                try {
                    if(guiMode) {
                        restoreWithGui(username, optionPass, optionDbaPass, f, uri);
                    } else {
                        restoreWithoutGui(username, optionPass, optionDbaPass, f, uri, rebuildRepo);
                    }
                }
                catch( final Exception e ) {
                    reportError( e );
                }
            }
        }

        try {
            String uri = properties.getProperty( "uri", XmldbURI.EMBEDDED_SERVER_URI_PREFIX );
            if(!(uri.contains(XmldbURI.ROOT_COLLECTION) || uri.endsWith( XmldbURI.ROOT_COLLECTION))) {
                uri += XmldbURI.ROOT_COLLECTION;
            }

            final Collection root = DatabaseManager.getCollection(uri, properties.getProperty( "user", "admin" ), ( optionDbaPass == null ) ? optionPass : optionDbaPass );
            shutdown( root );
        }
        catch( final Exception e ) {
            reportError( e );
        }
        System.exit( 0 );
    }

    private static void restoreWithoutGui(final String username, final String password, final String dbaPassword, final File f,
                                          final String uri, final boolean rebuildRepo) {
       
        final RestoreListener listener = new DefaultRestoreListener();
        final Restore restore = new Restore();

        try {
            restore.restore(listener, username, password, dbaPassword, f, uri);
        } catch(final FileNotFoundException fnfe) {
            listener.error(fnfe.getMessage());
        } catch(final IOException ioe) {
            listener.error(ioe.getMessage());
        } catch(final SAXException saxe) {
            listener.error(saxe.getMessage());
        } catch(final XMLDBException xmldbe) {
            listener.error(xmldbe.getMessage());
        } catch(final ParserConfigurationException pce) {
            listener.error(pce.getMessage());
        } catch(final URISyntaxException use) {
            listener.error(use.getMessage());
        }
       
        if(listener.hasProblems()) {
            System.err.println(listener.warningsAndErrorsAsString());
        }
        if (rebuildRepo) {
            System.out.println("Rebuilding application repository ...");
            System.out.println("URI: " + uri);
            try {
                String rootURI = uri;
                if(!(rootURI.contains(XmldbURI.ROOT_COLLECTION) || rootURI.endsWith( XmldbURI.ROOT_COLLECTION))) {
                    rootURI += XmldbURI.ROOT_COLLECTION;
                }
                final Collection root = DatabaseManager.getCollection(rootURI, username, dbaPassword);
                if (root != null) {
                    ClientFrame.repairRepository(root);
                    System.out.println("Application repository rebuilt successfully.");
                } else {
                    System.err.println("Failed to retrieve root collection: " + uri);
                }
            } catch (XMLDBException e) {
                reportError(e);
                System.err.println("Rebuilding application repository failed!");
            }
        } else {
            System.out.println("\nIf you restored collections inside /db/apps, you may want\n" +
                    "to rebuild the application repository. To do so, run the following query\n" +
                    "as admin:\n\n" +
                    "import module namespace repair=\"http://exist-db.org/xquery/repo/repair\"\n" +
                    "at \"resource:org/exist/xquery/modules/expathrepo/repair.xql\";\n" +
                    "repair:rebuild-all()\n");
        }
    }
   
    private static void restoreWithGui(final String username, final String password, final String dbaPassword, final File f, final String uri) {
       
        final GuiRestoreListener listener = new GuiRestoreListener();
       
        final Callable<Void> callable = new Callable<Void>() {

            @Override
            public Void call() throws Exception {
               
                final Restore restore = new Restore();
               
                try {
                    restore.restore(listener, username, password, dbaPassword, f, uri);

                    listener.hideDialog();

                    if (JOptionPane.showConfirmDialog(null, "Would you like to rebuild the application repository?\nThis is only necessary if application packages were restored.", "Rebuild App Repository?",
                            JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
                        System.out.println("Rebuilding application repository ...");
                        try {
                            String rootURI = uri;
                            if(!(rootURI.contains(XmldbURI.ROOT_COLLECTION) || rootURI.endsWith( XmldbURI.ROOT_COLLECTION))) {
                                rootURI += XmldbURI.ROOT_COLLECTION;
                            }
                            final Collection root = DatabaseManager.getCollection(rootURI, username, dbaPassword);
                            ClientFrame.repairRepository(root);
                            System.out.println("Application repository rebuilt successfully.");
                        } catch (XMLDBException e) {
                            reportError(e);
                            System.err.println("Rebuilding application repository failed!");
                        }
                    }
                } catch (final Exception e) {
                    ClientFrame.showErrorMessage(e.getMessage(), null); //$NON-NLS-1$
                } finally {
                    if(listener.hasProblems()) {
                        ClientFrame.showErrorMessage(listener.warningsAndErrorsAsString(), null);
                    }
                }
               
                return null;
            }
        };
      
        final ExecutorService executor = Executors.newSingleThreadExecutor();
        final Future<Void> future = executor.submit(callable);

        while(!future.isDone() && !future.isCancelled()) {
            try {
                future.get(100, TimeUnit.MILLISECONDS);
            } catch (final InterruptedException ie) {

            } catch (final ExecutionException ee) {
                break;
            } catch (final TimeoutException te) {

            }
        }
    }
   
   
    private static void reportError( Throwable e )
    {
        e.printStackTrace();

        if( e.getCause() != null ) {
            System.err.println( "caused by " );
            e.getCause().printStackTrace();
        }
       
        System.exit(1);
    }


    private static void printUsage()
    {
        System.out.println( "Usage: java " + Main.class.getName() + " [options]" );
        System.out.println( CLUtil.describeOptions( OPTIONS ).toString() );
    }


    private static void shutdown( Collection root )
    {
        try {
            final DatabaseInstanceManager mgr = (DatabaseInstanceManager)root.getService( "DatabaseInstanceManager", "1.0" );

            if( mgr == null ) {
                System.err.println( "service is not available" );
            } else if( mgr.isLocalInstance() ) {
                System.out.println( "shutting down database..." );
                mgr.shutdown();
            }
        }
        catch( final XMLDBException e ) {
            System.err.println( "database shutdown failed: " );
            e.printStackTrace();
        }
    }


    public static void main( String[] args )
    {
        try {
            process( args );
        }
        catch( final Throwable e ) {
            e.printStackTrace();
            System.exit(1);
        }
    }
}
TOP

Related Classes of org.exist.backup.Main

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.