001package org.biopax.paxtools.query.wrapperL3; 002 003import org.biopax.paxtools.controller.PathAccessor; 004import org.biopax.paxtools.model.BioPAXElement; 005import org.biopax.paxtools.model.level3.Level3Element; 006 007import java.util.*; 008 009/** 010 * This is the base class for filters that are filtering based on values of specific fields of the 011 * objects and their related objects. 012 * 013 * @author Ozgun Babur 014 */ 015public abstract class StringFieldFilter extends Filter 016{ 017 /** 018 * Accessors and their applicable classes. 019 */ 020 Map<PathAccessor, Class<? extends BioPAXElement>> accessors; 021 022 /** 023 * Set of valid values (case insensitive), for filtering. 024 */ 025 Set<String> validValues; 026 027 /** 028 * Option to accept objects if the field is empty or null. 029 */ 030 protected boolean emptyOK; 031 032 /** 033 * Constructor. 034 * 035 * @param emptyOK whether to always accept empty field when traversing the graph or reject 036 * @param valid filter values (strings' capitalization does not matter) 037 */ 038 protected StringFieldFilter(boolean emptyOK, String[] valid) 039 { 040 setEmptyOK(emptyOK); 041 accessors = new HashMap<PathAccessor, Class<? extends BioPAXElement>>(); 042 043 if(valid == null || valid.length == 0) { 044 validValues = Collections.EMPTY_SET; 045 } else { 046 validValues = new HashSet<String>(); 047 //copy all the filter values, making them lower-case (will then match ignoring case) 048 for(String val : valid) 049 if(val != null && !val.isEmpty()) 050 validValues.add(val.toLowerCase()); 051 } 052 053 createFieldAccessors(); 054 } 055 056 /** 057 * Gets the option to accept empty fields. 058 * @return true if empty is ok 059 */ 060 public boolean isEmptyOK() 061 { 062 return emptyOK; 063 } 064 065 /** 066 * Sets the parameter to accept empty field values. 067 * @param emptyOK parameter to accept empty filed 068 */ 069 public void setEmptyOK(boolean emptyOK) 070 { 071 this.emptyOK = emptyOK; 072 } 073 074 /** 075 * The child class should populate the list of PathAccessor object using the 076 * <code>addAccessor</code> method. 077 */ 078 public abstract void createFieldAccessors(); 079 080 /** 081 * Adds the given <code>PathAccessor</code> to the list of accessors to use to get field values 082 * of objects and their related objects. 083 * @param acc accessor 084 * @param clazz the type of element that the accessor is applied 085 */ 086 protected void addAccessor(PathAccessor acc, Class<? extends BioPAXElement> clazz) 087 { 088 accessors.put(acc, clazz); 089 } 090 091 /** 092 * Adds the given valid value to the set of valid values. 093 * @param value a valid value 094 */ 095 protected void addValidValue(String value) 096 { 097 if(value!=null && !value.isEmpty()) 098 validValues.add(value.toLowerCase()); 099 } 100 101 /** 102 * Checks if the related values of the object are among valid values. Returns true if none of 103 * the accessors is applicable to the given object. 104 * @param ele level 3 element to check 105 * @return true if ok to traverse 106 */ 107 @Override 108 public boolean okToTraverse(Level3Element ele) 109 { 110 if(validValues.isEmpty()) 111 return true; 112 113 boolean empty = true; 114 boolean objectRelevant = false; 115 116 for (PathAccessor acc : accessors.keySet()) 117 { 118 Class clazz = accessors.get(acc); 119 120 if (!clazz.isAssignableFrom(ele.getClass())) continue; 121 122 objectRelevant = true; 123 124 Set values = acc.getValueFromBean(ele); 125 if (empty) empty = values.isEmpty(); 126 127 for (Object o : values) 128 //ignoring capitalization (case) 129 if (validValues.contains(o.toString().toLowerCase())) 130 return true; 131 } 132 133 return !objectRelevant || (empty && isEmptyOK()); 134 } 135}