    001    package org.maltparser;
    002
    003    import java.net.MalformedURLException;
    004    import java.net.URL;
    005    import java.util.Iterator;
    006
    007    import org.maltparser.core.exception.MaltChainedException;
    008    import org.maltparser.core.flow.FlowChartInstance;
    009    import org.maltparser.core.helper.SystemInfo;
    010    import org.maltparser.core.helper.Util;
    011    import org.maltparser.core.io.dataformat.ColumnDescription;
    012    import org.maltparser.core.io.dataformat.DataFormatInstance;
    013    import org.maltparser.core.options.OptionManager;
    014    import org.maltparser.core.syntaxgraph.DependencyGraph;
    015    import org.maltparser.core.syntaxgraph.DependencyStructure;
    016    import org.maltparser.core.syntaxgraph.node.DependencyNode;
    017    import org.maltparser.parser.SingleMalt;
    018
    019    /**
    020     * The purpose of MaltParserService is to easily write third-party programs that uses MaltParser.
    021     *
    022     *  There are two ways to call the MaltParserService:
    023     *  1. By running experiments, which allow other programs to train a parser model or parse with a parser model. IO-handling is done by MaltParser.
    024     *  2. By first initialize a parser model and then call the method parse() with an array of tokens that MaltParser parses. IO-handling of the sentence is
    025     *  done by the third-party program.
    026     *
    027     *  How to use MaltParserService, please see the examples provided in the directory 'examples/apiexamples/srcex'
    028     *
    029     * @author Johan Hall
    030     */
    031    public class MaltParserService {
    032            private URL urlMaltJar;
    033            private Engine engine;
    034            private FlowChartInstance flowChartInstance;
    035            private DataFormatInstance dataFormatInstance;
    036            private SingleMalt singleMalt;
    037            private int optionContainer;
    038            private boolean initialized = false;
    039
    040            /**
    041             * Creates a MaltParserService with the option container 0
    042             *
    043             * @throws MaltChainedException
    044             */
    045            public MaltParserService() throws MaltChainedException {
    046                    this(0);
    047            }
    048
    049            /**
    050             * Creates a MaltParserService with the specified option container. To use different option containers allows the calling program
    051             * to load several parser models or several experiments. The option management in MaltParser uses the singleton design pattern, which means that there can only
    052             * be one instance of the option manager. To be able to have several parser models or experiments at same time please use different option containers.
    053             *
    054             * @param optionContainer an integer from 0 to max value of data type Integer
    055             * @throws MaltChainedException
    056             */
    057            public MaltParserService(int optionContainer) throws MaltChainedException {
    058                    initialize();
    059                    setOptionContainer(optionContainer);
    060            }
    061
    062            /**
    063             * Runs a MaltParser experiment. The experiment is controlled by a commandLine string, please see the documentation of MaltParser to see all available options.
    064             *
    065             * @param commandLine a commandLine string that controls the MaltParser.
    066             * @throws MaltChainedException
    067             */
    068            public void runExperiment(String commandLine) throws MaltChainedException {
    069                    OptionManager.instance().parseCommandLine(commandLine, optionContainer);
    070                    engine = new Engine();
    071                    engine.initialize(optionContainer);
    072                    engine.process(optionContainer);
    073                    engine.terminate(optionContainer);
    074            }
    075
    076            /**
    077             * Initialize a parser model that later can by used to parse sentences. MaltParser is controlled by a commandLine string, please see the documentation of MaltParser to see all available options.
    078             *
    079             * @param commandLine a commandLine string that controls the MaltParser
    080             * @throws MaltChainedException
    081             */
    082            public void initializeParserModel(String commandLine) throws MaltChainedException {
    083                    OptionManager.instance().parseCommandLine(commandLine, optionContainer);
    084                    // Creates an engine
    085                    engine = new Engine();
    086                    // Initialize the engine with option container and gets a flow chart instance
    087                    flowChartInstance = engine.initialize(optionContainer);
    088                    // Runs the preprocess chart items of the "parse" flow chart
    089                    if (flowChartInstance.hasPreProcessChartItems()) {
    090                            flowChartInstance.preprocess();
    091                    }
    092                    singleMalt = (SingleMalt)flowChartInstance.getFlowChartRegistry(org.maltparser.parser.SingleMalt.class, "singlemalt");
    093                    singleMalt.getConfigurationDir().initDataFormat();
    094                    dataFormatInstance = singleMalt.getConfigurationDir().getDataFormatManager().getInputDataFormatSpec().createDataFormatInstance(
    095                                    singleMalt.getSymbolTables(),
    096                                    OptionManager.instance().getOptionValueString(optionContainer, "singlemalt", "null_value"),
    097                                    OptionManager.instance().getOptionValueString(optionContainer, "graph", "root_label"));
    098                    initialized = true;
    099            }
    100
    101            /**
    102             * Parses an array of tokens and returns a dependency structure.
    103             *
    104             * Note: To call this method requires that a parser model has been initialized by using the initializeParserModel().
    105             *
    106             * @param tokens an array of tokens
    107             * @return a dependency structure
    108             * @throws MaltChainedException
    109             */
    110            public DependencyStructure parse(String[] tokens) throws MaltChainedException {
    111                    if (!initialized) {
    112                            throw new MaltChainedException("No parser model has been initialized. Please use the method initializeParserModel() before invoking this method.");
    113                    }
    114                    if (tokens == null || tokens.length == 0) {
    115                            throw new MaltChainedException("Nothing to parse. ");
    116                    }
    117
    118                    DependencyStructure outputGraph = new DependencyGraph(singleMalt.getSymbolTables());
    119
    120                    for (int i = 0; i < tokens.length; i++) {
    121                            Iterator<ColumnDescription> columns = dataFormatInstance.iterator();
    122                            DependencyNode node = outputGraph.addDependencyNode(i+1);
    123                            String[] items = tokens[i].split("\t");
    124                            for (int j = 0; j < items.length; j++) {
    125                                    if (columns.hasNext()) {
    126                                            ColumnDescription column = columns.next();
    127                                            if (column.getCategory() == ColumnDescription.INPUT && node != null) {
    128                                                    outputGraph.addLabel(node, column.getName(), items[j]);
    129                                            }
    130                                    }
    131                            }
    132                    }
    133                    outputGraph.setDefaultRootEdgeLabel(outputGraph.getSymbolTables().getSymbolTable("DEPREL"), "ROOT");
    134                    // Invoke parse with the output graph
    135                    singleMalt.parse(outputGraph);
    136                    return outputGraph;
    137            }
    138
    139            /**
    140             * Terminates the parser model.
    141             *
    142             * @throws MaltChainedException
    143             */
    144            public void terminateParserModel() throws MaltChainedException {
    145                    // Runs the postprocess chart items of the "parse" flow chart
    146                    if (flowChartInstance.hasPostProcessChartItems()) {
    147                            flowChartInstance.postprocess();
    148                    }
    149
    150                    // Terminate the flow chart with an option container
    151                    engine.terminate(optionContainer);
    152            }
    153
    154            private void initialize() throws MaltChainedException {
    155                    if (OptionManager.instance().getOptionDescriptions().getOptionGroupNameSet().size() > 0) {
    156                            return; // OptionManager is already initialized
    157                    }
    158                    String maltpath = getMaltJarPath();
    159                    if (maltpath == null) {
    160                            new MaltChainedException("malt.jar could not be found. ");
    161                    }
    162                    urlMaltJar = Util.findURL(maltpath);
    163                    try {
    164                            OptionManager.instance().loadOptionDescriptionFile(new URL("jar:"+urlMaltJar.toString()+"!/appdata/options.xml"));
    165
    166                    } catch (MalformedURLException e) {
    167                            throw new MaltChainedException("MaltParser couldn't find its options 'malt.jar!/appdata/options.xml'", e);
    168                    }
    169                    OptionManager.instance().generateMaps();
    170            }
    171
    172
    173            /**
    174             * Returns the option container index
    175             *
    176             * @return the option container index
    177             */
    178            public int getOptionContainer() {
    179                    return optionContainer;
    180            }
    181
    182            private void setOptionContainer(int optionContainer) {
    183                    this.optionContainer = optionContainer;
    184            }
    185
    186            /**
    187             * Returns the path of malt.jar file
    188             *
    189             * @return the path of malt.jar file
    190             */
    191            public static String getMaltJarPath() {
    192                    if (SystemInfo.getMaltJarPath() != null) {
    193                            return SystemInfo.getMaltJarPath().toString();
    194                    }
    195                    return null;
    196            }
    197
    198
    199    }