View Javadoc

1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2011, QOS.ch. All rights reserved.
4    *
5    * This program and the accompanying materials are dual-licensed under
6    * either the terms of the Eclipse Public License v1.0 as published by
7    * the Eclipse Foundation
8    *
9    *   or (per the licensee's choosing)
10   *
11   * under the terms of the GNU Lesser General Public License version 2.1
12   * as published by the Free Software Foundation.
13   */
14  package ch.qos.logback.core.rolling.helper;
15  
16  
17  import java.io.File;
18  import java.io.FileInputStream;
19  import java.io.FileOutputStream;
20  import java.io.IOException;
21  
22  import ch.qos.logback.core.CoreConstants;
23  import ch.qos.logback.core.rolling.RollingFileAppender;
24  import ch.qos.logback.core.rolling.RolloverFailure;
25  import ch.qos.logback.core.spi.ContextAwareBase;
26  import ch.qos.logback.core.util.FileUtil;
27  
28  
29  /**
30   * Utility class to help solving problems encountered while renaming files.
31   *
32   * @author Ceki Gulcu
33   */
34  public class RenameUtil extends ContextAwareBase {
35  
36    static String RENAMING_ERROR_URL = CoreConstants.CODES_URL+"#renamingError";
37  
38    /**
39     * A robust file renaming method which in case of failure falls back to
40     * renaming by copying. In case, the file to be renamed is open by another
41     * process, renaming by copying will succeed whereas regular renaming will
42     * fail. However, renaming by copying is much slower.
43     *
44     * @param from
45     * @param to
46     * @throws RolloverFailure
47     */
48    public void rename(String from, String to) throws RolloverFailure {
49      if (from.equals(to)) {
50        addWarn("From and to file are the same [" + from + "]. Skipping.");
51        return;
52      }
53      File fromFile = new File(from);
54  
55      if (fromFile.exists()) {
56        File toFile = new File(to);
57        createMissingTargetDirsIfNecessary(toFile);
58  
59        addInfo("Renaming file [" + fromFile + "] to [" + toFile + "]");
60  
61        boolean result = fromFile.renameTo(toFile);
62  
63        if (!result) {
64          addWarn("Failed to rename file [" + fromFile + "] to [" + toFile + "].");
65          addWarn("Please consider leaving the [file] option of "+ RollingFileAppender.class.getSimpleName()+" empty.");
66          addWarn("See also "+ RENAMING_ERROR_URL);
67  
68        }
69      } else {
70        throw new RolloverFailure("File [" + from + "] does not exist.");
71      }
72    }
73  
74    static final int BUF_SIZE = 32 * 1024;
75  
76    public void renameByCopying(String from, String to)
77            throws RolloverFailure {
78      try {
79        FileInputStream fis = new FileInputStream(from);
80        FileOutputStream fos = new FileOutputStream(to);
81        byte[] inbuf = new byte[BUF_SIZE];
82        int n;
83  
84        while ((n = fis.read(inbuf)) != -1) {
85          fos.write(inbuf, 0, n);
86        }
87  
88        fis.close();
89        fos.close();
90  
91        File fromFile = new File(from);
92  
93        if (!fromFile.delete()) {
94          addWarn("Could not delete " + from);
95        }
96      } catch (IOException ioe) {
97        addError("Failed to rename file by copying", ioe);
98        throw new RolloverFailure("Failed to rename file by copying");
99      }
100   }
101 
102   void createMissingTargetDirsIfNecessary(File toFile) throws RolloverFailure {
103     if (FileUtil.isParentDirectoryCreationRequired(toFile)) {
104       boolean result = FileUtil.createMissingParentDirectories(toFile);
105       if (!result) {
106         throw new RolloverFailure("Failed to create parent directories for ["
107                 + toFile.getAbsolutePath() + "]");
108       }
109     }
110   }
111 
112   @Override
113   public String toString() {
114     return "c.q.l.co.rolling.helper.RenameUtil";
115   }
116 }