View Javadoc

1   /*
2    */
3   package org.rcfaces.core.internal.component;
4   
5   import java.util.List;
6   import java.util.Collections;
7   import java.util.Set;
8   import java.io.IOException;
9   
10  import javax.el.ValueExpression;
11  
12  import javax.faces.context.FacesContext;
13  import javax.faces.render.Renderer;
14  import javax.faces.event.ActionEvent;
15  import javax.faces.event.FacesEvent;
16  import javax.faces.event.FacesListener;
17  import javax.faces.event.PhaseId;
18  
19  import org.apache.commons.logging.Log;
20  import org.apache.commons.logging.LogFactory;
21  
22  import javax.faces.convert.Converter;
23  import org.rcfaces.core.internal.capability.IConvertValueHolder;
24  import java.util.HashSet;
25  import java.lang.String;
26  import java.util.Arrays;
27  
28  
29  import org.rcfaces.core.component.capability.IAsyncDecodeModeCapability;
30  import org.rcfaces.core.component.capability.IHiddenModeCapability;
31  import org.rcfaces.core.component.capability.IImmediateCapability;
32  import org.rcfaces.core.component.capability.ILookAndFeelCapability;
33  import org.rcfaces.core.component.capability.IValidationEventCapability;
34  import org.rcfaces.core.component.capability.IVisibilityCapability;
35  import org.rcfaces.core.internal.Constants;
36  import org.rcfaces.core.internal.RcfacesContext;
37  
38  import org.rcfaces.core.internal.capability.IVariableScopeCapability;
39  import org.rcfaces.core.internal.capability.IComponentEngine;
40  import org.rcfaces.core.internal.capability.IComponentLifeCycle;
41  import org.rcfaces.core.internal.capability.IListenerStrategy;
42  import org.rcfaces.core.internal.capability.IRCFacesComponent;
43  import org.rcfaces.core.internal.capability.IStateChildrenList;
44  import org.rcfaces.core.internal.component.CameliaComponents;
45  import org.rcfaces.core.internal.component.RestoreViewPhaseListener;
46  import org.rcfaces.core.internal.component.IFactory;
47  import org.rcfaces.core.internal.component.IInitializationState;
48  import org.rcfaces.core.internal.converter.StrategyListenerConverter;
49  import org.rcfaces.core.internal.manager.IContainerManager;
50  import org.rcfaces.core.internal.manager.ITransientAttributesManager;
51  import org.rcfaces.core.internal.renderkit.IAsyncRenderer;
52  import org.rcfaces.core.internal.renderkit.IRendererExtension;
53  import org.rcfaces.core.internal.tools.ComponentTools;
54  import org.rcfaces.core.internal.tools.BindingTools;
55  import org.rcfaces.core.event.IValidationListener;
56  import org.rcfaces.core.event.ValidationEvent;
57  
58  /**
59   * @author Olivier Oeuillot
60   */
61  public abstract class CameliaOutputComponent extends javax.faces.component.UIOutput implements
62  		IRCFacesComponent, IContainerManager, IComponentLifeCycle, ITransientAttributesManager, IConvertValueHolder {
63  	private static final String REVISION = "$Revision: 1.17 $";
64  
65  	private static final Log LOG = LogFactory.getLog(CameliaOutputComponent.class);
66  
67  	protected static final Set CAMELIA_ATTRIBUTES=new HashSet(Arrays.asList(new String[] {"converter","value"}));
68  
69  	protected transient IComponentEngine engine;
70  
71  	private transient IStateChildrenList stateChildrenList;
72  
73  
74  	protected CameliaOutputComponent() {
75  		IFactory factory = Constants.getCameliaFactory();
76  
77  		this.engine = factory.createComponentEngine();
78  
79  		IInitializationState state=factory.createInitializationState();
80          initializeComponent(state);	
81      }
82  
83      protected void initializeComponent(IInitializationState state) {
84      	if (Constants.TEMPLATE_ENGINE_SUPPORT) {
85  	        if (isTemplateComponent(state) && state.isConstructionState()) {
86  	        	if (LOG.isDebugEnabled()) {
87  	        		LOG.debug("Call construct template method.");
88  	        	}
89  	            constructTemplate(state);
90  	        }
91  	    }
92  	    if (Constants.COMPONENT_DEFAULT_PROPERTIES_SUPPORT) {
93  	        if (hasDefaultProperties(state) && state.isConstructionState()) {
94  	        	if (LOG.isDebugEnabled()) {
95  	        		LOG.debug("Call setDefaultProperties method.");
96  	        	}
97  	            setDefaultProperties(state);
98  	        }
99  	    }
100 	    
101 	    constructPhase(state.getFacesContext());	    
102     }
103  
104     protected boolean isTemplateComponent(IInitializationState state) {
105         return false;
106     }
107 
108     protected void constructTemplate(IInitializationState state) {
109     }
110 
111     protected boolean hasDefaultProperties(IInitializationState state) {
112         return false;
113     }
114 
115     protected void setDefaultProperties(IInitializationState state) {
116     }
117 
118 	public String getFamily() {
119 		return CameliaComponents.FAMILY;
120 	}
121 
122 	public final String getRendererType() {
123 		String rendererType = super.getRendererType();
124 		if (rendererType == null) {
125         	if (LOG.isTraceEnabled()) {
126         		LOG.trace("RendererType is null for component id='"+getId()+"' class='"+getClass()+"'");
127         	}
128 			return null;
129 		}
130 
131 		if ((this instanceof ILookAndFeelCapability) == false) {
132 			return rendererType;
133 		}
134 
135 		String lookId = ((ILookAndFeelCapability) this).getLookId();
136 		if (lookId == null) {
137 			return rendererType;
138 		}
139 
140 		return rendererType + ":" + lookId;
141 	}
142 
143 	public void restoreState(FacesContext context, Object state) {
144 		if (LOG.isTraceEnabled()) {
145 			LOG.trace("Restoring state of component '"+getId()+"'.");
146 		}
147 		
148 		try {
149 			Object states[] = (Object[]) state;
150 	
151 			super.restoreState(context, states[0]);
152 	
153 			engine.restoreState(context, states[1]);
154 	    	
155 	    } catch (RuntimeException ex) {
156 	    	LOG.error("Can not restore state of component '"+getId()+"'.", ex);
157 	    	
158 	    	throw ex;
159 	    }
160 
161 		if (LOG.isTraceEnabled()) {
162 			LOG.trace("State of component '"+getId()+"' restored.");
163 		}
164 	}
165 
166 	public Object saveState(FacesContext context) {
167 		if (LOG.isTraceEnabled()) {
168 			LOG.trace("Saving state of component '"+getId()+"'.");
169 		}
170 
171 		Object states[] = new Object[2];
172 		try {	
173 			states[0] = super.saveState(context);
174 			states[1] = engine.saveState(context);
175 	    	
176 	    } catch (RuntimeException ex) {
177 	    	LOG.error("Can not save state of component '"+getId()+"'.", ex);
178 	    	
179 	    	throw ex;
180 	    }
181 
182 		if (LOG.isTraceEnabled()) {
183 			LOG.trace("State of component '"+getId()+"' saved.");
184 		}
185 
186 		return states;
187 	}
188 
189 	public void setValueExpression(String name, ValueExpression binding) {
190 		if (getCameliaFields().contains(name)) {
191 			if (name.equals(getCameliaValueAlias())) {
192 				name=Properties.VALUE;
193 			}
194 
195 			
196 
197 			engine.setProperty(name, binding);
198 			return;
199 		}
200 
201 		
202 		
203 		super.setValueExpression(name, binding);
204 	}
205 
206 	protected Set getCameliaFields() {
207 		return CAMELIA_ATTRIBUTES;
208 	}
209 
210 	protected String getCameliaValueAlias() {
211 		return null;
212 	}
213 
214 	public final ValueExpression getValueExpression(String name) {
215 		if (getCameliaFields().contains(name)) {
216 			if (name.equals(getCameliaValueAlias())) {
217 				name=Properties.VALUE;
218 			}
219 
220 			return engine.getValueExpressionProperty(name);
221 		}
222 
223 		return super.getValueExpression(name);
224 	}
225 
226 /*
227 	public void release() {
228 		if (engine != null) {
229 			engine.release();
230 		}
231 	}
232 */
233 
234     public void encodeBegin(FacesContext context) throws IOException {
235 		if (context == null) {
236 			throw new NullPointerException("FacesContext is null");
237 		}
238 
239 		try {	
240 	    	super.encodeBegin(context);
241 	    	
242 	    } catch (RuntimeException ex) {
243 	    	LOG.error("Can not encode-begin component '"+getId()+"'.", ex);
244 	    	
245 	    	throw ex;
246 	    }
247 	}
248 	
249     public void encodeChildren(FacesContext context) throws IOException {
250 		if (context == null) {
251 			throw new NullPointerException("FacesContext is null");
252 		}
253 
254 		try {
255 	    	super.encodeChildren(context);    	
256 	    	
257 	    } catch (RuntimeException ex) {
258 	    	LOG.error("Can not encode children of component '"+getId()+"'.", ex);
259 	    	
260 	    	throw ex;
261 	    }
262 	}
263 	
264     public void encodeEnd(FacesContext context) throws IOException {
265 		if (context == null) {
266 			throw new NullPointerException("FacesContext is null");
267 		}
268 
269 		try  {	
270 	    	super.encodeEnd(context);    	
271 	    	
272 	    } catch (RuntimeException ex) {
273 	    	LOG.error("Can not encode-end component '"+getId()+"'.", ex);
274 	    	
275 	    	throw ex;
276 	    }
277 	}
278 	
279 	protected boolean verifyAsyncDecode(FacesContext context, PhaseId phaseId) {
280 		return ComponentTools.verifyAsyncDecode(context, (IAsyncDecodeModeCapability) this, phaseId);
281 	}
282 	
283 	public void processDecodes(FacesContext context) {
284 		if (context == null) {
285 			throw new NullPointerException();
286 		}
287 		
288 		try {
289 			if (isRendered()==false) {
290 				return;
291 			}
292 			
293 			if (this instanceof IAsyncDecodeModeCapability) {
294 			    if (verifyAsyncDecode(context, PhaseId.APPLY_REQUEST_VALUES)==false) {
295 			        return;
296 			    }
297 			}			
298 	
299 	        ComponentTools.IVarScope varScope = null;
300 	        if (this instanceof IVariableScopeCapability) {
301 	            varScope=BindingTools.processVariableScope(context, (IVariableScopeCapability)this, PhaseId.APPLY_REQUEST_VALUES);
302 	        }
303 	
304 			engine.startDecodes(context);
305 			
306 			Renderer renderer = getRenderer(context);
307 	        if ((renderer instanceof IRendererExtension) == false) {
308 	            super.processDecodes(context);
309 	
310 	        } else  {
311 		        CameliaComponents.processDecodes(context, this, renderer);
312 		    }
313 			
314             boolean immediate=false;
315 	  		if (this instanceof IValidationEventCapability) {
316 	            if (this instanceof IImmediateCapability) {
317 	                immediate=((IImmediateCapability)this).isImmediate();
318 	            }
319 			}
320 
321  			if (immediate) {
322 				if (ComponentTools.hasValidationServerListeners(getFacesListeners(IValidationListener.class))) {
323 					this.broadcast(new ValidationEvent(this));
324 				}
325 				processEngineValidators(context);
326 			}
327 	       
328 	        if (varScope!=null) {
329 	            varScope.popVar(context);
330 	        }
331 	    	
332 	    } catch (RuntimeException ex) {
333 	    	LOG.error("Can not decode component '"+getId()+"'.", ex);
334 	    	
335 	    	throw ex;
336 	    }
337 	}
338 
339 	public void processValidators(FacesContext context) {
340 		if (context == null) {
341             throw new NullPointerException("Context is NULL to processValidators");
342         }
343 
344 		try {
345 	        // Skip processing if our rendered flag is false
346 			if (isRendered()==false) {
347 	            return;
348 	        }
349 			
350 			if (this instanceof IAsyncDecodeModeCapability) {
351 			    if (verifyAsyncDecode(context, PhaseId.PROCESS_VALIDATIONS)==false) {
352 			        return;
353 			    }
354 			}			
355 	
356 	        ComponentTools.IVarScope varScope = null;
357 	        if (this instanceof IVariableScopeCapability) {
358 	            varScope=BindingTools.processVariableScope(context, (IVariableScopeCapability)this, PhaseId.PROCESS_VALIDATIONS);
359 	        }
360 	
361 			super.processValidators(context);
362 	
363             boolean immediate=false;
364 	 		if (this instanceof IValidationEventCapability) {
365 	            if (this instanceof IImmediateCapability) {
366 	                immediate=((IImmediateCapability)this).isImmediate();
367 	            }
368 			}
369 	 			
370 			if (immediate==false) {
371 				if (ComponentTools.hasValidationServerListeners(getFacesListeners(IValidationListener.class))) {
372 					this.broadcast(new ValidationEvent(this));
373 				}
374 			
375 				processEngineValidators(context);
376 			}
377 			       
378 	        if (varScope!=null) {
379 	            varScope.popVar(context);
380 	        }
381 	    	
382 	    } catch (RuntimeException ex) {
383 	    	LOG.error("Can not valid component '"+getId()+"'.", ex);
384 	    	
385 	    	throw ex;
386 	    }
387 	}
388   
389 	protected void processEngineValidators(FacesContext context) {
390 		engine.processValidation(context);			
391 	}
392  
393     public void processUpdates(FacesContext context) {
394 
395 		try {
396 	
397 	 		if (isRendered()==false) {
398 	            return;
399 	        }        
400 			
401 			if (this instanceof IAsyncDecodeModeCapability) {
402 			    if (verifyAsyncDecode(context, PhaseId.UPDATE_MODEL_VALUES)==false) {
403 			        return;
404 			    }
405 			}			
406 	
407 			ComponentTools.IVarScope varScope = null;
408 	        if (this instanceof IVariableScopeCapability) {
409 	            varScope=BindingTools.processVariableScope(context, (IVariableScopeCapability)this, PhaseId.UPDATE_MODEL_VALUES);
410 	        }
411 	
412 			processEngineUpdates(context);
413 	
414 	        super.processUpdates(context);
415 	        
416 	        if (varScope!=null) {
417 	            varScope.popVar(context);
418 	        }
419 	    	
420 	    } catch (RuntimeException ex) {
421 	    	LOG.error("Can not update component '"+getId()+"'.", ex);
422 	    	
423 	    	throw ex;
424 	    }
425     }
426     
427 	protected void processEngineUpdates(FacesContext context) {
428 		engine.processUpdates(context);			
429 	}
430     
431 	/*
432 	 * (non-Javadoc)
433 	 * 
434 	 * @see javax.faces.component.UIComponent#getChildren()
435 	 */
436 	public final List getChildren() {
437 		if (Constants.STATED_COMPONENT_CHILDREN_LIST==false) {
438 			return super.getChildren();
439 		}
440 		
441 		List list = super.getChildren();
442 
443 		if (stateChildrenList == null) {
444 			stateChildrenList = engine.createStateChildrenList();
445 		}
446 
447 		stateChildrenList.setChildren(list);
448 
449 		return stateChildrenList;
450 	}
451 
452 	public final int getChildrenListState() {
453 		if (Constants.STATED_COMPONENT_CHILDREN_LIST==false) {
454 			throw new UnsupportedOperationException("STATED_COMPONENT_CHILDREN_LIST=false");
455 		}
456 
457 		if (stateChildrenList == null) {
458 			return 0;
459 		}
460 
461 		return stateChildrenList.getState();
462 	}
463 
464 	public final Object getTransientAttribute(String name) {
465 		return engine.getTransientAttribute(name);
466 	}
467 
468 	public final Object setTransientAttribute(String name, Object value) {
469 		return engine.setTransientAttribute(name, value);
470 	}
471 
472 	public final boolean isClientRendered() {
473 		if ((this instanceof IVisibilityCapability)==false) {
474 			return true;
475 		}
476 		
477 		IVisibilityCapability visibilityCapability=(IVisibilityCapability)this;
478 		
479 		Boolean visible=visibilityCapability.getVisibleState();
480 		if (visible==null || visible.booleanValue()) {
481 			return true;
482 		}
483 		
484 		if ((this instanceof IHiddenModeCapability)==false) {
485 			return false;
486 		}
487 		
488 		IHiddenModeCapability hiddenModeCapability=(IHiddenModeCapability)this;
489 		
490 		int hiddenMode=hiddenModeCapability.getHiddenMode();
491 		if (IHiddenModeCapability.SERVER_HIDDEN_MODE==hiddenMode) {
492 			return false;
493 		}
494 		
495 		return true;
496 	}
497 	
498 	public boolean isRendered() {
499 		if (super.isRendered()==false) {
500 			return false;
501 		}
502 		
503 		return isClientRendered();
504 	}
505 	
506 	public void setRendered(ValueExpression binding) {
507 		setValueExpression("rendered", binding);
508 	}
509 	
510 	
511 	public final IAsyncRenderer getAsyncRenderer(FacesContext facesContext) {
512 		Renderer renderer=getRenderer(facesContext);
513 		if (renderer instanceof IAsyncRenderer) {
514 			return (IAsyncRenderer) renderer;
515 		}
516 		
517 		return null;
518 	}
519 
520    public void queueEvent(FacesEvent e) {
521 // Un keyPress doit pouvoir activer l'immediate !
522 // Oui mais le code d'appel ne fait r?f?rence qu'a des ActionEvent
523 		if ((e instanceof ActionEvent) && e.getComponent()==this) {
524 	   		if (this instanceof IImmediateCapability) {
525 	   			IImmediateCapability immediateCapability=(IImmediateCapability)this;
526 	   			
527 			    if (immediateCapability.isImmediate()) {
528 					e.setPhaseId(PhaseId.APPLY_REQUEST_VALUES);
529 					
530 			    } else {
531 					e.setPhaseId(PhaseId.INVOKE_APPLICATION);
532 			    }
533 			}
534 		}
535 		
536 		super.queueEvent(e);
537     }	
538     
539     public void clearListeners() {
540     	FacesListener fcs[]=getFacesListeners(FacesListener.class);
541     	for(int i=0;i<fcs.length;i++) {
542     		removeFacesListener(fcs[i]);
543     	}
544     }
545     
546     public void constructPhase(FacesContext facesContext) {
547     }
548     
549     public void initializePhase(FacesContext facesContext,  boolean reused) {
550         if (reused) {
551         
552        		RcfacesContext rcfacesContext = RcfacesContext
553 					.getInstance(facesContext);
554 			int faceletListenerMode = rcfacesContext
555 					.getListenerManagerStrategy();
556 
557 			if ((IListenerStrategy.CLEAN_ALL & faceletListenerMode) > 0) {
558 				clearListeners();
559 			}
560         }
561     }
562 
563     public void decodePhase(FacesContext facesContext) {
564     }
565 
566     public void validationPhase(FacesContext facesContext) {
567     }
568 
569     public void updatePhase(FacesContext facesContext) {
570     }
571 
572     public void renderPhase(FacesContext facesContext) {
573     }   
574     
575     public boolean confirmListenerAppend(FacesContext facesContext, Class facesListenerClass){
576     	
577     	RcfacesContext rcfacesContext = RcfacesContext
578 				.getInstance(facesContext);
579 		int faceletListenerMode = rcfacesContext.getListenerManagerStrategy();
580 
581 		if (((IListenerStrategy.ADD_IF_NEW | IListenerStrategy.CLEAN_BY_CLASS) & faceletListenerMode) == 0) {
582 			return true;
583 		}
584 
585 		FacesListener fcs[] = getFacesListeners(facesListenerClass);
586 		if ((IListenerStrategy.ADD_IF_NEW & faceletListenerMode) > 0) {
587 			return fcs.length == 0;
588 		}
589 
590 		if ((IListenerStrategy.CLEAN_BY_CLASS & faceletListenerMode) > 0) {
591 			for (int i = 0; i < fcs.length; i++) {
592 				removeFacesListener(fcs[i]);
593 			}
594 
595 			return true;
596 		}
597 
598 		return true;
599     } 
600 	
601 	public String toString() {
602 		String name=getClass().getName();
603 		name=name.substring(name.lastIndexOf('.')+1);
604 		
605 		String s=name+"[id='"+getId()+"'";
606 		
607 		if (isRendered()==false) {
608 			s+=",rendered=false";
609 		}
610 		
611 		s+=","+engine.toString();
612 		
613 		s+=",rendererId='"+getRendererType()+"'";
614 		
615 		if (getFamily()!=CameliaComponents.FAMILY) {
616 			s+=",family='"+getFamily()+"'";
617 		}
618 		
619 		return s+"]";
620 	}
621 	
622 	public void setConverter(String converterId) {
623 
624 
625 			 setConverter(null, converterId);
626 		
627 	}
628 
629 	public void setConverter(FacesContext facesContext, String converterId) {
630 
631 
632 			if (facesContext==null) {
633 				facesContext=FacesContext.getCurrentInstance();
634 			}
635 			Converter converter = facesContext.getApplication().createConverter(converterId);
636             this.setConverter(converter);
637 		
638 	}
639 
640 
641 }