mcardle 2005/05/27 16:51:11 CEST
Added files:
core/src/java/org/jahia/data/containers
ContainerChainedFilter.java
Log:
Use this class to combine multiple filters implementing the
ContainerFilterInterface interface, such as ContainerFilterBean or
ContainerChainedFilter, with logical operators.
Revision Changes Path
1.1 +484 -0
jahia/core/src/java/org/jahia/data/containers/ContainerChainedFilter.java (new)
http://jahia.mine.nu:8080/cgi-bin/cvsweb.cgi/jahia/core/src/java/org/jahia/data/containers/ContainerChainedFilter.java?rev=1.1&content-type=text/plain
Index: ContainerChainedFilter.java
====================================================================
package org.jahia.data.containers;
import org.jahia.exceptions.JahiaException;
import java.util.BitSet;
/**
* Use this class to combine multiple filters implementing the [EMAIL
PROTECTED] ContainerFilterInterface}
* interface, such as [EMAIL PROTECTED] ContainerFilterBean} or [EMAIL
PROTECTED] ContainerChainedFilter}, with
* logical operators.
*
* Since you can enclose multiple [EMAIL PROTECTED] ContainerChainedFilter}
objects inside a ContainerChainedFilter
* object, this means you can have a hierarchy of logical operators, giving
an equilavent to braces in
* the following expression (a AND b OR (C XOR d))
*
* Supported logical operators are: OR, AND, ANDNOT, XOR.
*
* Example:
*
* ContainerFilterBean containerFilter1 = new ContainerFilterBean("people",
jParams.getEntryLoadRequest());
* containerFilter1.addClause(ContainerFilterBean.COMP_EQUAL,"");
*
* ContainerFilterBean containerFilter2 = new ContainerFilterBean("skills",
jParams.getEntryLoadRequest());
* containerFilter2.addClause(ContainerFilterBean.COMP_EQUAL,"computers");
*
* ContainerFilterBean containerFilter3 = new ContainerFilterBean("john",
jParams.getEntryLoadRequest());
* containerFilter3.addClause(ContainerFilterBean.COMP_EQUAL,"");
*
* ContainerFilterBean containerFilter4 = new ContainerFilterBean("Age",true,
jParams.getEntryLoadRequest());
*
containerFilter4.addClause(ContainerFilterBean.COMP_SMALLER_OR_EQUAL,String.valueOf(ageLong));
*
* ContainerChainedFilter someFilters = new ContainerChainedFilter(
* new
ContainerFilterInterface[]{containerFilter1,containerFilter2,containerFilter3,containerFilter4},
* new
int[]{ContainerChainedFilter.OR,ContainerChainedFilter.OR,ContainerChainedFilter.OR});
*
* ContainerFilterBean containerFilter5 = new ContainerFilterBean("Type",
jParams.getEntryLoadRequest());
* containerFilter4.addClause(ContainerFilterBean.COMP_NOTEQUAL,"Wood");
*
* ContainerChainedFilter allFilters = new ContainerChainedFilter(
* new ContainerFilterInterface[]{someFilters,containerFilter5},
* new int[]{ContainerChainedFilter.AND});
*
* This is equivalent to :
*
* (people=="" OR skills=="computers" OR john=="" OR Age<=ageLong) AND
Type!=Wood
*
* @see ContainerFilterInterface
* @see ContainerFilterBean
* @see ContainerFilterByContainerDefinition
* @see ContainerFilterByContainerDefinitions
*
* @author Khue Nguyen <a href="mailto:[EMAIL PROTECTED]">[EMAIL
PROTECTED]</a>
* @author MC
*/
public class ContainerChainedFilter implements ContainerFilterInterface
{
private static org.apache.log4j.Logger logger =
org.apache.log4j.Logger.getLogger (ContainerChainedFilter.class);
/**
* [EMAIL PROTECTED] BitSet#or}.
*/
public static final int OR = 0;
/**
* [EMAIL PROTECTED] BitSet#and}.
*/
public static final int AND = 1;
/**
* [EMAIL PROTECTED] BitSet#andNot}.
*/
public static final int ANDNOT = 2;
/**
* [EMAIL PROTECTED] BitSet#xor}.
*/
public static final int XOR = 3;
/**
* Logical operation when none is declared. Defaults to
* [EMAIL PROTECTED] BitSet#or}.
*/
public static int DEFAULT = OR;
/** The filter chain */
private ContainerFilterInterface[] chain = null;
private int[] logicArray;
private int logic = -1;
/**
* Ctor.
* @param chain The chain of filters
*/
public ContainerChainedFilter(ContainerFilterInterface[] chain)
{
this.chain = chain;
}
/**
* Ctor.
* @param chain The chain of filters
* @param logicArray Logical operations to apply between filters
*/
public ContainerChainedFilter(ContainerFilterInterface[] chain, int[]
logicArray)
{
this.chain = chain;
this.logicArray = logicArray;
}
/**
* Ctor.
* @param chain The chain of filters
* @param logic Logicial operation to apply to ALL filters
*/
public ContainerChainedFilter(ContainerFilterInterface[] chain, int logic)
{
this.chain = chain;
this.logic = logic;
}
//--------------------------------------------------------------------------
/**
* Perform filtering.
* The expected result is a bit set of matching container ids.
*
* @ param int ctnListID, the container list id
* @ return BitSet bitsFromLogic, the expected result as a bit set of
matching ctn ids,each bit position set to true correspond to matching ctn ids.
*/
public BitSet doFilter(int ctnListID)
throws JahiaException {
return this.bits(new FilterData(ctnListID));
}
//--------------------------------------------------------------------------
/**
* Return the select statement, build with the clauses for all container
list of the site.
*
* @ param int ctnListID, the container list id
* @ return String , the sql statement. Null on error
*/
public String getSelect (int ctnListID) {
if (chain == null) {
return "";
}
StringBuffer buff = new StringBuffer();
FilterData data = new FilterData(ctnListID);
ContainerFilterInterface filter = null;
String val = "";
for (int i = 0; i < chain.length; i++) {
filter = (ContainerFilterInterface) chain[i];
val = filter.getSelect(ctnListID);
if (val != null) {
if (i > 0) {
int logop = (this.logic != -1) ? this.logic :
this.logicArray[i-1];
switch (logop) {
case OR:
buff.append(" UNION ");
break;
case AND:
buff.append(" INTERSECT ");
break;
case XOR:
buff.append(" XOR "); //probably not supported in
SQL but this SQL statement is not executed anyway, just used as ID for caching
break;
case ANDNOT:
buff.append(" ANDNOT "); //probably not supported
in SQL but this SQL statement is not executed anyway, just used as ID for
caching
break;
default:
buff.append(" DEFAULT_OPERATOR ");//probably not
supported in SQL but this SQL statement is not executed anyway, just used as ID
for caching
break;
}
}
buff.append(val);
}
}
return buff.toString();
}
//--------------------------------------------------------------------------
/**
* Set reference to a containerFilters
*
* @ return
* @ throws JahiaException
*/
public void setContainerFilters(ContainerFilters containerFilters){
if ( chain == null ){
return;
}
ContainerFilterInterface filter = null;
for ( int i=0; i<chain.length; i++ ){
filter = (ContainerFilterInterface)chain[i];
filter.setContainerFilters(containerFilters);
}
}
//--------------------------------------------------------------------------
/**
* Perform filtering on a given site or all sites
*
* The expected result is a bit set of matching container ids.
*
* If siteId = -1 , returns results from all sites
*
* If the containerDefinitionName is null, return result from all
containers
* no regards to it definition !
*
* @param siteId
* @param containerDefinitionName
* @param listId , optionally, a listID can be passed to returns all
containers of this containerlist.
* @return BitSet bitsFromLogic, the expected result as a bit set of
matching ctn ids,each bit position set to true correspond to matching ctn ids.
* @throws JahiaException
*/
public BitSet doFilterBySite(int siteId, String containerDefinitionName,
int listId)
throws JahiaException{
return this.bits(new FilterData(siteId, containerDefinitionName,
listId));
}
//--------------------------------------------------------------------------
/**
* Return the select statement, build with the clauses for a given site.
* If siteId = -1 -> build query for all sites
*
* If the containerDefinitionName is null, return result from all
containers
* no regards to it definition !
*
* @param siteId
* @param containerDefinitionName
* @return
*/
public String getSelectBySiteID (int siteId,
String containerDefinitionName) {
if (chain == null) {
return "";
}
StringBuffer buff = new StringBuffer();
ContainerFilterInterface filter = null;
String val = "";
for (int i = 0; i < chain.length; i++) {
filter = (ContainerFilterInterface) chain[i];
val = filter.getSelectBySiteID(siteId, containerDefinitionName);
if (val != null) {
if (i > 0) {
int logop = (this.logic != -1) ? this.logic :
this.logicArray[i-1];
switch (logop) {
case OR:
buff.append(" UNION ");
break;
case AND:
buff.append(" INTERSECT ");
break;
case XOR:
buff.append(" XOR "); //probably not supported in
SQL but this SQL statement is not executed anyway, just used as ID for caching
break;
case ANDNOT:
buff.append(" ANDNOT ");//probably not supported
in SQL but this SQL statement is not executed anyway, just used as ID for
caching
break;
default:
buff.append(" DEFAULT_OPERATOR ");//probably not
supported in SQL but this SQL statement is not executed anyway, just used as ID
for caching
break;
}
}
buff.append(val);
}
}
return buff.toString();
}
private BitSet bits(FilterData filterData) throws JahiaException
{
if (logic != -1)
return bitsFromLogic(logic, filterData);
else if (logicArray != null)
return bits(logicArray, filterData);
else
return bitsFromLogic(DEFAULT, filterData);
}
/**
* Delegates to each filter in the chain.
* @param logic Logical operation
* @return BitSet
*/
private BitSet bitsFromLogic(int logic, FilterData filterData) throws
JahiaException
{
BitSet result;
int i = 0;
/**
* First AND operation takes place against a completely false
* bitset and will always return zero results. Thanks to
* Daniel Armbrust for pointing this out and suggesting workaround.
*/
if (logic == AND)
{
if ( !filterData.isSiteSearch() ) {
result = (BitSet)
chain[i].doFilter(filterData.getListId()).clone();
} else {
result = (BitSet)
chain[i].doFilterBySite(filterData.getSiteId(),
filterData.getContainerDefinitionName(),filterData.getListId()).clone();
}
++i;
}
else
{
result = new BitSet();
}
for (; i < chain.length; i++)
{
doChain(result, logic, chain[i], filterData);
}
return result;
}
/**
* Delegates to each filter in the chain.
* @param logic Logical operation
* @return BitSet
*/
private BitSet bits(int[] logic, FilterData filterData) throws
JahiaException
{
if (logic.length < chain.length-1)
throw new IllegalArgumentException("Invalid number of elements in
logic array");
BitSet result = null;
if ( !filterData.isSiteSearch() ) {
result = (BitSet)
chain[0].doFilter(filterData.getListId()).clone();
} else {
result = (BitSet) chain[0].doFilterBySite(filterData.getSiteId(),
filterData.getContainerDefinitionName(),filterData.getListId()).clone();
}
for (int i=1; i < chain.length; i++)
{
doChain(result, logic[i-1], chain[i], filterData);
}
return result;
}
private void doChain(BitSet result, int logic, ContainerFilterInterface
filter, FilterData filterData)
throws JahiaException
{
System.err.println("Before Resultset : " +
filterData.containerDefinitionName+" "
+ " size: " + result.size() );
switch (logic)
{
case OR:
if ( !filterData.isSiteSearch() ) {
result.or(filter.doFilter(filterData.getListId()));
} else {
result.or(filter.doFilterBySite(filterData.getSiteId(),
filterData.getContainerDefinitionName(),filterData.getListId()));
}
break;
case AND:
if ( !filterData.isSiteSearch() ) {
result.and(filter.doFilter(filterData.getListId()));
} else {
result.and(filter.doFilterBySite(filterData.getSiteId(),
filterData.getContainerDefinitionName(),filterData.getListId()));
}
break;
case ANDNOT:
if ( !filterData.isSiteSearch() ) {
result.andNot(filter.doFilter(filterData.getListId()));
} else {
result.andNot(filter.doFilterBySite(filterData.getSiteId(),
filterData.getContainerDefinitionName(),filterData.getListId()));
}
break;
case XOR:
if ( !filterData.isSiteSearch() ) {
result.xor(filter.doFilter(filterData.getListId()));
} else {
result.xor(filter.doFilterBySite(filterData.getSiteId(),
filterData.getContainerDefinitionName(),filterData.getListId()));
}
break;
default:
doChain(result, DEFAULT, filter, filterData);
break;
}
System.err.println("After Resultset : " +
filterData.containerDefinitionName+" "
+ " size: " + result.size() );
}
public String toString()
{
StringBuffer sb = new StringBuffer();
sb.append("ChainedFilter: [");
for (int i = 0; i < chain.length; i++)
{
if (i>0) {
int logop = (this.logic != -1) ? this.logic :
this.logicArray[i-1] ;
switch (logop) {
case OR:
sb.append(" OR ");
break;
case AND:
sb.append(" AND ");
break;
case XOR:
sb.append(" XOR ");
break;
case ANDNOT:
sb.append(" XOR ");
break;
default:
sb.append(" OR ");
break;
}
}
sb.append(chain[i]);
sb.append(' ');
}
sb.append(']');
return sb.toString();
}
private class FilterData {
private int listId;
private String containerDefinitionName;
private int siteId;
private boolean siteSearch = false;
public FilterData(int listId) {
this.listId = listId;
}
public FilterData(int siteId, String containerDefinitionName, int
listId) {
this.listId = listId;
this.containerDefinitionName = containerDefinitionName;
this.siteId = siteId;
this.siteSearch = true;
}
public int getListId() {
return listId;
}
public void setListId(int listId) {
this.listId = listId;
}
public String getContainerDefinitionName() {
return containerDefinitionName;
}
public void setContainerDefinitionName(String
containerDefinitionName) {
this.containerDefinitionName = containerDefinitionName;
}
public int getSiteId() {
return siteId;
}
public void setSiteId(int siteId) {
this.siteId = siteId;
}
public boolean isSiteSearch() {
return siteSearch;
}
public void setSiteSearch(boolean siteSearch) {
this.siteSearch = siteSearch;
}
}
}