/******************************************************************************* * 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.io.Reader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; 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.ontologies.openanzo.NamedGraph; 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.Statement; import org.openanzo.rdf.URI; import org.openanzo.rdf.utils.ReadWriteUtils; import org.openanzo.rdf.utils.UriGenerator; import org.openanzo.rdf.vocabulary.RDF; import org.openanzo.services.UpdateServerException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Base for commands that upload rdf from local files and streams. * * @author Joe Betz <jpbetz@cambridgesemantics.com> * */ abstract class RdfUploadCommand extends RdfIOCommand { private static final Logger log = LoggerFactory.getLogger(RdfUploadCommand.class); private static final Option NON_REVISIONED = new Option("nr", "non-revisioned", false, "When creating a graph, make it non-revisioned."); private static final Option BASE = new Option("b", "base", true, "Set the base URI of the input RDF file(s) or URI(s)"); protected static final Option GRAPH = new Option("g", "graph", true, "Named graph uri to use for rdf inputs that do not support named graph serialization"); protected static final Option INPUT_FORMAT = new Option("i", "input-format", true, "Override the default RDF format associated with RDF input(s)."); protected static final Option ENCODING = new Option("e", "encoding", true, "Override the default charset for uploading RDF files."); static { BASE.setArgName("URI"); GRAPH.setArgName("URI"); INPUT_FORMAT.setArgName("format"); } public Options getOptions() { Options options = new Options(); options.addOption(NON_REVISIONED); options.addOption(BASE); options.addOption(GRAPH); options.addOption(INPUT_FORMAT); options.addOption(ENCODING); options.addOption(VERBOSE); options.addOption(RECURSE); return options; } public int invoke(CommandLine cl, CommandContext context, AnzoClient client) throws AnzoException { return invoke(cl, context, client, true); } public int invoke(CommandLine cl, CommandContext context, AnzoClient client, boolean defaultToStdin) throws AnzoException { String[] args = cl.getArgs(); boolean nonRevisioned = isFlagSet(cl, NON_REVISIONED); RDFFormat overrideFormat = getFormatOption(cl, INPUT_FORMAT); String charsetName = getEncodingOption(cl, ENCODING); Collection<RdfInputArgument> inputs = getArgumentsAsStreams(cl, context, args, 0, args.length, overrideFormat, charsetName); URI defaultNamedGraphUri = getURIOption(cl, GRAPH, context); URI base = getURIOption(cl, BASE, context); if (args.length == 0 && defaultToStdin) { if (overrideFormat == null) { inputs.add(new RdfInputArgument(System.in, RDFFormat.forFileName("." + CommandLineInterface.DEFAULT_RDF_FORMAT), charsetName)); } else { inputs.add(new RdfInputArgument(System.in, overrideFormat, charsetName)); } } return update(cl, context, client, inputs, defaultNamedGraphUri, base, nonRevisioned); } /** * Performs the commit operation. * * Reads through the provided files, constructs diffs by computing the differences between the file and the server graphs and commits those diffs in a * transaction to the repository. * * @throws AnzoException */ protected int update(CommandLine cl, CommandContext context, AnzoClient client, Collection<RdfInputArgument> inputs, URI defaultNamedGraphUri, URI base, boolean nonRevisioned) throws AnzoException { IDataset store = new Dataset(); INamedGraph defaultNamedGraph = null; if (defaultNamedGraphUri == null && inputs.size() == 1) { defaultNamedGraphUri = inputs.iterator().next().getDefaultGraphURI(); } if (defaultNamedGraphUri != null) { store.addNamedGraph(defaultNamedGraphUri); defaultNamedGraph = store.getNamedGraph(defaultNamedGraphUri); } for (RdfInputArgument input : inputs) { try { Reader in = input.getReader(); RDFFormat fileFormat = input.getFormat(); URI inputBase = base; if (inputBase == null) { inputBase = input.getDefaultGraphURI(); } if (fileFormat == null) { throw new InvalidArgumentException(input.inputName + " is not a valid RDF format file type. Use a proper file type or STDIN."); } if (!fileFormat.supportsNamedGraphs()) { INamedGraph inputNamedGraph = defaultNamedGraph; if (inputNamedGraph == null) { URI uri = input.getDefaultGraphURI(); if (uri != null) { store.addNamedGraph(uri); inputNamedGraph = store.getNamedGraph(uri); } } if (defaultNamedGraphUri == null) { throw new InvalidArgumentException(GRAPH.getLongOpt() + " option must be set for format " + fileFormat + " since this format does not support named graphs"); } ReadWriteUtils.loadGraph(inputNamedGraph, in, fileFormat, ObjectUtils.toString(inputBase)); } else { ReadWriteUtils.loadQuadStore(store, in, fileFormat, ObjectUtils.toString(inputBase)); } } catch (AnzoException e) { context.writeError("Error loading RDF Input: " + input.inputName); throw e; } } return update(cl, context, client, store, base, nonRevisioned); } public abstract INamedGraphInitializer[] getNamedGraphInitializers(); public INamedGraphInitializer[] getNamedGraphInitializers(boolean nonRevisioned) { INamedGraphInitializer[] initializers = getNamedGraphInitializers(); if (nonRevisioned) { ArrayList<INamedGraphInitializer> list = new ArrayList<INamedGraphInitializer>(); list.addAll(Arrays.asList(initializers)); list.remove(AnzoClient.REVISIONED_NAMED_GRAPH); list.add(AnzoClient.NON_REVISIONED_NAMED_GRAPH); initializers = list.toArray(new INamedGraphInitializer[0]); } return initializers; } protected int update(CommandLine cl, CommandContext context, AnzoClient client, IDataset store, URI base, boolean nonRevisioned) throws AnzoException { int result = 1; boolean owns = false; try { owns = !client.isConnected(); if (owns) { client.connect(); printOnConnectionSuccess(context); } for (URI uri : store.getNamedGraphUris()) { client.begin(); 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); ClientGraph graph = client.getReplicaGraph(uri_ng, getNamedGraphInitializers(nonRevisioned)); // get the named graph object INamedGraph metaG = graph.getMetadataGraph(); for (Statement statement : metaG.getStatements()) { if (!hasReservedPredicate(statement)) metaG.remove(statement); } Collection<Statement> stmts = store.getNamedGraph(uri).getStatements(); metaG.add(stmts); } else { ClientGraph graph = client.getReplicaGraph(uri, getNamedGraphInitializers(nonRevisioned)); Collection<Statement> stmts = store.getNamedGraph(uri).getStatements(); graph.clear(); graph.add(stmts); } client.commit(); } client.updateRepository(); result = 0; } catch (UpdateServerException e) { context.writeError("Update failed due to validation error(s): "); for (List<AnzoException> list : e.getErrors()) { if (list != null) { 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; } /** * Returns true if the statement contains one of the metadata properties that cannot be modified. */ static boolean hasReservedPredicate(Statement statement) { boolean retval = false; URI uri = statement.getPredicate(); retval = (uri.equals(NamedGraph.lastModifiedByUserProperty) || uri.equals(NamedGraph.modifiedProperty) || uri.equals(NamedGraph.createdProperty) || uri.equals(NamedGraph.createdByProperty) || uri.equals(NamedGraph.uuidProperty) || uri.equals(NamedGraph.revisionProperty) || uri.equals(NamedGraph.datasourceProperty) || uri.equals(NamedGraph.persistedProperty) || uri.equals(NamedGraph.revisionedProperty) || uri.equals(NamedGraph.hasMetadataGraphProperty)); return retval || (uri.equals(RDF.TYPE) && statement.getObject().equals(NamedGraph.TYPE)); } }