/*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is the Kowari Metadata Store.
*
* The Initial Developer of the Original Code is Plugged In Software Pty
* Ltd (http://www.pisoftware.com, mailto:info@pisoftware.com). Portions
* created by Plugged In Software Pty Ltd are Copyright (C) 2001,2002
* Plugged In Software Pty Ltd. All Rights Reserved.
*
* Contributor(s): N/A.
*
* [NOTE: The text of this Exhibit A may differ slightly from the text
* of the notices in the Source Code files of the Original Code. You
* should use the text of this Exhibit A rather than the text found in the
* Original Code Source Code for Your Modifications.]
*
*/
package org.mulgara.resolver;
// Java 2 standard packages
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.URI;
import java.util.Date;
import java.util.zip.GZIPOutputStream;
import org.apache.log4j.Logger;
import org.mulgara.query.ConstraintImpl;
import org.mulgara.query.QueryException;
import org.mulgara.query.TuplesException;
import org.mulgara.resolver.spi.DatabaseMetadata;
import org.mulgara.resolver.spi.SecurityAdapter;
import org.mulgara.resolver.spi.SystemResolver;
import org.mulgara.store.statement.StatementStore;
import org.mulgara.store.stringpool.SPObject;
import org.mulgara.store.tuples.Tuples;
/**
* An {@link Operation} that serializes the state of the database into a backup
* file which can be read back by the complementary {@link RestoreOperation}.
*
* @created 2004-10-07
* @author <a href="http://staff.pisoftware.com/raboczi">Simon Raboczi</a>
* @version $Revision: 1.9 $
* @modified $Date: 2005/02/22 08:16:06 $ by $Author: newmana $
* @company <a href="mailto:info@PIsoftware.com">Plugged In Software</a>
* @copyright ©2004 <a href="http://www.tucanatech.com/">Tucana
* Technology, Inc</a>
* @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
*/
class BackupOperation extends OutputOperation implements BackupConstants, Operation {
private static final Logger logger = Logger.getLogger(BackupOperation.class);
//
// Constructor
//
/**
* Create an {@link Operation} that backs up all the data on the specified
* server to a URI or an output stream.
*
* The database is not changed by this method.
* If an {@link OutputStream} is supplied then the destinationURI is ignored.
*
* @param outputStream output stream to receive the contents, may be
* <code>null</code> if a <var>destinationURI</var> is specified
* @param destinationURI URI of the file to backup into, may be
* <code>null</code> if an <var>outputStream</var> is specified
*/
public BackupOperation(OutputStream outputStream, URI destinationURI) {
super(outputStream, destinationURI);
}
//
// Methods implementing Operation
//
public void execute(OperationContext operationContext,
SystemResolver systemResolver,
DatabaseMetadata metadata) throws Exception {
// Make sure security adapters are satisfied before proceeding.
for (SecurityAdapter securityAdapter : operationContext.getSecurityAdapterList()) {
if (!securityAdapter.canBackup()) {
throw new QueryException("You do not have permission to back up the database.");
}
}
OutputStream os = getOutputStream();
Writer writer = null;
boolean success = false;
try {
// The existence of a fragment indicates that a model is to be backed
// up otherwise the entire database is to be backed up.
writer = new BufferedWriter(new OutputStreamWriter(
new GZIPOutputStream(os), "UTF-8"
));
backupDatabase(systemResolver, metadata, writer);
success = true;
} finally {
// Clean up.
try {
if (writer != null) {
// Close the writer if it exists. This will also close the wrapped
// OutputStream.
writer.close();
} else if (os != null) {
// Close the os if it exists.
os.close();
}
} catch (IOException e) {
if (success) throw e; // The backup worked but we couldn't close, so re-throw.
else logger.info("Suppressing I/O exception closing failed backup writer", e); // Log and ignore.
}
}
}
/**
* Dumps the entire database to the specified Writer.
*
* @param systemResolver The system resolver for the database.
* @param metadata The Metadata for the database.
* @param writer Writer The output to write to.
* @throws Exception Due to any error accessing the database or writing to the writer.
*/
private void backupDatabase(SystemResolver systemResolver, DatabaseMetadata metadata, Writer writer)
throws Exception {
// Write the backup
writer.write(BACKUP_FILE_HEADER + BACKUP_VERSION6 + '\n');
writer.write(new Date().toString());
writer.write('\n');
// Dump the strings.
writer.write("RDFNODES\n");
Tuples t = systemResolver.findStringPoolType(null, null);
assert t != null;
try {
t.beforeFirst();
while (t.next()) {
long localNode = t.getColumnValue(0);
writer.write(Long.toString(localNode));
writer.write(' ');
SPObject spObject = systemResolver.findSPObject(localNode);
writer.write(spObject.getEncodedString());
writer.write('\n');
}
} finally {
try {
t.close();
} catch (TuplesException e) {
logger.warn("Error closing tuples during backup", e);
}
}
// Dump the triples.
Tuples tuples = systemResolver.resolve(new ConstraintImpl(
StatementStore.VARIABLES[0],
StatementStore.VARIABLES[1],
StatementStore.VARIABLES[2],
StatementStore.VARIABLES[3]));
assert tuples != null;
try {
int[] colMap = mapColumnsToStd(tuples.getVariables());
writer.write("TRIPLES\n");
long preallocationModelNode = metadata.getPreallocationModelNode();
for (tuples.beforeFirst(); tuples.next(); ) {
// Suppress output of the preallocation model.
long modelNode = tuples.getColumnValue(colMap[3]);
if (modelNode != preallocationModelNode) {
writer.write(Long.toString(tuples.getColumnValue(colMap[0])));
writer.write(' ');
writer.write(Long.toString(tuples.getColumnValue(colMap[1])));
writer.write(' ');
writer.write(Long.toString(tuples.getColumnValue(colMap[2])));
writer.write(' ');
writer.write(Long.toString(modelNode));
writer.write('\n');
}
}
} finally {
try {
tuples.close();
} catch (TuplesException e) {
logger.warn("Error closing tuples during backup", e);
}
}
writer.write("END\n");
}
}