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 */ 019 package org.apache.wiki.tags; 020 021 import java.io.IOException; 022 import java.util.Arrays; 023 import java.util.Collection; 024 import java.util.Iterator; 025 026 import javax.servlet.jsp.JspWriter; 027 import javax.servlet.jsp.PageContext; 028 import javax.servlet.jsp.tagext.BodyTagSupport; 029 import javax.servlet.jsp.tagext.TryCatchFinally; 030 031 import org.apache.log4j.Logger; 032 import org.apache.wiki.WikiContext; 033 import org.apache.wiki.WikiPage; 034 035 036 /** 037 * Iterates through tags. 038 * 039 * <P><B>Attributes</B></P> 040 * <UL> 041 * <LI>list - a collection. 042 * </UL> 043 * 044 * @since 2.0 045 */ 046 public abstract class IteratorTag extends BodyTagSupport implements TryCatchFinally { 047 048 private static final long serialVersionUID = 8945334759300595321L; 049 protected String m_pageName; 050 protected Iterator m_iterator; 051 protected WikiContext m_wikiContext; 052 053 private static final Logger log = Logger.getLogger( IteratorTag.class ); 054 055 /** 056 * Sets the collection that is used to form the iteration. 057 * 058 * @param arg A Collection which will be iterated. 059 */ 060 public void setList( Collection arg ) 061 { 062 if( arg != null ) 063 m_iterator = arg.iterator(); 064 } 065 066 /** 067 * Sets the collection list, but using an array. 068 * @param arg An array of objects which will be iterated. 069 */ 070 public void setList( Object[] arg ) 071 { 072 if( arg != null ) 073 { 074 m_iterator = Arrays.asList(arg).iterator(); 075 } 076 } 077 078 /** 079 * Sets the iterator directly that is used to form the iteration. 080 */ 081 /* 082 public void setList( Iterator arg ) 083 { 084 m_iterator = arg; 085 } 086 */ 087 088 /** 089 * Clears the iterator away. After calling this method doStartTag() 090 * will always return SKIP_BODY 091 */ 092 public void clearList() 093 { 094 m_iterator = null; 095 } 096 097 /** 098 * Override this method to reset your own iterator. 099 */ 100 public void resetIterator() 101 { 102 // No operation here 103 } 104 105 /** 106 * {@inheritDoc} 107 */ 108 public int doStartTag() 109 { 110 m_wikiContext = WikiContext.findContext(pageContext); 111 112 resetIterator(); 113 114 if( m_iterator == null ) return SKIP_BODY; 115 116 if( m_iterator.hasNext() ) 117 { 118 buildContext(); 119 } 120 121 return EVAL_BODY_BUFFERED; 122 } 123 124 /** 125 * Arg, I hate globals. 126 */ 127 private void buildContext() 128 { 129 // 130 // Build a clone of the current context 131 // 132 WikiContext context = (WikiContext)m_wikiContext.clone(); 133 134 Object o = m_iterator.next(); 135 136 if( o instanceof WikiPage ) 137 context.setPage( (WikiPage)o ); 138 139 // 140 // Push it to the iterator stack, and set the id. 141 // 142 pageContext.setAttribute( WikiTagBase.ATTR_CONTEXT, 143 context, 144 PageContext.REQUEST_SCOPE ); 145 pageContext.setAttribute( getId(), 146 o ); 147 } 148 149 /** 150 * {@inheritDoc} 151 */ 152 public int doEndTag() 153 { 154 // Return back to the original. 155 pageContext.setAttribute( WikiTagBase.ATTR_CONTEXT, 156 m_wikiContext, 157 PageContext.REQUEST_SCOPE ); 158 159 return EVAL_PAGE; 160 } 161 162 /** 163 * {@inheritDoc} 164 */ 165 public int doAfterBody() 166 { 167 if( bodyContent != null ) 168 { 169 try 170 { 171 JspWriter out = getPreviousOut(); 172 out.print(bodyContent.getString()); 173 bodyContent.clearBody(); 174 } 175 catch( IOException e ) 176 { 177 log.error("Unable to get inner tag text", e); 178 // FIXME: throw something? 179 } 180 } 181 182 if( m_iterator != null && m_iterator.hasNext() ) 183 { 184 buildContext(); 185 return EVAL_BODY_BUFFERED; 186 } 187 188 return SKIP_BODY; 189 } 190 191 /** 192 * In case your tag throws an exception at any point, you can 193 * override this method and implement a custom exception handler. 194 * <p> 195 * By default, this handler does nothing. 196 * 197 * @param arg0 The Throwable that the tag threw 198 * 199 * @throws Throwable I have no idea why this would throw anything 200 */ 201 public void doCatch(Throwable arg0) throws Throwable 202 { 203 } 204 205 /** 206 * Executed after the tag has been finished. This is a great place 207 * to put any cleanup code. However you <b>must</b> call super.doFinally() 208 * if you override this method, or else some of the things may not 209 * work as expected. 210 */ 211 public void doFinally() 212 { 213 resetIterator(); 214 m_iterator = null; 215 m_pageName = null; 216 m_wikiContext = null; 217 } 218 219 }