001: /*
002: * Copyright Aduna (http://www.aduna-software.com/) (c) 1997-2006.
003: *
004: * Licensed under the Aduna BSD-style license.
005: */
006: package org.openrdf.query.algebra.evaluation;
007:
008: import java.util.Collection;
009: import java.util.HashMap;
010: import java.util.Iterator;
011: import java.util.Map;
012: import java.util.Set;
013:
014: import info.aduna.collections.iterators.ConvertingIterator;
015:
016: import org.openrdf.model.Value;
017: import org.openrdf.query.Binding;
018: import org.openrdf.query.BindingSet;
019: import org.openrdf.query.impl.BindingImpl;
020: import org.openrdf.query.impl.MapBindingSet;
021:
022: /**
023: * An implementation of the {@link BindingSet} interface that is used to evalate
024: * query object models. This implementations differs from {@link MapBindingSet}
025: * in that it maps variable names to Value objects and that the Binding objects
026: * are created lazily.
027: */
028: public class QueryBindingSet implements BindingSet {
029:
030: /*-----------*
031: * Variables *
032: *-----------*/
033:
034: private Map<String, Value> bindings;
035:
036: /*--------------*
037: * Constructors *
038: *--------------*/
039:
040: public QueryBindingSet() {
041: this (8);
042: }
043:
044: public QueryBindingSet(int capacity) {
045: // Create bindings map with some extra space for new bindings and
046: // compensating for HashMap's load factor
047: bindings = new HashMap<String, Value>(capacity * 2);
048: }
049:
050: public QueryBindingSet(BindingSet bindingSet) {
051: this (bindingSet.size());
052: addAll(bindingSet);
053: }
054:
055: /*---------*
056: * Methods *
057: *---------*/
058:
059: public void addAll(BindingSet bindingSet) {
060: if (bindingSet instanceof QueryBindingSet) {
061: bindings.putAll(((QueryBindingSet) bindingSet).bindings);
062: } else {
063: for (Binding binding : bindingSet) {
064: this .addBinding(binding);
065: }
066: }
067: }
068:
069: /**
070: * Adds a new binding to the solution. The binding's name must not already be
071: * part of this solution.
072: *
073: * @param binding
074: * The binding to add this this BindingSet.
075: */
076: public void addBinding(Binding binding) {
077: addBinding(binding.getName(), binding.getValue());
078: }
079:
080: /**
081: * Adds a new binding to the solution. The binding's name must not already be
082: * part of this solution.
083: *
084: * @param name
085: * The binding's name, must not be bound in this solution already.
086: * @param value
087: * The binding's value.
088: */
089: public void addBinding(String name, Value value) {
090: assert !bindings.containsKey(name) : "variable already bound: "
091: + name;
092: setBinding(name, value);
093: }
094:
095: public void setBinding(Binding binding) {
096: setBinding(binding.getName(), binding.getValue());
097: }
098:
099: public void setBinding(String name, Value value) {
100: assert value != null : "null value for variable " + name;
101: bindings.put(name, value);
102: }
103:
104: public void removeBinding(String name) {
105: bindings.remove(name);
106: }
107:
108: public void removeAll(Collection<String> bindingNames) {
109: bindings.keySet().removeAll(bindingNames);
110: }
111:
112: public void retainAll(Collection<String> bindingNames) {
113: bindings.keySet().retainAll(bindingNames);
114: }
115:
116: public Set<String> getBindingNames() {
117: return bindings.keySet();
118: }
119:
120: public Value getValue(String bindingName) {
121: return bindings.get(bindingName);
122: }
123:
124: public Binding getBinding(String bindingName) {
125: Value value = getValue(bindingName);
126:
127: if (value != null) {
128: return new BindingImpl(bindingName, value);
129: }
130:
131: return null;
132: }
133:
134: public boolean hasBinding(String bindingName) {
135: return bindings.containsKey(bindingName);
136: }
137:
138: public Iterator<Binding> iterator() {
139: Iterator<Map.Entry<String, Value>> entries = bindings
140: .entrySet().iterator();
141:
142: return new ConvertingIterator<Map.Entry<String, Value>, Binding>(
143: entries) {
144:
145: @Override
146: protected Binding convert(Map.Entry<String, Value> entry) {
147: return new BindingImpl(entry.getKey(), entry.getValue());
148: }
149: };
150: }
151:
152: public int size() {
153: return bindings.size();
154: }
155:
156: @Override
157: public boolean equals(Object other) {
158: if (this == other) {
159: return true;
160: } else if (other instanceof QueryBindingSet) {
161: return bindings.equals(((QueryBindingSet) other).bindings);
162: } else if (other instanceof BindingSet) {
163: int otherSize = 0;
164:
165: // Compare other's bindings to own
166: for (Binding binding : (BindingSet) other) {
167: Value ownValue = getValue(binding.getName());
168:
169: if (!binding.getValue().equals(ownValue)) {
170: // Unequal bindings for this name
171: return false;
172: }
173:
174: otherSize++;
175: }
176:
177: // All bindings have been matched, sets are equal if this solution
178: // doesn't have any additional bindings.
179: return otherSize == bindings.size();
180: }
181:
182: return false;
183: }
184:
185: @Override
186: public int hashCode() {
187: int hashCode = 0;
188:
189: for (Map.Entry<String, Value> entry : bindings.entrySet()) {
190: hashCode ^= entry.getKey().hashCode()
191: ^ entry.getValue().hashCode();
192: }
193:
194: return hashCode;
195: }
196:
197: @Override
198: public String toString() {
199: StringBuilder sb = new StringBuilder(32 * size());
200:
201: sb.append('[');
202:
203: Iterator<Binding> iter = iterator();
204: while (iter.hasNext()) {
205: sb.append(iter.next().toString());
206: if (iter.hasNext()) {
207: sb.append(';');
208: }
209: }
210:
211: sb.append(']');
212:
213: return sb.toString();
214: }
215: }
|