GeneticAlgorithmXmlSaxParserFactory.java

/**
 * @(#)GeneticAlgorithmXmlSaxParserFactory.java
 * Copyright (C) 2008-2011 delhezi.com
 *
 * This class is released under the:
 * GNU Lesser General Public License (LGPL) version 3 or later.
 * http://www.gnu.org/copyleft/lesser.html
 */
package com.delhezi.ga;

import java.io.IOException;
import java.io.InputStream;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.SchemaFactory;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.XMLReader;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXParseException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.LinkedList;
import com.delhezi.ga.crossover.factory.CrossoverOperatorType;
import com.delhezi.ga.exception.GeneticAlgorithmException;
import com.delhezi.ga.initialize.data.SampleTsp;
import com.delhezi.ga.fitnessfunction.FitnessFunction;
import com.delhezi.ga.fitnessfunction.drivers.IFitnessFunctionDriver;
import com.delhezi.ga.fitnessfunction.drivers.factory.FitnessFunctionDriverFactory;
import com.delhezi.ga.fitnessfunction.FitnessFunctionOption;
import com.delhezi.ga.mutation.factory.MutationOperatorType;
import com.delhezi.ga.selection.factory.SelectionMethodType;

/**
 * <code>GeneticAlgorithmXmlSaxParserFactory</code>: Analiza składniwa dokumentu xml
 * z użyciem parsera JAXP. Walidacja w oparciu o newInstanceParameters.xsd
 * @version 1.0 2009-12-14
 * @author <a href="mailto:wojciech.wolszczak@delhezi.com">
 * Wojciech Wolszczak</a>
 */
public class GeneticAlgorithmXmlSaxParserFactory {

    /** Logger object. */
    private static final Logger LOGGER =
        Logger.getLogger(GeneticAlgorithmXmlSaxParserFactory.class.getName());

    /** Delhezi Error Code. */
    //private static final String DERC = "1-5-";

    /** Źródło inicjalizacji populacji. */
    public static enum InitializeDataSource {
        /** Baza danych. */
        db,

        /** Przykład komiwojażera. */
        sampleTSP;
    }
    private static final String XML_SCHEMA_FILE = "newInstanceParameters.xsd";
    private GeneticAlgorithm ga;

    public GeneticAlgorithm newGeneticAlgorithm(
            final String fitnassFunctionScriptsPath,
            final String xmlParams) throws GeneticAlgorithmException {

        ga = new GeneticAlgorithm();

        DefaultHandler handler = new DefaultHandler() {
            String currTag;
            Population population;
            PopulationType populationType;
            CrossoverOperatorType crossoverOperator;
            double crossoverProbability;
            MutationOperatorType mutationOperator;
            double mutationProbability;
            boolean elitism;
            String fitnessFunctionScript;
            FitnessFunctionOption fitnessFunctionOption;
            SelectionMethodType selectionMethod;
            int maxLT;
            int minLT;
            InitializeDataSource initializeDataSource;
            String initializePopulationConnectionName;
            String initializePopulationSQLQuery;
            int populationSize;

            @Override
            public void startElement(String uri, String localName,
                                     String qName,
                                     Attributes attributes) throws SAXException {
                currTag = qName;
                if (qName.equalsIgnoreCase("changeablePopulationSize")) {
                    populationType = PopulationType.PopulationChangeableSize;
                } else if (qName.equalsIgnoreCase("constantPopulationSize")) {
                    populationType = PopulationType.PopulationConstantSize;
                } else if (qName.equalsIgnoreCase("elitism")) {
                    elitism = true; //Jeśli występuje pusty element to domyślnie jest true
                } else if (qName.equalsIgnoreCase("db")) {
                    initializeDataSource = com.delhezi.ga.GeneticAlgorithmXmlSaxParserFactory.InitializeDataSource.db;
                } else if (qName.equalsIgnoreCase("sampleTSP")) {
                    initializeDataSource = com.delhezi.ga.GeneticAlgorithmXmlSaxParserFactory.InitializeDataSource.sampleTSP;
                }
            }

            @Override
            public void endDocument() throws SAXException {
              FitnessFunction fitnessFunction;
              IFitnessFunctionDriver fitnessFunctionDriver;
                try {
                  fitnessFunctionDriver =
                                    FitnessFunctionDriverFactory.getFitnessFunctionEngineDriver("javascript",
                                                                                                fitnassFunctionScriptsPath,
                                                                                                fitnessFunctionScript);
                    fitnessFunction = new FitnessFunction(fitnessFunctionDriver, "fitnessFunction");
                } catch (GeneticAlgorithmException ex) {
                  LOGGER.log(Level.SEVERE, null, ex);
                  throw new SAXException(ex.getMessage());
                }
                if (fitnessFunctionOption == FitnessFunctionOption.minimisation) {
                  fitnessFunction.setMaximisation(false);
              } else if (fitnessFunctionOption == FitnessFunctionOption.maximisation) {
                  fitnessFunction.setMaximisation(true);
                }

                ChromosomeProperties chromosomeProperties =
                    ChromosomeProperties.getInstance();
                chromosomeProperties.setFitnessFunction(fitnessFunction);

                LinkedList<Chromosome> chromosomes = null;
                switch (initializeDataSource) {
              case sampleTSP:
                    chromosomes = SampleTsp.newChromosomes(populationSize, chromosomeProperties);
                    break;
              case db:
                    //UZUPEŁNIĆ
                    //initializePopulationConnectionName
                    //initializePopulationSQLQuery
                    chromosomes = null;
                    break;
                  }

              switch (populationType) {
              case PopulationChangeableSize:
                    try {
                        population = PopulationChangeableSize.newPopulationChangeableSize(
                            maxLT, minLT, chromosomes,
                            crossoverOperator, crossoverProbability,
                            mutationOperator, mutationProbability,
                            chromosomeProperties);
                      } catch (GeneticAlgorithmException ex) {
                          LOGGER.log(Level.SEVERE, null, ex);
                          throw new SAXException(ex.getMessage());
                      }
                    break;
              case PopulationConstantSize:
                    try {
                        population = PopulationConstantSize.newPopulationConstantSize(
                            selectionMethod, chromosomes,
                            crossoverOperator, crossoverProbability,
                            mutationOperator, mutationProbability,
                            chromosomeProperties);
                      } catch (GeneticAlgorithmException ex) {
                          LOGGER.log(Level.SEVERE, null, ex);
                          throw new SAXException(ex.getMessage());
                      }
                    break;
                  }
              ga.setPopulation(population);
              ga.setState(GeneticAlgorithmState.INITIALIZED);
            }

            @Override
            public void characters(char[] ch, int start,
                                   int length) throws SAXException {
                if (currTag.equalsIgnoreCase("maxLT")) {
                    maxLT = Integer.parseInt(new String(ch, start, length));
                } else if (currTag.equalsIgnoreCase("minLT")) {
                    minLT = Integer.parseInt(new String(ch, start, length));
                } else if (currTag.equalsIgnoreCase("selectionMethod")) {
                    selectionMethod =
                            SelectionMethodType.valueOf(new String(ch, start,
                                                                   length));
                } else if (currTag.equalsIgnoreCase("crossoverOperator")) {
                    crossoverOperator =
                            CrossoverOperatorType.valueOf(new String(ch, start,
                                                                     length));
                } else if (currTag.equalsIgnoreCase("crossoverProbability")) {
                    crossoverProbability =
                            Double.parseDouble(new String(ch, start, length));
                } else if (currTag.equalsIgnoreCase("mutationOperator")) {
                    mutationOperator =
                            MutationOperatorType.valueOf(new String(ch, start,
                                                                    length));
                } else if (currTag.equalsIgnoreCase("mutationProbability")) {
                    mutationProbability =
                            Double.parseDouble(new String(ch, start, length));
                } else if (currTag.equalsIgnoreCase("elitism")) {
                    //Jeśli element ma wartość to nadpisz wartość wstawioną w startElement.elitism.
                    elitism = Boolean.valueOf(new String(ch, start, length));
                } else if (currTag.equalsIgnoreCase("fitnessFunctionScript")) {
                    fitnessFunctionScript = new String(ch, start, length);
                } else if (currTag.equalsIgnoreCase("fitnessFunctionOption")) {
                    fitnessFunctionOption =
                            FitnessFunctionOption.valueOf(new String(ch, start,
                                                                     length));
                } else if (currTag.equalsIgnoreCase("initializePopulationConnectionName")) {
                    this.initializePopulationConnectionName =
                            new String(ch, start, length);
                } else if (currTag.equalsIgnoreCase("initializePopulationSQLQuery")) {
                    this.initializePopulationSQLQuery =
                            new String(ch, start, length);
                } else if (currTag.equalsIgnoreCase("populationSize")) {
                    this.populationSize =
                            Integer.parseInt(new String(ch, start, length));
                } else if (currTag.equalsIgnoreCase("maxGenerationCount")) {
                    ga.setMaxGenerationCount(Integer.parseInt(new String(ch,
                                                                         start,
                                                                         length)));
                } else if (currTag.equalsIgnoreCase("lastGenerationTopChromosomeFind")) {
                    ga.setLastGenerationTopChromosomeFind(Integer.parseInt(new String(ch,
                                                                                      start,
                                                                                      length)));
                }
            }
        };
      
        SchemaFactory schemaFactory = SchemaFactory
                .newInstance(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI);
        SAXParserFactory factory = SAXParserFactory.newInstance();
        factory.setValidating(false);//Wyłączenie walidacji (przestarzały mechanizm).
        factory.setNamespaceAware(true); //Obsługa przestrzeni nazw.
        try {
            //Wymagana biblioteka xercesImpl.jar !!!!, zostala dodana w POM projektu.
            InputStream xmlSchemaInputStream = GeneticAlgorithmXmlSaxParserFactory.class.getClassLoader().getResourceAsStream(XML_SCHEMA_FILE);
            //InputStream xmlSchemaInputStream = this.getClass().getClassLoader().getResourceAsStream(XML_SCHEMA_FILE);
            //InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream(XML_SCHEMA_FILE);
            factory.setSchema(schemaFactory.newSchema(new Source[]{new StreamSource(xmlSchemaInputStream)})); //Walidacja ze schematem
            //factory.setSchema(schemaFactory.newSchema(new Source[]{new StreamSource("contacts.xsd")}));
            //factory.setSchema(schemaFactory.newSchema(schemaFileUrl));
            SAXParser saxParser = factory.newSAXParser();
            XMLReader xmlReder = saxParser.getXMLReader(); //interfejs pozwala na analizę składni dokumentu xml
            xmlReder.setContentHandler(handler);
            xmlReder.setErrorHandler(new InitializeParametersXMLParserErrorHandler());
            InputSource xmlInputSource = new InputSource(new java.io.ByteArrayInputStream(xmlParams.getBytes()));
            xmlReder.parse(xmlInputSource);
        } catch (ParserConfigurationException ex) {
            Logger.getLogger(GeneticAlgorithmXmlSaxParserFactory.class.getName()).log(Level.SEVERE, null, ex);
            throw new GeneticAlgorithmException(ex.getMessage());
        } catch (SAXException ex) {
            Logger.getLogger(GeneticAlgorithmXmlSaxParserFactory.class.getName()).log(Level.SEVERE, null, ex);
            throw new GeneticAlgorithmException(ex.getMessage());
        } catch (IOException ex) {
            Logger.getLogger(GeneticAlgorithmXmlSaxParserFactory.class.getName()).log(Level.SEVERE, null, ex);
            throw new GeneticAlgorithmException(ex.getMessage());
        }
      ga.setState(GeneticAlgorithmState.INITIALIZED);
      return ga;
    }

    private static class InitializeParametersXMLParserErrorHandler implements ErrorHandler {
        @Override
        public void warning(SAXParseException ex) throws SAXException {
          System.out.println("CCC1"); 
            Logger.getLogger(InitializeParametersXMLParserErrorHandler.class.getName()).log(Level.SEVERE, null, ex);
            throw new SAXException(ex.getMessage());
        }
        @Override
        public void error(SAXParseException ex) throws SAXException {
          System.out.println("CCC2"); 
            Logger.getLogger(InitializeParametersXMLParserErrorHandler.class.getName()).log(Level.SEVERE, null, ex);
            throw new SAXException(ex.getMessage());
        }
        @Override
        public void fatalError(SAXParseException ex) throws SAXException {
          System.out.println("CCC3"); 
            Logger.getLogger(InitializeParametersXMLParserErrorHandler.class.getName()).log(Level.SEVERE, null, ex);
            throw new SAXException(ex.getMessage());
        }
    }

}