gov.nih.nci.caarray.application.translation.magetab.MageTabExporterBean.java Source code

Java tutorial

Introduction

Here is the source code for gov.nih.nci.caarray.application.translation.magetab.MageTabExporterBean.java

Source

//======================================================================================
// Copyright 5AM Solutions Inc, Yale University
//
// Distributed under the OSI-approved BSD 3-Clause License.
// See http://ncip.github.com/caarray/LICENSE.txt for details.
//======================================================================================
package gov.nih.nci.caarray.application.translation.magetab;

import gov.nih.nci.caarray.domain.contact.AbstractContact;
import gov.nih.nci.caarray.domain.contact.Organization;
import gov.nih.nci.caarray.domain.contact.Person;
import gov.nih.nci.caarray.domain.data.AbstractArrayData;
import gov.nih.nci.caarray.domain.data.DerivedArrayData;
import gov.nih.nci.caarray.domain.data.RawArrayData;
import gov.nih.nci.caarray.domain.file.CaArrayFile;
import gov.nih.nci.caarray.domain.file.FileType;
import gov.nih.nci.caarray.domain.hybridization.Hybridization;
import gov.nih.nci.caarray.domain.project.Experiment;
import gov.nih.nci.caarray.domain.project.ExperimentOntologyCategory;
import gov.nih.nci.caarray.domain.sample.AbstractBioMaterial;
import gov.nih.nci.caarray.domain.sample.AbstractCharacteristic;
import gov.nih.nci.caarray.domain.sample.Extract;
import gov.nih.nci.caarray.domain.sample.LabeledExtract;
import gov.nih.nci.caarray.domain.sample.MeasurementCharacteristic;
import gov.nih.nci.caarray.domain.sample.Sample;
import gov.nih.nci.caarray.domain.sample.Source;
import gov.nih.nci.caarray.domain.sample.TermBasedCharacteristic;
import gov.nih.nci.caarray.domain.sample.UserDefinedCharacteristic;
import gov.nih.nci.caarray.domain.vocabulary.Category;
import gov.nih.nci.caarray.domain.vocabulary.Term;
import gov.nih.nci.caarray.magetab.MageTabDocumentSet;
import gov.nih.nci.caarray.magetab.MageTabFileSet;
import gov.nih.nci.caarray.magetab.OntologyTerm;
import gov.nih.nci.caarray.magetab.TermSource;
import gov.nih.nci.caarray.magetab.idf.IdfDocument;
import gov.nih.nci.caarray.magetab.idf.Investigation;
import gov.nih.nci.caarray.magetab.io.JavaIOFileRef;
import gov.nih.nci.caarray.magetab.sdrf.AbstractSampleDataRelationshipNode;
import gov.nih.nci.caarray.magetab.sdrf.ArrayDataFile;
import gov.nih.nci.caarray.magetab.sdrf.ArrayDataMatrixFile;
import gov.nih.nci.caarray.magetab.sdrf.Characteristic;
import gov.nih.nci.caarray.magetab.sdrf.DerivedArrayDataFile;
import gov.nih.nci.caarray.magetab.sdrf.DerivedArrayDataMatrixFile;
import gov.nih.nci.caarray.magetab.sdrf.Provider;
import gov.nih.nci.caarray.magetab.sdrf.SdrfDocument;
import gov.nih.nci.caarray.magetab.sdrf.SdrfDocumentNodes;
import gov.nih.nci.caarray.util.io.logging.LogUtil;

import java.io.File;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import javax.ejb.Local;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

/**
 * Exports an Experiment into MAGE-TAB format. An IDF file and an SDRF file are generated.
 * 
 * @author Rashmi Srinivasa
 */
@Local(MageTabExporter.class)
@Stateless
@SuppressWarnings("PMD.CyclomaticComplexity")
public class MageTabExporterBean implements MageTabExporter {
    private static final Logger LOG = Logger.getLogger(MageTabExporterBean.class);

    // Generated SDRF nodes
    private final Set<gov.nih.nci.caarray.magetab.sdrf.Source> allSources = new HashSet<gov.nih.nci.caarray.magetab.sdrf.Source>();
    private final Set<gov.nih.nci.caarray.magetab.sdrf.Sample> allSamples = new HashSet<gov.nih.nci.caarray.magetab.sdrf.Sample>();
    private final Set<gov.nih.nci.caarray.magetab.sdrf.Extract> allExtracts = new HashSet<gov.nih.nci.caarray.magetab.sdrf.Extract>();
    private final Set<gov.nih.nci.caarray.magetab.sdrf.LabeledExtract> allLabeledExtracts = new HashSet<gov.nih.nci.caarray.magetab.sdrf.LabeledExtract>();
    private final Set<gov.nih.nci.caarray.magetab.sdrf.Hybridization> allHybridizations = new HashSet<gov.nih.nci.caarray.magetab.sdrf.Hybridization>();
    private final Set<ArrayDataFile> allArrayDataFiles = new HashSet<ArrayDataFile>();
    private final Set<DerivedArrayDataFile> allDerivedArrayDataFiles = new HashSet<DerivedArrayDataFile>();
    private final Set<ArrayDataMatrixFile> allArrayDataMatrixFiles = new HashSet<ArrayDataMatrixFile>();
    private final Set<DerivedArrayDataMatrixFile> allDerivedArrayDataMatrixFiles = new HashSet<DerivedArrayDataMatrixFile>();

    // Temporary caches
    private final Map<NodeKey, AbstractSampleDataRelationshipNode> nodeCache = new HashMap<NodeKey, AbstractSampleDataRelationshipNode>();
    private final Map<Term, OntologyTerm> termMap = new HashMap<Term, OntologyTerm>();
    private final Map<gov.nih.nci.caarray.domain.vocabulary.TermSource, TermSource> termSourceMap = new HashMap<gov.nih.nci.caarray.domain.vocabulary.TermSource, TermSource>();

    /**
     * {@inheritDoc}
     */
    @Override
    @TransactionAttribute(TransactionAttributeType.SUPPORTS)
    public MageTabDocumentSet exportToMageTab(Experiment experiment, File idfFile, File sdrfFile) {
        LogUtil.logSubsystemEntry(LOG, experiment);

        final MageTabFileSet fileSet = new MageTabFileSet();
        fileSet.addIdf(new JavaIOFileRef(idfFile));
        fileSet.addSdrf(new JavaIOFileRef(sdrfFile));

        // Translate caArray domain object graph into MAGE-TAB object graph, and new_JavaIOFileRef MAGE-TAB documents.
        final MageTabDocumentSet mageTabDocumentSet = translateToMageTab(experiment, fileSet);

        // Ask the MAGE-TAB documents to export themselves into their respective files.
        mageTabDocumentSet.export();

        // Clear private caches.
        this.nodeCache.clear();
        this.termMap.clear();
        this.termSourceMap.clear();
        this.allSources.clear();
        this.allSamples.clear();
        this.allExtracts.clear();
        this.allLabeledExtracts.clear();
        this.allHybridizations.clear();
        this.allArrayDataFiles.clear();
        this.allDerivedArrayDataFiles.clear();
        this.allArrayDataMatrixFiles.clear();
        this.allDerivedArrayDataMatrixFiles.clear();

        LogUtil.logSubsystemExit(LOG);
        return mageTabDocumentSet;
    }

    /**
     * Takes an Experiment and constructs a MAGE-TAB IDF and SDRF describing the sample-data relationships and
     * annotations.
     * 
     * @param experiment the experiment whose contents need to be translated into MAGE-TAB.
     * @return a MAGE-TAB SDRF.
     */
    private MageTabDocumentSet translateToMageTab(Experiment experiment, MageTabFileSet fileSet) {
        final MageTabDocumentSet mageTabDocumentSet = new MageTabDocumentSet(fileSet);
        final IdfDocument idfDocument = mageTabDocumentSet.getIdfDocuments().iterator().next();
        final SdrfDocument sdrfDocument = mageTabDocumentSet.getSdrfDocuments().iterator().next();

        // Create the IDF elements.
        translateIdfElements(experiment, idfDocument);

        // Create the SDRF elements.
        translateSdrfElements(experiment, sdrfDocument);

        // Add terms and term sources to the document set.
        mageTabDocumentSet.getTerms().addAll(this.termMap.values());
        for (final TermSource termSource : this.termSourceMap.values()) {
            final String name = termSource.getName();
            mageTabDocumentSet.getTermSourceMap().put(name, termSource);
        }

        // Link the IDF and SDRF documents together.
        idfDocument.getSdrfDocuments().add(sdrfDocument);
        sdrfDocument.setIdfDocument(idfDocument);

        return mageTabDocumentSet;
    }

    private void translateIdfElements(Experiment experiment, IdfDocument idfDocument) {
        final Investigation investigation = idfDocument.getInvestigation();
        investigation.setTitle(experiment.getTitle());
        investigation.setDescription(experiment.getDescription());
        // TODO Translate other IDF elements.
    }

    private void translateSdrfElements(Experiment experiment, SdrfDocument sdrfDocument) {
        // Translate caArray domain biomaterial-data chains into MAGE-TAB biomaterial-data chains.
        for (final Source source : experiment.getSources()) {
            final AbstractSampleDataRelationshipNode sdrfSource = getOrCreateNode(source);
            addBiomaterialAttributes(source, (gov.nih.nci.caarray.magetab.sdrf.Source) sdrfSource);
            addSourceAttributes(source, sdrfSource);
            handleSamples(source, sdrfSource);
        }

        // Initialize the SDRF document with all the object graph nodes.
        final SdrfDocumentNodes sdrfDocumentNodes = new SdrfDocumentNodes();
        sdrfDocumentNodes.initNonDataNodes(this.allSources, this.allSamples, this.allExtracts,
                this.allLabeledExtracts, this.allHybridizations);
        sdrfDocumentNodes.initDataNodes(this.allArrayDataFiles, this.allArrayDataMatrixFiles,
                this.allDerivedArrayDataFiles, this.allDerivedArrayDataMatrixFiles);
        sdrfDocument.initializeNodes(sdrfDocumentNodes);

        // TODO Translate other SDRF elements, i.e., protocols, experimental factors.
    }

    private void addSourceAttributes(Source source, AbstractSampleDataRelationshipNode sdrfNode) {
        final gov.nih.nci.caarray.magetab.sdrf.Source sdrfSource = (gov.nih.nci.caarray.magetab.sdrf.Source) sdrfNode;

        // Set providers.
        for (final AbstractContact contact : source.getProviders()) {
            if (contact.getClass() == Organization.class) {
                final Organization org = (Organization) contact;
                final Provider provider = new Provider();
                provider.setName(org.getName());
                sdrfSource.getProviders().add(provider);
            } else if (contact.getClass() == Person.class) {
                final Person person = (Person) contact;
                final Provider provider = new Provider();
                provider.setName(person.getLastName());
                sdrfSource.getProviders().add(provider);
            }
        }
    }

    private void addBiomaterialAttributes(AbstractBioMaterial biomaterial,
            gov.nih.nci.caarray.magetab.sdrf.AbstractBioMaterial sdrfBiomaterial) {
        // Set material type.
        final Term term = biomaterial.getMaterialType();
        if (term != null) {
            final OntologyTerm sdrfTerm = getSdrfTerm(term);
            sdrfBiomaterial.setMaterialType(sdrfTerm);
        }

        // Set all other characteristics.
        addPredefinedCharacteristics(biomaterial, sdrfBiomaterial);
        for (final AbstractCharacteristic characteristic : biomaterial.getCharacteristics()) {
            final String category = characteristic.getCategory().getName();
            final Characteristic sdrfCharacteristic = new Characteristic();
            if (characteristic instanceof TermBasedCharacteristic) {
                final Term characteristicTerm = ((TermBasedCharacteristic) characteristic).getTerm();
                final OntologyTerm sdrfTerm = getSdrfTerm(characteristicTerm);
                sdrfCharacteristic.setTerm(sdrfTerm);
            } else if (characteristic instanceof MeasurementCharacteristic) {
                final float value = ((MeasurementCharacteristic) characteristic).getValue();
                sdrfCharacteristic.setValue(Float.toString(value));
            } else {
                sdrfCharacteristic.setValue(((UserDefinedCharacteristic) characteristic).getValue());
            }
            sdrfCharacteristic.setCategory(category);
            final OntologyTerm sdrfUnit = getSdrfTerm(characteristic.getUnit());
            sdrfCharacteristic.setUnit(sdrfUnit);
            sdrfBiomaterial.getCharacteristics().add(sdrfCharacteristic);
        }
        if (StringUtils.isNotEmpty(biomaterial.getExternalId())) {
            final Characteristic sdrfCharacteristic = new Characteristic();
            sdrfCharacteristic.setCategory(ExperimentOntologyCategory.EXTERNAL_ID.getCategoryName());
            sdrfCharacteristic.setValue(biomaterial.getExternalId());
            sdrfBiomaterial.getCharacteristics().add(sdrfCharacteristic);
        }
        // TODO Organism and ProtocolApplications
    }

    private void addPredefinedCharacteristics(AbstractBioMaterial biomaterial,
            gov.nih.nci.caarray.magetab.sdrf.AbstractBioMaterial sdrfBiomaterial) {
        Term term;
        OntologyTerm sdrfTerm;
        term = biomaterial.getDiseaseState();
        if (term != null) {
            sdrfTerm = getSdrfTerm(term);
            final Characteristic sdrfTermBasedCharacteristic = createSdrfTermBasedCharacteristic(
                    ExperimentOntologyCategory.DISEASE_STATE.getCategoryName(), sdrfTerm);
            sdrfBiomaterial.getCharacteristics().add(sdrfTermBasedCharacteristic);
        }
        term = biomaterial.getCellType();
        if (term != null) {
            sdrfTerm = getSdrfTerm(term);
            final Characteristic sdrfTermBasedCharacteristic = createSdrfTermBasedCharacteristic(
                    ExperimentOntologyCategory.CELL_TYPE.getCategoryName(), sdrfTerm);
            sdrfBiomaterial.getCharacteristics().add(sdrfTermBasedCharacteristic);
        }
        term = biomaterial.getTissueSite();
        if (term != null) {
            sdrfTerm = getSdrfTerm(term);
            final Characteristic sdrfTermBasedCharacteristic = createSdrfTermBasedCharacteristic(
                    ExperimentOntologyCategory.ORGANISM_PART.getCategoryName(), sdrfTerm);
            sdrfBiomaterial.getCharacteristics().add(sdrfTermBasedCharacteristic);
        }
    }

    private Characteristic createSdrfTermBasedCharacteristic(String category, OntologyTerm sdrfTerm) {
        final Characteristic sdrfCharacteristic = new Characteristic();
        sdrfCharacteristic.setCategory(category);
        sdrfCharacteristic.setTerm(sdrfTerm);
        return sdrfCharacteristic;
    }

    private OntologyTerm getSdrfTerm(Term term) {
        if (term == null) {
            return null;
        }
        OntologyTerm sdrfTerm = this.termMap.get(term);
        if (sdrfTerm == null) {
            sdrfTerm = createSdrfTerm(term);
        }
        return sdrfTerm;
    }

    private OntologyTerm createSdrfTerm(Term term) {
        final OntologyTerm sdrfTerm = new OntologyTerm();
        sdrfTerm.setValue(term.getValue());
        if (!(term.getCategories().isEmpty())) {
            sdrfTerm.setCategory(term.getCategories().iterator().next().getName());
        }
        final TermSource sdrfTermSource = getSdrfTermSource(term);
        sdrfTerm.setTermSource(sdrfTermSource);
        this.termMap.put(term, sdrfTerm);
        return sdrfTerm;
    }

    private TermSource getSdrfTermSource(Term term) {
        gov.nih.nci.caarray.domain.vocabulary.TermSource termSource = term.getSource();
        // If the term doesn't have a source, get the term's category's source.
        if ((termSource == null) && (!(term.getCategories().isEmpty()))) {
            final Iterator<Category> iterator = term.getCategories().iterator();
            if (iterator.hasNext()) {
                termSource = iterator.next().getSource();
            }
        }
        if (termSource == null) {
            return null;
        }

        TermSource sdrfTermSource = this.termSourceMap.get(termSource);
        if (sdrfTermSource == null) {
            sdrfTermSource = new TermSource(termSource.getName());
            sdrfTermSource.setVersion(term.getSource().getVersion());
            sdrfTermSource.setFile(term.getSource().getUrl());
            this.termSourceMap.put(termSource, sdrfTermSource);
        }
        return sdrfTermSource;
    }

    private void handleSamples(Source source, AbstractSampleDataRelationshipNode sdrfSource) {
        for (final Sample sample : source.getSamples()) {
            final AbstractSampleDataRelationshipNode sdrfSample = getOrCreateNode(sample);
            sdrfSample.getPredecessors().add(sdrfSource);
            sdrfSource.getSuccessors().add(sdrfSample);
            addBiomaterialAttributes(sample, (gov.nih.nci.caarray.magetab.sdrf.Sample) sdrfSample);
            // TODO Add external Sample ID
            handleExtracts(sample, sdrfSample);
        }
    }

    private void handleExtracts(Sample sample, AbstractSampleDataRelationshipNode sdrfSample) {
        for (final Extract extract : sample.getExtracts()) {
            final AbstractSampleDataRelationshipNode sdrfExtract = getOrCreateNode(extract);
            sdrfExtract.getPredecessors().add(sdrfSample);
            sdrfSample.getSuccessors().add(sdrfExtract);
            addBiomaterialAttributes(extract, (gov.nih.nci.caarray.magetab.sdrf.Extract) sdrfExtract);
            handleLabeledExtracts(extract, sdrfExtract);
        }
    }

    private void handleLabeledExtracts(Extract extract, AbstractSampleDataRelationshipNode sdrfExtract) {
        for (final LabeledExtract labeledExtract : extract.getLabeledExtracts()) {
            final AbstractSampleDataRelationshipNode sdrfLabeledExtract = getOrCreateNode(labeledExtract);
            sdrfLabeledExtract.getPredecessors().add(sdrfExtract);
            sdrfExtract.getSuccessors().add(sdrfLabeledExtract);
            addBiomaterialAttributes(labeledExtract,
                    (gov.nih.nci.caarray.magetab.sdrf.LabeledExtract) sdrfLabeledExtract);
            addLabeledExtractAttributes(labeledExtract,
                    (gov.nih.nci.caarray.magetab.sdrf.LabeledExtract) sdrfLabeledExtract);
            handleHybridizations(labeledExtract, sdrfLabeledExtract);
        }
    }

    private void handleHybridizations(LabeledExtract labeledExtract,
            AbstractSampleDataRelationshipNode sdrfLabeledExtract) {
        for (final Hybridization hybridization : labeledExtract.getHybridizations()) {
            final AbstractSampleDataRelationshipNode sdrfHybridization = getOrCreateNode(hybridization);
            sdrfHybridization.getPredecessors().add(sdrfLabeledExtract);
            sdrfLabeledExtract.getSuccessors().add(sdrfHybridization);
            handleRawData(hybridization, sdrfHybridization);
            handleDerivedData(hybridization, sdrfHybridization);
        }
    }

    private void handleRawData(Hybridization hybridization, AbstractSampleDataRelationshipNode sdrfHybridization) {
        for (final RawArrayData rawData : hybridization.getRawDataCollection()) {
            final AbstractSampleDataRelationshipNode sdrfRawData = getOrCreateNode(rawData);
            sdrfRawData.getPredecessors().add(sdrfHybridization);
            sdrfHybridization.getSuccessors().add(sdrfRawData);
        }
    }

    private void handleDerivedData(Hybridization hybridization,
            AbstractSampleDataRelationshipNode sdrfHybridization) {
        for (final DerivedArrayData derivedData : hybridization.getDerivedDataCollection()) {
            final AbstractSampleDataRelationshipNode sdrfDerivedData = getOrCreateNode(derivedData);
            final Set<AbstractArrayData> derivedFromDataSet = derivedData.getDerivedFromArrayDataCollection();
            if (derivedFromDataSet.isEmpty()) {
                final AbstractSampleDataRelationshipNode unavailableRawData = createNode(new RawArrayData());
                sdrfDerivedData.getPredecessors().add(unavailableRawData);
                unavailableRawData.getSuccessors().add(sdrfDerivedData);
                unavailableRawData.getPredecessors().add(sdrfHybridization);
                sdrfHybridization.getSuccessors().add(unavailableRawData);
            } else {
                for (final AbstractArrayData derivedFromData : derivedFromDataSet) {
                    final AbstractSampleDataRelationshipNode sdrfDerivedFromData = getOrCreateNode(derivedFromData);
                    sdrfDerivedData.getPredecessors().add(sdrfDerivedFromData);
                    sdrfDerivedFromData.getSuccessors().add(sdrfDerivedData);
                }
            }
        }
    }

    private void addLabeledExtractAttributes(LabeledExtract labeledExtract,
            gov.nih.nci.caarray.magetab.sdrf.LabeledExtract sdrfLabeledExtract) {
        // Set label.
        final Term term = labeledExtract.getLabel();
        if (term != null) {
            final OntologyTerm sdrfTerm = getSdrfTerm(term);
            sdrfLabeledExtract.setLabel(sdrfTerm);
        }
    }

    private AbstractSampleDataRelationshipNode getOrCreateNode(
            gov.nih.nci.caarray.domain.project.AbstractExperimentDesignNode caarrayNode) {
        final NodeKey nodeKey = new NodeKey(caarrayNode.getClass(), caarrayNode.getName());
        AbstractSampleDataRelationshipNode node = this.nodeCache.get(nodeKey);
        if (node == null) {
            node = createNode(caarrayNode);
            this.nodeCache.put(nodeKey, node);
        }
        return node;
    }

    @SuppressWarnings("PMD")
    // warnings suppressed due to long switch statement
    private AbstractSampleDataRelationshipNode createNode(
            gov.nih.nci.caarray.domain.project.AbstractExperimentDesignNode caarrayNode) {
        AbstractSampleDataRelationshipNode node = null;
        switch (caarrayNode.getNodeType()) {
        case SOURCE:
            node = new gov.nih.nci.caarray.magetab.sdrf.Source();
            this.allSources.add((gov.nih.nci.caarray.magetab.sdrf.Source) node);
            break;
        case SAMPLE:
            node = new gov.nih.nci.caarray.magetab.sdrf.Sample();
            this.allSamples.add((gov.nih.nci.caarray.magetab.sdrf.Sample) node);
            break;
        case EXTRACT:
            node = new gov.nih.nci.caarray.magetab.sdrf.Extract();
            this.allExtracts.add((gov.nih.nci.caarray.magetab.sdrf.Extract) node);
            break;
        case LABELED_EXTRACT:
            node = new gov.nih.nci.caarray.magetab.sdrf.LabeledExtract();
            this.allLabeledExtracts.add((gov.nih.nci.caarray.magetab.sdrf.LabeledExtract) node);
            break;
        case HYBRIDIZATION:
            node = new gov.nih.nci.caarray.magetab.sdrf.Hybridization();
            this.allHybridizations.add((gov.nih.nci.caarray.magetab.sdrf.Hybridization) node);
            break;
        default:
            // Should never get here.
            break;
        }
        node.setName(caarrayNode.getName());
        return node;
    }

    private AbstractSampleDataRelationshipNode getOrCreateNode(
            gov.nih.nci.caarray.domain.data.AbstractArrayData caarrayNode) {
        final NodeKey nodeKey = new NodeKey(caarrayNode.getClass(), caarrayNode.getName());
        AbstractSampleDataRelationshipNode node = this.nodeCache.get(nodeKey);
        if (node == null) {
            node = createNode(caarrayNode);
            this.nodeCache.put(nodeKey, node);
        }
        return node;
    }

    private AbstractSampleDataRelationshipNode createNode(AbstractArrayData caarrayNode) {
        return createNode(caarrayNode, allArrayDataFiles, allArrayDataMatrixFiles, allDerivedArrayDataMatrixFiles,
                allDerivedArrayDataFiles);
    }

    /**
     * Create new relationship node based upon the incoming abstract array data.  Adds the created node
     * to one of the sets, based upon node type (raw or derived) and whether the file is a data matrix
     * (or not.)
     * 
     * @param caarrayNode incoming node
     * @param arrayDataFiles raw non-matrix set
     * @param arrayDataMatrixFiles raw matrix set
     * @param derivedArrayDataMatrixFiles derived matrix set
     * @param derivedArrayDataFiles derived non-matrix set
     * @return the newly created node
     */
    static AbstractSampleDataRelationshipNode createNode(AbstractArrayData caarrayNode,
            Set<ArrayDataFile> arrayDataFiles, Set<ArrayDataMatrixFile> arrayDataMatrixFiles,
            Set<DerivedArrayDataMatrixFile> derivedArrayDataMatrixFiles,
            Set<DerivedArrayDataFile> derivedArrayDataFiles) {
        AbstractSampleDataRelationshipNode node = null;
        if (caarrayNode.getClass() == RawArrayData.class) {
            final CaArrayFile file = ((RawArrayData) caarrayNode).getDataFile();
            if (file == null || !file.getFileType().isDataMatrix()) {
                node = new gov.nih.nci.caarray.magetab.sdrf.ArrayDataFile();
                arrayDataFiles.add((gov.nih.nci.caarray.magetab.sdrf.ArrayDataFile) node);
            } else {
                node = new gov.nih.nci.caarray.magetab.sdrf.ArrayDataMatrixFile();
                arrayDataMatrixFiles.add((gov.nih.nci.caarray.magetab.sdrf.ArrayDataMatrixFile) node);
            }
        } else if (caarrayNode.getClass() == DerivedArrayData.class) {
            final FileType fileType = ((DerivedArrayData) caarrayNode).getDataFile().getFileType();
            if (fileType.isDataMatrix()) {
                node = new gov.nih.nci.caarray.magetab.sdrf.DerivedArrayDataMatrixFile();
                derivedArrayDataMatrixFiles.add((gov.nih.nci.caarray.magetab.sdrf.DerivedArrayDataMatrixFile) node);
            } else {
                node = new gov.nih.nci.caarray.magetab.sdrf.DerivedArrayDataFile();
                derivedArrayDataFiles.add((gov.nih.nci.caarray.magetab.sdrf.DerivedArrayDataFile) node);
            }
        }
        node.setName(caarrayNode.getName());
        return node;
    }

    /**
     * Compound key for node lookup and caching.
     */
    private static final class NodeKey {

        private final Class<?> nodeClass;
        private final String nodeName;

        NodeKey(Class<?> nodeClass, String nodeName) {
            this.nodeClass = nodeClass;
            this.nodeName = nodeName;
        }

        @Override
        public boolean equals(Object obj) {
            if (!(obj instanceof NodeKey)) {
                return false;
            } else {
                final NodeKey nodeKey = (NodeKey) obj;
                return this.nodeClass.equals(nodeKey.nodeClass) && this.nodeName.equals(nodeKey.nodeName);
            }
        }

        @Override
        public int hashCode() {
            return this.nodeClass.hashCode() + this.nodeName.hashCode();
        }
    }
}