/*
* Eoulsan development code
*
* This code may be freely distributed and modified under the
* terms of the GNU Lesser General Public License version 2.1 or
* later and CeCILL-C. This should be distributed with the code.
* If you do not have a copy, see:
*
* http://www.gnu.org/licenses/lgpl-2.1.txt
* http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.txt
*
* Copyright for this code is held jointly by the Genomic platform
* of the Institut de Biologie de l'École normale supérieure and
* the individual authors. These should be listed in @author doc
* comments.
*
* For more information on the Eoulsan project and its aims,
* or to join the Eoulsan Google group, visit the home page
* at:
*
* http://outils.genomique.biologie.ens.fr/eoulsan
*
*/
package fr.ens.biologie.genomique.eoulsan.modules.expression;
import static fr.ens.biologie.genomique.eoulsan.EoulsanLogger.getLogger;
import static fr.ens.biologie.genomique.eoulsan.core.Modules.renamedParameter;
import static fr.ens.biologie.genomique.eoulsan.core.OutputPortsBuilder.singleOutputPort;
import static fr.ens.biologie.genomique.eoulsan.data.DataFormats.ANNOTATION_GFF;
import static fr.ens.biologie.genomique.eoulsan.data.DataFormats.ANNOTATION_GTF;
import static fr.ens.biologie.genomique.eoulsan.data.DataFormats.EXPRESSION_RESULTS_TSV;
import static fr.ens.biologie.genomique.eoulsan.data.DataFormats.GENOME_DESC_TXT;
import static fr.ens.biologie.genomique.eoulsan.data.DataFormats.MAPPER_RESULTS_SAM;
import java.util.Set;
import fr.ens.biologie.genomique.eoulsan.AbstractEoulsanRuntime.EoulsanExecMode;
import fr.ens.biologie.genomique.eoulsan.EoulsanException;
import fr.ens.biologie.genomique.eoulsan.Globals;
import fr.ens.biologie.genomique.eoulsan.bio.expressioncounters.ExpressionCounter;
import fr.ens.biologie.genomique.eoulsan.bio.expressioncounters.ExpressionCounterService;
import fr.ens.biologie.genomique.eoulsan.bio.expressioncounters.HTSeqCounter;
import fr.ens.biologie.genomique.eoulsan.bio.expressioncounters.OverlapMode;
import fr.ens.biologie.genomique.eoulsan.bio.expressioncounters.StrandUsage;
import fr.ens.biologie.genomique.eoulsan.core.InputPorts;
import fr.ens.biologie.genomique.eoulsan.core.InputPortsBuilder;
import fr.ens.biologie.genomique.eoulsan.core.Modules;
import fr.ens.biologie.genomique.eoulsan.core.OutputPorts;
import fr.ens.biologie.genomique.eoulsan.core.Parameter;
import fr.ens.biologie.genomique.eoulsan.core.StepConfigurationContext;
import fr.ens.biologie.genomique.eoulsan.core.Version;
import fr.ens.biologie.genomique.eoulsan.modules.AbstractModule;
import fr.ens.biologie.genomique.eoulsan.modules.CheckerModule;
/**
* This abstract class define and parse arguments for the expression module.
* @since 1.0
* @author Laurent Jourdren
* @author Maria Bernard
* @author Claire Wallon
*/
public abstract class AbstractExpressionModule extends AbstractModule {
public static final String MODULE_NAME = "expression";
private static final String OLD_EOULSAN_COUNTER_NAME = "eoulsanCounter";
public static final String REMOVE_AMBIGUOUS_CASES_PARAMETER_NAME =
"remove.ambiguous.cases";
public static final String OVERLAP_MODE_PARAMETER_NAME = "overlap.mode";
public static final String STRANDED_PARAMETER_NAME = "stranded";
public static final String COUNTER_PARAMETER_NAME = "counter";
public static final String GENOMIC_TYPE_PARAMETER_NAME = "genomic.type";
public static final String ATTRIBUTE_ID_PARAMETER_NAME = "attribute.id";
public static final String SPLIT_ATTRIBUTE_VALUES_PARAMETER_NAME =
"split.attribute.values";
public static final String FEATURES_FILE_FORMAT = "features.file.format";
public static final String OLD_REMOVE_AMBIGUOUS_CASES_PARAMETER_NAME =
"removeambiguouscases";
public static final String OLD_OVERLAP_MODE_PARAMETER_NAME = "overlapmode";
public static final String OLD_GENOMIC_TYPE_PARAMETER_NAME = "genomictype";
public static final String OLD_ATTRIBUTE_ID_PARAMETER_NAME = "attributeid";
public static final String OLD_SPLIT_ATTRIBUTE_VALUES_PARAMETER_NAME =
"splitattributevalues";
protected static final String COUNTER_GROUP = "expression";
private static final String DEFAULT_GENOMIC_TYPE = "exon";
private static final String DEFAULT_ATTRIBUTE_ID = "PARENT";
private String genomicType = DEFAULT_GENOMIC_TYPE;
private String attributeId = DEFAULT_ATTRIBUTE_ID;
private String counterName;
private StrandUsage stranded = StrandUsage.NO;
private OverlapMode overlapmode = OverlapMode.UNION;
private boolean removeAmbiguousCases = true;
private boolean splitAttributeValues = false;
private boolean gtfFormat;
//
// Getters
//
/**
* Get the genomic type.
* @return Returns the genomicType
*/
protected String getGenomicType() {
return this.genomicType;
}
/**
* Get the attribute id.
* @return Returns the attribute id
*/
protected String getAttributeId() {
return this.attributeId;
}
/**
* Get the name of the counter to use.
* @return Returns the counterName
*/
protected String getCounterName() {
return this.counterName;
}
/**
* Get the stranded mode.
* @return the stranded mode as a String
*/
protected StrandUsage getStranded() {
return this.stranded;
}
/**
* Get the overlap mode.
* @return the overlap mode as a String
*/
protected OverlapMode getOverlapMode() {
return this.overlapmode;
}
/**
* Get the ambiguous case mode.
* @return the ambiguous case mode
*/
protected boolean isRemoveAmbiguousCases() {
return this.removeAmbiguousCases;
}
/**
* Get the split attribute values mode.
* @return the split attribute values mode
*/
protected boolean isSplitAttributeValues() {
return this.splitAttributeValues;
}
/**
* Get the counter object.
* @return the counter object
*/
protected ExpressionCounter getCounter() {
return ExpressionCounterService.getInstance().newService(this.counterName);
}
/**
* Test if the annotation file format is GTF.
* @return true if the annotation file format is GTF
*/
protected boolean isGTFFormat() {
return this.gtfFormat;
}
//
// Module methods
//
@Override
public String getName() {
return MODULE_NAME;
}
@Override
public String getDescription() {
return "This module compute the expression.";
}
@Override
public Version getVersion() {
return Globals.APP_VERSION;
}
@Override
public InputPorts getInputPorts() {
final InputPortsBuilder builder = new InputPortsBuilder();
builder.addPort("alignments", MAPPER_RESULTS_SAM);
builder.addPort("featuresannotation",
this.gtfFormat ? ANNOTATION_GTF : ANNOTATION_GFF);
builder.addPort("genomedescription", GENOME_DESC_TXT);
return builder.create();
}
@Override
public OutputPorts getOutputPorts() {
return singleOutputPort(EXPRESSION_RESULTS_TSV);
}
@Override
public void configure(final StepConfigurationContext context,
final Set<Parameter> stepParameters) throws EoulsanException {
String counterName = null;
for (Parameter p : stepParameters) {
// Check if the parameter is deprecated
checkDeprecatedParameter(p);
switch (p.getName()) {
case OLD_GENOMIC_TYPE_PARAMETER_NAME:
renamedParameter(context, p, GENOMIC_TYPE_PARAMETER_NAME);
case GENOMIC_TYPE_PARAMETER_NAME:
this.genomicType = p.getStringValue();
break;
case OLD_ATTRIBUTE_ID_PARAMETER_NAME:
renamedParameter(context, p, ATTRIBUTE_ID_PARAMETER_NAME);
case ATTRIBUTE_ID_PARAMETER_NAME:
this.attributeId = p.getStringValue();
break;
case COUNTER_PARAMETER_NAME:
counterName = p.getStringValue();
break;
case STRANDED_PARAMETER_NAME:
this.stranded = StrandUsage.getStrandUsageFromName(p.getStringValue());
if (this.stranded == null) {
Modules.badParameterValue(context, p, "Unknown strand mode");
}
break;
case OLD_OVERLAP_MODE_PARAMETER_NAME:
renamedParameter(context, p, OVERLAP_MODE_PARAMETER_NAME);
case OVERLAP_MODE_PARAMETER_NAME:
this.overlapmode =
OverlapMode.getOverlapModeFromName(p.getStringValue());
if (this.overlapmode == null) {
Modules.badParameterValue(context, p, "Unknown overlap mode");
}
break;
case OLD_REMOVE_AMBIGUOUS_CASES_PARAMETER_NAME:
renamedParameter(context, p, REMOVE_AMBIGUOUS_CASES_PARAMETER_NAME);
case REMOVE_AMBIGUOUS_CASES_PARAMETER_NAME:
this.removeAmbiguousCases = p.getBooleanValue();
break;
case OLD_SPLIT_ATTRIBUTE_VALUES_PARAMETER_NAME:
renamedParameter(context, p, SPLIT_ATTRIBUTE_VALUES_PARAMETER_NAME);
case SPLIT_ATTRIBUTE_VALUES_PARAMETER_NAME:
this.splitAttributeValues = p.getBooleanValue();
break;
case FEATURES_FILE_FORMAT:
switch (p.getLowerStringValue()) {
case "gtf":
this.gtfFormat = true;
break;
case "gff":
case "gff3":
this.gtfFormat = false;
break;
default:
Modules.badParameterValue(context, p,
"Unknown annotation file format");
break;
}
break;
default:
Modules.unknownParameter(context, p);
}
}
if (this.genomicType == null) {
Modules.invalidConfiguration(context, "No parent type set");
}
if (this.attributeId == null) {
Modules.invalidConfiguration(context, "No attribute id set");
}
if (counterName == null) {
counterName = HTSeqCounter.COUNTER_NAME;
}
// Test if counter engine exists
if (ExpressionCounterService.getInstance()
.newService(counterName) == null) {
Modules.invalidConfiguration(context, "Unknown counter: " + counterName);
}
// Set the counter name to use
this.counterName = counterName;
// Configure Checker
if (context.getRuntime().getMode() != EoulsanExecMode.CLUSTER_TASK) {
CheckerModule.configureChecker(
this.gtfFormat ? ANNOTATION_GTF : ANNOTATION_GFF, stepParameters);
}
// Log Step parameters
getLogger().info("In " + getName() + ", counter=" + this.counterName);
getLogger().info("In "
+ getName() + ", stranded=" + this.stranded + ", overlapmode="
+ this.overlapmode);
}
//
// Other methods
//
/**
* Check deprecated parameters.
* @param parameter the parameter to check
* @throws EoulsanException if the parameter is no more supported
*/
private static void checkDeprecatedParameter(final Parameter parameter)
throws EoulsanException {
if (parameter == null) {
return;
}
switch (parameter.getName()) {
case COUNTER_PARAMETER_NAME:
if (OLD_EOULSAN_COUNTER_NAME.toLowerCase()
.equals(parameter.getLowerStringValue())) {
getLogger().warning("The "
+ OLD_EOULSAN_COUNTER_NAME + " counter support has been removed");
}
break;
default:
break;
}
}
}