0001: /*
0002: * Copyright Aduna (http://www.aduna-software.com/) (c) 1997-2007.
0003: *
0004: * Licensed under the Aduna BSD-style license.
0005: */
0006: package org.openrdf.console;
0007:
0008: import static org.openrdf.query.QueryLanguage.SERQL;
0009: import static org.openrdf.query.QueryLanguage.SPARQL;
0010:
0011: import java.io.BufferedReader;
0012: import java.io.File;
0013: import java.io.FileInputStream;
0014: import java.io.IOException;
0015: import java.io.InputStream;
0016: import java.io.InputStreamReader;
0017: import java.io.PrintStream;
0018: import java.io.StringReader;
0019: import java.net.MalformedURLException;
0020: import java.net.URL;
0021: import java.util.ArrayList;
0022: import java.util.Collection;
0023: import java.util.Collections;
0024: import java.util.HashMap;
0025: import java.util.LinkedHashMap;
0026: import java.util.List;
0027: import java.util.Locale;
0028: import java.util.Map;
0029: import java.util.logging.Level;
0030:
0031: import org.apache.commons.cli.CommandLine;
0032: import org.apache.commons.cli.CommandLineParser;
0033: import org.apache.commons.cli.HelpFormatter;
0034: import org.apache.commons.cli.Option;
0035: import org.apache.commons.cli.OptionGroup;
0036: import org.apache.commons.cli.Options;
0037: import org.apache.commons.cli.ParseException;
0038: import org.apache.commons.cli.PosixParser;
0039: import org.slf4j.Logger;
0040: import org.slf4j.LoggerFactory;
0041:
0042: import info.aduna.app.AppConfiguration;
0043: import info.aduna.app.AppVersion;
0044: import info.aduna.io.IOUtil;
0045: import info.aduna.iteration.CloseableIteration;
0046: import info.aduna.text.StringUtil;
0047:
0048: import org.openrdf.http.client.HTTPClient;
0049: import org.openrdf.http.protocol.UnauthorizedException;
0050: import org.openrdf.model.Graph;
0051: import org.openrdf.model.Namespace;
0052: import org.openrdf.model.Resource;
0053: import org.openrdf.model.Statement;
0054: import org.openrdf.model.URI;
0055: import org.openrdf.model.Value;
0056: import org.openrdf.model.ValueFactory;
0057: import org.openrdf.model.impl.GraphImpl;
0058: import org.openrdf.model.util.GraphUtil;
0059: import org.openrdf.model.vocabulary.RDF;
0060: import org.openrdf.query.BindingSet;
0061: import org.openrdf.query.GraphQueryResult;
0062: import org.openrdf.query.MalformedQueryException;
0063: import org.openrdf.query.QueryEvaluationException;
0064: import org.openrdf.query.QueryLanguage;
0065: import org.openrdf.query.TupleQuery;
0066: import org.openrdf.query.TupleQueryResult;
0067: import org.openrdf.query.UnsupportedQueryLanguageException;
0068: import org.openrdf.query.parser.ParsedBooleanQuery;
0069: import org.openrdf.query.parser.ParsedGraphQuery;
0070: import org.openrdf.query.parser.ParsedQuery;
0071: import org.openrdf.query.parser.ParsedTupleQuery;
0072: import org.openrdf.query.parser.QueryParserUtil;
0073: import org.openrdf.query.parser.serql.SeRQLUtil;
0074: import org.openrdf.query.parser.sparql.SPARQLUtil;
0075: import org.openrdf.repository.Repository;
0076: import org.openrdf.repository.RepositoryConnection;
0077: import org.openrdf.repository.RepositoryException;
0078: import org.openrdf.repository.config.RepositoryConfig;
0079: import org.openrdf.repository.config.RepositoryConfigException;
0080: import org.openrdf.repository.config.RepositoryConfigSchema;
0081: import org.openrdf.repository.config.RepositoryConfigUtil;
0082: import org.openrdf.repository.manager.LocalRepositoryManager;
0083: import org.openrdf.repository.manager.RemoteRepositoryManager;
0084: import org.openrdf.repository.manager.RepositoryManager;
0085: import org.openrdf.rio.ParseErrorListener;
0086: import org.openrdf.rio.RDFFormat;
0087: import org.openrdf.rio.RDFHandlerException;
0088: import org.openrdf.rio.RDFParseException;
0089: import org.openrdf.rio.RDFParser;
0090: import org.openrdf.rio.Rio;
0091: import org.openrdf.rio.UnsupportedRDFormatException;
0092: import org.openrdf.rio.helpers.RDFHandlerBase;
0093: import org.openrdf.rio.helpers.StatementCollector;
0094: import org.openrdf.rio.ntriples.NTriplesUtil;
0095:
0096: /**
0097: * The Sesame Console is a command-line application for interacting with Sesame.
0098: * It reads commands from standard input and prints feedback to standard output.
0099: * Available options include loading and querying of data in repositories,
0100: * repository creation and verification of RDF files.
0101: *
0102: * @author jeen
0103: * @author Arjohn Kampman
0104: */
0105: public class Console {
0106:
0107: /*------------------*
0108: * Static constants *
0109: *------------------*/
0110:
0111: private static final AppVersion VERSION = new AppVersion(2, 0,
0112: "SNAPSHOT");
0113:
0114: private static final String APP_NAME = "OpenRDF Sesame console";
0115:
0116: private static final String TEMPLATES_DIR = "templates";
0117:
0118: /**
0119: * Query that produces the list of the IDs and (optionally) titles of
0120: * configured repositories.
0121: */
0122: public static final String REPOSITORY_LIST_QUERY;
0123:
0124: /**
0125: * Query that yields the context of a specific repository configuration.
0126: */
0127: public static final String REPOSITORY_CONTEXT_QUERY;
0128:
0129: public static final Map<String, Level> LOG_LEVELS;
0130:
0131: static {
0132: StringBuilder query = new StringBuilder(256);
0133: query.append("SELECT ID, Title ");
0134: query.append("FROM {} rdf:type {sys:Repository};");
0135: query.append(" sys:repositoryID {ID};");
0136: query
0137: .append(" [rdfs:label {Title} where isLiteral(Title)] ");
0138: query.append("WHERE isLiteral(ID) ");
0139: query
0140: .append("USING NAMESPACE sys = <http://www.openrdf.org/config/repository#>");
0141: REPOSITORY_LIST_QUERY = query.toString();
0142:
0143: query.setLength(0);
0144: query.append("SELECT C ");
0145: query.append("FROM CONTEXT C ");
0146: query.append(" {} rdf:type {sys:Repository};");
0147: query.append(" sys:repositoryID {ID} ");
0148: query
0149: .append("USING NAMESPACE sys = <http://www.openrdf.org/config/repository#>");
0150: REPOSITORY_CONTEXT_QUERY = query.toString();
0151:
0152: Map<String, Level> logLevels = new LinkedHashMap<String, Level>();
0153: logLevels.put("none", Level.OFF);
0154: logLevels.put("error", Level.SEVERE);
0155: logLevels.put("warning", Level.WARNING);
0156: logLevels.put("info", Level.INFO);
0157: logLevels.put("debug", Level.FINE);
0158: LOG_LEVELS = Collections.unmodifiableMap(logLevels);
0159: }
0160:
0161: /*-----------*
0162: * Constants *
0163: *-----------*/
0164:
0165: private final AppConfiguration appConfig = new AppConfiguration(
0166: APP_NAME, APP_NAME, VERSION);
0167:
0168: private final java.util.logging.Logger jdkRootLogger = java.util.logging.Logger
0169: .getLogger("");
0170:
0171: private final Logger logger = LoggerFactory.getLogger(this
0172: .getClass());
0173:
0174: /*-----------*
0175: * Variables *
0176: *-----------*/
0177:
0178: private RepositoryManager manager;
0179:
0180: private String managerID;
0181:
0182: private Repository repository;
0183:
0184: private String repositoryID;
0185:
0186: private BufferedReader in;
0187:
0188: private PrintStream out;
0189:
0190: private int consoleWidth = 80;
0191:
0192: private boolean showPrefix = true;
0193:
0194: private boolean queryPrefix = false;
0195:
0196: /*---------------*
0197: * Static metods *
0198: *---------------*/
0199:
0200: public static void main(String[] args) throws Exception {
0201: Console console = new Console();
0202:
0203: // Parse command line options
0204: Options options = new Options();
0205:
0206: Option helpOption = new Option("h", "help", false,
0207: "print this help");
0208: Option versionOption = new Option("v", "version", false,
0209: "print version information");
0210: Option serverURLOption = new Option("s", "serverURL", true,
0211: "URL of Sesame server to connect to, e.g. http://localhost/openrdf-sesame/");
0212: Option dirOption = new Option("d", "dataDir", true,
0213: "Sesame data dir to 'connect' to");
0214:
0215: options.addOption(helpOption);
0216:
0217: OptionGroup connectGroup = new OptionGroup();
0218: connectGroup.addOption(serverURLOption);
0219: connectGroup.addOption(dirOption);
0220: options.addOptionGroup(connectGroup);
0221:
0222: CommandLineParser argsParser = new PosixParser();
0223:
0224: try {
0225: CommandLine commandLine = argsParser.parse(options, args);
0226:
0227: if (commandLine.hasOption(helpOption.getOpt())) {
0228: printUsage(options);
0229: System.exit(0);
0230: }
0231:
0232: if (commandLine.hasOption(versionOption.getOpt())) {
0233: System.out.println(console.appConfig.getFullName());
0234: System.exit(0);
0235: }
0236:
0237: String dir = commandLine.getOptionValue(dirOption.getOpt());
0238: String serverURL = commandLine
0239: .getOptionValue(serverURLOption.getOpt());
0240: String[] otherArgs = commandLine.getArgs();
0241:
0242: if (otherArgs.length > 1) {
0243: printUsage(options);
0244: System.exit(1);
0245: }
0246:
0247: boolean connected = false;
0248: if (dir != null) {
0249: connected = console.connectLocal(dir);
0250: } else if (serverURL != null) {
0251: connected = console.connectRemote(serverURL);
0252: } else {
0253: connected = console.connectDefault();
0254: }
0255:
0256: if (!connected) {
0257: System.exit(2);
0258: }
0259:
0260: if (otherArgs.length > 0) {
0261: console.openRepository(otherArgs[0]);
0262: }
0263: } catch (ParseException e) {
0264: System.err.println(e.getMessage());
0265: System.exit(1);
0266: }
0267:
0268: console.start();
0269: }
0270:
0271: private static void printUsage(Options options) {
0272: System.out
0273: .println("Sesame Console, an interactive shell based utility to communicate with Sesame repositories.");
0274: HelpFormatter formatter = new HelpFormatter();
0275: formatter.setWidth(80);
0276: formatter.printHelp("start-console [OPTION] [repositoryID]",
0277: options);
0278: // writeln("Usage: start-console [OPTION] [repositoryID]");
0279: // writeln();
0280: // writeln(" -h, --help print this help");
0281: // writeln(" -s, --serverURL=URL URL of Sesame server to connect to, e.g.
0282: // http://localhost/openrdf-sesame/");
0283: // writeln(" -d, --dataDir=DIR Sesame data dir to 'connect' to");
0284: System.out.println();
0285: System.out
0286: .println("For bug reports and suggestions, see http://www.openrdf.org/");
0287: }
0288:
0289: public Console() throws IOException {
0290: // Set log level to WARNING by default
0291: jdkRootLogger.setLevel(Level.WARNING);
0292:
0293: appConfig.init();
0294:
0295: in = new BufferedReader(new InputStreamReader(System.in));
0296: out = System.out;
0297: }
0298:
0299: public void start() throws IOException {
0300: writeln();
0301: writeln("Commands end with '.' at the end of a line");
0302: writeln("Type 'help.' for help");
0303:
0304: try {
0305: boolean exitFlag = false;
0306: while (!exitFlag) {
0307: String command = readMultiLineInput();
0308:
0309: if (command == null) {
0310: // EOF
0311: break;
0312: }
0313:
0314: exitFlag = executeCommand(command);
0315: }
0316: } finally {
0317: disconnect(false);
0318: }
0319:
0320: writeln("Bye");
0321: }
0322:
0323: private boolean executeCommand(String command) throws IOException {
0324: boolean exit = false;
0325: String[] tokens = command.split("[ \t\r\n]");
0326: String operation = tokens[0].toLowerCase(Locale.ENGLISH);
0327:
0328: if ("quit".equals(operation) || "exit".equals(operation)) {
0329: exit = true;
0330: } else if ("help".equals(operation)) {
0331: printHelp(tokens);
0332: } else if ("info".equals(operation)) {
0333: printInfo();
0334: } else if ("connect".equals(operation)) {
0335: connect(tokens);
0336: } else if ("disconnect".equals(operation)) {
0337: disconnect(true);
0338: } else if ("create".equals(operation)) {
0339: createRepository(tokens);
0340: } else if ("drop".equals(operation)) {
0341: dropRepository(tokens);
0342: } else if ("open".equals(operation)) {
0343: open(tokens);
0344: } else if ("close".equals(operation)) {
0345: close(tokens);
0346: } else if ("show".equals(operation)) {
0347: show(tokens);
0348: } else if ("load".equals(operation)) {
0349: load(tokens);
0350: } else if ("verify".equals(operation)) {
0351: verify(tokens);
0352: } else if ("clear".equals(operation)) {
0353: clear(tokens);
0354: } else if ("select".equals(operation)) {
0355: // TODO: should this be removed now that the 'serql' command is
0356: // supported?
0357: evaluateQuery(QueryLanguage.SERQL, command);
0358: } else if ("construct".equals(operation)) {
0359: // TODO: should this be removed now that the 'serql' command is
0360: // supported?
0361: evaluateQuery(QueryLanguage.SERQL, command);
0362: } else if ("serql".equals(operation)) {
0363: evaluateQuery(QueryLanguage.SERQL, command
0364: .substring("serql".length()));
0365: } else if ("sparql".equals(operation)) {
0366: evaluateQuery(QueryLanguage.SPARQL, command
0367: .substring("sparql".length()));
0368: } else if ("set".equals(operation)) {
0369: setParameter(tokens);
0370: } else if (command.length() == 0) {
0371: // empty line, ignore
0372: } else {
0373: writeError("Unknown command");
0374: }
0375:
0376: return exit;
0377: }
0378:
0379: private void printHelp(String[] tokens) {
0380: if (tokens.length < 2) {
0381: printCommandOverview();
0382: } else {
0383: String target = tokens[1].toLowerCase(Locale.ENGLISH);
0384:
0385: if ("connect".equals(target)) {
0386: printHelpConnect();
0387: } else if ("disconnect".equals(target)) {
0388: printHelpDisconnect();
0389: } else if ("create".equals(target)) {
0390: printHelpCreate();
0391: } else if ("drop".equals(target)) {
0392: printHelpDrop();
0393: } else if ("open".equals(target)) {
0394: printHelpOpen();
0395: } else if ("close".equals(target)) {
0396: printHelpClose();
0397: } else if ("show".equals(target)) {
0398: printHelpShow();
0399: } else if ("load".equals(target)) {
0400: printHelpLoad();
0401: } else if ("verify".equals(target)) {
0402: printHelpVerify();
0403: } else if ("clear".equals(target)) {
0404: printHelpClear();
0405: } else if ("set".equals(target)) {
0406: printHelpSet();
0407: } else {
0408: writeln("No info available for command " + tokens[1]);
0409: }
0410: }
0411: }
0412:
0413: private void printCommandOverview() {
0414: writeln("For more information on a specific command, try 'help <command>.'");
0415: writeln("List of all commands:");
0416: writeln("help Displays this help message");
0417: writeln("info Shows info about the console");
0418: writeln("connect Connects to a (local or remote) set of repositories");
0419: writeln("disconnect Disconnects from the current set of repositories");
0420: writeln("create Creates a new repository");
0421: writeln("drop Drops a repository");
0422: writeln("open Opens a repository to work on, takes a repository ID as argument");
0423: writeln("close Closes the current repository");
0424: writeln("show Displays an overview of various resources");
0425: writeln("load Loads a data file into a repository, takes a file path or URL as argument");
0426: writeln("verify Verifies the syntax of an RDF data file, takes a file path or URL as argument");
0427: writeln("clear Removes data from a repository");
0428: writeln("serql Evaluates the SeRQL query, takes a query as argument");
0429: writeln("sparql Evaluates the SPARQL query, takes a query as argument");
0430: writeln("set Allows various console parameters to be set");
0431: writeln("exit, quit Exit the console");
0432: }
0433:
0434: private void printInfo() {
0435: writeln(appConfig.getFullName());
0436: writeln("Data dir: " + appConfig.getDataDir());
0437: writeln("Connected to: "
0438: + (managerID == null ? "-" : managerID));
0439: }
0440:
0441: private void printHelpConnect() {
0442: writeln("Usage:");
0443: writeln("connect default Opens the default repository set for this console");
0444: writeln("connect <dataDirectory> Opens the repository set in the specified data dir");
0445: writeln("connect <serverURL> Connects to a Sesame server");
0446: }
0447:
0448: private void connect(String[] tokens) {
0449: if (tokens.length != 2) {
0450: printHelpConnect();
0451: return;
0452: }
0453:
0454: String target = tokens[1];
0455:
0456: if ("default".equalsIgnoreCase(target)) {
0457: connectDefault();
0458: } else {
0459: try {
0460: new URL(target);
0461: // target is a valid URL
0462: connectRemote(target);
0463: } catch (MalformedURLException e) {
0464: // assume target is a directory path
0465: connectLocal(target);
0466: }
0467: }
0468: }
0469:
0470: private boolean connectDefault() {
0471: return installNewManager(new LocalRepositoryManager(appConfig
0472: .getDataDir()), "default data directory");
0473: }
0474:
0475: private boolean connectLocal(String path) {
0476: File dir = new File(path);
0477: if (!dir.exists() && !dir.isDirectory()) {
0478: writeError("Specified path is not an (existing) directory: "
0479: + path);
0480: return false;
0481: }
0482:
0483: return installNewManager(new LocalRepositoryManager(dir), dir
0484: .toString());
0485: }
0486:
0487: private boolean connectRemote(String url) {
0488: try {
0489: // Ping server
0490: HTTPClient httpClient = new HTTPClient();
0491: httpClient.setServerURL(url);
0492: httpClient.getServerProtocol();
0493:
0494: return installNewManager(new RemoteRepositoryManager(url),
0495: url);
0496: } catch (UnauthorizedException e) {
0497: // FIXME: handle authentication
0498: writeError("Not authorized to access the server");
0499: } catch (IOException e) {
0500: writeError("Failed to access the server: " + e.getMessage());
0501: logger.warn("Failed to access the server", e);
0502: } catch (RepositoryException e) {
0503: writeError("Failed to access the server: " + e.getMessage());
0504: logger.warn("Failed to access the server", e);
0505: }
0506:
0507: return false;
0508: }
0509:
0510: private boolean installNewManager(RepositoryManager newManager,
0511: String newManagerID) {
0512: if (newManagerID.equals(managerID)) {
0513: writeln("Already connected to " + managerID);
0514: return true;
0515: }
0516:
0517: try {
0518: newManager.initialize();
0519:
0520: disconnect(false);
0521: manager = newManager;
0522: managerID = newManagerID;
0523:
0524: writeln("Connected to " + managerID);
0525: return true;
0526: } catch (RepositoryException e) {
0527: writeError(e.getMessage());
0528: logger.error("Failed to install new manager", e);
0529: return false;
0530: }
0531: }
0532:
0533: private void printHelpDisconnect() {
0534: writeln("Usage:");
0535: writeln("disconnect Disconnects from the current set of repositories or server");
0536: }
0537:
0538: private void disconnect(boolean verbose) {
0539: if (manager != null) {
0540: closeRepository(false);
0541:
0542: writeln("Disconnecting from " + managerID);
0543: manager.shutDown();
0544: manager = null;
0545: managerID = null;
0546: } else if (verbose) {
0547: writeln("Already disconnected");
0548: }
0549: }
0550:
0551: private void printHelpCreate() {
0552: writeln("Usage:");
0553: writeln("create <template-name>");
0554: writeln(" <template-name> The name of a repository configuration template");
0555: }
0556:
0557: private void createRepository(String[] tokens) throws IOException {
0558: if (tokens.length < 2) {
0559: printHelpCreate();
0560: } else {
0561: createRepository(tokens[1]);
0562: }
0563: }
0564:
0565: private void createRepository(String templateName)
0566: throws IOException {
0567: Repository systemRepo = manager.getSystemRepository();
0568:
0569: try {
0570: // FIXME: remove assumption of .ttl extension
0571: String templateFileName = templateName + ".ttl";
0572:
0573: File templatesDir = new File(appConfig.getDataDir(),
0574: TEMPLATES_DIR);
0575:
0576: File templateFile = new File(templatesDir, templateFileName);
0577: InputStream templateStream;
0578:
0579: if (templateFile.exists()) {
0580: if (!templateFile.canRead()) {
0581: writeError("Not allowed to read template file: "
0582: + templateFile);
0583: return;
0584: }
0585:
0586: templateStream = new FileInputStream(templateFile);
0587: } else {
0588: // Try classpath for built-ins
0589: templateStream = Console.class
0590: .getResourceAsStream(templateFileName);
0591:
0592: if (templateStream == null) {
0593: writeError("No template called " + templateName
0594: + " found in " + templatesDir);
0595: return;
0596: }
0597: }
0598:
0599: String template = IOUtil.readString(new InputStreamReader(
0600: templateStream, "UTF-8"));
0601: templateStream.close();
0602:
0603: ConfigTemplate configTemplate = new ConfigTemplate(template);
0604:
0605: Map<String, String> valueMap = new HashMap<String, String>();
0606: Map<String, List<String>> variableMap = configTemplate
0607: .getVariableMap();
0608:
0609: if (!variableMap.isEmpty()) {
0610: writeln("Please specify values for the following variables:");
0611: }
0612:
0613: for (Map.Entry<String, List<String>> entry : variableMap
0614: .entrySet()) {
0615: String var = entry.getKey();
0616: List<String> values = entry.getValue();
0617:
0618: write(var);
0619: if (values.size() > 1) {
0620: write(" (");
0621: for (int i = 0; i < values.size(); i++) {
0622: if (i > 0) {
0623: write("|");
0624: }
0625: write(values.get(i));
0626: }
0627: write(")");
0628: }
0629: if (!values.isEmpty()) {
0630: write(" [" + values.get(0) + "]");
0631: }
0632: write(": ");
0633:
0634: String value = in.readLine();
0635: if (value == null) {
0636: // EOF
0637: return;
0638: }
0639:
0640: value = value.trim();
0641: if (value.length() == 0) {
0642: value = null;
0643: }
0644: valueMap.put(var, value);
0645: }
0646:
0647: String configString = configTemplate.render(valueMap);
0648: // writeln(configString);
0649:
0650: ValueFactory vf = systemRepo.getValueFactory();
0651:
0652: Graph graph = new GraphImpl(vf);
0653:
0654: RDFParser rdfParser = Rio
0655: .createParser(RDFFormat.TURTLE, vf);
0656: rdfParser.setRDFHandler(new StatementCollector(graph));
0657: rdfParser.parse(new StringReader(configString),
0658: RepositoryConfigSchema.NAMESPACE);
0659:
0660: Resource repositoryNode = GraphUtil.getUniqueSubject(graph,
0661: RDF.TYPE, RepositoryConfigSchema.REPOSITORY);
0662: RepositoryConfig repConfig = RepositoryConfig.create(graph,
0663: repositoryNode);
0664: repConfig.validate();
0665:
0666: if (RepositoryConfigUtil.hasRepositoryConfig(systemRepo,
0667: repConfig.getID())) {
0668: boolean proceed = askProceed(
0669: "WARNING: you are about to overwrite the configuration of an existing repository!",
0670: false);
0671:
0672: if (!proceed) {
0673: writeln("Create aborted");
0674: return;
0675: }
0676: }
0677:
0678: RepositoryConfigUtil.updateRepositoryConfigs(systemRepo,
0679: repConfig);
0680: writeln("Repository created");
0681: } catch (Exception e) {
0682: writeError(e.getMessage());
0683: logger.error("Failed to create repository", e);
0684: }
0685: }
0686:
0687: private void printHelpDrop() {
0688: writeln("Usage:");
0689: writeln("drop <repositoryID> Drops the repository with the specified id");
0690: }
0691:
0692: private void dropRepository(String[] tokens) throws IOException {
0693: if (tokens.length < 2) {
0694: printHelpDrop();
0695: return;
0696: }
0697:
0698: String id = tokens[1];
0699:
0700: Repository systemRepo = manager.getSystemRepository();
0701:
0702: try {
0703: ValueFactory vf = systemRepo.getValueFactory();
0704:
0705: RepositoryConnection con = systemRepo.getConnection();
0706:
0707: try {
0708: Resource context;
0709: TupleQuery query = con.prepareTupleQuery(
0710: QueryLanguage.SERQL, REPOSITORY_CONTEXT_QUERY);
0711: query.setBinding("ID", vf.createLiteral(id));
0712: TupleQueryResult queryResult = query.evaluate();
0713:
0714: try {
0715: if (!queryResult.hasNext()) {
0716: writeError("Unable to find context information for repository '"
0717: + id + "'");
0718: logger
0719: .warn(
0720: "Multiple contexts found for repository '{}'",
0721: id);
0722: return;
0723: }
0724:
0725: BindingSet bindings = queryResult.next();
0726: context = (Resource) bindings.getValue("C");
0727:
0728: if (queryResult.hasNext()) {
0729: writeError("Multiple contexts found for repository '"
0730: + id + "'");
0731: logger
0732: .error(
0733: "Multiple contexts found for repository '{}'",
0734: id);
0735: return;
0736: }
0737: } finally {
0738: queryResult.close();
0739: }
0740:
0741: boolean proceed = askProceed(
0742: "WARNING: you are about to drop repository '"
0743: + id + "'.", true);
0744: if (proceed) {
0745: if (id.equals(repositoryID)) {
0746: closeRepository(false);
0747: }
0748: con.clear(context);
0749: writeln("Dropped repository '" + id + "'");
0750: } else {
0751: writeln("Drop aborted");
0752: }
0753: } catch (MalformedQueryException e) {
0754: writeError("Internal error: malformed preconfigured query");
0755: logger.error("Malformed preconfigured query", e);
0756: } catch (QueryEvaluationException e) {
0757: throw new RepositoryException(e);
0758: } finally {
0759: con.close();
0760: }
0761: } catch (RepositoryException e) {
0762: writeError("Failed to drop repository: " + e.getMessage());
0763: logger.error("Failed to drop repository", e);
0764: }
0765: }
0766:
0767: private void printHelpOpen() {
0768: writeln("Usage:");
0769: writeln("open <repositoryID> Opens the repository with the specified ID");
0770: }
0771:
0772: private void open(String[] tokens) {
0773: if (tokens.length != 2) {
0774: printHelpOpen();
0775: } else {
0776: openRepository(tokens[1]);
0777: }
0778: }
0779:
0780: private void openRepository(String id) {
0781: try {
0782: Repository newRepository = manager.getRepository(id);
0783:
0784: if (newRepository != null) {
0785: // Close current repository, if any
0786: closeRepository(false);
0787:
0788: repository = newRepository;
0789: repositoryID = id;
0790: writeln("Opened repository '" + id + "'");
0791: } else {
0792: writeError("Unknown repository: '" + id + "'");
0793: }
0794: } catch (RepositoryConfigException e) {
0795: writeError(e.getMessage());
0796: logger.error("Failed to open repository", e);
0797: } catch (RepositoryException e) {
0798: writeError(e.getMessage());
0799: logger.error("Failed to open repository", e);
0800: }
0801: }
0802:
0803: private void printHelpClose() {
0804: writeln("Usage:");
0805: writeln("close Closes the current repository");
0806: }
0807:
0808: private void close(String[] tokens) {
0809: if (tokens.length != 1) {
0810: printHelpClose();
0811: } else {
0812: closeRepository(true);
0813: }
0814: }
0815:
0816: private void closeRepository(boolean verbose) {
0817: if (repository != null) {
0818: writeln("Closing repository '" + repositoryID + "'...");
0819: repository = null;
0820: repositoryID = null;
0821: } else if (verbose) {
0822: writeln("There are no open repositories that can be closed");
0823: }
0824: }
0825:
0826: private void printHelpShow() {
0827: writeln("Usage:");
0828: writeln("show {r, repositories} Shows all available repositories");
0829: writeln("show {n, namespaces} Shows all namespaces");
0830: writeln("show {c, contexts} Shows all context identifiers");
0831: }
0832:
0833: private void show(String[] tokens) {
0834: if (tokens.length != 2) {
0835: printHelpShow();
0836: } else {
0837: String target = tokens[1].toLowerCase(Locale.ENGLISH);
0838:
0839: if ("repositories".equals(target) || "r".equals(target)) {
0840: showRepositories();
0841: } else if ("namespaces".equals(target)
0842: || "n".equals(target)) {
0843: showNamespaces();
0844: } else if ("contexts".equals(target) || "c".equals(target)) {
0845: showContexts();
0846: } else {
0847: writeError("Unknown target '" + tokens[1] + "'");
0848: }
0849: }
0850: }
0851:
0852: private void showRepositories() {
0853: try {
0854: Repository systemRepo = manager.getSystemRepository();
0855: RepositoryConnection con = systemRepo.getConnection();
0856: try {
0857: TupleQueryResult queryResult = con.prepareTupleQuery(
0858: QueryLanguage.SERQL, REPOSITORY_LIST_QUERY)
0859: .evaluate();
0860: try {
0861: if (!queryResult.hasNext()) {
0862: writeln("--no repositories found--");
0863: } else {
0864: writeln("+----------");
0865: while (queryResult.hasNext()) {
0866: BindingSet bindings = queryResult.next();
0867: String id = bindings.getValue("ID")
0868: .stringValue();
0869: String title = bindings.getValue("Title")
0870: .stringValue();
0871:
0872: write("|" + id);
0873: if (title != null) {
0874: write(" (\"" + title + "\")");
0875: }
0876: writeln();
0877: }
0878: writeln("+----------");
0879: }
0880: } finally {
0881: queryResult.close();
0882: }
0883: } catch (MalformedQueryException e) {
0884: writeError("Internal error: malformed preconfigured query");
0885: logger.error("Failed to show repository", e);
0886: } catch (QueryEvaluationException e) {
0887: throw new RepositoryException(e);
0888: } finally {
0889: con.close();
0890: }
0891: } catch (RepositoryException e) {
0892: writeError("Failed to get repository list: "
0893: + e.getMessage());
0894: logger.error("Failed to get repository list", e);
0895: }
0896: }
0897:
0898: private void showNamespaces() {
0899: if (repository == null) {
0900: writeError("please open a repository first");
0901: return;
0902: }
0903:
0904: RepositoryConnection con;
0905: try {
0906: con = repository.getConnection();
0907:
0908: try {
0909: CloseableIteration<? extends Namespace, RepositoryException> namespaces = con
0910: .getNamespaces();
0911:
0912: try {
0913: if (namespaces.hasNext()) {
0914: writeln("+----------");
0915: while (namespaces.hasNext()) {
0916: Namespace ns = namespaces.next();
0917: writeln("|" + ns.getPrefix() + " "
0918: + ns.getName());
0919: }
0920: writeln("+----------");
0921: } else {
0922: writeln("--no namespaces found--");
0923: }
0924: } finally {
0925: namespaces.close();
0926: }
0927: } finally {
0928: con.close();
0929: }
0930: } catch (RepositoryException e) {
0931: writeError(e.getMessage());
0932: logger.error("Failed to show namespaces", e);
0933: }
0934: }
0935:
0936: private void showContexts() {
0937: if (repository == null) {
0938: writeError("please open a repository first");
0939: return;
0940: }
0941:
0942: RepositoryConnection con;
0943: try {
0944: con = repository.getConnection();
0945:
0946: try {
0947: CloseableIteration<? extends Resource, RepositoryException> contexts = con
0948: .getContextIDs();
0949:
0950: try {
0951: if (contexts.hasNext()) {
0952: writeln("+----------");
0953: while (contexts.hasNext()) {
0954: Resource context = contexts.next();
0955: writeln("|" + context.toString());
0956: }
0957: writeln("+----------");
0958: } else {
0959: writeln("--no contexts found--");
0960: }
0961: } finally {
0962: contexts.close();
0963: }
0964: } finally {
0965: con.close();
0966: }
0967: } catch (RepositoryException e) {
0968: writeError(e.getMessage());
0969: logger.error("Failed to show contexts", e);
0970: }
0971: }
0972:
0973: private void printHelpLoad() {
0974: writeln("Usage:");
0975: writeln("load <file-or-url> [from <base-uri>] [into <context-id>]");
0976: writeln(" <file-or-url> The path or URL identifying the data file");
0977: writeln(" <base-uri> The base URI to use for resolving relative references, defaults to <file-or-url>");
0978: writeln(" <context-id> The ID of the context to add the data to, e.g. foo:bar or _:n123");
0979: writeln("Loads the specified data file into the current repository");
0980: }
0981:
0982: private void load(String[] tokens) {
0983: if (repository == null) {
0984: writeError("please open a repository first");
0985: return;
0986: }
0987:
0988: if (tokens.length < 2) {
0989: printHelpLoad();
0990: return;
0991: }
0992:
0993: String dataPath = tokens[1];
0994: String baseURI = null;
0995: String context = null;
0996:
0997: int i = 2;
0998:
0999: if (tokens.length >= i + 2
1000: && tokens[i].equalsIgnoreCase("from")) {
1001: baseURI = tokens[i + 1];
1002: i += 2;
1003: }
1004:
1005: if (tokens.length >= i + 2
1006: && tokens[i].equalsIgnoreCase("into")) {
1007: context = tokens[tokens.length - 1];
1008: i += 2;
1009: }
1010:
1011: if (i < tokens.length) {
1012: printHelpLoad();
1013: return;
1014: }
1015:
1016: try {
1017: new URL(dataPath);
1018: // dataPath is a URI
1019: } catch (MalformedURLException e) {
1020: // dataPath is a file, convert to URL
1021: dataPath = "file:" + dataPath;
1022: }
1023:
1024: try {
1025: URL dataURL = new URL(dataPath);
1026:
1027: Resource contextURI = null;
1028: if (context != null) {
1029: if (context.startsWith("_:")) {
1030: contextURI = repository.getValueFactory()
1031: .createBNode(context.substring(2));
1032: } else {
1033: contextURI = repository.getValueFactory()
1034: .createURI(context);
1035: }
1036: }
1037:
1038: RDFFormat format = Rio.getParserFormatForFileName(dataPath,
1039: RDFFormat.RDFXML);
1040:
1041: writeln("Loading data...");
1042: long startTime = System.currentTimeMillis();
1043:
1044: RepositoryConnection con = repository.getConnection();
1045: try {
1046: if (context == null) {
1047: con.add(dataURL, baseURI, format);
1048: } else {
1049: con.add(dataURL, baseURI, format, contextURI);
1050: }
1051: } finally {
1052: con.close();
1053: }
1054:
1055: long endTime = System.currentTimeMillis();
1056: writeln("Data has been added to the repository ("
1057: + (endTime - startTime) + " ms)");
1058: } catch (MalformedURLException e) {
1059: writeError("Malformed URL: " + dataPath);
1060: } catch (IllegalArgumentException e) {
1061: // Thrown when context URI is invalid
1062: writeError(e.getMessage());
1063: } catch (IOException e) {
1064: writeError("Failed to load data: " + e.getMessage());
1065: } catch (UnsupportedRDFormatException e) {
1066: writeError("No parser available for this RDF format");
1067: } catch (RDFParseException e) {
1068: writeError("Malformed document: " + e.getMessage());
1069: } catch (RepositoryException e) {
1070: writeError("Unable to add data to repository: "
1071: + e.getMessage());
1072: logger.error("Failed to add data to repository", e);
1073: }
1074: }
1075:
1076: private void printHelpVerify() {
1077: writeln("Usage:");
1078: writeln("verify <file-or-url>");
1079: writeln(" <file-or-url> The path or URL identifying the data file");
1080: writeln("Verifies the validity of the specified data file");
1081: }
1082:
1083: private void verify(String[] tokens) {
1084: if (tokens.length != 2) {
1085: printHelpVerify();
1086: return;
1087: }
1088:
1089: String dataPath = tokens[1];
1090:
1091: try {
1092: new URL(dataPath);
1093: // dataPath is a URI
1094: } catch (MalformedURLException e) {
1095: // File path specified, convert to URL
1096: dataPath = "file:" + dataPath;
1097: }
1098:
1099: try {
1100: URL dataURL = new URL(dataPath);
1101: RDFFormat format = Rio.getParserFormatForFileName(dataPath,
1102: RDFFormat.RDFXML);
1103:
1104: writeln("RDF Format is " + format.getName());
1105:
1106: RDFParser parser = Rio.createParser(format);
1107: VerificationListener listener = new VerificationListener();
1108: parser
1109: .setDatatypeHandling(RDFParser.DatatypeHandling.VERIFY);
1110: parser.setVerifyData(true);
1111: parser.setParseErrorListener(listener);
1112: parser.setRDFHandler(listener);
1113:
1114: writeln("Verifying data...");
1115: InputStream in = dataURL.openStream();
1116: try {
1117: parser.parse(in, "urn://openrdf.org/RioVerifier/");
1118: } finally {
1119: in.close();
1120: }
1121:
1122: int warnings = listener.getWarnings();
1123: int errors = listener.getErrors();
1124: int statements = listener.getStatements();
1125:
1126: if (warnings + errors > 0) {
1127: writeln("Found " + warnings + " warnings and " + errors
1128: + " errors");
1129: } else {
1130: writeln("Data verified, no errors were found");
1131: }
1132:
1133: if (errors == 0) {
1134: writeln("File contains " + statements + " statements");
1135: }
1136: } catch (MalformedURLException e) {
1137: writeError("Malformed URL: " + dataPath);
1138: } catch (IOException e) {
1139: writeError("Failed to load data: " + e.getMessage());
1140: } catch (UnsupportedRDFormatException e) {
1141: writeError("No parser available for this RDF format");
1142: } catch (RDFParseException e) {
1143: // Any parse errors have already been reported by the
1144: // VerificationListener
1145: } catch (RDFHandlerException e) {
1146: writeError("Unable to verify : " + e.getMessage());
1147: logger.error("Unable to verify data file", e);
1148: }
1149: }
1150:
1151: private void printHelpClear() {
1152: writeln("Usage:");
1153: writeln("clear Clears the entire repository");
1154: writeln("clear (<uri>|null)... Clears the specified context(s)");
1155: }
1156:
1157: private void clear(String[] tokens) {
1158: if (repository == null) {
1159: writeError("please open a repository first");
1160: return;
1161: }
1162:
1163: ValueFactory valueFactory = repository.getValueFactory();
1164:
1165: Resource[] contexts = new Resource[tokens.length - 1];
1166:
1167: for (int i = 1; i < tokens.length; i++) {
1168: String contextID = tokens[i];
1169:
1170: if (contextID.equalsIgnoreCase("null")) {
1171: contexts[i - 1] = null;
1172: } else if (contextID.startsWith("_:")) {
1173: contexts[i - 1] = valueFactory.createBNode(contextID
1174: .substring(2));
1175: } else {
1176: try {
1177: contexts[i - 1] = valueFactory.createURI(contextID);
1178: } catch (IllegalArgumentException e) {
1179: writeError("illegal URI: " + contextID);
1180: printHelpClear();
1181: return;
1182: }
1183: }
1184: }
1185:
1186: if (contexts.length == 0) {
1187: writeln("Clearing repository...");
1188: } else {
1189: writeln("Removing specified contexts...");
1190: }
1191:
1192: try {
1193: RepositoryConnection con = repository.getConnection();
1194: try {
1195: con.clear(contexts);
1196: } finally {
1197: con.close();
1198: }
1199: } catch (RepositoryException e) {
1200: writeError("Failed to clear repository: " + e.getMessage());
1201: logger.error("Failed to clear repository", e);
1202: }
1203: }
1204:
1205: private void evaluateQuery(QueryLanguage ql, String queryString) {
1206: try {
1207: queryString = addQueryPrefixes(ql, queryString);
1208: ParsedQuery query = QueryParserUtil.parseQuery(ql,
1209: queryString, null);
1210: if (query instanceof ParsedTupleQuery) {
1211: evaluateTupleQuery(ql, queryString);
1212: } else if (query instanceof ParsedGraphQuery) {
1213: evaluateGraphQuery(ql, queryString);
1214: } else if (query instanceof ParsedBooleanQuery) {
1215: evaluateBooleanQuery(ql, queryString);
1216: } else {
1217: writeError("Unexpected query type");
1218: }
1219: } catch (UnsupportedQueryLanguageException e) {
1220: writeError("Unsupported query lanaguge: " + ql.getName());
1221: } catch (MalformedQueryException e) {
1222: writeError("Malformed query: " + e.getMessage());
1223: } catch (QueryEvaluationException e) {
1224: writeError("Query evaluation error: " + e.getMessage());
1225: logger.error("Query evaluation error", e);
1226: } catch (RepositoryException e) {
1227: writeError("Failed to evaluate query: " + e.getMessage());
1228: logger.error("Failed to evaluate query", e);
1229: }
1230: }
1231:
1232: private String addQueryPrefixes(QueryLanguage ql, String queryString) {
1233: String result = queryString;
1234:
1235: if (repository != null && queryPrefix) {
1236: // FIXME this is a bit of a sloppy hack, a better way would be to
1237: // explicitly provide the query parser with namespace mappings in
1238: // advance.
1239: if ((SERQL.equals(ql) && queryString.toLowerCase().indexOf(
1240: "using namespace ") == -1)
1241: || SPARQL.equals(ql)
1242: && !queryString.toLowerCase().startsWith("prefix")) {
1243: try {
1244: RepositoryConnection con = repository
1245: .getConnection();
1246: try {
1247: Collection<Namespace> namespaces = con
1248: .getNamespaces().asList();
1249:
1250: if (!namespaces.isEmpty()) {
1251: StringBuilder namespaceClause = new StringBuilder(
1252: 512);
1253:
1254: if (SERQL.equals(ql)) {
1255: namespaceClause
1256: .append(" USING NAMESPACE ");
1257:
1258: for (Namespace namespace : namespaces) {
1259: namespaceClause.append(namespace
1260: .getPrefix());
1261: namespaceClause.append(" = ");
1262: namespaceClause.append("<");
1263: namespaceClause.append(SeRQLUtil
1264: .encodeString(namespace
1265: .getName()));
1266: namespaceClause.append(">, ");
1267: }
1268:
1269: // Remove trailing ", "
1270: namespaceClause
1271: .setLength(namespaceClause
1272: .length() - 2);
1273:
1274: result += namespaceClause.toString();
1275: } else if (SPARQL.equals(ql)) {
1276: for (Namespace namespace : namespaces) {
1277: namespaceClause.append("PREFIX ");
1278: namespaceClause.append(namespace
1279: .getPrefix());
1280: namespaceClause.append(": ");
1281: namespaceClause.append("<");
1282: namespaceClause.append(SPARQLUtil
1283: .encodeString(namespace
1284: .getName()));
1285: namespaceClause.append("> ");
1286: }
1287:
1288: result = namespaceClause.toString()
1289: + result;
1290: }
1291: }
1292: } finally {
1293: con.close();
1294: }
1295: } catch (RepositoryException e) {
1296: writeError("Error connecting to repository: "
1297: + e.getMessage());
1298: logger.error("Error connecting to repository", e);
1299: }
1300: }
1301: }
1302:
1303: return result;
1304: }
1305:
1306: private void evaluateTupleQuery(QueryLanguage ql, String queryString)
1307: throws UnsupportedQueryLanguageException,
1308: MalformedQueryException, QueryEvaluationException,
1309: RepositoryException {
1310: if (repository == null) {
1311: writeError("please open a repository first");
1312: return;
1313: }
1314:
1315: RepositoryConnection con = repository.getConnection();
1316:
1317: try {
1318: writeln("Evaluating query...");
1319: long startTime = System.currentTimeMillis();
1320:
1321: Collection<Namespace> namespaces = con.getNamespaces()
1322: .addTo(new ArrayList<Namespace>());
1323:
1324: TupleQueryResult tupleQueryResult = con.prepareTupleQuery(
1325: ql, queryString).evaluate();
1326:
1327: try {
1328: int resultCount = 0;
1329: List<String> bindingNames = tupleQueryResult
1330: .getBindingNames();
1331:
1332: if (bindingNames.isEmpty()) {
1333: while (tupleQueryResult.hasNext()) {
1334: tupleQueryResult.next();
1335: resultCount++;
1336: }
1337: } else {
1338: int columnWidth = (consoleWidth - 1)
1339: / bindingNames.size() - 3;
1340:
1341: // Build table header
1342: StringBuilder sb = new StringBuilder(consoleWidth);
1343: for (String bindingName : bindingNames) {
1344: sb.append("| ").append(bindingName);
1345: StringUtil.appendN(' ', columnWidth
1346: - bindingName.length(), sb);
1347: }
1348: sb.append("|");
1349: String header = sb.toString();
1350:
1351: // Build separator line
1352: sb.setLength(0);
1353: for (int i = bindingNames.size(); i > 0; i--) {
1354: sb.append('+');
1355: StringUtil.appendN('-', columnWidth + 1, sb);
1356: }
1357: sb.append('+');
1358: String separatorLine = sb.toString();
1359:
1360: // Write table header
1361: writeln(separatorLine);
1362: writeln(header);
1363: writeln(separatorLine);
1364:
1365: // Write table rows
1366:
1367: while (tupleQueryResult.hasNext()) {
1368: BindingSet bindingSet = tupleQueryResult.next();
1369: resultCount++;
1370:
1371: sb.setLength(0);
1372: for (String bindingName : bindingNames) {
1373: Value value = bindingSet
1374: .getValue(bindingName);
1375: String valueStr = getStringRepForValue(
1376: value, namespaces);
1377:
1378: sb.append("| ").append(valueStr);
1379: StringUtil.appendN(' ', columnWidth
1380: - valueStr.length(), sb);
1381: }
1382: sb.append("|");
1383: writeln(sb.toString());
1384: }
1385:
1386: writeln(separatorLine);
1387: }
1388:
1389: long endTime = System.currentTimeMillis();
1390: writeln(resultCount + " result(s) ("
1391: + (endTime - startTime) + " ms)");
1392: } finally {
1393: tupleQueryResult.close();
1394: }
1395: } finally {
1396: con.close();
1397: }
1398: }
1399:
1400: private void evaluateGraphQuery(QueryLanguage ql, String queryString)
1401: throws UnsupportedQueryLanguageException,
1402: MalformedQueryException, QueryEvaluationException,
1403: RepositoryException {
1404: if (repository == null) {
1405: writeError("please open a repository first");
1406: return;
1407: }
1408:
1409: RepositoryConnection con = repository.getConnection();
1410:
1411: try {
1412: writeln("Evaluating query...");
1413: long startTime = System.currentTimeMillis();
1414:
1415: Collection<Namespace> namespaces = con.getNamespaces()
1416: .addTo(new ArrayList<Namespace>());
1417:
1418: GraphQueryResult queryResult = con.prepareGraphQuery(ql,
1419: queryString).evaluate();
1420:
1421: try {
1422: int resultCount = 0;
1423:
1424: while (queryResult.hasNext()) {
1425: Statement st = queryResult.next();
1426: resultCount++;
1427:
1428: write(getStringRepForValue(st.getSubject(),
1429: namespaces));
1430: write(" ");
1431: write(getStringRepForValue(st.getPredicate(),
1432: namespaces));
1433: write(" ");
1434: write(getStringRepForValue(st.getObject(),
1435: namespaces));
1436: writeln();
1437: }
1438:
1439: long endTime = System.currentTimeMillis();
1440: writeln(resultCount + " results ("
1441: + (endTime - startTime) + " ms)");
1442: } finally {
1443: queryResult.close();
1444: }
1445: } finally {
1446: con.close();
1447: }
1448: }
1449:
1450: private void evaluateBooleanQuery(QueryLanguage ql,
1451: String queryString)
1452: throws UnsupportedQueryLanguageException,
1453: MalformedQueryException, QueryEvaluationException,
1454: RepositoryException {
1455: if (repository == null) {
1456: writeError("please open a repository first");
1457: return;
1458: }
1459:
1460: RepositoryConnection con = repository.getConnection();
1461:
1462: try {
1463: writeln("Evaluating query...");
1464: long startTime = System.currentTimeMillis();
1465:
1466: boolean booleanQueryResult = con.prepareBooleanQuery(ql,
1467: queryString).evaluate();
1468:
1469: writeln("Answer: " + booleanQueryResult);
1470:
1471: long endTime = System.currentTimeMillis();
1472: writeln("Query evaluated in " + (endTime - startTime)
1473: + " ms");
1474: } finally {
1475: con.close();
1476: }
1477: }
1478:
1479: /**
1480: * @param namespace
1481: * @param namespaces
1482: * @return
1483: */
1484: private String getPrefixForNamespace(String namespace,
1485: Collection<Namespace> namespaces) {
1486: for (Namespace ns : namespaces) {
1487: if (namespace.equals(ns.getName())) {
1488: return ns.getPrefix();
1489: }
1490: }
1491: return null;
1492: }
1493:
1494: private String getStringRepForValue(Value value,
1495: Collection<Namespace> namespaces) {
1496: if (value == null) {
1497: return "";
1498: } else if (showPrefix && value instanceof URI) {
1499: URI uri = (URI) value;
1500:
1501: String prefix = getPrefixForNamespace(uri.getNamespace(),
1502: namespaces);
1503:
1504: if (prefix != null) {
1505: return prefix + ":" + uri.getLocalName();
1506: } else {
1507: return NTriplesUtil.toNTriplesString(value);
1508: }
1509: } else {
1510: return NTriplesUtil.toNTriplesString(value);
1511: }
1512: }
1513:
1514: private void printHelpSet() {
1515: writeln("Usage:");
1516: writeln("set Shows all parameter values");
1517: writeln("set width=<number> Set the width for query result tables");
1518: writeln("set log=<level> Set the logging level (none, error, warning, info or debug)");
1519: writeln("set showPrefix=<true|false> Toggles use of prefixed names in query results");
1520: writeln("set queryPrefix=<true|false> Toggles automatic use of known namespace prefixes in queries (warning: buggy!)");
1521: }
1522:
1523: private void setParameter(String[] tokens) {
1524: if (tokens.length == 1) {
1525: showParameters();
1526: } else if (tokens.length == 2) {
1527: String param = tokens[1];
1528:
1529: String key, value;
1530:
1531: int eqIdx = param.indexOf('=');
1532: if (eqIdx == -1) {
1533: key = param;
1534: value = null;
1535: } else {
1536: key = param.substring(0, eqIdx);
1537: value = param.substring(eqIdx + 1);
1538: }
1539:
1540: setParameter(key, value);
1541: } else {
1542: printHelpSet();
1543: }
1544: }
1545:
1546: private void showParameters() {
1547: setLog(null);
1548: setWidth(null);
1549: setShowPrefix(null);
1550: setQueryPrefix(null);
1551: }
1552:
1553: private void setParameter(String key, String value) {
1554: key = key.toLowerCase(Locale.ENGLISH);
1555:
1556: if ("log".equals(key)) {
1557: setLog(value);
1558: } else if ("width".equals(key)) {
1559: setWidth(value);
1560: } else if ("showprefix".equals(key)) {
1561: setShowPrefix(value);
1562: } else if ("queryprefix".equals(key)) {
1563: setQueryPrefix(value);
1564: } else {
1565: writeError("unknown parameter: " + key);
1566: }
1567: }
1568:
1569: private void setWidth(String value) {
1570: if (value == null) {
1571: writeln("width: " + consoleWidth);
1572: } else {
1573: try {
1574: int width = Integer.parseInt(value);
1575: if (width > 0) {
1576: consoleWidth = width;
1577: } else {
1578: writeError("Width must be larger than 0");
1579: }
1580: } catch (NumberFormatException e) {
1581: writeError("Width must be a positive number");
1582: }
1583: }
1584: }
1585:
1586: private void setLog(String value) {
1587: if (value == null) {
1588: Level currentLevel = jdkRootLogger.getLevel();
1589: String levelString = currentLevel.getName();
1590:
1591: for (Map.Entry<String, Level> entry : LOG_LEVELS.entrySet()) {
1592: if (entry.getValue().equals(currentLevel)) {
1593: levelString = entry.getKey();
1594: break;
1595: }
1596: }
1597:
1598: writeln("log: " + levelString);
1599: } else {
1600: Level logLevel = LOG_LEVELS.get(value.toLowerCase());
1601:
1602: if (logLevel != null) {
1603: jdkRootLogger.setLevel(logLevel);
1604: } else {
1605: writeError("unknown logging level: " + value);
1606: }
1607: }
1608: }
1609:
1610: private void setShowPrefix(String value) {
1611: if (value == null) {
1612: writeln("showPrefix: " + showPrefix);
1613: } else {
1614: showPrefix = Boolean.parseBoolean(value);
1615: }
1616: }
1617:
1618: private void setQueryPrefix(String value) {
1619: if (value == null) {
1620: writeln("queryPrefix: " + queryPrefix);
1621: } else {
1622: queryPrefix = Boolean.parseBoolean(value);
1623: }
1624: }
1625:
1626: private boolean askProceed(String msg, boolean defaultValue)
1627: throws IOException {
1628: String defaultString = defaultValue ? "yes" : "no";
1629:
1630: while (true) {
1631: writeln(msg);
1632: write("Proceed? (yes|no) [" + defaultString + "]: ");
1633: String reply = in.readLine();
1634:
1635: if ("no".equalsIgnoreCase(reply)
1636: || "no.".equalsIgnoreCase(reply)) {
1637: return false;
1638: } else if ("yes".equalsIgnoreCase(reply)
1639: || "yes.".equalsIgnoreCase(reply)) {
1640: return true;
1641: } else if (reply.trim().length() == 0) {
1642: return defaultValue;
1643: }
1644: }
1645: }
1646:
1647: /**
1648: * Reads multiple lines from the input until a line that ends with a '.' is
1649: * read.
1650: */
1651: private String readMultiLineInput() throws IOException {
1652: if (repositoryID != null) {
1653: write(repositoryID);
1654: }
1655: write("> ");
1656:
1657: String line = in.readLine();
1658: if (line == null) {
1659: // EOF
1660: return null;
1661: }
1662:
1663: StringBuilder buf = new StringBuilder(256);
1664: buf.append(line);
1665:
1666: while (line != null && !line.endsWith(".")) {
1667: line = in.readLine();
1668: buf.append('\n');
1669: buf.append(line);
1670: }
1671:
1672: // Remove closing dot
1673: buf.setLength(buf.length() - 1);
1674:
1675: return buf.toString().trim();
1676: }
1677:
1678: private void write(String s) {
1679: out.print(s);
1680: }
1681:
1682: private void writeln() {
1683: out.println();
1684: }
1685:
1686: private void writeln(String s) {
1687: out.println(s);
1688: }
1689:
1690: private void writeError(String errMsg) {
1691: writeln("ERROR: " + errMsg);
1692: }
1693:
1694: private void writeParseError(String prefix, int lineNo, int colNo,
1695: String msg) {
1696: StringBuilder sb = new StringBuilder(256);
1697:
1698: sb.append(prefix);
1699: sb.append(": ");
1700: sb.append(msg);
1701:
1702: String locationString = RDFParseException.getLocationString(
1703: lineNo, colNo);
1704: if (locationString.length() > 0) {
1705: sb.append(" ").append(locationString);
1706: }
1707:
1708: writeln(sb.toString());
1709: }
1710:
1711: class VerificationListener extends RDFHandlerBase implements
1712: ParseErrorListener {
1713:
1714: private int warnings;
1715:
1716: private int errors;
1717:
1718: private int statements;
1719:
1720: public int getWarnings() {
1721: return warnings;
1722: }
1723:
1724: public int getErrors() {
1725: return errors;
1726: }
1727:
1728: public int getStatements() {
1729: return statements;
1730: }
1731:
1732: public void handleStatement(Statement st)
1733: throws RDFHandlerException {
1734: statements++;
1735: }
1736:
1737: public void warning(String msg, int lineNo, int colNo) {
1738: warnings++;
1739: writeParseError("WARNING", lineNo, colNo, msg);
1740: }
1741:
1742: public void error(String msg, int lineNo, int colNo) {
1743: errors++;
1744: writeParseError("ERROR", lineNo, colNo, msg);
1745: }
1746:
1747: public void fatalError(String msg, int lineNo, int colNo) {
1748: errors++;
1749: writeParseError("FATAL ERROR", lineNo, colNo, msg);
1750: }
1751: }
1752: }
|