fedora.server.utilities.rebuild.Rebuild.java Source code

Java tutorial

Introduction

Here is the source code for fedora.server.utilities.rebuild.Rebuild.java

Source

/* The contents of this file are subject to the license and copyright terms
 * detailed in the license directory at the root of the source tree (also
 * available online at http://fedora-commons.org/license/).
 */
package fedora.server.utilities.rebuild;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import fedora.common.Constants;

import fedora.server.Server;
import fedora.server.config.Configuration;
import fedora.server.config.ModuleConfiguration;
import fedora.server.config.Parameter;
import fedora.server.config.ServerConfiguration;
import fedora.server.config.ServerConfigurationParser;
import fedora.server.errors.InitializationException;
import fedora.server.errors.LowlevelStorageException;
import fedora.server.storage.lowlevel.FileSystem;
import fedora.server.storage.lowlevel.IListable;
import fedora.server.storage.lowlevel.ILowlevelStorage;
import fedora.server.storage.translation.DODeserializer;
import fedora.server.storage.translation.DOTranslationUtility;
import fedora.server.storage.translation.FOXML1_1DODeserializer;
import fedora.server.storage.types.BasicDigitalObject;
import fedora.server.storage.types.DigitalObject;
import fedora.server.utilities.ServerUtility;

import fedora.utilities.FileComparator;

/**
 * Entry-point for rebuilding various aspects of the repository.
 *
 * @author Chris Wilper
 */
public class Rebuild implements Constants {

    private static Server server;

    private FileSystem fs;

    private static FileComparator _REVERSE_FILE_COMPARATOR = new FileComparator(true);

    /**
     * Rebuilders that the rebuild utility knows about.
     */
    public static String[] REBUILDERS = new String[] { "fedora.server.resourceIndex.ResourceIndexRebuilder",
            "fedora.server.utilities.rebuild.SQLRebuilder" };

    public Rebuild(Rebuilder rebuilder, Map<String, String> options, ServerConfiguration serverConfig)
            throws Exception {
        // set these here so DOTranslationUtility doesn't try to get a Server
        // instance
        System.setProperty("fedoraServerHost", serverConfig.getParameter("fedoraServerHost").getValue());
        System.setProperty("fedoraServerPort", serverConfig.getParameter("fedoraServerPort").getValue());
        System.setProperty("fedoraAppServerContext",
                serverConfig.getParameter("fedoraAppServerContext").getValue());
        boolean serverIsRunning = ServerUtility.pingServer("http", null, null);
        if (serverIsRunning && rebuilder.shouldStopServer()) {
            throw new Exception("The Fedora server appears to be running."
                    + "  It must be stopped before the rebuilder can run.");
        }
        if (options != null) {
            System.err.println();
            System.err.println("Rebuilding...");
            try {
                // ensure rebuilds are possible before trying anything,
                // as rebuilder.start() may be destructive!
                final String llPackage = "fedora.server.storage.lowlevel";
                String llstoreInterface = llPackage + ".ILowlevelStorage";
                String listableInterface = llPackage + ".IListable";
                ModuleConfiguration mcfg = serverConfig.getModuleConfiguration(llstoreInterface);
                Class<?> clazz = Class.forName(mcfg.getClassName());
                boolean isListable = false;
                for (Class<?> iface : clazz.getInterfaces()) {
                    if (iface.getName().equals(listableInterface)) {
                        isListable = true;
                    }
                }
                if (!isListable) {
                    throw new Exception("ERROR: Rebuilds are not supported" + " by " + clazz.getName()
                            + " because it does not implement the" + " fedora.server.storage.lowlevel.IListable"
                            + " interface.");
                }

                // looks good, so init the rebuilder
                rebuilder.start(options);

                // add each object in llstore
                ILowlevelStorage llstore = (ILowlevelStorage) getServer().getModule(llstoreInterface);
                Iterator<String> pids = ((IListable) llstore).listObjects();
                int total = 0;
                int errors = 0;
                while (pids.hasNext()) {
                    total++;
                    String pid = pids.next();
                    System.out.println("Adding object #" + total + ": " + pid);
                    if (!addObject(rebuilder, llstore, pid)) {
                        errors++;
                    }
                }
                if (errors == 0) {
                    System.out.println("SUCCESS: " + total + " objects rebuilt.");
                } else {
                    System.out.println(
                            "WARNING: " + errors + " of " + total + " objects failed to rebuild due to errors.");
                }
            } finally {
                rebuilder.finish();
                if (server != null) {
                    server.shutdown(null);
                    server = null;
                }
            }
            System.err.print("Finished.");
            System.err.println();
        }
    }

    private boolean addObject(Rebuilder rebuilder, ILowlevelStorage llstore, String pid) {
        InputStream in = null;
        try {
            in = llstore.retrieveObject(pid);
            DigitalObject obj = new BasicDigitalObject();
            DODeserializer deser = new FOXML1_1DODeserializer();
            deser.deserialize(in, obj, "UTF-8", DOTranslationUtility.SERIALIZE_STORAGE_INTERNAL);
            rebuilder.addObject(obj);
            return true;
        } catch (Exception e) {
            System.out.println("WARNING: Skipped " + pid + " due to exception: ");
            e.printStackTrace();
            return false;
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                }
            }
        }
    }

    /**
     * Gets the instance of the server appropriate for rebuilding.
     * If no such instance has been initialized yet, initialize one.
     *
     * @return the server instance.
     * @throws InitializationException if initialization fails.
     */
    public static Server getServer() throws InitializationException {
        if (server == null) {
            server = RebuildServer.getRebuildInstance(new File(Constants.FEDORA_HOME));
        }
        return server;
    }

    private static Map<String, String> getOptions(Map<String, String> descs) throws IOException {
        Map<String, String> options = new HashMap<String, String>();
        Iterator<String> iter = descs.keySet().iterator();
        while (iter.hasNext()) {
            String name = iter.next();
            String desc = descs.get(name);
            options.put(name, getOptionValue(name, desc));
        }
        int c = getChoice("Start rebuilding with the above options?",
                new String[] { "Yes", "No, let me re-enter the options.", "No, exit." });
        if (c == 0) {
            return options;
        }
        if (c == 1) {
            System.err.println();
            return getOptions(descs);
        }
        return null;
    }

    private static String getOptionValue(String name, String desc) throws IOException {
        System.err.println("[" + name + "]");
        System.err.println(desc);
        System.err.println();
        System.err.print("Enter a value --> ");
        String val = new BufferedReader(new InputStreamReader(System.in)).readLine();
        System.err.println();
        return val;
    }

    private static Rebuilder getRebuilder() throws Exception {
        String[] labels = new String[REBUILDERS.length + 1];
        Rebuilder[] rebuilders = new Rebuilder[REBUILDERS.length];
        int i = 0;
        for (i = 0; i < REBUILDERS.length; i++) {
            Rebuilder r = (Rebuilder) Class.forName(REBUILDERS[i]).newInstance();
            labels[i] = r.getAction();
            rebuilders[i] = r;
        }
        labels[i] = "Exit";
        int choiceNum = getChoice("What do you want to do?", labels);
        if (choiceNum == i) {
            return null;
        } else {
            return rebuilders[choiceNum];
        }
    }

    private static int getChoice(String title, String[] labels) throws IOException {
        boolean validChoice = false;
        int choiceIndex = -1;
        System.err.println(title);
        System.err.println();
        for (int i = 1; i <= labels.length; i++) {
            System.err.println("  " + i + ") " + labels[i - 1]);
        }
        System.err.println();
        while (!validChoice) {
            System.err.print("Enter (1-" + labels.length + ") --> ");
            BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
            String line = in.readLine();
            try {
                int choiceNum = Integer.parseInt(line);
                if (choiceNum > 0 && choiceNum <= labels.length) {
                    choiceIndex = choiceNum - 1;
                    validChoice = true;
                }
            } catch (NumberFormatException nfe) {
            }
        }
        return choiceIndex;
    }

    private InputStream getFile(File f, String searchString) throws IOException, LowlevelStorageException {

        /*
         * If we don't care about the existence of a search string, don't bother
         * looking
         */
        if (searchString == null) {
            return fs.read(f);
        }

        BufferedReader reader = null;

        try {
            reader = new BufferedReader(new InputStreamReader(fs.read(f)));
            String line = reader.readLine();
            while (line != null) {
                if (line.indexOf(searchString) != -1) {
                    return fs.read(f);
                } else {
                    line = reader.readLine();
                }
            }
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (Exception e) {
                }
            }
        }

        return null;
    }

    private static ServerConfiguration getServerConfig(File serverDir, String profile) throws IOException {
        ServerConfigurationParser parser = new ServerConfigurationParser(
                new FileInputStream(new File(serverDir, "config/fedora.fcfg")));
        ServerConfiguration serverConfig = parser.parse();
        // set all the values according to the profile, if specified
        if (profile != null) {
            int c = setValuesForProfile(serverConfig, profile);
            c += setValuesForProfile(serverConfig.getModuleConfigurations(), profile);
            c += setValuesForProfile(serverConfig.getDatastoreConfigurations(), profile);
            if (c == 0) {
                throw new IOException("Unrecognized server-profile: " + profile);
            }
        }
        return serverConfig;
    }

    private static int setValuesForProfile(Configuration config, String profile) {
        int c = 0;
        Iterator<Parameter> iter = config.getParameters().iterator();
        while (iter.hasNext()) {
            Parameter param = iter.next();
            String profileValue = param.getProfileValues().get(profile);
            if (profileValue != null) {
                param.setValue(profileValue);
                c++;
            }
        }
        return c;
    }

    private static int setValuesForProfile(List configs, String profile) {
        Iterator iter = configs.iterator();
        int c = 0;
        while (iter.hasNext()) {
            c += setValuesForProfile((Configuration) iter.next(), profile);
        }
        return c;
    }

    private static Map<String, String> getUserInput(Rebuilder rebuilder, File serverDir,
            ServerConfiguration serverConfig) throws Exception {
        if (rebuilder != null) {
            System.err.println();
            System.err.println(rebuilder.getAction());
            System.err.println();
            Map<String, String> options = getOptions(rebuilder.init(serverDir, serverConfig));
            return options;
        } else {
            return new HashMap<String, String>();
        }
    }

    public static void fail(String message, boolean showUsage, boolean exit) {
        System.err.println("Error: " + message);
        System.err.println();
        if (showUsage) {
            System.err.println("Usage: fedora-rebuild [server-profile]");
            System.err.println();
            System.err.println("server-profile : the argument you start Fedora with, such as 'mckoi'");
            System.err.println("                 or 'oracle'.  If you start fedora with 'fedora-start'");
            System.err.println("                 (without arguments), don't specify a server-profile here either.");
            System.err.println();
        }
        if (exit) {
            System.exit(1);
        }
    }

    public static void main(String[] args) {
        // tell commons-logging to use log4j
        System.setProperty("org.apache.commons.logging.LogFactory", "org.apache.commons.logging.impl.Log4jFactory");
        System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.Log4JLogger");
        // log4j
        // File log4jConfig = new File(new File(homeDir), "config/log4j.xml");
        // DOMConfigurator.configure(log4jConfig.getPath());
        String profile = null;
        if (args.length > 0) {
            profile = args[0];
        }
        if (args.length > 1) {
            fail("Too many arguments", true, true);
        }
        try {
            File serverDir = new File(new File(Constants.FEDORA_HOME), "server");
            ServerConfiguration serverConfig = getServerConfig(serverDir, profile);
            System.err.println();
            System.err.println("                       Fedora Rebuild Utility");
            System.err.println("                     ..........................");
            System.err.println();
            System.err.println("WARNING: Live rebuilds are not currently supported.");
            System.err.println("         Make sure your server is stopped before continuing.");
            System.err.println();
            System.err.println("Server directory is " + serverDir.toString());
            if (profile != null) {
                System.err.print("Server profile is " + profile);
            }
            System.err.println();
            System.err.println("---------------------------------------------------------------------");
            System.err.println();
            Rebuilder rebuilder = getRebuilder();
            Map<String, String> options = getUserInput(rebuilder, serverDir, serverConfig);
            new Rebuild(rebuilder, options, serverConfig);
        } catch (Throwable th) {
            String msg = th.getMessage();
            if (msg == null) {
                msg = th.getClass().getName();
            }
            fail(msg, false, false);
            th.printStackTrace();
        }
    }

}