/**
* Licensed under the Common Development and Distribution License,
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.sun.com/cddl/
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.idega.builder.facelets;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.el.ELException;
import javax.el.ValueExpression;
import javax.faces.FacesException;
import javax.faces.application.Application;
import javax.faces.component.ActionSource;
import javax.faces.component.EditableValueHolder;
import javax.faces.component.UIComponent;
import javax.faces.component.UIViewRoot;
import javax.faces.component.ValueHolder;
import javax.faces.context.FacesContext;
import javax.faces.el.ValueBinding;
import com.sun.facelets.FaceletContext;
import com.sun.facelets.el.LegacyValueBinding;
import com.sun.facelets.tag.MetaRule;
import com.sun.facelets.tag.MetaRuleset;
import com.sun.facelets.tag.MetaTagHandler;
import com.sun.facelets.tag.TagAttribute;
import com.sun.facelets.tag.TagConfig;
import com.sun.facelets.tag.TagException;
import com.sun.facelets.tag.jsf.ComponentSupport;
import com.sun.facelets.tag.jsf.EditableValueHolderRule;
import com.sun.facelets.tag.jsf.core.FacetHandler;
import com.sun.facelets.util.FacesAPI;
/**
* <p>
* Implementation of the "page" tag in the IBXML page format
* as a Facelets Tag handler
* </p>
*
* @author <a href="tryggvi@idega.is">Tryggvi Larusson </a>
*
* Last modified: $Date: 2009/01/14 15:35:25 $ by $Author: tryggvil $
* @version $Id: BuilderPageTagHandler.java,v 1.2 2009/01/14 15:35:25 tryggvil Exp $
*/
public class BuilderPageTagHandler extends MetaTagHandler {
private final static Logger log = Logger
.getLogger("facelets.tag.component");
private final TagAttribute binding;
private final String componentType;
private final TagAttribute id;
private String rendererType;
@SuppressWarnings("unused")
private TagAttribute componentClass;
private String type;
private TagAttribute template;
//public ModuleTagHandler(ComponentConfig config) {
public BuilderPageTagHandler(TagConfig config){
//super(new ModuleComponentConfig(config,this.getAttribute("id").getValue(),this.get));
super(config);
//this.componentType = config.getComponentType();
//this.rendererType = config.getRendererType();
this.id = this.getAttribute("id");
this.binding = this.getAttribute("binding");
this.componentClass = this.getAttribute("class");
this.template = this.getAttribute("template");
TagAttribute atype = this.getAttribute("type");
if(atype!=null){
this.type=atype.getValue();
}
String sId = null;
if(this.id!=null){
sId=this.id.getValue();
}
String sTemplate=null;
if(this.template!=null){
sTemplate=this.template.getValue();
}
BuilderPageComponentConfig conf = new BuilderPageComponentConfig(config,sId,sTemplate);
this.componentType=conf.getTemplateComponentType();
}
/**
* Method handles UIComponent tree creation in accordance with the JSF 1.2
* spec.
* <ol>
* <li>First determines this UIComponent's id by calling
* {@link #getId(FaceletContext) getId(FaceletContext)}.</li>
* <li>Search the parent for an existing UIComponent of the id we just
* grabbed</li>
* <li>If found, {@link #markForDeletion(UIComponent) mark} its children
* for deletion.</li>
* <li>If <i>not</i> found, call
* {@link #createComponent(FaceletContext) createComponent}.
* <ol>
* <li>Set the UIComponent's id</li>
* <li>Set the RendererType of this instance</li>
* </ol>
* </li>
* <li>Now apply the nextHandler, passing the UIComponent we've
* created/found.</li>
* <li>Now add the UIComponent to the passed parent</li>
* <li>Lastly, if the UIComponent already existed (found), then
* {@link #finalizeForDeletion(UIComponent) finalize} for deletion.</li>
* </ol>
*
* @see com.sun.facelets.FaceletHandler#apply(com.sun.facelets.FaceletContext,
* javax.faces.component.UIComponent)
*
* @throws TagException
* if the UIComponent parent is null
*/
public final void apply(FaceletContext ctx, UIComponent parent)
throws IOException, FacesException, ELException {
// make sure our parent is not null
if (parent == null) {
throw new TagException(this.tag, "Parent UIComponent was null");
}
// possible facet scoped
String facetName = this.getFacetName(ctx, parent);
// our id
String id = ctx.generateUniqueId(this.tagId);
// grab our component
UIComponent c = ComponentSupport.findChildByTagId(parent, id);
boolean componentFound = false;
if (c != null) {
componentFound = true;
// mark all children for cleaning
if (log.isLoggable(Level.FINE)) {
log.fine(this.tag
+ " Component["+id+"] Found, marking children for cleanup");
}
ComponentSupport.markForDeletion(c);
} else {
c = this.createComponent(ctx);
if (log.isLoggable(Level.FINE)) {
log.fine(this.tag + " Component["+id+"] Created: "
+ c.getClass().getName());
}
this.setAttributes(ctx, c);
// mark it owned by a facelet instance
c.getAttributes().put(ComponentSupport.MARK_CREATED, id);
// assign our unique id
if (this.id != null) {
c.setId(this.id.getValue(ctx));
} else {
UIViewRoot root = ComponentSupport.getViewRoot(ctx, parent);
if (root != null) {
String uid = root.createUniqueId();
c.setId(uid);
}
}
if (this.rendererType != null) {
c.setRendererType(this.rendererType);
}
// hook method
this.onComponentCreated(ctx, c, parent);
}
// first allow c to get populated
this.applyNextHandler(ctx, c);
// finish cleaning up orphaned children
if (componentFound) {
ComponentSupport.finalizeForDeletion(c);
if (facetName == null) {
parent.getChildren().remove(c);
}
}
this.onComponentPopulated(ctx, c, parent);
// add to the tree afterwards
// this allows children to determine if it's
// been part of the tree or not yet
if (facetName == null) {
parent.getChildren().add(c);
} else {
parent.getFacets().put(facetName, c);
}
}
/**
* Return the Facet name we are scoped in, otherwise null
* @param ctx
* @return
*/
protected final String getFacetName(FaceletContext ctx, UIComponent parent) {
return (String) parent.getAttributes().get(FacetHandler.KEY);
}
/**
* If the binding attribute was specified, use that in conjuction with our
* componentType String variable to call createComponent on the Application,
* otherwise just pass the componentType String.
* <p />
* If the binding was used, then set the ValueExpression "binding" on the
* created UIComponent.
*
* @see Application#createComponent(javax.faces.el.ValueBinding,
* javax.faces.context.FacesContext, java.lang.String)
* @see Application#createComponent(java.lang.String)
* @param ctx
* FaceletContext to use in creating a component
* @return
*/
protected UIComponent createComponent(FaceletContext ctx) {
UIComponent c = null;
FacesContext faces = ctx.getFacesContext();
Application app = faces.getApplication();
if (this.binding != null) {
ValueExpression ve = this.binding.getValueExpression(ctx,
Object.class);
if (FacesAPI.getVersion() >= 12) {
c = app.createComponent(ve, faces, this.componentType);
if (c != null) {
// Make sure the component supports 1.2
if (FacesAPI.getComponentVersion(c) >= 12) {
c.setValueExpression("binding", ve);
} else {
ValueBinding vb = new LegacyValueBinding(ve);
c.setValueBinding("binding", vb);
}
}
} else {
ValueBinding vb = new LegacyValueBinding(ve);
c = app.createComponent(vb, faces, this.componentType);
if (c != null) {
c.setValueBinding("binding", vb);
}
}
} else {
c = app.createComponent(this.componentType);
}
return c;
}
/**
* If the id TagAttribute was specified, get it's value, otherwise generate
* a unique id from our tagId.
*
* @see TagAttribute#getValue(FaceletContext)
* @param ctx
* FaceletContext to use
* @return what should be a unique Id
*/
protected String getId(FaceletContext ctx) {
if (this.id != null) {
return this.id.getValue(ctx);
}
return ctx.generateUniqueId(this.tagId);
}
protected MetaRuleset createMetaRuleset(Class type){
MetaRuleset m = super.createMetaRuleset(type);
// ignore standard component attributes
m.ignore("binding").ignore("id");
// add auto wiring for attributes
Class componentRuleClass;
try {
componentRuleClass = Class.forName("com.sun.facelets.tag.jsf.ComponentRule");
MetaRule rule = (MetaRule)componentRuleClass.newInstance();
//m.addRule(ComponentRule.Instance);
m.addRule(rule);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// if it's an ActionSource
if (ActionSource.class.isAssignableFrom(type)) {
//m.addRule(ActionSourceRule.Instance);
try{
Class acomponentRuleClass = Class.forName("com.sun.facelets.tag.jsf.ActionSourceRule");
MetaRule aRule = (MetaRule)acomponentRuleClass.newInstance();
//m.addRule(ComponentRule.Instance);
m.addRule(aRule);
}
catch(Exception e){}
}
// if it's a ValueHolder
if (ValueHolder.class.isAssignableFrom(type)) {
//m.addRule(ValueHolderRule.Instance);
try{
Class acomponentRuleClass = Class.forName("com.sun.facelets.tag.jsf.ValueHolderRule");
MetaRule aRule = (MetaRule)acomponentRuleClass.newInstance();
//m.addRule(ComponentRule.Instance);
m.addRule(aRule);
}
catch(Exception e){}
// if it's an EditableValueHolder
if (EditableValueHolder.class.isAssignableFrom(type)) {
m.ignore("submittedValue");
m.ignore("valid");
m.addRule(EditableValueHolderRule.Instance);
}
}
return m;
}
/**
* A hook method for allowing developers to do additional processing once Facelets
* creates the component. The 'setAttributes' method is still perferred, but this
* method will provide the parent UIComponent before it's been added to the tree and
* before any children have been added to the newly created UIComponent.
*
* @param ctx
* @param c
* @param parent
*/
protected void onComponentCreated(FaceletContext ctx, UIComponent c, UIComponent parent) {
// do nothing
}
protected void onComponentPopulated(FaceletContext ctx, UIComponent c, UIComponent parent) {
// do nothing
}
protected void applyNextHandler(FaceletContext ctx, UIComponent c)
throws IOException, FacesException, ELException {
// first allow c to get populated
this.nextHandler.apply(ctx, c);
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}