From 1387e05a497147cd1a320c9651a47f122e942b93 Mon Sep 17 00:00:00 2001
From: kenneth_suter <kenneth_suter@localhost>
Date: Mon, 09 Apr 2007 12:24:58 +0000
Subject: [PATCH] historical log for upgrader tool

---
 opends/src/quicksetup/org/opends/quicksetup/upgrader/HistoricalRecord.java |  291 ++++++++++++++++++++++++++++++++
 opends/src/quicksetup/org/opends/quicksetup/util/Utils.java                |   19 ++
 opends/src/quicksetup/org/opends/quicksetup/Installation.java              |    7 
 opends/src/quicksetup/org/opends/quicksetup/upgrader/HistoricalLog.java    |  139 +++++++++++++++
 opends/src/quicksetup/org/opends/quicksetup/upgrader/Upgrader.java         |   81 ++++++++
 5 files changed, 526 insertions(+), 11 deletions(-)

diff --git a/opends/src/quicksetup/org/opends/quicksetup/Installation.java b/opends/src/quicksetup/org/opends/quicksetup/Installation.java
index 4b902f5..35f8a8b 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/Installation.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/Installation.java
@@ -490,7 +490,6 @@
     return new File(getHistoryDirectory(), HISTORY_LOG_FILE_NAME);
   }
 
-
   /**
    * Gets the directory config/upgrade.
    * @return File representing the config/upgrade directory
@@ -570,9 +569,9 @@
   }
 
   /**
-   * Returns the path to the status-panel file.
-   *
-   * @return the path to the status-panel file.
+   * Gets the status panel command file appropriate for the current operating
+   * system.
+   * @return File object representing the status panel command
    */
   public File getStatusPanelCommandFile() {
     File statusPanelCommandFile;
diff --git a/opends/src/quicksetup/org/opends/quicksetup/upgrader/HistoricalLog.java b/opends/src/quicksetup/org/opends/quicksetup/upgrader/HistoricalLog.java
new file mode 100644
index 0000000..5144c5b
--- /dev/null
+++ b/opends/src/quicksetup/org/opends/quicksetup/upgrader/HistoricalLog.java
@@ -0,0 +1,139 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
+ */
+
+package org.opends.quicksetup.upgrader;
+
+import org.opends.quicksetup.util.Utils;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.io.*;
+
+/**
+ * Log of past upgrade/reversion events that is backed by the file
+ * [install root]/history/log.
+ */
+public class HistoricalLog {
+
+  private File file;
+
+  /**
+   * Creates a historical log backed by <code>file</code>.  If file
+   * does not exist an attempt will be made to create it.
+   * @param file File containing the historical record
+   * @throws IOException if something goes wrong attempting to create
+   * a new historical record file
+   */
+  public HistoricalLog(File file) throws IOException {
+    this.file = file;
+    if (!file.exists()) {
+      Utils.createFile(file);
+    }
+  }
+
+  /**
+   * Gets a list of the historical records in the file.
+   * @return List of HistoricalRecord
+   * @throws IOException if there was an error reading the records file
+   */
+  public List<HistoricalRecord> getRecords() throws IOException {
+    List<HistoricalRecord> records = new ArrayList<HistoricalRecord>();
+    BufferedReader br = new BufferedReader(new FileReader(file));
+    String s;
+    while (null != (s = br.readLine())) {
+      records.add(HistoricalRecord.fromString(s));
+    }
+    return Collections.unmodifiableList(records);
+  }
+
+  /**
+   * Creates a new historical log record and appends a new log record to the
+   * log.  A new operation ID is generated and returned so that future calls
+   * can use the same ID.
+   * @param from current version
+   * @param to version to upgrade to
+   * @param status of the upgrade
+   * @param note optional string with additional information
+   * @return Long operation ID that can be used in writing future logs
+   * @throws IOException if there is a problem appending the log to the file
+   */
+  public Long append(Integer from, Integer to,
+                     HistoricalRecord.Status status, String note)
+          throws IOException
+  {
+    HistoricalRecord record = new HistoricalRecord(from, to, status, note);
+    Long id = record.getOperationId();
+    append(record);
+    return id;
+  }
+
+  /**
+   * Creates a new historical log record and appends a new log record to the
+   * log.
+   * @param id Long ID obtained from a call to
+            {@link org.opends.quicksetup.upgrader.HistoricalLog#
+            append(Integer, Integer,
+            org.opends.quicksetup.upgrader.HistoricalRecord.Status)}
+   * @param from current version
+   * @param to version to upgrade to
+   * @param status of the upgrade
+   * @param note optional string with additional information
+   * @throws IOException if there is a problem appending the log to the file
+   */
+  public void append(Long id, Integer from, Integer to,
+                     HistoricalRecord.Status status, String note)
+          throws IOException
+  {
+    HistoricalRecord record = new HistoricalRecord(id, from, to, status, note);
+    append(record);
+  }
+
+  /**
+   * Appends a historical record to the log.
+   * @param record to append to the log file
+   * @throws IOException if there is a problem appending the record to the file
+   */
+  private void append(HistoricalRecord record) throws IOException {
+    BufferedWriter bw = null;
+    try {
+      bw = new BufferedWriter(new FileWriter(file, true));
+      bw.write(record.toString());
+      bw.newLine();
+      bw.flush();
+    } finally {
+      if (bw != null) {
+        try {
+          bw.close();
+        } catch (IOException ioe2) {
+        // do nothing;
+        }
+      }
+    }
+  }
+
+}
diff --git a/opends/src/quicksetup/org/opends/quicksetup/upgrader/HistoricalRecord.java b/opends/src/quicksetup/org/opends/quicksetup/upgrader/HistoricalRecord.java
new file mode 100644
index 0000000..f4cf4a3
--- /dev/null
+++ b/opends/src/quicksetup/org/opends/quicksetup/upgrader/HistoricalRecord.java
@@ -0,0 +1,291 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
+ */
+
+package org.opends.quicksetup.upgrader;
+
+import java.util.StringTokenizer;
+import java.util.EnumSet;
+import java.util.Set;
+import java.util.Date;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.text.SimpleDateFormat;
+
+/**
+ * A record in the historical log stored in [install root]/history/log.
+ */
+public class HistoricalRecord {
+
+  static private final Logger LOG =
+          Logger.getLogger(HistoricalRecord.class.getName());
+
+  static private String OPERATION = "operation:";
+
+  static private String TIME = "time:";
+
+  static private String FROM = "from:";
+
+  static private String TO = "to:";
+
+  static private String STATUS = "status:";
+
+  static private String NOTE = "note:";
+
+  static private String SEPARATOR = " ";
+
+  static private String DATE_FORMAT = "yyyyMMddHHmmss";
+
+  /**
+   * State of an upgrade.
+   */
+  enum Status {
+
+    STARTED("started"),
+
+    SUCCESS("success"),
+
+    FAILURE("failure");
+
+    private String representation;
+
+    /**
+     * Creates a State from a String.
+     * @param s string representation of a state
+     * @return Status created from <code>s</code>
+     */
+    static public Status fromString(String s) {
+      Status retOc = null;
+      Set<Status> all = EnumSet.allOf(Status.class);
+      for (Status oc : all) {
+        if (oc.toString().equals(s)) {
+          retOc = oc;
+        }
+      }
+      return retOc;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString() {
+      return representation;
+    }
+
+    private Status(String representation) {
+      this.representation = representation;
+    }
+
+  }
+
+  /**
+   * Creates a historical log record from its string representation.
+   * @param s string representation
+   * @return HistoricalRecord created from the string
+   * @throws IllegalArgumentException if the string is misformatted
+   */
+  static public HistoricalRecord fromString(String s)
+          throws IllegalArgumentException {
+    Long operationid = null;
+    Integer fromInt = null;
+    Integer toInt = null;
+    Status outcome = null;
+    Date date = null;
+    String note = null;
+    Exception creationError = null;
+    try {
+      StringTokenizer st = new StringTokenizer(s, SEPARATOR);
+
+      String token = st.nextToken();
+      String operationIdString = token.substring(OPERATION.length());
+      operationid = Long.parseLong(operationIdString);
+
+      token = st.nextToken();
+      String timeString = token.substring(TIME.length());
+      date = new SimpleDateFormat(DATE_FORMAT).parse(timeString);
+
+      token = st.nextToken();
+      String fromString = token.substring(FROM.length());
+      fromInt = new Integer(fromString);
+
+      token = st.nextToken();
+      String toString = token.substring(TO.length());
+      toInt = new Integer(toString);
+
+      token = st.nextToken();
+      String outcomeString = token.substring(STATUS.length());
+      outcome = Status.fromString(outcomeString);
+
+      if (st.hasMoreTokens()) {
+        token = st.nextToken("");
+        if (token != null) {
+          note = token.substring(NOTE.length());
+        }
+      }
+    } catch (Exception e) {
+      // There was a problem creating the record.  Log the error and
+      // create the record with what we have already accumulated.
+      LOG.log(Level.INFO, "error creating historical log record", e);
+      creationError = e;
+    }
+    return new HistoricalRecord(operationid, date, fromInt,
+            toInt, outcome, note, creationError);
+  }
+
+  private Long operationId;
+
+  private Integer from;
+
+  private Integer to;
+
+  private Status status;
+
+  private Date date;
+
+  private String note;
+
+  /** true indicates there were not errors creating this record. */
+  private Exception creationError;
+
+  /**
+   * Creates a new historical record using the current time and generating.
+   * a new operation id
+   * @param from current version
+   * @param to version to upgrade to
+   * @param status of the upgrade
+   * @param note containing details of status; can be null
+   */
+  public HistoricalRecord(Integer from,
+                          Integer to, Status status, String note) {
+    this.from = from;
+    this.to = to;
+    this.status = status;
+    this.date = new Date();
+    this.operationId = date.getTime();
+    this.note = note;
+  }
+
+  /**
+   * Creates a new historical record using the current time.
+   * @param operationId obtained from a previously created HistoricalRecord
+   * @param from current version
+   * @param to version to upgrade to
+   * @param status of the upgrade
+   * @param note containing details of status; can be null
+   */
+  public HistoricalRecord(Long operationId, Integer from,
+                          Integer to, Status status, String note) {
+    this.from = from;
+    this.to = to;
+    this.status = status;
+    this.date = new Date();
+    this.operationId = operationId;
+    this.note = note;
+  }
+
+  /**
+   * Creates a new historical record using the current time.
+   * @param operationId obtained from a previously created HistoricalRecord
+   * @param from current version
+   * @param to version to upgrade to
+   * @param status of the upgrade
+   * @param note containing details of status; can be null
+   * @param creationError Exception that occurred while this record was
+   * being created
+   */
+  private HistoricalRecord(Long operationId, Date date, Integer from,
+                          Integer to, Status status, String note,
+                          Exception creationError) {
+    this.operationId = operationId;
+    this.from = from;
+    this.to = to;
+    this.status = status;
+    this.date = date;
+    this.note = note;
+    this.creationError = creationError;
+  }
+
+  /**
+   * Gets the operation ID associated with this record.
+   * @return Long ID of this operation
+   */
+  public Long getOperationId() {
+    return operationId;
+  }
+
+  /**
+   * Gets the Date the record was created.
+   * @return Date of the record
+   */
+  public Date getDate() {
+    return this.date;
+  }
+
+  /**
+   * Gets the Integer representing the SVN rev ID of the current installation.
+   * @return Integer version ID
+   */
+  public Integer getFromVersion() {
+    return this.from;
+  }
+
+  /**
+   * Gets the Integer representing the SVN rev ID of the installation being
+   * upgraded to.
+   * @return Integer version ID
+   */
+  public Integer getToVersion() {
+    return this.to;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public String toString() {
+    StringBuilder sb = new StringBuilder()
+    .append(OPERATION)
+    .append(operationId)
+    .append(SEPARATOR)
+    .append(TIME)
+    .append(new SimpleDateFormat(DATE_FORMAT).format(date))
+    .append(SEPARATOR)
+    .append(FROM)
+    .append(from)
+    .append(SEPARATOR)
+    .append(TO)
+    .append(to)
+    .append(SEPARATOR)
+    .append(STATUS)
+    .append(status);
+    if (note != null) {
+      sb.append(SEPARATOR)
+      .append(NOTE)
+      .append(note);
+    }
+    return sb.toString();
+  }
+
+}
diff --git a/opends/src/quicksetup/org/opends/quicksetup/upgrader/Upgrader.java b/opends/src/quicksetup/org/opends/quicksetup/upgrader/Upgrader.java
index 0fe630e..a6ce096 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/upgrader/Upgrader.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/upgrader/Upgrader.java
@@ -41,10 +41,7 @@
 import java.util.*;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import java.io.IOException;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileFilter;
+import java.io.*;
 
 import static org.opends.quicksetup.Installation.*;
 
@@ -154,7 +151,7 @@
     DATABASES_PATH_RELATIVE, // db
     LOGS_PATH_RELATIVE, // logs
     LOCKS_PATH_RELATIVE, // locks
-    HISTORY_PATH_RELATIVE // history; TODO: should we do this?
+    HISTORY_PATH_RELATIVE // history
   };
 
   private ProgressStep currentProgressStep = UpgradeProgressStep.NOT_STARTED;
@@ -171,6 +168,11 @@
   /** Directory where backup is kept in case the upgrade needs reversion. */
   private File backupDirectory = null;
 
+  /** ID that uniquely identifieds this invocation of the Upgrader in the
+   * historical logs.
+   */
+  private Long historicalOperationId;
+
   /**
    * {@inheritDoc}
    */
@@ -317,11 +319,17 @@
     // Reset exception just in case this application is rerun
     // for some reason
     runException = null;
+    Integer fromVersion = null;
+    Integer toVersion = null;
 
     try {
       try {
         setCurrentProgressStep(UpgradeProgressStep.INITIALIZING);
         initialize();
+        fromVersion = getStagedInstallation().getSvnRev();
+        toVersion = getInstallation().getSvnRev();
+        this.historicalOperationId =
+                writeInitialHistoricalRecord(fromVersion, toVersion);
       } catch (ApplicationException e) {
         LOG.log(Level.INFO, "error initializing upgrader", e);
         throw e;
@@ -390,8 +398,8 @@
 //      sleepFor1();
 //      setCurrentProgressStep(UpgradeProgressStep.VERIFYING);
 //      sleepFor1();
-//      setCurrentProgressStep(UpgradeProgressStep.RECORDING_HISTORY);
-//      sleepFor1();
+
+
 
     } catch (ApplicationException ae) {
       this.runException = ae;
@@ -404,6 +412,23 @@
       try {
         setCurrentProgressStep(UpgradeProgressStep.CLEANUP);
         cleanup();
+
+        // Write a record in the log file indicating success/failure
+        setCurrentProgressStep(UpgradeProgressStep.RECORDING_HISTORY);
+        HistoricalRecord.Status status;
+        String note = null;
+        if (runException == null) {
+          status = HistoricalRecord.Status.SUCCESS;
+        } else {
+          status = HistoricalRecord.Status.FAILURE;
+          note = runException.getLocalizedMessage();
+        }
+        writeHistoricalRecord(historicalOperationId,
+                fromVersion,
+                toVersion,
+                status,
+                note);
+
       } catch (ApplicationException e) {
         System.err.print("error cleaning up after upgrade: " +
                 e.getLocalizedMessage());
@@ -419,6 +444,48 @@
 
   }
 
+  private Long writeInitialHistoricalRecord(
+          Integer fromVersion,
+          Integer toVersion)
+          throws ApplicationException
+  {
+    Long id;
+    try {
+      HistoricalLog log =
+            new HistoricalLog(getInstallation().getHistoryLogFile());
+      id = log.append(fromVersion, toVersion,
+              HistoricalRecord.Status.STARTED, null);
+    } catch (IOException e) {
+      throw ApplicationException.createFileSystemException(
+              "error logging operation", e);
+    }
+    return id;
+  }
+
+  private void writeHistoricalRecord(
+          Long id,
+          Integer from,
+          Integer to,
+          HistoricalRecord.Status status,
+          String note)
+          throws ApplicationException {
+    try {
+      HistoricalLog log =
+            new HistoricalLog(getInstallation().getHistoryLogFile());
+      log.append(id, from, to, status, note);
+
+      // FOR TESTING
+      List<HistoricalRecord> records = log.getRecords();
+      for(HistoricalRecord record : records) {
+        System.out.println(record);
+      }
+
+    } catch (IOException e) {
+      throw ApplicationException.createFileSystemException(
+              "error logging operation", e);
+    }
+  }
+
   private void upgradeComponents() throws ApplicationException {
     try {
       File stageDir = getStageDirectory();
diff --git a/opends/src/quicksetup/org/opends/quicksetup/util/Utils.java b/opends/src/quicksetup/org/opends/quicksetup/util/Utils.java
index 18bbdf9..2ac5655 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/util/Utils.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/util/Utils.java
@@ -135,6 +135,25 @@
   }
 
   /**
+   * Creates a new file attempting to create the parent directories
+   * if necessary.
+   * @param f File to create
+   * @return boolean indicating whether the file was created; false otherwise
+   * @throws IOException if something goes wrong
+   */
+  public static boolean createFile(File f) throws IOException {
+    boolean success = false;
+    if (f != null) {
+      File parent = f.getParentFile();
+      if (!parent.exists()) {
+        parent.mkdirs();
+      }
+      success = f.createNewFile();
+    }
+    return success;
+  }
+
+  /**
    * Returns the absolute path for the given parentPath and relativePath.
    * @param parentPath the parent path.
    * @param relativePath the relative path.

--
Gitblit v1.10.0