/*
* #!
* 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.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspTagException;
import javax.servlet.jsp.tagext.TagSupport;
import net.ontopia.utils.DeciderIF;
import net.ontopia.topicmaps.nav2.core.NavigatorPageIF;
import net.ontopia.topicmaps.nav2.core.NavigatorConfigurationIF;
import net.ontopia.topicmaps.nav2.core.NavigatorRuntimeException;
import net.ontopia.topicmaps.nav2.core.NavigatorDeciderIF;
import net.ontopia.topicmaps.nav2.core.ContextManagerIF;
import net.ontopia.topicmaps.nav2.core.VariableNotSetException;
import net.ontopia.topicmaps.nav2.core.ValueProducingTagIF;
import net.ontopia.topicmaps.nav2.core.ValueAcceptingTagIF;
import net.ontopia.topicmaps.nav2.impl.basic.DefaultIfDecider;
import net.ontopia.topicmaps.nav2.impl.basic.DeciderIFWrapper;
import net.ontopia.topicmaps.nav2.utils.FrameworkUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* INTERNAL: Logic Tag for iterating over each object in a collection,
* creating new content for each iteration.
*/
public class IfTag extends TagSupport
implements ValueProducingTagIF, ValueAcceptingTagIF {
// initialization of logging facility
private static Logger log = LoggerFactory.getLogger(IfTag.class.getName());
// members
private NavigatorPageIF contextTag;
private Collection collection; // to test on
private List inputs; // collections received from below
private NavigatorDeciderIF decider;
// tag attributes
private String deciderClassName;
private String collVariableName;
private String equalsVariableName;
private int lessThanNumber = -1;
private int greaterThanNumber = -1;
private int equalsSize = -1;
/**
* Process the start tag for this instance.
*/
public int doStartTag() throws JspTagException {
this.contextTag = FrameworkUtils.getContextTag(pageContext);
ContextManagerIF ctxtMgr = contextTag.getContextManager();
// get Collection to test matching on
if (collVariableName != null) {
// Policy: treat none existing collections like empty
// collections (see bug 413).
collection = ctxtMgr.getValue(collVariableName, Collections.EMPTY_LIST);
} else {
collection = ctxtMgr.getDefaultValue();
}
// establish new lexical scope for this condition...
ctxtMgr.pushScope();
// ...and set up the test collection as default value
ctxtMgr.setDefaultValue( collection );
// ...then get ready to receive inputs from descendants
inputs = new ArrayList();
// use the decider specified by tag attribute
if (deciderClassName != null)
this.decider = getDeciderInstance(deciderClassName);
if (decider == null) {
// get name of default decider class
NavigatorConfigurationIF navConf =
contextTag.getNavigatorApplication().getConfiguration();
String dcn = navConf.getProperty(NavigatorConfigurationIF.DEF_DECIDER,
NavigatorConfigurationIF.DEFVAL_DECIDER);
if (dcn.equals(NavigatorConfigurationIF.DEFVAL_DECIDER))
// TODO: Should replace with generic attributes support in NavigatorDeciderIF
decider = new DefaultIfDecider(equalsVariableName, equalsSize,
lessThanNumber, greaterThanNumber);
else
decider = getDeciderInstance(dcn);
}
return EVAL_BODY_INCLUDE;
}
/**
* Process the end tag.
*/
public int doEndTag() throws JspException {
// establish old lexical scope, back to outside of the condition
contextTag.getContextManager().popScope();
// pass received collections further upwards
ValueAcceptingTagIF acceptingTag = (ValueAcceptingTagIF)
findAncestorWithClass(this, ValueAcceptingTagIF.class);
if (acceptingTag != null)
for (int ix = 0; ix < inputs.size(); ix++)
acceptingTag.accept((Collection) inputs.get(ix));
// Reset members
contextTag = null;
collection = null;
decider = null;
return EVAL_PAGE;
}
/**
* Resets the state of the Tag.
*/
public void release() {
// overwrite default behaviour
// do not set parent to null!!!
}
/**
* If all conditions are matched deliver true, otherwise false.
*/
protected boolean matchCondition() {
return decider.ok(contextTag, collection);
}
// -----------------------------------------------------------------
// Implementation of ValueProducingTagIF
// -----------------------------------------------------------------
// this probably isn't needed any more. keeping it so that we can
// continue to consider (the really rather meaningless)
// ValueProducingTagIF as a marker interface.
public Collection process(Collection input) {
return input;
}
// -----------------------------------------------------------------
// Implementation of ValueAcceptingTagIF
// -----------------------------------------------------------------
// because of bug #1476 it's not enough for us simply to receive a
// collection, and then pass it on. we may receive more than one
// collection from our descendants, and we don't know how to combine
// them, since we don't know our parent tag. the solution is to keep
// them all, and then pass them upwards one by one.
public void accept(Collection inputCollection) {
inputs.add(inputCollection);
}
// -----------------------------------------------------------------
// Set methods for all attributes
// -----------------------------------------------------------------
public void setName(String collectionName) {
this.collVariableName = collectionName;
}
public void setDecider(String classname) throws NavigatorRuntimeException {
deciderClassName = classname;
}
public void setEquals(String equalsVariableName) {
this.equalsVariableName = equalsVariableName;
}
/**
* Sets Lower Bound test value against Collection size.
*
* @param lessThanString try to convert to valid integer,
* otherwise fallback to default value (-1).
*/
public void setLessThan(String lessThanString) {
try {
this.lessThanNumber = Integer.parseInt( lessThanString );
} catch (NumberFormatException e) {
log.warn("Reset invalid lessThan value to '-1' was '" +
lessThanString + "'.");
this.lessThanNumber = -1;
}
}
/**
* Sets Upper Bound test value against Collection size.
*
* @param greaterThanString try to convert to valid integer,
* otherwise fallback to default value (-1).
*/
public void setGreaterThan(String greaterThanString) {
try {
this.greaterThanNumber = Integer.parseInt( greaterThanString );
} catch (NumberFormatException e) {
log.warn("Reset invalid greaterThan value to '-1' was '" +
greaterThanString + "'.");
this.greaterThanNumber = -1;
}
}
/**
* Sets exact equals size test value against Collection size.
*
* @param equalsSizeString try to convert to valid integer,
* otherwise fallback to default value (-1).
*/
public void setSizeEquals(String equalsSizeString) {
try {
this.equalsSize = Integer.parseInt( equalsSizeString );
} catch (NumberFormatException e) {
log.warn("Reset invalid equalsSize value to '-1' was '" +
equalsSizeString + "'.");
this.equalsSize = -1;
}
}
// ---------------------------------------------------------------
// Internal method(s)
// ---------------------------------------------------------------
protected NavigatorDeciderIF getDeciderInstance(String classname)
throws NavigatorRuntimeException {
Object obj = null;
try {
// Create decider instance
obj = contextTag.getNavigatorApplication().getInstanceOf(classname);
// if instance of DeciderIF we need to wrap in NavigatorDeciderWrapper
if (obj instanceof NavigatorDeciderIF)
return (NavigatorDeciderIF) obj;
else if (obj instanceof DeciderIF)
return new DeciderIFWrapper((DeciderIF)obj);
} catch (NavigatorRuntimeException e) {
log.warn("Unable to retrieve instance of " + classname);
}
// We weren't able to create an instance so let's return null.
return null;
}
}