/*
* Copyright (c) 2009, SQL Power Group Inc.
*
* This file is part of SQL Power Library.
*
* SQL Power Library 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; either version 3 of the License, or
* (at your option) any later version.
*
* SQL Power Library 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, see <http://www.gnu.org/licenses/>.
*/
package ca.sqlpower.object;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.apache.commons.collections.map.MultiValueMap;
/**
* This is a default implementation of a variable resolver the {@link SPObject}
* implementations can use. It implements the {@link SPVariableResolver}
* and you can use it to store variables.
*
* <p>It is backed by a MultiMap object. Keep that in mind ;)
*
* @see {@link SPVariableResolver}
* @author Luc Boudreau
*
*/
public class SPSimpleVariableResolver implements SPVariableResolver {
protected final MultiValueMap variables = new MultiValueMap();
private String namespace = null;
private String userFriendlyName;
private final SPObject owner;
public SPSimpleVariableResolver(SPObject owner, String namespace, String userFriendlyName) {
this(owner, namespace, userFriendlyName, true);
}
public SPSimpleVariableResolver(
SPObject owner,
String namespace,
String userFriendlyName,
boolean register)
{
this.owner = owner;
this.namespace = namespace;
this.userFriendlyName = userFriendlyName;
if (register) {
SPResolverRegistry.register(owner, this);
}
}
/**
* This is a hook method that sub classes can override. It gets called
* before all lookup operations (resolve, match and resolves).
* @param key The key we were asked to lookup info on.
*/
protected void beforeLookups(String key) {
// Nothing to do here. Only sub-classes implement this.
}
/**
* This is a hook method that sub classes can override. It gets called
* before the keySet operation.
* @param namespace The namespace we were asked to lookup info on.
*/
protected void beforeKeyLookup(String namespace) {
// Nothing to do here. Only sub-classes implement this.
}
/**
* Defines this variable resolver's namespace.
* @param namespace The namespace to use. Can be null.
*/
public void setNamespace(String namespace) {
this.namespace = namespace;
}
/**
* Clears all currently stored variables.
*/
public void clear() {
this.variables.clear();
}
/**
* Closes this resolver and removes it from the registry
*/
public void cleanup() {
SPResolverRegistry.deregister(owner, this);
this.clear();
}
public void store(String key, Object value) {
if (this.namespace != null
&& SPVariableHelper.getNamespace(key) != null
&& !this.namespace.equals(SPVariableHelper.getNamespace(key))) {
throw new IllegalArgumentException("Cannot store a namespaced variable of a different namespace than this resolver is configured with.");
}
this.variables.put(SPVariableHelper.getKey(key), value);
}
public void update(String key, Object value) {
if (this.variables.containsKey(SPVariableHelper.getKey(key))) {
this.variables.remove(SPVariableHelper.getKey(key));
}
this.variables.put(SPVariableHelper.getKey(key), value);
}
public void delete(String key) {
this.variables.remove(SPVariableHelper.getKey(key));
}
public Collection<Object> matches(String key, String partialValue) {
// Call the subclass hook.
this.beforeLookups(key);
String namespace = SPVariableHelper.getNamespace(key);
if (this.resolvesNamespace(namespace)) {
Set<Object> matches = new HashSet<Object>();
Collection<Object> values = this.resolveCollection(key);
for (Object obj : values) {
String stringRep = obj.toString();
if (stringRep.startsWith(partialValue)) {
matches.add(obj);
}
}
return matches;
}
return Collections.emptySet();
}
public Object resolve(String key) {
return this.resolve(key, null);
}
public Object resolve(String key, Object defaultValue) {
// Call the subclass hook.
this.beforeLookups(key);
String namespace = SPVariableHelper.getNamespace(key);
if (this.resolvesNamespace(namespace)) {
Collection<Object> value = this.variables.getCollection(SPVariableHelper.getKey(key));
if (value == null || value.size() == 0) {
return defaultValue;
} else {
return value.iterator().next();
}
} else {
return defaultValue;
}
}
public Collection<Object> resolveCollection(String key) {
return this.resolveCollection(key, null);
}
public Collection<Object> resolveCollection(String key, Object defaultValue) {
// Call the subclass hook.
this.beforeLookups(key);
String namespace = SPVariableHelper.getNamespace(key);
if (this.resolvesNamespace(namespace)) {
Collection<Object> value = this.variables.getCollection(SPVariableHelper.getKey(key));
if (value != null) {
return value;
}
}
return Collections.singleton(defaultValue);
}
public boolean resolves(String key) {
// Call the subclass hook.
this.beforeLookups(key);
String namespace = SPVariableHelper.getNamespace(key);
if (this.resolvesNamespace(namespace)) {
return this.variables.containsKey(SPVariableHelper.getKey(key));
}
return false;
}
public boolean resolvesNamespace(String namespace) {
if (namespace == null) {
return true;
}
return namespace.equals(this.namespace);
}
public Collection<String> keySet(String namespace) {
// Call the subclass hook.
this.beforeKeyLookup(namespace);
if (this.resolvesNamespace(namespace)) {
if (this.namespace == null) {
return this.variables.keySet();
} else {
Set<String> keys = new HashSet<String>();
for (Object key : this.variables.keySet()) {
keys.add(this.namespace.concat(NAMESPACE_DELIMITER).concat(key.toString()));
}
return keys;
}
}
return Collections.emptySet();
}
public String getNamespace() {
return this.namespace;
}
public String getUserFriendlyName() {
return this.userFriendlyName;
}
public void setUserFriendlyName(String userFriendlyName) {
this.userFriendlyName = userFriendlyName;
}
}