001/* 002 Licensed to the Apache Software Foundation (ASF) under one 003 or more contributor license agreements. See the NOTICE file 004 distributed with this work for additional information 005 regarding copyright ownership. The ASF licenses this file 006 to you under the Apache License, Version 2.0 (the 007 "License"); you may not use this file except in compliance 008 with the License. You may obtain a copy of the License at 009 010 http://www.apache.org/licenses/LICENSE-2.0 011 012 Unless required by applicable law or agreed to in writing, 013 software distributed under the License is distributed on an 014 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 KIND, either express or implied. See the License for the 016 specific language governing permissions and limitations 017 under the License. 018 */ 019package org.apache.wiki.tags; 020 021import org.apache.log4j.Logger; 022import org.apache.wiki.api.core.Context; 023import org.apache.wiki.api.core.Page; 024 025import javax.servlet.jsp.JspWriter; 026import javax.servlet.jsp.PageContext; 027import javax.servlet.jsp.tagext.BodyTagSupport; 028import javax.servlet.jsp.tagext.TryCatchFinally; 029import java.io.IOException; 030import java.util.Arrays; 031import java.util.Collection; 032import java.util.Iterator; 033 034 035/** 036 * Iterates through tags. 037 * 038 * <P><B>Attributes</B></P> 039 * <UL> 040 * <LI>list - a collection. 041 * </UL> 042 * 043 * @since 2.0 044 */ 045public abstract class IteratorTag extends BodyTagSupport implements TryCatchFinally { 046 047 private static final long serialVersionUID = 8945334759300595321L; 048 protected String m_pageName; 049 protected Iterator< ? > m_iterator; 050 protected Context m_wikiContext; 051 052 private static final Logger log = Logger.getLogger( IteratorTag.class ); 053 054 /** 055 * Sets the collection that is used to form the iteration. 056 * 057 * @param arg A Collection which will be iterated. 058 */ 059 public void setList( final Collection< ? > arg ) { 060 if( arg != null ) { 061 m_iterator = arg.iterator(); 062 } 063 } 064 065 /** 066 * Sets the collection list, but using an array. 067 * 068 * @param arg An array of objects which will be iterated. 069 */ 070 public void setList( final Object[] arg ) { 071 if( arg != null ) { 072 m_iterator = Arrays.asList(arg).iterator(); 073 } 074 } 075 076 /** 077 * Clears the iterator away. After calling this method doStartTag() will always return SKIP_BODY 078 */ 079 public void clearList() { 080 m_iterator = null; 081 } 082 083 /** 084 * Override this method to reset your own iterator. 085 */ 086 public void resetIterator() { 087 // No operation here 088 } 089 090 /** {@inheritDoc} */ 091 @Override 092 public int doStartTag() { 093 m_wikiContext = Context.findContext(pageContext); 094 resetIterator(); 095 if( m_iterator == null ) { 096 return SKIP_BODY; 097 } 098 if( m_iterator.hasNext() ) { 099 buildContext(); 100 } 101 102 return EVAL_BODY_BUFFERED; 103 } 104 105 /** 106 * Arg, I hate globals. 107 */ 108 private void buildContext() { 109 final Context context = m_wikiContext.clone(); 110 final Object o = m_iterator.next(); 111 if( o instanceof Page ) { 112 context.setPage( ( Page )o ); 113 } 114 115 pageContext.setAttribute( Context.ATTR_CONTEXT, context, PageContext.REQUEST_SCOPE ); 116 pageContext.setAttribute( getId(), o ); 117 } 118 119 /** {@inheritDoc} */ 120 @Override 121 public int doEndTag() { 122 // Return back to the original. 123 pageContext.setAttribute( Context.ATTR_CONTEXT, m_wikiContext, PageContext.REQUEST_SCOPE ); 124 125 return EVAL_PAGE; 126 } 127 128 /** {@inheritDoc} */ 129 @Override 130 public int doAfterBody() { 131 if( bodyContent != null ) { 132 try { 133 final JspWriter out = getPreviousOut(); 134 out.print( bodyContent.getString() ); 135 bodyContent.clearBody(); 136 } catch( final IOException e ) { 137 log.error( "Unable to get inner tag text", e ); 138 // FIXME: throw something? 139 } 140 } 141 142 if( m_iterator != null && m_iterator.hasNext() ) { 143 buildContext(); 144 return EVAL_BODY_BUFFERED; 145 } 146 147 return SKIP_BODY; 148 } 149 150 /** 151 * In case your tag throws an exception at any point, you can override this method and implement a custom exception handler. 152 * <p> 153 * By default, this handler does nothing. 154 * 155 * @param arg0 The Throwable that the tag threw 156 * @throws Throwable I have no idea why this would throw anything 157 */ 158 @Override 159 public void doCatch( final Throwable arg0) throws Throwable { 160 } 161 162 /** 163 * Executed after the tag has been finished. This is a great place to put any cleanup code. However you <b>must</b> call 164 * super.doFinally() if you override this method, or else some of the things may not work as expected. 165 */ 166 @Override 167 public void doFinally() { 168 resetIterator(); 169 m_iterator = null; 170 m_pageName = null; 171 m_wikiContext = null; 172 } 173 174}