You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jena.apache.org by an...@apache.org on 2016/01/05 13:46:07 UTC
[13/20] jena git commit: JENA-1108 : jena-cmds module
http://git-wip-us.apache.org/repos/asf/jena/blob/498b2264/jena-cmds/src/main/java/jena/cmd/CmdGeneral.java
----------------------------------------------------------------------
diff --git a/jena-cmds/src/main/java/jena/cmd/CmdGeneral.java b/jena-cmds/src/main/java/jena/cmd/CmdGeneral.java
new file mode 100644
index 0000000..fc04397
--- /dev/null
+++ b/jena-cmds/src/main/java/jena/cmd/CmdGeneral.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package jena.cmd;
+
+import java.io.PrintStream ;
+
+import org.apache.jena.atlas.io.IndentedWriter ;
+import jena.cmd.ArgModuleGeneral;
+import jena.cmd.CmdArgModule;
+import jena.cmd.ModGeneral;
+
+// Added usage + some common flags
+// This is the usual starting point for any sub
+
+public abstract class CmdGeneral extends CmdArgModule
+{
+ protected ModGeneral modGeneral = new ModGeneral(this::printHelp) ;
+ protected ModVersion modVersion = new ModVersion(true) ;
+
+ // Could be turned into a module but these are convenient as inherited flags
+
+ protected CmdGeneral(String[] argv)
+ {
+ super(argv) ;
+ addModule(modGeneral) ;
+ addModule(modVersion) ;
+ }
+
+ @Override
+ public void addModule(ArgModuleGeneral argModule)
+ {
+ super.addModule(argModule) ;
+ argModule.registerWith(this) ;
+ }
+
+ protected boolean isVerbose() { return modGeneral.verbose ; }
+ protected boolean isQuiet() { return modGeneral.quiet ; }
+ protected boolean isDebug() { return modGeneral.debug ; }
+ protected boolean help() { return modGeneral.help ; }
+
+ final public void printHelp()
+ {
+ usage() ;
+ throw new TerminationException(0) ;
+ }
+
+ @Override
+ protected void processModulesAndArgs()
+ {
+ if ( modVersion.getVersionFlag() )
+ modVersion.printVersionAndExit() ;
+ }
+
+ private Usage usage = new Usage() ;
+
+ protected String cmdName = null ;
+
+ protected abstract String getSummary() ;
+
+ public void usage() { usage(System.err) ; }
+
+ public void usage(PrintStream pStr)
+ {
+ IndentedWriter out = new IndentedWriter(pStr) ;
+ out.println(getSummary()) ;
+ usage.output(out) ;
+ }
+
+ public void add(ArgDecl argDecl, String argName, String msg)
+ {
+ add(argDecl) ;
+ getUsage().addUsage(argName, msg) ;
+ }
+
+ public Usage getUsage() { return usage ; }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/498b2264/jena-cmds/src/main/java/jena/cmd/CmdLineArgs.java
----------------------------------------------------------------------
diff --git a/jena-cmds/src/main/java/jena/cmd/CmdLineArgs.java b/jena-cmds/src/main/java/jena/cmd/CmdLineArgs.java
new file mode 100644
index 0000000..2ba515c
--- /dev/null
+++ b/jena-cmds/src/main/java/jena/cmd/CmdLineArgs.java
@@ -0,0 +1,413 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package jena.cmd;
+
+import static java.nio.file.Files.readAllBytes;
+
+import java.io.IOException;
+import java.nio.file.Paths;
+import java.util.ArrayList ;
+import java.util.Arrays ;
+import java.util.Collections ;
+import java.util.HashMap ;
+import java.util.Iterator ;
+import java.util.List ;
+import java.util.Map ;
+
+import org.apache.jena.atlas.logging.Log ;
+
+/**
+ * Command line, using the common named/positional arguments paradigm
+ * (also called options/arguments).
+ */
+public class CmdLineArgs extends CommandLineBase {
+ public CmdLineArgs(String[] args) {
+ super(args) ;
+ }
+
+ private boolean processedArgs = false ;
+ protected Map<String, ArgDecl> argMap = new HashMap<>() ; // Map from string name to ArgDecl
+ protected Map<String, Arg> args = new HashMap<>() ; // Name to Arg
+ protected List<String> positionals = new ArrayList<>() ; // Positional arguments as strings.
+
+ public void process() throws IllegalArgumentException
+ {
+ processedArgs = true ;
+ apply(new ArgProcessor()) ;
+ }
+
+ // ---- Setting the ArgDecls
+
+ /** Add an argument to those to be accepted on the command line.
+ * @param argName Name
+ * @param hasValue True if the command takes a (string) value
+ * @return The CommandLine processor object
+ */
+
+ public CmdLineArgs add(String argName, boolean hasValue) {
+ return add(new ArgDecl(hasValue, argName)) ;
+ }
+
+ /** Add an argument to those to be accepted on the command line.
+ * Argument order reflects ArgDecl.
+ * @param hasValue True if the command takes a (string) value
+ * @param argName Name
+ * @return The CommandLine processor object
+ */
+
+ public CmdLineArgs add(boolean hasValue, String argName) {
+ return add(new ArgDecl(hasValue, argName)) ;
+ }
+
+ /** Add an argument object
+ * @param arg Argument to add
+ * @return The CommandLine processor object
+ */
+
+ public CmdLineArgs add(ArgDecl arg) {
+ for (Iterator<String> iter = arg.names(); iter.hasNext();) {
+ String name = iter.next() ;
+ if ( argMap.containsKey(name) )
+ Log.warn(this, "Argument '" + name + "' already added") ;
+ argMap.put(name, arg) ;
+ }
+ return this ;
+ }
+
+ /**
+ * Add a positional parameter
+ * @param value
+ * @return this object
+ */
+ public CmdLineArgs addPositional(String value) {
+ positionals.add(value) ;
+ return this ;
+ }
+
+ /**
+ * Add a named argument which has no value.
+ * @param name
+ * @return this
+ */
+ public CmdLineArgs addArg(String name) {
+ return addArg(name, null) ;
+ }
+
+ /**
+ * Add a named argument/value pair
+ * @param name
+ * @param value
+ * @return this object
+ */
+ public CmdLineArgs addArg(String name, String value) {
+ if ( !args.containsKey(name) )
+ args.put(name, new Arg(name)) ;
+ Arg arg = args.get(name) ;
+ return addArgWorker(arg, value) ;
+ }
+
+ private CmdLineArgs addArgWorker(Arg arg, String value) {
+ ArgDecl argDecl = argMap.get(arg.getName()) ;
+
+ if ( !argDecl.takesValue() && value != null )
+ throw new IllegalArgumentException("No value for argument: " + arg.getName()) ;
+
+ if ( argDecl.takesValue() ) {
+ if ( value == null )
+ throw new IllegalArgumentException("No value for argument: " + arg.getName()) ;
+
+ arg.setValue(value) ;
+ arg.addValue(value) ;
+ }
+
+ return this ;
+ }
+
+ // ---- Indirection
+
+ static final String DefaultIndirectMarker = "@" ;
+
+ public boolean matchesIndirect(String s) { return matchesIndirect(s, DefaultIndirectMarker) ; }
+ public boolean matchesIndirect(String s, String marker) { return s.startsWith(marker) ; }
+
+ public String indirect(String s) { return indirect(s, DefaultIndirectMarker) ; }
+
+ public String indirect(String s, String marker) {
+ if ( !matchesIndirect(s, marker) )
+ return s ;
+ s = s.substring(marker.length()) ;
+ try {
+ return new String(readAllBytes(Paths.get(s)));
+ } catch (IOException e) {
+ throw new CmdException("Could not read from: " + s, e);
+ }
+ }
+
+ // ---- Argument access
+
+ /** Test whether an argument was seen. */
+
+ public boolean contains(ArgDecl argDecl) { return getArg(argDecl) != null ; }
+
+ /** Test whether an argument was seen. */
+
+ public boolean contains(String s) { return getArg(s) != null ; }
+
+ /** Test whether an argument was seen more than once */
+ public boolean containsMultiple(String s) { return getValues(s).size() > 1 ; }
+
+ /** Test whether an argument was seen more than once */
+ public boolean containsMultiple(ArgDecl argDecl) { return getValues(argDecl).size() > 1 ; }
+
+ public boolean hasArgs() { return args.size() > 0 ; }
+
+ /** Test whether the command line had a particular argument
+ *
+ * @param argName
+ * @return this object
+ */
+ public boolean hasArg(String argName) { return getArg(argName) != null ; }
+
+ /** Test whether the command line had a particular argument
+ *
+ * @param argDecl
+ * @return true or false
+ */
+
+ public boolean hasArg(ArgDecl argDecl) { return getArg(argDecl) != null ; }
+
+
+ /** Get the argument associated with the argument declaration.
+ * Actually returns the LAST one seen
+ * @param argDecl Argument declaration to find
+ * @return Last argument that matched.
+ */
+
+ public Arg getArg(ArgDecl argDecl) {
+ Arg arg = null ;
+ for ( Arg a : args.values() )
+ {
+ if ( argDecl.matches( a ) )
+ {
+ arg = a;
+ }
+ }
+ return arg ;
+ }
+
+ /** Get the argument associated with the argument name.
+ * Actually returns the LAST one seen
+ * @param argName Argument name
+ * @return Last argument that matched.
+ */
+ public Arg getArg(String argName) {
+ argName = ArgDecl.canonicalForm(argName) ;
+ return args.get(argName) ;
+ }
+
+ /**
+ * Returns the value (a string) for an argument with a value -
+ * returns null for no argument and no value.
+ * @param argDecl
+ * @return String
+ */
+ public String getValue(ArgDecl argDecl) {
+ Arg arg = getArg(argDecl) ;
+ if ( arg == null )
+ return null ;
+ if ( arg.hasValue() )
+ return arg.getValue() ;
+ return null ;
+ }
+
+ /**
+ * Returns the value (a string) for an argument with a value -
+ * returns null for no argument and no value.
+ * @param argName
+ * @return String
+ */
+ public String getValue(String argName) {
+ Arg arg = getArg(argName) ;
+ if ( arg == null )
+ return null ;
+ return arg.getValue() ;
+ }
+
+ /** Is the value something that looks like "true" or "yes"? */
+ public boolean hasValueOfTrue(ArgDecl argDecl) {
+ String x = getValue(argDecl) ;
+ if ( x == null )
+ return false ;
+ if ( x.equalsIgnoreCase("true") || x.equalsIgnoreCase("t") ||
+ x.equalsIgnoreCase("yes") || x.equalsIgnoreCase("y") )
+ return true ;
+ return false ;
+ }
+
+ /** Is the value something that looks like "false" or "no"? */
+ public boolean hasValueOfFalse(ArgDecl argDecl) {
+ String x = getValue(argDecl) ;
+ if ( x == null )
+ return false ;
+ if ( x.equalsIgnoreCase("false") || x.equalsIgnoreCase("f") ||
+ x.equalsIgnoreCase("no") || x.equalsIgnoreCase("n") )
+ return true ;
+ return false ;
+ }
+
+ /**
+ * Returns all the values (0 or more strings) for an argument.
+ * @param argDecl
+ * @return List
+ */
+ public List<String> getValues(ArgDecl argDecl) {
+ Arg arg = getArg(argDecl) ;
+ if ( arg == null )
+ return new ArrayList<>() ;
+ return arg.getValues() ;
+ }
+
+ /**
+ * Returns all the values (0 or more strings) for an argument.
+ * @param argName
+ * @return List
+ */
+ public List<String> getValues(String argName) {
+ Arg arg = getArg(argName) ;
+ if ( arg == null )
+ return new ArrayList<>() ;
+ return arg.getValues() ;
+ }
+
+ // ---- Positional
+ /** Get the i'th positional argument (indexed from 0)*/
+ public String getPositionalArg(int i) {
+ return positionals.get(i) ;
+ }
+
+ /** Return the number of positional arguments */
+ public int getNumPositional() {
+ return positionals.size() ;
+ }
+
+ public boolean hasPositional() {
+ return positionals.size() > 0 ;
+ }
+
+ public List<String> getPositional() {
+ return positionals ;
+ }
+
+ /** Return the positional arguments or "-" to indicate stdin */
+ public List<String> getPositionalOrStdin() {
+ if ( !positionals.isEmpty() )
+ return Collections.unmodifiableList(positionals) ;
+ List<String> x = Arrays.asList("-") ;
+ return Collections.unmodifiableList(x) ;
+ }
+
+ // ----
+
+ /**
+ * Handle an unrecognised argument; default is to throw an exception
+ * @param argStr The string image of the unrecognised argument
+ */
+ protected void handleUnrecognizedArg( String argStr ) {
+ throw new CmdException("Unknown argument: "+argStr) ;
+ }
+
+ @Override
+ public String toString() {
+ if ( !processedArgs )
+ return super.toString() ;
+ String str = "" ;
+ String sep = "" ;
+ for ( String k : args.keySet() )
+ {
+ Arg a = args.get( k );
+ str = str + sep + a;
+ sep = " ";
+ }
+ sep = " -- " ;
+ for ( String v : positionals )
+ {
+ str = str + sep + v;
+ sep = " ";
+ }
+ return str ;
+ }
+
+ // ---- Process arguments after low level parsing and after ArgDecls added.
+ class ArgProcessor implements ArgProc {
+ boolean nextArgProcessed = false ;
+ boolean positionalArgsStarted = false ;
+
+ @Override
+ public void startArgs() {
+ nextArgProcessed = false ;
+ positionalArgsStarted = false ;
+ }
+
+ @Override
+ public void finishArgs() {}
+
+ @Override
+ public void arg(String argStr, int i) {
+ if ( nextArgProcessed ) {
+ nextArgProcessed = false ;
+ return ;
+ }
+
+ if ( positionalArgsStarted ) {
+ addPositional(argStr) ;
+ return ;
+ }
+
+ if ( argStr.equals("-") || argStr.equals("--") ) {
+ positionalArgsStarted = true ;
+ return ;
+ }
+
+ if ( !argStr.startsWith("-") ) {
+ // End of flags, start of positional arguments
+ positionalArgsStarted = true ;
+ addPositional(argStr) ;
+ return ;
+ }
+
+ argStr = ArgDecl.canonicalForm(argStr) ;
+ if ( !argMap.containsKey(argStr) ) {
+ handleUnrecognizedArg(argStr) ;
+ return ;
+ }
+
+ // Recognized flag
+ ArgDecl argDecl = argMap.get(argStr) ;
+
+ if ( argDecl.takesValue() ) {
+ String val = getArg(i + 1) ;
+ // Use first name as the canonical one.
+ String x = argDecl.getKeyName() ;
+ addArg(x, val) ;
+ nextArgProcessed = true ;
+ } else
+ addArg(argStr) ;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/498b2264/jena-cmds/src/main/java/jena/cmd/CmdMain.java
----------------------------------------------------------------------
diff --git a/jena-cmds/src/main/java/jena/cmd/CmdMain.java b/jena-cmds/src/main/java/jena/cmd/CmdMain.java
new file mode 100644
index 0000000..3caca21
--- /dev/null
+++ b/jena-cmds/src/main/java/jena/cmd/CmdMain.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package jena.cmd;
+
+import org.apache.jena.atlas.logging.LogCtl ;
+
+/** Adds main()-like methods
+ *
+ * Usage:
+ * new YourCommand(args).mainAndExit()
+ * which never returns and routes thing to System.exit.
+ * or call
+ * new YourCommand(args).mainMethod()
+ * which should not call System.exit anywhere */
+
+public abstract class CmdMain extends CmdLineArgs
+{
+ // Do this very early so it happens before anything else
+ // gets a chance to create a logger.
+ static { LogCtl.setCmdLogging() ; }
+
+ public CmdMain(String[] args)
+ {
+ super(args) ;
+ }
+
+ /** Run command - exit on failure */
+ public void mainRun()
+ { mainRun(false, true) ; }
+
+ /** Run command - choose whether to exit on failure */
+ public void mainRun(boolean exitOnFailure)
+ { mainRun(exitOnFailure, true) ; }
+
+ /** Run command - exit on success or failure */
+ public void mainAndExit()
+ { mainRun(true, true) ; }
+
+ /** Run command */
+ public int mainRun(boolean exitOnSuccess, boolean exitOnFailure)
+ {
+ try { mainMethod() ; }
+ catch (TerminationException ex) { System.exit(ex.getCode()) ; }
+ catch (IllegalArgumentException ex)
+ {
+ ex.printStackTrace(System.err) ;
+ //System.err.println(ex.getMessage()) ;
+ if ( exitOnFailure ) System.exit(1) ;
+ return 1 ;
+ }
+ catch (CmdException ex)
+ {
+ if ( ex.getMessage() != null && ex.getMessage().length() > 0 )
+ System.err.println(ex.getMessage()) ;
+ //ex.printStackTrace() ;
+
+ if ( ex.getCause() != null )
+ ex.getCause().printStackTrace(System.err) ;
+
+ if ( exitOnFailure ) System.exit(1) ;
+ return 1 ;
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace(System.err) ;
+ if ( exitOnFailure ) System.exit(2) ;
+ return 2 ;
+ }
+ if ( exitOnSuccess )
+ System.exit(0) ;
+ return 0 ;
+ }
+
+ protected final void mainMethod()
+ {
+ process() ;
+ exec() ;
+ }
+
+ protected abstract void exec() ;
+
+ protected abstract String getCommandName() ;
+
+ public void cmdError(String msg) { cmdError(msg, true) ;}
+
+ public void cmdError(String msg, boolean exit)
+ {
+ System.err.println(msg) ;
+ if ( exit )
+ throw new TerminationException(5) ;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/498b2264/jena-cmds/src/main/java/jena/cmd/CommandLineBase.java
----------------------------------------------------------------------
diff --git a/jena-cmds/src/main/java/jena/cmd/CommandLineBase.java b/jena-cmds/src/main/java/jena/cmd/CommandLineBase.java
new file mode 100644
index 0000000..def345e
--- /dev/null
+++ b/jena-cmds/src/main/java/jena/cmd/CommandLineBase.java
@@ -0,0 +1,136 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package jena.cmd;
+
+import static java.util.stream.IntStream.range;
+
+import java.util.ArrayList ;
+import java.util.List ;
+
+/**
+ * Incoming String[] to a list of argument/values + items.
+ */
+
+
+public class CommandLineBase {
+ private List<String> argList = new ArrayList<>() ;
+ boolean splitTerms = true ;
+
+ public CommandLineBase(String[] args) {
+ setArgs(args) ;
+ }
+
+ public CommandLineBase() {}
+
+ public void setArgs(String[] argv)
+ { argList = processArgv(argv) ; }
+
+ protected List<String> getArgList() { return argList ; }
+
+ protected String getArg(int i) {
+ if ( i < 0 || i >= argList.size() )
+ return null ;
+ return argList.get(i) ;
+ }
+
+ protected void apply(ArgProc a) {
+ a.startArgs() ;
+ range(0, argList.size()).forEach(i -> a.arg(argList.get(i), i));
+ a.finishArgs() ;
+ }
+
+ /** Process String[] to a list of tokens.
+ * All "=" and ":" terms are split.
+ * Make -flag/--flag consistent.
+ * @param argv The words of the command line.
+ */
+ private List<String> processArgv(String[] argv) {
+ // Combine with processedArgs/process?
+ List<String> argList = new ArrayList<>() ;
+
+ boolean positional = false ;
+
+ for ( String anArgv : argv )
+ {
+ String argStr = anArgv;
+
+ if ( positional || !argStr.startsWith( "-" ) )
+ {
+ argList.add( argStr );
+ continue;
+ }
+
+ if ( argStr.equals( "-" ) || argStr.equals( "--" ) )
+ {
+ positional = true;
+ argList.add( "--" );
+ continue;
+ }
+
+ // Starts with a "-"
+ // Do not canonicalize positional arguments.
+ if ( !argStr.startsWith( "--" ) )
+ {
+ argStr = "-" + argStr;
+ }
+
+ if ( !splitTerms )
+ {
+ argList.add( argStr );
+ continue;
+ }
+
+ // If the flag has a "=" or :, it is long form --arg=value.
+ // Split and insert the arg
+ int j1 = argStr.indexOf( '=' );
+ int j2 = argStr.indexOf( ':' );
+ int j = -1;
+
+ if ( j1 > 0 && j2 > 0 )
+ {
+ j = Math.min( j1, j2 );
+ }
+ else
+ {
+ if ( j1 > 0 )
+ {
+ j = j1;
+ }
+ if ( j2 > 0 )
+ {
+ j = j2;
+ }
+ }
+
+ if ( j < 0 )
+ {
+ argList.add( argStr );
+ continue;
+ }
+
+ // Split it.
+ String argStr1 = argStr.substring( 0, j );
+ String argStr2 = argStr.substring( j + 1 );
+
+ argList.add( argStr1 );
+ argList.add( argStr2 );
+ }
+ return argList ;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/498b2264/jena-cmds/src/main/java/jena/cmd/ModBase.java
----------------------------------------------------------------------
diff --git a/jena-cmds/src/main/java/jena/cmd/ModBase.java b/jena-cmds/src/main/java/jena/cmd/ModBase.java
new file mode 100644
index 0000000..3899608
--- /dev/null
+++ b/jena-cmds/src/main/java/jena/cmd/ModBase.java
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package jena.cmd;
+
+public abstract class ModBase implements ArgModuleGeneral
+{
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/498b2264/jena-cmds/src/main/java/jena/cmd/ModGeneral.java
----------------------------------------------------------------------
diff --git a/jena-cmds/src/main/java/jena/cmd/ModGeneral.java b/jena-cmds/src/main/java/jena/cmd/ModGeneral.java
new file mode 100644
index 0000000..25e1dac
--- /dev/null
+++ b/jena-cmds/src/main/java/jena/cmd/ModGeneral.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package jena.cmd;
+
+public class ModGeneral extends ModBase
+{
+ private Runnable helpFunction = null ;
+
+ public ModGeneral(Runnable helpFunction) { this.helpFunction = helpFunction ; }
+
+ // Could be turned into a module but these are convenient as inherited flags
+ private final ArgDecl argDeclHelp = new ArgDecl(false, "help", "h");
+ private final ArgDecl argDeclVerbose = new ArgDecl(false, "v", "verbose");
+ private final ArgDecl argDeclQuiet = new ArgDecl(false, "q", "quiet");
+ private final ArgDecl argDeclDebug = new ArgDecl(false, "debug");
+
+ protected boolean verbose = false ;
+ protected boolean quiet = false ;
+ public boolean debug = false ;
+ protected boolean help = false ;
+
+ @Override
+ public void registerWith(CmdGeneral cmdLine)
+ {
+ cmdLine.getUsage().startCategory("General") ;
+ cmdLine.add(argDeclVerbose, "-v --verbose", "Verbose") ;
+ cmdLine.add(argDeclQuiet, "-q --quiet", "Run with minimal output") ;
+ cmdLine.add(argDeclDebug, "--debug", "Output information for debugging") ;
+ cmdLine.add(argDeclHelp, "--help", null) ;
+ }
+
+ @Override
+ public void processArgs(CmdArgModule cmdLine)
+ {
+ verbose = cmdLine.contains(argDeclVerbose) || cmdLine.contains(argDeclDebug) ;
+ quiet = cmdLine.contains(argDeclQuiet) ;
+ help = cmdLine.contains(argDeclHelp) ;
+ if ( help )
+ helpFunction.run() ;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/498b2264/jena-cmds/src/main/java/jena/cmd/ModVersion.java
----------------------------------------------------------------------
diff --git a/jena-cmds/src/main/java/jena/cmd/ModVersion.java b/jena-cmds/src/main/java/jena/cmd/ModVersion.java
new file mode 100644
index 0000000..3b47fb5
--- /dev/null
+++ b/jena-cmds/src/main/java/jena/cmd/ModVersion.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package jena.cmd;
+
+import org.apache.jena.atlas.io.IndentedWriter;
+import org.apache.jena.atlas.lib.Version ;
+
+public class ModVersion extends ModBase
+{
+ protected final ArgDecl versionDecl = new ArgDecl(ArgDecl.NoValue, "version") ;
+ protected boolean version = false ;
+ protected boolean printAndExit = false ;
+
+ private Version versionMgr = new Version() ;
+
+ public ModVersion(boolean printAndExit)
+ {
+ this.printAndExit = printAndExit ;
+ }
+
+ public void addClass(Class<?> c) { versionMgr.addClass(c) ; }
+
+ @Override
+ public void registerWith(CmdGeneral cmdLine)
+ {
+ cmdLine.add(versionDecl, "--version", "Version information") ;
+ }
+
+ @Override
+ public void processArgs(CmdArgModule cmdLine)
+ {
+ if ( cmdLine.contains(versionDecl) )
+ version = true ;
+ // The --version flag causes us to print and exit.
+ if ( version && printAndExit )
+ printVersionAndExit() ;
+ }
+
+ public boolean getVersionFlag() { return version ; }
+
+ public void printVersion()
+ {
+ versionMgr.print(IndentedWriter.stdout);
+ }
+
+ public void printVersionAndExit()
+ {
+ printVersion() ;
+ System.exit(0) ;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/498b2264/jena-cmds/src/main/java/jena/cmd/TerminationException.java
----------------------------------------------------------------------
diff --git a/jena-cmds/src/main/java/jena/cmd/TerminationException.java b/jena-cmds/src/main/java/jena/cmd/TerminationException.java
new file mode 100644
index 0000000..090fa48
--- /dev/null
+++ b/jena-cmds/src/main/java/jena/cmd/TerminationException.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package jena.cmd;
+
+
+/** Exception used to indicate that the command should end now.
+ * Use instead of System.exit so that a wrapper can catch (else a command server
+ * wil exit wrongly). */
+
+public class TerminationException extends CmdException
+{
+ public int returnCode ;
+ public TerminationException(int rc) { super() ; this.returnCode = rc ; }
+ public int getCode() { return returnCode ; }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/498b2264/jena-cmds/src/main/java/jena/cmd/Usage.java
----------------------------------------------------------------------
diff --git a/jena-cmds/src/main/java/jena/cmd/Usage.java b/jena-cmds/src/main/java/jena/cmd/Usage.java
new file mode 100644
index 0000000..1331eb9
--- /dev/null
+++ b/jena-cmds/src/main/java/jena/cmd/Usage.java
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package jena.cmd;
+
+import java.io.PrintStream ;
+import java.util.ArrayList ;
+import java.util.Collections ;
+import java.util.List ;
+
+import org.apache.jena.atlas.io.IndentedWriter ;
+
+public class Usage
+{
+ class Category
+ {
+ String desc ;
+ List<Entry> entries = new ArrayList<>() ;
+ Category(String desc) { this.desc = desc ; }
+ }
+
+ class Entry
+ { String arg; String msg ;
+ Entry(String arg, String msg) { this.arg = arg ; this.msg = msg ; }
+ }
+
+ List<Category> categories = new ArrayList<>() ;
+ public Usage()
+ {
+ // Start with an unnamed category
+ startCategory(null) ;
+ }
+
+ public void startCategory(String desc)
+ {
+ categories.add(new Category(desc)) ;
+ }
+
+ public void addUsage(String argName, String msg)
+ {
+ current().entries.add(new Entry(argName, msg)) ;
+ }
+
+
+ public void output(PrintStream out)
+ {
+ output(new IndentedWriter(out)) ;
+ }
+
+ public void output(IndentedWriter out)
+ {
+ int INDENT1 = 2 ;
+ int INDENT2 = 4 ;
+ out.incIndent(INDENT1) ;
+
+ List<Category> categories2 = new ArrayList<>(categories) ;
+ Collections.reverse(categories2) ;
+
+ for ( Category c : categories2 )
+ {
+ if ( c.desc != null )
+ {
+ out.println( c.desc );
+ }
+ out.incIndent( INDENT2 );
+ for ( final Entry e : c.entries )
+ {
+ out.print( e.arg );
+ if ( e.msg != null )
+ {
+ out.pad( 20 );
+ out.print( " " );
+ out.print( e.msg );
+ }
+ out.println();
+ }
+ out.decIndent( INDENT2 );
+ }
+ out.decIndent(INDENT1) ;
+ out.flush() ;
+ }
+
+ private Category current()
+ {
+ return categories.get(categories.size()-1) ;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/498b2264/jena-cmds/src/main/java/jena/cmd/package-info.java
----------------------------------------------------------------------
diff --git a/jena-cmds/src/main/java/jena/cmd/package-info.java b/jena-cmds/src/main/java/jena/cmd/package-info.java
new file mode 100644
index 0000000..26000b5
--- /dev/null
+++ b/jena-cmds/src/main/java/jena/cmd/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * Contains framework components for CLI and command execution.
+ *
+ * @author ajs6f
+ */
+package jena.cmd;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/jena/blob/498b2264/jena-cmds/src/main/java/jena/package.html
----------------------------------------------------------------------
diff --git a/jena-cmds/src/main/java/jena/package.html b/jena-cmds/src/main/java/jena/package.html
new file mode 100644
index 0000000..b0db285
--- /dev/null
+++ b/jena-cmds/src/main/java/jena/package.html
@@ -0,0 +1,34 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+</head>
+ <body>
+<p>A package for some Jena command-line programs, including
+<ul>
+<li>copying RDF data with representation conversion, eg XML to N3
+<li>comparing two RDF files for isomorphism (extended equality)
+<li>an interface to the ARP RDF parser
+<li>access to the RDQL interpreter
+<li>a schema-to-Java generator
+</ul>
+</p>
+</body>
+</html>
http://git-wip-us.apache.org/repos/asf/jena/blob/498b2264/jena-cmds/src/main/java/jena/query.java
----------------------------------------------------------------------
diff --git a/jena-cmds/src/main/java/jena/query.java b/jena-cmds/src/main/java/jena/query.java
new file mode 100644
index 0000000..a04e02f
--- /dev/null
+++ b/jena-cmds/src/main/java/jena/query.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package jena;
+
+public class query {
+ // Call-through to arq command line application
+ public static void main(String... args) {
+ arq.query.main(args);
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/498b2264/jena-cmds/src/main/java/jena/rdfcat.java
----------------------------------------------------------------------
diff --git a/jena-cmds/src/main/java/jena/rdfcat.java b/jena-cmds/src/main/java/jena/rdfcat.java
new file mode 100644
index 0000000..c292d45
--- /dev/null
+++ b/jena-cmds/src/main/java/jena/rdfcat.java
@@ -0,0 +1,1150 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Package
+///////////////
+package jena;
+
+
+// Imports
+///////////////
+
+import static org.apache.jena.atlas.logging.LogCtl.setCmdLogging;
+
+import java.io.OutputStream ;
+import java.util.* ;
+import java.util.function.BiConsumer;
+
+import org.apache.jena.rdf.model.* ;
+import org.apache.jena.rdf.model.impl.RDFWriterFImpl ;
+import org.apache.jena.shared.NoWriterForLangException ;
+import org.apache.jena.system.JenaSystem ;
+import org.apache.jena.util.FileManager ;
+import org.apache.jena.util.FileUtils ;
+import org.apache.jena.vocabulary.OWL ;
+import org.apache.jena.vocabulary.RDFS ;
+
+
+/**
+ * <p>
+ * An RDF utility that takes its name from the Unix utility <em>cat</em>, and
+ * is used to generate serialisations of the contents of zero or more
+ * input model serialisations. <strong>Note</strong> In a change from previous
+ * versions, but to ensure compatability with standard argument handling
+ * practice, the input language options are <em>no longer sticky</em>. In
+ * previous versions, <code>rdfcat -n A B C</code> would ensure that A, B
+ * and C were all read as N3. From Jena 2.5.2 onwards, this requires:
+ * <code>rdfcat -n A -n B -n C</code>, or the use of the <code>-in</code>
+ * option.
+ * </p>
+ * <p>Synopsis:</p>
+ * <pre>
+ * java jena.rdfcat (options|input)*
+ * where options are:
+ * -out N3 (aliases n, n3, ttl)
+ * -out N-TRIPLE (aliases t, ntriple)
+ * -out RDF/XML (aliases x, rdf, xml, rdfxml)
+ * -out RDF/XML-ABBREV (default)
+ * -in N3 (aliases n, n3, ttl)
+ * -in N-TRIPLE (aliases t, ntriple)
+ * -in RDF/XML (aliases x, rdf, xml, rdfxml)
+ * -include
+ * -noinclude (default)
+ *
+ * input is one of:
+ * -n <filename> for n3 input (aliases -n3, -N3, -ttl)
+ * -x <filename> for rdf/xml input (aliases -rdf, -xml, -rdfxml)
+ * -t <filename> for n-triple input (aliases -ntriple)
+ * or just a URL, a filename, or - for the standard input.
+ * </pre>
+ * <p>
+ * The default
+ * input language is RDF/XML, but the reader will try to guess the
+ * input language based on the file extension (e.g. N3 for file with a .n3
+ * file extension.
+ * </p>
+ * <p>The input language options set the language for the following file
+ * name only. So in the following example, input
+ * A is read as N3, inputs B, C and D are read as RDF/XML,
+ * while stdin is read as N-TRIPLE:</p>
+ * <pre>
+ * java jena.rdfcat -n A B C -t - -x D
+ * </pre>
+ * <p>To change the default input language for all files that do
+ * not have a specified language encoding, use the <code>-in</code> option.
+ * </p>
+ * <p>If the <code>include</code> option is set, the input files are scanned
+ * for <code>rdfs:seeAlso</code> and <code>owl:imports</code> statements, and
+ * the objects of these statements are read as well. By default, <code>include</code>
+ * is off. If <code>include</code> is turned on, the normal behaviour is for
+ * the including statements (e.g <code>owl:imports</code> to be filtered
+ * from the output models. To leave such statements in place, use the <code>--nofilter</code>
+ * option.</p>
+ * <p>rdfcat uses the Jena {@link org.apache.jena.util.FileManager FileManager}
+ * to resolve input URI's to locations. This allows, for example, <code>http:</code>
+ * URI's to be re-directed to local <code>file:</code> locations, to avoid a
+ * network transaction.</p>
+ * <p>Examples:</p>
+ * <pre>
+ * Join two RDF/XML files together into a single model in RDF/XML-ABBREV:
+ * java jena.rdfcat in1 in2 > out.rdf
+ *
+ * Convert a single RDF/XML file to N3:
+ * java jena.rdfcat in1 -out N3 > out.n3
+ *
+ * Join two owl files one N3, one XML, and their imports, into a single NTRIPLE file:
+ * java jena.rdfcat -out NTRIPLE -include in1.owl -n in2.owl > out.ntriple
+ *
+ * Concatenate two N3-serving http URL's as N-TRIPLE
+ * java jena.rdfcat -in N3 -out N-TRIPLE http://example.com/a http://example.com/b
+ * </pre>
+ * <p>Note that, in a difference from the Unix utility <code>cat</code>, the order
+ * of input statements is not preserved. The output document is a merge of the
+ * input documents, and does not preserve any statement ordering from the input
+ * serialisations. Also, duplicate triples will be suppressed.</p>
+ */
+@Deprecated
+public class rdfcat
+{
+ static { setCmdLogging("jena-log4j.properties") ; }
+
+ /** The merged model containing all of the inputs */
+ protected Model m_model = ModelFactory.createDefaultModel();
+
+ /** The output format to write to, defaults to RDF/XML-ABBREV */
+ protected String m_outputFormat = "RDF/XML-ABBREV";
+
+ /** The input format we're expecting for the next URL to be read - defaults to RDF/XML */
+ protected String m_inputFormat = "RDF/XML";
+
+ /** Flag to indicate whether we include owl:imports and rdfs:seeAlso */
+ protected boolean m_include = false;
+
+ /** List of URL's that have been loaded already, occurs check */
+ protected Set<String> m_seen = new HashSet<>();
+
+ /** Flag to control whether import/include statements are filtered from merged models */
+ protected boolean m_removeIncludeStatements = true;
+
+ /** Action queue */
+ protected List<RCAction> m_actionQ = new ArrayList<>();
+
+ // Allow testing to run silent.
+ public static boolean suppressDeprecationBanner = false ;
+
+ // Constants
+ //////////////////////////////////
+
+ /** Argument setting expected input language to N3 */
+ public final ArgDecl IN_N3 = new ArgDecl( true, "n", "n3", "ttl", "N3",
+ (arg,val) -> m_actionQ.add( new ReadAction( val, "N3") ) );
+
+ /** Argument setting expected input language to RDF/XML */
+ public final ArgDecl IN_RDF_XML = new ArgDecl( true, "x", "xml", "rdfxml", "rdf",
+ (arg,val) -> m_actionQ.add( new ReadAction( val, "RDF/XML") ) );
+
+ /** Argument setting expected input language to NTRIPLE */
+ public final ArgDecl IN_NTRIPLE = new ArgDecl( true, "t", "ntriples", "ntriple", "n-triple", "n-triples",
+ (arg,val) -> m_actionQ.add( new ReadAction( val, "N-TRIPLE" ) ) );
+
+ /** Argument to set the output language */
+ public final ArgDecl OUT_LANG = new ArgDecl( true, "out", (arg,val) -> setOutput( val ) );
+
+ /** Argument to set the default input language */
+ public final ArgDecl IN_LANG = new ArgDecl( true, "in", (arg,val) -> expectInput( val ) );
+
+ /** Argument to turn include processing on */
+ public final ArgDecl INCLUDE = new ArgDecl( false, "include", (arg,val) -> setInclude( true ) );
+
+ /** Argument to turn include processing off */
+ public final ArgDecl NOINCLUDE = new ArgDecl( false, "noinclude", (arg,val) -> setInclude( false ) );
+
+ /** Argument to leave import/seeAlso statements in place in flattened models */
+ public final ArgDecl NOFILTER = new ArgDecl( false, "nofilter", (arg,val) -> setRemoveIncludeStatements( false ) );
+
+ /** Argument to show usage */
+ public final ArgDecl HELP = new ArgDecl( false, "help", (arg,val) -> usage() );
+ public final ArgDecl USAGE = new ArgDecl( false, "usage", (arg,val) -> usage() );
+
+ // Instance variables
+ //////////////////////////////////
+
+ /** The command line processor that handles the arguments */
+ protected CommandLine m_cmdLine = new RCCommandLine().add( IN_N3 )
+ .add( IN_NTRIPLE )
+ .add( IN_RDF_XML )
+ .add( OUT_LANG )
+ .add( IN_LANG )
+ .add( INCLUDE )
+ .add( NOINCLUDE )
+ .add( NOFILTER )
+ .add( HELP )
+ .add( USAGE );
+
+ // Constructors
+ //////////////////////////////////
+
+ // External signature methods
+ //////////////////////////////////
+
+ public static void main( String... args ) {
+ new rdfcat().go( args );
+ }
+
+ // Internal implementation methods
+ //////////////////////////////////
+
+ /* main loop */
+ protected void go( String[] args ) {
+ JenaSystem.init();
+ if ( ! suppressDeprecationBanner ) {
+ System.err.println("------------------------------------------------------------------");
+ System.err.println(" DEPRECATED: Please use 'riot' instead.");
+ System.err.println(" http://jena.apache.org/documentation/io/#command-line-tools");
+ System.err.println("------------------------------------------------------------------");
+ System.err.println() ;
+ }
+
+ m_cmdLine.process( args );
+
+ // process any stored items
+ for (int i = 0; i < m_cmdLine.numItems(); i++) {
+ m_actionQ.add( new ReadAction( m_cmdLine.getItem( i ), getExpectedInput() ) );
+ }
+ for ( RCAction aM_actionQ : m_actionQ )
+ {
+ aM_actionQ.run( this );
+ }
+
+ // generate the output
+ m_model.write( getOutputStream(), m_outputFormat );
+ }
+
+ /** Set the input language of next and subsequent reads */
+ protected void expectInput( String lang ) {
+ m_inputFormat = lang;
+ }
+
+ /** Answer the currently expected input format */
+ protected String getExpectedInput() {
+ return m_inputFormat;
+ }
+
+ /** Set the language to write the output model in */
+ protected void setOutput( String lang ) {
+ m_outputFormat = getCheckedLanguage( lang );
+ }
+
+ /**
+ Answer the full, checked, language name expanded from <code>shortName</code>.
+ The shortName is expanded according to the table of abbreviations [below].
+ It is then checked against RDFWriterFImpl's writer table [this is hacky but
+ at the moment it's the most available interface] and the NoWriter exception
+ trapped and replaced by the original IllegalArgument exception.
+ */
+ public static String getCheckedLanguage( String shortLang )
+ {
+ String fullLang = unabbreviate.get( shortLang );
+ String tryLang = (fullLang == null ? shortLang : fullLang);
+ try { new RDFWriterFImpl().getWriter( tryLang ); }
+ catch (NoWriterForLangException e)
+ { throw new IllegalArgumentException( "'" + shortLang + "' is not recognised as a legal output format" ); }
+ return tryLang;
+ }
+
+ /**
+ Map from abbreviated names to full names.
+ */
+ public static Map<String,String> unabbreviate = makeUnabbreviateMap();
+
+ /**
+ Construct the canonical abbreviation map.
+ */
+ protected static Map<String,String> makeUnabbreviateMap()
+ {
+ Map<String,String> result = new HashMap<>();
+ result.put( "x", "RDF/XML" );
+ result.put( "rdf", "RDF/XML" );
+ result.put( "rdfxml", "RDF/XML" );
+ result.put( "xml", "RDF/XML" );
+ result.put( "n3", "N3" );
+ result.put( "n", "N3" );
+ result.put( "ttl", "N3" );
+ result.put( "ntriples", "N-TRIPLE" );
+ result.put( "ntriple", "N-TRIPLE" );
+ result.put( "t", "N-TRIPLE" );
+ result.put( "owl", "RDF/XML-ABBREV" );
+ result.put( "abbrev", "RDF/XML-ABBREV" );
+ return result;
+ }
+
+ /** Set the flag to include owl:imports and rdf:seeAlso files in the output, default off */
+ protected void setInclude( boolean incl ) {
+ m_include = incl;
+ }
+
+ /** Set the flag to leave owl:imports and rdfs:seeAlso statements in place, rather than filter them */
+ protected void setRemoveIncludeStatements( boolean f ) {
+ m_removeIncludeStatements = f;
+ }
+
+ /* Take the string as an input file or URI, and
+ * try to read using the current default input syntax.
+ */
+ protected void readInput( String inputName ) {
+ List<IncludeQueueEntry> queue = new ArrayList<>();
+ queue.add( new IncludeQueueEntry( inputName, null ) );
+
+ while (!queue.isEmpty()) {
+ IncludeQueueEntry entry = queue.remove( 0 );
+ String in = entry.m_includeURI;
+
+ if (!m_seen.contains( in )) {
+ m_seen.add( in );
+ Model inModel = ModelFactory.createDefaultModel();
+
+ // check for stdin
+ if (in.equals( "-" )) {
+ inModel.read( System.in, null, m_inputFormat );
+ }
+ else {
+ // lang from extension overrides default set on command line
+ String lang = FileUtils.guessLang( in, m_inputFormat );
+ FileManager.get().readModel( inModel, in, lang );
+ }
+
+ // check for anything more that we need to read
+ if (m_include) {
+ addIncludes( inModel, queue );
+ }
+
+ // merge the models
+ m_model.add( inModel );
+ m_model.setNsPrefixes( inModel );
+
+ // do we remove the include statement?
+ if (m_removeIncludeStatements && entry.m_includeStmt != null) {
+ m_model.remove( entry.m_includeStmt );
+ }
+ }
+ }
+ }
+
+ /** Return the stream to which the output is written, defaults to stdout */
+ protected OutputStream getOutputStream() {
+ return System.out;
+ }
+
+ /** Add any additional models to include given the rdfs:seeAlso and
+ * owl:imports statements in the given model
+ */
+ protected void addIncludes( Model inModel, List<IncludeQueueEntry> queue ) {
+ // first collect any rdfs:seeAlso statements
+ StmtIterator i = inModel.listStatements( null, RDFS.seeAlso, (RDFNode) null );
+ while (i.hasNext()) {
+ Statement s = i.nextStatement();
+ queue.add( new IncludeQueueEntry( getURL( s.getObject() ), s ) );
+ }
+
+ // then any owl:imports
+ i = inModel.listStatements( null, OWL.imports, (RDFNode) null );
+ while (i.hasNext()) {
+ Statement s = i.nextStatement();
+ queue.add( new IncludeQueueEntry( getURL( s.getResource() ), s ) );
+ }
+ }
+
+ protected void usage() {
+ System.err.println( "------------------------------------" );
+ System.err.println( "DEPRECATED: Please use riot instead." );
+ System.err.println( "------------------------------------\n" );
+ System.err.println( "Usage: java jena.rdfcat (option|input)*" );
+ System.err.println( "Concatenates the contents of zero or more input RDF documents." );
+ System.err.println( "Options: -out N3 | N-TRIPLE | RDF/XML | RDF/XML-ABBREV" );
+ System.err.println( " -n expect subsequent inputs in N3 syntax" );
+ System.err.println( " -x expect subsequent inputs in RDF/XML syntax" );
+ System.err.println( " -t expect subsequent inputs in N-TRIPLE syntax" );
+ System.err.println( " -[no]include include rdfs:seeAlso and owl:imports" );
+ System.err.println( "input can be filename, URL, or - for stdin" );
+ System.err.println( "Recognised aliases for -n are: -n3 -ttl or -N3" );
+ System.err.println( "Recognised aliases for -x are: -xml -rdf or -rdfxml" );
+ System.err.println( "Recognised aliases for -t are: -ntriple" );
+ System.err.println( "Output format aliases: x, xml or rdf for RDF/XML, n, n3 or ttl for N3, t or ntriple for N-TRIPLE" );
+ System.err.println( "See the Javadoc for jena.rdfcat for additional details." );
+
+
+ System.exit(0);
+ }
+
+ /** Answer a URL string from a resource or literal */
+ protected String getURL( RDFNode n ) {
+ return n.isLiteral() ? ((Literal) n).getLexicalForm() : ((Resource) n).getURI();
+ }
+
+ //==============================================================================
+ // Inner class definitions
+ //==============================================================================
+
+ /** Local extension to CommandLine to handle mixed arguments and values */
+ protected class RCCommandLine
+ extends CommandLine
+ {
+ /** Don't stop processing args on the first non-arg */
+ public boolean xendProcessing( String argStr ) {
+ return false;
+ }
+
+ /** Handle an unrecognised argument by assuming it's a URI to read */
+ @Override
+ public void handleUnrecognizedArg( String argStr ) {
+ if (argStr.equals("-") || !argStr.startsWith( "-" )) {
+ // queue this action for reading later
+ m_actionQ.add( new ReadAction( argStr, getExpectedInput() ) );
+ }
+ else {
+ System.err.println( "Unrecognised argument: " + argStr );
+ usage();
+ }
+ }
+
+ /** Hook to test whether this argument should be processed further
+ */
+ @Override
+ public boolean ignoreArgument( String argStr ) {
+ return !argStr.startsWith("-") || argStr.length() == 1;
+ }
+
+ /** Answer an iterator over the non-arg items from the command line */
+ public Iterator<String> getItems() {
+ return items.iterator();
+ }
+ }
+
+ /** Queue entry that contains both a URI to be included, and a statement that may be removed */
+ protected class IncludeQueueEntry
+ {
+ protected String m_includeURI;
+ protected Statement m_includeStmt;
+ protected IncludeQueueEntry( String includeURI, Statement includeStmt ) {
+ m_includeURI = includeURI;
+ m_includeStmt = includeStmt;
+ }
+ }
+
+ /** Simple action object for local processing queue */
+ protected interface RCAction {
+ public void run( rdfcat rc );
+ }
+
+ /** Action to set the output format */
+ protected class ReadAction
+ implements RCAction
+ {
+ private String m_lang;
+ private String m_uri;
+ protected ReadAction( String uri, String lang ) {
+ m_lang = lang;
+ m_uri = uri;
+ }
+
+ /** perform the action of reading a uri */
+ @Override
+ public void run( rdfcat rc ) {
+ String l = rc.getExpectedInput();
+ if (m_lang != null) {
+ // if an input lang was given, use that
+ rc.expectInput( m_lang );
+ }
+ rc.readInput( m_uri );
+
+ // put the lang back to default
+ rc.expectInput( l );
+ }
+ }
+
+ /**
+ * Command line argument processing based on a trigger model.
+ * An action is called whenever an argument is encountered. Example:
+ * <CODE>
+ * public static void main (String[] args)
+ * {
+ * CommandLine cl = new CommandLine() ;
+ * cl.add(false, "verbose")
+ * .add(true, "--file") ;
+ * cl.process(args) ;
+ *
+ * for ( Iterator iter = cl.args() ; iter.hasNext() ; )
+ * ...
+ * }
+ * </CODE>
+ * A gloabl hook is provided to inspect arguments just before the
+ * action. Tracing is enabled by setting this to a suitable function
+ * such as that provided by trace():
+ * <CODE>
+ * cl.setHook(cl.trace()) ;
+ * </CODE>
+ *
+ * <ul>
+ * <li>Neutral as to whether options have - or --</li>
+ * <li>Does not allow multiple single letter options to be concatenated.</li>
+ * <li>Options may be ended with - or --</li>
+ * <li>Arguments with values can use "="</li>
+ * </ul>
+ */
+
+
+ static class CommandLine
+ {
+ /* Extra processor called before the registered one when set.
+ * Used for tracing.
+ */
+ protected BiConsumer<String,String> argHook = null ;
+ protected String usage = null ;
+ protected Map<String, ArgDecl> argMap = new HashMap<>() ;
+ protected Map<String, Arg> args = new HashMap<>() ;
+ //protected boolean ignoreUnknown = false ;
+
+ // Rest of the items found on the command line
+ String indirectionMarker = "@" ;
+ protected boolean allowItemIndirect = false ; // Allow @ to mean contents of file
+ boolean ignoreIndirectionMarker = false ; // Allow comand line items to have leading @ but strip it.
+ protected List<String> items = new ArrayList<>() ;
+
+
+ /** Creates new CommandLine */
+ public CommandLine()
+ {
+ }
+
+ /** Set the global argument handler. Called on every valid argument.
+ * @param argHandler Handler
+ */
+ public void setHook(BiConsumer<String, String> argHandler) { argHook = argHandler ; }
+
+ public void setUsage(String usageMessage) { usage = usageMessage ; }
+
+ public boolean hasArgs() { return args.size() > 0 ; }
+ public boolean hasItems() { return items.size() > 0 ; }
+
+ public Iterator<Arg> args() { return args.values().iterator() ; }
+// public Map args() { return args ; }
+// public List items() { return items ; }
+
+ public int numArgs() { return args.size() ; }
+ public int numItems() { return items.size() ; }
+ public void pushItem(String s) { items.add(s) ; }
+
+ public boolean isIndirectItem(int i)
+ { return allowItemIndirect && items.get(i).startsWith(indirectionMarker) ; }
+
+ public String getItem(int i)
+ {
+ return getItem(i, allowItemIndirect) ;
+ }
+
+ public String getItem(int i, boolean withIndirect)
+ {
+ if ( i < 0 || i >= items.size() )
+ return null ;
+
+
+ String item = items.get(i) ;
+
+ if ( withIndirect && item.startsWith(indirectionMarker) )
+ {
+ item = item.substring(1) ;
+ try { item = FileUtils.readWholeFileAsUTF8(item) ; }
+ catch (Exception ex)
+ { throw new IllegalArgumentException("Failed to read '"+item+"': "+ex.getMessage()) ; }
+ }
+ return item ;
+ }
+
+
+ /** Process a set of command line arguments.
+ * @param argv The words of the command line.
+ * @throws IllegalArgumentException Throw when something is wrong (no value found, action fails).
+ */
+ public void process(String[] argv) throws java.lang.IllegalArgumentException
+ {
+ List<String> argList = new ArrayList<>() ;
+ argList.addAll(Arrays.asList(argv)) ;
+
+ int i = 0 ;
+ for ( ; i < argList.size() ; i++ )
+ {
+ String argStr = argList.get(i) ;
+ if (endProcessing(argStr))
+ break ;
+
+ if ( ignoreArgument(argStr) )
+ continue ;
+
+ // If the flag has a "=" or :, it is long form --arg=value.
+ // Split and insert the arg
+ int j1 = argStr.indexOf('=') ;
+ int j2 = argStr.indexOf(':') ;
+ int j = Integer.MAX_VALUE ;
+
+ if ( j1 > 0 && j1 < j )
+ j = j1 ;
+ if ( j2 > 0 && j2 < j )
+ j = j2 ;
+
+ if ( j != Integer.MAX_VALUE )
+ {
+ String a2 = argStr.substring(j+1) ;
+ argList.add(i+1,a2) ;
+ argStr = argStr.substring(0,j) ;
+ }
+
+ argStr = ArgDecl.canonicalForm(argStr) ;
+ String val = null ;
+
+ if ( argMap.containsKey(argStr) )
+ {
+ if ( ! args.containsKey(argStr))
+ args.put(argStr, new Arg(argStr)) ;
+
+ Arg arg = args.get(argStr) ;
+ ArgDecl argDecl = argMap.get(argStr) ;
+
+ if ( argDecl.takesValue() )
+ {
+ if ( i == (argList.size()-1) )
+ throw new IllegalArgumentException("No value for argument: "+arg.getName()) ;
+ i++ ;
+ val = argList.get(i) ;
+ arg.setValue(val) ;
+ arg.addValue(val) ;
+ }
+
+ // Global hook
+ if ( argHook != null )
+ argHook.accept(argStr, val) ;
+
+ argDecl.trigger(arg) ;
+ }
+ else
+ handleUnrecognizedArg( argList.get(i) );
+// if ( ! getIgnoreUnknown() )
+// // Not recognized
+// throw new IllegalArgumentException("Unknown argument: "+argStr) ;
+ }
+
+ // Remainder.
+ if ( i < argList.size() )
+ {
+ if ( argList.get(i).equals("-") || argList.get(i).equals("--") )
+ i++ ;
+ for ( ; i < argList.size() ; i++ )
+ {
+ String item = argList.get(i) ;
+ items.add(item) ;
+ }
+ }
+ }
+
+ /** Hook to test whether this argument should be processed further
+ */
+ public boolean ignoreArgument( String argStr )
+ { return false ; }
+
+ /** Answer true if this argument terminates argument processing for the rest
+ * of the command line. Default is to stop just before the first arg that
+ * does not start with "-", or is "-" or "--".
+ */
+ public boolean endProcessing( String argStr )
+ {
+ return ! argStr.startsWith("-") || argStr.equals("--") || argStr.equals("-");
+ }
+
+ /**
+ * Handle an unrecognised argument; default is to throw an exception
+ * @param argStr The string image of the unrecognised argument
+ */
+ public void handleUnrecognizedArg( String argStr ) {
+ throw new IllegalArgumentException("Unknown argument: "+argStr) ;
+ }
+
+
+ /** Test whether an argument was seen.
+ */
+
+ public boolean contains(ArgDecl argDecl) { return getArg(argDecl) != null ; }
+
+ /** Test whether an argument was seen.
+ */
+
+ public boolean contains(String s) { return getArg(s) != null ; }
+
+
+ /** Test whether the command line had a particular argument
+ *
+ * @param argName
+ */
+ public boolean hasArg(String argName) { return getArg(argName) != null ; }
+
+ /** Test whether the command line had a particular argument
+ *
+ * @param argDecl
+ */
+
+ public boolean hasArg(ArgDecl argDecl) { return getArg(argDecl) != null ; }
+
+
+ /** Get the argument associated with the argument declaration.
+ * Actually returns the LAST one seen
+ * @param argDecl Argument declaration to find
+ * @return Last argument that matched.
+ */
+
+ public Arg getArg(ArgDecl argDecl)
+ {
+ Arg arg = null ;
+ for ( Arg a : args.values() )
+ {
+ if ( argDecl.matches( a ) )
+ {
+ arg = a;
+ }
+ }
+ return arg ;
+ }
+
+ /** Get the argument associated with the arguement name.
+ * Actually returns the LAST one seen
+ * @param arg Argument declaration to find
+ * @return Arg - Last argument that matched.
+ */
+
+ public Arg getArg(String arg)
+ {
+ arg = ArgDecl.canonicalForm(arg) ;
+ return args.get(arg) ;
+ }
+
+ /**
+ * Returns the value (a string) for an argument with a value -
+ * returns null for no argument and no value.
+ * @param argDecl
+ * @return String
+ */
+ public String getValue(ArgDecl argDecl)
+ {
+ Arg arg = getArg(argDecl) ;
+ if ( arg == null )
+ return null ;
+ if ( arg.hasValue())
+ return arg.getValue() ;
+ return null ;
+ }
+
+ /**
+ * Returns the value (a string) for an argument with a value -
+ * returns null for no argument and no value.
+ * @param argName
+ * @return String
+ */
+ public String getValue(String argName)
+ {
+ Arg arg = getArg(argName) ;
+ if ( arg == null )
+ return null ;
+ return arg.getValue() ;
+ }
+
+ /**
+ * Returns all the values (0 or more strings) for an argument.
+ * @param argDecl
+ * @return List
+ */
+ public List<String> getValues(ArgDecl argDecl)
+ {
+ Arg arg = getArg(argDecl) ;
+ if ( arg == null )
+ return null ;
+ return arg.getValues() ;
+ }
+
+ /**
+ * Returns all the values (0 or more strings) for an argument.
+ * @param argName
+ * @return List
+ */
+ public List<String> getValues(String argName)
+ {
+ Arg arg = getArg(argName) ;
+ if ( arg == null )
+ return null ;
+ return arg.getValues() ;
+ }
+
+
+
+ /** Add an argument to those to be accepted on the command line.
+ * @param argName Name
+ * @param hasValue True if the command takes a (string) value
+ * @return The CommandLine processor object
+ */
+
+ public CommandLine add(String argName, boolean hasValue)
+ {
+ return add(new ArgDecl(hasValue, argName)) ;
+ }
+
+ /** Add an argument to those to be accepted on the command line.
+ * Argument order reflects ArgDecl.
+ * @param hasValue True if the command takes a (string) value
+ * @param argName Name
+ * @return The CommandLine processor object
+ */
+
+ public CommandLine add(boolean hasValue, String argName)
+ {
+ return add(new ArgDecl(hasValue, argName)) ;
+ }
+
+ /** Add an argument object
+ * @param arg Argument to add
+ * @return The CommandLine processor object
+ */
+
+ public CommandLine add(ArgDecl arg)
+ {
+ for ( Iterator<String> iter = arg.names() ; iter.hasNext() ; )
+ argMap.put(iter.next(), arg) ;
+ return this ;
+ }
+
+// public boolean getIgnoreUnknown() { return ignoreUnknown ; }
+// public void setIgnoreUnknown(boolean ign) { ignoreUnknown = ign ; }
+
+ /**
+ * @return Returns whether items starting "@" have the value of named file.
+ */
+ public boolean allowItemIndirect()
+ {
+ return allowItemIndirect ;
+ }
+
+ /**
+ * @param allowItemIndirect Set whether items starting "@" have the value of named file.
+
+ */
+ public void setAllowItemIndirect(boolean allowItemIndirect)
+ {
+ this.allowItemIndirect = allowItemIndirect ;
+ }
+
+ /**
+ * @return Returns the ignoreIndirectionMarker.
+ */
+ public boolean isIgnoreIndirectionMarker()
+ {
+ return ignoreIndirectionMarker ;
+ }
+
+ /**
+ * @return Returns the indirectionMarker.
+ */
+ public String getIndirectionMarker()
+ {
+ return indirectionMarker ;
+ }
+
+ /**
+ * @param indirectionMarker The indirectionMarker to set.
+ */
+ public void setIndirectionMarker(String indirectionMarker)
+ {
+ this.indirectionMarker = indirectionMarker ;
+ }
+
+ /**
+ * @param ignoreIndirectionMarker The ignoreIndirectionMarker to set.
+ */
+ public void setIgnoreIndirectionMarker(boolean ignoreIndirectionMarker)
+ {
+ this.ignoreIndirectionMarker = ignoreIndirectionMarker ;
+ }
+
+ public BiConsumer<String, String> trace() {
+ return (arg, val) -> {
+ System.err.println("Seen: " + arg + (val != null ? " = " + val : ""));
+ };
+ }
+
+ }
+
+ /** A command line argument that has been foundspecification.
+ */
+ static class Arg
+ {
+ String name ;
+ String value ;
+ List<String> values = new ArrayList<>() ;
+
+ Arg() { name = null ; value = null ; }
+
+ Arg(String _name) { this() ; setName(_name) ; }
+
+ Arg(String _name, String _value) { this() ; setName(_name) ; setValue(_value) ; }
+
+ void setName(String n) { name = n ; }
+
+ void setValue(String v) { value = v ; }
+ void addValue(String v) { values.add(v) ; }
+
+ public String getName() { return name ; }
+ public String getValue() { return value; }
+ public List<String> getValues() { return values; }
+
+ public boolean hasValue() { return value != null ; }
+
+ public boolean matches(ArgDecl decl)
+ {
+ return decl.getNames().contains(name) ;
+ }
+
+ }
+
+ /** A command line argument specification.
+ */
+ static class ArgDecl
+ {
+ boolean takesValue ;
+ Set<String> names = new HashSet<>() ;
+ boolean takesArg = false ;
+ List<BiConsumer<String, String>> argHooks = new ArrayList<>() ;
+ public static final boolean HasValue = true ;
+ public static final boolean NoValue = false ;
+
+ /** Create a declaration for a command argument.
+ *
+ * @param hasValue Does it take a value or not?
+ */
+
+ public ArgDecl(boolean hasValue)
+ {
+ takesValue = hasValue ;
+ }
+
+ /** Create a declaration for a command argument.
+ *
+ * @param hasValue Does it take a value or not?
+ * @param name Name of argument
+ */
+
+ public ArgDecl(boolean hasValue, String name)
+ {
+ this(hasValue) ;
+ addName(name) ;
+ }
+
+ /** Create a declaration for a command argument.
+ *
+ * @param hasValue Does it take a value or not?
+ * @param name Name of argument
+ * @param handler BiConsumer<String, String>
+ */
+
+ public ArgDecl(boolean hasValue, String name, BiConsumer<String, String> handler)
+ {
+ this(hasValue) ;
+ addName(name) ;
+ addHook( handler );
+ }
+
+ /** Create a declaration for a command argument.
+ *
+ * @param hasValue Does it take a value or not?
+ * @param name1 Name of argument
+ * @param name2 Name of argument
+ */
+
+ public ArgDecl(boolean hasValue, String name1, String name2)
+ {
+ this(hasValue) ;
+ addName(name1) ;
+ addName(name2) ;
+ }
+
+ /** Create a declaration for a command argument.
+ *
+ * @param hasValue Does it take a value or not?
+ * @param name1 Name of argument
+ * @param name2 Name of argument
+ * @param handler BiConsumer<String, String>
+ */
+
+ public ArgDecl(boolean hasValue, String name1, String name2, BiConsumer<String, String> handler)
+ {
+ this(hasValue) ;
+ addName(name1) ;
+ addName(name2) ;
+ addHook( handler );
+ }
+
+ /** Create a declaration for a command argument.
+ *
+ * @param hasValue Does it take a value or not?
+ * @param name1 Name of argument
+ * @param name2 Name of argument
+ * @param name3 Name of argument
+ */
+
+ public ArgDecl(boolean hasValue, String name1, String name2, String name3)
+ {
+ this(hasValue) ;
+ addName(name1) ;
+ addName(name2) ;
+ addName(name3) ;
+ }
+
+ /** Create a declaration for a command argument.
+ *
+ * @param hasValue Does it take a value or not?
+ * @param name1 Name of argument
+ * @param name2 Name of argument
+ * @param name3 Name of argument
+ * @param handler BiConsumer<String, String>
+ */
+
+ public ArgDecl(boolean hasValue, String name1, String name2, String name3, BiConsumer<String, String> handler)
+ {
+ this(hasValue) ;
+ addName(name1) ;
+ addName(name2) ;
+ addName(name3) ;
+ addHook( handler );
+ }
+
+ /** Create a declaration for a command argument.
+ *
+ * @param hasValue Does it take a value or not?
+ * @param name1 Name of argument
+ * @param name2 Name of argument
+ * @param name3 Name of argument
+ * @param name4 Name of argument
+ */
+
+ public ArgDecl(boolean hasValue, String name1, String name2, String name3, String name4)
+ {
+ this(hasValue) ;
+ addName(name1) ;
+ addName(name2) ;
+ addName(name3) ;
+ addName(name4) ;
+ }
+
+ /** Create a declaration for a command argument.
+ *
+ * @param hasValue Does it take a value or not?
+ * @param name1 Name of argument
+ * @param name2 Name of argument
+ * @param name3 Name of argument
+ * @param name4 Name of argument
+ * @param handler BiConsumer<String, String>
+ */
+
+ public ArgDecl(boolean hasValue, String name1, String name2, String name3, String name4, BiConsumer<String, String> handler)
+ {
+ this(hasValue) ;
+ addName(name1) ;
+ addName(name2) ;
+ addName(name3) ;
+ addName(name4) ;
+ addHook( handler );
+ }
+
+ /** Create a declaration for a command argument.
+ *
+ * @param hasValue Does it take a value or not?
+ * @param name1 Name of argument
+ * @param name2 Name of argument
+ * @param name3 Name of argument
+ * @param name4 Name of argument
+ * @param name5 Name of argument
+ * @param handler BiConsumer<String, String>
+ */
+
+ public ArgDecl(boolean hasValue, String name1, String name2, String name3, String name4, String name5, BiConsumer<String, String> handler)
+ {
+ this(hasValue) ;
+ addName(name1) ;
+ addName(name2) ;
+ addName(name3) ;
+ addName(name4) ;
+ addName(name5) ;
+ addHook( handler );
+ }
+
+ public void addName(String name)
+ {
+ name = canonicalForm(name) ;
+ names.add(name) ;
+ }
+
+ public Set<String> getNames() { return names ; }
+ public Iterator<String> names() { return names.iterator() ; }
+
+ // Callback model
+
+ public void addHook(BiConsumer<String, String> argHandler)
+ {
+ argHooks.add(argHandler) ;
+ }
+
+ protected void trigger(Arg arg)
+ {
+ argHooks.forEach(action -> action.accept( arg.getName(), arg.getValue() ));
+ }
+
+ public boolean takesValue() { return takesValue ; }
+
+ public boolean matches(Arg a)
+ {
+ for ( String n : names )
+ {
+ if ( a.getName().equals( n ) )
+ {
+ return true;
+ }
+ }
+ return false ;
+ }
+
+ public boolean matches(String arg)
+ {
+ arg = canonicalForm(arg) ;
+ return names.contains(arg) ;
+ }
+
+ static String canonicalForm(String str)
+ {
+ if ( str.startsWith("--") )
+ return str.substring(2) ;
+
+ if ( str.startsWith("-") )
+ return str.substring(1) ;
+
+ return str ;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/498b2264/jena-cmds/src/main/java/jena/rdfcompare.java
----------------------------------------------------------------------
diff --git a/jena-cmds/src/main/java/jena/rdfcompare.java b/jena-cmds/src/main/java/jena/rdfcompare.java
new file mode 100644
index 0000000..95cc602
--- /dev/null
+++ b/jena-cmds/src/main/java/jena/rdfcompare.java
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package jena;
+
+import static org.apache.jena.atlas.logging.LogCtl.setCmdLogging;
+
+import java.net.URL;
+import java.io.FileInputStream;
+
+import org.apache.jena.rdf.model.* ;
+
+/** A program which read two RDF models and determines if they are the same.
+ *
+ * <p>This program will read two RDF models, in a variety of languages,
+ * and compare them. Input can be read either from a URL or from a file.
+ * The program writes its results to the standard output stream and sets
+ * its exit code to 0 if the models are equal, to 1 if they are not and
+ * to -1 if it encounters an error.</p>
+ *
+ * <p></p>
+ *
+ * <pre>java jena.rdfcompare model1 model2 [lang1 [lang2]]
+ *
+ * model1 and model2 can be file names or URL's
+ * lang1 and lang2 specify the language of the input and can be:
+ * RDF/XML
+ * N-TRIPLE
+ * N3
+ * </pre>
+ */
+public class rdfcompare extends java.lang.Object {
+
+ static { setCmdLogging(); }
+
+ /**
+ * @param args the command line arguments
+ */
+ public static void main (String ... args) {
+ if (args.length < 2 || args.length > 6) {
+ usage();
+ System.exit(-1);
+ }
+
+ String in1 = args[0];
+ String in2 = args[1];
+ String lang1 = "RDF/XML";
+ if (args.length >= 3) {
+ lang1 = args[2];
+ }
+ String lang2 = "N-TRIPLE";
+ if (args.length >= 4) {
+ lang2 = args[3];
+ }
+ String base1 = null;
+ if (args.length >= 5) {
+ base1 = args[4];
+ }
+ String base2 = base1;
+ if (args.length >= 6) {
+ base2 = args[5];
+ }
+
+ System.out.println(in1 + " " + in2 + " " + lang1 + " " + lang2 + " " + base1 + " " + base2);
+ try {
+ Model m1 = ModelFactory.createDefaultModel();
+ Model m2 = ModelFactory.createDefaultModel();
+
+ read(m1, in1, lang1, base1);
+ read(m2, in2, lang2, base2);
+
+ if (m1.isIsomorphicWith(m2)) {
+ System.out.println("models are equal");
+ System.out.println();
+ System.exit(0);
+ } else {
+ System.out.println("models are unequal");
+ System.out.println();
+ System.exit(1);
+ }
+ } catch (Exception e) {
+ System.err.println("Unhandled exception:");
+ System.err.println(" " + e.toString());
+ System.exit(-1);
+ }
+ }
+
+ protected static void usage() {
+ System.err.println("usage:");
+ System.err.println(
+ " java jena.rdfcompare source1 source2 [lang1 [lang2 [base1 [base2]]]]");
+ System.err.println();
+ System.err.println(" source1 and source2 can be URL's or filenames");
+ System.err.println(" lang1 and lang2 can take values:");
+ System.err.println(" RDF/XML");
+ System.err.println(" N-TRIPLE");
+ System.err.println(" N3");
+ System.err.println(" lang1 defaults to RDF/XML, lang2 to N-TRIPLE");
+ System.err.println(" base1 and base2 are URIs");
+ System.err.println(" base1 defaults to null");
+ System.err.println(" base2 defaults to base1");
+ System.err.println(" If no base URIs are specified Jena determines the base URI based on the input source");
+
+ System.err.println();
+ }
+
+ protected static void read(Model model, String in, String lang, String base)
+ throws java.io.FileNotFoundException {
+ try {
+ URL url = new URL(in);
+ model.read(in, base, lang);
+ } catch (java.net.MalformedURLException e) {
+ model.read(new FileInputStream(in), base, lang);
+ }
+ }
+}