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