/*
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;
import java.util.logging.Logger;
import org.ensembl.mart.lib.config.AttributeDescription;
import org.ensembl.mart.lib.config.ConfigurationException;
import org.ensembl.mart.lib.config.DSConfigAdaptor;
import org.ensembl.mart.lib.config.DatasetConfig;
import org.ensembl.mart.lib.config.Exportable;
import org.ensembl.mart.lib.config.FilterDescription;
import org.ensembl.mart.lib.config.Importable;
/**
* Contains the knowledge for creating the different sequences
* that Mart is able to generate.
*
* @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 SequenceDescription {
/**
* @return Returns the adaptor.
*/
public DSConfigAdaptor getAdaptor() {
return adaptor;
}
/**
* @return Returns the refDataSource.
*/
public DetailedDataSource getRefDataSource() {
return refDataSource;
}
/**
* @return Returns the refDatasetName.
*/
public String getRefDatasetName() {
return refDatasetName;
}
/**
* @return Returns the seqDatasetName.
*/
public String getSeqDatasetName() {
return seqDatasetName;
}
/**
* @return Returns the seqDescription.
*/
public String getSeqDescription() {
return seqDescription;
}
/**
* @return Returns the seqInfo.
*/
public String getSeqInfo() {
return seqInfo;
}
/**
* default constructor private, so SequeceDescription cannot be subclassed
*/
private SequenceDescription() {
}
/**
* Construct a SequenceDescription of a specified type.
* type can be one of the static sequence types.
* This is useful for types that cannot have
* their flanking sequences extended.
*
* @param type int
*/
public SequenceDescription(String refDatasetName, String seqDatasetName, String seqDescription, DSConfigAdaptor adaptor) throws InvalidQueryException {
this(refDatasetName, seqDatasetName, seqDescription, adaptor, 0, 0);
}
/**
* Construct a fully qualified SequenceDescription with all
* necessary information.
*
* @param type Must be one of the static enums
* @param leftFlank length of left flanking sequence to append to the resulting sequences
* @param rightFlank length of right flanking sequence to append to the resulting sequences
* @throws InvalidQueryException if the client requests an unknown sequence type,
* or requests flanking sequence for a sequence which is not applicable for flanking sequence.
*/
public SequenceDescription(String refDatasetName, String seqDatasetName, String seqDescription, DSConfigAdaptor adaptor, int lflank, int rflank) throws InvalidQueryException {
this.seqDatasetName = seqDatasetName;
this.seqDescription = seqDescription;
this.refDatasetName = refDatasetName;
this.adaptor = adaptor;
this.leftFlank = lflank;
this.rightFlank = rflank;
addSeqConfig();
refDataSource = refDataset.getAdaptor().getDataSource();
seqInfo = refDataset.getOptionalParameter();
}
private void addSeqConfig() throws InvalidQueryException {
try {
seqType = seqDescription;
refDataset = adaptor.getDatasetConfigByDatasetInternalName(refDatasetName, "default"); //assume default for now
finalDatasetName = seqDatasetName;
finalDataset = adaptor.getDatasetConfigByDatasetInternalName(seqDatasetName, "default");
finalDataSource = finalDataset.getAdaptor().getDataSource();
} catch (ConfigurationException e) {
throw new InvalidQueryException("addSeqConfig: Could not get Sequence Dataset for " + seqDatasetName + "\n", e);
}
}
/**
* Copy constructor.
* @param o - a SequenceDescription object
*/
public SequenceDescription(SequenceDescription o) {
seqDescription = o.getSeqDescription();
adaptor = o.getAdaptor();
refDataSource = o.getRefDataSource();
seqInfo = o.getSeqInfo();
leftFlank = o.getLeftFlank();
rightFlank = o.getRightFlank();
finalDataset = o.getFinalDataset();
intermediateDataset = o.getIntermediateDataset();
refDataset = o.getRefDataset();
seqType = o.getSeqType();
finalDatasetName = o.getFinalDatasetName();
finalDataSource = o.getFinalDataSource();
finalLink = o.getFinalLink();
subQuery = o.getSubQuery();
seqDatasetName = o.getSeqDatasetName();
refDatasetName = o.getRefDatasetName();
}
/**
* Returns the length of the left flank
*
* @return int leftFlank
*/
public int getLeftFlank() {
return leftFlank;
}
/**
* Returns the length of the right flank
*
* @return int rightFlank
*/
public int getRightFlank() {
return rightFlank;
}
public String getSeqType() {
return seqType;
}
public Attribute getAttribute(Attribute attribute) throws InvalidQueryException {
AttributeDescription attrDesc = refDataset.getAttributeDescriptionByInternalName(attribute.getField());
System.err.println("Attribute field name: "+attribute.getField()+" gave "+attrDesc);
if (subQuery != null)
initializeSubQuery();
if (attrDesc!=null && attrDesc.getPointerDataset()!=null && !"".equals(attrDesc.getPointerDataset())) {
AttributeDescription structAttD = finalDataset.getAttributeDescriptionByInternalName(attrDesc.getPointerAttribute());
if (structAttD == null)
throw new InvalidQueryException("getAttribute: Could not get attribute " + attrDesc.getPointerAttribute() + " from " + finalDataset.getDisplayName() + "\n");
attribute = new FieldAttribute(structAttD.getField(), structAttD.getTableConstraint(), structAttD.getKey());
}
return attribute;
}
public IDListFilter getFilter(Filter filter) throws InvalidQueryException {
//for non structure intermediate queries, return null
if (finalDataset == null)
return null;
//as new filters come through here, the IDListFilter returned will be different each time
subQuery.addFilter(filter);
return getSubQueryFilter();
}
private Importable getReferenceImportable() throws InvalidQueryException {
Importable[] imps = refDataset.getImportables();
Importable imp = null;
for (int i = 0, n = imps.length; i < n; i++) {
Importable importable = imps[i];
if (importable.getLinkName().equals(seqType)) {
imp = importable;
break;
}
}
if (imp == null)
throw new InvalidQueryException("getReferenceImportable: Sequence " + seqType + " is not supported\n");
return imp;
}
private Importable getFinalImportable() throws InvalidQueryException {
Importable[] imps = finalDataset.getImportables();
Importable imp = null;
if (finalDataset == refDataset) {
for (int i = 0, n = imps.length; i < n; i++) {
if (imps[i].getLinkName().equals(seqType)) {
imp = imps[i];
break;
}
}
} else
imp = imps[0]; //there is only one
if (imp == null)
throw new InvalidQueryException("getFinalImportable: Could not get Importable for " + seqType + " from " + finalDatasetName + "\n");
return imp;
}
private IDListFilter getSubQueryFilter() throws InvalidQueryException {
FilterDescription finalListFilter = finalDataset.getFilterDescriptionByInternalName(getFinalImportable().getFilters());
if (finalListFilter == null)
throw new InvalidQueryException("getSubQueryFilter: Could not run sequence query\n");
return new IDListFilter(finalListFilter.getField(),
finalListFilter.getTableConstraint(),
finalListFilter.getKey(),
subQuery);
}
public void setSubQuery(Query query) throws InvalidQueryException {
try {
String qDataset = query.getDataset();
intermediateDataset = adaptor.getDatasetConfigByDatasetInternalName(qDataset, "default");
} catch (ConfigurationException e) {
throw new InvalidQueryException("setSubQuery: Could not get Configuration for " + query.getDataset() + "\n", e);
}
subQuery = new Query();
subQuery.setDataset(intermediateDataset.getDataset());
subQuery.setDatasetConfig(intermediateDataset);
subQuery.setDataSource(intermediateDataset.getAdaptor().getDataSource());
subQuery.setMainTables(intermediateDataset.getStarBases());
subQuery.setPrimaryKeys(intermediateDataset.getPrimaryKeys());
}
private void initializeSubQuery() throws InvalidQueryException {
//must find the finalLink
if (finalDataset == refDataset) {
//use intermediate exportable <-> final importable
Exportable[] intExps = intermediateDataset.getExportables();
Importable finalImp = getFinalImportable();
for (int i = 0, n = intExps.length; i < n; i++) {
Exportable exportable = intExps[i];
if (exportable.getLinkName().equals(finalImp.getLinkName())) {
//this is the one we need. Split its attributes and add them to finalLink
String[] attNames = intExps[i].getAttributes().split("\\,");
finalLink = new Attribute[attNames.length];
for (int j = 0, m = attNames.length; j < m; j++) {
AttributeDescription att = intermediateDataset.getAttributeDescriptionByInternalName(
attNames[j]);
finalLink[j] = new FieldAttribute(att.getField(),
att.getTableConstraint(),
att.getKey());
}
break;
}
}
} else {
//use final exportable <-> reference importable
Exportable[] finalExps = refDataset.getExportables();
Importable refImp = getFinalImportable();
for (int i = 0, n = finalExps.length; i < n; i++) {
if (finalExps[i].getLinkName().equals(refImp.getLinkName())) {
//this is the one we need. Split its attributes and add them to finalLink
String[] attNames = finalExps[i].getAttributes().split("\\,");
finalLink = new Attribute[attNames.length];
for (int j = 0, m = attNames.length; j < m; j++) {
AttributeDescription att = refDataset.getAttributeDescriptionByInternalName(
attNames[j]);
finalLink[j] = new FieldAttribute(att.getField(),
att.getTableConstraint(),
att.getKey());
}
break;
}
}
}
if (finalLink == null)
throw new InvalidQueryException("InitializeSubQuery: Sequence type " + seqType + " does not appear to be supported\n");
//must find the intermediate exportable <-> final importable link
//and use it to add the link attribute to the subQuery
Importable finalImportable = getFinalImportable();
Exportable[] intermediateExportables = intermediateDataset.getExportables();
Exportable exp = null;
for (int i = 0, n = intermediateExportables.length; i < n; i++) {
if (intermediateExportables[i].getLinkName().equals(finalImportable.getLinkName())) {
//ignoring version, come back if bugs
exp = intermediateExportables[i];
break;
}
}
if (exp == null)
throw new InvalidQueryException("InitializeSubQuery: Could not run sequence query\n");
//note, in this case, the finalLink will only have one attribute
AttributeDescription visAtt = intermediateDataset.getAttributeDescriptionByInternalName( exp.getAttributes() );
if (visAtt == null)
throw new InvalidQueryException("InitializeSubQuery: Could not run sequence query\n");
subQuery.addAttribute(
new FieldAttribute(visAtt.getField(), visAtt.getTableConstraint(), visAtt.getKey())
);
}
public String getFinalDatasetName() {
return finalDatasetName;
}
public DatasetConfig getFinalDataset() {
return finalDataset;
}
public DetailedDataSource getFinalDataSource() {
return finalDataSource;
}
public String[] getStructureMainTables() {
return finalDataset.getStarBases();
}
public String[] getStructurePrimaryKeys() {
return finalDataset.getPrimaryKeys();
}
public Attribute[] getFinalLink() {
//for sequence queries not involving a structure intermediate
if (finalLink == null && intermediateDataset != null) {
Exportable[] intermediateExps = intermediateDataset.getExportables();
for (int i = 0, n = intermediateExps.length; i < n; i++) {
if (intermediateExps[i].getLinkName().equals(seqType)) {
//this is the one we need. Split its attributes and add them to finalLink
String[] attNames = intermediateExps[i].getAttributes().split("\\,");
finalLink = new Attribute[attNames.length];
for (int j = 0, m = attNames.length; j < m; j++) {
AttributeDescription att = intermediateDataset.getAttributeDescriptionByInternalName(
attNames[j]);
finalLink[j] = new FieldAttribute(att.getField(),
att.getTableConstraint(),
att.getKey());
}
break;
}
}
}
return finalLink;
}
public Query getSubQuery() {
return subQuery;
}
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("[");
buf.append(" seqDescription=").append(seqDescription);
buf.append(", seqInfo=").append(seqInfo);
buf.append(", refDataSource=").append(refDataSource);
buf.append(", leftFlank=").append(leftFlank);
buf.append(", rightFlank=").append(rightFlank);
buf.append("]");
return buf.toString();
}
/**
* Allows Equality Comparison manipulation of SequenceDescription objects
*/
public boolean equals(Object o) {
return o instanceof SequenceDescription && hashCode() == ((SequenceDescription) o).hashCode();
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
public int hashCode() {
int tmp = seqDescription.hashCode();
tmp = (31 * tmp) + refDataSource.hashCode();
tmp = (31 * tmp) + leftFlank;
tmp = (31 * tmp) + rightFlank;
if (seqInfo != null)
tmp = (31 * tmp) + seqInfo.hashCode();
return tmp;
}
/**
* @return Returns the refDataset.
*/
public DatasetConfig getRefDataset() {
return refDataset;
}
/**
* @return Returns the intermediateDataset.
*/
public DatasetConfig getIntermediateDataset() {
return intermediateDataset;
}
private DatasetConfig finalDataset, intermediateDataset, refDataset;
private String seqDescription, seqInfo, seqType, finalDatasetName;
private DSConfigAdaptor adaptor;
private DetailedDataSource refDataSource, finalDataSource;
private int leftFlank = 0;
private int rightFlank = 0;
private Attribute[] finalLink;
Query subQuery;
private String seqDatasetName, refDatasetName;
private Logger logger = Logger.getLogger(SequenceDescription.class.getName());
}