KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > continuent > sequoia > controller > backup > backupers > PostgreSQLBinaryBackuper


1 /**
2  * Sequoia: Database clustering technology.
3  * Copyright (C) 2005 Emic Networks
4  * Contact: sequoia@continuent.org
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * Initial developer(s): Emmanuel Cecchet.
19  * Contributor(s): Dylan Hansen, Mathieu Peltier, Olivier Fambon.
20  */

21
22 package org.continuent.sequoia.controller.backup.backupers;
23
24 import java.io.File JavaDoc;
25 import java.io.IOException JavaDoc;
26 import java.util.ArrayList JavaDoc;
27 import java.util.Date JavaDoc;
28
29 import org.continuent.sequoia.common.exceptions.BackupException;
30 import org.continuent.sequoia.common.log.Trace;
31 import org.continuent.sequoia.controller.backend.DatabaseBackend;
32 import org.continuent.sequoia.controller.backup.BackupManager;
33 import org.continuent.sequoia.controller.backup.DumpTransferInfo;
34
35 /**
36  * This class defines a Backuper for PostgreSQL databases. This backuper creates
37  * dumps in a binary format, using the "--format=c" switch on pg_dump.
38  * <p>
39  * Supported URLs are:
40  * <ul>
41  * <li>jdbc:postgresql://host:port/dbname?param1=foo,param2=bar</li>
42  * <li>jdbc:postgresql://host/dbname?param1=foo,param2=bar</li>
43  * <li>jdbc:postgresql:dbname?param1=foo,param2=bar</li>
44  * </ul>
45  *
46  * @author <a HREF="mailto:emmanuel.cecchet@emicnetworks.com">Emmanuel Cecchet</a>
47  * @author <a HREF="mailto:dhansen@h2st.com">Dylan Hansen</a>
48  * @author <a HREF="mailto:mathieu.peltier@emicnetworks.com">Mathieu Peltier</a>
49  * @author <a HREF="mailto:olivier.fambon@emicnetworks.com">Olivier Fambon</a>
50  * @version 1.0
51  */

52 public class PostgreSQLBinaryBackuper extends AbstractPostgreSQLBackuper
53 {
54   // Logger
55
static Trace logger = Trace
56                                              .getLogger(PostgreSQLBinaryBackuper.class
57                                                  .getName());
58
59   /**
60    * The dump format for this (family of) backuper.
61    */

62   public static final String JavaDoc DUMP_FORMAT = "PostgreSQL Binary Dump";
63
64   /**
65    * @see org.continuent.sequoia.controller.backup.Backuper#getDumpFormat()
66    */

67   public String JavaDoc getDumpFormat()
68   {
69     return DUMP_FORMAT;
70   }
71
72   /**
73    * @see org.continuent.sequoia.controller.backup.Backuper#backup(DatabaseBackend,
74    * String, String, String, String, ArrayList)
75    */

76   public Date JavaDoc backup(DatabaseBackend backend, String JavaDoc login, String JavaDoc password,
77       String JavaDoc dumpName, String JavaDoc path, ArrayList JavaDoc tables) throws BackupException
78   {
79     // Parse the URL for the connection information
80
String JavaDoc url = backend.getURL();
81     PostgreSQLUrlInfo info = new AbstractPostgreSQLBackuper.PostgreSQLUrlInfo(
82         url);
83
84     if (logger.isDebugEnabled())
85       logger.debug("Backing up database '" + info.getDbName() + "' on host '"
86           + info.getHost() + ":" + info.getPort() + "'");
87
88     try
89     {
90       // Create the path, if it does not already exist
91
File JavaDoc pathDir = new File JavaDoc(path);
92       if (!pathDir.exists())
93       {
94         pathDir.mkdirs();
95         pathDir.mkdir();
96       }
97       String JavaDoc fullPath = getDumpPhysicalPath(path, dumpName);
98
99       boolean succeeded = false;
100       String JavaDoc dumpOptions = "";
101       if (pgDumpFlags != null)
102       {
103         if (pgDumpFlags.indexOf("-F") >= 0
104             || pgDumpFlags.indexOf("--format=") >= 0)
105         {
106           logger.error("Invalid option in pgDumpFlags \"" + pgDumpFlags
107               + "\". You are not allowed to set the format of the dump!");
108         }
109         else
110         {
111           dumpOptions = " " + pgDumpFlags + " ";
112         }
113       }
114       if (useAuthentication)
115       {
116         // TODO: Check if this works--it should be disabled?
117
if (logger.isDebugEnabled())
118           logger.debug("Performing backup using authentication");
119         int timeout = -1;
120         if (dumpTimeout != null)
121         {
122           try
123           {
124             timeout = Integer.parseInt(dumpTimeout);
125           }
126           catch (NumberFormatException JavaDoc e)
127           {
128             logger.error("\"" + dumpTimeout
129                 + "\" is not a valid dump-timeout value!");
130             timeout = -1;
131           }
132         }
133         String JavaDoc[] expectFeed = makeExpectDialogueWithAuthentication("pg_dump",
134             info, " --format=c -f " + fullPath + dumpOptions, login, password,
135             timeout);
136
137         String JavaDoc[] cmd = makeExpectCommandReadingStdin();
138
139         succeeded = safelyExecNativeCommand(cmd, expectFeed, 0);
140       }
141       else
142       {
143         if (pgDumpFlags != null)
144         {
145           if (pgDumpFlags.indexOf("-U") >= 0 || pgDumpFlags.indexOf("-W") >= 0)
146           {
147             logger
148                 .error("Invalid option in pgDumpFlags \""
149                     + pgDumpFlags
150                     + "\". Set \"authentication=true\" if you want to use authentication!");
151           }
152           else
153           {
154             dumpOptions = " " + pgDumpFlags + " ";
155           }
156         }
157
158         String JavaDoc cmd = makeCommand("pg_dump", info, " --format=c -f " + fullPath
159             + dumpOptions, login);
160         succeeded = safelyExecNativeCommand(cmd, null, 0);
161       }
162
163       if (! succeeded)
164       {
165         throw new BackupException(
166             "pg_dump execution did not complete successfully!");
167       }
168
169     }
170     catch (Exception JavaDoc e)
171     {
172       String JavaDoc msg = "Error while performing backup";
173       logger.error(msg, e);
174       throw new BackupException(msg, e);
175     }
176
177     return new Date JavaDoc(System.currentTimeMillis());
178   }
179
180   /**
181    * @see org.continuent.sequoia.controller.backup.Backuper#restore(DatabaseBackend,
182    * String, String, String, String, ArrayList)
183    */

184   public void restore(DatabaseBackend backend, String JavaDoc login, String JavaDoc password,
185       String JavaDoc dumpName, String JavaDoc path, ArrayList JavaDoc tables) throws BackupException
186   {
187     // Parse the URL for the connection information
188
String JavaDoc url = backend.getURL();
189     PostgreSQLUrlInfo info = new AbstractPostgreSQLBackuper.PostgreSQLUrlInfo(
190         url);
191
192     if (logger.isDebugEnabled())
193       logger.debug("Restoring database '" + info.getDbName() + "' on host '"
194           + info.getHost() + ":" + info.getPort() + "'");
195
196     // Check to see if the given path + dumpName exists
197
String JavaDoc fullPath = getDumpPhysicalPath(path, dumpName);
198     File JavaDoc dump = new File JavaDoc(fullPath);
199     if (!dump.exists())
200       throw new BackupException("Backup '" + fullPath + "' does not exist!");
201
202     try
203     {
204       if (useAuthentication)
205       {
206         if (logger.isInfoEnabled())
207           logger.info("Performing database operations using authentication");
208
209         // Drop the database if it already exists
210
if (logger.isDebugEnabled())
211           logger.debug("Dropping database '" + info.getDbName() + "'");
212
213         String JavaDoc[] expectFeed = makeExpectDialogueWithAuthentication("dropdb",
214             info, "", login, password, 60); // 1 minute timeout
215

216         String JavaDoc[] cmd = makeExpectCommandReadingStdin();
217
218         if (! safelyExecNativeCommand(cmd, expectFeed, 0))
219         {
220           logger.warn("Unable to drop drop database prior to restore");
221         }
222
223         // Re-create the database, use the specified encoding if provided
224
if (logger.isDebugEnabled())
225           logger.debug("Re-creating '" + info.getDbName() + "'");
226
227         expectFeed = makeExpectDialogueWithAuthentication("createdb", info,
228             encoding != null ? "--encoding=" + encoding + " " : "", login,
229             password, 60); // 1 minute timeout
230

231         cmd = makeExpectCommandReadingStdin();
232
233         if (! safelyExecNativeCommand(cmd, expectFeed, 0))
234         {
235           throw new BackupException(
236               "createdb execution did not complete successfully!");
237         }
238
239         // Run a pre-restore script, if specified
240
if (preRestoreScript != null)
241         {
242           if (logger.isDebugEnabled())
243             logger.debug("Running pre-restore script '" + preRestoreScript
244                 + "' on '" + info.getDbName() + "'");
245
246           expectFeed = makeExpectDialogueWithAuthentication("psql", info,
247               "--pset pager -f " + preRestoreScript, login, password, 300); // 5
248
// minutes
249
// timeout
250

251           cmd = makeExpectCommandReadingStdin();
252
253           if (! safelyExecNativeCommand(expectFeed, cmd, 0))
254           {
255             throw new BackupException(
256                 "psql execution did not complete successfully!");
257           }
258         }
259
260         // Use the pg_restore command to rebuild the database
261
if (logger.isDebugEnabled())
262           logger.debug("Rebuilding '" + info.getDbName() + "' from dump '"
263               + dumpName + "'");
264
265         int timeout = -1;
266         if (restoreTimeout != null)
267         {
268           try
269           {
270             timeout = Integer.parseInt(restoreTimeout);
271           }
272           catch (NumberFormatException JavaDoc e)
273           {
274             logger.error("\"" + restoreTimeout
275                 + "\" is not a valid restore-timeout value!");
276             timeout = -1;
277           }
278         }
279
280         expectFeed = makeExpectDialogueWithAuthentication("pg_restore", info,
281             "--format=c -d " + info.getDbName() + " " + fullPath, login,
282             password, timeout); // 30 minutes timeout
283

284         cmd = makeExpectCommandReadingStdin();
285
286         if (! safelyExecNativeCommand(cmd, expectFeed, 0))
287         {
288           throw new BackupException(
289               "pg_restore execution did not complete successfully!");
290         }
291         
292         // Run a post-restore script, if specified
293
if (postRestoreScript != null)
294         {
295           if (logger.isDebugEnabled())
296             logger.debug("Running post-restore script '" + postRestoreScript
297                 + "' on '" + info.getDbName() + "'");
298
299           expectFeed = makeExpectDialogueWithAuthentication("psql", info,
300               "--pset pager -f " + postRestoreScript, login, password, 300); // 5
301
// minutes
302
// timeout
303

304           cmd = makeExpectCommandReadingStdin();
305
306           if (! safelyExecNativeCommand(expectFeed, cmd, 0))
307           {
308             throw new BackupException(
309                 "psql execution did not complete successfully!");
310           }
311         }
312       }
313       else
314       // No authentication
315
{
316         // Drop the database if it already exists
317
if (logger.isDebugEnabled())
318           logger.debug("Dropping database '" + info.getDbName() + "'");
319
320         String JavaDoc dropCmd = makeCommand("dropdb", info, "", login);
321         if (! safelyExecNativeCommand(dropCmd, null, 0))
322         {
323           // Errors can happen there, e.g. if the database does not exist yet.
324
// Just log them, and carry-on...
325
logger.warn("Unable to drop drop database prior to restore");
326         }
327
328         // Re-create the database, use the specified encoding if provided
329
if (logger.isDebugEnabled())
330           logger.debug("Re-creating '" + info.getDbName() + "'");
331
332         String JavaDoc createCmd = makeCommand("createdb", info, encoding != null
333             ? "--encoding=" + encoding + " "
334             : "", login);
335         if (! safelyExecNativeCommand(createCmd, null, 0))
336         {
337           throw new BackupException(
338               "createdb execution did not complete successfully!");
339         }
340
341         // Run a pre-restore script, if specified
342
if (preRestoreScript != null)
343         {
344           if (logger.isDebugEnabled())
345             logger.debug("Running pre-restore script '" + preRestoreScript
346                 + "' on '" + info.getDbName() + "'");
347
348           String JavaDoc preRestoreCmd = makeCommand("psql", info, "--pset pager -f "
349               + preRestoreScript, login);
350           if (! safelyExecNativeCommand(preRestoreCmd, null, 0))
351           {
352             printErrors();
353             throw new BackupException(
354                 "psql execution did not complete successfully!");
355           }
356         }
357
358         // Use the psql command to rebuild the database
359
if (logger.isDebugEnabled())
360           logger.debug("Rebuilding '" + info.getDbName() + "' from dump '"
361               + dumpName + "'");
362
363         String JavaDoc replayCmd = makeCommand("pg_restore", info, "--format=c -d "
364             + info.getDbName() + " " + fullPath, login);
365         if (! safelyExecNativeCommand(replayCmd, null, 0))
366         {
367           throw new BackupException(
368               "pg_restore execution did not complete successfully!");
369         }
370         
371         // Run a post-restore script, if specified
372
if (postRestoreScript != null)
373         {
374           if (logger.isDebugEnabled())
375             logger.debug("Running post-restore script '" + postRestoreScript
376                 + "' on '" + info.getDbName() + "'");
377
378           String JavaDoc postRestoreCmd = makeCommand("psql", info, "--pset pager -f "
379               + postRestoreScript, login);
380           if (! safelyExecNativeCommand(postRestoreCmd, null, 0))
381           {
382             throw new BackupException(
383                 "psql execution did not complete successfully!");
384           }
385         }
386       }
387     }
388     catch (Exception JavaDoc e)
389     {
390       String JavaDoc msg = "Error while performing backup";
391       logger.error(msg, e);
392       throw new BackupException(msg, e);
393     }
394   }
395
396   /**
397    * @see org.continuent.sequoia.controller.backup.Backuper#fetchDump(org.continuent.sequoia.controller.backup.DumpTransferInfo,
398    * java.lang.String, java.lang.String)
399    */

400   public void fetchDump(DumpTransferInfo dumpTransferInfo, String JavaDoc path,
401       String JavaDoc dumpName) throws BackupException, IOException JavaDoc
402   {
403     BackupManager.fetchDumpFile(dumpTransferInfo, path, dumpName);
404   }
405 }
406
Popular Tags