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 }