001/*
002 *                    BioJava development code
003 *
004 * This code may be freely distributed and modified under the
005 * terms of the GNU Lesser General Public Licence.  This should
006 * be distributed with the code.  If you do not have a copy,
007 * see:
008 *
009 *      http://www.gnu.org/copyleft/lesser.html
010 *
011 * Copyright for this code is held jointly by the individual
012 * authors.  These should be listed in @author doc comments.
013 *
014 * For more information on the BioJava project and its aims,
015 * or to join the biojava-l mailing list, visit the home page
016 * at:
017 *
018 *      http://www.biojava.org/
019 *
020 */
021
022
023package org.biojava.bio.dist;
024
025import java.io.NotSerializableException;
026import java.io.ObjectStreamException;
027import java.io.Serializable;
028
029import org.biojava.bio.symbol.Alphabet;
030import org.biojava.bio.symbol.FiniteAlphabet;
031import org.biojava.bio.symbol.IllegalAlphabetException;
032import org.biojava.utils.StaticMemberPlaceHolder;
033
034/**
035 * <p>
036 * A thing that can make Distributions.
037 * </p>
038 *
039 * <p>
040 * This decouples programs from needing to know what implementation of Distribution
041 * to instantiate for a given alphabet. It also lets you parameterise model creation
042 * for things like profile HMMs.
043 * </p>
044 *
045 * @author Matthew Pocock
046 * @since 1.0
047 */
048public interface DistributionFactory {
049  /**
050   * Generate a new Distribution as requested.
051   *
052   * @param alpha  the emission alphabet for the state
053   * @return a new Distribution instance
054   * @throws IllegalAlphabetException if the factory is unable to generate a
055   *         distribution for the required alphabet
056   */
057  Distribution createDistribution(Alphabet alpha)
058  throws IllegalAlphabetException;
059  
060  /**
061   * <p>
062   * The default DistributionFactory object.
063   * </p>
064   *
065   * <p>
066   * You may wish to alias this within your scripts with something like:
067   * DistributionFactory dFact = DistributionFactory.DEFAULT; dFact.createDistribution(...);
068   * </p>
069   */
070  static DistributionFactory DEFAULT = new DefaultDistributionFactory();
071  
072  /**
073   * <p>
074   * The default DistributionFactory implementation.
075   * </p>
076   *
077   * <p>
078   * It knows about hand-optimized implementations for some alphabets (like DNA)
079   * without the optimized classes needing to be exposed from the DP package.
080   * </p>
081   *
082   * @author Matthew Pocock
083   */
084  class DefaultDistributionFactory implements DistributionFactory, Serializable {
085    public Distribution createDistribution(Alphabet alpha)
086    throws IllegalAlphabetException {
087      Distribution dis;
088      if(! (alpha instanceof FiniteAlphabet) ) {
089        throw new IllegalAlphabetException(
090          "The default StateFactory implementation can only produce states over " +
091          "finite alphabets, not " + alpha.getName()
092        );
093      }
094      FiniteAlphabet fa = (FiniteAlphabet) alpha;
095      
096      //if(fa == DNATools.getDNA()) {
097      //  dis = new DNADistribution();
098      //} else {
099        dis = new SimpleDistribution(fa);
100      //}
101    
102      return dis;
103    }
104    
105    private Object writeReplace() throws ObjectStreamException {
106      try {
107        return new StaticMemberPlaceHolder(DistributionFactory.class.getField("DEFAULT"));
108      } catch (NoSuchFieldException nsfe) { 
109        throw new NotSerializableException(nsfe.getMessage());
110      }
111    }
112  }
113}