Improve error handling by backups
authorMathieu Baudier <mbaudier@argeo.org>
Fri, 5 Oct 2012 09:15:18 +0000 (09:15 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Fri, 5 Oct 2012 09:15:18 +0000 (09:15 +0000)
git-svn-id: https://svn.argeo.org/commons/trunk@5592 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

base/runtime/org.argeo.util/src/main/java/org/argeo/ArgeoException.java
server/runtime/org.argeo.server.core/src/main/java/org/argeo/server/ArgeoServerException.java [deleted file]
server/runtime/org.argeo.server.core/src/main/java/org/argeo/server/backup/AbstractAtomicBackup.java
server/runtime/org.argeo.server.core/src/main/java/org/argeo/server/backup/AtomicBackup.java
server/runtime/org.argeo.server.core/src/main/java/org/argeo/server/backup/BackupUtils.java
server/runtime/org.argeo.server.core/src/main/java/org/argeo/server/backup/MySqlBackup.java
server/runtime/org.argeo.server.core/src/main/java/org/argeo/server/backup/OsCallBackup.java
server/runtime/org.argeo.server.core/src/main/java/org/argeo/server/backup/SystemBackup.java

index 343b6c947fad8d05d42410650ca75af0dea67587..03ac4958e125598e17e1f023b522963e2c4c9abb 100644 (file)
@@ -29,10 +29,21 @@ public class ArgeoException extends RuntimeException {
                super(message, e);
        }
 
-       /** @deprecated use {@link #ArgeoException(String, Throwable)} instead. */
-       @Deprecated
-       public ArgeoException(Throwable cause) {
-               super(cause);
+       /**
+        * Chain the messages of all causes (one per line, <b>starts with a line
+        * return</b>) without all the stack
+        */
+       public static String chainCausesMessages(Throwable t) {
+               StringBuffer buf = new StringBuffer();
+               chainCauseMessage(buf, t);
+               return buf.toString();
        }
 
+       /** Recursive chaining of messages */
+       private static void chainCauseMessage(StringBuffer buf, Throwable t) {
+               buf.append('\n').append(' ').append(t.getClass().getCanonicalName())
+                               .append(": ").append(t.getMessage());
+               if (t.getCause() != null)
+                       chainCauseMessage(buf, t.getCause());
+       }
 }
diff --git a/server/runtime/org.argeo.server.core/src/main/java/org/argeo/server/ArgeoServerException.java b/server/runtime/org.argeo.server.core/src/main/java/org/argeo/server/ArgeoServerException.java
deleted file mode 100644 (file)
index 368ee5a..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2007-2012 Mathieu Baudier
- *
- * 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.argeo.server;
-
-import org.argeo.ArgeoException;
-
-/** @deprecated use {@link ArgeoException} instead */
-public class ArgeoServerException extends ArgeoException {
-       private static final long serialVersionUID = 1L;
-
-       public ArgeoServerException(String message) {
-               super(message);
-       }
-
-       public ArgeoServerException(Throwable cause) {
-               super(cause);
-       }
-
-       public ArgeoServerException(String message, Throwable cause) {
-               super(message, cause);
-       }
-
-}
index dd47651a6be759d761dc41ed980abf7856d9d303..637e78cf64a76d4cca53f50392e62e9b047eb698 100644 (file)
@@ -22,6 +22,15 @@ public abstract class AbstractAtomicBackup implements AtomicBackup {
                this.name = name;
        }
 
+       public void init() {
+               if (name == null)
+                       throw new ArgeoException("Atomic backup name must be set");
+       }
+
+       public void destroy() {
+
+       }
+
        @Override
        public String backup(FileSystemManager fileSystemManager,
                        String backupsBase, BackupContext backupContext,
@@ -64,6 +73,10 @@ public abstract class AbstractAtomicBackup implements AtomicBackup {
                this.name = name;
        }
 
+       public String getName() {
+               return name;
+       }
+
        public void setCompression(String compression) {
                this.compression = compression;
        }
index 2c06cda4a43327314c300b1f038517b99bd02709..873068f063758b1fee8de5f1e5f55f5f3355c62f 100644 (file)
@@ -5,6 +5,9 @@ import org.apache.commons.vfs.FileSystemOptions;
 
 /** Performs the backup of a single component, typically a database dump */
 public interface AtomicBackup {
+       /** Name identifiying this backup */
+       public String getName();
+
        /**
         * Retrieves the data of the component in a format that allows to restore
         * the component
@@ -14,5 +17,6 @@ public interface AtomicBackup {
         * @return the VFS URI of the generated file or directory
         */
        public String backup(FileSystemManager fileSystemManager,
-                       String backupsBase, BackupContext backupContext, FileSystemOptions opts);
+                       String backupsBase, BackupContext backupContext,
+                       FileSystemOptions opts);
 }
index 88480b31872144f9ae2e87e76c88fde91f39bbfb..9bac5db95c02ba282cad8ae86b60cb399d6a6773 100644 (file)
@@ -1,7 +1,6 @@
 package org.argeo.server.backup;
 
 import org.apache.commons.vfs.FileObject;
-import org.apache.commons.vfs.FileSystemException;
 
 /** Backup utilities */
 public class BackupUtils {
@@ -10,12 +9,12 @@ public class BackupUtils {
                if (fo != null) {
                        try {
                                fo.close();
-                       } catch (FileSystemException e) {
+                       } catch (Exception e) {
                                // silent
                        }
                }
        }
-
+       
        /** Prevents instantiation */
        private BackupUtils() {
        }
index 8d729eafffd875e59b7be5dc8fe5e3d11b5f4345..e4ec54e346461661dfccddc44c1b7c82541e4316 100644 (file)
@@ -15,12 +15,19 @@ public class MySqlBackup extends OsCallBackup {
        }
 
        public MySqlBackup(String dbUser, String dbPassword, String dbName) {
-               super(dbName);
+               super(dbName + ".sql");
                this.dbUser = dbUser;
                this.dbPassword = dbPassword;
                this.dbName = dbName;
        }
 
+       @Override
+       public void init() {
+               if (getName() == null)
+                       setName(dbName + ".sql");
+               super.init();
+       }
+
        @Override
        public void writeBackup(FileObject targetFo) {
                if (getCommand() == null)
index eeca1ccc7d60abf78be7aaab3d0a161a0dd45e42..989c29a6872ddebda58f78fd307ff0459aac89a2 100644 (file)
@@ -58,9 +58,8 @@ public class OsCallBackup extends AbstractAtomicBackup {
                } catch (ExecuteException e) {
                        byte[] err = errBos.toByteArray();
                        String errStr = new String(err);
-                       throw new ArgeoException("Process " + commandLine
-                                       + " failed with exit value " + e.getExitValue() + ": "
-                                       + errStr, e);
+                       throw new ArgeoException("Process " + commandLine + " failed ("
+                                       + e.getExitValue() + "): " + errStr, e);
                } catch (Exception e) {
                        byte[] err = errBos.toByteArray();
                        String errStr = new String(err);
index 54bb2938464f3d5329ecc5924807383beaeb12ad..a8149ee54d18fd5ba1837969d7d57c95d7ab101d 100644 (file)
@@ -59,7 +59,7 @@ public class SystemBackup implements Runnable {
                        backupPurge.purge(fileSystemManager, backupsBase, systemName,
                                        backupContext.getDateFormat(), opts);
                } catch (Exception e) {
-                       failures.add(e.getMessage());
+                       failures.add("Purge " + backupsBase + " failed: " + e.getMessage());
                        log.error("Purge of " + backupsBase + " failed", e);
                }
 
@@ -71,8 +71,14 @@ public class SystemBackup implements Runnable {
                                if (log.isDebugEnabled())
                                        log.debug("Performed backup " + target);
                        } catch (Exception e) {
-                               failures.add(e.getMessage());
-                               log.error("Atomic backup failed", e);
+                               String msg = "Atomic backup " + atomickBackup.getName()
+                                               + " failed: " + ArgeoException.chainCausesMessages(e);
+                               failures.add(msg);
+                               log.error(msg);
+                               if (log.isTraceEnabled())
+                                       log.trace(
+                                                       "Stacktrace of atomic backup "
+                                                                       + atomickBackup.getName() + " failure.", e);
                        }
                }
 
@@ -82,14 +88,20 @@ public class SystemBackup implements Runnable {
                        FileObject remoteBaseFo = null;
                        UserAuthenticator auth = remoteBases.get(remoteBase);
 
+                       // authentication
+                       FileSystemOptions remoteOpts = new FileSystemOptions();
                        try {
-                               // authentication
-                               FileSystemOptions remoteOpts = new FileSystemOptions();
                                DefaultFileSystemConfigBuilder.getInstance()
                                                .setUserAuthenticator(remoteOpts, auth);
                                backupPurge.purge(fileSystemManager, remoteBase, systemName,
                                                backupContext.getDateFormat(), remoteOpts);
+                       } catch (Exception e) {
+                               failures.add("Purge " + remoteBase + " failed: "
+                                               + e.getMessage());
+                               log.error("Cannot purge " + remoteBase, e);
+                       }
 
+                       try {
                                localBaseFo = fileSystemManager.resolveFile(backupsBase + '/'
                                                + backupContext.getRelativeFolder(), opts);
                                remoteBaseFo = fileSystemManager.resolveFile(remoteBase + '/'
@@ -99,7 +111,9 @@ public class SystemBackup implements Runnable {
                                        log.debug("Copied backup to " + remoteBaseFo + " from "
                                                        + localBaseFo);
                                // }
-                       } catch (FileSystemException e) {
+                       } catch (Exception e) {
+                               failures.add("Dispatch to " + remoteBase + " failed: "
+                                               + e.getMessage());
                                log.error(
                                                "Cannot dispatch backups from "
                                                                + backupContext.getRelativeFolder() + " to "
@@ -109,11 +123,16 @@ public class SystemBackup implements Runnable {
                        BackupUtils.closeFOQuietly(remoteBaseFo);
                }
 
+               int failureCount = 0;
                if (failures.size() > 0) {
                        StringBuffer buf = new StringBuffer();
-                       for (String failure : failures)
-                               buf.append('\n').append(failure);
-                       throw new ArgeoException("Errors when running the backup,"
+                       for (String failure : failures) {
+                               buf.append('\n').append(failureCount).append(" - ")
+                                               .append(failure);
+                               failureCount++;
+                       }
+                       throw new ArgeoException(failureCount
+                                       + " error(s) when running the backup,"
                                        + " check the logs and the backups as soon as possible."
                                        + buf);
                }