/*
* #!
* Ontopia Navigator
* #-
* Copyright (C) 2001 - 2013 The Ontopia Project
* #-
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* !#
*/
package net.ontopia.topicmaps.nav2.impl.basic;
import java.util.Map;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Stack;
import java.util.Collection;
import java.util.Collections;
import javax.servlet.jsp.PageContext;
import net.ontopia.topicmaps.nav2.core.ContextManagerIF;
import net.ontopia.topicmaps.nav2.core.VariableNotSetException;
import net.ontopia.topicmaps.nav2.impl.framework.InteractionELSupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* INTERNAL: Default Implementation of ContextManagerIF.
*/
public class ContextManager implements ContextManagerIF {
// initialization of logging facility
private static Logger log = LoggerFactory
.getLogger(ContextManager.class.getName());
/**
* INTERNAL: Name of the default value key which is needed by the
* maps stored in the <code>ContextManager</code> scope-stacks.
*/
private static final String DEFAULT_VALUE_KEY = "@@DEFAULT@@";
/** Stack which contains the lexical scope */
private Stack scopes;
/** Current scoped set of variables (equivalent to peeking on stack) */
private Map values;
/** Reference to page context so we can look things up there */
private PageContext pageContext;
public ContextManager(PageContext pageContext) {
// initialize root scope
scopes = new Stack();
pushScope();
this.pageContext = pageContext;
}
// ------------------------------------------------------------------
// implementation of ContextManagerIF interface
// ------------------------------------------------------------------
public Collection getValue(String name) throws VariableNotSetException {
// remove prefix (if there)
name = cutoffPre(name);
Object result = _getValue(name);
if (result == null)
throw new VariableNotSetException(name);
else
return (Collection)result;
}
public Collection getValue(String name, Collection defaultValue) {
// remove prefix (if there)
name = cutoffPre(name);
Object result = _getValue(name);
if (result == null)
return defaultValue;
else
return (Collection)result;
}
/**
* INTERNAL: Helper method that does the actual variable value
* lookup.
*/
private Object _getValue(String name) {
// first search in current lexical scope for value
if (values.containsKey(name)) {
return values.get(name);
} else {
// try to retrieve value from ancestor scope
if (scopes.size() > 1) {
for (int i = scopes.size()-2; i >= 0; i--) {
Map ancestorValues = (Map)scopes.elementAt(i);
if (ancestorValues != null && ancestorValues.containsKey(name))
return ancestorValues.get(name);
} // for
}
// we still haven't found anything. try pageContext
Object v = InteractionELSupport.getValue(name, pageContext);
if (v == null || v instanceof Collection)
return v;
else
return Collections.singleton(v);
}
}
public void setValue(String name, Collection coll) {
values.put(cutoffPre(name), coll);
}
public void setValueInScope(Object scope, String name, Collection coll) {
int index = ((Integer) scope).intValue();
if (index >= 0) {
Map currValues = (Map) scopes.get(index);
currValues.put(cutoffPre(name), coll);
scopes.set(index, currValues);
} else
log.warn("Cannot set value for variable '" + name + "', because " +
"couldn't find scope.");
}
public void setValue(String name, Object obj) {
if (obj == null) return;
if (obj instanceof Collection)
setValue(name, (Collection) obj);
else
values.put(cutoffPre(name), Collections.singleton(obj));
}
public Collection getDefaultValue() {
return (Collection)_getValue(DEFAULT_VALUE_KEY);
}
public void setDefaultValue(Collection coll) {
setValue(DEFAULT_VALUE_KEY, coll);
}
public void setDefaultValue(Object obj) {
setValue(DEFAULT_VALUE_KEY, obj);
}
public Object getCurrentScope() {
return new Integer(scopes.size()-1);
}
public void pushScope() {
values = new HashMap();
scopes.push(values);
}
public void popScope() {
scopes.pop();
// get old values back from top of stack
values = (Map) scopes.peek();
}
public void clear() {
values.clear();
scopes.clear();
}
// ------------------------------------------------------------------
// private helper method(s)
// ------------------------------------------------------------------
/**
* INTERNAL: Cut off prefix ($) from given string (used to identify
* variable names since OKS Version 1.4).
*/
private static String cutoffPre(String name) {
if (name == null)
return null;
if (name.charAt(0) == '$')
return name.substring(1);
else
return name;
}
}