fr.ens.transcriptome.teolenn.DesignReader.java Source code

Java tutorial

Introduction

Here is the source code for fr.ens.transcriptome.teolenn.DesignReader.java

Source

/*
 *                  Teolenn development code
 *
 * This code may be freely distributed and modified under the
 * terms of the GNU General Public License version 2 or later. This
 * should be distributed with the code. If you do not have a copy,
 * see:
 *
 *      http://www.gnu.org/licenses/gpl-2.0.txt
 *
 * Copyright for this code is held jointly by the microarray platform
 * of the cole Normale Suprieure and the individual authors.
 * These should be listed in @author doc comments.
 *
 * For more information on the Teolenn project and its aims,
 * or to join the Teolenn Google group, visit the home page
 * at:
 *
 *      http://www.transcriptome.ens.fr/teolenn
 *
 */

package fr.ens.transcriptome.teolenn;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Logger;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import fr.ens.transcriptome.teolenn.measurement.ChromosomeMeasurement;
import fr.ens.transcriptome.teolenn.measurement.Measurement;
import fr.ens.transcriptome.teolenn.measurement.MeasurementRegistery;
import fr.ens.transcriptome.teolenn.measurement.OligoLengthMeasurement;
import fr.ens.transcriptome.teolenn.measurement.OligoStartMeasurement;
import fr.ens.transcriptome.teolenn.measurement.filter.MeasurementFilter;
import fr.ens.transcriptome.teolenn.measurement.filter.MeasurementFilterRegistery;
import fr.ens.transcriptome.teolenn.output.DefaultOutput;
import fr.ens.transcriptome.teolenn.output.Output;
import fr.ens.transcriptome.teolenn.output.OutputRegistery;
import fr.ens.transcriptome.teolenn.selector.SequenceSelector;
import fr.ens.transcriptome.teolenn.selector.SequenceSelectorRegistery;
import fr.ens.transcriptome.teolenn.sequence.SequenceMeasurements;
import fr.ens.transcriptome.teolenn.sequence.filter.SequenceFilter;
import fr.ens.transcriptome.teolenn.sequence.filter.SequenceFilterRegistery;

/**
 * Tis class allow to read the design file.
 * @author Laurent Jourdren
 */
public class DesignReader {

    private static Logger logger = Logger.getLogger(Globals.APP_NAME);

    private DesignCommand design;
    private Properties constants;

    /**
     * Read the design file and run the design
     * @param designFile The design file
     * @param genomeFile The genome file
     * @param genomeMaskedFile The genome masked file
     * @param outputDir The output dir
     * @throws TeolennException if an error occurs while computing the design
     * @throws IOException if an error occurs while reading the design file
     * @throws DocumentException if an error occurs while parsing the design file
     */
    public void readDesign(final File designFile, final File genomeFile, final File genomeMaskedFile,
            File outputDir) throws TeolennException, IOException, DocumentException {

        this.design = new DesignCommand();
        this.constants = new Properties();

        logger.info(Globals.APP_NAME + " version " + Globals.APP_VERSION + " (" + Globals.APP_BUILD_NUMBER + " "
                + Globals.APP_BUILD_DATE + ")");

        SAXReader saxReader = new SAXReader();
        Document document = saxReader.read(new FileReader(designFile));

        Element root = document.getRootElement();
        Element designElement = root;

        double designFileVersion = 0.0;
        for (Iterator i1 = designElement.elementIterator("formatversion"); i1.hasNext();)
            designFileVersion = Double.parseDouble(((Element) i1.next()).getTextTrim());

        if (designFileVersion != Globals.DESIGN_FILE_VERSION) {
            System.err.println("Invalid version of your " + Globals.APP_NAME + " design file.");
            System.exit(1);
        }

        // constants element
        this.constants = getElementConstants(designElement);

        for (Iterator i2 = designElement.elementIterator("startposition"); i2.hasNext();) {

            final String sp = ((Element) i2.next()).getTextTrim();
            if ("1".equals(sp))
                this.design.setStart1(true);
            else
                this.design.setStart1(false);
        }
        setConstant("startPosition", "" + this.design.isStart1());

        // oligolength element
        for (Iterator i3 = designElement.elementIterator("oligolength"); i3.hasNext();)
            this.design.setOligoLength(Integer.parseInt(getValue(i3)));
        setConstant("oligolength", "" + this.design.getOligoLength());

        // oligoIntervallength element
        for (Iterator i4 = designElement.elementIterator("oligointervallength"); i4.hasNext();)
            this.design.setOligoIntervalLength(Integer.parseInt(getValue(i4)));
        setConstant("oligointervallength", "" + this.design.getOligoIntervalLength());

        // genomefile element
        if (genomeFile != null)
            this.design.setGenomeFile(genomeFile);
        else
            for (Iterator i5 = designElement.elementIterator("genomefile"); i5.hasNext();)
                this.design.setGenomeFile(new File(getValue(i5)));
        setConstant("genomefile", "" + this.design.getGenomeFile().getAbsolutePath());

        // genomemakedfile element
        if (genomeMaskedFile != null)
            this.design.setGenomeMaskedFile(genomeMaskedFile);
        else
            for (Iterator i6 = designElement.elementIterator("genomemaskedfile"); i6.hasNext();) {
                final String filename = getValue(i6);
                if (!"".equals(filename))
                    this.design.setGenomeMaskedFile(new File(filename));
            }
        setConstant("genomemaskedfile", "" + this.design.getGenomeMaskedFile().getAbsolutePath());

        // outputdir element
        if (outputDir != null)
            this.design.setOutputDir(outputDir);
        else
            for (Iterator i7 = designElement.elementIterator("outputdir"); i7.hasNext();) {
                final String path = getValue(i7);
                if (!"".equals(path))
                    this.design.setOutputDir((new File(path)).getCanonicalFile());
            }
        setConstant("outputdir", "" + this.design.getOutputDir().getAbsolutePath());

        if (this.design.getGenomeFile() == null || !this.design.getGenomeFile().isFile())
            throw new InvalidParameterException("genome file is not found"
                    + (this.design.getGenomeFile() == null ? "." : ": " + this.design.getGenomeFile()));

        if (this.design.getGenomeMaskedFile() != null && !this.design.getGenomeMaskedFile().isFile())
            throw new InvalidParameterException("genome masked file is not found"
                    + (this.design.getGenomeMaskedFile() == null ? "." : ": " + this.design.getGenomeMaskedFile()));

        // Test the validity of the outptdir
        if (this.design.getOutputDir() == null || !this.design.getOutputDir().isDirectory())
            throw new InvalidParameterException("output directory is not found"
                    + (this.design.getOutputDir() == null ? "." : ": " + this.design.getOutputDir()));

        isSkipElementEnable(designElement, "sequencefilters");

        final DesignCommand d = design;

        // Test if phases must be skipped
        d.setSkipSequenceCreation(isSkipElementEnable(designElement, "sequencecreation"));
        d.setSkipSequenceFilters(isSkipElementEnable(designElement, "sequencefilters"));
        d.setSkipMeasurementsComputation(isSkipElementEnable(designElement, "measurements"));
        d.setSkipMeasurementsFilters(isSkipElementEnable(designElement, "measurementfilters"));
        d.setSkipSelector(isSkipElementEnable(designElement, "selector"));

        // Set the sequenceFilters
        d.setSequenceFiltersList(parseSequenceFilters(designElement));

        // Set the measurements
        d.setMeasurementsList(parseMeasurements(designElement));

        // Set the measurement filters
        d.setMeasurementFiltersList(parseMeasurementFilters(designElement));

        // Set the selector
        d.setSelector(parseSelector(designElement));

        // Set the weights
        d.setWeightSetters(parseSelectWeights(designElement));

        // Set the outputs
        d.setOutputsList(parseOutput(designElement));

    }

    /**
     * Set a constant.
     * @param constantName Name of the constant
     * @param constantValue Value of the constant
     */
    private void setConstant(final String constantName, final String constantValue) {

        this.constants.setProperty(constantName, constantValue);
    }

    private String getValue(final Iterator i) {

        return getValue((Element) i.next());
    }

    private String getValue(final Element e) {

        if (e == null)
            return "";

        return getValue(e.getTextTrim());
    }

    private String getValue(final String s) {

        if (s.startsWith("${") && s.endsWith("}")) {

            final String constantName = s.substring(2, s.length() - 1);
            if (this.constants.containsKey(constantName))
                return this.constants.getProperty(constantName);
        }

        return s;
    }

    /**
     * Parse the "sequencefilters" element of the DOM.
     * @param rootElement root element of the document
     * @return a list of SequenceFilter objects
     * @throws IOException if an error occurs while parsing
     */
    private List<SequenceFilter> parseSequenceFilters(final Element rootElement) throws IOException {

        List<SequenceFilter> list = new ArrayList<SequenceFilter>();

        for (Iterator i = rootElement.elementIterator("sequencefilters"); i.hasNext();) {
            final Element filters = (Element) i.next();

            for (Iterator i2 = filters.elementIterator("sequencefilter"); i2.hasNext();) {
                final Element filter = (Element) i2.next();

                String filterName = null;

                for (Iterator i3 = filter.elementIterator("name"); i3.hasNext();) {
                    final Element name = (Element) i3.next();
                    filterName = name.getTextTrim();
                }

                if (filterName == null) {
                    logger.warning("Filter without name.");
                    continue;
                }

                // Add the sequence filter to the registery if it is a plug in
                for (Iterator i4 = filter.elementIterator("class"); i4.hasNext();) {
                    final Element clazz = (Element) i4.next();
                    String filterClass = clazz.getTextTrim();
                    SequenceFilterRegistery.addSequenceFilterType(filterName, filterClass);
                }

                // Get the parameters of the sequenceFilter
                final Properties properties = getElementParameters(filter);
                final SequenceFilter f = SequenceFilterRegistery.getSequenceFilter(filterName);

                if (f == null)
                    logger.warning("Unknown sequence filter: " + filterName);
                else {

                    for (Map.Entry<Object, Object> entry : properties.entrySet())
                        // Set the initialization parameters for the sequence filter
                        f.setInitParameter((String) entry.getKey(), (String) entry.getValue());

                    list.add(f);
                }
            }

        }

        // Set the defaults initialization parameters of the sequence filters
        for (SequenceFilter sq : list)
            this.design.setDefaultModuleInitParameters(sq);

        return list;
    }

    /**
     * Parse the "measurements" element of the DOM.
     * @param rootElement root element of the document
     * @return a list of Measurement objects
     * @throws IOException if an error occurs while parsing
     */
    private List<Measurement> parseMeasurements(final Element rootElement) throws IOException {

        final List<Measurement> list = new ArrayList<Measurement>();

        list.add(new ChromosomeMeasurement());
        list.add(new OligoStartMeasurement());
        list.add(new OligoLengthMeasurement());

        for (Iterator i = rootElement.elementIterator("measurements"); i.hasNext();) {
            final Element measurements = (Element) i.next();

            for (Iterator i2 = measurements.elementIterator("measurement"); i2.hasNext();) {
                final Element measurement = (Element) i2.next();

                String measurementName = null;

                for (Iterator i3 = measurement.elementIterator("name"); i3.hasNext();) {
                    final Element name = (Element) i3.next();
                    measurementName = name.getTextTrim();
                }

                if (measurementName == null) {
                    logger.warning("Measurement without name.");
                    continue;
                }

                // Skip if user attempt to add another Scaffold measurement
                if (ChromosomeMeasurement.MEASUREMENT_NAME.toLowerCase().equals(measurementName.toLowerCase()))
                    continue;

                // Skip if user attempt to add another oligo start measurement
                if (OligoStartMeasurement.MEASUREMENT_NAME.toLowerCase().equals(measurementName.toLowerCase()))
                    continue;

                // Add the measurement to registery if it is a plug in
                for (Iterator i4 = measurement.elementIterator("class"); i4.hasNext();) {
                    final Element clazz = (Element) i4.next();
                    String measurementClass = clazz.getTextTrim();
                    MeasurementRegistery.addMeasurementType(measurementName, measurementClass);
                }

                // Get the parameters of the measurement
                final Properties properties = getElementParameters(measurement);

                final Measurement m = MeasurementRegistery.getMeasurement(measurementName);
                if (m == null)
                    logger.warning("Unknown measurement: " + measurementName);
                else {

                    // Set the initialization parameters for the measurement
                    for (Map.Entry<Object, Object> entry : properties.entrySet())
                        m.setInitParameter((String) entry.getKey(), (String) entry.getValue());

                    list.add(m);
                }
            }

        }

        // Set the default initialization parameters of the measurements
        for (Measurement m : list)
            this.design.setDefaultModuleInitParameters(m);

        return list;
    }

    /**
     * Parse the "measurementfilters" element of the DOM.
     * @param rootElement root element of the document
     * @return a list of MeasurementFilter objects
     * @throws IOException if an error occurs while parsing
     */
    private List<MeasurementFilter> parseMeasurementFilters(final Element rootElement) throws IOException {

        final List<MeasurementFilter> list = new ArrayList<MeasurementFilter>();

        for (Iterator i = rootElement.elementIterator("measurementfilters"); i.hasNext();) {
            final Element filters = (Element) i.next();

            for (Iterator i2 = filters.elementIterator("measurementfilter"); i2.hasNext();) {
                final Element filter = (Element) i2.next();

                String measurementFilterName = null;

                for (Iterator i3 = filter.elementIterator("name"); i3.hasNext();) {
                    final Element name = (Element) i3.next();
                    measurementFilterName = name.getTextTrim();
                }

                if (measurementFilterName == null) {
                    logger.warning("Measurement filter without name.");
                    continue;
                }

                // Add the measurement to registery if it is a plug in
                for (Iterator i4 = filter.elementIterator("class"); i4.hasNext();) {
                    final Element clazz = (Element) i4.next();
                    String measurementClass = clazz.getTextTrim();
                    MeasurementFilterRegistery.addMeasurementFilterType(measurementFilterName, measurementClass);
                }

                // Get the parameters of the measurement filters
                final Properties properties = getElementParameters(filter);

                final MeasurementFilter mf = MeasurementFilterRegistery
                        .getMeasuremrentFilter(measurementFilterName);
                if (mf == null)
                    logger.warning("Unknown measurement: " + measurementFilterName);
                else {

                    // Set the initialization parameters for the measurement filters
                    for (Map.Entry<Object, Object> entry : properties.entrySet())
                        mf.setInitParameter((String) entry.getKey(), (String) entry.getValue());

                    list.add(mf);
                }
            }

        }

        // Set the defaults initialization parameters of the measurements filters
        for (MeasurementFilter mf : list)
            this.design.setDefaultModuleInitParameters(mf);

        return list;
    }

    /**
     * Parse the "selector" element of the DOM.
     * @param rootElement root element of the document
     * @return a selector objects
     * @throws TeolennException if an error occurs while parsing
     */
    private SequenceSelector parseSelector(final Element rootElement) throws TeolennException {

        for (Iterator i = rootElement.elementIterator("selector"); i.hasNext();) {

            final Element selector = (Element) i.next();

            String selectorName = null;

            for (Iterator i1 = selector.elementIterator("name"); i1.hasNext();) {
                final Element name = (Element) i1.next();
                selectorName = name.getTextTrim();
            }

            // Add the selector to registery if it is a plug in
            for (Iterator i2 = selector.elementIterator("class"); i2.hasNext();) {
                final Element clazz = (Element) i2.next();
                String selectorClass = clazz.getTextTrim();
                SequenceSelectorRegistery.addSequenceSelectorType(selectorName, selectorClass);
            }

            // Get the parameters of the measurement
            final Properties properties = getElementParameters(selector);

            SequenceSelector s = SequenceSelectorRegistery.getSequenceSelector(selectorName);

            if (s == null) {
                logger.warning("Unknown selector: " + selectorName);
                throw new TeolennException("Unknown selector: " + selectorName);
            }

            // Set the initialization parameters for the selector
            for (Map.Entry<Object, Object> entry : properties.entrySet())
                s.setInitParameter((String) entry.getKey(), (String) entry.getValue());

            // Set defaults parameters
            this.design.setDefaultModuleInitParameters(s);

            return s;
        }

        throw new TeolennException("No selector found.");
    }

    /**
     * Parse the "select" element of the DOM.
     * @param rootElement root element of the document
     * @return a list of weights objects
     * @throws IOException if an error occurs while parsing
     */
    private WeightsSetter parseSelectWeights(final Element rootElement) throws IOException {

        // Map of weights
        final Map<String, Float> selectWeights = new HashMap<String, Float>();

        // Map of properties
        final Map<String, Properties> selectProperties = new HashMap<String, Properties>();

        for (Iterator i = rootElement.elementIterator("selector"); i.hasNext();) {
            final Element select = (Element) i.next();

            for (Iterator i2 = select.elementIterator("measurement"); i2.hasNext();) {
                final Element measurement = (Element) i2.next();

                String measurementName = null;
                String measurementWeight = null;

                for (Iterator i3 = measurement.elementIterator("name"); i3.hasNext();) {
                    final Element name = (Element) i3.next();
                    measurementName = name.getTextTrim();
                }

                if (measurementName == null) {
                    logger.warning("Measurement without name.");
                    continue;
                }

                // Get the weight for the measurement
                for (Iterator i4 = measurement.elementIterator("weight"); i4.hasNext();) {
                    final Element weight = (Element) i4.next();
                    measurementWeight = weight.getTextTrim();
                }

                try {
                    selectWeights.put(measurementName, Float.parseFloat(measurementWeight));
                } catch (NumberFormatException e) {
                    logger.warning("Invalid " + measurementName + " weight: " + measurementWeight);
                }

                // Get the properties of the measurement
                selectProperties.put(measurementName, getElementParameters(measurement));
            }
        }

        return new WeightsSetter() {

            @Override
            public void setWeights(SequenceMeasurements sm) {

                // Set the weights
                for (Map.Entry<String, Float> e : selectWeights.entrySet())
                    sm.setWeight(sm.getMeasurement(e.getKey()), e.getValue());

                // Set the properties
                for (Map.Entry<String, Properties> e : selectProperties.entrySet()) {

                    final String name = e.getKey();
                    final Properties properties = e.getValue();

                    if (!sm.isMeasurement(name)) {
                        logger.warning("Unknown measurement: " + name);
                        continue;
                    }

                    for (Map.Entry<Object, Object> e2 : properties.entrySet()) {

                        sm.getMeasurement(name).setProperty((String) e2.getKey(), (String) e2.getValue());

                    }
                }
            }
        };

    }

    /**
     * Parse the "output" element of the DOM.
     * @param rootElement root element of the document
     * @return a selector objects
     * @throws TeolennException if an error occurs while parsing
     */
    private List<Output> parseOutput(final Element rootElement) throws TeolennException {

        List<Output> list = new ArrayList<Output>();

        for (Iterator i = rootElement.elementIterator("outputs"); i.hasNext();) {

            final Element outputs = (Element) i.next();

            for (Iterator i1 = outputs.elementIterator("output"); i1.hasNext();) {

                final Element output = (Element) i1.next();

                String selectorName = null;

                for (Iterator i2 = output.elementIterator("name"); i2.hasNext();) {
                    final Element name = (Element) i2.next();
                    selectorName = name.getTextTrim();
                }

                // Add the selector to registery if it is a plug in
                for (Iterator i3 = output.elementIterator("class"); i3.hasNext();) {
                    final Element clazz = (Element) i3.next();
                    String outputClass = clazz.getTextTrim();
                    OutputRegistery.addOutputType(selectorName, outputClass);
                }

                // Get the parameters of the measurement
                final Properties properties = getElementParameters(output);

                Output o = OutputRegistery.getOutput(selectorName);

                if (output == null) {
                    logger.warning("Unknown output: " + selectorName);
                    throw new TeolennException("Unknown output: " + selectorName);
                }

                // Set the initialization parameters for the selector
                for (Map.Entry<Object, Object> entry : properties.entrySet())
                    o.setInitParameter((String) entry.getKey(), (String) entry.getValue());

                list.add(o);
            }
        }

        if (list.size() == 0)
            list.add(new DefaultOutput());

        // Set the default initialization parameters of the outputs
        for (Output o : list)
            this.design.setDefaultModuleInitParameters(o);

        return list;
    }

    /**
     * Get the parameter of an element
     * @param element Element to parse
     * @return a Properties object with the name and values of the parameters
     */
    private final Properties getElementParameters(final Element element) {

        final Properties result = new Properties();

        for (Iterator i4 = element.elementIterator("parameters"); i4.hasNext();) {
            final Element params = (Element) i4.next();

            for (Iterator i5 = params.elementIterator("parameter"); i5.hasNext();) {
                final Element param = (Element) i5.next();

                String pKey = null;
                String pValue = null;

                for (Iterator i6 = param.elementIterator("name"); i6.hasNext();) {
                    final Element name = (Element) i6.next();
                    pKey = name.getTextTrim().toLowerCase();
                }

                for (Iterator i7 = param.elementIterator("value"); i7.hasNext();) {
                    final Element value = (Element) i7.next();
                    pValue = getValue(value.getTextTrim());
                }

                if (pKey != null && pValue != null)
                    result.setProperty(pKey, pValue);
            }

        }

        return result;
    }

    /**
     * Get the constants
     * @param element Element to parse
     * @return a Properties object with the name and values of the parameters
     */
    private final Properties getElementConstants(final Element element) {

        final Properties result = new Properties();

        for (Iterator i4 = element.elementIterator("constants"); i4.hasNext();) {
            final Element params = (Element) i4.next();

            for (Iterator i5 = params.elementIterator("constant"); i5.hasNext();) {
                final Element param = (Element) i5.next();

                String pKey = null;
                String pValue = null;

                for (Iterator i6 = param.elementIterator("name"); i6.hasNext();) {
                    final Element name = (Element) i6.next();
                    pKey = name.getTextTrim().toLowerCase();
                }

                for (Iterator i7 = param.elementIterator("value"); i7.hasNext();) {
                    final Element value = (Element) i7.next();
                    pValue = value.getTextTrim();

                }

                if (pKey != null || pValue != null)
                    result.setProperty(pKey, pValue);
            }

        }

        return result;
    }

    /**
     * Test if the phase of the element must be skipped.
     * @param rootElement DOM root element
     * @param elementName Name of the tag to test
     * @return true if the phase of the element must be skipped
     */
    private final boolean isSkipElementEnable(final Element rootElement, final String elementName) {

        boolean result = false;

        for (Iterator i = rootElement.elementIterator(elementName); i.hasNext();) {
            final Element e = (Element) i.next();

            final String value = e.attributeValue("skip");
            if (value == null)
                return false;

            result = Boolean.parseBoolean(value.trim());
        }

        return result;
    }

    /**
     * Get the read design.
     * @return a design object
     */
    public DesignCommand getDesign() {

        return this.design;
    }

}