View Javadoc

1   /*
2   Copyright (C) 2004 Grid Systems, S.A.
3   
4   This program is free software; you can redistribute it and/or modify
5   it under the terms of the GNU General Public License, version 2, as
6   published by the Free Software Foundation.
7   
8   This program is distributed in the hope that it will be useful,
9   but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12  
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  */
17  package com.gridsystems.storage;
18  
19  import java.io.File;
20  import java.lang.reflect.Constructor;
21  import java.lang.reflect.Method;
22  import java.util.Map;
23  
24  import org.apache.commons.logging.Log;
25  import org.apache.commons.logging.LogFactory;
26  
27  /**
28   * This class manages the safe load and stores.
29   *
30   * @version 1.0
31   */
32  public final class FailSafeManager {
33  
34    /**
35     * Class logger.
36     */
37    private static final Log LOG = LogFactory.getLog(FailSafeManager.class);
38  
39    /**
40     * Constructor.
41     */
42    private FailSafeManager() { }
43  
44    /**
45     * Manages the store information of the class.
46     *
47     * @param data The FailSafe instance to manage
48     * @throws Exception if the files cannot be stored correctly.
49     */
50    public static void store(FailSafe data) throws Exception {
51      synchronized (data) {
52        try {
53          String[] fl = data.getFileNameList();
54          String[] flbak = new String[fl.length];
55          for (int i = 0; i < fl.length; i++) {
56            flbak[i] = fl[i] + ".bak";
57          }
58          // First, it stores backup files
59          data.store(flbak);
60  
61          // Once backups are made, stores actual files
62          data.store(fl);
63        } catch (Exception e) {
64          data.recoverFromStoreError(e);
65        }
66      }
67    }
68  
69    /**
70     * Manages all load information of the class.
71     *
72     * @param data The FailSafe instance to manage
73     * @throws Exception if the files cannot be loaded correctly.
74     */
75    public static void load(FailSafe data) throws Exception {
76      synchronized (data) {
77        String[] fl = data.getFileNameList();
78        try {
79          data.load(fl); //load files
80        } catch (Exception e) {
81          //If there is any exception try to load backup file
82          try {
83            String[] flbak = new String[fl.length];
84            for (int i = 0; i < fl.length; i++) {
85              flbak[i] = fl[i] + ".bak";
86            }
87            data.load(flbak); //store backup files
88            data.store(fl);
89          } catch (Exception e1) {
90            data.recoverFromLoadError(e1);
91          }
92        }
93      }
94    }
95  
96    /**
97     * Manages all load information of the class.
98     * <p>
99     * As this method does not use initialization data, it is preferred to use it
100    * only with classes implementing the Singleton pattern.
101    *
102    * @param c The class to load
103    * @return An initialized instance of the class
104    * @throws Exception In case of execution error
105    */
106   public static FailSafe load(Class c) throws Exception {
107     return load(c, null);
108   }
109 
110   /**
111    * Manages all load information of the class.
112    * <p>
113    * The map parameter will be used as the argument for the constructor. If no
114    * appropriate constructor is found, it will fall back to the "no-argument"
115    * version.
116    *
117    * @param c   The class to load
118    * @param map The map to pass to the constructor
119    * @return An initialized instance of the class
120    * @throws Exception In case of execution error
121    */
122   public static FailSafe load(Class c, Map map) throws Exception {
123     FailSafe fs = (FailSafe)instantiate(c, map, Map.class);
124     load(fs);
125     return fs;
126   }
127 
128   /**
129    * Manages all load information of the class.
130    * <p>
131    * The object parameter will be used as the argument for the constructor. The object
132    * must be exactly of the same class than the expected constructor parameter. If no
133    * appropriate constructor is found, it will fall back to the "no-argument"
134    * version.
135    *
136    * @param c   The class to load
137    * @param obj The object to pass to the constructor
138    * @return An initialized instance of the class
139    * @throws Exception In case of execution error
140    */
141   public static FailSafe load(Class c, Object obj) throws Exception {
142     FailSafe fs = (FailSafe)instantiate(c, obj, obj == null ? null : obj.getClass());
143     load(fs);
144     return fs;
145   }
146 
147   /**
148    * Deletes all files (including backups) for the specified FailSafe instance.
149    *
150    * @param fs The instance whose files to delete
151    * @throws Exception In case of execution error
152    */
153   public static void delete(FailSafe fs) throws Exception {
154     String[] files = fs.getFileNameList();
155 
156     int count = files == null ? 0 : files.length;
157     for (int i = 0; i < count; i++) {
158       attemptDelete(new File(files[i]));
159       attemptDelete(new File(files[i] + ".bak"));
160     }
161   }
162 
163   /**
164    * Tries to delete a file. If it is not possible, logs the failure and
165    * marks the file for deletion on exit.
166    *
167    * @param f The file to delete
168    */
169   private static void attemptDelete(File f) {
170     if (f != null && f.exists() && !f.delete()) {
171       LOG.info("Could not delete file '" + f.getPath() + "'");
172       f.deleteOnExit();
173     }
174   }
175 
176   /**
177    * Creates a new instance of the specified class.
178    * <p>
179    * It first checks the existence of an static getInstance() method, and if found, it
180    * uses it. If no getInstance method is found, or an invocation error occurs, it
181    * tries to use the default constructor. If this also fails, it returns null.
182    *
183    * @param c The class to instantiate
184    * @return  An instance of class c, or null
185    */
186   private static Object instantiate(Class c) {
187     try {
188       Method m = c.getMethod("getInstance");
189       return m.invoke(null);
190     } catch (Exception e) {
191       try {
192         return c.newInstance();
193       } catch (Exception ee) {
194         return null;
195       }
196     }
197   }
198 
199   /**
200    * Creates a new instance of the specified class using an initializer constructor.
201    * <p>
202    * It first checks the existence of an static getInstance() method, and if found, it
203    * uses it. If no getInstance method is found, or an invocation error occurs, it
204    * tries to use the default constructor. If this also fails, it returns null.
205    *
206    * @param c       The class to instantiate
207    * @param obj     The object to pass to the constructor
208    * @param objType The type of the parameter
209    * @return  An instance of class c, or null
210    */
211   private static Object instantiate(Class c, Object obj, Class objType) {
212     if (obj != null) {
213       try {
214         Constructor constr = c.getConstructor(new Class[] { objType });
215         return constr.newInstance(new Object[] { obj });
216       } catch (Exception e) { }
217     }
218     return instantiate(c);
219   }
220 }