/*
* $Id$
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.struts2.views.jsp.iterator;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.util.SubsetIteratorFilter;
import org.apache.struts2.util.SubsetIteratorFilter.Decider;
import org.apache.struts2.views.annotations.StrutsTag;
import org.apache.struts2.views.annotations.StrutsTagAttribute;
import org.apache.struts2.views.jsp.StrutsBodyTagSupport;
import javax.servlet.jsp.JspException;
/**
* <!-- START SNIPPET: javadoc -->
* <b>NOTE: JSP-TAG</b>
*
* <p>A tag that takes an iterator and outputs a subset of it. It delegates to
* {@link org.apache.struts2.util.SubsetIteratorFilter} internally to
* perform the subset functionality.</p>
* <!-- END SNIPPET: javadoc -->
*
* <!-- START SNIPPET: params -->
* <ul>
* <li>count (Object) - Indicate the number of entries to be in the resulting subset iterator</li>
* <li>source* (Object) - Indicate the source of which the resulting subset iterator is to be derived base on</li>
* <li>start (Object) - Indicate the starting index (eg. first entry is 0) of entries in the source to be available as the first entry in the resulting subset iterator</li>
* <li>decider (Object) - Extension to plug-in a decider to determine if that particular entry is to be included in the resulting subset iterator</li>
* <li>var (String) - Indicate the pageContext attribute name to store the resultant subset iterator in</li>
* </ul>
* <!-- END SNIPPET: params -->
*
*
* <pre>
* <!-- START SNIPPET: action -->
* public class MySubsetTagAction extends ActionSupport {
* public String execute() throws Exception {
* l = new ArrayList();
* l.add(new Integer(1));
* l.add(new Integer(2));
* l.add(new Integer(3));
* l.add(new Integer(4));
* l.add(new Integer(5));
* return "done";
* }
*
*
* public Integer[] getMyArray() {
* return a;
* }
*
* public List getMyList() {
* return l;
* }
*
* public Decider getMyDecider() {
* return new Decider() {
* public boolean decide(Object element) throws Exception {
* int i = ((Integer)element).intValue();
* return (((i % 2) == 0)?true:false);
* }
* };
* }
* }
* <!-- END SNIPPET: action -->
* </pre>
*
*
* <pre>
* <!-- START SNIPPET: example1 -->
* <!-- s: List basic -->
* <s:subset source="myList">
* <s:iterator>
* <s:property />
* </s:iterator>
* </s:subset>
* <!-- END SNIPPET: example1 -->
* </pre>
*
* <pre>
* <!-- START SNIPPET: example2 -->
* <!-- B: List with count -->
* <s:subset source="myList" count="3">
* <s:iterator>
* <s:property />
* </s:iterator>
* </s:subset>
* <!-- END SNIPPET: example2 -->
* </pre>
*
* <pre>
* <!-- START SNIPPET: example3 -->
* <!-- C: List with start -->
* <s:subset source="myList" count="13" start="3">
* <s:iterator>
* <s:property />
* </s:iterator>
* </s:subset>
* <!-- END SNIPPET: example3 -->
* </pre>
*
* <pre>
* <!-- START SNIPPET: example4 -->
* <!-- D: List with var -->
* <s:subset var="mySubset" source="myList" count="13" start="3" />
* <%
* Iterator i = (Iterator) pageContext.getAttribute("mySubset");
* while(i.hasNext()) {
* %>
* <%=i.next() %>
* <% } %>
* <!-- END SNIPPET: example4 -->
* </pre>
*
* <pre>
* <!-- START SNIPPET: example5 -->
* <!-- D: List with Decider -->
* <s:subset source="myList" decider="myDecider">
* <s:iterator>
* <s:property />
* </s:iterator>
* </s:subset>
* <!-- END SNIPPET: example5 -->
* </pre>
*
*
* {@literal @}s.tag name="subset" tld-body-content="JSP"
* description="Takes an iterator and outputs a subset of it"
*/
@StrutsTag(name="subset", tldTagClass="org.apache.struts2.views.jsp.iterator.SubsetIteratorTag",
description="Takes an iterator and outputs a subset of it.")
public class SubsetIteratorTag extends StrutsBodyTagSupport {
private static final long serialVersionUID = -6252696081713080102L;
private static final Logger LOG = LogManager.getLogger(SubsetIteratorTag.class);
String countAttr;
String sourceAttr;
String startAttr;
String deciderAttr;
String var;
SubsetIteratorFilter subsetIteratorFilter = null;
@StrutsTagAttribute(type="Integer", description="Indicate the number of entries to be in the resulting subset iterator")
public void setCount(String count) {
countAttr = count;
}
@StrutsTagAttribute(description="Indicate the source of which the resulting subset iterator is to be derived base on")
public void setSource(String source) {
sourceAttr = source;
}
/**
* {@literal @}s.tagattribute required="false" type="Integer"
* description="Indicate the starting index (eg. first entry is 0) of entries in the source to be available as the first entry in the resulting subset iterator"
*
* @param start start
*/
@StrutsTagAttribute(type="Integer",
description="Indicate the starting index (eg. first entry is 0) of entries in the source to be available as the first entry in the resulting subset iterator")
public void setStart(String start) {
startAttr = start;
}
@StrutsTagAttribute(type="org.apache.struts2.util.SubsetIteratorFilter.Decider",
description="Extension to plug-in a decider to determine if that particular entry is to be included in the resulting subset iterator")
public void setDecider(String decider) {
deciderAttr = decider;
}
@StrutsTagAttribute(description="The name to store the resultant iterator into page context, if such name is supplied")
public void setVar(String var) {
this.var = var;
}
public int doStartTag() throws JspException {
// source
Object source = null;
if (sourceAttr == null || sourceAttr.length() == 0) {
source = findValue("top");
} else {
source = findValue(sourceAttr);
}
// count
int count = -1;
if (countAttr != null && countAttr.length() > 0) {
Object countObj = findValue(countAttr);
if (countObj instanceof Number) {
count = ((Number)countObj).intValue();
}
else if (countObj instanceof String) {
try {
count = Integer.parseInt((String)countObj);
}
catch(NumberFormatException e) {
LOG.warn("unable to convert count attribute [{}] to number, ignore count attribute", countObj, e);
}
}
}
// start
int start = 0;
if (startAttr != null && startAttr.length() > 0) {
Object startObj = findValue(startAttr);
if (startObj instanceof Integer) {
start = ((Integer)startObj).intValue();
}
else if (startObj instanceof Float) {
start = ((Float)startObj).intValue();
}
else if (startObj instanceof Long) {
start = ((Long)startObj).intValue();
}
else if (startObj instanceof Double) {
start = ((Double)startObj).intValue();
}
else if (startObj instanceof String) {
try {
start = Integer.parseInt((String)startObj);
}
catch(NumberFormatException e) {
LOG.warn("unable to convert count attribute [{}] to number, ignore count attribute", startObj, e);
}
}
}
// decider
Decider decider = null;
if (deciderAttr != null && deciderAttr.length() > 0) {
Object deciderObj = findValue(deciderAttr);
if (! (deciderObj instanceof Decider)) {
throw new JspException("decider found from stack ["+deciderObj+"] does not implement "+Decider.class);
}
decider = (Decider) deciderObj;
}
subsetIteratorFilter = new SubsetIteratorFilter();
subsetIteratorFilter.setCount(count);
subsetIteratorFilter.setDecider(decider);
subsetIteratorFilter.setSource(source);
subsetIteratorFilter.setStart(start);
subsetIteratorFilter.execute();
getStack().push(subsetIteratorFilter);
if (var != null && var.length() > 0) {
pageContext.setAttribute(var, subsetIteratorFilter);
}
return EVAL_BODY_INCLUDE;
}
public int doEndTag() throws JspException {
getStack().pop();
subsetIteratorFilter = null;
return EVAL_PAGE;
}
}