/** Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved. Contact: SYSTAP, LLC DBA Blazegraph 2501 Calvert ST NW #106 Washington, DC 20008 licenses@blazegraph.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package com.bigdata.rdf.sail.remote; import java.io.File; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.Properties; import org.openrdf.repository.sail.SailRepository; import org.openrdf.sail.Sail; import com.bigdata.rdf.sail.webapp.client.RemoteRepositoryManager; import com.bigdata.util.httpd.Config; /** * Helper class to create a bigdata instance. * * @author mikepersonick * * @see <a href="http://trac.bigdata.com/ticket/1152" > BigdataSailFactory must be * moved to the client package </a> */ public class BigdataSailFactory { /** * The default bigdata SAIL_PROVIDER. */ public static final String BIGDATA_SAIL_INSTANCE = "com.bigdata.rdf.sail.BigdataSail"; /** * The name of the property to set with the class that will provide the Sail. * * It must have a constructor that takes a single properties file as the parameter. */ public static final String SAIL_PROVIDER = "com.bigdata.rdf.sail.remote.Provider"; /** * A handy list of common Options you might want to specify when creating * your bigdata instance. * * @author mikepersonick * */ public static enum Option { /** * Inference on or off. Off by default. */ Inference, /** * Quads on or off. Off by default. */ Quads, /** * RDR (statement identifiers) on or off. Off by default. */ RDR, /** * Text index on or off. Off by default. */ TextIndex, // /** // * Create an in-memory instance. // */ // InMemory, // // /** // * Create a persistent instance backed by a file. You must specify // * the file. // */ // Persistent } /** * Connect to a remote bigdata instance. * * FIXME This does not parameterize the value of the ContextPath. See * {@link com.bigdata.BigdataStatics#getContextPath()}. */ public static BigdataSailRemoteRepository connect(final String host, final int port) { return connect("http://" + host + ":" + port + "/" + Config.BLAZEGRAPH_PATH); } /** * Connect to a remote bigdata instance. * * @param sparqlEndpointURL * The URL of the SPARQL end point. * * FIXME This does not support the HA load balancer pattern. See #1148. * * FIXME This does not parameterize the value of the ContextPath. See * {@link com.bigdata.BigdataStatics#getContextPath()}. * * FIXME This MIGHT leak HttpClient or Executor resources. */ public static BigdataSailRemoteRepository connect( final String sparqlEndpointURL) { return new RemoteRepositoryManager().getRepositoryForURL( sparqlEndpointURL).getBigdataSailRemoteRepository(); } /** * Convenience method to allow the testing of the URL normalization * functionality. * * @see <a href="http://trac.blazegraph.com/ticket/1139"> * BigdataSailFactory.connect() </a> */ @Deprecated // We are getting rid of this, right? public static String testServiceEndpointUrl(final String serviceEndpoint) { return normalizeEndpoint(serviceEndpoint); } /** * Massage the service endpoint to ensure that it ends with * </code>/blazegraph</code> */ @Deprecated // We are getting rid of this, right? static private String normalizeEndpoint(final String serviceEndpoint) { if (serviceEndpoint.endsWith("/sparql")) { return serviceEndpoint.substring(0, serviceEndpoint.length()-"/sparql".length()); } if (serviceEndpoint.endsWith("/sparql/")) { return serviceEndpoint.substring(0, serviceEndpoint.length()-"/sparql/".length()); } else if (serviceEndpoint.endsWith("/" + Config.BLAZEGRAPH_PATH + "/")) { return serviceEndpoint.substring(0, serviceEndpoint.length()-1) ; } else if (serviceEndpoint.endsWith("/" + Config.BLAZEGRAPH_PATH)) { return serviceEndpoint; } else if (serviceEndpoint.contains("/" + Config.BLAZEGRAPH_PATH) && serviceEndpoint.endsWith("/")) { // This is the case of /blazegraph/namespace/NAMESPACE/ return serviceEndpoint.substring(0, serviceEndpoint.length() - 1); } else if (serviceEndpoint.contains("/" + Config.BLAZEGRAPH_PATH)) { // This is the case of /blazegraph/namespace/NAMESPACE return serviceEndpoint; } else if (serviceEndpoint.endsWith("/")) { return serviceEndpoint + Config.BLAZEGRAPH_PATH; } else { return serviceEndpoint + "/" + Config.BLAZEGRAPH_PATH; } } /** * Open an existing persistent bigdata instance. If a journal does * not exist at the specified location then an exception will be thrown. */ public static SailRepository openRepository(final String file) { return new SailRepository(openSail(file, false)); } /** * Open an existing persistent bigdata instance. If a journal does * not exist at the specified location and the boolean create flag is true * a journal will be created at that location with the default set of * options. */ public static SailRepository openRepository(final String file, final boolean create) { return new SailRepository(openSail(file, create)); } /** * Open an existing persistent bigdata instance. If a journal does * not exist at the specified location then an exception will be thrown. */ public static Sail openSail(final String file) { return openSail(file, false); } /** * Open an existing persistent bigdata instance. If a journal does * not exist at the specified location and the boolean create flag is true * a journal will be created at that location with the default set of * options. */ public static Sail openSail(final String file, final boolean create) { if (!new File(file).exists()) { if (!create) { throw new IllegalArgumentException("journal does not exist at specified location"); } else { return createSail(file); } } else { final Properties props = new Properties(); props.setProperty("com.bigdata.journal.AbstractJournal.file", file); final Sail sail = getSailProviderInstance(props); return sail; } } /** * Create a new bigdata instance using the specified options. Since no * journal file is specified this must be an in-memory instance. */ public static SailRepository createRepository(final Option... args) { return createRepository(new Properties(), null, args); } /** * Create a new bigdata instance using the specified options. Since no * journal file is specified this must be an in-memory instance. */ public static SailRepository createRepository(final Properties props, final Option... args) { return createRepository(props, null, args); } /** * Create a new bigdata instance using the specified options. */ public static SailRepository createRepository(final String file, final Option... args) { return createRepository(new Properties(), file, args); } /** * Create a new bigdata instance using the specified options. Since no * journal file is specified this must be an in-memory instance. */ public static SailRepository createRepository(final Properties props, final String file, final Option... args) { return new SailRepository(createSail(props, file, args)); } /** * Create a new bigdata instance using the specified options. Since no * journal file is specified this must be an in-memory instance. */ public static Sail createSail(final Option... args) { return createSail(new Properties(), null, args); } /** * Create a new bigdata instance using the specified options and filename. */ public static Sail createSail(final String file, final Option... args) { //Ticket #1185: BigdataGraphFactory create not working. return createSail(new Properties(), file, args); } /** * Create a new bigdata instance using the specified options. */ public static Sail createSail(final Properties props, final String file, final Option... args) { final List<Option> options = args != null ? Arrays.asList(args) : new LinkedList<Option>(); checkArgs(file, options); // final Properties props = new Properties(); //FIXME: Changed these to String Values to remove package / artifact dependency /* if (file != null) { props.setProperty(BigdataSail.Options.FILE, file); props.setProperty(Journal.Options.BUFFER_MODE, BufferMode.DiskRW.toString()); } else { props.setProperty(Journal.Options.BUFFER_MODE, BufferMode.MemStore.toString()); } if (options.contains(Option.Inference)) { props.setProperty(BigdataSail.Options.AXIOMS_CLASS, OwlAxioms.class.getName()); props.setProperty(BigdataSail.Options.TRUTH_MAINTENANCE, "true"); props.setProperty(BigdataSail.Options.JUSTIFY, "true"); } else { props.setProperty(BigdataSail.Options.AXIOMS_CLASS, NoAxioms.class.getName()); props.setProperty(BigdataSail.Options.TRUTH_MAINTENANCE, "false"); props.setProperty(BigdataSail.Options.JUSTIFY, "false"); } props.setProperty(BigdataSail.Options.TEXT_INDEX, String.valueOf(options.contains(Option.TextIndex))); props.setProperty(BigdataSail.Options.STATEMENT_IDENTIFIERS, String.valueOf(options.contains(Option.RDR))); props.setProperty(BigdataSail.Options.QUADS, String.valueOf(options.contains(Option.Quads))); */ if (file != null) { props.setProperty("com.bigdata.journal.AbstractJournal.file", file); props.setProperty("com.bigdata.journal.AbstractJournal.bufferMode", "DiskRW"); } else { props.setProperty("com.bigdata.journal.AbstractJournal.bufferMode", "MemStore"); } if (options.contains(Option.Inference)) { props.setProperty("com.bigdata.rdf.store.AbstractTripleStore.axiomsClass","com.bigdata.rdf.axioms.OwlAxioms"); props.setProperty("com.bigdata.rdf.sail.truthMaintenance","true"); props.setProperty("com.bigdata.rdf.store.AbstractTripleStore.justify", "true"); } else { props.setProperty("com.bigdata.rdf.store.AbstractTripleStore.axiomsClass","com.bigdata.rdf.axioms.NoAxioms"); props.setProperty("com.bigdata.rdf.sail.truthMaintenance","false"); props.setProperty("com.bigdata.rdf.store.AbstractTripleStore.justify", "false"); } props.setProperty("com.bigdata.rdf.store.AbstractTripleStore.textIndex", String.valueOf(options.contains(Option.TextIndex))); props.setProperty("com.bigdata.rdf.store.AbstractTripleStore.statementIdentifiers", String.valueOf(options.contains(Option.RDR))); props.setProperty("com.bigdata.rdf.store.AbstractTripleStore.quads", String.valueOf(options.contains(Option.Quads))); // Setup for the RWStore recycler rather than session protection. props.setProperty("com.bigdata.service.AbstractTransactionService.minReleaseAge","1"); props.setProperty("com.bigdata.btree.writeRetentionQueue.capacity","4000"); props.setProperty("com.bigdata.btree.BTree.branchingFactor","128"); // Bump up the branching factor for the lexicon indices on the default kb. props.setProperty("com.bigdata.namespace.kb.lex.com.bigdata.btree.BTree.branchingFactor","400"); // Bump up the branching factor for the statement indices on the default kb. props.setProperty("com.bigdata.namespace.kb.spo.com.bigdata.btree.BTree.branchingFactor","1024"); final Sail sail = getSailProviderInstance(props); return sail; } protected static Sail getSailProviderInstance(Properties props) { final String providerClass = System.getProperty(SAIL_PROVIDER, BIGDATA_SAIL_INSTANCE); try { final Class<?> c = Class.forName(providerClass); final Constructor<?> cons = c.getConstructor(Properties.class); final Object object = cons.newInstance(props); final Sail proxy = (Sail) object; return proxy; } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { throw new RuntimeException(e); } } protected static void checkArgs(final String file, final List<Option> options) { if (options.contains(Option.Inference) && options.contains(Option.Quads)) { throw new IllegalArgumentException(); } if (options.contains(Option.RDR) && options.contains(Option.Quads)) { throw new IllegalArgumentException(); } // if (options.contains(Option.InMemory) && options.contains(Option.Persistent)) { // throw new IllegalArgumentException(); // } // // if (options.contains(Option.InMemory) && file != null) { // throw new IllegalArgumentException(); // } // // if (options.contains(Option.Persistent) && file == null) { // throw new IllegalArgumentException(); // } } }