/*
* eXist Open Source Native XML Database
* Copyright (C) 2010 The eXist Project
* http://exist-db.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* $Id$
*/
package org.exist.ant;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.Properties;
import javax.xml.transform.OutputKeys;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.exist.util.serializer.SAXSerializer;
import org.exist.util.serializer.SerializerPool;
import org.exist.xmldb.ExtendedResource;
import org.xmldb.api.DatabaseManager;
import org.xmldb.api.base.Collection;
import org.xmldb.api.base.Resource;
import org.xmldb.api.base.XMLDBException;
import org.xmldb.api.modules.XMLResource;
/**
* an ant task to extract the content of a collection or resource
*
* @author peter.klotz@blue-elephant-systems.com
* @author jim.fuller at webcomposite.com to handle binary file extraction
*/
public class XMLDBExtractTask extends AbstractXMLDBTask {
private String resource = null;
private File destFile = null;
private File destDir = null;
private String type = "xml";
private boolean createdirectories = false;
private boolean subcollections = false;
private boolean overwrite = false;
// output encoding
private String encoding = "UTF-8";
/* (non-Javadoc)
* @see org.apache.tools.ant.Task#execute()
*/
public void execute() throws BuildException {
if (uri == null) {
if (failonerror) {
throw new BuildException("You need to specify an XMLDB collection URI");
}
} else {
registerDatabase();
try {
Collection base = DatabaseManager.getCollection(uri, user, password);
if (base == null) {
throw new BuildException("Collection " + uri + " could not be found.");
}
if (resource != null && destDir == null) {
// extraction of a single resource
log("Extracting resource: " + resource + " to " + destFile.getAbsolutePath(), Project.MSG_INFO);
Resource res = base.getResource(resource);
if (res == null) {
String msg = "Resource " + resource + " not found.";
if (failonerror) {
throw new BuildException(msg);
} else {
log(msg, Project.MSG_ERR);
}
} else {
writeResource(res, destFile);
}
} else {
// extraction of a collection
extractResources(base, null);
if (subcollections) {
extractSubCollections(base, null);
}
}
} catch (XMLDBException e) {
String msg = "XMLDB exception caught while executing query: " + e.getMessage();
if (failonerror) {
throw new BuildException(msg, e);
} else {
log(msg, e, Project.MSG_ERR);
}
} catch (IOException e) {
String msg = "XMLDB exception caught while writing destination file: " + e.getMessage();
if (failonerror) {
throw new BuildException(msg, e);
} else {
log(msg, e, Project.MSG_ERR);
}
}
}
}
/**
* Create directory from a collection
*
*/
private void extractResources(Collection base, String path)
throws XMLDBException, IOException {
Resource res = null;
String[] resources = base.listResources();
if (resources != null) {
File dir = destDir;
log("Extracting to directory " + destDir.getAbsolutePath(), Project.MSG_DEBUG);
if (path != null) {
dir = new File(destDir, path);
}
for (String resource : resources) {
res = base.getResource(resource);
log("Extracting resource: " + res.getId(), Project.MSG_DEBUG);
if (!dir.exists() && createdirectories) {
dir.mkdirs();
}
if (dir.exists()) {
writeResource(res, dir);
}
}
}
}
/**
* Extract multiple resources from a collection
*
*/
private void extractSubCollections(Collection base, String path) throws XMLDBException, IOException {
String[] childCols = base.listChildCollections();
if (childCols != null) {
Collection col = null;
for (String childCol : childCols) {
col = base.getChildCollection(childCol);
if (col != null) {
log("Extracting collection: " + col.getName(), Project.MSG_DEBUG);
File dir = destDir;
String subdir;
if (path != null) {
dir = new File(destDir, path + File.separator + childCol);
subdir = path + File.separator + childCol;
} else {
subdir = childCol;
}
if (!dir.exists() && createdirectories == true) {
dir.mkdirs();
}
extractResources(col, subdir);
if (subcollections == true) {
extractSubCollections(col, subdir);
}
}
}
}
}
/**
* Extract single resource
*
*/
private void writeResource(Resource res, File dest) throws XMLDBException, FileNotFoundException, UnsupportedEncodingException, IOException {
if (res instanceof XMLResource) {
writeXMLResource((XMLResource) res, dest);
} else if (res instanceof ExtendedResource) {
writeBinaryResource(res, dest);
}
}
/**
* Extract XML resource
*
*/
private void writeXMLResource(XMLResource res, File dest) throws IOException, XMLDBException {
if (createdirectories == true) {
File parentDir = new File(dest.getParent());
if (!parentDir.exists()) {
parentDir.mkdirs();
}
}
if (dest != null || overwrite == true) {
Properties outputProperties = new Properties();
outputProperties.setProperty(OutputKeys.INDENT, "yes");
SAXSerializer serializer = (SAXSerializer) SerializerPool.getInstance().borrowObject(SAXSerializer.class);
Writer writer = null;
if (dest.isDirectory()) {
String fname = res.getId();
if (!fname.endsWith("." + type)) {
fname += "." + type;
}
File file = new File(dest, fname);
writer = new OutputStreamWriter(new FileOutputStream(file), encoding);
} else {
writer = new OutputStreamWriter(new FileOutputStream(dest), encoding);
}
log("Writing resource " + res.getId() + " to destination " + dest.getAbsolutePath(), Project.MSG_DEBUG);
serializer.setOutput(writer, outputProperties);
res.getContentAsSAX(serializer);
SerializerPool.getInstance().returnObject(serializer);
writer.close();
} else {
String msg = "Destination xml file " + ((dest != null) ? (dest.getAbsolutePath() + " ") : "") + "exists. Use "
+ "overwrite property to overwrite this file.";
if (failonerror) {
throw new BuildException(msg);
} else {
log(msg, Project.MSG_ERR);
}
}
}
/**
* Extract single binary resource
*
*/
private void writeBinaryResource(Resource res, File dest) throws XMLDBException, FileNotFoundException, UnsupportedEncodingException, IOException {
if (createdirectories == true) {
File parentDir = new File(dest.getParent());
if (!parentDir.exists()) {
parentDir.mkdirs();
}
}
//dest != null && ( !dest.exists() ||
if (dest != null || overwrite == true) {
if (dest.isDirectory()) {
String fname = res.getId();
if (!fname.endsWith("." + type)) {
fname += "";
}
dest = new File(dest, fname);
}
FileOutputStream os;
os = new FileOutputStream(dest);
((ExtendedResource) res).getContentIntoAStream(os);
} else {
String msg = "Dest binary file " + ((dest != null) ? (dest.getAbsolutePath() + " ") : "") + "exists. Use "
+ "overwrite property to overwrite file.";
if (failonerror) {
throw new BuildException(msg);
} else {
log(msg, Project.MSG_ERR);
}
}
}
public void setResource(String resource) {
this.resource = resource;
}
public void setDestFile(File destFile) {
this.destFile = destFile;
}
public void setDestDir(File destDir) {
this.destDir = destDir;
}
public void setType(String type) {
this.type = type;
if (!"xml".equalsIgnoreCase(type) & !"binary".equalsIgnoreCase(type)) {
throw new BuildException("non-xml or non-binary resource types are not supported currently");
}
}
public void setCreatedirectories(boolean createdirectories) {
this.createdirectories = createdirectories;
}
public void setSubcollections(boolean subcollections) {
this.subcollections = subcollections;
}
public void setOverwrite(boolean createdirectories) {
this.overwrite = createdirectories;
}
}