/*******************************************************************************
* Copyright (c) 2010-2011 VIVO Harvester Team. For full list of contributors, please see the AUTHORS file provided.
* All rights reserved.
* This program and the accompanying materials are made available under the terms of the new BSD license which accompanies this distribution, and is available at http://www.opensource.org/licenses/bsd-license.html
******************************************************************************/
package org.vivoweb.harvester.util;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.vivoweb.harvester.util.args.ArgDef;
import org.vivoweb.harvester.util.args.ArgList;
import org.vivoweb.harvester.util.args.ArgParser;
import org.vivoweb.harvester.util.args.UsageException;
import org.vivoweb.harvester.util.repo.JenaConnect;
import org.vivoweb.harvester.util.repo.MemJenaConnect;
import org.vivoweb.harvester.util.repo.Record;
import org.vivoweb.harvester.util.repo.RecordHandler;
/**
* Merge multiple rdf files into one
* @author Christopher Haines (hainesc@ctrip.ufl.edu)
*/
public class Merge {
/**
* SLF4J Logger
*/
protected static Logger log = LoggerFactory.getLogger(Merge.class);
/**
* Input RecordHandler
*/
private RecordHandler input;
/**
* Output RecordHandler
*/
private RecordHandler output;
/**
* Regex for finding primary records (with a grouping for the subsection to use to find sub-records)
*/
private Pattern regex;
/**
* Constructor
* @param input input recordhandler
* @param output output recordhandler
* @param regex regex for finding primary records (with a grouping for the subsection to use to find sub-records)
*/
public Merge(RecordHandler input, RecordHandler output, String regex) {
this.input = input;
if(this.input == null) {
throw new IllegalArgumentException("Must provide an input recordhandler");
}
this.output = output;
if(this.output == null) {
throw new IllegalArgumentException("Must provide an output recordhandler");
}
this.regex = Pattern.compile(regex);
}
/**
* Constructor
* @param args commandline arguments
* @throws IOException error creating task
* @throws UsageException user requested usage message
*/
public Merge(String[] args) throws IOException, UsageException {
this(getParser().parse(args));
}
/**
* Constructor
* @param argList arguments
* @throws IOException error connecting to record handler
*/
public Merge(ArgList argList) throws IOException {
this(
RecordHandler.parseConfig(argList.get("i"), argList.getValueMap("I")),
RecordHandler.parseConfig(argList.get("o"), argList.getValueMap("O")),
argList.get("b")
);
}
/**
* Merge records in input using regex and write to output
* @param input input recordhandler
* @param output output recordhandler
* @param regex regex for finding primary records (with a grouping for the subsection to use to find sub-records)
* @throws IOException error in record handling
*/
public static void merge(RecordHandler input, RecordHandler output, Pattern regex) throws IOException {
Map<String, String> matchedIDs = new HashMap<String, String>();
log.info("Building List of Primary Records");
for(Record r : input) {
Matcher m = regex.matcher(r.getID());
if(m.matches()) {
log.debug("Matched record '" + r.getID() + "' => '" + m.group(1) + "'");
matchedIDs.put(r.getID(), m.group(1));
}
}
int count = matchedIDs.size();
log.info("Building List Complete: Matched " + count + " records");
log.info("Beginning Merging Records into Primary Records");
int cur = 0;
JenaConnect jc = new MemJenaConnect();
for(String rid : new TreeSet<String>(matchedIDs.keySet())) {
cur++;
String matchTerm = matchedIDs.get(rid);
log.debug("(" + cur + "/" + count + ": " + Math.round(10000f * cur / count) / 100f + "%): merging '" + matchTerm + "'");
jc.truncate();
for(String id : input.find(matchTerm)) {
log.trace("Merging Record '" + id + "' into '" + matchTerm + "'");
jc.loadRdfFromString(input.getRecord(id).getData(), null, null);
}
output.addRecord(matchTerm, jc.exportRdfToString(), Merge.class);
}
log.info("Merging into Primary Records Complete");
jc.close();
}
/**
* Runs the merge
* @throws IOException error executing
*/
public void execute() throws IOException {
merge(this.input, this.output, this.regex);
}
/**
* Get the ArgParser for this task
* @return the ArgParser
*/
private static ArgParser getParser() {
ArgParser parser = new ArgParser("Merge");
// Inputs
parser.addArgument(new ArgDef().setShortOption('i').setLongOpt("input").withParameter(true, "CONFIG_FILE").setDescription("config file for input jena model").setRequired(false));
parser.addArgument(new ArgDef().setShortOption('I').setLongOpt("inputOverride").withParameterValueMap("JENA_PARAM", "VALUE").setDescription("override the JENA_PARAM of input jena model config using VALUE").setRequired(false));
// Outputs
parser.addArgument(new ArgDef().setShortOption('o').setLongOpt("output").withParameter(true, "CONFIG_FILE").setDescription("config file for output jena model").setRequired(false));
parser.addArgument(new ArgDef().setShortOption('O').setLongOpt("outputOverride").withParameterValueMap("JENA_PARAM", "VALUE").setDescription("override the JENA_PARAM of output jena model config using VALUE").setRequired(false));
// Params
parser.addArgument(new ArgDef().setShortOption('b').setLongOpt("baseRegex").withParameter(true, "REGEX").setDescription("match records using REGEX and use the first Group to find sub-records").setRequired(true));
return parser;
}
/**
* Main method
* @param args commandline arguments
*/
public static void main(String... args) {
Exception error = null;
try {
InitLog.initLogger(args, getParser());
log.info(getParser().getAppName() + ": Start");
new Merge(args).execute();
} catch(IllegalArgumentException e) {
log.error(e.getMessage());
log.debug("Stacktrace:",e);
System.out.println(getParser().getUsage());
error = e;
} catch(UsageException e) {
log.info("Printing Usage:");
System.out.println(getParser().getUsage());
error = e;
} catch(Exception e) {
log.error(e.getMessage());
log.debug("Stacktrace:",e);
error = e;
} finally {
log.info(getParser().getAppName() + ": End");
if(error != null) {
System.exit(1);
}
}
}
}