View Javadoc

1   /*
2    * $Id: MergeIterator.java 497654 2007-01-19 00:21:57Z rgielen $
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  package org.apache.struts2.components;
22  
23  import java.io.Writer;
24  import java.util.ArrayList;
25  import java.util.Iterator;
26  import java.util.List;
27  
28  import org.apache.commons.logging.Log;
29  import org.apache.commons.logging.LogFactory;
30  import org.apache.struts2.views.annotations.StrutsTag;
31  import org.apache.struts2.views.annotations.StrutsTagAttribute;
32  import org.apache.struts2.components.Param.UnnamedParametric;
33  import org.apache.struts2.util.MakeIterator;
34  import org.apache.struts2.util.MergeIteratorFilter;
35  
36  import com.opensymphony.xwork2.util.ValueStack;
37  
38  /***
39   * <!-- START SNIPPET: javadoc -->
40   * <p>Component for MergeIteratorTag, which job is to merge iterators and successive
41   * call to the merged iterator will cause each merge iterator to have a chance to
42   * expose its element, subsequently next call will allow the next iterator to expose
43   * its element. Once the last iterator is done exposing its element, the first iterator
44   * is allowed to do so again (unless it is exhausted of entries).</P>
45   *
46   * <p>Internally the task are delegated to MergeIteratorFilter</p>
47   *
48   * <p>Example if there are 3 lists being merged, each list have 3 entries, the following will
49   * be the logic.</P>
50   * <ol>
51   *      <li>Display first element of the first list</li>
52   *      <li>Display first element of the second list</li>
53   *      <li>Display first element of the third list</li>
54   *      <li>Display second element of the first list</li>
55   *      <li>Display second element of the second list</li>
56   *      <li>Display second element of the third list</li>
57   *      <li>Display third element of the first list</li>
58   *      <li>Display thrid element of the second list</li>
59   *      <li>Display third element of the thrid list</li>
60   * </ol>
61   * <!-- END SNIPPET: javadoc -->
62   *
63   * <!-- START SNIPPET: params -->
64   * <ul>
65   *          <li>id (String) - the id where the resultant merged iterator will be stored in the stack's context</li>
66   * </ul>
67   * <!-- END SNIPPET: params -->
68   *
69   *
70   * <!-- START SNIPPET: javacode -->
71   * public class MergeIteratorTagAction extends ActionSupport {
72   *
73   *  private List myList1;
74   *  private List myList2;
75   *  private List myList3;
76   *
77   *  public List getMyList1() {
78   *      return myList1;
79   *  }
80   *
81   *  public List getMyList2() {
82   *      return myList2;
83   *  }
84   *
85   *  public List getMyList3() {
86   *      return myList3;
87   *  }
88   *
89   *
90   *  public String execute() throws Exception {
91   *
92   *      myList1 = new ArrayList();
93   *      myList1.add("1");
94   *      myList1.add("2");
95   *      myList1.add("3");
96   *
97   *      myList2 = new ArrayList();
98   *      myList2.add("a");
99   *      myList2.add("b");
100  *      myList2.add("c");
101  *
102  *      myList3 = new ArrayList();
103  *      myList3.add("A");
104  *      myList3.add("B");
105  *      myList3.add("C");
106  *
107  *      return "done";
108  *  }
109  * }
110  * <!-- END SNIPPET: javacode -->
111  *
112  * <!-- START SNIPPET: example -->
113  * &lt;s:merge id="myMergedIterator1"&gt;
114  *      &lt;s:param value="%{myList1}" /&gt;
115  *      &lt;s:param value="%{myList2}" /&gt;
116  *      &lt;s:param value="%{myList3}" /&gt;
117  * &lt;/s:merge&gt;
118  * &lt;s:iterator value="%{#myMergedIterator1}"&gt;
119  *      &lt;s:property /&gt;
120  * &lt;/s:iterator&gt;
121  * <!-- END SNIPPET: example -->
122  *
123  * <!-- START SNIPPET: description -->
124  * This wil generate "1aA2bB3cC".
125  * <!-- START SNIPPET: description -->
126  *
127  * @see org.apache.struts2.util.MergeIteratorFilter
128  * @see org.apache.struts2.views.jsp.iterator.MergeIteratorTag
129  *
130  */
131 @StrutsTag(name="merge", tldTagClass="org.apache.struts2.views.jsp.iterator.MergeIteratorTag", description="Merge the values " +
132                 "of a list of iterators into one iterator")
133 public class MergeIterator extends Component implements UnnamedParametric {
134 
135     private static final Log _log = LogFactory.getLog(MergeIterator.class);
136 
137     private MergeIteratorFilter mergeIteratorFilter = null;
138     private List _parameters;
139 
140     public MergeIterator(ValueStack stack) {
141         super(stack);
142     }
143 
144     public boolean start(Writer writer) {
145 
146         mergeIteratorFilter = new MergeIteratorFilter();
147         _parameters = new ArrayList();
148 
149         return super.start(writer);
150     }
151 
152     public boolean end(Writer writer, String body) {
153 
154         for (Iterator parametersIterator = _parameters.iterator(); parametersIterator.hasNext(); ) {
155             Object iteratorEntryObj = parametersIterator.next();
156             if (! MakeIterator.isIterable(iteratorEntryObj)) {
157                 _log.warn("param with value resolved as "+iteratorEntryObj+" cannot be make as iterator, it will be ignored and hence will not appear in the merged iterator");
158                 continue;
159             }
160             mergeIteratorFilter.setSource(MakeIterator.convert(iteratorEntryObj));
161         }
162 
163         mergeIteratorFilter.execute();
164 
165         // if id exists, we put it in the stack's context
166         if (getId() != null && getId().length() > 0) {
167             getStack().getContext().put(getId(), mergeIteratorFilter);
168         }
169 
170         mergeIteratorFilter = null;
171 
172         return super.end(writer, body);
173     }
174 
175     @StrutsTagAttribute(description="The id where the resultant merged iterator will be stored in the stack's context")
176     public void setId(String id) {
177         super.setId(id);
178     }
179 
180     // == UnnamedParametric interface implementation ---------------------
181     public void addParameter(Object value) {
182         _parameters.add(value);
183     }
184 }