/*
 * $Header: /home/cvspublic/jakarta-slide/proposals/tamino/src/store/org/apache/slide/store/tamino/tools/repairer/Repair.java,v 1.4 2004/12/15 10:38:27 pnever Exp $
 * $Revision: 1.4 $
 * $Date: 2004/12/15 10:38:27 $
 *
 * ====================================================================
 *
 * Copyright 1999-2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.slide.store.tamino.tools.repairer;

import java.io.File;
import java.io.IOException;
import org.apache.slide.common.Domain;
import org.apache.slide.common.Namespace;
import org.apache.slide.store.tamino.security.XURMAccessor;
import org.apache.slide.store.tamino.tools.Command;
import org.apache.slide.store.tamino.tools.Tws;
import org.apache.slide.store.tamino.tools.config.Security;
import org.apache.slide.store.tamino.tools.config.UrmTemplate;
import org.apache.slide.store.tamino.tools.repairer.RepairHandler;
import org.apache.slide.urm.URMException;
import org.apache.slide.urm.common.URMPrincipal;
import org.apache.slide.util.XAssertionFailed;
import org.apache.slide.util.XException;
import org.apache.slide.util.cli.Abort;
import org.apache.slide.util.cli.Actuals;
import org.apache.slide.util.cli.CommandLine;
import org.apache.slide.util.os.Catalina;


/**
 * This class checks the integrity of the stored documents in Tamino
 * for xdav purposes and try to repair inconsistencies.
 *
 * <P>
 * The following table lists all checks which will be performed:
 * <P>
 *
 * <table border=1 cellpadding=5>
 * <tr>
 * <th>Check</th>
 * <th>Action to repair this problem</th>
 * </tr>
 *
 * <tr>
 *   <td>Find all documents without metadata.</td>
 *   <td>Add the missing metadata structure</td>
 * </tr>
 * <tr>
 *   <td>Find all metadata without a document.</td>
 *   <td>Remove this metadata.</td>
 * </tr>
 * <tr>
 *   <td>Check correctness of stored metadata DTD.</td>
 *   <td>Create a new correct DTD and store it into Tamino.</td>
 * </tr>
 * <tr>
 *   <td>Check correctness of metadata concerning the DTD.</td>
 *   <td>?</td>
 * </tr>
 * <tr>
 *   <td>Check for unique URL's in metadata.</td>
 *   <td>Delete the doubles (?).</td>
 * </tr>
 * <tr>
 *   <td>Check for the correct content length.</td>
 *   <td>Correct the content length.</td>
 * </tr>
 * <tr>
 *   <td>Check the consistency of the directory information:
 *       a directory has more or less entries as real documents.</td>
 *   <td>Correct the directory entry.</td>
 * </tr>
 * <tr>
 *   <td>Check the consistency of the directory information:
 *       a document has directory information but the directory doesn't know this document.</td>
 *   <td>Add this document to the directory.</td>
 * </tr>
 *
 * </table>
 *
 * @author Hardy.Kiefer@softwareag.com
 *
 * @version $Revision: 1.4 $
 */
public class Repair extends Tws {
    private static final String CMD_REPAIR = "full";
    private static final String CMD_MIGRATE = "migrate";
    private static final String CMD_ENABLE = "enable";

    private static final String ARG_CHECK_ONLY = "checkOnly";

    private static final String ARG_STORE = "store";
    private static final String ARG_ALL_STORES = "allStores";
    private static final String ARG_NAMING = "naming";

    private static final String ARG_URL = "url";
    private static final String ARG_USER = "user";
    private static final String ARG_PWD = "password";
    private static final String ARG_URM_ADMIN = "urmadministrator";
    private static final String ARG_URM_PASSWORD = "urmpassword";
    private static final String ARG_URM_DOMAIN = "urmdomain";
    
    public Repair() {
        super(new String[] { CMD_REPAIR, CMD_MIGRATE, CMD_ENABLE}, "repair",
            "Checks the consistency of the WebDAV meta information " +
            "and corrects detected inconsistencies.",
            new String[] {
                "Checks the consistency of the WebDAV meta information " +
                "and corrects detected inconsistencies; WebDAV enable existing Tamino documents." },
                  "Commands:\n"+
                  "  full            Repair everything (includes enabling of existing Tamino\n"+
                  "                  documents)\n"+
                  "  enable          Only missing meta information (WebDAV enabling of\n"+
                  "                  documents which already exist in Tamino) will be\n"+
                  "                  checked/repaired.\n"+
                  "  migrate         Only the metadata version will be checked/migrated.\n"+
                  "Options:\n"+
                  "  -url <url>      The URL of the Tamino WebDAV Server (optional)\n"+
                  "                  The URL may contain user information of the form\n"+
                  "                  \"http://user:password@host:port/context\"\n"+
                  "                  in which case it takes precedence over over the \n"+
                  "                  user information supplied by -user and -password.\n"+
                  "                  NOTE:\n"+
                  "                  If the Tamino WebDAV Server is running during check and\n"+
                  "                  repair, the Repair Tool will use this URL to\n" +
                  "                  temporarily lock the store. Therefore, it is very \n" +
                  "                  important to provide the correct URL.\n" +
                  "                  For this reason, it might be safer to use the WebDAV\n" +
                  "                  interface of the Check and Repair Tool instead (see\n" +
                  "                  documentation).\n" +
                  "  -user           The user to connect to the Tamino WebDAV Server\n" +
                  "                  (optional; default is an empty string).\n" +
                  "  -password       The password to connect to the Tamino WebDAV Server\n" +
                  "                  (optional; default is an empty string).\n" +
                  "  -store <store>  The name of the store to be checked/repaired.\n"+
                  "  -allStores      All configured stores will be checked/repaired.\n"+
                  "  -checkOnly      Checks only and reports errors, no repairing is\n"+
                  "                  performed.\n" +
                  "Further Options:\n"+
                  "  -urmadministrator <name>  Name of the URM administrator to migrate \n"+
                  "                            permissions. Default: none\n" +
                  "  -urmpassword <password>   Password of the URM administrator. Default: none\n" +
                  "  -urmdomain <domain>       Domain of the URM administrator. Default: none\n" +
                  "  -naming <class>           Allows to customize document names that will be\n" +
                  "                            created by the enabler.\n"+
                  "                            Default is " + RepairHandler.DEFAULT_NAMING_CLASS + ".\n" +
                  "                            which is fine for most situations. Please refer\n" +
                  "                            to the documentation for more details. "
              // -naming is also available, but it's not documented here
             );
    }
    
    public CommandLine commandLine() {
        CommandLine cl;
        
        cl = new CommandLine(false);
        cl.addOption(ARG_URL);
        cl.addOption(ARG_USER);
        cl.addOption(ARG_PWD);
        cl.addOption(ARG_STORE);
        cl.addOption(ARG_URM_ADMIN);
        cl.addOption(ARG_URM_PASSWORD);
        cl.addOption(ARG_URM_DOMAIN);
        cl.addSwitch(ARG_ALL_STORES);
        cl.addSwitch(ARG_CHECK_ONLY);
        return cl;
        
    }
    
    public Command dispatch(String cmd, Actuals actuals) throws Abort, XException, IOException {
        final String url;
        final String user;
        final String pwd;
        final boolean checkOnly;
        final String store;
        final XURMAccessor urmAccessor;
        final String namespace;
        final Catalina catalina;
        final String naming;
        final RepairHandler repairer;
        
        url = actuals.getString(ARG_URL, getCatalina().getUrl());
        user = actuals.getString(ARG_USER, "");
        pwd = actuals.getString(ARG_PWD, "");
        checkOnly = actuals.getSwitch(ARG_CHECK_ONLY);
        if (actuals.getSwitch(ARG_ALL_STORES)) {
            store = RepairHandler.ALL_STORES;
        } else {
            store = actuals.getString(ARG_STORE);
            if (store == null) {
                throw new Abort("No store specified! Please indicate a single store or \"-allStores\".");
            }
        }
        urmAccessor = getAccessor(getCatalina().home, actuals.getString(ARG_URM_ADMIN), actuals.getString(ARG_URM_PASSWORD), actuals.getString(ARG_URM_DOMAIN));
        namespace = getNamespace();
        catalina = getCatalina();
        naming = actuals.getString(ARG_NAMING, RepairHandler.DEFAULT_NAMING_CLASS);
        repairer = new RepairHandler(namespace, catalina, url, user, pwd, true /* console */, naming, urmAccessor);
        if (CMD_MIGRATE.equals(cmd)) {
            return new Command("migrate", out) {
                public void run() throws Abort {
                    repairer.migrate(store, checkOnly);
                }
            };
        } else if (CMD_ENABLE.equals(cmd)) {
            return new Command("enable", out) {
                public void run() throws Abort {
                    repairer.enable(store, checkOnly);
                }
            };
        } else if (CMD_REPAIR.equals(cmd)) {
            return new Command("repair", out) {
                public void run() throws Abort {
                    repairer.repair(store, OnOpenTaToken.DEFAULT, checkOnly);
                }
            };
        } else {
            throw new XAssertionFailed(cmd);
        }
    }
    
    public XURMAccessor getAccessor(File catalinaHome, String admin, String password, String domain)
        throws Abort, IOException
    {
        URMPrincipal p;
        Namespace ns;
        
        if (admin == null) {
            return null;
        }
        if (password == null) {
            password = admin;
        }
        Security.setPath(UrmTemplate.getDest(catalinaHome));
        p = Security.getPrincipal(admin, password, domain);
        // we have exactly one namespace
        ns = (Namespace) Domain.enumerateNamespaces().nextElement();
        try {
            return new XURMAccessor(p, ns.getConfig());
        } catch (URMException e) {
            throw new Abort("can't create urm accessor", e);
        }
    }
}


