Changeset 6934


Ignore:
Timestamp:
Jun 22, 2015, 3:37:26 PM (8 years ago)
Author:
Nicklas Nordborg
Message:

References #1950: Add support for any-to-any link filters in table lists views

Redesigned the hibernate filter definitions to make it possible to only activate the filters for a single item type (=the item type reutned by a query) at a time.

Location:
trunk/src/core/net/sf/basedb/core
Files:
3 edited
1 moved

Legend:

Unmodified
Added
Removed
  • trunk/src/core/net/sf/basedb/core/AbstractEntityQuery.java

    r6771 r6934  
    359359    if (requiredFilter != null || optionalFilter != null)
    360360    {
    361       filterManager = new QueryRuntimeFilterManager(dc);
     361      filterManager = new QueryRuntimeFilterManager(dc, getItemType());
    362362      if (requiredFilter != null) requiredFilter.enableFilters(filterManager, this, dc);
    363363      if (optionalFilter != null) optionalFilter.enableFilters(filterManager, this, dc);
  • trunk/src/core/net/sf/basedb/core/HibernateUtil.java

    r6880 r6934  
    5555import java.util.ArrayList;
    5656import java.util.Enumeration;
     57import java.util.HashMap;
    5758import java.util.LinkedList;
    5859import java.util.List;
    5960import java.util.Iterator;
    6061import java.util.Date;
     62import java.util.Map;
    6163import java.util.jar.JarEntry;
    6264import java.util.jar.JarFile;
     
    6769import java.sql.DatabaseMetaData;
    6870import java.sql.SQLException;
     71import java.io.IOException;
    6972import java.net.URL;
    7073
     
    302305        }
    303306      }
     307
    304308     
    305309      // Load the XML mapping files and register them with Hibernate
    306310      final URL dtdFile = HibernateUtil.class.getResource("/org/hibernate/hibernate-mapping-3.0.dtd");
     311      Map<String, Element> filterTemplate = loadFilterTemplate(dtdFile);
    307312      DOMOutputter out = new DOMOutputter();
    308313      for (URL url : mappingFiles)
     
    310315        log.info("Loading mapping file: " + url);
    311316        Document dom = XmlUtil2.getValidatedXml(url, dtdFile);
    312         manipulateDocument(dom);
     317        manipulateDocument(dom, filterTemplate);
    313318        cfg.addDocument(out.output(dom));
    314319      }
     
    334339   
    335340  */
    336   private static void manipulateDocument(Document dom)
    337   {
    338     // Get the <class> tag
    339     Element classTag = dom.getRootElement().getChild("class");
    340     String className = classTag != null ? classTag.getAttributeValue("name") : null;
    341     // We are only interested in <hibernate-mapping> with <class> elements
    342     if (className == null) return;
    343    
    344     // Extended properties
    345     if (ExtendedProperties.isExtendable(className))
    346     {
    347       addExtendedProperties(classTag, className);
    348     }
    349    
    350     // Permission filters
    351     addFilterConditions(classTag, className);
    352    
    353     // Unit symbol need to be case-sensitive
    354     if (className.endsWith("UnitSymbolData"))
    355     {
    356       fixUnitSymbolColumnDefinition(classTag);
     341  private static void manipulateDocument(Document dom, Map<String, Element> filterTemplate)
     342  {
     343    Element root = dom.getRootElement();
     344   
     345    // Load all <class> and <subclass> tags in the document
     346    Iterator<Element> it = root.getDescendants(new org.jdom2.filter.AbstractFilter<Element>()
     347      {
     348        private static final long serialVersionUID = 1L;
     349
     350        @Override
     351        public Element filter(Object obj)
     352        {
     353          if (!(obj instanceof Element)) return null;
     354 
     355          Element e = (Element)obj;
     356          String name = e.getName();
     357          return "class".equals(name) || "subclass".equals(name) ? e : null;
     358        }
     359      });
     360   
     361    // Copy to a list since we can't use the iterater and add elements to the
     362    // document at the same time (ConcurrentModificationException)
     363    List<Element> classTags = new ArrayList<Element>();
     364    while (it.hasNext())
     365    {
     366      classTags.add(it.next());
     367    }
     368   
     369    for (Element classTag: classTags)
     370    {
     371      String className = classTag.getAttributeValue("name");
     372   
     373      // Extended properties
     374      if (ExtendedProperties.isExtendable(className))
     375      {
     376        addExtendedProperties(classTag, className);
     377      }
     378   
     379      // Permission filters
     380      addFilterConditions(classTag, className, filterTemplate);
     381     
     382      // Unit symbol need to be case-sensitive
     383      if (className.endsWith("UnitSymbolData"))
     384      {
     385        fixUnitSymbolColumnDefinition(classTag);
     386      }
    357387    }
    358388  }
     
    395425 
    396426  /**
     427    Load filter definitions from 'filter-def-template.xml'. Store in map
     428    using the name of the filter as key.
     429    @since 3.6
     430  */
     431  private static Map<String, Element> loadFilterTemplate(final URL dtdFile)
     432    throws IOException
     433  {
     434    Document filterDef = XmlUtil2.getValidatedXml(HibernateUtil.class.getResource("/net/sf/basedb/core/filter-def-template.xml"), dtdFile);
     435    Map<String, Element> filters = new HashMap<String, Element>();
     436    for (Element filter : filterDef.getRootElement().getChildren())
     437    {
     438      filters.put(filter.getAttributeValue("name"), filter);
     439    }
     440    return filters;
     441  }
     442 
     443  /**
    397444    Add &lt;filter&gt; conditions to the given class tag.
    398445    @param classTag An Element representing a &lt;class&gt; tag
     
    400447    @since 2.17
    401448  */
    402   private static void addFilterConditions(Element classTag, String className)
     449  private static void addFilterConditions(Element classTag, String className, Map<String, Element> filterTemplate)
    403450  {
    404451    try
    405452    {
    406453      Class<?> c = Class.forName(className);
     454      Item itemType = Item.fromClass(c);
    407455      log.info("Adding 'denyAll' filter to "+c.getName());
    408       classTag.addContent(createFilterElement("denyAll", "`id` != `id`"));
     456      System.out.println("Class: " + c + "; itemType: " + itemType);
     457      if (itemType == null) return;
     458     
     459      defineFilter(classTag, itemType, "denyAll", "`id` != `id`", filterTemplate);
    409460      if (NewsData.class.isAssignableFrom(c))
    410461      {
    411462        log.info("Adding 'todaysNews' filter to "+c.getName());
    412         classTag.addContent(createFilterElement("todaysNews",
    413             ":today >= `start_date` AND (:today <= `end_date` OR `end_date` IS NULL)"));
     463        defineFilter(classTag, itemType, "todaysNews",
     464            ":today >= `start_date` AND (:today <= `end_date` OR `end_date` IS NULL)", filterTemplate);
    414465      }
    415466      if (MessageData.class.isAssignableFrom(c))
    416467      {
    417468        log.info("Adding 'ownedBy' filter to " + c.getName());
    418         classTag.addContent(createFilterElement("ownedBy", ":owner = `to_user_id`"));
     469        defineFilter(classTag, itemType, "ownedBy", ":owner = `to_user_id`", filterTemplate);
    419470      }
    420471      if (AnnotationData.class.isAssignableFrom(c))
    421472      {
    422473        log.info("Adding 'annotationTypes' filter to " + c.getName());
    423         classTag.addContent(createFilterElement("annotationTypes", "`annotationtype_id` IN (:annotationTypes)"));
     474        defineFilter(classTag, itemType, "annotationTypes", "`annotationtype_id` IN (:annotationTypes)", filterTemplate);
    424475      }
    425476      if (RemovableData.class.isAssignableFrom(c))
    426477      {
    427478        log.info("Adding 'isRemoved' filter to "+c.getName());
    428         classTag.addContent(createFilterElement("isRemoved", ":removed = `removed`"));
     479        defineFilter(classTag, itemType, "isRemoved", ":removed = `removed`", filterTemplate);
    429480      }
    430481      if (AnnotatableData.class.isAssignableFrom(c))
    431482      {
    432483        log.info("Adding 'isAnnotatated' filter to "+c.getName());
    433         classTag.addContent(createFilterElement("isAnnotated", ":annotated = (`annotationset_id` IS NOT NULL)"));
     484        defineFilter(classTag, itemType, "isAnnotated", ":annotated = (`annotationset_id` IS NOT NULL)", filterTemplate);
    434485      }
    435486      if (OwnableData.class.isAssignableFrom(c))
    436487      {
    437488        log.info("Adding 'ownedBy' filter to "+c.getName());
    438         classTag.addContent(createFilterElement("ownedBy", ":owner = `owner`"));
     489        defineFilter(classTag, itemType, "ownedBy", ":owner = `owner`", filterTemplate);
    439490       
    440491        log.info("Adding 'notOwnedBy' filter to "+c.getName());
    441         classTag.addContent(createFilterElement("notOwnedBy", ":owner != `owner`"));
     492        defineFilter(classTag, itemType, "notOwnedBy", ":owner != `owner`", filterTemplate);
    442493 
    443494        log.info("Adding 'memberOf' filter to "+c.getName());
    444         classTag.addContent(createFilterElement("memberOf", ":owner != `owner` AND `id` IN (:items)"));
     495        defineFilter(classTag, itemType, "memberOf", ":owner != `owner` AND `id` IN (:items)", filterTemplate);
    445496 
    446497        log.info("Adding 'ownedByOrMemberOf' filter to "+c.getName());
    447         classTag.addContent(createFilterElement("ownedByOrMemberOf", "(:owner = `owner` OR `id` IN (:items))"));
     498        defineFilter(classTag, itemType, "ownedByOrMemberOf", "(:owner = `owner` OR `id` IN (:items))", filterTemplate);
    448499      }
    449500      else if (UserData.class.isAssignableFrom(c))
    450501      {
    451502        log.info("Adding 'memberOf' filter to "+c.getName());
    452         classTag.addContent(createFilterElement("memberOf", "(`id` IN (:items) OR `id` = :owner)"));
     503        defineFilter(classTag, itemType, "memberOf", "(`id` IN (:items) OR `id` = :owner)", filterTemplate);
    453504      }
    454505      else
    455506      {
    456507        log.info("Adding 'memberOf' filter to "+c.getName());
    457         classTag.addContent(createFilterElement("memberOf", "`id` IN (:items)"));
     508        defineFilter(classTag, itemType, "memberOf", "`id` IN (:items)", filterTemplate);
    458509      }
    459510      if (ShareableData.class.isAssignableFrom(c))
    460511      {
    461512        log.info("Adding 'sharedTo' filter to "+c.getName());
    462         classTag.addContent(createFilterElement("sharedTo", ":owner != `owner` AND `itemkey_id` IN (:itemKeys)"));
     513        defineFilter(classTag, itemType, "sharedTo", ":owner != `owner` AND `itemkey_id` IN (:itemKeys)", filterTemplate);
    463514 
    464515        log.info("Adding 'inProject' filter to "+c.getName());
    465         classTag.addContent(createFilterElement("inProject", "`projectkey_id` IN (:projectKeys)"));
     516        defineFilter(classTag, itemType, "inProject", "`projectkey_id` IN (:projectKeys)", filterTemplate);
    466517 
    467518        log.info("Adding 'ownedByOrSharedTo' filter to "+c.getName());
    468         classTag.addContent(createFilterElement("ownedByOrSharedTo", "(:owner = `owner` OR `itemkey_id` IN (:itemKeys))"));
     519        defineFilter(classTag, itemType, "ownedByOrSharedTo", "(:owner = `owner` OR `itemkey_id` IN (:itemKeys))", filterTemplate);
    469520 
    470521        log.info("Adding 'ownedByOrInProject' filter to "+c.getName());
    471         classTag.addContent(createFilterElement("ownedByOrInProject",
    472             "(:owner = `owner` OR `projectkey_id` IN (:projectKeys))"));
     522        defineFilter(classTag, itemType, "ownedByOrInProject",
     523            "(:owner = `owner` OR `projectkey_id` IN (:projectKeys))", filterTemplate);
    473524 
    474525        log.info("Adding 'sharedToOrInProject' filter to "+c.getName());
    475         classTag.addContent(createFilterElement("sharedToOrInProject",
    476             "((:owner != `owner` AND `itemkey_id` IN (:itemKeys)) OR `projectkey_id` IN (:projectKeys))"));
     526        defineFilter(classTag, itemType, "sharedToOrInProject",
     527            "((:owner != `owner` AND `itemkey_id` IN (:itemKeys)) OR `projectkey_id` IN (:projectKeys))", filterTemplate);
    477528 
    478529        log.info("Adding 'ownedByOrSharedToOrInProject' filter to "+c.getName());
    479         classTag.addContent(createFilterElement("ownedByOrSharedToOrInProject",
    480             "(:owner = `owner` OR `itemkey_id` IN (:itemKeys) OR `projectkey_id` IN (:projectKeys))"));
     530        defineFilter(classTag, itemType, "ownedByOrSharedToOrInProject",
     531            "(:owner = `owner` OR `itemkey_id` IN (:itemKeys) OR `projectkey_id` IN (:projectKeys))", filterTemplate);
    481532      }
    482533    }
     
    488539   
    489540  /**
    490     Create a &lt;filter&gt; tag using the given name and condition.
    491     @since 2.17
    492   */
    493   private static Element createFilterElement(String name, String condition)
    494   {
     541    Define a filter for on the given class.
     542    @since 3.6
     543  */
     544  private static void defineFilter(Element classTag, Item itemType, String name, String condition, Map<String, Element> filterTemplate)
     545  {
     546    // Load the template
     547    Element filterSource = filterTemplate.get(name);
     548    if (filterSource == null) return;
     549
     550    // Define the filter by cloning the template onto the
     551    // root element and set the name including the item type.
     552    Element filterDef = filterSource.clone();
     553    filterDef.setAttribute("name", name + itemType.name());
     554    classTag.getDocument().getRootElement().addContent(filterDef);
     555
     556    // Second part of the filter definition goes inside the
     557    // class tag
    495558    Element element = new Element("filter");
    496     element.setAttribute("name", name);
     559    element.setAttribute("name", name + itemType.name());
    497560    element.setAttribute("condition", condition);
    498     return element;
     561    classTag.addContent(element);
     562   
     563    System.out.println("Adding filter def: " + filterDef.getAttributeValue("name") + " to " + classTag.getAttributeValue("name"));
     564   
    499565  }
    500566 
  • trunk/src/core/net/sf/basedb/core/QueryRuntimeFilterManager.java

    r5818 r6934  
    4949  private final org.hibernate.Session session;
    5050
     51  private final Item itemType;
     52 
    5153  /**
    5254    Create a new manager for the <code>DbControl</code>.
     55    The manager will only manage filters for queries returning
     56    item of the given item type.
    5357  */
    54   QueryRuntimeFilterManager(DbControl dc)
     58  QueryRuntimeFilterManager(DbControl dc, Item itemType)
    5559  {
    5660    this.enabledFilters = new HashSet<String>();
    5761    this.session = dc.getHibernateSession();
     62    this.itemType = itemType;
    5863  }
    5964 
     
    6772  {
    6873    org.hibernate.Filter filter = null;
    69     if (!enabledFilters.contains(filterName))
     74    String name = filterName + itemType.name();
     75    if (!enabledFilters.contains(name))
    7076    {
    71       filter = HibernateUtil.enableFilter(session, filterName);
    72       enabledFilters.add(filterName);
     77      filter = HibernateUtil.enableFilter(session, name);
     78      enabledFilters.add(name);
    7379    }
    7480    return filter;
     
    8187  void disableFilter(String filterName)
    8288  {
    83     if (enabledFilters.contains(filterName))
     89    String name = filterName + itemType.name();
     90    if (enabledFilters.contains(name))
    8491    {
    85       HibernateUtil.disableFilter(session, filterName);
    86       enabledFilters.remove(filterName);
     92      HibernateUtil.disableFilter(session, name);
     93      enabledFilters.remove(name);
    8794    }
    8895  }
Note: See TracChangeset for help on using the changeset viewer.