001// $Id: PsiToBiopax3Converter.java,v 1.2 2009/11/23 13:59:42 rodche Exp $
002//------------------------------------------------------------------------------
003/** Copyright (c) 2009 Memorial Sloan-Kettering Cancer Center.
004 **
005 ** This library is free software; you can redistribute it and/or modify it
006 ** under the terms of the GNU Lesser General Public License as published
007 ** by the Free Software Foundation; either version 2.1 of the License, or
008 ** any later version.
009 **
010 ** This library is distributed in the hope that it will be useful, but
011 ** WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF
012 ** MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  The software and
013 ** documentation provided hereunder is on an "as is" basis, and
014 ** Memorial Sloan-Kettering Cancer Center
015 ** has no obligations to provide maintenance, support,
016 ** updates, enhancements or modifications.  In no event shall
017 ** Memorial Sloan-Kettering Cancer Center
018 ** be liable to any party for direct, indirect, special,
019 ** incidental or consequential damages, including lost profits, arising
020 ** out of the use of this software and its documentation, even if
021 ** Memorial Sloan-Kettering Cancer Center
022 ** has been advised of the possibility of such damage.  See
023 ** the GNU Lesser General Public License for more details.
024 **
025 ** You should have received a copy of the GNU Lesser General Public License
026 ** along with this library; if not, write to the Free Software Foundation,
027 ** Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
028 **/
029package org.biopax.paxtools.converter.psi;
030
031
032import psidev.psi.mi.tab.PsimiTabException;
033import psidev.psi.mi.tab.PsimiTabReader;
034import psidev.psi.mi.tab.converter.tab2xml.Tab2Xml;
035import psidev.psi.mi.tab.converter.tab2xml.XmlConversionException;
036import psidev.psi.mi.tab.model.BinaryInteraction;
037import psidev.psi.mi.xml.model.Entry;
038import psidev.psi.mi.xml.model.EntrySet;
039import psidev.psi.mi.xml.PsimiXmlReader;
040import psidev.psi.mi.xml.PsimiXmlReaderException;
041
042import java.io.IOException;
043import java.io.InputStream;
044import java.io.OutputStream;
045import java.util.Collection;
046
047import org.biopax.paxtools.io.SimpleIOHandler;
048import org.biopax.paxtools.model.BioPAXLevel;
049import org.biopax.paxtools.model.Model;
050
051/**
052 * The PSIMI 2.5 to BioPAX Level3 converter. 
053 *
054 * @author Igor Rodchenkov (rodche)
055 */
056public class PsiToBiopax3Converter {
057
058        private final String xmlBase; //common URI prefix
059
060        /**
061         * Constructor.
062         * Will use the default empty string xml:base.
063         *
064         */
065        public PsiToBiopax3Converter() {
066                this.xmlBase = null;
067        }
068
069        /**
070         * Constructor.
071         * 
072         * @param xmlBase xml:base to be used when generating non-canonical BioPAX objects' URIs
073         */
074        public PsiToBiopax3Converter(String xmlBase) {
075                this.xmlBase = xmlBase;
076        }
077
078        
079        /**
080         * Converts the PSI-MI inputStream into BioPAX outputStream.
081         * Streams will be closed by the converter.
082         * 
083         * Warning: for very large models (about 1-2Gb if serialized), and when ByteArrayOutputStream
084         * is used, OutOfMemoryError might be thrown (increasing the "heap" RAM won't help; but using FileOutputStream will).
085         *
086         * @param inputStream PSI-MI
087         * @param outputStream BioPAX
088         * @param forceInteractionToComplex - always generate Complex instead of MolecularInteraction
089         *
090         * @throws IOException when an I/O error occur
091         * @throws PsimiXmlReaderException when an error in the PSI-MI parser happens
092         */
093        public void convert(InputStream inputStream, OutputStream outputStream, 
094                        boolean forceInteractionToComplex) throws IOException, PsimiXmlReaderException {
095
096                // check args
097                if (inputStream == null || outputStream == null) {
098                        throw new IllegalArgumentException("convert(): " +
099                                        "one or more null arguments.");
100                }
101
102                // unmarshall the data, close the stream
103                PsimiXmlReader reader = new PsimiXmlReader();
104                EntrySet entrySet = reader.read(inputStream);
105                inputStream.close();
106                
107                // convert
108                convert(entrySet, outputStream, forceInteractionToComplex);
109        }
110
111        
112        /**
113         * Converts the PSI-MITAB inputStream into BioPAX outputStream.
114         * Streams will be closed by the converter.
115         *
116         * @param inputStream psi-mitab
117         * @param outputStream biopax
118         * @param forceInteractionToComplex - always generate Complex instead of MolecularInteraction
119         *
120         * @throws IOException when an I/O error occur
121         * @throws PsimiTabException when there's a problem within the PSI-MITAB parser
122         */
123        public void convertTab(InputStream inputStream, OutputStream outputStream, 
124                        boolean forceInteractionToComplex) throws IOException, PsimiTabException {
125
126                // check args
127                if (inputStream == null || outputStream == null) {
128                        throw new IllegalArgumentException("convertTab(): " +
129                                        "one or more null arguments.");
130                }
131
132                // unmarshall the data, close the stream
133                PsimiTabReader reader = new PsimiTabReader();
134                Collection<BinaryInteraction> interactions = reader.read(inputStream);
135                Tab2Xml tab2Xml = new Tab2Xml();
136                EntrySet entrySet;
137                try {
138                        entrySet = tab2Xml.convert(interactions);
139                } catch (IllegalAccessException e) {
140                        throw new RuntimeException(e);
141                } catch (XmlConversionException e) {
142                        throw new RuntimeException(e);
143                }
144                inputStream.close();
145                
146                // convert
147                convert(entrySet, outputStream, forceInteractionToComplex);
148        }       
149        
150        /**
151         * Converts the PSI interactions from the EntrySet and places into BioPAX output stream.
152         * Stream will be closed by the converter.
153         *
154         * @param entrySet PSI-MI entry set
155         * @param outputStream output stream for writing the BioPAX RDF/XML result
156         * @param forceInteractionToComplex true/false - whether to always generate Complex instead of MolecularInteraction
157         */
158        public void convert(EntrySet entrySet, OutputStream outputStream, 
159                        boolean forceInteractionToComplex) {
160
161                // check args
162                if (entrySet == null || outputStream == null) {
163                        throw new IllegalArgumentException("convert: one or more null arguments.");
164                }
165                if (entrySet.getLevel() != 2) {
166                        throw new IllegalArgumentException("convert: only PSI-MI Level 2.5 is supported.");
167                }
168
169                //create a new empty BioPAX Model
170                final Model model = BioPAXLevel.L3.getDefaultFactory().createModel();
171                model.setXmlBase(xmlBase);
172                
173                // convert all psimi entries
174                EntryMapper entryMapper = new EntryMapper(model, forceInteractionToComplex);
175                for (Entry entry : entrySet.getEntries()) {
176                        entryMapper.run(entry);
177                }
178                
179                //try to release some RAM earlier
180                entrySet.getEntries().clear();
181                entrySet = null;
182                
183                // write BioPAX RDF/XML
184                (new SimpleIOHandler()).convertToOWL(model, outputStream);
185        }
186
187        /**
188         * @return the xml:base, a namespace for the converter-generated BioPAX objects' URIs.
189         */
190        public String getXmlBase() {
191                return xmlBase;
192        }
193        
194}