View Javadoc

1   /*
2    * $Id: BasicComponentEngine.java,v 1.17 2011/06/16 09:29:40 jbmeslin Exp $
3    */
4   package org.rcfaces.core.internal.component;
5   
6   import java.util.ArrayList;
7   import java.util.Collection;
8   import java.util.Collections;
9   import java.util.HashMap;
10  import java.util.Iterator;
11  import java.util.List;
12  import java.util.Map;
13  
14  import javax.el.ValueExpression;
15  import javax.faces.FacesException;
16  import javax.faces.component.UIComponentBase;
17  import javax.faces.context.FacesContext;
18  import javax.faces.convert.Converter;
19  
20  import org.apache.commons.logging.Log;
21  import org.apache.commons.logging.LogFactory;
22  import org.rcfaces.core.internal.capability.IComponentEngine;
23  import org.rcfaces.core.internal.capability.IStateChildrenList;
24  
25  /**
26   * @author Olivier Oeuillot (latest modification by $Author: jbmeslin $)
27   * @version $Revision: 1.17 $ $Date: 2011/06/16 09:29:40 $
28   */
29  public class BasicComponentEngine extends AbstractComponentEngine {
30      private static final String REVISION = "$Revision: 1.17 $";
31  
32      private static final Log LOG = LogFactory
33              .getLog(BasicComponentEngine.class);
34  
35      private static final boolean debugEnabled = LOG.isDebugEnabled();
36  
37      private static final String VALIDATORS_KEY = "camelia.validators";
38  
39      private static final String CONVERTER_ID_PROPERTY = "camalia.converterId";
40  
41      static final Class BOOLEAN_CLASS = Boolean.class;
42  
43      static final Class STRING_CLASS = String.class;
44  
45      private static final Class INTEGER_CLASS = Integer.class;
46  
47      private static final Integer INTEGER_0 = new Integer(0);
48  
49      private static final Class DOUBLE_CLASS = Double.class;
50  
51      private static final Double DOUBLE_0 = new Double(0);
52  
53      private static final String[] STRING_EMPTY_ARRAY = new String[0];
54  
55      private static final int DATA_ACCESSORS_INIT_SIZE = 2;
56  
57      private transient boolean enableDelta;
58  
59      private Converter converter;
60  
61      private boolean converterSetted = false;
62  
63      private Map transientAttributes;
64  
65      private Map dataAccessorsByName;
66  
67      private IPropertiesManager propertiesManager;
68  
69      public BasicComponentEngine(IFactory factory) {
70          super(factory);
71      }
72  
73      protected BasicComponentEngine(BasicComponentEngine original) {
74          this(original.factory);
75  
76          if (debugEnabled) {
77              LOG.debug("Clone BasicComponentEngine  source=" + original);
78          }
79  
80          if (original.propertiesManager != null) {
81              propertiesManager = original.propertiesManager.copyOriginalState();
82          }
83  
84          if (original.dataAccessorsByName != null
85                  && original.dataAccessorsByName.isEmpty() == false) {
86  
87              dataAccessorsByName = new HashMap(DATA_ACCESSORS_INIT_SIZE);
88  
89              for (Iterator it = original.dataAccessorsByName.entrySet()
90                      .iterator(); it.hasNext();) {
91                  Map.Entry entry = (Map.Entry) it.next();
92  
93                  BasicDataAccessor originalDataAccessor = (BasicDataAccessor) entry
94                          .getValue();
95  
96                  BasicDataAccessor newDataAccessor = (BasicDataAccessor) originalDataAccessor
97                          .copyOriginalState();
98  
99                  dataAccessorsByName.put(entry.getKey(), newDataAccessor);
100             }
101         }
102     }
103 
104     public final Boolean getBooleanProperty(String propertyName,
105             FacesContext facesContext) {
106         return (Boolean) getInternalProperty(propertyName, BOOLEAN_CLASS,
107                 facesContext);
108     }
109 
110     public final Integer getIntegerProperty(String propertyName,
111             FacesContext facesContext) {
112         return (Integer) getInternalProperty(propertyName, INTEGER_CLASS,
113                 facesContext);
114     }
115 
116     public final boolean getBoolProperty(String propertyName,
117             boolean defaultValue, FacesContext facesContext) {
118         Object object = getBooleanProperty(propertyName, facesContext);
119 
120         if (object == null) {
121             return defaultValue;
122         }
123 
124         if (object == Boolean.FALSE) {
125             return false;
126         }
127 
128         if (object == Boolean.TRUE) {
129             return true;
130         }
131 
132         return ((Boolean) object).booleanValue();
133     }
134 
135     public final String getStringProperty(String propertyName,
136             FacesContext facesContext) {
137         return (String) getInternalProperty(propertyName, STRING_CLASS,
138                 facesContext);
139     }
140 
141     public final Object getProperty(String propertyName,
142             FacesContext facesContext) {
143         return getInternalProperty(propertyName, null, facesContext);
144     }
145 
146     public final int getIntProperty(String propertyName, int defaultValue,
147             FacesContext facesContext) {
148         Integer i = (Integer) getInternalProperty(propertyName, INTEGER_CLASS,
149                 facesContext);
150         if (i == null) {
151             return defaultValue;
152         }
153         return i.intValue();
154     }
155 
156     public final double getDoubleProperty(String propertyName,
157             double defaultValue, FacesContext facesContext) {
158         Double i = (Double) getInternalProperty(propertyName, DOUBLE_CLASS,
159                 facesContext);
160         if (i == null) {
161             return defaultValue;
162         }
163         return i.doubleValue();
164     }
165 
166     final Object getLocalProperty(String propertyName) {
167 
168         if (debugEnabled) {
169             LOG.debug("getLocalProperty(\"" + propertyName + "\") ...");
170         }
171 
172         IPropertiesAccessor propertiesAccessor = getPropertiesAccessor(false);
173         if (propertiesAccessor == null) {
174             if (debugEnabled) {
175                 LOG.debug("getLocalProperty(\"" + propertyName
176                         + "\") returns null (propertiesAccessor="
177                         + propertiesAccessor + ")");
178             }
179             return null;
180         }
181 
182         Object value = propertiesAccessor.getProperty(propertyName);
183 
184         if (debugEnabled) {
185             LOG.debug("getLocalProperty(\"" + propertyName + "\") returns "
186                     + value + "  (propertiesAccessor=" + propertiesAccessor
187                     + ")");
188         }
189 
190         return value;
191     }
192 
193     public final Object getInternalProperty(String propertyName,
194             Class requestedClass, FacesContext facesContext) {
195 
196         if (debugEnabled) {
197             LOG.debug("getInternalProperty(\""
198                     + propertyName
199                     + "\" ["
200                     + ((requestedClass != null) ? requestedClass.getName()
201                             : "no class") + "]) ... (enableDelta="
202                     + enableDelta + ")");
203         }
204 
205         Object object = getLocalProperty(propertyName);
206         if (object == null) {
207 
208             if (debugEnabled) {
209                 LOG.debug("getInternalProperty(\""
210                         + propertyName
211                         + "\" ["
212                         + ((requestedClass != null) ? requestedClass.getName()
213                                 : "no class") + "]) returns null");
214             }
215             return null;
216         }
217 
218         if (object instanceof ValueExpression) {
219             ValueExpression valueExpression = (ValueExpression) object;
220 
221             if (facesContext == null) {
222                 facesContext = getFacesContext();
223             }
224 
225             object = valueExpression.getValue(facesContext.getELContext());
226 
227             if (debugEnabled) {
228                 LOG.debug("getInternalProperty(\""
229                         + propertyName
230                         + "\" ["
231                         + ((requestedClass != null) ? requestedClass.getName()
232                                 : "no class") + "]) returns a value binding ("
233                         + valueExpression + ") => " + object);
234             }
235             return object;
236         }
237 
238         if (debugEnabled) {
239             LOG.debug("getInternalProperty(\""
240                     + propertyName
241                     + "\" ["
242                     + ((requestedClass != null) ? requestedClass.getName()
243                             : "no class") + "]) returns " + object);
244         }
245 
246         return object;
247     }
248 
249     protected FacesContext getFacesContext() {
250         FacesContext facesContext = FacesContext.getCurrentInstance();
251         if (facesContext != null) {
252             return facesContext;
253         }
254 
255         throw new FacesException("FacesContext is not initialized !", null);
256     }
257 
258     protected final void setInternalProperty(String propertyName, Object value) {
259 
260         if (debugEnabled) {
261             LOG.debug("setInternalProperty(\"" + propertyName + "\", " + value
262                     + ") ...");
263         }
264 
265         IPropertiesAccessor pa = getPropertiesAccessor(true);
266 
267         pa.setProperty(null, propertyName, value);
268 
269         if (debugEnabled) {
270             LOG.debug("setInternalProperty(\"" + propertyName + "\", " + value
271                     + ") propertiesAccessor=" + pa);
272         }
273     }
274 
275     protected final void setInternalProperty(String propertyName,
276             ValueExpression value) {
277 
278         if (debugEnabled) {
279             LOG.debug("setInternalProperty(\"" + propertyName + "\", " + value
280                     + ") ...");
281         }
282 
283         IPropertiesAccessor pa = getPropertiesAccessor(true);
284 
285         pa.setProperty(null, propertyName, value);
286 
287         if (debugEnabled) {
288             LOG.debug("setInternalProperty(\"" + propertyName + "\", " + value
289                     + ") propertiesAccessor=" + pa);
290         }
291     }
292 
293     public final void setProperty(String propertyName, boolean value) {
294         if (value) {
295             setInternalProperty(propertyName, Boolean.TRUE);
296             return;
297         }
298 
299         setInternalProperty(propertyName, Boolean.FALSE);
300     }
301 
302     public final void setProperty(String propertyName, Boolean bool) {
303         if (bool != null) {
304             // On s'assure que l'instance de l'objet BOOLEAN est bien static !
305             if (bool.booleanValue()) {
306                 bool = Boolean.TRUE;
307 
308             } else {
309                 bool = Boolean.FALSE;
310             }
311         }
312 
313         setInternalProperty(propertyName, bool);
314     }
315 
316     public final void setProperty(String propertyName, Integer value) {
317         if (value != null) {
318             if (value.intValue() == 0) {
319                 value = INTEGER_0;
320             }
321         }
322 
323         setInternalProperty(propertyName, value);
324     }
325 
326     public final void setProperty(String propertyName, Double value) {
327         if (value != null) {
328             if (value.doubleValue() == 0.0) {
329                 value = DOUBLE_0;
330             }
331         }
332 
333         setInternalProperty(propertyName, value);
334     }
335 
336     public final void setProperty(String propertyName, double value) {
337         if (value == 0.0) {
338             setInternalProperty(propertyName, DOUBLE_0);
339             return;
340         }
341 
342         setInternalProperty(propertyName, new Double(value));
343     }
344 
345     public final void setProperty(String propertyName, int value) {
346         if (value == 0) {
347             setInternalProperty(propertyName, INTEGER_0);
348             return;
349         }
350 
351         setInternalProperty(propertyName, new Integer(value));
352     }
353 
354     public final void setProperty(String propertyName, Object value) {
355         setInternalProperty(propertyName, value);
356     }
357 
358     public final void setProperty(String propertyName, ValueExpression value) {
359         setInternalProperty(propertyName, value);
360     }
361 
362     final IPropertiesAccessor getPropertiesAccessor(boolean forceDelta) {
363 
364         if (debugEnabled) {
365             LOG.debug("getPropertiesAccessor  enableDelta=" + enableDelta
366                     + " forceDelta=" + forceDelta + " ...");
367         }
368 
369         if (propertiesManager != null) {
370             return propertiesManager.getPropertiesAccessor(enableDelta,
371                     forceDelta);
372         }
373 
374         if (forceDelta == false) {
375             return null;
376         }
377 
378         propertiesManager = factory.createPropertiesManager(this);
379 
380         if (debugEnabled) {
381             LOG.debug("Create propertiesManager='" + propertiesManager
382                     + " for this='" + this + "' enableDelta=" + enableDelta
383                     + " forceDelta=" + forceDelta);
384         }
385 
386         return propertiesManager.getPropertiesAccessor(enableDelta, forceDelta);
387     }
388 
389     public IDataMapAccessor getDataMapAccessor(FacesContext context,
390             String name, boolean forceDelta) {
391         IDataMapAccessor dataAccessor;
392         if (dataAccessorsByName != null) {
393             dataAccessor = (IDataMapAccessor) dataAccessorsByName.get(name);
394             if (dataAccessor != null) {
395                 return dataAccessor;
396             }
397         }
398 
399         if (forceDelta == false) {
400             return null;
401         }
402 
403         dataAccessor = createDataAccessor(context, name);
404         if (dataAccessorsByName == null) {
405             dataAccessorsByName = new HashMap(DATA_ACCESSORS_INIT_SIZE);
406         }
407 
408         dataAccessorsByName.put(name, dataAccessor);
409 
410         return dataAccessor;
411     }
412 
413     protected BasicDataAccessor createDataAccessor(FacesContext context,
414             String name) {
415         return new BasicDataAccessor(name);
416     }
417 
418     public void restoreState(FacesContext context, Object state) {
419         Object states[] = (Object[]) state;
420 
421         Object props = states[0];
422         if (props != null) {
423             propertiesManager = factory.createPropertiesManager(this);
424             propertiesManager.restoreManagerState(context, props);
425 
426         } else {
427             propertiesManager = null;
428         }
429 
430         Object datas = states[1];
431         if (datas != null) {
432             Object ds[] = (Object[]) datas;
433 
434             dataAccessorsByName = new HashMap(ds.length / 2);
435             for (int i = 0; i < ds.length;) {
436                 String name = (String) ds[i++];
437 
438                 BasicDataAccessor dataAccessor = createDataAccessor(context,
439                         name);
440                 dataAccessor.setCameliaFactory(factory);
441 
442                 dataAccessor.restoreDataState(context, ds[i++]);
443 
444                 dataAccessorsByName.put(name, dataAccessor);
445             }
446         } else {
447             dataAccessorsByName = null;
448         }
449 
450         Object converter = states[2];
451         if (converter != null) {
452             this.converterSetted = true;
453             if (Boolean.FALSE.equals(converter)) {
454                 this.converter = null;
455 
456             } else {
457                 this.converter = (Converter) UIComponentBase
458                         .restoreAttachedState(context, converter);
459             }
460 
461         } else {
462             this.converterSetted = false;
463             this.converter = null;
464         }
465     }
466 
467     /*
468      * (non-Javadoc)
469      * 
470      * @see
471      * javax.faces.component.StateHolder#saveState(javax.faces.context.FacesContext
472      * )
473      */
474     public Object saveState(FacesContext context) {
475         Object states[] = new Object[3];
476 
477         if (propertiesManager != null) {
478             states[0] = propertiesManager.saveManagerState(context);
479         }
480 
481         if (dataAccessorsByName != null
482                 && dataAccessorsByName.isEmpty() == false) {
483             List l = new ArrayList(dataAccessorsByName.size() * 2);
484 
485             for (Iterator it = dataAccessorsByName.entrySet().iterator(); it
486                     .hasNext();) {
487                 Map.Entry entry = (Map.Entry) it.next();
488 
489                 BasicDataAccessor dataAccessor = (BasicDataAccessor) entry
490                         .getValue();
491 
492                 Object serializedForm = dataAccessor.saveDataState(context);
493 
494                 if (serializedForm == null) {
495                     continue;
496                 }
497 
498                 l.add(entry.getKey());
499                 l.add(serializedForm);
500             }
501 
502             if (l.isEmpty() == false) {
503                 states[1] = l.toArray();
504             }
505         }
506 
507         if (converterSetted) {
508             Object savedConverter = Boolean.FALSE;
509             if (converter != null) {
510                 savedConverter = UIComponentBase.saveAttachedState(context,
511                         converter);
512 
513                 if (savedConverter == null) {
514                     savedConverter = Boolean.FALSE;
515                 }
516             }
517 
518             states[2] = savedConverter;
519         }
520 
521         return states;
522     }
523 
524     /*
525      * (non-Javadoc)
526      * 
527      * @see
528      * javax.faces.component.UIComponent#setValueExpression(java.lang.String,
529      * javax.faces.el.ValueExpression)
530      */
531     public final void setValue(String valueName, Object value) {
532         setInternalProperty(valueName, value);
533     }
534 
535     public final void setValueExpression(String valueName, ValueExpression value) {
536         setProperty(valueName, value);
537     }
538 
539     public final Object getValue(String valueName, FacesContext context) {
540         return getInternalProperty(valueName, null, context);
541     }
542 
543     public final Object getLocalValue(String valueName) {
544         return getLocalProperty(valueName);
545     }
546 
547     public final ValueExpression getValueExpressionProperty(String name) {
548         Object object = getLocalProperty(name);
549         if (object instanceof ValueExpression) {
550             return (ValueExpression) object;
551         }
552 
553         return null;
554     }
555 
556     public void release() {
557         if (dataAccessorsByName != null
558                 && dataAccessorsByName.isEmpty() == false) {
559             for (Iterator it = dataAccessorsByName.values().iterator(); it
560                     .hasNext();) {
561                 BasicDataAccessor dataAccessor = (BasicDataAccessor) it.next();
562 
563                 dataAccessor.releaseDatas();
564             }
565 
566             dataAccessorsByName = null;
567         }
568 
569         if (propertiesManager != null) {
570             propertiesManager.releaseManager();
571             propertiesManager = null;
572         }
573 
574         enableDelta = false;
575         converter = null;
576         converterSetted = false;
577     }
578 
579     /*
580      * public final String getConverterId(FacesContext facesContext) { return
581      * getStringProperty(CONVERTER_ID_PROPERTY, facesContext); }
582      * 
583      * public final void setConverterId(String converterId) {
584      * setProperty(CONVERTER_ID_PROPERTY, converterId); this.converter = null;
585      * this.converterSetted = false; }
586      * 
587      * public final void setConverterId(ValueExpression converterId) {
588      * setProperty(CONVERTER_ID_PROPERTY, converterId); this.converter = null;
589      * this.converterSetted = false; }
590      */
591 
592     public final Converter getConverter(FacesContext facesContext) {
593         if (converterSetted) {
594             return converter;
595         }
596         converterSetted = true;
597 
598         if (facesContext == null) {
599             facesContext = getFacesContext();
600         }
601 
602         Object converterValue = getProperty(CONVERTER_ID_PROPERTY, facesContext);
603         if (converterValue == null) {
604             return null;
605         }
606 
607         if (converterValue instanceof Converter) {
608             converter = (Converter) converterValue;
609 
610             return converter;
611         }
612 
613         String converterId = String.valueOf(converterValue);
614         if (converterId == null) {
615             return null;
616         }
617 
618         converter = facesContext.getApplication().createConverter(converterId);
619 
620         return converter;
621     }
622 
623     public final void setConverter(Converter converter) {
624         this.converter = converter;
625         this.converterSetted = true;
626 
627         if (debugEnabled) {
628             LOG.debug("Set converter: " + converter);
629         }
630     }
631 
632     public Object getTransientAttribute(String name) {
633         if (transientAttributes == null) {
634             return null;
635         }
636 
637         Object value = transientAttributes.get(name);
638 
639         if (debugEnabled) {
640             LOG.debug("Get transient attribute '" + name + "' => " + value);
641         }
642 
643         return value;
644     }
645 
646     public Object setTransientAttribute(String name, Object value) {
647         if (transientAttributes == null) {
648             transientAttributes = factory.createMap(4);
649         }
650 
651         if (debugEnabled) {
652             LOG.debug("Set transient attribute '" + name + "'=" + value);
653         }
654 
655         return transientAttributes.put(name, value);
656     }
657 
658     public boolean isPropertySetted(String propertyName) {
659 
660         if (debugEnabled) {
661             LOG.debug("Is property setted '" + propertyName + "' ...");
662         }
663 
664         IPropertiesAccessor propertiesAccessor = getPropertiesAccessor(false);
665         if (propertiesAccessor == null) {
666 
667             if (debugEnabled) {
668                 LOG.debug("Is property setted '" + propertyName
669                         + "' => FALSE  (propertiesAccessor='"
670                         + propertiesAccessor + "')");
671             }
672             return false;
673         }
674 
675         boolean setted = propertiesAccessor.isPropertySetted(propertyName);
676 
677         if (debugEnabled) {
678             LOG.debug("Is property setted '" + propertyName + "' => " + setted
679                     + "  (propertiesAccessor='" + propertiesAccessor + "')");
680         }
681 
682         return setted;
683     }
684 
685     public void processValidation(FacesContext context) {
686 
687         if (debugEnabled) {
688             LOG.debug("Process validation, enableDelta=" + enableDelta);
689         }
690 
691         if (enableDelta == false) {
692             return;
693         }
694 
695         enableDelta = false;
696     }
697 
698     public void processUpdates(FacesContext context) {
699 
700         if (debugEnabled) {
701             LOG.debug("Process update, enableDelta=" + enableDelta);
702         }
703 
704         enableDelta = false;
705 
706         if (enableDelta == true) {
707             throw new FacesException(
708                     "Invalid update state without validation phase !");
709         }
710 
711         if (dataAccessorsByName != null
712                 && dataAccessorsByName.isEmpty() == false) {
713             for (Iterator it = dataAccessorsByName.values().iterator(); it
714                     .hasNext();) {
715                 BasicDataAccessor dataAccessor = (BasicDataAccessor) it.next();
716 
717                 dataAccessor.commitDatas(context);
718             }
719         }
720 
721         if (propertiesManager != null) {
722             propertiesManager.commitManager(context);
723         }
724     }
725 
726     public void startDecodes(FacesContext context) {
727         enableDelta = true;
728 
729         if (debugEnabled) {
730             LOG.debug("Start decode component ");
731         }
732     }
733 
734     /**
735      * 
736      * @author Olivier Oeuillot (latest modification by $Author: jbmeslin $)
737      * @version $Revision: 1.17 $ $Date: 2011/06/16 09:29:40 $
738      */
739     protected class BasicDataAccessor extends BasicPropertiesManager implements
740             IDataMapAccessor {
741         private static final String REVISION = "$Revision: 1.17 $";
742 
743         private final String name;
744 
745         private IPropertiesManager propertiesManager;
746 
747         public BasicDataAccessor(String name) {
748             this.name = name;
749         }
750 
751         final IPropertiesAccessor getDataPropertiesAccessor(boolean forceDelta) {
752             if (propertiesManager != null) {
753                 return propertiesManager.getPropertiesAccessor(enableDelta,
754                         forceDelta);
755             }
756 
757             if (forceDelta == false) {
758                 return null;
759             }
760 
761             propertiesManager = createPropertiesManager();
762 
763             return propertiesManager.getPropertiesAccessor(enableDelta,
764                     forceDelta);
765         }
766 
767         public IPropertiesManager copyOriginalState() {
768             BasicDataAccessor copy = new BasicDataAccessor(name);
769             copy.propertiesManager = copy;
770             copy.setCameliaFactory(factory);
771             copy.originalPropertiesAccessor = originalPropertiesAccessor;
772 
773             return copy;
774         }
775 
776         protected IPropertiesManager createPropertiesManager() {
777             return this;
778         }
779 
780         public Object removeData(String name, FacesContext facesContext) {
781             IPropertiesAccessor propertiesAccessor = getDataPropertiesAccessor(true);
782 
783             return propertiesAccessor.removeProperty(facesContext, name);
784         }
785 
786         public Object getData(String key, FacesContext facesContext) {
787             IPropertiesAccessor propertiesAccessor = getDataPropertiesAccessor(false);
788             if (propertiesAccessor == null) {
789                 return null;
790             }
791 
792             Object object = propertiesAccessor.getProperty(key);
793             if (object == null) {
794                 return null;
795             }
796 
797             if (object instanceof ValueExpression) {
798                 ValueExpression valueBinding = (ValueExpression) object;
799 
800                 if (facesContext == null) {
801                     facesContext = getFacesContext();
802                 }
803 
804                 object = valueBinding.getValue(facesContext.getELContext());
805                 if (object == null) {
806                     return null;
807                 }
808             }
809 
810             return object;
811         }
812 
813         public Object setData(String name, Object value,
814                 FacesContext facesContext) {
815             IPropertiesAccessor propertiesAccessor = getDataPropertiesAccessor(true);
816 
817             return propertiesAccessor.setProperty(facesContext, name, value);
818         }
819 
820         public void setData(String name, ValueExpression value,
821                 FacesContext facesContext) {
822             IPropertiesAccessor propertiesAccessor = getDataPropertiesAccessor(true);
823 
824             propertiesAccessor.setProperty(facesContext, name, value);
825         }
826 
827         public int getDataCount() {
828             IPropertiesAccessor propertiesAccessor = getDataPropertiesAccessor(false);
829             if (propertiesAccessor == null) {
830                 return 0;
831             }
832 
833             return propertiesAccessor.size();
834         }
835 
836         public String[] listDataKeys(FacesContext facesContext) {
837             IPropertiesAccessor propertiesAccessor = getDataPropertiesAccessor(false);
838             if (propertiesAccessor == null) {
839                 return STRING_EMPTY_ARRAY;
840             }
841 
842             Collection c = propertiesAccessor.keySet();
843             if (c.isEmpty()) {
844                 return STRING_EMPTY_ARRAY;
845             }
846 
847             return (String[]) c.toArray(new String[c.size()]);
848         }
849 
850         public void restoreDataState(FacesContext context, Object datas) {
851             propertiesManager = factory
852                     .createPropertiesManager(BasicComponentEngine.this);
853             propertiesManager.restoreManagerState(context, datas);
854         }
855 
856         public Object saveDataState(FacesContext context) {
857             if (propertiesManager == null) {
858                 return null;
859             }
860 
861             return propertiesManager.saveManagerState(context);
862         }
863 
864         public void releaseDatas() {
865             if (propertiesManager == null) {
866                 return;
867             }
868 
869             propertiesManager.releaseManager();
870             propertiesManager = null;
871         }
872 
873         public void commitDatas(FacesContext context) {
874             if (propertiesManager == null) {
875                 return;
876             }
877 
878             propertiesManager.commitManager(context);
879         }
880 
881         public Map getDataMap(FacesContext facesContext) {
882             String keys[] = listDataKeys(facesContext);
883             if (keys.length < 1) {
884                 return Collections.EMPTY_MAP;
885             }
886 
887             Map map = new HashMap(keys.length);
888 
889             for (int i = 0; i < keys.length; i++) {
890                 String key = keys[i];
891 
892                 Object value = getData(key, facesContext);
893 
894                 // On accepte les <null>
895                 map.put(key, value);
896             }
897 
898             return map;
899         }
900     }
901 
902     public IStateChildrenList createStateChildrenList() {
903         return new BasicStateChildrenList();
904     }
905 
906     public IComponentEngine copyOriginalState() {
907 
908         BasicComponentEngine newComponentEngine = new BasicComponentEngine(this);
909 
910         return newComponentEngine;
911     }
912 
913     public String toString() {
914         String s = "";
915 
916         if (propertiesManager != null) {
917             s += propertiesManager.toString();
918         }
919 
920         if (transientAttributes != null
921                 && transientAttributes.isEmpty() == false) {
922             if (s.length() > 0) {
923                 s += ",";
924             }
925             s += "transient=" + transientAttributes;
926         }
927 
928         if (converter != null) {
929             if (s.length() > 0) {
930                 s += ",";
931             }
932             s += "converter='" + converter + "'";
933         }
934 
935         return s;
936     }
937 
938 }