/*
* BeastParser.java
*
* Copyright (c) 2002-2015 Alexei Drummond, Andrew Rambaut and Marc Suchard
*
* This file is part of BEAST.
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership and licensing.
*
* BEAST is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* BEAST is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with BEAST; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
package dr.app.beast;
import dr.util.Citation;
import dr.util.Pair;
import dr.xml.PropertyParser;
import dr.xml.UserInput;
import dr.xml.XMLObjectParser;
import dr.xml.XMLParser;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.util.*;
import java.util.logging.Logger;
/**
* @author Alexei Drummond
* @author Andrew Rambaut
* @author Walter Xie
* @version $Id: BeastParser.java,v 1.76 2006/08/30 16:01:59 rambaut Exp $
*/
public class BeastParser extends XMLParser {
public static final String RELEASE ="release";
public static final String DEV = "development";
public static final String PARSER_PROPERTIES_SUFFIX ="_parsers.properties";
public String parsers;
public BeastParser(String[] args, List<String> additionalParsers, boolean verbose, boolean parserWarnings, boolean strictXML) {
super(parserWarnings, strictXML);
addCitable(BeastVersion.INSTANCE);
setup(args);
if (verbose) {
System.out.println("Built-in parsers:");
Iterator iterator = getParsers();
while (iterator.hasNext()) {
XMLObjectParser parser = (XMLObjectParser) iterator.next();
System.out.println(parser.getParserName());
}
}
// Try to find and load the additional 'core' parsers
try {
Properties properties = new Properties();
properties.load(this.getClass().getResourceAsStream("beast.properties"));
// get the parsers file prefix from the beast.properties file
parsers = properties.getProperty("parsers");
if (System.getProperty("parsers") != null) {
// If a system property has been set then allow this to override the default
// e.g. -Dparsers=development
parsers = properties.getProperty("parsers");
}
if (parsers.equalsIgnoreCase(DEV)) {
this.parserWarnings = true; // if dev, then auto turn on, otherwise default to turn off
}
// always load release_parsers.properties !!!
loadProperties(this.getClass(), RELEASE + PARSER_PROPERTIES_SUFFIX, verbose, this.parserWarnings, false);
// suppose to load developement_parsers.properties
if (parsers != null && (!parsers.equalsIgnoreCase(RELEASE))) {
// load the development parsers
if (parsers.equalsIgnoreCase(DEV)) {
System.out.println("Loading additional development parsers from " + parsers + PARSER_PROPERTIES_SUFFIX
+ ", which is additional set of parsers only available for development version ...");
}
loadProperties(this.getClass(), parsers + PARSER_PROPERTIES_SUFFIX, verbose, this.parserWarnings, true);
}
// load additional parsers
if (additionalParsers != null) {
for (String addParsers : additionalParsers) {
loadProperties(this.getClass(), addParsers + PARSER_PROPERTIES_SUFFIX, verbose, verbose, true);
}
}
} catch (IOException e) {
e.printStackTrace();
}
// Now search the package hierarchy for 'beast.properties' files.
// try {
// loadProperties(this.getClass(), verbose);
// } catch (IOException e) {
// e.printStackTrace();
// }
}
/**
* Load the parser for *.properties file
* @param c BeastParser
* @param parsersFile parser file name, (*.properties)
* @param verbose verbose
* @param parserWarning parserWarning
* @param canReplace can this new loaded parser to replace old one with the same name
* @throws IOException IOException
*/
private void loadProperties(Class c, String parsersFile, boolean verbose, boolean parserWarning, boolean canReplace) throws IOException {
if (verbose) {
if (parsersFile.equalsIgnoreCase(RELEASE + PARSER_PROPERTIES_SUFFIX)) {
System.out.println("\nAlways loading " + parsersFile + ":");
} else {
System.out.println("\n\nLoading additional parsers (" + parsersFile + "):");
}
}
final InputStream stream = c.getResourceAsStream(parsersFile);
if (stream == null) {
throw new RuntimeException("Parsers file not found: " + parsersFile);
}
BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
String line = reader.readLine();
while (line != null) {
if (verbose && line.trim().startsWith("#")) System.out.println(line);
if (line.trim().length() > 0 && !line.trim().startsWith("#")) {
try {
if (line.contains("Vector")) {
System.out.println("");
}
Class parser = Class.forName(line);
if (XMLObjectParser.class.isAssignableFrom(parser)) {
// if this class is an XMLObjectParser then create an instance
boolean replaced = addXMLObjectParser((XMLObjectParser) parser.newInstance(), canReplace);
if (verbose) {
System.out.println((replaced ? "Replaced" : "Loaded") + " parser: " + parser.getName());
} else if (parserWarning && replaced) {
System.out.println("WARNING: parser - " + parser.getName() + " in " + parsersFile +" is duplicated, "
+ "which is REPLACING the same parser loaded previously.\n");
}
} else {
boolean parserFound = false;
// otherwise look for a static member which is an instance of XMLObjectParser
Field[] fields = parser.getDeclaredFields();
for (Field field : fields) {
if (XMLObjectParser.class.isAssignableFrom(field.getType())) {
try {
boolean replaced = addXMLObjectParser((XMLObjectParser) field.get(null), canReplace);
if (verbose) {
System.out.println((replaced ? "Replaced" : "Loaded") + " parser: "
+ parser.getName() + "." + field.getName());
} else if (parserWarning && replaced) {
System.out.println("WARNING: parser - " + parser.getName() + " in " + parsersFile +" is duplicated, "
+ "which is REPLACING the same parser loaded previously.\n");
}
} catch (IllegalArgumentException iae) {
System.err.println("Failed to install parser: " + iae.getMessage());
}
parserFound = true;
}
}
if (!parserFound) {
throw new IllegalArgumentException(parser.getName() + " is not of type XMLObjectParser " +
"and doesn't contain any static members of this type");
}
}
} catch (Exception e) {
System.err.println("\nFailed to load parser: " + e.getMessage());
System.err.println("line = " + line + "\n");
}
}
line = reader.readLine();
}
if (verbose) {
System.out.println("load " + parsersFile + " successfully.\n");
}
}
@Override
protected void executingRunnable() {
Logger.getLogger("dr.apps.beast").info("\nCitations for this analysis: ");
Map<String, Set<Pair<String, String>>> categoryMap = new LinkedHashMap<String, Set<Pair<String, String>>>();
// force the Framework category to be first...
categoryMap.put("Framework", new LinkedHashSet<Pair<String, String>>());
for (Pair<String, String> keyPair : getCitationStore().keySet()) {
Set<Pair<String, String>> pairSet = categoryMap.get(keyPair.fst);
if (pairSet == null) {
pairSet = new LinkedHashSet<Pair<String, String>>();
categoryMap.put(keyPair.fst, pairSet);
}
pairSet.add(keyPair);
}
for (String category : categoryMap.keySet()) {
Logger.getLogger("dr.apps.beast").info("\n"+category.toUpperCase());
Set<Pair<String, String>> pairSet = categoryMap.get(category);
for (Pair<String, String>keyPair : pairSet) {
Logger.getLogger("dr.apps.beast").info(keyPair.snd + ":");
for (Citation citation : getCitationStore().get(keyPair)) {
Logger.getLogger("dr.apps.beast").info("\t" + citation.toString());
}
}
}
// clear the citation store so all the same citations don't get cited again
getCitationStore().clear();
Logger.getLogger("dr.apps.beast").info("\n");
}
private void setup(String[] args) {
for (int i = 0; i < args.length; i++) {
storeObject(Integer.toString(i), args[i]);
}
// built-in parsers
addXMLObjectParser(new PropertyParser());
addXMLObjectParser(UserInput.STRING_PARSER);
addXMLObjectParser(UserInput.DOUBLE_PARSER);
addXMLObjectParser(UserInput.INTEGER_PARSER);
addXMLObjectParser(new dr.xml.AttributeParser());
addXMLObjectParser(new dr.xml.AttributesParser());
addXMLObjectParser(new dr.inference.model.StatisticParser());
addXMLObjectParser(new dr.inference.model.ParameterParser());
//**************** all other parsers are read at runtime from property lists *********************
}
}