Today, I'm going to show how to create composite component with backing component and how to add event listener triggered within composite component. There is a lot of tutorials showing how to create composite component, but there is a lack of how to add event handler even in books. I've decided to write about it. By the way I show how to implement image editor based on Creative Cloud. I hope it will be useful.
The goal: create composite component which enable to edit images with Creative Cloud Web SDK. The first step is registering on Adobe in order to create application and obtain appKey.
The second step is to create composite component.
As always code comes from my project. In this case it is simple image editor integrated with image chooser, but you can implement your own soulution.
Now, I only show soruce code, but later I'm going to explain in details.
Composite component
simpleImage.xhtml
Simple image editor
Backing component for composite component
SimpleImageEditorComponent.java
/**
* SimpleImageEditorComponent.java
*/
package aik.cms.component.composite;
import java.util.Map;
import javax.el.ELContext;
import javax.el.MethodExpression;
import javax.el.ValueExpression;
import javax.faces.component.FacesComponent;
import javax.faces.component.NamingContainer;
import javax.faces.component.UIInput;
import javax.faces.component.UINamingContainer;
import javax.faces.context.FacesContext;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.FacesEvent;
import org.apache.log4j.Logger;
import aik.cms.component.event.image.ImageChangedEvent;
import aik.cms.image.Image;
@FacesComponent("simpleImage")
public class SimpleImageEditorComponent extends UIInput implements NamingContainer
{
/**
* Logger object
*/
static Logger logger = Logger.getLogger(SimpleImageEditorComponent.class);
/**
*
*/
protected Image selectedImage;
enum PropertyKeys
{
imageSelectionVisibility,
image,
value
}
/**
* Default constructor
*/
public SimpleImageEditorComponent()
{
super();
logger.debug("SimpleImageEditorComponent has been created");
setImageSelectionVisibility(false);
}
/* (non-Javadoc)
* @see javax.faces.component.UIInput#getFamily()
*/
public String getFamily()
{
return UINamingContainer.COMPONENT_FAMILY;
}
/* (non-Javadoc)
* @see javax.faces.component.UIComponentBase#decode(javax.faces.context.FacesContext)
*/
@Override
public void decode(FacesContext facesContext)
{
super.decode(facesContext);
logger.debug("value: " + getAttributes().get("value"));
Map params = facesContext.getExternalContext().getRequestParameterMap();
String event = params.get("aikEvent");
if(event != null && event.compareTo("1") == 0) // image changed event
{
String imageURL = params.get("aikImageURL");
if(imageURL != null)
{
//TODO: Create image from given URL
Image image = getImage();
if(image == null) // Image not selected from aikcms images browser. Get and set image URL
{
image = new Image();
}
image.setImageURL(imageURL);
this.queueEvent(new ImageChangedEvent(this, image));
}
logger.debug("imageChangedEvent called");
}
}
/* (non-Javadoc)
* @see javax.faces.component.UIComponentBase#broadcast(javax.faces.event.FacesEvent)
*/
@Override
public void broadcast(FacesEvent event) throws AbortProcessingException
{
super.broadcast(event);
FacesContext facesContext = FacesContext.getCurrentInstance();
MethodExpression me = null;
if(event instanceof ImageChangedEvent)
{
me = (MethodExpression) this.getAttributes().get("imageChangedListener");
}
if(me != null)
{
me.invoke(facesContext.getELContext(), new Object[] {event});
}
}
/**
*
*/
public String setImageChooserVisible()
{
setImageSelectionVisibility(true);
return null;
}
/**
*
*/
public void setImageChooserInvisible()
{
setImageSelectionVisibility(false);
//return null;
}
/**
* @param visibility
*/
public void setImageSelectionVisibility(boolean visibility)
{
getStateHelper().put(PropertyKeys.imageSelectionVisibility, visibility);
}
/**
* @return
*/
public boolean getImageSelectionVisibility()
{
return (boolean)getStateHelper().eval(PropertyKeys.imageSelectionVisibility, null);
}
/**
* @return the selectedImage
*/
public Image getSelectedImage()
{
return selectedImage;
}
/**
* @param selectedImage the selectedImage to set
*/
public void setSelectedImage(Image selectedImage)
{
this.selectedImage = selectedImage;
setImage(selectedImage);
}
/**
* @param image
*/
public void setImage(Image image)
{
getStateHelper().put(PropertyKeys.image, image);
}
/**
* @return
*/
public Image getImage()
{
return (Image)getStateHelper().eval(PropertyKeys.image, null);
}
/**
* @return
*/
public String applyImage()
{
//TODO: Insert cms domain
getAttributes().put("value", "http://93.105.125.207:8080/" + getImage().getCmsPath());
setImageSelectionVisibility(false);
FacesContext facesContext = FacesContext.getCurrentInstance();
ELContext elContext = facesContext.getELContext();
ValueExpression valueExpression = facesContext.getApplication().getExpressionFactory().createValueExpression(elContext, "#{cc.attrs.value}", String.class);
if(selectedImage == null)
{
logger.error("selectedImage is null");
return null;
}
valueExpression.setValue(elContext, selectedImage.getCmsPath());
return null;
}
public void saveImage()
{
}
}
Component handler for composite component
/**
* ImageHandler.java
*/
package aik.cms.component.event.image;
import javax.faces.view.facelets.ComponentConfig;
import javax.faces.view.facelets.ComponentHandler;
import javax.faces.view.facelets.MetaRuleset;
import org.apache.log4j.Logger;
import com.sun.faces.facelets.tag.MethodRule;
public class ImageHandler extends ComponentHandler
{
/**
* Logger object
*/
static Logger logger = Logger.getLogger(ImageHandler.class);
/**
* @param config
*/
public ImageHandler(ComponentConfig config)
{
super(config);
// TODO Auto-generated constructor stub
logger.debug("ImageHandler has been created");
}
/* (non-Javadoc)
* @see javax.faces.view.facelets.DelegatingMetaTagHandler#createMetaRuleset(java.lang.Class)
*/
@Override
protected MetaRuleset createMetaRuleset(Class type)
{
// TODO Auto-generated method stub
MetaRuleset metaRuleset = super.createMetaRuleset(type);
Class[] changeEventClasses = new Class[]{ ImageChangedEvent.class };
metaRuleset.addRule(new MethodRule("imageChangedListener", Void.class, changeEventClasses));
return metaRuleset;
}
}
Event handler
/**
* ImageChangedEvent.java
*/
package aik.cms.component.event.image;
import javax.faces.component.UIComponent;
import javax.faces.event.FacesEvent;
import javax.faces.event.FacesListener;
import org.apache.log4j.Logger;
import aik.cms.image.Image;
public class ImageChangedEvent extends FacesEvent
{
/**
* Serial version UID
*/
private static final long serialVersionUID = -4854070727246981410L;
/**
* Logger object
*/
static Logger logger = Logger.getLogger(ImageChangedEvent.class);
/**
* Image :)
*/
protected Image image;
/**
* @param component
*/
public ImageChangedEvent(UIComponent component, Image image)
{
super(component);
this.image = image;
logger.debug("ImageChangedEvent called");
// TODO Auto-generated constructor stub
}
/* (non-Javadoc)
* @see javax.faces.event.FacesEvent#isAppropriateListener(javax.faces.event.FacesListener)
*/
@Override
public boolean isAppropriateListener(FacesListener arg0)
{
// TODO Auto-generated method stub
return false;
}
/* (non-Javadoc)
* @see javax.faces.event.FacesEvent#processListener(javax.faces.event.FacesListener)
*/
@Override
public void processListener(FacesListener arg0)
{
// TODO Auto-generated method stub
}
/**
* @return the image
*/
public Image getImage()
{
return image;
}
/**
* @param image the image to set
*/
public void setImage(Image image)
{
this.image = image;
}
}
aik.taglib.xml
simpleImage
aik.cms.component.composite.SimpleImageEditorComponent
aik.cms.component.composite.SimpleImageEditorComponent
aik.cms.component.event.image.ImageHandler
Usage. Method from managed bean
public void imageChangedListener(ImageChangedEvent event)
{
logger.debug("ImageChangedEvent called. URL of saved image: " + event.getImage().getImageURL());
}