Changeset 6770


Ignore:
Timestamp:
Mar 13, 2015, 1:48:44 PM (7 years ago)
Author:
Nicklas Nordborg
Message:

References #1325: Lists of items

Re-factored the syn with filter implementation. Each item list can now have multiple "Synchronization filters". This is now it's own item (Item.SYNCFILTER) which is a child item to item an item list.

Each filter have settings for the relation to the type of items it filters on (eg. parent or child items).

The ListableChildItems and ListableParentItems annotations was added to make it possible to annotate a class which parent and child item types it can navigate to.

The GUI has been updated to make it possible to create and specify filters for a list, but all synchonrization code has been temporarily removed since it no longer works.

Location:
trunk
Files:
9 added
19 edited

Legend:

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

    r6127 r6770  
    4141  @base.modified $Date$
    4242*/
     43@ListableChildItems({Item.SAMPLE, Item.EXTRACT, Item.PHYSICALBIOASSAY, Item.DERIVEDBIOASSAY, Item.RAWBIOASSAY})
    4344public class BioSource
    4445  extends BioMaterial<BioSourceData>
  • trunk/src/core/net/sf/basedb/core/DerivedBioAssay.java

    r6738 r6770  
    5353  @base.modified $Date$
    5454*/
     55@ListableParentItems({Item.DERIVEDBIOASSAY, Item.PHYSICALBIOASSAY, Item.EXTRACT, Item.SAMPLE, Item.BIOSOURCE})
     56@ListableChildItems({Item.DERIVEDBIOASSAY, Item.RAWBIOASSAY})
    5557public class DerivedBioAssay
    5658  extends AnnotatedItem<DerivedBioAssayData>
  • trunk/src/core/net/sf/basedb/core/Extract.java

    r6383 r6770  
    4040  @base.modified $Date$
    4141*/
     42@ListableParentItems({Item.EXTRACT, Item.SAMPLE, Item.BIOSOURCE})
     43@ListableChildItems({Item.EXTRACT, Item.PHYSICALBIOASSAY, Item.DERIVEDBIOASSAY, Item.RAWBIOASSAY})
    4244public class Extract
    4345  extends MeasuredBioMaterial<ExtractData>
  • trunk/src/core/net/sf/basedb/core/File.java

    r6738 r6770  
    8080public class File
    8181  extends CommonItem<FileData>
    82   implements Transactional, DiskConsumable, Subtypable, Listable
     82  implements Transactional, DiskConsumable, Subtypable
    8383{
    8484  /**
  • trunk/src/core/net/sf/basedb/core/Item.java

    r6758 r6770  
    225225  ITEMLIST(209, "Item list", "ils", ItemList.class, ItemListData.class, DefinedPermissions.shareable,
    226226      11),
     227  /**
     228    The item is a {@link SyncFilter}
     229  */
     230  SYNCFILTER(148, "Sync filter", "sfl", SyncFilter.class, ItemListSyncFilterData.class, null,
     231      12),
    227232
    228233  /**
  • trunk/src/core/net/sf/basedb/core/ItemContext.java

    r6768 r6770  
    247247  /**
    248248    Initialize the context from an item list synchronization filter.
     249    Note that this creates a special context used for implementing
     250    the query functionality of a {@link SyncFilter}. It should
     251    not be used for representing context in a GUI. To do this start
     252    with a regular context and the use {@link #copyFromSyncFilter(ItemListSyncFilterData)}
     253    instead.
    249254    @since 3.5
    250255  */
     
    254259    this.subContext = null;
    255260    this.name = null;
    256     this.include = Include.fromInt(syncFilter.getInclude());
    257261    this.noPaging = true;
    258     initPropertyFilters(syncFilter.getPropertyFilters());
     262    copyFromSyncFilter(syncFilter);
    259263  }
    260264 
     
    298302    @since 3.5
    299303  */
    300   ItemListSyncFilterData asItemListSyncFilter()
    301   {
    302     ItemListSyncFilterData syncFilter = new ItemListSyncFilterData();
     304  void copyToSyncFilter(ItemListSyncFilterData syncFilter)
     305  {
     306    syncFilter.setSourceItemType(getItemType().getValue());
    303307    if (include != null) syncFilter.setInclude(Include.toInt(include));
     308    syncFilter.getPropertyFilters().clear();
    304309    if (propertyFilters != null)
    305310    {
    306311      storePropertyFilters(syncFilter.getPropertyFilters());
    307312    }
    308     return syncFilter;
     313  }
     314 
     315  void copyFromSyncFilter(ItemListSyncFilterData syncFilter)
     316  {
     317    this.numFilterRows = 1;
     318    this.include = Include.fromInt(syncFilter.getInclude());
     319    if (propertyFilters != null) propertyFilters.clear();
     320    initPropertyFilters(syncFilter.getPropertyFilters());
    309321  }
    310322 
     
    336348    for (Map.Entry<String, PropertyFilterData> entry : filterData.entrySet())
    337349    {
    338       // The property can string can actually be <property>[filterrow]
    339       // So we need to split and parse in that case
    340       // properties without [filterrow] belong to row 0.
    341       // The largest value for filterrow becomes the 'numFilterRows' value
    342       String property = entry.getKey();
    343       int rowIndex = 0;
    344       if (property.endsWith("]"))
    345       {
    346         int split = property.lastIndexOf('[');
    347         rowIndex = Integer.parseInt(property.substring(split+1, property.length()-1));
    348         property = property.substring(0, split);
    349       }
    350       if (rowIndex >= numFilterRows) numFilterRows = rowIndex+1;
    351       setPropertyFilter(new PropertyFilter(property, rowIndex, entry.getValue()));
     350      PropertyFilter pf = PropertyFilter.create(entry.getKey(), entry.getValue());
     351      if (pf.getRowIndex() >= numFilterRows)
     352      {
     353        numFilterRows = pf.getRowIndex()+1;
     354      }
     355      setPropertyFilter(pf);
    352356    }
    353357  }
  • trunk/src/core/net/sf/basedb/core/ItemList.java

    r6768 r6770  
    3434
    3535import net.sf.basedb.core.query.Hql;
     36import net.sf.basedb.core.SyncFilter.SourceItemTransform;
     37import net.sf.basedb.core.data.ItemListData;
    3638import net.sf.basedb.core.data.ItemListSyncFilterData;
    37 import net.sf.basedb.core.data.ItemListData;
    3839
    3940/**
     
    892893 
    893894  /**
    894     Is this item list backed by a synchronization filter or not?
    895   */
    896   public boolean hasSyncFilter()
    897   {
    898     return getData().getSyncFilter() != null;
    899   }
    900 
    901   /**
    902895    Get the last sync date+time. Note that manual changes may have been made to
    903896    the list after this date.
     
    909902 
    910903  /**
    911     Get information about the synchronization filter that is backing
    912     this list.
    913     @return A SyncFilter object or null
    914   */
    915   public SyncFilter getSyncFilter()
    916   {
    917     ItemListSyncFilterData syncFilter = getData().getSyncFilter();
    918     if (syncFilter == null) return null;
    919     return new SyncFilter(getMemberType(), syncFilter);
    920   }
    921  
    922   /**
    923     Apply a synchronization filter to this list. If this list already has
    924     synchronization filter it is replaced. The filter is stored
    925    
    926     @param dc
    927     @param syncContext An ItemContext providing the filter
    928     @param syncOptions Options for how to sync with existing members of this list
    929     @return The number of members in the list after applying the filter
    930   */
    931   public int applySyncFilter(DbControl dc, ItemContext syncContext, SynchronizeOption syncOptions)
    932   {
    933     checkPermission(Permission.WRITE);
    934     checkMemberType(syncContext.getItemType());
    935    
    936     ItemListData data = getData();
    937     org.hibernate.Session session = dc.getHibernateSession();
    938    
    939     // Switch the filter
    940     ItemListSyncFilterData oldFilter = data.getSyncFilter();
    941     if (oldFilter != null) session.delete(oldFilter);
    942     ItemListSyncFilterData newFilter = syncContext.asItemListSyncFilter();
    943     session.save(newFilter);
    944     data.setSyncFilter(newFilter);
    945    
    946     return resyncFilter(dc, syncOptions);
     904    Get a query returning all synchronization filters
     905    for this list
     906    @return An {@link ItemQuery} object
     907  */
     908  public ItemQuery<SyncFilter> getSyncFilters()
     909  {
     910    return SyncFilter.getQuery(this);
     911  }
     912 
     913  /**
     914    Creates a new sync filter for this list. The sync filter will
     915    start using the same item type as the list member type and
     916    {@link SourceItemTransform#NONE}. Use {@link SyncFilter#setSyncContext(ItemContext, SourceItemTransform)}
     917    to apply different sync filter and options.
     918   
     919  */
     920  public SyncFilter newSyncFilter(DbControl dc)
     921  {
     922    checkPermission(Permission.WRITE);
     923   
     924    SyncFilter sf = dc.newItem(SyncFilter.class);
     925    ItemListSyncFilterData sfData = sf.getData();
     926    sf.setName("New sync filter");
     927    sfData.setItemList(getData());
     928    sfData.setSourceItemType(getMemberType().getValue());
     929    sfData.setSourceItemTransform(SourceItemTransform.NONE.ordinal());
     930   
     931    getData().getSyncFilters().add(sfData);
     932    return sf;
    947933  }
    948934 
     
    952938    @return The number of members in the list after applying the filter
    953939  */
     940  /*
    954941  public int resyncFilter(DbControl dc, SynchronizeOption syncOptions)
    955942  {
    956943    checkPermission(Permission.WRITE);
    957     ItemListSyncFilterData syncFilter = getData().getSyncFilter();
    958     if (syncFilter == null) return getSize();
     944    Set<ItemListSyncFilterData> syncFilters = getData().getSyncFilters();
     945    if (syncFilters == null || syncFilters.size() == 0) return getSize();
    959946   
    960947    // Create filter query
    961     ItemQuery<? extends Listable> query = getAllItems();
    962     ItemContext syncContext = new ItemContext(getMemberType(), syncFilter);
    963     syncContext.configureQuery(dc, query, true);
    964    
    965     // Load all matching items and save their id:s
    966     Set<Integer> matching = new HashSet<Integer>();
    967     Iterator<? extends Listable> it = query.iterate(dc);
    968     while (it.hasNext())
    969     {
    970       matching.add(it.next().getId());
     948    Set<Integer> intersection = null;
     949    for (ItemListSyncFilterData sf : syncFilters)
     950    {
     951      ItemQuery<? extends Listable> query = getAllItems();
     952      ItemContext syncContext = new ItemContext(getMemberType(), sf);
     953      syncContext.configureQuery(dc, query, true);
     954
     955      // Load all matching items and save their id:s
     956      Set<Integer> matching = new HashSet<Integer>();
     957      Iterator<? extends Listable> it = query.iterate(dc);
     958      while (it.hasNext())
     959      {
     960        matching.add(it.next().getId());
     961      }
     962      sf.setMatching(matching.size());
     963      if (intersection == null)
     964      {
     965        intersection = matching;
     966      }
     967      else
     968      {
     969        intersection.retainAll(matching);
     970      }
    971971    }
    972972 
    973973    Set<Integer> members = getData().getMembers();
    974     syncOptions.synchronize(members, matching);
     974    syncOptions.synchronize(members, intersection);
    975975   
    976976    getData().setSyncDate(new Date());
     
    978978    return members.size();
    979979  }
     980  */
    980981 
    981982 
  • trunk/src/core/net/sf/basedb/core/PhysicalBioAssay.java

    r6738 r6770  
    4343  @base.modified $Date$
    4444*/
     45@ListableParentItems({Item.EXTRACT, Item.SAMPLE, Item.BIOSOURCE})
     46@ListableChildItems({Item.DERIVEDBIOASSAY, Item.RAWBIOASSAY})
    4547public class PhysicalBioAssay
    4648  extends AnnotatedItem<PhysicalBioAssayData>
  • trunk/src/core/net/sf/basedb/core/PropertyFilter.java

    r6756 r6770  
    5959{
    6060
     61  /**
     62    Create a property filter instance from what has been saved in the database.
     63    Basically, we need to strip the [filterrow] if it is set.
     64    @since 3.5
     65  */
     66  static PropertyFilter create(String propertyFromDb, PropertyFilterData data)
     67  {
     68    int rowIndex = 0;
     69    // The property can string can actually be <property>[filterrow]
     70    // So we need to split and parse in that case
     71    // properties without [filterrow] belong to row 0.
     72    // The largest value for filterrow becomes the 'numFilterRows' value
     73    if (propertyFromDb.endsWith("]"))
     74    {
     75      int split = propertyFromDb.lastIndexOf('[');
     76      rowIndex = Integer.parseInt(propertyFromDb.substring(split+1, propertyFromDb.length()-1));
     77      propertyFromDb = propertyFromDb.substring(0, split);
     78    }
     79    return new PropertyFilter(propertyFromDb, rowIndex, data);
     80  }
     81 
    6182  /**
    6283    The maximum allowed length of a filter value.
  • trunk/src/core/net/sf/basedb/core/RawBioAssay.java

    r6738 r6770  
    6363  @base.modified $Date$
    6464*/
     65@ListableParentItems({Item.DERIVEDBIOASSAY, Item.PHYSICALBIOASSAY, Item.EXTRACT, Item.SAMPLE, Item.BIOSOURCE})
    6566public class RawBioAssay
    6667  extends AnnotatedItem<RawBioAssayData>
  • trunk/src/core/net/sf/basedb/core/Sample.java

    r6127 r6770  
    4141  @base.modified $Date$
    4242*/
     43@ListableParentItems({Item.SAMPLE, Item.BIOSOURCE})
     44@ListableChildItems({Item.SAMPLE, Item.EXTRACT, Item.PHYSICALBIOASSAY, Item.DERIVEDBIOASSAY, Item.RAWBIOASSAY})
    4345public class Sample
    4446  extends MeasuredBioMaterial<SampleData>
  • trunk/src/core/net/sf/basedb/core/SyncFilter.java

    r6768 r6770  
    2222package net.sf.basedb.core;
    2323
     24import java.util.ArrayList;
    2425import java.util.Collection;
     26import java.util.List;
     27import java.util.Map;
    2528
    2629import net.sf.basedb.core.data.ItemListSyncFilterData;
     30import net.sf.basedb.core.data.PropertyFilterData;
     31import net.sf.basedb.core.data.SharedData;
     32import net.sf.basedb.core.query.Hql;
     33import net.sf.basedb.core.query.Restrictions;
     34import net.sf.basedb.util.listable.ListableUtil;
    2735
    2836/**
    2937  Holds information about a synchronization filter used
    3038  by an item list.
    31   @author nicklas
     39  @author Nicklas
    3240  @since 3.5
    3341*/
    34 public class SyncFilter
     42public class SyncFilter
     43  extends ChildItem<ItemListSyncFilterData>
     44  implements Nameable
    3545{
    3646
    37   private final ItemContext syncContext;
    38  
    39   SyncFilter(Item memberType, ItemListSyncFilterData syncFilter)
    40   {
    41     syncContext = new ItemContext(memberType, syncFilter);
     47  /**
     48    The type of item represented by this class.
     49    @see Item#SYNCFILTER
     50    @see #getType()
     51  */
     52  public static final Item TYPE = Item.SYNCFILTER;
     53
     54  /**
     55    Get a <code>SyncFilter</code> item when you know the id.
     56 
     57    @param dc The <code>DbControl</code> which will be used for
     58      permission checking and database access.
     59    @param id The id of the item to load
     60    @return The <code>SyncFilter</code> item
     61    @throws ItemNotFoundException If an item with the specified
     62      id is not found
     63    @throws PermissionDeniedException If the logged in user doesn't
     64      have {@link Permission#READ} permission to the item
     65    @throws BaseException If there is another error
     66  */
     67  public static SyncFilter getById(DbControl dc, int id)
     68    throws ItemNotFoundException, PermissionDeniedException, BaseException
     69  {
     70    SyncFilter sf = dc.loadItem(SyncFilter.class, id);
     71    if (sf == null) throw new ItemNotFoundException("SyncFilter[id="+id+"]");
     72    return sf;
     73  }
     74 
     75  /**
     76    Get a query configured to retrieve
     77    sync filters for the specified item list.
     78   
     79    @param list The item list, null is not allowed
     80    @return An {@link ItemQuery} object
     81  */
     82  public static ItemQuery<SyncFilter> getQuery(ItemList list)
     83  {
     84    if (list == null) throw new InvalidUseOfNullException("list");
     85    ItemQuery<SyncFilter> query = new ItemQuery<SyncFilter>(SyncFilter.class, null);
     86    query.restrictPermanent(
     87      Restrictions.eq(
     88        Hql.property("itemList"),
     89        Hql.entity(list)
     90      )
     91    );
     92    return query;
     93  }
     94
     95 
     96  private Item listMemberType;
     97  private List<PropertyFilter> filters;
     98  private int numFilterRows;
     99 
     100 
     101  SyncFilter(ItemListSyncFilterData syncFilter)
     102  {
     103    super(syncFilter);
     104  }
     105 
     106  /*
     107    From the Identifiable interface
     108    -------------------------------------------
     109  */
     110  @Override
     111  public Item getType()
     112  {
     113    return TYPE;
     114  }
     115  // -------------------------------------------
     116  /*
     117    From the ChildItem class
     118    -------------------------------------------
     119  */
     120  @Override
     121  SharedData getSharedParent()
     122  {
     123    return getData().getItemList();
     124  }
     125  // -------------------------------------------
     126
     127  /*
     128    From the Nameable interface
     129    -------------------------------------------
     130  */
     131  @Override
     132  public String getName()
     133  {
     134    return getData().getName();
     135  }
     136  @Override
     137  public void setName(String name)
     138    throws PermissionDeniedException, InvalidDataException
     139  {
     140    checkPermission(Permission.WRITE);
     141    NameableUtil.setName(getData(), name);
     142  }
     143  @Override
     144  public String getDescription()
     145  {
     146    return getData().getDescription();
     147  }
     148  @Override
     149  public void setDescription(String description)
     150    throws PermissionDeniedException, InvalidDataException
     151  {
     152    checkPermission(Permission.WRITE);
     153    NameableUtil.setDescription(getData(), description);
     154  }
     155  // -------------------------------------------
     156
     157  /**
     158    Get the item list this filter belongs to.
     159    @return The <code>SyncFilter</code> item
     160    @throws PermissionDeniedException If the logged in user doesn't have
     161      {@link Permission#READ} permission
     162    @throws BaseException If there is another error
     163  */
     164  public ItemList getItemList()
     165    throws PermissionDeniedException, BaseException
     166  {
     167    return getDbControl().getItem(ItemList.class, getData().getItemList());
     168  }
     169 
     170  /**
     171    Copy filters and other settings from the given context
     172    to this synchronization filter. This changes
     173    the source item type ({@link #getSourceItemType()}),
     174    transform ({@link #getSourceItemTransformation()})
     175    and replaces all existing filters with the filters from the
     176    item context.
     177  */
     178  public void setSyncContext(ItemContext syncContext, SourceItemTransform transform)
     179  {
     180    checkPermission(Permission.WRITE);
     181    if (syncContext == null) throw new InvalidUseOfNullException("context");
     182    if (transform == null) throw new InvalidUseOfNullException("transform");
     183   
     184    List<Item> allowedSourceItems = ListableUtil.getListableItems(getListMemberType(), transform);
     185    if (!allowedSourceItems.contains(syncContext.getItemType()))
     186    {
     187      throw new InvalidDataException("Sync context is not found among allowed source items " + allowedSourceItems);
     188    }
     189    syncContext.copyToSyncFilter(getData());
     190    getData().setSourceItemTransform(transform.ordinal());
     191    initFilters();
     192  }
     193 
     194  /**
     195    Copy the filter settings in this synchronization filter to
     196    the given item context. All filter settings in the item
     197    context are replaced with this filter.
     198    The context must be for the same item type as the source item
     199    type of this filter.
     200  */
     201  public void copyToContext(ItemContext context)
     202  {
     203    if (context == null) throw new InvalidUseOfNullException("context");
     204    if (context.getItemType() != getSourceItemType())
     205    {
     206      throw new InvalidDataException("Incompatible item types: " + context.getItemType().name() + " != " + getSourceItemType().name());
     207    }
     208    context.copyFromSyncFilter(getData());
     209  }
     210
     211  /**
     212    Get the source item type that this synchronization filter applies to.
     213    This may or may not be the same item type as the member type of the
     214    list. If this type is different from the list member type an item
     215    transformation is required, but a transformation can also be used
     216    for items of the same type.
     217  */
     218  public Item getSourceItemType()
     219  {
     220    return Item.fromValue(getData().getSourceItemType());
     221  }
     222
     223  /**
     224    Get the transformation to use for converting the items matching
     225    this filter to list members.
     226  */
     227  public SourceItemTransform getSourceItemTransformation()
     228  {
     229    return SourceItemTransform.values()[getData().getSourceItemTransform()];
     230  }
     231 
     232  /**
     233    Get the number of items that matched this particular filter during the last
     234    synchronization. See {@link ItemList#getSyncDate()}.
     235  */
     236  public int getMatchingItems()
     237  {
     238    return getData().getMatching();
    42239  }
    43240 
     
    47244  public int getFilterRows()
    48245  {
    49     return syncContext.getFilterRows();
     246    if (filters == null) initFilters();
     247    return numFilterRows;
    50248  }
    51249 
     
    56254  public Collection<PropertyFilter> getPropertyFilters(int filterRow)
    57255  {
    58     return syncContext.getPropertyFilters(filterRow);
    59   }
    60  
    61  
     256    if (filters == null) initFilters();
     257    List<PropertyFilter> tmp = new ArrayList<PropertyFilter>(filters.size());
     258    for (PropertyFilter f : filters)
     259    {
     260      if (f.getRowIndex() == filterRow)
     261      {
     262        tmp.add(f);
     263      }
     264    }
     265    return tmp;
     266  }
     267
     268  private void initFilters()
     269  {
     270    numFilterRows = 0;
     271    filters = new ArrayList<PropertyFilter>();
     272    for (Map.Entry<String, PropertyFilterData> entry : getData().getPropertyFilters().entrySet())
     273    {
     274      PropertyFilter pf = PropertyFilter.create(entry.getKey(), entry.getValue());
     275      if (pf.getRowIndex() >= numFilterRows)
     276      {
     277        numFilterRows = pf.getRowIndex()+1;
     278      }
     279      filters.add(pf);
     280    }
     281  }
     282
     283  private Item getListMemberType()
     284  {
     285    if (listMemberType == null)
     286    {
     287      listMemberType = Item.fromValue(getData().getItemList().getMemberType());
     288    }
     289    return listMemberType;
     290  }
     291 
     292  public enum SourceItemTransform
     293  {
     294    /**
     295      No transformation of source items is done. The items matching the filter
     296      will become members of the item list.
     297    */
     298    NONE,
     299   
     300    /**
     301      Source items are transformed to child items. Items matching the filter
     302      will have their child items looked up which will become members of the
     303      list.
     304    */
     305    PARENT_TO_CHILD,
     306   
     307    /**
     308      Source items are transformed to parent items. Items matching the filter
     309      will have their parent items looked up which will become members of
     310      the list.
     311    */
     312    CHILD_TO_PARENT;
     313  }
    62314}
  • trunk/src/core/net/sf/basedb/core/data/ItemListData.java

    r6768 r6770  
    108108    this.rawDataType = rawDataType;
    109109  }
    110 
    111110 
    112111  private int size;
     
    156155  }
    157156 
    158   private ItemListSyncFilterData syncFilter;
     157  private Set<ItemListSyncFilterData> syncFilters;
    159158  /**
    160     Get the filter context that was used to create this item list. This can
    161     be used to update members in the item list.
    162     @hibernate.many-to-one column="`syncfilter_id`" not-null="false" outer-join="false"
     159    This is the inverse end.
     160    @see ItemListSyncFilterData#getItemList()
     161    @hibernate.set lazy="true" inverse="true" cascade="delete"
     162    @hibernate.collection-key column="`itemlist_id`"
     163    @hibernate.collection-one-to-many class="net.sf.basedb.core.data.ItemListSyncFilterData"
    163164  */
    164   public ItemListSyncFilterData getSyncFilter()
     165  public Set<ItemListSyncFilterData> getSyncFilters()
    165166  {
    166     return syncFilter;
    167   }
    168   public void setSyncFilter(ItemListSyncFilterData syncFilter)
    169   {
    170     this.syncFilter = syncFilter;
     167    if (syncFilters == null) syncFilters = new HashSet<ItemListSyncFilterData>();
     168    return syncFilters;
    171169  }
    172170 
     171  void setSyncFilters(Set<ItemListSyncFilterData> syncFilters)
     172  {
     173    this.syncFilters = syncFilters;
     174  }
     175
     176 
    173177}
  • trunk/src/core/net/sf/basedb/core/data/ItemListSyncFilterData.java

    r6768 r6770  
    3535public class ItemListSyncFilterData
    3636  extends BasicData
     37  implements NameableData
    3738{
     39 
    3840  public ItemListSyncFilterData()
    3941  {}
     42
     43  /*
     44    From the NameableData interface
     45    -------------------------------------------
     46  */
     47  private String name;
     48  @Override
     49  public String getName()
     50  {
     51    return name;
     52  }
     53  @Override
     54  public void setName(String name)
     55  {
     56    this.name = name;
     57  }
     58  private String description;
     59  @Override
     60  public String getDescription()
     61  {
     62    return description;
     63  }
     64  @Override
     65  public void setDescription(String description)
     66  {
     67    this.description = description;
     68  }
     69  // -------------------------------------------
     70 
     71  private ItemListData itemList;
     72  /**
     73    Get the item list this sync filter belongs to.
     74    @hibernate.many-to-one column="`itemlist_id`" not-null="true" outer-join="false" update="false"
     75  */
     76  public ItemListData getItemList()
     77  {
     78    return itemList;
     79  }
     80  public void setItemList(ItemListData itemList)
     81  {
     82    this.itemList = itemList;
     83  }
     84
     85  private int sourceItemType;
     86  /**
     87    Get the type of items that this filter is applies to.
     88    @hibernate.property column="`source_type`" type="int" not-null="true"
     89  */
     90  public int getSourceItemType()
     91  {
     92    return sourceItemType;
     93  }
     94  public void setSourceItemType(int sourceItemType)
     95  {
     96    this.sourceItemType = sourceItemType;
     97  }
     98 
     99  private int sourceItemTransform;
     100  /**
     101    The transform to use for converting filter matches to list members.
     102    0 = none; 1 = parent to child, 2 = child to parent
     103    @hibernate.property column="`source_transform`" type="int" not-null="true"
     104  */
     105  public int getSourceItemTransform()
     106  {
     107    return sourceItemTransform;
     108  }
     109  public void setSourceItemTransform(int sourceItemTransform)
     110  {
     111    this.sourceItemTransform = sourceItemTransform;
     112  }
     113 
     114  private int matching;
     115  /**
     116    The number of matching items during that last sync.
     117    @hibernate.property column="`matching`" type="int" not-null="true"
     118  */
     119  public int getMatching()
     120  {
     121    return matching;
     122  }
     123  public void setMatching(int matching)
     124  {
     125    this.matching = matching;
     126  }
    40127
    41128  private int include;
    42129  /**
    43130    Flags for specifying include options to an entity query.
    44     @hibernate.property column="`include`" type="int"
     131    @hibernate.property column="`include`" type="int" not-null="true"
    45132  */
    46133  public int getInclude()
  • trunk/www/include/scripts/main-2.js

    r6754 r6770  
    19701970    controllers['HELP'] = { url:'admin/clients/help/index.jsp', width:600, height:400, noAnyToAny:true };
    19711971    controllers['ITEMLIST'] = { url:'views/itemlists/index.jsp', width:750, height:500 };
     1972    controllers['SYNCFILTER'] = { url:'views/itemlists/syncfilter/index.jsp', width:750, height:500, popup:true, noAnyToAny:true };
    19721973    controllers['ITEMSUBTYPE'] = { url:'admin/itemsubtypes/index.jsp', width:690, height:460 };
    19731974    controllers['JOB'] = { url:'views/jobs/index.jsp', width:750, height:500, popup:true, edit:false };
  • trunk/www/include/scripts/table.js

    r6699 r6770  
    842842   
    843843    var remaining = selected.length-1;
     844    if (notifyTarget)
     845    {
     846      Events.sendCustomEvent(notifyTarget, 'base-selected-start', { 'numSelected': selected.length });
     847    }
    844848    for (var i = 0; i < selected.length; i++)
    845849    {
  • trunk/www/views/itemlists/index.jsp

    r6768 r6770  
    3434  import="net.sf.basedb.core.Permission"
    3535  import="net.sf.basedb.core.ItemContext"
     36  import="net.sf.basedb.core.SyncFilter"
     37  import="net.sf.basedb.core.SyncFilter.SourceItemTransform"
    3638  import="net.sf.basedb.core.ItemResultIterator"
    3739  import="net.sf.basedb.core.ItemQuery"
     
    197199            query.setFirstResult(0);
    198200            query.setMaxResults(-1);
     201            if (useSyncFilter)
     202            {
     203              SyncFilter sf = list.newSyncFilter(dc);
     204              sf.setName("Origin");
     205              sf.setSyncContext(filterContext, SourceItemTransform.NONE);
     206              dc.saveItem(sf);
     207            }
    199208          }
    200209          else if ("selected".equals(source))
     
    213222          // else -- no modifications to the query mean that we only get the current page
    214223         
    215           int numAdded = useSyncFilter ? list.applySyncFilter(dc, filterContext, ItemList.SynchronizeOption.ADD_ONLY) : list.add(query.iterate(dc));
     224          if (!useSyncFilter) list.add(query.iterate(dc));
    216225        }
    217226       
     
    235244    }
    236245  }
     246  /*
    237247  else if ("ReSyncFilter".equals(cmd))
    238248  {
     
    243253    forward = viewPage;
    244254  }
     255  */
    245256  else if ("DeleteItem".equals(cmd))
    246257  {
  • trunk/www/views/itemlists/lists.js

    r6768 r6770  
    8888      Buttons.addClickHandler('btnMergeComplement', lists.mergeOnClick);
    8989     
     90      Buttons.addClickHandler('btnAddSyncFilter', Buttons.newItem);
     91      Buttons.addClickHandler('btnRemoveSyncFilter', lists.removeSyncFilterOnClick);
     92     
    9093      TabControl.addTabActivateListener('main.annotations', AnnotationsList.loadOnce);
    9194      TabControl.addTabActivateListener('main.members', lists.viewMembers);
     
    142145  }
    143146
     147  lists.removeSyncFilterOnClick = function()
     148  {
     149    var tableDiv = Doc.element('tbl.syncFilters');
     150    var numSelected = Table.checkIfSelected(tableDiv);
     151    if (numSelected == 0) return;
     152   
     153    if (!confirm('You are about to remove '+numSelected+' filters. Continue?'))
     154    {
     155      return;
     156    }
     157    Table.submitToPopup(tableDiv, 'DeleteItems', 300, 200);
     158  }
     159 
    144160  lists.validateList = function()
    145161  {
  • trunk/www/views/itemlists/view_list.jsp

    r6769 r6770  
    3636  import="net.sf.basedb.core.ItemList"
    3737  import="net.sf.basedb.core.SyncFilter"
     38  import="net.sf.basedb.core.SyncFilter.SourceItemTransform"
     39  import="net.sf.basedb.core.PropertyFilter"
    3840  import="net.sf.basedb.core.MultiPermissions"
    3941  import="net.sf.basedb.core.User"
     
    6163  import="java.util.Map"
    6264  import="java.util.Set"
     65  import="java.util.List"
    6366  import="java.util.Date"
    6467%>
     
    100103  JspContext jspContext = ExtensionsControl.createContext(dc, pageContext, guiContext, list);
    101104  ExtensionsInvoker invoker = ToolbarUtil.useExtensions(jspContext);
     105 
     106  ItemQuery<SyncFilter> sfQuery = list.getSyncFilters();
     107  sfQuery.order(Orders.asc(Hql.property("sourceItemTransform")));
     108  sfQuery.order(Orders.asc(Hql.property("sourceItemType")));
     109  sfQuery.order(Orders.asc(Hql.property("name")));
     110  List<SyncFilter> syncFilters = sfQuery.list(dc);
    102111  %>
    103112  <base:page title="<%=title%>" id="view-page">
     
    268277        <td><%=list.getSize()%></td>
    269278      </tr>
    270       <tr style="vertical-align: top;">
    271         <th>Sync filter</th>
    272         <td>
    273           <%
    274           if (list.hasSyncFilter())
    275           {
    276             SyncFilter syncFilter = list.getSyncFilter();
    277             StringBuilder sb = new StringBuilder();
    278             for (int filterRow = 0; filterRow < syncFilter.getFilterRows(); filterRow++)
     279      <tr>
     280        <th>External ID</th>
     281        <td><%=HTML.encodeTags(list.getExternalId())%></td>
     282      </tr>
     283      <tr>
     284        <th>Owner</th>
     285        <td><base:propertyvalue item="<%=list%>" property="owner"/></td>
     286      </tr>
     287      <tr>
     288        <th>Permissions</th>
     289        <td><%=PermissionUtil.getFullPermissionNames(list)%></td>
     290      </tr>
     291      <tr>
     292        <th>Description</th>
     293        <td><%=HTML.niceFormat(list.getDescription())%></td>
     294      </tr>
     295      </table>
     296      </div>
     297     
     298      <base:section
     299        id="syncFilters"
     300        title="<%="Synchronization filters (" + syncFilters.size() +")"%>"
     301        context="<%=cc%>"
     302        >
     303        <tbl:table
     304          id="tbl.syncFilters"
     305          columns="all"
     306          item="SYNCFILTER"
     307          action="syncfilter/index.jsp"
     308          >
     309          <tbl:hidden name="list_id" value="<%=Integer.toString(itemId) %>" />
     310          <tbl:columndef
     311            id="name"
     312            title="Name"
     313          />
     314          <tbl:columndef
     315            id="sourceItems"
     316            title="List members"
     317          />
     318          <tbl:columndef
     319            id="filter"
     320            title="Filter"
     321          />
     322          <tbl:columndef
     323            id="matching"
     324            title="Matching items"
     325          />
     326          <tbl:columndef
     327            id="description"
     328            title="Description"
     329          />
     330          <tbl:toolbar subclass="topborder leftborder rightborder bg-filled-50">
     331            <tbl:button
     332              id="btnAddSyncFilter"
     333              image="add.png"
     334              disabled="<%=!writePermission%>"
     335              tooltip="<%=writePermission ? "Add new filter" : "You do not have permission to modify the filters"%>" 
     336              data-extra-url="<%="&list_id="+itemId%>"
     337              data-item-type="SYNCFILTER"
     338              title="Add filter&hellip;"
     339            />
     340            <tbl:button
     341              id="btnRemoveSyncFilter"
     342              image="delete_permanently.png"
     343              disabled="<%=!writePermission%>"
     344              tooltip="<%=writePermission ? "Remove the selected filters" : "You do not have permission to modify the filters"%>" 
     345              title="Remove&hellip;"
     346            />
     347          </tbl:toolbar>
     348          <tbl:data>
     349            <tbl:headers>
     350              <tbl:headerrow>
     351              <tbl:header subclass="index" />
     352              <tbl:header
     353                subclass="check"
     354                ><base:icon
     355                  id="check.uncheck"
     356                  image="check_uncheck.png"
     357                  tooltip="Check/uncheck all"
     358                /></tbl:header>
     359                <tbl:columnheaders />
     360              </tbl:headerrow>
     361            </tbl:headers>
     362            <tbl:rows>
     363            <%
     364            int index = 0;
     365            Formatter<PropertyFilter> filterFormatter = new PropertyFilterFormatter(dc, dateFormatter);
     366            for (SyncFilter sf : syncFilters)
    279367            {
    280               sb.append(filterRow > 0 ? "\nOR " : "");
    281               sb.append(Values.getString(syncFilter.getPropertyFilters(filterRow), "\n   AND ", true, new PropertyFilterFormatter(dc, dateFormatter)));
     368              index++;
     369              String name = HTML.encodeTags(sf.getName());
     370              int filterId = sf.getId();
     371              SourceItemTransform transform = sf.getSourceItemTransformation();
     372               
     373              StringBuilder sb = new StringBuilder();
     374              for (int filterRow = 0; filterRow < sf.getFilterRows(); filterRow++)
     375              {
     376                sb.append(filterRow > 0 ? "\nOR " : "");
     377                sb.append(Values.getString(sf.getPropertyFilters(filterRow), "\n   AND ", true, filterFormatter));
     378              }
     379              %>
     380              <tbl:row>
     381                <tbl:header
     382                  clazz="index"
     383                  ><%=index%></tbl:header>
     384                <tbl:header
     385                  clazz="check"
     386                  ><input
     387                    type="checkbox"
     388                    name="<%=filterId%>"
     389                    value="<%=filterId%>"
     390                    title="<%=name%>"
     391                  ></tbl:header>
     392                <tbl:cell column="name"><div
     393                  class="link table-item"
     394                  data-item-id="<%=filterId%>"
     395                  data-no-edit="<%=writePermission ? 0 : 1 %>"
     396                  data-extra-url="&list_id=<%=itemId%>"
     397                  tabindex="0"
     398                  title=""><%=name%></div></tbl:cell>
     399                <tbl:cell column="sourceItems">
     400                  <%
     401                  if (transform == SourceItemTransform.NONE)
     402                  {
     403                    %>
     404                    Must match filter
     405                    <%
     406                  }
     407                  else
     408                  {
     409                    %>
     410                    <%=transform == SourceItemTransform.PARENT_TO_CHILD ? "Parent" : "Child" %>
     411                    item of type <i><%=sf.getSourceItemType().toString() %></i> must match filter
     412                    <%
     413                  }
     414                  %>
     415                </tbl:cell>
     416                <tbl:cell column="filter"><pre><%=HTML.encodeTags(sb.toString())%></pre></tbl:cell>
     417                <tbl:cell column="matching"><%=sf.getMatchingItems()%></tbl:cell>
     418                <tbl:cell column="description"><%=HTML.niceFormat(sf.getDescription())%></tbl:cell>
     419              </tbl:row>
     420              <%
     421            }
     422            if (index == 0)
     423            {
     424              %>
     425              <tbl:panel>
     426                There are no synchronization filters for this list.
     427              </tbl:panel>
     428              <%
    282429            }
    283430            %>
    284             Yes (last sync: <%=timeFormatter.format(list.getSyncDate()) %>) [<a href="index.jsp?ID=<%=ID%>&item_id=<%=itemId%>&cmd=ReSyncFilter">Re-sync</a>]<br>
    285             <pre style="margin: 5px;"><%=HTML.encodeTags(sb.toString())%></pre>
    286             <%
    287           }
    288           else
    289           {
    290             %>
    291             No
    292             <%
    293           }
    294           %>
    295         </td>
    296       </tr>
    297       <tr>
    298         <th>External ID</th>
    299         <td><%=HTML.encodeTags(list.getExternalId())%></td>
    300       </tr>
    301       <tr>
    302         <th>Owner</th>
    303         <td><base:propertyvalue item="<%=list%>" property="owner"/></td>
    304       </tr>
    305       <tr>
    306         <th>Permissions</th>
    307         <td><%=PermissionUtil.getFullPermissionNames(list)%></td>
    308       </tr>
    309       <tr>
    310         <th>Description</th>
    311         <td><%=HTML.niceFormat(list.getDescription())%></td>
    312       </tr>
    313       </table>
    314       </div>
     431            </tbl:rows>
     432          </tbl:data>
     433        </tbl:table>
     434     
     435      </base:section>
    315436
    316437      <jsp:include page="../../common/anytoany/list_anytoany.jsp">
Note: See TracChangeset for help on using the changeset viewer.