001package com.hfg.bio.seq.alignment.muscle;
002
003import java.io.ByteArrayInputStream;
004import java.io.File;
005import java.io.IOException;
006import java.io.InputStream;
007import java.util.Collection;
008import java.util.List;
009
010import com.hfg.bio.seq.BioSequence;
011import com.hfg.bio.seq.format.FASTA;
012import com.hfg.util.Executor;
013import com.hfg.util.StringBuilderPlus;
014import com.hfg.util.StringUtil;
015
016//==============================================================================
017/**
018 Wrapper for a Muscle multiple sequence alignment.
019 <div>
020 Command-line executable is downloadable from <pre>https://www.drive5.com/muscle</pre>
021 </div>
022 @author J. Alex Taylor, hairyfatguy.com
023 */
024//==============================================================================
025// com.hfg XML/HTML Coding Library
026//
027// This library is free software; you can redistribute it and/or
028// modify it under the terms of the GNU Lesser General Public
029// License as published by the Free Software Foundation; either
030// version 2.1 of the License, or (at your option) any later version.
031//
032// This library is distributed in the hope that it will be useful,
033// but WITHOUT ANY WARRANTY; without even the implied warranty of
034// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
035// Lesser General Public License for more details.
036//
037// You should have received a copy of the GNU Lesser General Public
038// License along with this library; if not, write to the Free Software
039// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
040//
041// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com
042// jataylor@hairyfatguy.com
043//==============================================================================
044
045public class Muscle
046{
047   private MuscleSettings mSettings;
048
049   private static MuscleSettings sDefaultSettings;
050
051   //###########################################################################
052   // CONSTRUCTORS
053   //###########################################################################
054
055   //---------------------------------------------------------------------------
056   public Muscle()
057   {
058      this(null);
059   }
060
061   //---------------------------------------------------------------------------
062   public Muscle(MuscleSettings inSettings)
063   {
064      mSettings = inSettings != null ? inSettings : getDefaultSettings();
065   }
066
067   //###########################################################################
068   // PUBLIC METHODS
069   //###########################################################################
070
071   //---------------------------------------------------------------------------
072   public MuscleSettings getSettings()
073   {
074      return mSettings;
075   }
076
077   //---------------------------------------------------------------------------
078   public MuscleOutput run(List<? extends BioSequence> inQueries)
079      throws IOException
080   {
081      preflight();
082
083      String cmd = generateCmd();
084
085      Executor executor = new Executor();
086      executor.setSTDIN(generateSTDIN(inQueries));
087      executor.setCommand(cmd);
088
089      int exitStatus = executor.exec();
090
091      MuscleOutput output = new MuscleOutput()
092            .setExitStatus(exitStatus)
093            .setStdErr(executor.getSTDERR())
094            .setStdOut(executor.getSTDOUT())
095            .setExecutedCmd(cmd)
096            .setMuscleVersion(getVersion());
097
098      return output;
099   }
100
101   //###########################################################################
102   // PRIVATE METHODS
103   //###########################################################################
104
105   //---------------------------------------------------------------------------
106   public static void setDefaultSettings(MuscleSettings inValue)
107   {
108      sDefaultSettings = inValue;
109   }
110
111   //---------------------------------------------------------------------------
112   public static MuscleSettings getDefaultSettings()
113   {
114      return (sDefaultSettings != null ? sDefaultSettings : new MuscleSettings());
115   }
116
117   //---------------------------------------------------------------------------
118   private File getExecutable()
119   {
120      return (getSettings().getExecutable() != null ? new File(getSettings().getExecutableDir(), getSettings().getExecutable()) : null);
121   }
122
123   //---------------------------------------------------------------------------
124   private void preflight()
125      throws IOException
126   {
127      File exe = getExecutable();
128      if (null == exe)
129      {
130         throw new IOException("No Muscle executable was specified!");
131      }
132      else if (! exe.exists())
133      {
134         File exeDir = exe.getParentFile();
135         if (exeDir != null
136               && !exeDir.exists())
137         {
138            throw new IOException("The Muscle executable directory " + StringUtil.singleQuote(exeDir.getPath()) + " doesn't exist!");
139         }
140
141         throw new IOException("The Muscle executable " + StringUtil.singleQuote(exe.getPath()) + " doesn't exist!");
142      }
143   }
144
145
146   //---------------------------------------------------------------------------
147   private String generateCmd()
148   {
149      StringBuilderPlus cmd = new StringBuilderPlus(getExecutable().getPath()).setDelimiter(" ");
150
151      if (getSettings().getOutputFormat() != null)
152      {
153         cmd.delimitedAppend("-" + getSettings().getOutputFormat().name());
154      }
155
156      if (getSettings().getCommandLineParams() != null)
157      {
158         cmd.delimitedAppend(getSettings().getCommandLineParams());
159      }
160
161      return cmd.toString();
162   }
163
164   //---------------------------------------------------------------------------
165   private InputStream generateSTDIN(Collection<? extends BioSequence> inQuery)
166   {
167      FASTA fasta = new FASTA();
168      // TODO
169      return new ByteArrayInputStream(fasta.write(inQuery).getBytes());
170   }
171
172   //---------------------------------------------------------------------------
173   private String getVersion()
174   {
175      String version = null;
176
177      Executor executor = new Executor();
178      executor.setCommand(getExecutable() + " -version");
179
180      int exitStatus = executor.exec();
181      if (0 == exitStatus)
182      {
183         // MUSCLE v3.8.31 by Robert C. Edgar
184         version = executor.getSTDOUT().split("\\s+")[1];
185      }
186
187      return version;
188   }
189}