/* The contents of this file are subject to the license and copyright terms
* detailed in the license directory at the root of the source tree (also
* available online at http://fedora-commons.org/license/).
*/
package org.fcrepo.server.resourceIndex;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.annotation.Resource;
import org.trippi.TriplestoreConnector;
import org.trippi.impl.mulgara.MulgaraConnector;
import org.fcrepo.server.Module;
import org.fcrepo.server.config.ModuleConfiguration;
import org.fcrepo.server.config.Parameter;
import org.fcrepo.server.config.ServerConfiguration;
import org.fcrepo.server.errors.ResourceIndexException;
import org.fcrepo.server.storage.SimpleDOReader;
import org.fcrepo.server.storage.types.DigitalObject;
import org.fcrepo.server.utilities.rebuild.Rebuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.support.GenericApplicationContext;
/**
* A Rebuilder for the resource index.
*/
public class ResourceIndexRebuilder
implements ApplicationContextAware, Rebuilder {
private static Logger logger = LoggerFactory.getLogger(ResourceIndexRebuilder.class.getName());
private static final String moduleName = "org.fcrepo.server.resourceIndex.ResourceIndex";
private static final String configName = "org.fcrepo.server.resourceIndex.ResourceIndexConfiguration";
private ModuleConfiguration m_riConfig;
private GenericApplicationContext m_context;
private ResourceIndex m_ri;
private TriplestoreConnector m_conn;
private TripleGenerator m_generator;
public ResourceIndexRebuilder(){
}
@Resource(name = "org.trippi.TriplestoreConnector")
public void setTriplestoreConnector(TriplestoreConnector conn){
m_conn = conn;
}
@Resource(name = configName)
public void setModuleConfiguration(ModuleConfiguration riConfig) {
m_riConfig = riConfig;
}
/**
* Get a short phrase describing what the user can do with this rebuilder.
*/
public String getAction() {
return "Rebuild the Resource Index.";
}
/**
* Returns true is the server _must_ be shut down for this rebuilder to
* safely operate.
*/
public boolean shouldStopServer() {
return true;
}
/**
* Initialize the rebuilder, given the server configuration.
*
*/
public void setServerConfiguration(ServerConfiguration serverConfig){
// not needed
}
public void setServerDir(File serverBaseDir) {
// not needed
}
public void init() {
}
public Map<String, String> getOptions() {
Map<String, String> m = new HashMap<String, String>();
return m;
}
@Resource(name = "org.fcrepo.server.resourceIndex.TripleGenerator")
public void setTripleGenerator(TripleGenerator generator) {
m_generator = generator;
}
/**
* Validate the provided options and perform any necessary startup tasks.
*/
public void start(Map<String, String> options)
throws ResourceIndexException {
// validate options
// do startup tasks
String levelValue;
if (m_riConfig == null){ //must have been configured outside fcfg
Module riModule = m_context.getBean(moduleName,Module.class);
if (riModule != null){
logger.warn("ModuleConfiguration bean unavailable; getting Module bean");
levelValue = riModule.getParameter("level");
}
else {
logger.error("Cannot load ResourceIndex module definition from Spring config or Fedora config");
throw new ResourceIndexException("Cannot locate ResourceIndex module definition in Spring config or Fedora config");
}
}
else {
levelValue = m_riConfig.getParameter("level",Parameter.class).getValue();
}
int riLevel = Integer.parseInt(levelValue);
Map<String, String> aliasMap = new HashMap<String, String>();
Iterator<Parameter> it = m_riConfig.getParameters(Parameter.class).iterator();
Parameter p;
while (it.hasNext()) {
p = it.next();
String pName = p.getName();
String[] parts = pName.split(":");
if (parts.length == 2 && parts[0].equals("alias")) {
aliasMap.put(parts[1], p.getValue(p.getIsFilePath()));
}
}
System.out.println("Initializing triplestore interface...");
try {
if (m_conn instanceof MulgaraConnector){
String path = m_conn.getConfiguration().get("path");
dropIndex(path);
}
m_ri = new ResourceIndexImpl(m_conn, m_generator, riLevel, false);
m_ri.setAliasMap(aliasMap);
} catch (Exception e) {
logger.error("Failed to initialize new Resource Index",e);
e.printStackTrace(System.err);
throw new ResourceIndexException("Failed to initialize new Resource Index",
e);
}
}
private void dropIndex(String tsPath){
if (tsPath == null) {
BufferedReader reader =
new BufferedReader(new InputStreamReader(System.in));
System.out.println();
System.out
.println("NOTE: You must now manually re-initialize (clear) ");
System.out
.println(" the existing triplestore. The RI rebuilder");
System.out
.println(" cannot yet automatically perform this step ");
System.out
.println(" for this type of triplestore. Press enter");
System.out.println(" when finished.");
try {
reader.readLine();
} catch (IOException e) {
}
System.out.println("OK, continuing...");
} else {
System.out.println("Clearing directory " + tsPath + "...");
deleteDirectory(tsPath);
File cleanDir = new File(tsPath);
cleanDir.mkdir();
}
}
/**
* Add the data of interest for the given object.
*
* @throws ResourceIndexException
*/
public void addObject(DigitalObject obj) throws ResourceIndexException {
m_ri.addObject(new SimpleDOReader(null, null, null, null, null, obj));
}
/**
* Free up any system resources associated with rebuilding.
*/
public void finish() throws Exception {
if (m_ri != null) {
m_ri.flushBuffer();
m_ri.close();
}
}
private boolean deleteDirectory(String directory) {
boolean result = false;
if (directory != null) {
File file = new File(directory);
if (file.exists() && file.isDirectory()) {
// 1. delete content of directory:
File[] files = file.listFiles();
result = true; //init result flag
int count = files.length;
for (int i = 0; i < count; i++) { //for each file:
File f = files[i];
if (f.isFile()) {
result = result && f.delete();
} else if (f.isDirectory()) {
result = result && deleteDirectory(f.getAbsolutePath());
}
}//next file
file.delete(); //finally delete (empty) input directory
}//else: input directory does not exist or is not a directory
}//else: no input value
return result;
}//deleteDirectory()
@Override
public void setApplicationContext(ApplicationContext context)
throws BeansException {
m_context = (GenericApplicationContext)context;
}
}