/*
* #!
* 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.taglibs.logic;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletRequest;
import javax.servlet.jsp.JspTagException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.TagSupport;
import javax.servlet.jsp.tagext.TryCatchFinally;
import net.ontopia.topicmaps.core.TMObjectIF;
import net.ontopia.topicmaps.core.TopicMapIF;
import net.ontopia.topicmaps.entry.TopicMapRepositoryIF;
import net.ontopia.topicmaps.nav2.core.ContextManagerIF;
import net.ontopia.topicmaps.nav2.core.FunctionIF;
import net.ontopia.topicmaps.nav2.core.NavigatorApplicationIF;
import net.ontopia.topicmaps.nav2.core.NavigatorConfigurationIF;
import net.ontopia.topicmaps.nav2.core.NavigatorPageIF;
import net.ontopia.topicmaps.nav2.core.NavigatorRuntimeException;
import net.ontopia.topicmaps.nav2.core.NonexistentObjectException;
import net.ontopia.topicmaps.nav2.impl.basic.ContextManager;
import net.ontopia.topicmaps.nav2.impl.basic.JSPEngineWrapper;
import net.ontopia.topicmaps.nav2.taglibs.tolog.Context;
import net.ontopia.topicmaps.nav2.taglibs.tolog.ContextManagerMapWrapper;
import net.ontopia.topicmaps.nav2.utils.NavigatorUtils;
import net.ontopia.topicmaps.query.core.DeclarationContextIF;
import net.ontopia.topicmaps.query.core.InvalidQueryException;
import net.ontopia.topicmaps.query.core.QueryProcessorIF;
import net.ontopia.topicmaps.query.core.QueryResultIF;
import net.ontopia.topicmaps.query.utils.QueryUtils;
/**
* INTERNAL: Logic Tag for establishing the outermost lexical scope in
* which all computation happens and the embedded tags are executed.
* <p>
* Use this tag as root tag for <b>all</b> tags defined in the Tag
* Libraries of the Ontopia Navigator Framework (2nd Generation).
*/
public class ContextTag extends TagSupport
implements TryCatchFinally, NavigatorPageIF {
private static final long serialVersionUID = -1545242249688762632L;
public static String TOPICMAPID_REQUEST_ATTRIBUTE = "ContextTag.topicmapid";
// members
private ContextManagerIF contextManager;
private NavigatorApplicationIF navApp;
private Map functions;
private Map queryResults;
private TopicMapIF topicmap;
private QueryProcessorIF queryProcessor;
private Collection tmObjects;
private String topicmapID;
private String[] objectIDs;
private DeclarationContextIF declarationContext;
private Object pcontext; // parent context tag
private Object pontopia; // parent ontopia attribute
private Object pontopiacontext; // parent ontopiacontext attribute
// tag attributes
private String tmParamName;
private String objParamName;
private String varObjName;
private String varTMName;
private String attrTopicmapID;
private boolean readonly = true;
/**
* Process the start tag for this instance.
*/
public int doStartTag() throws JspTagException {
this.contextManager = new ContextManager(pageContext);
this.functions = new HashMap();
this.queryResults = new HashMap();
// --- try to retrieve application wide configuration
navApp = getNavigatorApplication();
// retrieve parent context tag and parent ontopia attribute
pcontext = pageContext.getAttribute(NavigatorApplicationIF.CONTEXT_KEY,
PageContext.REQUEST_SCOPE);
pontopia = pageContext.getAttribute("ontopia", PageContext.REQUEST_SCOPE);
if (pontopia == null)
pontopia = pageContext.getAttribute("oks", PageContext.REQUEST_SCOPE);
pontopiacontext = pageContext.getAttribute("ontopiacontext", PageContext.REQUEST_SCOPE);
if (pontopiacontext == null)
pontopia = pageContext.getAttribute("okscontext", PageContext.REQUEST_SCOPE);
// set this instance to page context, so normal JSPs can access information
pageContext.setAttribute(NavigatorApplicationIF.CONTEXT_KEY, this,
PageContext.REQUEST_SCOPE);
// character encoding of the response stream to browser is set by
// the framework.ResponseTag. we need to interpret it as the same.
// see bug #541.
ServletRequest request = pageContext.getRequest();
String charenc = navApp.getConfiguration().getProperty("defaultCharacterEncoding");
try {
if (charenc != null && !charenc.equals(""))
JSPEngineWrapper.setRequestEncoding(request, charenc);
} catch (java.io.UnsupportedEncodingException e) {
throw new net.ontopia.utils.OntopiaRuntimeException(e);
}
// --- Set value of topicmap ID
if (attrTopicmapID != null) {
topicmapID = attrTopicmapID;
} else {
if (tmParamName != null)
// get the value from request parameter
topicmapID = request.getParameter(tmParamName);
else
topicmapID = null;
}
// get topicmap id from request attribute if not specified at this point
if (topicmapID == null)
topicmapID = (String)request.getAttribute(ContextTag.TOPICMAPID_REQUEST_ATTRIBUTE);
// --- Set value(s) of object ID
if (objParamName != null) {
// get value(s) from request parameter
objectIDs = request.getParameterValues(objParamName);
if (objectIDs == null)
throw new NavigatorRuntimeException("Object ID is not specified "
+ "by parameter '" + objParamName
+ "', but needed to process this page.");
} else {
objectIDs = null;
}
// --- try to retrieve RO topicmap belonging to topicmap ID
topicmap = null;
if (topicmapID != null) {
topicmap = navApp.getTopicMapById(topicmapID, readonly);
if (topicmap == null)
throw new NavigatorRuntimeException("Topicmap with ID '" + topicmapID +
"' could not be loaded, " +
"maybe wrong topicmap ID.");
}
// Make the ontopia variables available to the PageContext and hence to JSTL.
ContextManagerMapWrapper cmw = new ContextManagerMapWrapper(contextManager);
pageContext.setAttribute("ontopia", cmw, PageContext.REQUEST_SCOPE);
pageContext.setAttribute("oks", cmw, PageContext.REQUEST_SCOPE);
// Make the ontopiacontext request attribute is available
Context ctx = new Context(this);
pageContext.setAttribute("ontopiacontext", ctx, PageContext.REQUEST_SCOPE);
pageContext.setAttribute("okscontext", ctx, PageContext.REQUEST_SCOPE);
// --- try to retrieve topic object(s) belonging to object ID(s)
if (topicmap != null) {
if (objectIDs == null)
tmObjects = Collections.EMPTY_LIST;
else {
tmObjects = new ArrayList(objectIDs.length);
for (int i = 0; i < objectIDs.length; i++) {
TMObjectIF tmObject = NavigatorUtils.stringID2Object(topicmap, objectIDs[i]);
if (tmObject == null)
throw new NonexistentObjectException(objectIDs[i], topicmapID);
tmObjects.add(tmObject);
} // for
contextManager.setDefaultValue(tmObjects);
if (varObjName != null)
contextManager.setValue(varObjName, tmObjects);
}
// --- setup topicmap object
if (objParamName == null)
// set default value to this topicmap object
contextManager.setDefaultValue(topicmap);
if (varTMName != null)
contextManager.setValue(varTMName, topicmap);
try {
declarationContext = QueryUtils.parseDeclarations(topicmap, "");
} catch (InvalidQueryException e) {
// Do nothing ...
// since an empty declaration should be valid for any topicmap
}
}
return EVAL_BODY_INCLUDE;
}
/**
* Process the end tag for this instance.
*/
public int doEndTag() throws JspTagException {
// put out debug message
//log.debug("\\\\\\ end of context-tag. - ");
// return topic map to navigator application
if (navApp != null && topicmap != null) {
navApp.returnTopicMap(topicmap);
navApp = null;
topicmap = null;
queryProcessor = null;
}
// put back parent context tag and ontopia attribute
// NOTE: null values to setAttribute not allowed! bug #1551
if (pcontext != null)
pageContext.setAttribute(NavigatorApplicationIF.CONTEXT_KEY, pcontext,
PageContext.REQUEST_SCOPE);
else
pageContext.removeAttribute(NavigatorApplicationIF.CONTEXT_KEY,
PageContext.REQUEST_SCOPE);
if (pontopia != null) {
pageContext.setAttribute("ontopia", pontopia, PageContext.REQUEST_SCOPE);
pageContext.setAttribute("oks", pontopia, PageContext.REQUEST_SCOPE);
} else {
pageContext.removeAttribute("ontopia", PageContext.REQUEST_SCOPE);
pageContext.removeAttribute("oks", PageContext.REQUEST_SCOPE);
}
if (pontopiacontext != null) {
pageContext.setAttribute("ontopiacontext", pontopiacontext, PageContext.REQUEST_SCOPE);
pageContext.setAttribute("okscontext", pontopiacontext, PageContext.REQUEST_SCOPE);
} else {
pageContext.removeAttribute("ontopiacontext", PageContext.REQUEST_SCOPE);
pageContext.removeAttribute("okscontext", PageContext.REQUEST_SCOPE);
}
// reset members
contextManager = null;
functions = null;
queryResults = null;
topicmap = null;
queryProcessor = null;
tmObjects = null;
topicmapID = null;
objectIDs = null;
readonly = true;
return EVAL_PAGE;
}
// -----------------------------------------------------------------
// get/set methods for tag attributes
// -----------------------------------------------------------------
/**
* Tells the tag which request parameter contains the
* ID of the topic map in the context.
*
* @param tmParam String which specifies a
* Request parameter name.
*/
public void setTmparam(String tmParam) {
this.tmParamName = tmParam;
}
public String getTmparam() {
return tmParamName;
}
/**
* If set, it tells the tag what request parameter contains
* the object ID of the object to set as the value of the default
* variable. If not set, the default variable is set to the topic
* map.
*
* @param objParam String which specifies a
* Request parameter name.
*/
public void setObjparam(String objParam) {
this.objParamName = objParam;
}
public String getObjparam() {
return objParamName;
}
/**
* The variable name which the object will be set as the
* value of.
*
* @param varObjName String which specifies a variable name
* for the object.
*/
public void setSet(String varObjName) {
this.varObjName = varObjName;
}
/**
* The variable name which the topic map will be set as the
* value of.
*
* @param varTMName String which specifies a variable name
* for the topicmap.
*/
public void setSettm(String varTMName) {
this.varTMName = varTMName;
}
/**
* If set, the ID taken from this attribute is the ID of
* the topic map.
*
* @param topicmap String which specifies a Topic map ID.
*/
public void setTopicmap(String topicmap) {
this.attrTopicmapID = topicmap;
}
/**
* A boolean flag to tell the tag to fetch a read-only or a
* read-write topic map.
*
* @param readonly boolean value; true if read-only. The default is true.
*/
public void setReadonly(boolean readonly) {
this.readonly = readonly;
}
// --- get methods for members which are not JSP tag attributes
/**
* Get Topic map object identifiers.
*/
public String[] getObjectIDs() {
return objectIDs;
}
/**
* Gets the topic map objects retrieved by the context tag.
*
* @return collection of TopicIF objects.
*/
public Collection getObjects() {
return tmObjects;
}
// -----------------------------------------------------------------
// NavigatorPageIF implementation
// -----------------------------------------------------------------
public ContextManagerIF getContextManager() {
return contextManager;
}
public void registerFunction(FunctionIF function) {
functions.put(function.getName(), function);
}
public void registerFunction(String name, FunctionIF function) {
functions.put(name, function);
}
public FunctionIF getFunction(String name) {
return (FunctionIF) functions.get(name);
}
public void registerQueryResult(String name, QueryResultIF queryResult) {
queryResults.put(name, queryResult);
}
public QueryResultIF getQueryResult(String name) {
return (QueryResultIF) queryResults.get(name);
}
public TopicMapRepositoryIF getTopicMapRepository() {
return getNavigatorApplication().getTopicMapRepository();
}
public NavigatorApplicationIF getNavigatorApplication() {
// Look up the navigator application
return NavigatorUtils.getNavigatorApplication(pageContext);
}
public NavigatorConfigurationIF getNavigatorConfiguration() {
return getNavigatorApplication().getConfiguration();
}
public TopicMapIF getTopicMap() {
return topicmap;
}
public String getTopicMapId() {
return topicmapID;
}
public QueryProcessorIF getQueryProcessor() {
if (queryProcessor == null)
// construct new query processor instance
queryProcessor = QueryUtils.getQueryProcessor(topicmap);
return queryProcessor;
}
public PageContext getPageContext() {
return pageContext;
}
public DeclarationContextIF getDeclarationContext() {
return declarationContext;
}
public void setDeclarationContext(DeclarationContextIF declarationContext) {
this.declarationContext = declarationContext;
}
// -----------------------------------------------------------------
// TryCatchFinally implementation
// -----------------------------------------------------------------
public void doCatch(Throwable t) throws Throwable {
throw t;
}
public void doFinally() {
// NOTE: no need to rollback transaction because it is read-only
if (navApp != null && topicmap != null) {
navApp.returnTopicMap(topicmap);
navApp = null;
topicmap = null;
queryProcessor = null;
}
// put back parent context tag and ontopia attribute
if (pcontext != null)
pageContext.setAttribute(NavigatorApplicationIF.CONTEXT_KEY, pcontext,
PageContext.REQUEST_SCOPE);
else
pageContext.removeAttribute(NavigatorApplicationIF.CONTEXT_KEY,
PageContext.REQUEST_SCOPE);
if (pontopia != null) {
pageContext.setAttribute("ontopia", pontopia, PageContext.REQUEST_SCOPE);
pageContext.setAttribute("oks", pontopia, PageContext.REQUEST_SCOPE);
} else {
pageContext.removeAttribute("ontopia", PageContext.REQUEST_SCOPE);
pageContext.removeAttribute("oks", PageContext.REQUEST_SCOPE);
}
if (pontopiacontext != null) {
pageContext.setAttribute("ontopiacontext", pontopiacontext, PageContext.REQUEST_SCOPE);
pageContext.setAttribute("okscontext", pontopiacontext, PageContext.REQUEST_SCOPE);
} else {
pageContext.removeAttribute("ontopiacontext", PageContext.REQUEST_SCOPE);
pageContext.removeAttribute("okscontext", PageContext.REQUEST_SCOPE);
}
}
// -----------------------------------------------------------------
// Unit test code
// -----------------------------------------------------------------
/**
* Special setter used only for unit testing purposes. The JSP
* containers will never call this constructor, nor should anyone
* else.
*/
public void _setTopicMap(TopicMapIF topicmap) {
this.topicmap = topicmap;
}
/**
* Special setter used only for unit testing purposes. The JSP
* containers will never call this constructor, nor should anyone
* else.
*/
public void setContextManager(ContextManagerIF ctxtmgr) {
this.contextManager = ctxtmgr;
}
}