package com.thespeechcorporation.plugin.maven;
import java.io.File;
import java.util.List;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.xmldb.api.DatabaseManager;
import org.xmldb.api.base.Collection;
import org.xmldb.api.base.Database;
import org.xmldb.api.base.Resource;
import org.xmldb.api.base.XMLDBException;
import org.xmldb.api.modules.CollectionManagementService;
/**
* This plugin communicates with the eXist database. This plugin is considered a replacement of the
* existing possibility to communicate with the database from maven, namely the Ant plugin. The root
* of the database is initialized as follow:
*
* Collection root = DatabaseManager.getCollection("xmldb:exist://localhost:8080/exist/xmlrpc/db", "username", "password");
*
* @goal execute
* @phase install
*/
public class ExistPlugin extends AbstractMojo {
// Constants
private final String CLASSNAME = this.getClass().getName();
private final String XML = "XMLResource"; // According to XM:DB API specification
private final String BINARY = "BinaryResource"; // According to XM:DB API specification
private final String COLLECTION_MANAGEMENT_SERVICE = "CollectionManagementService";
private final String COLLECTION_MANAGEMENT_SERVICE_VERSION = "1.0";
private final String DELIMITER = "/";
// Globals
private Collection root = null;
private CollectionManagementService service = null;
private Database database = null;
/**
* The url, the database is running under
* @parameter default-value=""
* @required
*/
private String url = null;
/**
* The username associated with the eXist user.
* @parameter default-value=""
* @required
*/
private String username = null;
/**
* The password associated with the eXist user.
* @parameter default-value=""
*/
private String password = null;
/**
* The List of collections to be created
* @parameter
*/
private List createCollections = null;
/**
* The List of collections to be deleted
* @parameter
*/
private List deleteCollections = null;
/**
* The List of resources to be created
* @parameter
*/
private List createData = null;
/**
* The list of resources to be deleted
* @parameter
*/
private List deleteData = null;
/**
* An auxiliary to initialize the maven plugin.
* @throws MojoExecutionException When intialization failed.
*/
private void init() throws MojoExecutionException {
try {
Class> driver = Class.forName("org.exist.xmldb.DatabaseImpl");
this.database = (Database) driver.newInstance();
this.database.setProperty("create-database", "true");
DatabaseManager.registerDatabase(this.database);
this.root = DatabaseManager.getCollection(this.url, this.username, this.password);
this.service = (CollectionManagementService) root.getService(COLLECTION_MANAGEMENT_SERVICE, COLLECTION_MANAGEMENT_SERVICE_VERSION);
} catch (Exception e) {
if(super.getLog().isErrorEnabled()) {
super.getLog().error(e.getMessage(), e);
}
throw new MojoExecutionException(e.getMessage(), e);
}
}
/**
* The method to execute the maven plugin.
* @throws MojoExecutionException When execution failed.
*/
public void execute() throws MojoExecutionException, MojoFailureException {
this.init();
if(super.getLog().isInfoEnabled()) {
super.getLog().info("[" + CLASSNAME + "] executing...");
super.getLog().info("\tUsing url: " + this.url);
super.getLog().info("\tUsing username: " + this.username);
super.getLog().info("\tUsing password: " + this.password);
}
// Delete collections
this.deleteCollections();
// Create collections
this.createCollections();
// Create files
this.createFiles();
// Delete files
this.deleteFiles();
if(super.getLog().isInfoEnabled()) {
super.getLog().info("[" + CLASSNAME + "] executing... done!");
}
}
/**
* An auxiliary method to delete collections. Note that subdirectories are deleted as well.
*/
private void deleteCollections() throws MojoExecutionException {
if(this.deleteCollections == null || this.deleteCollections.size() == 0) {
if(super.getLog().isInfoEnabled()) {
super.getLog().info("No collections to delete");
}
return;
}
try {
for(String collection : this.deleteCollections) {
if(super.getLog().isInfoEnabled()) {
super.getLog().info("Deleted collection: " + collection);
}
this.service.removeCollection(collection);
}
} catch (Exception e) {
if(super.getLog().isErrorEnabled()) {
super.getLog().error(e.getMessage(), e);
}
throw new MojoExecutionException(e.getMessage(), e);
}
}
/**
* An auxiliary method to create collections. Note that subdirectories are created as well when the parent
* is non existent, i.e. the parent is created along.
* @throws MojoExecutionException When the database is non responsive.
*/
private void createCollections() throws MojoExecutionException {
if(this.createCollections == null || this.createCollections.size() == 0) {
if(super.getLog().isInfoEnabled()) {
super.getLog().info("No collections to create");
}
return;
}
try {
for(String collection : this.createCollections) {
if(super.getLog().isInfoEnabled()) {
super.getLog().info("Created collection: " + collection);
}
this.service.createCollection(collection);
}
} catch (Exception e) {
if(super.getLog().isErrorEnabled()) {
super.getLog().error(e.getMessage(), e);
}
throw new MojoExecutionException(e.getMessage(), e);
}
}
/**
* An auxiliary method to create files.
* @throws MojoExecutionException
*/
private void createFiles() throws MojoExecutionException {
Collection target = null;
File file = null;
Resource resource = null;
if(this.createData == null || this.createData.size() == 0) {
if(super.getLog().isInfoEnabled()) {
super.getLog().info("No files to create");
}
return;
}
if(super.getLog().isInfoEnabled()) {
super.getLog().info("Total files to create: " + this.createData.size());
}
try {
for(Data data : this.createData) {
if(super.getLog().isInfoEnabled()) {
super.getLog().info("Resource to be created:");
}
file = new File(data.getSource());
if(super.getLog().isInfoEnabled()) {
super.getLog().info("\tResource source: " + data.getSource() + ", exist: " + file.exists());
super.getLog().info("\tResource destination: " + data.getDestination());
}
if(data.getType() == null || data.getType().trim().equals("") ||
data.getType().trim().equals("xml") || data.getType().trim().equals(XML))
{
data.setType(XML); // Set type default to XML
} else {
data.setType(BINARY); // All other is considered binary content
}
if(super.getLog().isInfoEnabled()) {
super.getLog().info("\tResource type: " + data.getType());
}
// Get target Collection
target = this.navigateToCollection(data.getDestination(), this.root, false);
if(target == null) {
if(super.getLog().isInfoEnabled()) {
super.getLog().info("Target collection (" + data.getDestination() + ") does not exist, aborting...");
}
continue;
}
resource = target.createResource(file.getName(), data.getType());
resource.setContent(file);
target.storeResource(resource);
}
} catch (Exception e) {
if(super.getLog().isErrorEnabled()) {
super.getLog().error(e.getMessage(), e);
}
throw new MojoExecutionException(e.getMessage(), e);
}
}
/**
* An auxiliary method to delete files.
* @throws MojoExecutionException
*/
private void deleteFiles() throws MojoExecutionException {
Collection target = null;
Resource resource = null;
if(this.deleteData == null || this.deleteData.size() == 0) {
if(super.getLog().isInfoEnabled()) {
super.getLog().info("No files to delete");
}
return;
}
if(super.getLog().isInfoEnabled()) {
super.getLog().info("Total files to delete: " + this.deleteData.size());
}
try {
for(String data : this.deleteData) {
// Get target Collection
target = this.navigateToCollection(data, this.root, true);
data = data.substring(data.lastIndexOf(DELIMITER) + 1, data.length());
resource = target.getResource(data);
if(resource != null) {
target.removeResource(resource);
}
}
} catch (Exception e) {
if(super.getLog().isErrorEnabled()) {
super.getLog().error(e.getMessage(), e);
}
throw new MojoExecutionException(e.getMessage(), e);
}
}
/**
* Auxiliary method to navigate to the correct Collection. This is typically used for creation and deletion
* of resources in sub collections.
* @param path The path of the collection.
* @param current The current collection.
* @return The target collection.
* @throws XMLDBException When a database error occurs.
*/
private Collection navigateToCollection(String path, Collection current, boolean fileIncluded) throws XMLDBException {
int index = -1;
index = path.indexOf(DELIMITER);
if(index == -1) {
if(fileIncluded) {
return current;
} else {
return current.getChildCollection(path);
}
} else {
return this.navigateToCollection(path.substring(index + 1), current.getChildCollection(path.substring(0, index)), fileIncluded);
}
}
}