/******************************************************************************* * Copyright (c) 2008 Cambridge Semantics Incorporated. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Cambridge Semantics Incorporated *******************************************************************************/ package org.openanzo.client.cli; import java.util.List; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.Option; import org.apache.commons.cli.Options; import org.apache.commons.lang.ObjectUtils; import org.openanzo.client.AnzoClient; import org.openanzo.client.ClientGraph; import org.openanzo.client.INamedGraphInitializer; import org.openanzo.exceptions.AnzoException; import org.openanzo.exceptions.AnzoRuntimeException; import org.openanzo.exceptions.ExceptionConstants; import org.openanzo.rdf.Constants; import org.openanzo.rdf.Dataset; import org.openanzo.rdf.IDataset; import org.openanzo.rdf.INamedGraph; import org.openanzo.rdf.RDFFormat; import org.openanzo.rdf.URI; import org.openanzo.rdf.utils.ReadWriteUtils; import org.openanzo.rdf.utils.UriGenerator; import org.openanzo.services.UpdateServerException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; class UpdateCommand extends RdfIOCommand { private static final Logger log = LoggerFactory.getLogger(UpdateCommand.class); private static final Option BASE_OPTION = new Option("b", "base", true, "Set the base URI of the input RDF file(s) or URI(s)"); private static final Option ADD_OPTION = new Option("a", "add", true, "RDF file or URI containing additions."); private static final Option REMOVE_OPTION = new Option("r", "remove", true, "RDF or URI containing removals."); private static final Option INPUT_FORMAT = new Option("i", "input-format", true, "Overide the default RDF format associated with RDF input(s)."); private static final Option GRAPH = new Option("g", "graph", true, "Named graph uri to use for rdf inputs that do not support named graph serialization"); private static final Option FORCE_CREATE = new Option("f", "force-create", false, "Create graphs if they do not exist already."); private static final Option ENCODING = new Option("e", "encoding", true, "Override the default charset for uploading RDF files."); INamedGraphInitializer[] inits = new INamedGraphInitializer[] { AnzoClient.GRAPH_MUST_EXIST }; public INamedGraphInitializer[] getNamedGraphInitializers() { return inits; } static { BASE_OPTION.setArgName("URI"); ADD_OPTION.setArgName("file | URI"); REMOVE_OPTION.setArgName("file | URI"); INPUT_FORMAT.setArgName("format"); GRAPH.setArgName("URI"); } public String getName() { return "update"; } public Options getOptions() { Options options = new Options(); options.addOption(BASE_OPTION); options.addOption(ADD_OPTION); options.addOption(REMOVE_OPTION); options.addOption(INPUT_FORMAT); options.addOption(GRAPH); options.addOption(FORCE_CREATE); options.addOption(ENCODING); return options; } public int invoke(CommandLine cl, CommandContext context, AnzoClient client) throws AnzoException { if (isFlagSet(cl, FORCE_CREATE)) { inits = new INamedGraphInitializer[] {}; } RDFFormat overrideInputFormat = getFormatOption(cl, INPUT_FORMAT); String charsetName = getEncodingOption(cl, ENCODING); RdfInputArgument addsOption = getRdfInputOption(context, cl, ADD_OPTION, overrideInputFormat, charsetName); RdfInputArgument removesOption = getRdfInputOption(context, cl, REMOVE_OPTION, overrideInputFormat, charsetName); URI base = getURIOption(cl, BASE_OPTION, context); URI defaultNamedGraphUri = getURIOption(cl, GRAPH, context); return update(context, client, addsOption, removesOption, defaultNamedGraphUri, base); } public int update(CommandContext context, AnzoClient client, RdfInputArgument add, RdfInputArgument remove, URI defaultNamedGraphUri, URI base) throws AnzoException { int result = 1; IDataset adds = new Dataset(); IDataset removes = new Dataset(); INamedGraph addsDefaultNamedGraph = null; INamedGraph removesDefaultNamedGraph = null; URI addDefaultNamedGraphUri = defaultNamedGraphUri; if (addDefaultNamedGraphUri == null && add != null) { addDefaultNamedGraphUri = add.getDefaultGraphURI(); } URI removeDefaultNamedGraphUri = defaultNamedGraphUri; if (removeDefaultNamedGraphUri == null && remove != null) { removeDefaultNamedGraphUri = remove.getDefaultGraphURI(); } if (addDefaultNamedGraphUri != null) { adds.addNamedGraph(addDefaultNamedGraphUri); addsDefaultNamedGraph = adds.getNamedGraph(addDefaultNamedGraphUri); } if (removeDefaultNamedGraphUri != null) { removes.addNamedGraph(removeDefaultNamedGraphUri); removesDefaultNamedGraph = removes.getNamedGraph(removeDefaultNamedGraphUri); } if (add != null) { URI addBase = base; if (addBase == null) { addBase = add.getDefaultGraphURI(); } RDFFormat addFileFormat = add.getFormat(); if (addFileFormat == null) { throw new InvalidArgumentException(add.inputName + " is not a valid RDF format file type. Use a proper file type or STDIN."); } if (!addFileFormat.supportsNamedGraphs()) { if (addDefaultNamedGraphUri == null) { throw new InvalidArgumentException(GRAPH.getLongOpt() + " option must be set for format " + addFileFormat + " since this format does not support named graphs"); } ReadWriteUtils.loadGraph(addsDefaultNamedGraph, add.getReader(), addFileFormat, ObjectUtils.toString(addBase)); } else { ReadWriteUtils.loadQuadStore(adds, add.getReader(), addFileFormat, ObjectUtils.toString(addBase)); } } if (remove != null) { URI removeBase = base; if (removeBase == null) { removeBase = remove.getDefaultGraphURI(); } RDFFormat removeFileFormat = remove.getFormat(); if (removeFileFormat == null) { throw new InvalidArgumentException(remove.inputName + " is not a valid RDF format file type. Use a proper file type or STDIN."); } if (!removeFileFormat.supportsNamedGraphs()) { if (removeDefaultNamedGraphUri == null) { throw new InvalidArgumentException(GRAPH.getLongOpt() + " option must be set for format " + removeFileFormat + " since this format does not support named graphs"); } ReadWriteUtils.loadGraph(removesDefaultNamedGraph, remove.getReader(), removeFileFormat, ObjectUtils.toString(removeBase)); } else { ReadWriteUtils.loadQuadStore(removes, remove.getReader(), removeFileFormat, ObjectUtils.toString(removeBase)); } } boolean owns = false; try { owns = !client.isConnected(); if (owns) { client.connect(); printOnConnectionSuccess(context); } client.begin(); int total = 0; for (URI uri : removes.getNamedGraphUris()) { ClientGraph graph; INamedGraph ng; if (UriGenerator.isMetadataGraphUri(uri)) { URI uri_ng = UriGenerator.stripEncapsulatedURI(Constants.NAMESPACES.METADATAGRAPH_PREFIX, uri); graph = client.getReplicaGraph(uri_ng, getNamedGraphInitializers()); ng = graph.getMetadataGraph(); total += removes.getNamedGraph(uri).getStatements().size(); ng.remove(removes.getNamedGraph(uri).getStatements()); // remove the listed statements from the metadata graph } else { graph = client.getReplicaGraph(uri, getNamedGraphInitializers()); ng = removes.getNamedGraph(uri); total += ng.getStatements().size(); graph.remove(ng.getStatements()); } if (total > 20000) { client.commit(); client.begin(); total = 0; } } for (URI uri : adds.getNamedGraphUris()) { ClientGraph graph; INamedGraph ng; if (UriGenerator.isMetadataGraphUri(uri)) { // get the uri of the named graph that is associated with this metadata URI uri_ng = UriGenerator.stripEncapsulatedURI(Constants.NAMESPACES.METADATAGRAPH_PREFIX, uri); graph = client.getReplicaGraph(uri_ng, getNamedGraphInitializers()); // get the named graph object ng = graph.getMetadataGraph(); total += adds.getNamedGraph(uri).getStatements().size(); ng.add(adds.getNamedGraph(uri).getStatements()); // add the new statements to the metadata graph } else { graph = client.getReplicaGraph(uri, getNamedGraphInitializers()); ng = adds.getNamedGraph(uri); total += ng.getStatements().size(); graph.add(ng.getStatements()); } if (total > 20000) { client.commit(); client.begin(); } } client.commit(); client.updateRepository(); result = 0; } catch (UpdateServerException e) { context.writeError("Update failed due to validation error(s): "); for (List<AnzoException> list : e.getErrors()) { for (AnzoException ex : list) { if (ex.getErrorCode() == ExceptionConstants.VALIDATION.INVALID_TYPEDLITERAL_LABEL) { context.writeError("\t" + ex.getArgs()[0]); } else { context.writeError("unknown transaction error:" + ex.getMessage(false)); context.getConsoleWriter().printException(ex, context.getShowTrace()); } } } } finally { try { if (owns) client.close(); } catch (AnzoRuntimeException e) { log.error("Error closing connection", e); } } return result; } public void printHelp(IConsole consoleWriter) { String header = "Updates existing graphs in the repository, adding the statements from the adds option file and removing statements from the deletes option file."; String syntax = "anzo update [options] --add RDF-INPUT-FILE-OR-URI --remove RDF-INPUT-FILE-OR-URI"; String footer = "RDF format options are: " + CommandLineInterface.getRDFFormatOptionsString(); Options options = getOptions(); CommandLineInterface.appendGlobalOptions(options); consoleWriter.printHelp( syntax, header, options, footer); } }