001: package com.sun.facelets.component;
002:
003: import java.io.IOException;
004: import java.io.Serializable;
005: import java.sql.ResultSet;
006: import java.util.Collections;
007: import java.util.HashMap;
008: import java.util.Iterator;
009: import java.util.List;
010: import java.util.Map;
011:
012: import javax.faces.FacesException;
013: import javax.faces.application.FacesMessage;
014: import javax.faces.component.EditableValueHolder;
015: import javax.faces.component.NamingContainer;
016: import javax.faces.component.UIComponent;
017: import javax.faces.component.UIComponentBase;
018: import javax.faces.component.UIData;
019: import javax.faces.context.FacesContext;
020: import javax.faces.el.ValueBinding;
021: import javax.faces.event.AbortProcessingException;
022: import javax.faces.event.FacesEvent;
023: import javax.faces.event.FacesListener;
024: import javax.faces.event.PhaseId;
025: import javax.faces.model.ArrayDataModel;
026: import javax.faces.model.DataModel;
027: import javax.faces.model.ListDataModel;
028: import javax.faces.model.ResultSetDataModel;
029: import javax.faces.model.ScalarDataModel;
030: import javax.faces.render.Renderer;
031:
032: import com.sun.facelets.tag.jsf.ComponentSupport;
033: import com.sun.facelets.util.FacesAPI;
034:
035: public class UIRepeat extends UIComponentBase implements
036: NamingContainer {
037:
038: public static final String COMPONENT_TYPE = "facelets.ui.Repeat";
039:
040: public static final String COMPONENT_FAMILY = "facelets";
041:
042: private final static DataModel EMPTY_MODEL = new ListDataModel(
043: Collections.EMPTY_LIST);
044:
045: // our data
046: private Object value;
047:
048: private transient DataModel model;
049:
050: // variables
051: private String var;
052:
053: private String varStatus;
054:
055: private int index = -1;
056:
057: // scoping
058: private int offset = -1;
059:
060: private int size = -1;
061:
062: public UIRepeat() {
063: this .setRendererType("facelets.ui.Repeat");
064: }
065:
066: public String getFamily() {
067: return COMPONENT_FAMILY;
068: }
069:
070: public int getOffset() {
071: if (this .offset != -1) {
072: return this .offset;
073: }
074: ValueBinding vb = this .getValueBinding("offset");
075: if (vb != null) {
076: return ((Integer) vb.getValue(FacesContext
077: .getCurrentInstance())).intValue();
078: }
079: return 0;
080: }
081:
082: public void setOffset(int offset) {
083: this .offset = offset;
084: }
085:
086: public int getSize() {
087: if (this .size != -1) {
088: return this .size;
089: }
090: ValueBinding vb = this .getValueBinding("size");
091: if (vb != null) {
092: return ((Integer) vb.getValue(FacesContext
093: .getCurrentInstance())).intValue();
094: }
095: return -1;
096: }
097:
098: public void setSize(int size) {
099: this .size = size;
100: }
101:
102: public String getVar() {
103: return this .var;
104: }
105:
106: public void setVar(String var) {
107: this .var = var;
108: }
109:
110: private void resetDataModel() {
111: if (this .isNestedInIterator()) {
112: this .setDataModel(null);
113: }
114: }
115:
116: private synchronized void setDataModel(DataModel model) {
117: this .model = model;
118: }
119:
120: private synchronized DataModel getDataModel() {
121: if (this .model == null) {
122: Object val = this .getValue();
123: if (val == null) {
124: this .model = EMPTY_MODEL;
125: } else if (val instanceof DataModel) {
126: this .model = (DataModel) val;
127: } else if (val instanceof List) {
128: this .model = new ListDataModel((List) val);
129: } else if (Object[].class.isAssignableFrom(val.getClass())) {
130: this .model = new ArrayDataModel((Object[]) val);
131: } else if (val instanceof ResultSet) {
132: this .model = new ResultSetDataModel((ResultSet) val);
133: } else {
134: this .model = new ScalarDataModel(val);
135: }
136: }
137: return this .model;
138: }
139:
140: public Object getValue() {
141: if (this .value == null) {
142: ValueBinding vb = this .getValueBinding("value");
143: if (vb != null) {
144: return vb.getValue(FacesContext.getCurrentInstance());
145: }
146: }
147: return this .value;
148: }
149:
150: public void setValue(Object value) {
151: this .value = value;
152: }
153:
154: private transient StringBuffer buffer;
155:
156: private StringBuffer getBuffer() {
157: if (this .buffer == null) {
158: this .buffer = new StringBuffer();
159: }
160: this .buffer.setLength(0);
161: return this .buffer;
162: }
163:
164: public String getClientId(FacesContext faces) {
165: String id = super .getClientId(faces);
166: if (this .index >= 0) {
167: id = this .getBuffer().append(id).append(
168: NamingContainer.SEPARATOR_CHAR).append(this .index)
169: .toString();
170: }
171: return id;
172: }
173:
174: private transient Object origValue;
175:
176: private void captureOrigValue() {
177: if (this .var != null) {
178: FacesContext faces = FacesContext.getCurrentInstance();
179: Map attrs = faces.getExternalContext().getRequestMap();
180: this .origValue = attrs.get(this .var);
181: }
182: }
183:
184: private void restoreOrigValue() {
185: if (this .var != null) {
186: FacesContext faces = FacesContext.getCurrentInstance();
187: Map attrs = faces.getExternalContext().getRequestMap();
188: if (this .origValue != null) {
189: attrs.put(this .var, this .origValue);
190: } else {
191: attrs.remove(this .var);
192: }
193: }
194: }
195:
196: private Map childState;
197:
198: private Map getChildState() {
199: if (this .childState == null) {
200: this .childState = new HashMap();
201: }
202: return this .childState;
203: }
204:
205: private void saveChildState() {
206: if (this .getChildCount() > 0) {
207:
208: FacesContext faces = FacesContext.getCurrentInstance();
209:
210: Iterator itr = this .getChildren().iterator();
211: while (itr.hasNext()) {
212: this .saveChildState(faces, (UIComponent) itr.next());
213: }
214: }
215: }
216:
217: private void saveChildState(FacesContext faces, UIComponent c) {
218:
219: if (c instanceof EditableValueHolder && !c.isTransient()) {
220: String clientId = c.getClientId(faces);
221: SavedState ss = (SavedState) this .getChildState().get(
222: clientId);
223: if (ss == null) {
224: ss = new SavedState();
225: this .getChildState().put(clientId, ss);
226: }
227: ss.populate((EditableValueHolder) c);
228: }
229:
230: // continue hack
231: Iterator itr = c.getFacetsAndChildren();
232: while (itr.hasNext()) {
233: saveChildState(faces, (UIComponent) itr.next());
234: }
235: }
236:
237: private void restoreChildState() {
238: if (this .getChildCount() > 0) {
239:
240: FacesContext faces = FacesContext.getCurrentInstance();
241:
242: Iterator itr = this .getChildren().iterator();
243: while (itr.hasNext()) {
244: this .restoreChildState(faces, (UIComponent) itr.next());
245: }
246: }
247: }
248:
249: private void restoreChildState(FacesContext faces, UIComponent c) {
250: // reset id
251: String id = c.getId();
252: c.setId(id);
253:
254: // hack
255: if (c instanceof EditableValueHolder) {
256: EditableValueHolder evh = (EditableValueHolder) c;
257: String clientId = c.getClientId(faces);
258: SavedState ss = (SavedState) this .getChildState().get(
259: clientId);
260: if (ss != null) {
261: ss.apply(evh);
262: } else {
263: NullState.apply(evh);
264: }
265: }
266:
267: // continue hack
268: Iterator itr = c.getFacetsAndChildren();
269: while (itr.hasNext()) {
270: restoreChildState(faces, (UIComponent) itr.next());
271: }
272: }
273:
274: private boolean keepSaved(FacesContext context) {
275:
276: Iterator clientIds = this .getChildState().keySet().iterator();
277: while (clientIds.hasNext()) {
278: String clientId = (String) clientIds.next();
279: Iterator messages = context.getMessages(clientId);
280: while (messages.hasNext()) {
281: FacesMessage message = (FacesMessage) messages.next();
282: if (message.getSeverity().compareTo(
283: FacesMessage.SEVERITY_ERROR) >= 0) {
284: return (true);
285: }
286: }
287: }
288: return (isNestedInIterator());
289: }
290:
291: private boolean isNestedInIterator() {
292: UIComponent parent = this .getParent();
293: while (parent != null) {
294: if (parent instanceof UIData || parent instanceof UIRepeat) {
295: return true;
296: }
297: parent = parent.getParent();
298: }
299: return false;
300: }
301:
302: private void setIndex(int index) {
303:
304: // save child state
305: this .saveChildState();
306:
307: this .index = index;
308: DataModel localModel = getDataModel();
309: localModel.setRowIndex(index);
310:
311: if (this .index != -1 && this .var != null
312: && localModel.isRowAvailable()) {
313: FacesContext faces = FacesContext.getCurrentInstance();
314: Map attrs = faces.getExternalContext().getRequestMap();
315: attrs.put(var, localModel.getRowData());
316: }
317:
318: // restore child state
319: this .restoreChildState();
320: }
321:
322: private boolean isIndexAvailable() {
323: return this .getDataModel().isRowAvailable();
324: }
325:
326: public void process(FacesContext faces, PhaseId phase) {
327:
328: // stop if not rendered
329: if (!this .isRendered())
330: return;
331:
332: // clear datamodel
333: this .resetDataModel();
334:
335: // reset index
336: this .captureOrigValue();
337: this .setIndex(-1);
338:
339: try {
340: // has children
341: if (this .getChildCount() > 0) {
342: Iterator itr;
343: UIComponent c;
344:
345: int i = this .getOffset();
346: int end = this .getSize();
347: end = (end >= 0) ? i + end : Integer.MAX_VALUE - 1;
348:
349: // grab renderer
350: String rendererType = getRendererType();
351: Renderer renderer = null;
352: if (rendererType != null) {
353: renderer = getRenderer(faces);
354: }
355:
356: this .setIndex(i);
357: while (i <= end && this .isIndexAvailable()) {
358:
359: if (PhaseId.RENDER_RESPONSE.equals(phase)
360: && renderer != null) {
361: renderer.encodeChildren(faces, this );
362: } else {
363: itr = this .getChildren().iterator();
364: while (itr.hasNext()) {
365: c = (UIComponent) itr.next();
366: if (PhaseId.APPLY_REQUEST_VALUES
367: .equals(phase)) {
368: c.processDecodes(faces);
369: } else if (PhaseId.PROCESS_VALIDATIONS
370: .equals(phase)) {
371: c.processValidators(faces);
372: } else if (PhaseId.UPDATE_MODEL_VALUES
373: .equals(phase)) {
374: c.processUpdates(faces);
375: } else if (PhaseId.RENDER_RESPONSE
376: .equals(phase)) {
377: if (FacesAPI.getVersion() >= 12) {
378: c.encodeAll(faces);
379: } else {
380: ComponentSupport.encodeRecursive(
381: faces, c);
382: }
383: }
384: }
385: }
386: i++;
387: this .setIndex(i);
388: }
389: }
390: } catch (IOException e) {
391: throw new FacesException(e);
392: } finally {
393: this .setIndex(-1);
394: this .restoreOrigValue();
395: }
396: }
397:
398: // public boolean invokeOnComponent(FacesContext faces, String clientId,
399: // ContextCallback callback) throws FacesException {
400: // String id = super.getClientId(faces);
401: // if (clientId.equals(id)) {
402: // callback.invokeContextCallback(faces, this);
403: // return true;
404: // } else if (clientId.startsWith(id)) {
405: // int prevIndex = this.index;
406: // int idxStart = clientId.indexOf(NamingContainer.SEPARATOR_CHAR, id
407: // .length());
408: // if (idxStart != -1
409: // && Character.isDigit(clientId.charAt(idxStart + 1))) {
410: // int idxEnd = clientId.indexOf(NamingContainer.SEPARATOR_CHAR,
411: // idxStart);
412: // if (idxEnd != -1) {
413: // int newIndex = Integer.parseInt(clientId.substring(
414: // idxStart, idxEnd));
415: // boolean found = false;
416: // try {
417: // this.captureOrigValue();
418: // this.setIndex(newIndex);
419: // if (this.isIndexAvailable()) {
420: // found = super.invokeOnComponent(faces, clientId,
421: // callback);
422: // }
423: // } finally {
424: // this.setIndex(prevIndex);
425: // this.restoreOrigValue();
426: // }
427: // return found;
428: // }
429: // } else {
430: // return super.invokeOnComponent(faces, clientId, callback);
431: // }
432: // }
433: // return false;
434: // }
435:
436: public void processDecodes(FacesContext faces) {
437: if (!this .isRendered())
438: return;
439: this .setDataModel(null);
440: if (!this .keepSaved(faces))
441: this .childState = null;
442: this .process(faces, PhaseId.APPLY_REQUEST_VALUES);
443: this .decode(faces);
444: }
445:
446: public void processUpdates(FacesContext faces) {
447: if (!this .isRendered())
448: return;
449: this .resetDataModel();
450: this .process(faces, PhaseId.UPDATE_MODEL_VALUES);
451: }
452:
453: public void processValidators(FacesContext faces) {
454: if (!this .isRendered())
455: return;
456: this .resetDataModel();
457: this .process(faces, PhaseId.PROCESS_VALIDATIONS);
458: }
459:
460: private final static SavedState NullState = new SavedState();
461:
462: // from RI
463: private final static class SavedState implements Serializable {
464:
465: private Object submittedValue;
466:
467: private static final long serialVersionUID = 2920252657338389849L;
468:
469: Object getSubmittedValue() {
470: return (this .submittedValue);
471: }
472:
473: void setSubmittedValue(Object submittedValue) {
474: this .submittedValue = submittedValue;
475: }
476:
477: private boolean valid = true;
478:
479: boolean isValid() {
480: return (this .valid);
481: }
482:
483: void setValid(boolean valid) {
484: this .valid = valid;
485: }
486:
487: private Object value;
488:
489: Object getValue() {
490: return (this .value);
491: }
492:
493: public void setValue(Object value) {
494: this .value = value;
495: }
496:
497: private boolean localValueSet;
498:
499: boolean isLocalValueSet() {
500: return (this .localValueSet);
501: }
502:
503: public void setLocalValueSet(boolean localValueSet) {
504: this .localValueSet = localValueSet;
505: }
506:
507: public String toString() {
508: return ("submittedValue: " + submittedValue + " value: "
509: + value + " localValueSet: " + localValueSet);
510: }
511:
512: public void populate(EditableValueHolder evh) {
513: this .value = evh.getValue();
514: this .valid = evh.isValid();
515: this .submittedValue = evh.getSubmittedValue();
516: this .localValueSet = evh.isLocalValueSet();
517: }
518:
519: public void apply(EditableValueHolder evh) {
520: evh.setValue(this .value);
521: evh.setValid(this .valid);
522: evh.setSubmittedValue(this .submittedValue);
523: evh.setLocalValueSet(this .localValueSet);
524: }
525:
526: }
527:
528: private final class IndexedEvent extends FacesEvent {
529:
530: private final FacesEvent target;
531:
532: private final int index;
533:
534: public IndexedEvent(UIRepeat owner, FacesEvent target, int index) {
535: super (owner);
536: this .target = target;
537: this .index = index;
538: }
539:
540: public PhaseId getPhaseId() {
541: return (this .target.getPhaseId());
542: }
543:
544: public void setPhaseId(PhaseId phaseId) {
545: this .target.setPhaseId(phaseId);
546: }
547:
548: public boolean isAppropriateListener(FacesListener listener) {
549: return this .target.isAppropriateListener(listener);
550: }
551:
552: public void processListener(FacesListener listener) {
553: UIRepeat owner = (UIRepeat) this .getComponent();
554: int prevIndex = owner.index;
555: try {
556: owner.setIndex(this .index);
557: if (owner.isIndexAvailable()) {
558: this .target.processListener(listener);
559: }
560: } finally {
561: owner.setIndex(prevIndex);
562: }
563: }
564:
565: public int getIndex() {
566: return index;
567: }
568:
569: public FacesEvent getTarget() {
570: return target;
571: }
572:
573: }
574:
575: public void broadcast(FacesEvent event)
576: throws AbortProcessingException {
577: if (event instanceof IndexedEvent) {
578: IndexedEvent idxEvent = (IndexedEvent) event;
579: this .resetDataModel();
580: int prevIndex = this .index;
581: try {
582: this .setIndex(idxEvent.getIndex());
583: if (this .isIndexAvailable()) {
584: FacesEvent target = idxEvent.getTarget();
585: target.getComponent().broadcast(target);
586: }
587: } finally {
588: this .setIndex(prevIndex);
589: }
590: } else {
591: super .broadcast(event);
592: }
593: }
594:
595: public void queueEvent(FacesEvent event) {
596: super .queueEvent(new IndexedEvent(this , event, this .index));
597: }
598:
599: public void restoreState(FacesContext faces, Object object) {
600: Object[] state = (Object[]) object;
601: super .restoreState(faces, state[0]);
602: this .childState = (Map) state[1];
603: this .offset = ((Integer) state[2]).intValue();
604: this .size = ((Integer) state[3]).intValue();
605: this .var = (String) state[4];
606: this .value = state[5];
607: }
608:
609: public Object saveState(FacesContext faces) {
610: Object[] state = new Object[6];
611: state[0] = super .saveState(faces);
612: state[1] = this .childState;
613: state[2] = new Integer(this .offset);
614: state[3] = new Integer(this .size);
615: state[4] = this .var;
616: state[5] = this .value;
617: return state;
618: }
619:
620: public void encodeChildren(FacesContext faces) throws IOException {
621: if (!isRendered()) {
622: return;
623: }
624: this .setDataModel(null);
625: if (!this .keepSaved(faces)) {
626: this .childState = null;
627: }
628: this .process(faces, PhaseId.RENDER_RESPONSE);
629: }
630:
631: public boolean getRendersChildren() {
632: Renderer renderer = null;
633: if (getRendererType() != null) {
634: if (null != (renderer = getRenderer(getFacesContext()))) {
635: return renderer.getRendersChildren();
636: }
637: }
638: return true;
639: }
640: }
|