package org.aksw.jena_sparql_api.views;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.aksw.commons.collections.multimaps.BiHashMultimap;
import org.aksw.commons.collections.multimaps.IBiSetMultimap;
import org.aksw.jena_sparql_api.utils.QuadUtils;
import org.apache.jena.graph.Node;
import org.apache.jena.sparql.core.Quad;
import org.apache.jena.sparql.core.Var;
class BindingVal
extends VarConst<Var, Node>
{
public BindingVal() {
super();
}
public BindingVal(Set<Var> keys, Node value) {
super(keys, value);
}
}
/**
* A variable binding maps query vars to sets of view variables.
*
*
*
*
* @author Claus Stadler <cstadler@informatik.uni-leipzig.de>
*
*/
public class VarBinding {
private Map<Var, Integer> keyToToken = new HashMap<Var, Integer>();
private Map<Var, Integer> valueToToken = new HashMap<Var, Integer>();
private Map<Integer, BindingVal> tokenToSet = new HashMap<Integer, BindingVal>();
//private Map<Integer, Node> tokenToValue = new HashMap<Integer, Node>();
private int nextToken;
public VarBinding() {
}
public Map<Var, Node> getQueryVarToConstant() {
Map<Var, Node> result = new HashMap<Var, Node>();
for(Entry<Var, Integer> entry : keyToToken.entrySet()) {
Var value = entry.getKey();
Integer token = entry.getValue();
BindingVal val = tokenToSet.get(token);
Node constant = val.getValue();
result.put(value, constant);
}
return result;
}
public IBiSetMultimap<Var, Var> getQueryVarToViewVars() {
IBiSetMultimap<Var, Var> result = new BiHashMultimap<Var, Var>();
for(Entry<Var, Integer> entry : keyToToken.entrySet()) {
Var value = entry.getKey();
Integer token = entry.getValue();
BindingVal val = tokenToSet.get(token);
Set<Var> keys = val.getKeys();
result.putAll(value, keys);
}
return result;
}
/*
* Return a mapping from view to query vars
*
*/
public IBiSetMultimap<Var, Var> getViewVarToQueryVars() {
IBiSetMultimap<Var, Var> tmp = getQueryVarToViewVars();
IBiSetMultimap<Var, Var> result = tmp.getInverse();
return result;
/*
Multimap<Var, Var> result = HashMultimap.create();
for(Entry<Var, Integer> entry : valueToToken.entrySet()) {
Var value = entry.getKey();
Integer token = entry.getValue();
BindingVal val = tokenToSet.get(token);
Set<Var> keys = val.getKeys();
result.putAll(value, keys);
}
return result;
*/
}
public Set<Var> getQueryVars() {
return keyToToken.keySet();
}
public Set<Var> getViewVars(Var queryVar) {
BindingVal tmp = get(queryVar);
if(tmp == null) {
return null;
}
return tmp.getKeys();
}
public Node getConstant(Var queryVar) {
BindingVal tmp = get(queryVar);
if(tmp == null) {
return null;
}
return tmp.getValue();
}
public BindingVal get(Var queryVar) {
Integer token = keyToToken.get(queryVar);
if(token == null) {
return null;
}
BindingVal result = tokenToSet.get(token);
return result;
}
/*
public VarBinding(IBiSetMultimap<Var, Var> queryVarToViewVars) {
this.queryVarToViewVars = queryVarToViewVars;
}
*/
/*
public boolean putAll(VarBinding other) {
for(other.ge)
}
*/
public boolean put(Var queryVar, Var viewVar) {
Integer keyToken = keyToToken.get(queryVar);
Integer valueToken = valueToToken.get(viewVar);
if(valueToken == null) {
if(keyToken == null) {
Integer token = nextToken++;
valueToToken.put(viewVar, token);
keyToToken.put(queryVar, token);
BindingVal val = new BindingVal();
val.getKeys().add(viewVar);
tokenToSet.put(token, val);
} else {
// The value already exists - point the key to the token
valueToToken.put(viewVar, keyToken);
BindingVal val = tokenToSet.get(keyToken);
val.getKeys().add(viewVar);
}
} else {
if(keyToken == null) {
// The value exists, but has not yet been associated with the key
keyToToken.put(queryVar, valueToken);
} else {
if(keyToken.equals(valueToken)) {
return true;
}
// Merge both the key and value token things
BindingVal a = tokenToSet.get(keyToken);
BindingVal b = tokenToSet.get(valueToken);
Node valA = a.getValue();
Node valB = b.getValue();
Node res = valA == null ? valB : valB;
if(valB != null && valB != res) {
return false;
}
a.setValue(res);
for(Var vv : b.getKeys()) {
valueToToken.put(vv, keyToken);
}
tokenToSet.remove(valueToken);
a.getKeys().addAll(b.getKeys());
}
}
return true;
}
public boolean put(Var queryVar, Node node) {
if(node == null) {
return true;
} else if(node.isVariable()) {
return put(queryVar, (Var)node);
}
Integer token = keyToToken.get(queryVar);
if(token == null) {
token = nextToken++;
keyToToken.put(queryVar, token);
BindingVal val = new BindingVal();
tokenToSet.put(token, val);
val.setValue(node);
return true;
} else {
BindingVal val = tokenToSet.get(token);
Node existing = val.getValue();
if(existing == null) {
val.setValue(node);
return true;
} else if(existing.equals(node)) {
return true;
} else {
return false;
}
}
}
public void putAll(VarBinding that) {
for(Entry<Var, Var> entry : that.getQueryVarToViewVars().entries()) {
this.put(entry.getKey(), entry.getValue());
}
for(Entry<Var, Node> entry : that.getQueryVarToConstant().entrySet()) {
this.put(entry.getKey(), entry.getValue());
}
}
public static VarBinding create(Quad a, Quad b)
{
VarBinding result = new VarBinding();
List<Node> nAs = QuadUtils.quadToList(a);
List<Node> nBs = QuadUtils.quadToList(b);
for(int i = 0; i < 4; ++i) {
Var nA = (Var)nAs.get(i);
Node nB = nBs.get(i);
if(!result.put(nA, nB)) {
return null;
}
}
return result;
}
@Override
public String toString() {
String result = "{";
boolean isFirst = true;
for(Entry<Var, Integer> entry : keyToToken.entrySet()) {
Var key = entry.getKey();
Integer token = entry.getValue();
BindingVal val = tokenToSet.get(token);
if(isFirst) {
isFirst = false;
} else {
result += ", ";
}
result += key + ": (" + token + ")" + val;
}
result += "}";
return result;
//return "keyToToken: " + keyToToken + ", tokenToSet:" + tokenToSet;
}
/*
public Set<Var> getQueryVars() {
return queryVarToViewVars.asMap().keySet();
}
public Set<Var> get(Var queryVar) {
return queryVarToViewVars.get(queryVar);
}
public IBiSetMultimap<Var, Var> getMap()
{
return queryVarToViewVars;
}
public VarBinding computeClosure() {
Map<Var, Set<Var>> state = new HashMap<Var, Set<Var>>();
// Invert the binding: For the set of viewVars, get the set of queryVars that map to them
IBiSetMultimap<Var, Var> viewVarsToQueryVars = queryVarToViewVars.getInverse();
for(Entry<Var, Collection<Var>> entry : queryVarToViewVars.asMap().entrySet()) {
Var queryVar = entry.getKey(); //open.iterator().next();
Collection<Var> viewVars = entry.getValue();
// Re-use a corresponding viewVar-set
// in the state, otherwise create a new one
Set<Var> mergedViewVars = state.get(queryVar);
if(mergedViewVars == null) {
mergedViewVars = new HashSet<Var>(viewVars);
}
for(Var viewVar : viewVars) {
Set<Var> queryVarsB = viewVarsToQueryVars.get(viewVar);
for(Var queryVarB : queryVarsB) {
if(queryVarB.equals(queryVar)) {
continue;
}
Set<Var> viewVarsC = state.get(queryVarB);
// A viewVars set might not exist for a key yet
if(viewVarsC == null) {
viewVarsC = queryVarToViewVars.get(queryVarB);
}
mergedViewVars.addAll(viewVarsC);
state.put(queryVarB, mergedViewVars);
}
}
}
// OPTIMIZE: Use some batch function for this - or at least hide the complexity here
IBiSetMultimap<Var, Var> map = new BiHashMultimap<Var, Var>();
for(Entry<Var, Set<Var>> entry : state.entrySet()) {
Var queryVar = entry.getKey();
for(Var viewVar : entry.getValue()) {
map.put(queryVar, viewVar);
}
}
VarBinding result = new VarBinding(map);
return result;
}
// public static <K, V> Set<V> getAll(Collection<K> keys, IBiSetMultimap<K, V> map) {
// Set<V> result
// }
/*
public Set<Var> getEquivalences(Var key, boolean reflexiv)
{
Set<Var> result = MultimapUtils.transitiveGetBoth(queryVarToViewVars, key);
if(reflexiv) {
result.add(key);
}
return result;
}
public Set<Var> getAllEquivalences(Collection<Var> keys, boolean reflexiv)
{
Set<Var> result = new HashSet<Var>();
Set<Var> open = new HashSet<Var>(keys);
while(!open.isEmpty()) {
Var key = open.iterator().next();
open.remove(key);
Set<Var> equivs = getEquivalences(key, reflexiv);
open.removeAll(equivs);
result.addAll(equivs);
}
return result;
}
* /
@Override
public String toString() {
return "" + queryVarToViewVars;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime
* result
+ ((queryVarToViewVars == null) ? 0 : queryVarToViewVars
.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
VarBinding other = (VarBinding) obj;
if (queryVarToViewVars == null) {
if (other.queryVarToViewVars != null)
return false;
} else if (!queryVarToViewVars.equals(other.queryVarToViewVars))
return false;
return true;
}
*/
}