KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mmbase > bridge > jsp > taglib > NodeListHelper


1 /*
2
3 This software is OSI Certified Open Source Software.
4 OSI Certified is a certification mark of the Open Source Initiative.
5
6 The license (Mozilla version 1.0) can be read at the MMBase site.
7 See http://www.MMBase.org/license
8
9 */

10 package org.mmbase.bridge.jsp.taglib;
11
12 import org.mmbase.bridge.jsp.taglib.util.*;
13 import org.mmbase.bridge.jsp.taglib.debug.TimerTag;
14
15 import javax.servlet.jsp.*;
16 import javax.servlet.jsp.tagext.*;
17 import javax.servlet.jsp.jstl.core.*;
18
19 import java.io.IOException JavaDoc;
20 import java.util.*;
21
22 import org.mmbase.bridge.*;
23 import org.mmbase.storage.search.*;
24 import org.mmbase.util.Casting;
25 import org.mmbase.util.logging.Logger;
26 import org.mmbase.util.logging.Logging;
27
28 /**
29  *
30  * @author Michiel Meeuwissen
31  * @version $Id: NodeListHelper.java,v 1.28 2006/08/03 17:14:59 michiel Exp $
32  * @since MMBase-1.7
33  */

34
35 public class NodeListHelper implements ListProvider {
36
37     private static final Logger log = Logging.getLoggerInstance(NodeListHelper.class);
38
39     private final ContextReferrerTag thisTag;
40     private final NodeProviderHelper nodeHelper;
41
42     public NodeListHelper(ContextReferrerTag thisTag, NodeProviderHelper nodeHelper) {
43         this.thisTag = thisTag;
44         this.nodeHelper = nodeHelper;
45     }
46
47     public String JavaDoc getId() {
48         try {
49             return (String JavaDoc) thisTag.id.getValue(thisTag);
50         } catch (JspTagException j) {
51             throw new RuntimeException JavaDoc(j);
52         }
53     }
54
55     /**
56      * The maximum number of elements in a list.
57      * Setting the list size to conform to this maximum is implementation specific.
58      */

59     protected Attribute max = Attribute.NULL;
60
61     /**
62      * The offset of the elements that are returned in a list.
63      * Setting the list to conform to this ofsset is implementation specific.
64      */

65     protected Attribute offset = Attribute.NULL;
66
67     protected Attribute comparator = Attribute.NULL;
68
69     protected Attribute add = Attribute.NULL;
70     protected Attribute retain = Attribute.NULL;
71     protected Attribute remove= Attribute.NULL;
72
73
74     /**
75      * Lists do implement ContextProvider
76      */

77     private ContextCollector collector;
78
79
80     /**
81      * Determines whether a field in {@link AbstractNodeListTag#orderby} changed
82      * during iteration.
83      */

84     protected boolean changed = true;
85
86     /**
87      * Data member to hold an iteration of the values to return.
88      * This variable is set in {@link #setReturnValues(NodeList, boolean)}, which
89      * should be called from {@link AbstractNodeListTag#doStartTag}, and will be used to
90      * fill the return variables for every iteration.
91      */

92     protected NodeIterator nodeIterator;
93     protected NodeList returnList;
94
95     /**
96      * The current item
97      */

98     protected int currentItemIndex= -1;
99
100     /**
101      * A handle necessary when using the Time Tag;
102      */

103     protected int timerHandle = -1;
104
105     private String JavaDoc previousValue = null;
106
107     public int getIndex() {
108         return currentItemIndex;
109     }
110
111     public int getIndexOffset() {
112         return 1;
113     }
114
115     public void remove() {
116         nodeIterator.remove();
117     }
118
119     /**
120      * Set the list maximum
121      * @param m the max number of values returned
122      */

123     public void setMax(String JavaDoc m) throws JspTagException {
124         max = thisTag.getAttribute(m);
125     }
126
127     public Attribute getMax() {
128         return max;
129     }
130
131     /**
132      * Set the list offset
133      * @param o The offset for the List.
134      */

135     public void setOffset(String JavaDoc o) throws JspTagException {
136         offset = thisTag.getAttribute(o);
137     }
138
139     public Attribute getOffset() {
140         return offset;
141     }
142
143     public void setComparator(String JavaDoc c) throws JspTagException {
144         comparator = thisTag.getAttribute(c);
145     }
146
147     /**
148      * @since MMBase-1.8
149      */

150     public void setAdd(String JavaDoc a) throws JspTagException {
151         add = thisTag.getAttribute(a);
152     }
153
154     /**
155      * @since MMBase-1.8
156      */

157     public void setRetain(String JavaDoc a) throws JspTagException {
158         retain = thisTag.getAttribute(a);
159     }
160
161     /**
162      * @since MMBase-1.8
163      */

164     public void setRemove(String JavaDoc a) throws JspTagException {
165         remove = thisTag.getAttribute(a);
166     }
167
168
169
170     public String JavaDoc getComparator() throws JspTagException {
171         return comparator.getString(thisTag);
172     }
173
174     public NodeList getReturnList() {
175         return returnList;
176     }
177
178     public ContextContainer getContextContainer() throws JspTagException {
179         if (collector == null) return thisTag.getContextProvider().getContextContainer(); // to make sure old-style implemntation work (which do not initialize container)
180
return collector;
181     }
182     public PageContext getPageContext() throws JspTagException {
183         return thisTag.getPageContext();
184     }
185
186     public int setReturnValues(NodeList nodes, boolean trim) throws JspTagException {
187         Cloud cloud = null;
188         if (cloud == null) {
189             Query q = (Query) nodes.getProperty(NodeList.QUERY_PROPERTY);
190             if (q != null) cloud = q.getCloud();
191         }
192         if (cloud == null && nodes.size() > 0) {
193             cloud = nodes.getNode(0).getCloud();
194         }
195
196         if (add != Attribute.NULL) {
197             Object JavaDoc addObject = thisTag.getObjectConditional(add.getString(thisTag));
198             if (addObject != null) {
199                 if (addObject instanceof Collection) {
200                     nodes.addAll((Collection) addObject);
201                 } else {
202                     nodes.add(Casting.toNode(addObject, cloud));
203                 }
204             }
205         }
206         if (retain != Attribute.NULL) {
207             Object JavaDoc retainObject = thisTag.getObjectConditional(retain.getString(thisTag));
208             if (retainObject != null) {
209                 if (retainObject instanceof Collection) {
210                     nodes.retainAll((Collection) retainObject);
211                 } else {
212                     nodes.retainAll(Collections.singletonList((Casting.toNode(retainObject, cloud))));
213                 }
214             }
215         }
216         if (remove != Attribute.NULL) {
217             Object JavaDoc removeObject = thisTag.getObjectConditional(remove.getString(thisTag));
218             if (removeObject != null) {
219                 if (removeObject instanceof Collection) {
220                     nodes.removeAll((Collection) removeObject);
221                 } else {
222                     nodes.remove((Casting.toNode(removeObject, cloud)));
223                 }
224             }
225         }
226         ListSorter.sort(nodes, (String JavaDoc) comparator.getValue(thisTag), thisTag);
227
228         if (trim && (max != Attribute.NULL || offset != Attribute.NULL)) {
229             int currentSize = nodes.size();
230
231             int maxi = max.getInt(thisTag, currentSize);
232             int maxx = (maxi > currentSize ? currentSize : maxi);
233
234             int offseti = offset.getInt(thisTag, 0);
235
236             int to = maxx + offseti;
237             if (to >= currentSize) {
238                 to = currentSize;
239             }
240             if (offseti >= currentSize) {
241                 offseti = currentSize;
242             }
243             if (offseti < 0) {
244                 offseti = 0;
245             }
246             nodes = nodes.subNodeList(offseti, to);
247
248         }
249         returnList = nodes;
250
251         // returnList is know, now we can serve parent formatter tag
252
FormatterTag f = (FormatterTag) thisTag.findParentTag(FormatterTag.class, null, false);
253         if (f != null && f.wantXML()) {
254             f.getGenerator().add(nodes);
255             f.setCloud(cloud);
256         }
257
258         nodeIterator = returnList.nodeIterator();
259         currentItemIndex= -1;
260         previousValue = null;
261         changed = true;
262
263         if (nodeIterator.hasNext()) {
264             setNext(); // because EVAL_BODY_INCLUDE is returned now (by setReturnValues), doInitBody is not called by taglib impl.
265
return ContextReferrerTag.EVAL_BODY;
266         } else {
267             return Tag.SKIP_BODY;
268         }
269     }
270
271     public void doStartTagHelper() throws JspTagException {
272         // make a (temporary) container
273
collector = new ContextCollector(thisTag.getContextProvider());
274
275         // serve parent timer tag:
276
TagSupport t = thisTag.findParentTag(TimerTag.class, null, false);
277         if (t != null) {
278             timerHandle = ((TimerTag)t).startTimer(getId(), getClass().getName());
279         }
280         /*
281         if (thisTag.getReferid() != null) {
282             if (offset != Attribute.NULL) {
283                 throw new JspTagException("'offset' attribute does not make sense with 'referid' attribute");
284             }
285             if (max != Attribute.NULL) {
286                 throw new JspTagException("'max' attribute does not make sense with 'referid' attribute");
287             }
288         }
289         */

290
291     }
292
293     public int doAfterBody() throws JspTagException {
294         log.debug("doafterbody");
295         if (getId() != null) {
296             thisTag.getContextProvider().getContextContainer().unRegister(getId());
297         }
298
299         if (collector != null) { // might occur for some legacy extensions
300
log.debug("copying to collector");
301             collector.doAfterBody();
302         }
303         if (nodeIterator.hasNext()){
304             setNext();
305             return IterationTag.EVAL_BODY_AGAIN;
306         } else {
307             log.debug("writing body");
308             if (ContextReferrerTag.EVAL_BODY == BodyTag.EVAL_BODY_BUFFERED) {
309                 BodyContent bodyContent = thisTag.getBodyContent();
310                 if (bodyContent != null) {
311                     try {
312                         bodyContent.writeOut(bodyContent.getEnclosingWriter());
313                     } catch (IOException JavaDoc ioe){
314                         throw new TaglibException(ioe);
315                     }
316                 }
317             }
318             return Tag.SKIP_BODY;
319         }
320     }
321
322     public int doEndTag() throws JspTagException {
323         if (getId() != null) {
324             thisTag.getContextProvider().getContextContainer().register(getId(), returnList, false); // use false because check was done in doStartTag (and doAfterBody not always called).
325
}
326         TagSupport t = thisTag.findParentTag(TimerTag.class, null, false);
327         if (t != null) {
328             ((TimerTag)t).haltTimer(timerHandle);
329         }
330
331         return EVAL_PAGE;
332     }
333
334
335     /**
336      * The first ordered field is used to determin the 'changed' status of a Node in a NodeList.
337      * @since MMBase-1.8
338      */

339     protected String JavaDoc getFirstOrderedField(NodeList returnList, NodeManager nextNodeManager) {
340         // the orderby attribute is arranged in AbstractNodeListTag#setReturnValues
341
// Perhaps its code could more logically be present here.
342
/*
343         Query query = (Query) returnList.getProperty(NodeList.QUERY_PROPERTY);
344         if (query != null && false) {
345             List sortOrders = query.getSortOrders();
346             if (sortOrders.size() > 0) {
347                 SortOrder order = (SortOrder) sortOrders.get(0);
348                 StepField stepField = order.getField();
349                 String alias = stepField.getAlias();
350                 if (alias == null) {
351                     Step step = stepField.getStep();
352                     String stepAlias = step.getAlias();
353                     if (stepAlias == null) stepAlias = step.getTableName();
354                     alias = stepAlias + "." + stepField.getFieldName();
355                 }
356                 return alias;
357             } else {
358                 return null;
359             }
360
361         } else {
362         */

363         // use order as stored in the nodelist (the property of the tag may not be set
364
// if you use referid to get the result of a previous listtag)
365
String JavaDoc listOrder = (String JavaDoc) returnList.getProperty("orderby");
366         if (listOrder != null && ! "".equals(listOrder)) {
367                 // then you can also ask if 'changed' the node
368
// look only at first field of sorted for the moment.
369
String JavaDoc[] fa = listOrder.trim().split("\\s*,\\s*");
370             int i = 0;
371             while(i < fa.length && ! nextNodeManager.hasField(fa[i])) {
372                 i++;
373             }
374             return i < fa.length ? fa[i] : null;
375         } else {
376             return null;
377         }
378         // }
379
}
380
381     public void setNext() throws JspTagException {
382         try {
383             currentItemIndex ++;
384             Node next = nodeIterator.nextNode();
385             while (next == null) {
386                 log.warn("Found null in node list " + returnList + " skipping");
387                 currentItemIndex ++;
388                 if (nodeIterator.hasNext()) {
389                     next = nodeIterator.nextNode();
390                 } else {
391                     return;
392                 }
393             }
394             NodeManager nextNodeManager = next.getNodeManager();
395             if (nextNodeManager == null) throw new RuntimeException JavaDoc("Found node " + next + " has no NodeManager");
396             String JavaDoc orderField = getFirstOrderedField(returnList, nextNodeManager);
397             if (orderField != null) {
398                 String JavaDoc value = "" + next.getValue(orderField);
399                 if (previousValue != null) {
400                     if (value.equals(previousValue)) {
401                         changed = false;
402                     } else {
403                         changed = true;
404                     }
405                 }
406                 previousValue = value;
407
408             }
409             nodeHelper.setNodeVar(next);
410             nodeHelper.fillVars();
411         } catch (BridgeException be) { // e.g. NodeManager does not exist
412
log.warn(be.getMessage(), be);
413         }
414     }
415
416     /**
417      * If you order a list, then the 'changed' property will be
418      * true if the field on which you order changed value.
419      **/

420     public boolean isChanged() {
421         return changed;
422     }
423
424     public int size() {
425         return returnList.size();
426     }
427
428     public Object JavaDoc getCurrent() {
429         return nodeHelper.getNodeVar();
430     }
431
432     public LoopTagStatus getLoopStatus() {
433         return new ListProviderLoopTagStatus(this);
434     }
435
436     public void release() {
437         doFinally();
438     }
439
440     public void doFinally() {
441         if (collector != null) {
442             try {
443                 collector.release(thisTag.getPageContext(), thisTag.getContextProvider().getContextContainer());
444                 collector = null;
445             } catch (Exception JavaDoc e) {
446             }
447         }
448         if (nodeHelper != null) {
449             nodeHelper.doFinally();
450         }
451         nodeIterator = null;
452         returnList = null;
453         previousValue = null;
454     }
455     // unused
456
public int doStartTag() throws JspTagException {
457         return -1;
458     }
459     // unused
460
public Tag getParent() {
461         return null;
462     }
463     // unused
464
public void setParent(Tag tag) {
465
466     }
467     // unused
468
public void setPageContext(PageContext pc) {
469     }
470
471
472
473 }
474
Popular Tags