AbstractBindable.java
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.ostrichemulators.semtool.rdf.query.util;
import com.ostrichemulators.semtool.rdf.engine.api.Bindable;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import org.apache.log4j.Logger;
import org.openrdf.model.Literal;
import org.openrdf.model.Resource;
import org.openrdf.model.URI;
import org.openrdf.model.Value;
import org.openrdf.model.ValueFactory;
import org.openrdf.model.impl.URIImpl;
import org.openrdf.model.impl.ValueFactoryImpl;
import org.openrdf.query.Operation;
/**
* A class that handles all the housekeeping of the QueryExecutor interface
*
* @author ryan
*/
public abstract class AbstractBindable implements Bindable {
private static final Logger log = Logger.getLogger( AbstractBindable.class );
private final Map<String, Value> vmap = new LinkedHashMap<>();
private final Map<String, String> namespaces = new LinkedHashMap<>();
private final ValueFactory vf = new ValueFactoryImpl();
private String sparql;
private boolean infer = true;
private URI context;
public AbstractBindable() {
}
public AbstractBindable( String sparq ) {
sparql = sparq;
}
@Override
public void setContext( URI ctx ) {
context = ctx;
}
@Override
public URI getContext() {
return context;
}
@Override
public void setSparql( String sparq ) {
sparql = sparq;
}
/**
* Gets a reference to this Executor's namespace map.
*
* @return The reference (not a copy) to the namespace map
*/
@Override
public Map<String, String> getNamespaces() {
return namespaces;
}
/**
* Sets custom namespaces for use with the query. These namespaces take
* precedence over system- and user- defined namespaces, but not over
* namespaces explicitly set in the query itself.
*
* @param ns
*/
@Override
public void setNamespaces( Map<String, String> ns ) {
namespaces.clear();
addNamespaces( ns );
}
@Override
public void addNamespaces( Map<String, String> ns ) {
namespaces.putAll( ns );
}
@Override
public void addNamespace( String prefix, String namespace ) {
namespaces.put( prefix, namespace );
}
@Override
public void removeNamespace( String prefix ) {
namespaces.remove( prefix );
}
@Override
public String bindAndGetSparql() {
return getBoundSparql( sparql, vmap );
}
@Override
public AbstractBindable bindURI( String var, String uri ) {
try {
vmap.put( var, new URIImpl( uri ) );
}
catch ( Exception e ) {
log.error( "Could not parse uri: " + uri, e );
}
return this;
}
@Override
public AbstractBindable bindURI( String var, String basename, String localname ) {
try {
ValueFactory vfac = new ValueFactoryImpl();
vmap.put( var, vfac.createURI( basename, localname ) );
}
catch ( Exception e ) {
log.error( "Could not parse uri: " + basename + localname, e );
}
return this;
}
@Override
public String getSparql() {
return sparql;
}
@Override
public void setBindings( Operation tq, ValueFactory fac ) {
for ( Map.Entry<String, Value> en : vmap.entrySet() ) {
tq.setBinding( en.getKey(), en.getValue() );
}
}
@Override
public AbstractBindable bind( String var, String s ) {
vmap.put( var, vf.createLiteral( s ) );
return this;
}
@Override
public AbstractBindable bind( String var, Resource r ) {
vmap.put( var, r );
return this;
}
@Override
public AbstractBindable bind( String var, String s, String lang ) {
vmap.put( var, vf.createLiteral( s, lang ) );
return this;
}
@Override
public AbstractBindable bind( String var, double d ) {
vmap.put( var, vf.createLiteral( d ) );
return this;
}
@Override
public AbstractBindable bind( String var, int d ) {
vmap.put( var, vf.createLiteral( d ) );
return this;
}
@Override
public AbstractBindable bind( String var, Date d ) {
vmap.put( var, vf.createLiteral( getCal( d ) ) );
return this;
}
@Override
public AbstractBindable bind( String var, boolean d ) {
vmap.put( var, vf.createLiteral( d ) );
return this;
}
@Override
public AbstractBindable bind( String var, Value val ) {
vmap.put( var, val );
return this;
}
@Override
public Bindable unbind( String var ) {
vmap.remove( var );
return this;
}
@Override
public void clearBindings() {
vmap.clear();
}
@Override
public void useInferred( boolean b ) {
infer = b;
}
@Override
public boolean usesInferred() {
return infer;
}
@Override
public void done() {
}
@Override
public Map<String, Value> getBindingMap() {
return new LinkedHashMap<>( vmap );
}
@Override
public void setBindings( Map<String, Value> vals ) {
vmap.clear();
addBindings( vals );
}
@Override
public void addBindings( Map<String, Value> map ) {
vmap.putAll( map );
}
@Override
public String toString() {
return getSparql();
}
/**
* Gets the given sparql with VALUES clauses appended for the given bindings.
* This function does not cover all possible SPARQL, so please use with care
*
* @param sparql
* @param bindings
* @return
*/
public static String getBoundSparql( String sparql, Map<String, Value> bindings ) {
StringBuilder binds = new StringBuilder();
for ( Map.Entry<String, Value> en : bindings.entrySet() ) {
String var = en.getKey();
//Skip making a "VALUES" clause if the variable isn't in the query
Pattern pattern = Pattern.compile( "\\?" + var + "\\b" );
Matcher matcher = pattern.matcher( sparql );
if ( !matcher.find() ) {
continue;
}
Value v = en.getValue();
binds.append( " VALUES ?" ).append( var );
if ( v instanceof Literal ) {
binds.append( " {" ).append( en.getValue() ).append( "}" );
}
else {
binds.append( " {<" ).append( en.getValue() ).append( ">}" );
}
}
// I don't really want to write a Sparql parser, so just replace the last }
// with our VALUES statements. This will break on just about any complicated
// Sparql
int last = sparql.lastIndexOf( '}' );
if ( last > -1 ) {
String select = sparql.substring( 0, last );
String end = sparql.substring( last );
return select + binds.toString() + end;
}
else {
// no }, so just append the bindings (is this even valid?)
return sparql + binds.toString();
}
}
public static XMLGregorianCalendar getCal( Date date ) {
GregorianCalendar gCalendar = new GregorianCalendar();
gCalendar.setTime( date );
XMLGregorianCalendar xmlCalendar = null;
try {
xmlCalendar = DatatypeFactory.newInstance().newXMLGregorianCalendar( gCalendar );
}
catch ( DatatypeConfigurationException ex ) {
log.error( ex );
}
return xmlCalendar;
}
public static Date getDate( XMLGregorianCalendar cal ) {
return cal.toGregorianCalendar().getTime();
}
}