Tuesday 19 April 2016

ocpsoft Rewrite

What is Rewrite? The answer is http://www.ocpsoft.org/rewrite/ :). There is a problem when you want to add rules at runtime without restarting web container. There isn't documentation for doing that. Here is the extension to official documentation ;).

When you want to add rule at runtime you have to implement your own HttpConfigurationCacheProvider.
public class ServletContextConfigurationCacheProvider extends HttpConfigurationCacheProvider
{
 /**
  * 
  */
 static Logger logger = Logger.getLogger(ServletContextConfigurationCacheProvider.class);
 /**
  * 
  */
 private static final String KEY = ServletContextConfigurationCacheProvider.class.getName() + "_cachedConfig";
 /**
  * 
  */
 private static final String RELOAD_CONFIGURATION = "org.ocpsoft.rewrite.config.CONFIG_RELOADING";

 /* (non-Javadoc)
  * @see org.ocpsoft.rewrite.spi.ConfigurationCacheProvider#getConfiguration(java.lang.Object)
  */
 @Override
 public Configuration getConfiguration(ServletContext context)
 {
  logger.debug("getConfiguration called");
  
  if(RewriteManager.isInitialized)
  {
   logger.debug("Configuration should not be reloaded");
   return (Configuration)context.getAttribute(KEY);
  }
  
  String reload = context.getInitParameter(RELOAD_CONFIGURATION);
  
  if (reload != null && "true".equalsIgnoreCase(reload.trim())) 
  {
   return null;
  }
  
  return (Configuration) context.getAttribute(KEY);
   }

   /* (non-Javadoc)
    * @see org.ocpsoft.rewrite.spi.ConfigurationCacheProvider#setConfiguration(java.lang.Object, org.ocpsoft.rewrite.config.Configuration)
    */
 @Override
   public void setConfiguration(ServletContext context, Configuration configuration)
   {
    logger.debug("setConfiguration called");
       context.setAttribute(KEY, configuration);
   }

   /* (non-Javadoc)
    * @see org.ocpsoft.common.pattern.Weighted#priority()
    */
 @Override
   public int priority()
   {
      return -10000;
   }
}

getConfiguration(ServletContext context) is called when reqeust occurs. When you want to reload rules you have to set  RewriteManager.isInitialized to false. The next step is to register service. In order to do that create file: org.ocpsoft.rewrite.spi.ConfigurationCacheProvider and place it in: WEB-INF/classes/META-INF/services catalog of your application. File should contain one line of code: aik.cms.navigation.configuration.ServletContextConfigurationCacheProvider.

Next step is to set contex parameter in web.xml, just add this code:


 
     org.ocpsoft.rewrite.config.CONFIG_RELOADING
     true
  
Of course you have to implement HttpConfigurationProvider to load configuration. The last step is to set variable to prevent reloading configuration for each request. You have to do it inside getConfiguration() method after return configuration. In should look like this:
@RewriteConfiguration
public class AikCmsRewriteConfigurationProvider extends HttpConfigurationProvider implements Serializable
{
 /**
  * Serial version UID
  */
 private static final long serialVersionUID = 5515384196041689598L;
 /**
  * Logger object
  */
 static Logger logger = Logger.getLogger(AikCmsRewriteConfigurationProvider.class);
 /**
  * 
  */
 @ManagedProperty(value="#{userBean}")
 protected UserBean userBean;
 
 /* (non-Javadoc)
  * @see org.ocpsoft.rewrite.config.ConfigurationProvider#getConfiguration(java.lang.Object)
  */
 @Override
 public Configuration getConfiguration(ServletContext servletContext)
 {
               ConfigurationBuilder config = ConfigurationBuilder.begin();
              // Here build your rules


  RewriteManager.getInstance().isInitialized = true; // This variable is read in  ServletContextConfigurationCacheProvider and prevents to calling this method each request

  return config;
 }
 /* (non-Javadoc)
  * @see org.ocpsoft.common.pattern.Weighted#priority()
  */
 @Override
 public int priority()
 {
  // TODO Auto-generated method stub
  return 1;
 }
}

Tuesday 14 April 2015

JSF Composite component with backing component, JavaScript, ajax, PrimeFaces and component handler

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());
	}

			

Thursday 12 February 2015

PrimeFaces theme converter

I've created PrimeFaces theme converter library as an aik-theme-converter.jar.

Dependencies:

- org.apache.commons.io.FileUtils;
- org.apache.log4j.Logger;

Usage. Create custom theme on JQuery web page. Download theme to local folder, for instance: c:\test. Create ThemeConverter object and call convert(...) method.  This method creates PrimeFaces theme jar in given folder.
 ThemeConverter converter = new ThemeConverter();
  
  try
  {
   converter.convert("c:\test\jquery-ui-1.11.2.custom.zip", "theme_name", "c:\test");
  }
  catch (IOException e)
  {
   logger.error(e.getMessage());
  }
theme_name.jar will be created in test directory.

Monday 8 December 2014

AikFaces User Guide

AikFaces is a JSF 2.2 component library extracted from AIK CMS project. This is my little contribution to Open Source community.

Let's start up ;).

Downloads:

https://sourceforge.net/projects/aikfaces/

Dependencies:

All libraries are included inside lib folder in aikfaces-showcase application.

Other requirements.
All components have to be nested inside <h:form> with property prependId set to false. The same rule you have to use for instance in PrimeFaces component like <p:accordionPanel prependId="false"/>

This component is used for fetching and creating atuomatically data from any databas from given SQL query.

Usage.



   
   


aik-cms:sqlResultSetDataTable.

sqlResultSetDataTable has default implementation for MySQL database. In order to use other databases you have to extends AbstractConnectionFactory class and add to classpath Jdbc driver. The code below is MySQL implementation.
public class MySqlConnectionFactory extends AbstractConnectionFactory
{
 /**
  * Serial version UID
  */
 private static final long serialVersionUID = 4689387254824026857L;
 /**
  * Logger object
  */
 static Logger logger = Logger.getLogger(MySqlConnectionFactory.class);
 /* (non-Javadoc)
  * @see aik.cms.database.AbstractConnectionFactory#createConnection(aik.cms.database.DatabaseConnectionData)
  */
 @Override
 public Connection createConnection(DatabaseConnectionData data)throws ClassNotFoundException, ParameterException, SQLException
 {
  if(data == null)
   throw new ParameterException("Parameter: data is null");
  if(data.getHost() == null)
   throw new ParameterException("Parameter: host is null");
  if(data.getDatabase() == null)
   throw new ParameterException("Parameter: database is null");
  if(data.getUser() == null)
   throw new ParameterException("Parameter: user is null");
  if(data.getPassword() == null)
   throw new ParameterException("Parameter: password is null");
  
  Connection con = null;
  
  try
  {
   Class.forName("com.mysql.jdbc.Driver");
   String url = "jdbc:mysql://" + data.getHost() + "/" + data.getDatabase() + "?user=" + data.getUser() + "&password=" + data.getPassword() + "&useUnicode=true&characterEncoding=UTF-8";
   logger.debug("Connection url: " + url);
   con = DriverManager.getConnection(url);
  }
  catch (ClassNotFoundException | SQLException e)
  {
   logger.error(e.getMessage());
   throw e;
  }
  
  return con;
 }
}


Tuesday 25 March 2014

PrimeFaces, JSF and Groovy integration

What to do if you want to add code dynamically to Jave EE application but you don't want to reload application every time? The answer is smiple add Groovy to your application. You don't have to learn Groovy language. Groovy's scripts can be written just in Java.

Suppose we want to implement in Groovy script p:commandButton action property and use it like this:


where beanTestowy is a Java Bean, groovyObject is type of Object and action is a method we want to implement in Groovy script.

The only requirement: Groovy class has to be derived from Java class. In other words yout have to create java class with interface you want to implement later in Groovy.

AikCmsBeanMethod.java

public class AikCmsBeanMethod implements Serializable
{
    /**
     * Serial version UID
     */
    private static final long serialVersionUID = -228352962604439051L;
    /**
     * Logger object
     */
    static Logger logger = Logger.getLogger(AikCmsBeanMethod.class);
    /**
     *
     */
    protected BasicWidgetBean bean;

    /**
     * Default constructor
     */
    public AikCmsBeanMethod()
    {

        super();

        logger.debug("AikCmsBeanMethod object has been created");
    }
    /**
     * @param bean
     */
    public AikCmsBeanMethod(BasicWidgetBean bean)
    {

        this();

        this.bean = bean;
    }
    /**
     * Action method
     * @return
     */
    public String action()
    {

        logger.debug("Default action() called");

        return null;
    }
    /**
     * @param argument
     * @return
     */
    public String action(Object argument)
    {
        logger.debug("Default action(Object arg) called");

        return null;
    }
    /**
     * @param arg
     * @param arg1
     * @return
     */
    public String action(Object arg, Object arg1)
    {
        logger.debug("Default action(Object arg, Object arg1) called");
        return null;
    }
    /**
     * @param arg
     * @param arg1
     * @param arg2
     * @return
     */
    public String action(Object arg, Object arg1, Object arg2)
    {
        logger.debug("Default action(Object arg, Object arg1, Object arg3) called");
        return null;
    }
    /**
     * @param vce
     */
    public void valueChangeListener(ValueChangeEvent vce)
    {
        logger.debug("valueChangeListener called");
        logger.debug("Old value: " + vce.getOldValue() + " New value: " + vce.getNewValue());
    }
    /**
     * PrimeFaces p:ajax listener
     */
    public void pAjaxListener()
    {
        logger.debug("Defautl PF ajax listener called");
    }
    /**
     * PrimeFaces p:ajax listener
     * @param argument
     */
    public void pAjaxListener(Object argument)
    {
        logger.debug("Default PF ajax listner caledd pAjaxListener(Object arg)");
    }
    /**
     * JSF native f:ajax listener
     * @param event
     */
    public void jsfAjaxListener(AjaxBehaviorEvent event)
    {
        logger.debug("Default jsfAjaxListener called jsfAjaxListener(AjaxBehaviorEvent event)");
    }
    /**
     * @return the bean
     */
    public BasicWidgetBean getBean()
    {
        return bean;
    }
    /**
     * @param bean the bean to set
     */
    public void setBean(BasicWidgetBean bean)
    {
        this.bean = bean;
    }
    /**
     * @param event
     */
    public void treeNodeSelectEvent(NodeSelectEvent event)
    { 
    }
    /**
     * @param event
     */
    public void treeNodeUnselectEvent(NodeUnselectEvent event)
    {
    }
    /**
     * @param event
     */
    public void treeNodeCollapseEvent(NodeCollapseEvent event)
    { 
    }
    /**
     * @param event
     */
    public void treeNodeExpandEvent(NodeExpandEvent event)
    { 
    }

Above class is from my AIK CMS project. The next step is to create Groovy script GroovyTestBean.groovy.

GroovyTestBean.groovy

public class GroovyTestBean extends aik.cms.widget.bean.method.AikCmsBeanMethod
{
    public String action()
    {
        println 'Action called'
        return super.action();
    }
    public void pAjaxListener()
    {
        println 'PrimeFaces ajax listener called'
    }
}
In order to use our Groovy scirpt like this:



we need access to Groovy object in java bean. In other words we have to load GroovyTestBean object from the script.

 public Object getGroovyObject()
 {
        Object myObject = null;

        try
        {
            String            groovy      = AikCms.getInstance().getValue(AikCms.AIK_CMS_PATH) +   File.separator + "aik" + File.separator + "groovy" + File.separator;
            FileInputStream   inputStream = new FileInputStream(groovy + "GroovyTestBean.groovy");
            String            everything  = IOUtils.toString(inputStream);
            GroovyClassLoader gcl         = new GroovyClassLoader();
            Class             clazz       = gcl.parseClass(everything, "GroovyTestBean.groovy");
            Object            aScript     = clazz.newInstance();
            myObject                      = aScript;           
        }
        catch (ResourceException | ScriptException | IOException | InstantiationException | IllegalAccessException e)
        {
            logger.error(e.getMessage());
        }       

        return myObject; // This is our Groovy object
} 
 
myObject - is our GroovyTestBean object loaded from GroovyTestBean.groovy script.

This is a short video from my YouTube channel. It shows that it works ;) http://youtu.be/WPW53GZkHDE