001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License version 2
011: * as published by the Free Software Foundation.
012: *
013: * Resin Open Source is distributed in the hope that it will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
016: * of NON-INFRINGEMENT. See the GNU General Public License for more
017: * details.
018: *
019: * You should have received a copy of the GNU General Public License
020: * along with Resin Open Source; if not, write to the
021: *
022: * Free Software Foundation, Inc.
023: * 59 Temple Place, Suite 330
024: * Boston, MA 02111-1307 USA
025: *
026: * @author Scott Ferguson
027: */
028:
029: package javax.faces.component;
030:
031: import java.util.*;
032: import java.sql.ResultSet;
033:
034: import javax.el.*;
035:
036: import javax.faces.context.*;
037: import javax.faces.event.*;
038: import javax.faces.model.*;
039:
040: import javax.servlet.jsp.jstl.sql.Result;
041:
042: public class UIData extends UIComponentBase implements NamingContainer {
043: public static final String COMPONENT_FAMILY = "javax.faces.Data";
044: public static final String COMPONENT_TYPE = "javax.faces.Data";
045:
046: private static final HashMap<String, PropEnum> _propMap = new HashMap<String, PropEnum>();
047:
048: private static final Object[] NULL_ARRAY = new Object[0];
049:
050: private DataModel _dataModel;
051: private Object _dataModelValue;
052:
053: private Integer _first;
054: private ValueExpression _firstExpr;
055:
056: private Integer _rows;
057: private ValueExpression _rowsExpr;
058:
059: private Object _value;
060: private ValueExpression _valueExpr;
061:
062: private String _var;
063: private int _rowIndex = -1;
064:
065: private ArrayList<ArrayList<State>> _state;
066:
067: public UIData() {
068: setRendererType("javax.faces.Table");
069: }
070:
071: /**
072: * Returns the component family, used to select the renderer.
073: */
074: public String getFamily() {
075: return COMPONENT_FAMILY;
076: }
077:
078: //
079: // Properties
080: //
081:
082: public int getFirst() {
083: if (_first != null)
084: return _first;
085: else if (_firstExpr != null)
086: return Util.evalInt(_firstExpr, getFacesContext());
087: else
088: return 0;
089: }
090:
091: public void setFirst(int first) {
092: if (first < 0)
093: throw new IllegalArgumentException(
094: "UIData.setFirst must have a positive value at '"
095: + first + "'");
096: _first = first;
097: }
098:
099: public int getRows() {
100: int rows;
101:
102: if (_rows != null)
103: rows = _rows;
104: else if (_rowsExpr != null)
105: rows = Util.evalInt(_rowsExpr, getFacesContext());
106: else
107: rows = 0;
108:
109: return rows;
110: }
111:
112: public void setRows(int rows) {
113: if (rows < 0)
114: throw new IllegalArgumentException(
115: "UIData.setFirst must have a positive value at '"
116: + rows + "'");
117: _rows = rows;
118: }
119:
120: public String getVar() {
121: return _var;
122: }
123:
124: public void setVar(String var) {
125: _var = var;
126: }
127:
128: public Object getValue() {
129: Object value;
130:
131: if (_value != null)
132: value = _value;
133: else if (_valueExpr != null)
134: value = Util.eval(_valueExpr, getFacesContext());
135: else
136: value = null;
137:
138: return value;
139: }
140:
141: public void setValue(Object value) {
142: _value = value;
143: setDataModel(null);
144:
145: }
146:
147: protected DataModel getDataModel() {
148: if (_dataModel != null)
149: return _dataModel;
150:
151: _dataModel = createDataModel(getValue());
152:
153: return _dataModel;
154: }
155:
156: protected void setDataModel(DataModel dataModel) {
157: _dataModel = dataModel;
158: _state = null;
159: }
160:
161: private void resetDataModel() {
162: Object value = getValue();
163:
164: if (value != _dataModelValue)
165: setDataModel(null);
166: }
167:
168: private DataModel createDataModel(Object value) {
169: _dataModelValue = value;
170:
171: if (value == null)
172: return new ArrayDataModel(NULL_ARRAY);
173: else if (value instanceof DataModel)
174: return (DataModel) value;
175: else if (value instanceof List)
176: return new ListDataModel((List) value);
177: else if (value instanceof ResultSet)
178: return new ResultSetDataModel((ResultSet) value);
179: else if (value instanceof Result)
180: return new ResultDataModel((Result) value);
181: else if (value.getClass().isArray())
182: return new ArrayDataModel((Object[]) value);
183: else
184: return new ScalarDataModel(value);
185: }
186:
187: public int getRowIndex() {
188: return _rowIndex;
189: }
190:
191: public Object getRowData() {
192: return getDataModel().getRowData();
193: }
194:
195: public void setRowIndex(int value) {
196: if (value < -1)
197: throw new IllegalArgumentException(
198: "UIData.setRowIndex must not be less than -1 at '"
199: + value + "'");
200:
201: DataModel dataModel = getDataModel();
202:
203: int oldRow = _rowIndex;
204:
205: _rowIndex = value;
206:
207: dataModel.setRowIndex(value);
208:
209: if (dataModel.isRowAvailable())
210: setRowIndexState(dataModel, oldRow, _rowIndex);
211: else
212: setRowIndexState(dataModel, oldRow, -1);
213:
214: if (_var == null) {
215: } else if (value >= 0 && dataModel.isRowAvailable()) {
216: Object rowData = dataModel.getRowData();
217:
218: FacesContext context = FacesContext.getCurrentInstance();
219:
220: context.getExternalContext().getRequestMap().put(_var,
221: rowData);
222: } else {
223: FacesContext context = FacesContext.getCurrentInstance();
224:
225: context.getExternalContext().getRequestMap().remove(_var);
226: }
227: }
228:
229: private void setRowIndexState(DataModel model, int oldRow,
230: int newRow) {
231: if (_state == null)
232: _state = new ArrayList<ArrayList<State>>();
233:
234: setRowIndexState(this , oldRow, newRow, false, 0);
235: }
236:
237: private int setRowIndexState(UIComponent comp, int oldRow,
238: int newRow, boolean isTransient, int valueIndex) {
239: //skip self
240: if (comp != this )
241: comp.setId(comp.getId());
242:
243: if (comp.isTransient())
244: isTransient = true;
245: else if (comp instanceof EditableValueHolder) {
246: EditableValueHolder holder = (EditableValueHolder) comp;
247:
248: if (oldRow >= 0) {
249: ArrayList<State> oldList;
250:
251: while (_state.size() <= oldRow)
252: _state.add(null);
253:
254: oldList = _state.get(oldRow);
255:
256: if (oldList == null) {
257: oldList = new ArrayList<State>();
258:
259: _state.set(oldRow, oldList);
260: }
261:
262: while (oldList.size() < (valueIndex + 1))
263: oldList.add(null);
264:
265: State state = oldList.get(valueIndex);
266:
267: if (state != null)
268: state = state.update(holder);
269: else
270: state = new State(holder);
271:
272: oldList.set(valueIndex, state);
273: }
274:
275: ArrayList<State> newList = null;
276:
277: if (newRow >= 0 && newRow < _state.size())
278: newList = _state.get(newRow);
279:
280: State state;
281:
282: if (newList != null && valueIndex < newList.size())
283: state = newList.get(valueIndex);
284: else
285: state = null;
286:
287: if (state != null)
288: state.restore(holder);
289: else {
290: holder.setSubmittedValue(null);
291: holder.setValue(null);
292: holder.setLocalValueSet(false);
293: holder.setValid(true);
294: }
295:
296: valueIndex += 1;
297: }
298:
299: if (comp instanceof UIComponentBase) {
300: UIComponentBase base = (UIComponentBase) comp;
301:
302: for (UIComponent child : base.getFacetsAndChildrenArray()) {
303: valueIndex = setRowIndexState(child, oldRow, newRow,
304: isTransient, valueIndex);
305: }
306: } else {
307: Iterator<UIComponent> iter = comp.getFacetsAndChildren();
308:
309: while (iter.hasNext()) {
310: UIComponent child = iter.next();
311:
312: valueIndex = setRowIndexState(child, oldRow, newRow,
313: isTransient, valueIndex);
314: }
315: }
316:
317: return valueIndex;
318: }
319:
320: public int getRowCount() {
321: DataModel model = getDataModel();
322:
323: if (model != null)
324: return model.getRowCount();
325: else
326: return -1;
327: }
328:
329: public boolean isRowAvailable() {
330: DataModel model = getDataModel();
331:
332: if (model != null)
333: return model.isRowAvailable();
334: else
335: return false;
336: }
337:
338: /**
339: * Returns the value expression with the given name.
340: */
341: @Override
342: public ValueExpression getValueExpression(String name) {
343: PropEnum prop = _propMap.get(name);
344:
345: if (prop != null) {
346: switch (_propMap.get(name)) {
347: case VALUE:
348: return _valueExpr;
349:
350: case FIRST:
351: return _firstExpr;
352:
353: case ROWS:
354: return _rowsExpr;
355: }
356: }
357:
358: return super .getValueExpression(name);
359: }
360:
361: /**
362: * Sets the value expression with the given name.
363: */
364: @Override
365: public void setValueExpression(String name, ValueExpression expr) {
366: PropEnum prop = _propMap.get(name);
367:
368: if (prop != null) {
369: switch (_propMap.get(name)) {
370: case VALUE:
371: _dataModel = null;
372: if (expr != null && expr.isLiteralText()) {
373: _value = expr.getValue(null);
374: return;
375: } else
376: _valueExpr = expr;
377: break;
378:
379: case FIRST:
380: if (expr != null && expr.isLiteralText()) {
381: _first = (Integer) expr.getValue(null);
382: return;
383: } else
384: _firstExpr = expr;
385: break;
386:
387: case ROWS:
388: if (expr != null && expr.isLiteralText()) {
389: _rows = (Integer) expr.getValue(null);
390: return;
391: } else
392: _rowsExpr = expr;
393: break;
394: }
395: }
396:
397: super .setValueExpression(name, expr);
398: }
399:
400: //
401: // Facets
402: //
403:
404: public UIComponent getHeader() {
405: return getFacet("header");
406: }
407:
408: public void setHeader(UIComponent header) {
409: getFacets().put("header", header);
410: }
411:
412: public UIComponent getFooter() {
413: return getFacet("footer");
414: }
415:
416: public void setFooter(UIComponent footer) {
417: getFacets().put("footer", footer);
418: }
419:
420: //
421: // overrides
422:
423: /**
424: * Returns the client-specific id for the component.
425: */
426: @Override
427: public String getClientId(FacesContext context) {
428: String clientId = super .getClientId(context);
429:
430: int rowIndex = getRowIndex();
431:
432: if (rowIndex < 0)
433: return clientId;
434: else
435: return clientId + SEPARATOR_CHAR + rowIndex;
436: }
437:
438: /**
439: * Queues the event, wrapping the rowIndex.
440: */
441: @Override
442: public void queueEvent(FacesEvent event) {
443: int rowIndex = getRowIndex();
444:
445: super .queueEvent(new UIDataEventWrapper(event, this , rowIndex));
446: }
447:
448: /**
449: * Broadcasts the event, unwrapping the rowIndex.
450: */
451: @Override
452: public void broadcast(FacesEvent event)
453: throws AbortProcessingException {
454: if (event instanceof UIDataEventWrapper) {
455: UIDataEventWrapper wrapper = (UIDataEventWrapper) event;
456:
457: event = wrapper.getEvent();
458:
459: int oldIndex = getRowIndex();
460: setRowIndex(wrapper.getRowIndex());
461:
462: event.getComponent().broadcast(event);
463:
464: setRowIndex(oldIndex);
465: } else
466: super .broadcast(event);
467: }
468:
469: /**
470: * Recursively calls the decodes for any children, then calls
471: * decode().
472: */
473: @Override
474: public void processDecodes(FacesContext context) {
475: if (context == null)
476: throw new NullPointerException();
477:
478: if (!isRendered())
479: return;
480:
481: setRowIndex(-1);
482:
483: if (getFacetCount() > 0) {
484: for (UIComponent facet : getFacets().values()) {
485: facet.processDecodes(context);
486: }
487: }
488:
489: int childCount = getChildCount();
490:
491: if (childCount > 0) {
492: List<UIComponent> children = getChildren();
493:
494: for (int i = 0; i < children.size(); i++) {
495: UIComponent child = children.get(i);
496:
497: if (!child.isRendered() && child.getFacetCount() == 0)
498: continue;
499:
500: for (UIComponent facet : child.getFacets().values()) {
501: facet.processDecodes(context);
502: }
503: }
504:
505: int first = getFirst();
506: int rows = getRows();
507:
508: if (rows <= 0)
509: rows = Integer.MAX_VALUE;
510:
511: for (int i = 0; i < rows; i++) {
512: setRowIndex(first + i);
513:
514: if (!isRowAvailable())
515: break;
516:
517: for (int j = 0; j < childCount; j++) {
518: UIComponent child = children.get(j);
519:
520: if (!child.isRendered())
521: continue;
522:
523: int grandchildCount = child.getChildCount();
524:
525: if (grandchildCount > 0) {
526: List<UIComponent> grandchildren = child
527: .getChildren();
528:
529: for (int k = 0; k < grandchildCount; k++) {
530: grandchildren.get(k)
531: .processDecodes(context);
532: }
533: }
534:
535: child.decode(context);
536: }
537: }
538: }
539:
540: setRowIndex(-1);
541:
542: decode(context);
543: }
544:
545: /**
546: * Recursively calls the validators for any children, then calls
547: * decode().
548: */
549: @Override
550: public void processValidators(FacesContext context) {
551: if (context == null)
552: throw new NullPointerException();
553:
554: if (!isRendered())
555: return;
556:
557: setRowIndex(-1);
558:
559: if (getFacetCount() > 0) {
560: for (UIComponent facet : getFacets().values()) {
561: facet.processValidators(context);
562: }
563: }
564:
565: int childCount = getChildCount();
566:
567: if (childCount > 0) {
568: List<UIComponent> children = getChildren();
569:
570: for (int i = 0; i < children.size(); i++) {
571: UIComponent child = children.get(i);
572:
573: if (!child.isRendered() && child.getFacetCount() == 0)
574: continue;
575:
576: for (UIComponent facet : child.getFacets().values()) {
577: facet.processValidators(context);
578: }
579: }
580:
581: int first = getFirst();
582: int rows = getRows();
583:
584: if (rows <= 0)
585: rows = Integer.MAX_VALUE;
586:
587: for (int i = 0; i < rows; i++) {
588: setRowIndex(first + i);
589:
590: if (!isRowAvailable())
591: break;
592:
593: for (int j = 0; j < childCount; j++) {
594: UIComponent child = children.get(j);
595:
596: if (!child.isRendered())
597: continue;
598:
599: int grandchildCount = child.getChildCount();
600: List<UIComponent> grandchildren = child
601: .getChildren();
602:
603: for (int k = 0; k < grandchildCount; k++) {
604: grandchildren.get(k).processValidators(context);
605: }
606: }
607: }
608: }
609:
610: setRowIndex(-1);
611: }
612:
613: /**
614: * Recursively calls the updates for any children, then calls
615: * decode().
616: */
617: @Override
618: public void processUpdates(FacesContext context) {
619: if (context == null)
620: throw new NullPointerException();
621:
622: if (!isRendered())
623: return;
624:
625: setRowIndex(-1);
626:
627: if (getFacetCount() > 0) {
628: for (UIComponent facet : getFacets().values()) {
629: facet.processUpdates(context);
630: }
631: }
632:
633: int childCount = getChildCount();
634:
635: if (childCount > 0) {
636: List<UIComponent> children = getChildren();
637:
638: for (int i = 0; i < children.size(); i++) {
639: UIComponent child = children.get(i);
640:
641: if (!child.isRendered() && child.getFacetCount() == 0)
642: continue;
643:
644: for (UIComponent facet : child.getFacets().values()) {
645: facet.processUpdates(context);
646: }
647: }
648:
649: int first = getFirst();
650: int rows = getRows();
651:
652: if (rows <= 0)
653: rows = Integer.MAX_VALUE;
654:
655: for (int i = 0; i < rows; i++) {
656: setRowIndex(first + i);
657:
658: if (!isRowAvailable())
659: break;
660:
661: for (int j = 0; j < childCount; j++) {
662: UIComponent child = children.get(j);
663:
664: if (!child.isRendered())
665: continue;
666:
667: int grandchildCount = child.getChildCount();
668: List<UIComponent> grandchildren = child
669: .getChildren();
670:
671: for (int k = 0; k < grandchildCount; k++) {
672: grandchildren.get(k).processUpdates(context);
673: }
674: }
675: }
676: }
677:
678: setRowIndex(-1);
679: }
680:
681: /**
682: * Recursively calls the encodes for any children, then calls
683: * decode().
684: */
685: @Override
686: public void encodeBegin(FacesContext context)
687: throws java.io.IOException {
688: if (context == null)
689: throw new NullPointerException();
690:
691: if (!isRendered())
692: return;
693:
694: resetDataModel();
695:
696: if (!context.getRenderResponse()
697: || !context.getResponseComplete())
698: _state = null;
699:
700: super .encodeBegin(context);
701: }
702:
703: //
704: // state
705: //
706:
707: public Object saveState(FacesContext context) {
708: return new Object[] { super .saveState(context),
709:
710: _value, _first, _rows, _var, };
711: }
712:
713: public void restoreState(FacesContext context, Object value) {
714: Object[] state = (Object[]) value;
715:
716: super .restoreState(context, state[0]);
717:
718: _value = state[1];
719: _first = (Integer) state[2];
720: _rows = (Integer) state[3];
721: _var = (String) state[4];
722: }
723:
724: //
725: // inner classes
726: //
727:
728: static class UIDataEventWrapper extends FacesEvent {
729: private FacesEvent _event;
730: private int _rowIndex;
731:
732: UIDataEventWrapper(FacesEvent event, UIData component,
733: int rowIndex) {
734: super (component);
735:
736: _event = event;
737: _rowIndex = rowIndex;
738: }
739:
740: FacesEvent getEvent() {
741: return _event;
742: }
743:
744: int getRowIndex() {
745: return _rowIndex;
746: }
747:
748: public void setPhaseId(PhaseId phaseId) {
749: _event.setPhaseId(phaseId);
750: }
751:
752: public PhaseId getPhaseId() {
753: return _event.getPhaseId();
754: }
755:
756: public boolean isAppropriateListener(FacesListener listener) {
757: return _event.isAppropriateListener(listener);
758: }
759:
760: public void processListener(FacesListener listener)
761: throws AbortProcessingException {
762: ((UIData) getComponent()).setRowIndex(_rowIndex);
763:
764: _event.processListener(listener);
765: }
766: }
767:
768: static class State implements java.io.Serializable {
769: private final Object _submittedValue;
770: private final Object _value;
771: private final boolean _isLocal;
772: private final boolean _isValid;
773:
774: State() {
775: _submittedValue = null;
776: _value = null;
777: _isLocal = false;
778: _isValid = false;
779: }
780:
781: State(EditableValueHolder holder) {
782: _submittedValue = holder.getSubmittedValue();
783: _value = holder.getValue();
784: _isLocal = holder.isLocalValueSet();
785: _isValid = holder.isValid();
786: }
787:
788: State update(EditableValueHolder holder) {
789: if (_submittedValue == holder.getSubmittedValue()
790: && _value == holder.getValue()
791: && _isLocal == holder.isLocalValueSet()
792: && _isValid == holder.isValid())
793: return this ;
794: else
795: return new State(holder);
796: }
797:
798: void restore(EditableValueHolder holder) {
799: holder.setSubmittedValue(_submittedValue);
800: holder.setValue(_value);
801: holder.setLocalValueSet(_isLocal);
802: holder.setValid(_isValid);
803: }
804: }
805:
806: //
807: // private helpers
808: //
809:
810: private static enum PropEnum {
811: VALUE, FIRST, ROWS,
812: }
813:
814: static {
815: _propMap.put("value", PropEnum.VALUE);
816: _propMap.put("first", PropEnum.FIRST);
817: _propMap.put("rows", PropEnum.ROWS);
818: }
819: }
|