/*
Copyright (C) 2003 EBI, GRL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.ensembl.mart.lib.config;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
/**
* Container for a group of Mart FilterCollections. Allows categorical grouping of collections
* of filters.
*
* @author <a href="mailto:dlondon@ebi.ac.uk">Darin London</a>
* @author <a href="mailto:craig@ebi.ac.uk">Craig Melsopp</a>
*/
public class FilterGroup extends BaseNamedConfigurationObject {
private boolean hasBrokenCollections = false;
private List filterCollections = new ArrayList();
private Hashtable filterCollectionNameMap = new Hashtable();
//cache one FilterDescription for call to containsFilterDescription or getUIFiterDescriptionByName
private FilterDescription lastFilt = null;
//cache one FilterCollection for call to getCollectionForFilter
private FilterCollection lastColl = null;
//cache one FilterDescription for call to supports
private FilterDescription lastSupportingFilter = null;
/**
* Copy constructor. Constructs a new FilterGroup which is an exact copy
* of an existing FilterGroup.
* @param fg FilterGroup to copy.
*/
public FilterGroup(FilterGroup fg) {
super(fg);
FilterCollection[] fcs = fg.getFilterCollections();
for (int i = 0, n = fcs.length; i < n; i++) {
addFilterCollection( new FilterCollection( fcs[i] ) );
}
}
public FilterGroup() {
super();
}
/**
* Constructor for a FilterGroup represented internally by internalName.
*
* @param internalName name to internally represent the FilterGroup
* @throws ConfigurationException when internalName is null or empty
*/
public FilterGroup(String internalName) throws ConfigurationException {
this(internalName, "", "");
}
/**
* Constructor for a FilterGroup named internally by internalName, with a displayName, and a description.
*
* @param internalName String name to internally represent the filterGroup. Must not be null.
* @param displayName
* @param description
* @throws ConfigurationException when internalName is null or empty.
*/
public FilterGroup(String internalName, String displayName, String description) throws ConfigurationException {
super(internalName, displayName, description);
}
/**
* Add a FilterCollection to the FilterGroup
*
* @param f a FilterCollection object
*/
public void addFilterCollection(FilterCollection f) {
filterCollections.add(f);
filterCollectionNameMap.put(f.getInternalName(), f);
}
/**
* Remove a FilterCollection from this FilterGroup.
* @param f -- FilterCollection to be removed.
*/
public void removeFilterCollection(FilterCollection f) {
filterCollectionNameMap.remove(f.getInternalName());
filterCollections.remove(f);
}
/**
* Insert a FilterCollection at a specific position within the List of FilterCollections.
* FilterCollection Objects occuring at or after the specified position are shifted right.
* @param position -- position at which to insert the FilterCollection
* @param f -- FilterCollection to insert.
*/
public void insertFilterCollection(int position, FilterCollection f) {
filterCollections.add(position, f);
filterCollectionNameMap.put(f.getInternalName(), f);
}
/**
* Insert a FilterCollection before a specific FilterCollection, named by internalName.
* @param internalName -- internalName of FilterCollection before which the given FilterCollection should be inserted.
* @param f -- FilterCollection to be inserted.
* @throws ConfigurationException when the FilterGroup does not contain a FilterCollection named by internalName.
*/
public void insertFilterCollectionBeforeFilterCollection(String internalName, FilterCollection f) throws ConfigurationException {
if (!filterCollectionNameMap.containsKey(internalName))
throw new ConfigurationException("FilterGroup does not contain a FilterCollection named by " + internalName +"\n");
insertFilterCollection( filterCollections.indexOf( filterCollectionNameMap.get(internalName) ) , f);
}
/**
* Insert a FilterCollection after a specific FilterCollection, named by internalName.
* @param internalName -- internalName of FilterCollection after which the given FilterCollection should be inserted.
* @param f -- FilterCollection to be inserted.
* @throws ConfigurationException when the FilterGroup does not contain a FilterCollection named by internalName.
*/
public void insertFilterCollectionAfterFilterCollection(String internalName, FilterCollection f) throws ConfigurationException {
if (!filterCollectionNameMap.containsKey(internalName))
throw new ConfigurationException("FilterGroup does not contain a FilterCollection named by " + internalName +"\n");
insertFilterCollection( filterCollections.indexOf( filterCollectionNameMap.get(internalName) ) + 1, f);
}
/**
* Add a group of FilterCollection objects in one call. Note, subsequent calls
* to addFilterCollection or addFilterCollections will add to what was previously added.
*
* @param f an Array of FilterCollection objects
*/
public void addFilterCollections(FilterCollection[] f) {
for (int i = 0, n = f.length; i < n; i++) {
filterCollections.add(f[i]);
filterCollectionNameMap.put(f[i].getInternalName(), f[i]);
}
}
/**
* Returns an array of FilterCollection objects, in the order they were added
*
* @return Array of FilterCollection objects
*/
public FilterCollection[] getFilterCollections() {
FilterCollection[] fc = new FilterCollection[filterCollections.size()];
filterCollections.toArray(fc);
return fc;
}
/**
* Returns a particular FilterCollection named by internalName
*
* @param internalName String name of the requested FilterCollection
*
* @return a FilterCollection object, or null
*/
public FilterCollection getFilterCollectionByName(String internalName) {
if (filterCollectionNameMap.containsKey(internalName))
return (FilterCollection) filterCollectionNameMap.get(internalName);
else
return null;
}
/**
* Check if a FilterGroup contains a given FilterCollection, of name internalName
*
* @param internalName String name of the requested FilterCollection
* @return boolean true if FilterGroup contains the FilterCollection, false if not
*/
public boolean containsFilterCollection(String internalName) {
return filterCollectionNameMap.containsKey(internalName);
}
/**
* Convenience method for non graphical UI. Allows a call against the FilterGroup for a particular FilterDescription object.
* Note, it is best to first call containsFilterDescription, as there is a caching system to cache a FilterDescription during a call
* to containsFilterDescription.
*
* @param internalName name of the requested FilterDescription
* @return requested FilterDescription, or null.
*/
public FilterDescription getFilterDescriptionByInternalName(String internalName) {
if (containsFilterDescription(internalName))
return lastFilt;
else
return null;
}
/**
* Convenience method for non graphical UI. Can determine if the FilterGroup contains a specific FilterDescription object.
* As an optimization for initial calls to containsFilterDescription with an immediate call to getFilterDescriptionByInternalName if
* found, this method caches the FilterDescription it has found.
*
* @param internalName name of the requested FilterDescription object
* @return boolean, true if found, false if not.
*/
public boolean containsFilterDescription(String internalName) {
boolean contains = false;
if (lastFilt == null) {
if ( ( internalName.indexOf(".") > 0 ) && !( internalName.endsWith(".") ) ) {
String[] refs = internalName.split("\\.");
if (refs.length > 1 && containsFilterDescription( refs[1] ) )
contains = true;
}
if (!contains) {
for (Iterator iter = (Iterator) filterCollections.iterator(); iter.hasNext();) {
FilterCollection collection = (FilterCollection) iter.next();
if (collection.containsFilterDescription(internalName)) {
lastFilt = collection.getFilterDescriptionByInternalName(internalName);
contains = true;
break;
}
}
}
} else {
if ( lastFilt.getInternalName().equals(internalName) )
contains = true;
else if (lastFilt.containsOption(internalName))
contains = true;
else if ( (internalName.indexOf(".") > 0) && !(internalName.endsWith(".")) && lastFilt.getInternalName().equals( internalName.split("\\.")[1] ) )
contains = true;
else if (lastFilt.getInternalName().matches("\\w+\\." + internalName)){
contains = true;
internalName = lastFilt.getInternalName();
}
else {
lastFilt = null;
contains = containsFilterDescription(internalName);
}
}
return contains;
}
/**
* Convenience method to get all FilterDescription objects
* contained in all FilterCollections in this FilterGroup.
*
* @return List of FilterDescription objects.
*/
public List getAllFilterDescriptions() {
List filts = new ArrayList();
for (Iterator iter = filterCollections.iterator(); iter.hasNext();) {
FilterCollection fc = (FilterCollection) iter.next();
filts.addAll(fc.getFilterDescriptions());
}
return filts;
}
/**
* Returns the FilterCollection for a particular FilterDescription
* based on its internalName.
*
* @param internalName - String internalName of the Filter Description for which the collection is being requested.
* @return FilterCollection for the FilterDescription provided, or null
*/
public FilterCollection getCollectionForFilter(String internalName) {
if (!containsFilterDescription(internalName))
return null;
else if (lastColl == null) {
for (Iterator iter = filterCollections.iterator(); iter.hasNext();) {
FilterCollection fc = (FilterCollection) iter.next();
if (fc.containsFilterDescription(internalName)) {
lastColl = fc;
break;
}
}
return lastColl;
} else {
if (lastColl.getInternalName().equals(internalName))
return lastColl;
else {
lastColl = null;
return getCollectionForFilter(internalName);
}
}
}
/**
* Get a FilterDescription object that supports a given field and tableConstraint. Useful for mapping from a Filter object
* added to a Query back to its FilterDescription.
* @param field -- String field of a mart database table
* @param tableConstraint -- String tableConstraint of a mart database
* @param qualifier -- Filter qualifier
* @return FilterDescription object supporting the given field and tableConstraint, or null.
*/
public FilterDescription getFilterDescriptionByFieldNameTableConstraint(String field, String tableConstraint, String qualifier) {
if (supports(field, tableConstraint, qualifier))
return lastSupportingFilter;
else
return null;
}
/**
* Determine if this FilterGroup contains a FilterDescription that supports a given field and tableConstraint.
* Calling this method will cache any FilterDescription that supports the field and tableConstraint, and this will
* be returned by a getFilterDescriptionByFieldNameTableConstraint call.
* @param field -- String field of a mart database table
* @param tableConstraint -- String tableConstraint of a mart database
* @param qualifier -- Filter qualifier
* @return boolean, true if the FilterGroup contains a FilterDescription supporting a given field, tableConstraint, false otherwise.
*/
public boolean supports(String field, String tableConstraint, String qualifier) {
boolean supports = false;
if (lastSupportingFilter == null) {
for (Iterator iter = filterCollections.iterator(); iter.hasNext();) {
FilterCollection element = (FilterCollection) iter.next();
if (element.supports(field, tableConstraint, qualifier)) {
lastSupportingFilter = element.getFilterDescriptionByFieldNameTableConstraint(field, tableConstraint, qualifier);
supports = true;
break;
}
}
} else {
if (lastSupportingFilter.supports(field, tableConstraint, qualifier))
supports = true;
else {
lastSupportingFilter = null;
supports = supports(field, tableConstraint,qualifier);
}
}
return supports;
}
/**
* Retruns a List of possible Completion names for filters to the MartCompleter command completion system.
* @return List possible completions
*/
public List getCompleterNames() {
List names = new ArrayList();
for (Iterator iter = filterCollections.iterator(); iter.hasNext();) {
FilterCollection element = (FilterCollection) iter.next();
if (element.getHidden() != null && element.getHidden().equals("true")) continue;
if (element.getDisplay() != null && element.getDisplay().equals("true")) continue;
names.addAll(element.getCompleterNames());
}
return names;
}
/**
* Allows MartShell to get all values associated with a given internalName (which may be of form x.y).
* Behaves differently than getFilterDescriptionByInternalName when internalName is x.y and y is the name of
* an actual filterDescription.
* @param internalName
* @return List of values to complete
*/
public List getCompleterValuesByInternalName(String internalName) {
if (internalName.indexOf(".") > 0)
return getFilterDescriptionByInternalName(internalName.split("\\.")[0]).getCompleterValues(internalName);
else
return getFilterDescriptionByInternalName(internalName).getCompleterValues(internalName);
}
/**
* Allows MartShell to get all qualifiers associated with a given internalName (which may be of form x.y).
* Behaves differently than getFilterDescriptionByInternalName when internalName is x.y and y is the name of
* an actual filterDescription.
* @param internalName
* @return List of qualifiers to complete
*/
public List getFilterCompleterQualifiersByInternalName(String internalName) {
if (internalName.indexOf(".") > 0 && !(internalName.endsWith(".")) && containsFilterDescription( internalName.split("\\.")[1] ) ) {
String refname = internalName.split("\\.")[1];
return getFilterDescriptionByInternalName(refname).getCompleterQualifiers(refname);
} else
return getFilterDescriptionByInternalName(internalName).getCompleterQualifiers(internalName);
}
/**
* debug output
*/
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("[");
buf.append(super.toString());
buf.append(", filterCollections=").append(filterCollections);
buf.append("]");
return buf.toString();
}
/**
* Allows Equality Comparisons manipulation of FilterGroup objects
*/
public boolean equals(Object o) {
return o instanceof FilterGroup && hashCode() == o.hashCode();
}
public int hashCode() {
int tmp = super.hashCode();
for (Iterator iter = filterCollections.iterator(); iter.hasNext();) {
FilterCollection element = (FilterCollection) iter.next();
tmp = (31 * tmp) + element.hashCode();
}
return tmp;
}
/**
* Set the hasBrokenCollections flag to true, meaning
* one or more FilterCollection objects contain FilterDescriptions
* with invalid field, tableConstraint, or Options.
*/
public void setCollectionsBroken() {
hasBrokenCollections = true;
}
/**
* Determine if this FilterGroup has broken Collections
* @return boolean
*/
public boolean hasBrokenCollections() {
return hasBrokenCollections;
}
/**
* True if hasBrokenCollections is true.
* @return boolean
*/
public boolean isBroken() {
return hasBrokenCollections;
}
public boolean containsOnlyPointerFilters() {
boolean contains = true;
FilterCollection[] cols = getFilterCollections();
for (int i = 0, n = cols.length; i < n; i++) {
if (cols[i].getHidden() != null && cols[i].getHidden().equals("true")) continue;
if (cols[i].getDisplay() != null && cols[i].getDisplay().equals("true")) continue;
if (!cols[i].containsOnlyPointerFilters()) {
contains = false;
break;
}
}
return contains;
}
}