/*
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 set of Mart AttributeCollections.
*
* @author <a href="mailto:dlondon@ebi.ac.uk">Darin London</a>
* @author <a href="mailto:craig@ebi.ac.uk">Craig Melsopp</a>
*/
public final class AttributeGroup extends BaseNamedConfigurationObject {
private boolean hasBrokenCollections;
private List attributeCollections = new ArrayList();
private Hashtable attributeCollectionNameMap = new Hashtable();
public final int DEFAULTMAXSELECT = 0;
private final String maxSelectKey = "maxSelect";
//cache one AttributeDescription for call to containsUIAttributeDescription or getAttributeDescriptionByName
private AttributeDescription lastAtt = null;
private AttributeList lastAttList = null;
//cache one AttributeCollecton for call to getCollectionForAttribute
private AttributeCollection lastColl = null;
//cache one AttributeDescription for call to supports/getAttributeDescriptionByFieldNameTableConstraint
private AttributeDescription lastSupportingAttribute = null;
/**
* Copy constructor. Constructs an exact copy of an existing AttributeGroup.
* @param ag AttributeGroup to copy.
*/
public AttributeGroup(AttributeGroup ag) {
super(ag);
AttributeCollection[] acs = ag.getAttributeCollections();
for (int i = 0, n = acs.length; i < n; i++) {
addAttributeCollection( new AttributeCollection( acs[i] ) );
}
}
/**
* Empty Constructor should only be used by DatasetConfigEditory
*/
public AttributeGroup() {
super();
setAttribute(maxSelectKey, null);
}
/**
* Constructor for an AttributeGroup named by internalName.
*
* @param internalName String name to internally represent the AttributeGroup.
* @throws ConfigurationException when internalName is null or empty
*/
public AttributeGroup(String internalName) throws ConfigurationException {
this(internalName, "", "","");
}
/**
* Constructor for a fully defined AttributeGroup, with an internalName, displayName, and description.
*
* @param internalName String name to internally represent the AttributeGroup. Must not be null or empty
* @param displayName String name to display in a UI.
* @param description String description of the AttributeGroup.
* @throws ConfigurationException when required parameters are null or empty
*/
public AttributeGroup(String internalName, String displayName, String description) throws ConfigurationException {
this(internalName, displayName, description,"");
}
public AttributeGroup(String internalName, String displayName, String description, String maxSelect) throws ConfigurationException {
super( internalName, displayName, description);
setAttribute(maxSelectKey, maxSelect);
}
/**
* Set the maxSelect value for this AttributeCollection
* @param maxSelect -- String value to limit selections of Attributes in groups. 0 means no limit.
*/
public void setMaxSelect(String maxSelect){
setAttribute(maxSelectKey, maxSelect);
}
public String getMaxSelectString() {
return getAttribute(maxSelectKey);
}
/**
* Returns the maxSelect value for attributes in this AttributeCollection.
* If the value for maxSelect provided is not a valid int (eg.
* Integer.parseInt( maxSelect) throws a NumberFormatException)
* this method returns DEFAULTMAXSELECT.
*
* @return int maxSelect value
*/
public int getMaxSelect() {
try {
return Integer.parseInt( getAttribute(maxSelectKey) );
} catch (NumberFormatException e) {
return DEFAULTMAXSELECT;
}
}
/**
* Add an AttributeColllection the the AttributeGroup.
*
* @param c an AttributeCollection object.
*/
public void addAttributeCollection(AttributeCollection c) {
attributeCollections.add(c);
attributeCollectionNameMap.put(c.getInternalName(), c);
}
/**
* Remove an AttributeCollection from the AttributeGroup
* @param c -- AttributeCollection to be removed.
*/
public void removeAttributeCollection(AttributeCollection c) {
attributeCollectionNameMap.remove(c.getInternalName());
attributeCollections.remove(c);
}
/**
* Insert an AttributeCollection at a particular position. AttributeCollection Objects
* at or after the given position are shifted right.
* @param position -- position to insert AttributeCollection
* @param c -- AttributeCollection to insert
*/
public void insertAttributeCollection(int position, AttributeCollection c) {
attributeCollections.add(position, c);
attributeCollectionNameMap.put(c.getInternalName(), c);
}
/**
* Insert an AttributeCollection before a specific AttributeCollection named by internalName.
* @param internalName -- internalName of AttributeCollection before which the given AttributeCollection is to be inserted.
* @param c -- AttributeCollection to be inserted.
* @throws ConfigurationException when the AttributeGroup does not contain an AttributeCollection named by internalName
*/
public void insertAttributeCollectionBeforeAttributeCollection(String internalName, AttributeCollection c) throws ConfigurationException {
if (!attributeCollectionNameMap.containsKey(internalName))
throw new ConfigurationException("AttributeGroup does not contain AttributeCollection " + internalName + "\n");
insertAttributeCollection( attributeCollections.indexOf( attributeCollectionNameMap.get(internalName) ) , c);
}
/**
* Insert an AttributeCollection after a specific AttributeCollection named by internalName.
* @param internalName -- internalName of AttributeCollection after which the given AttributeCollection is to be inserted.
* @param c -- AttributeCollection to be inserted.
* @throws ConfigurationException when the AttributeGroup does not contain an AttributeCollection named by internalName
*/
public void insertAttributeCollectionAfterAttributeCollection(String internalName, AttributeCollection c) throws ConfigurationException {
if (!attributeCollectionNameMap.containsKey(internalName))
throw new ConfigurationException("AttributeGroup does not contain AttributeCollection " + internalName + "\n");
insertAttributeCollection( attributeCollections.indexOf( attributeCollectionNameMap.get(internalName) ) + 1, c);
}
/**
* Add a group of AttributeCollection objects with one call.
*
* @param c an Array of AttributeCollection objects.
*/
public void addAttributeCollections(AttributeCollection[] c) {
for (int i = 0; i < c.length; i++) {
attributeCollections.add(c[i]);
attributeCollectionNameMap.put(c[i].getInternalName(), c[i]);
}
}
/**
* Get all of the AttributeCollection objects contained in this AttributeGroup in an array, in the order they were added.
*
* @return Array of AttributeCollection objects.
*/
public AttributeCollection[] getAttributeCollections() {
AttributeCollection[] a = new AttributeCollection[attributeCollections.size()];
attributeCollections.toArray(a);
return a;
}
/**
* Returns a specific AttributeCollection, named by internalName.
*
* @param internalName String internal name of the AttributeCollection
* @return an AttributeCollection object, or null
*/
public AttributeCollection getAttributeCollectionByName(String internalName) {
if (attributeCollectionNameMap.containsKey(internalName))
return (AttributeCollection) attributeCollectionNameMap.get(internalName);
else
return null;
}
/**
* Check to determine if this AttributeGroup contains a specific AttributeCollection named by intenalName.
*
* @param internalName String internal name of the AttributeCollection
* @return boolean, true if found, false if not.
*/
public boolean containsAttributeCollection(String internalName) {
return attributeCollectionNameMap.containsKey(internalName);
}
/**
* Convenience method for non graphical UI. Allows a call against the AttributeGroup for a particular AttributeDescription.
* Note, it is best to first call containsUIAttributeDescription,
* as there is a caching system to cache a AttributeDescription during a call to containsUIAttributeDescription.
*
* @param internalName name of the requested AttributeDescription
* @return AttributeDescription requested, or null
*/
public AttributeDescription getAttributeDescriptionByInternalName(String internalName) {
if ( containsAttributeDescription(internalName) )
return lastAtt;
else
return null;
}
/**
* Convenience method for non graphical UI. Can determine if the AttributeGroup contains a specific AttributeDescription.
* As an optimization for initial calls to containsUIAttributeDescription with an immediate call to getUIAttributeDescriptionByName if
* found, this method caches the AttributeDescription it has found.
*
* @param internalName name of the requested AttributeDescription
* @return boolean, true if found, false if not.
*/
public boolean containsAttributeDescription(String internalName){
boolean found = false;
if (lastAtt == null) {
for (Iterator iter = (Iterator) attributeCollections.iterator(); iter.hasNext();) {
AttributeCollection collection = (AttributeCollection) iter.next();
if (collection.containsAttributeDescription(internalName)) {
lastAtt = collection.getAttributeDescriptionByInternalName(internalName);
found = true;
break;
}
}
}
else {
if (lastAtt.getInternalName().equals(internalName))
found = true;
else {
lastAtt = null;
found = containsAttributeDescription(internalName);
}
}
return found;
}
/**
* Convenience method for non graphical UI. Allows a call against the AttributeGroup for a particular AttributeList.
* Note, it is best to first call containsUIAttributeList,
* as there is a caching system to cache a AttributeList during a call to containsUIAttributeList.
*
* @param internalName name of the requested AttributeList
* @return AttributeList requested, or null
*/
public AttributeList getAttributeListByInternalName(String internalName) {
if ( containsAttributeList(internalName) )
return lastAttList;
else
return null;
}
/**
* Convenience method for non graphical UI. Can determine if the AttributeGroup contains a specific AttributeList.
* As an optimization for initial calls to containsUIAttributeList with an immediate call to getUIAttributeListByName if
* found, this method caches the AttributeList it has found.
*
* @param internalName name of the requested AttributeList
* @return boolean, true if found, false if not.
*/
public boolean containsAttributeList(String internalName){
boolean found = false;
if (lastAttList == null) {
for (Iterator iter = (Iterator) attributeCollections.iterator(); iter.hasNext();) {
AttributeCollection collection = (AttributeCollection) iter.next();
if (collection.containsAttributeList(internalName)) {
lastAttList = collection.getAttributeListByInternalName(internalName);
found = true;
break;
}
}
}
else {
if (lastAttList.getInternalName().equals(internalName))
found = true;
else {
lastAttList = null;
found = containsAttributeList(internalName);
}
}
return found;
}
/**
* Retrieve a specific AttributeDescription that supports a given field and tableConstraint.
* @param field
* @param tableConstraint
* @return AttributeDescription supporting the field and tableConstraint, or null
*/
public AttributeDescription getAttributeDescriptionByFieldNameTableConstraint(String field, String tableConstraint) {
if (supports(field, tableConstraint))
return lastSupportingAttribute;
else
return null;
}
/**
* Determine if this AttributeGroup supports a given field and tableConstraint. Caches the first supporting AttributeDescription
* that it finds, for subsequent call to getAttributeDescriptionByFieldNameTableConstraint.
* @param field
* @param tableConstraint
* @return boolean, true if an AttributeDescription contained in this AttributeGroup supports the field and tableConstraint, false otherwise
*/
public boolean supports(String field, String tableConstraint) {
boolean supports = false;
for (Iterator iter = attributeCollections.iterator(); iter.hasNext();) {
AttributeCollection element = (AttributeCollection) iter.next();
if (element.supports(field, tableConstraint)) {
lastSupportingAttribute = element.getAttributeDescriptionByFieldNameTableConstraint(field, tableConstraint);
supports = true;
break;
}
}
return supports;
}
/**
* Convenience method. Returns all of the AttributeDescription objects
* contained in all of the AttributeCollections.
*
* @return List of AttributeDescription objects
*/
public List getAllAttributeDescriptions() {
List atts = new ArrayList();
for (Iterator iter = attributeCollections.iterator(); iter.hasNext();) {
AttributeCollection ac = (AttributeCollection) iter.next();
atts.addAll(ac.getAttributeDescriptions());
}
return atts;
}
/**
* Convenience method. Returns all of the AttributeList objects
* contained in all of the AttributeCollections.
*
* @return List of AttributeList objects
*/
public List getAllAttributeLists() {
List atts = new ArrayList();
for (Iterator iter = attributeCollections.iterator(); iter.hasNext();) {
AttributeCollection ac = (AttributeCollection) iter.next();
atts.addAll(ac.getAttributeLists());
}
return atts;
}
/**
* Returns the AttributeCollection for a particular Attribute (AttributeDescription or UIDSAttributeDescription)
* based on its internalName.
*
* @param internalName - String internalName of the Attribute Description for which the collection is being requested.
* @return AttributeCollection for the AttributeDescription provided, or null
*/
public AttributeCollection getCollectionForAttributeDescription(String internalName) {
if (! containsAttributeDescription(internalName))
return null;
else if (lastColl == null) {
for (Iterator iter = attributeCollections.iterator(); iter.hasNext();) {
AttributeCollection ac = (AttributeCollection) iter.next();
if (ac.containsAttributeDescription(internalName)) {
lastColl = ac;
break;
}
}
return lastColl;
}
else {
if (lastColl.getInternalName().equals(internalName))
return lastColl;
else {
lastColl = null;
return getCollectionForAttributeDescription(internalName);
}
}
}
/**
* Returns the AttributeCollection for a particular Attribute (AttributeList or UIDSAttributeList)
* based on its internalName.
*
* @param internalName - String internalName of the Attribute List for which the collection is being requested.
* @return AttributeCollection for the AttributeList provided, or null
*/
public AttributeCollection getCollectionForAttributeList(String internalName) {
if (! containsAttributeList(internalName))
return null;
else if (lastColl == null) {
for (Iterator iter = attributeCollections.iterator(); iter.hasNext();) {
AttributeCollection ac = (AttributeCollection) iter.next();
if (ac.containsAttributeList(internalName)) {
lastColl = ac;
break;
}
}
return lastColl;
}
else {
if (lastColl.getInternalName().equals(internalName))
return lastColl;
else {
lastColl = null;
return getCollectionForAttributeList(internalName);
}
}
}
/**
* Returns a List of internalNames for the MartCompleter command completion system.
* @return List of internalNames
*/
public List getCompleterNames() {
List names = new ArrayList();
for (Iterator iter = attributeCollections.iterator(); iter.hasNext();) {
AttributeCollection acol = (AttributeCollection) iter.next();
if (acol.getHidden() != null && acol.getHidden().equals("true")) continue;
if (acol.getDisplay() != null && acol.getDisplay().equals("true")) continue;
// hacky special case for sequence supported pointers in
// sequences.header_info.gene,transcript,exon
if (getInternalName().equals("header_info")) {
names.addAll(acol.getHiddenCompleterNames());
} else {
names.addAll(acol.getCompleterNames());
}
}
return names;
}
/**
* debug output
*/
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("[");
buf.append( super.toString() );
buf.append(", attributeCollections=").append(attributeCollections);
buf.append("]");
return buf.toString();
}
/**
* Allows Equality Comparisons manipulation of AttributeGroup objects
*/
public boolean equals(Object o) {
return o instanceof AttributeGroup && hashCode() == ((AttributeGroup) o).hashCode();
}
public int hashCode() {
int tmp = super.hashCode();
for (Iterator iter = attributeCollections.iterator(); iter.hasNext();) {
AttributeCollection element = (AttributeCollection) iter.next();
tmp = (31 * tmp) + element.hashCode();
}
return tmp;
}
/**
* Set the hasBrokenCollections flag to true, meaning the AttributeGroup
* contains one or more AttributeGroups with broken AttributeDescription Objects.
*/
public void setCollectionsBroken() {
hasBrokenCollections = true;
}
/**
* Determine if this AttributeGroup contains broken AttributeCollections
* @return boolean
*/
public boolean hasBrokenCollections() {
return hasBrokenCollections;
}
/**
* True if hasBrokenCollections is true
* @return boolean
*/
public boolean isBroken() {
return hasBrokenCollections;
}
public boolean containsOnlyPointerAttributes() {
boolean ret = true;
AttributeCollection[] acols = getAttributeCollections();
for (int i = 0, n = acols.length; i < n; i++) {
AttributeCollection collection = acols[i];
if (!collection.containsOnlyPointerAttributes()) {
ret = false;
break;
}
}
return ret;
}
}