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

Reply via email to