org.jvoicexml.interpreter.grammar.GrammarLoader.java Source code

Java tutorial

Introduction

Here is the source code for org.jvoicexml.interpreter.grammar.GrammarLoader.java

Source

/*
 * File:    $HeadURL$
 * Version: $LastChangedRevision$
 * Date:    $Date$
 * Author:  $LastChangedBy$
 *
 * JVoiceXML - A free VoiceXML implementation.
 *
 * Copyright (C) 2011-2013 JVoiceXML group - http://jvoicexml.sourceforge.net
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */
package org.jvoicexml.interpreter.grammar;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Locale;

import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.log4j.Logger;
import org.jvoicexml.DocumentServer;
import org.jvoicexml.FetchAttributes;
import org.jvoicexml.GrammarDocument;
import org.jvoicexml.Session;
import org.jvoicexml.event.error.BadFetchError;
import org.jvoicexml.event.error.SemanticError;
import org.jvoicexml.event.error.UnsupportedFormatError;
import org.jvoicexml.interpreter.VoiceXmlInterpreterContext;
import org.jvoicexml.interpreter.datamodel.DataModel;
import org.jvoicexml.xml.IllegalAttributeException;
import org.jvoicexml.xml.srgs.Grammar;

/**
 * Loads external and internal grammars.
 * 
 * @author Dirk Schnelle-Walka
 * @version $Revision$
 * @since 0.7.5
 */
final class GrammarLoader {
    /** Logger for this class. */
    private static final Logger LOGGER = Logger.getLogger(GrammarLoader.class);

    /**
     * Loads the document that is specified by the given grammar.
     * 
     * @param context
     *            The current context.
     * @param attributes
     *            attributes governing the fetch.
     * @param grammar
     *            the grammar to process
     * @param language
     *            the default language
     * @return the transformed grammar
     * @exception BadFetchError
     *                If the document could not be fetched successfully.
     * @exception SemanticError
     *                if there was an error evaluating a scripting expression
     * @exception UnsupportedFormatError
     *                If an unsupported grammar has to be loaded.
     */
    public GrammarDocument loadGrammarDocument(final VoiceXmlInterpreterContext context,
            final FetchAttributes attributes, final Grammar grammar, final Locale language)
            throws UnsupportedFormatError, BadFetchError, SemanticError {
        try {
            if (grammar.isExternalGrammar()) {
                return loadExternalGrammar(context, attributes, grammar);
            } else {
                final Session session = context.getSession();
                final String sessionId = session.getSessionID();
                final DocumentServer server = context.getDocumentServer();
                return loadInternalGrammar(sessionId, server, grammar, language);
            }
        } catch (IllegalAttributeException | URISyntaxException e) {
            throw new BadFetchError(e.getMessage(), e);
        }
    }

    /**
     * Takes the route of processing an inline grammar. In fact, it just
     * identifies the grammar and puts it into a temporary container. The
     * container used is the ExternalGrammar, that can hold the grammar as a
     * String representation as well as the corresponding media type, if one is
     * applicable.
     *
     * @param sessionId
     *            the session id
     * @param server
     *            the document server
     * @param grammar
     *            takes a VoiceXML Node and processes the contained grammar
     * @param language
     *          the default language
     *
     * @return The result of the processing. A grammar representation which can
     *         be used to transform into a RuleGrammar.
     * @throws UnsupportedFormatError
     *             If the grammar could not be identified. This means, the
     *             grammar is not valid or (even worse) not supported.
     * @throws URISyntaxException
     *             error generating the URI for the document
     */
    private GrammarDocument loadInternalGrammar(final String sessionId, final DocumentServer server,
            final Grammar grammar, final Locale language) throws UnsupportedFormatError, URISyntaxException {
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("loading internal grammar");
        }
        // Set the language if omitted
        final Locale grammarLanguage = grammar.getXmlLangObject();
        if (grammarLanguage == null) {
            grammar.setXmlLang(language);
        }
        // Create an internal grammar document thereof and publicize it to the
        // server
        final GrammarDocument document = new InternalGrammarDocument(grammar);
        server.addGrammarDocument(sessionId, document);
        return document;
    }

    /**
     * Take the route of processing an external grammar.
     *
     * @param context
     *            The current context
     * @param attributes
     *            attributes governing the fetch.
     * @param grammar
     *            The grammar to be processed.
     *
     * @return Is just the string representation of the grammar as well as the
     *         type.
     *
     * @throws UnsupportedFormatError
     *             If an unsupported grammar has to be processed.
     * @throws BadFetchError
     *             If the document could not be fetched successfully.
     * @throws SemanticError
     *             if the srcexpr attribute could not be evaluated
     * @exception URISyntaxException
     *                if the URI of the external grammar could not be resolved
     */
    private GrammarDocument loadExternalGrammar(final VoiceXmlInterpreterContext context,
            final FetchAttributes attributes, final Grammar grammar)
            throws BadFetchError, UnsupportedFormatError, SemanticError, URISyntaxException {
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("loading external grammar");
        }

        // First of all, we need to check, if user has provided any
        // grammar type.
        URI src = getExternalUriSrc(grammar, context);
        if (src.getFragment() != null) {
            // TODO add support for URI fragments
            LOGGER.warn("URI fragments are currently not supported: " + "ignoring fragment");
            src = new URI(src.getScheme(), src.getUserInfo(), src.getHost(), src.getPort(), src.getPath(),
                    src.getQuery(), null);
        }

        // Now load the grammar
        LOGGER.info("loading grammar from source: '" + src + "'");
        final FetchAttributes adaptedAttributes = adaptFetchAttributes(attributes, grammar);
        final GrammarDocument document = context.acquireExternalGrammar(src, adaptedAttributes);
        if (document == null) {
            throw new BadFetchError("Unable to load grammar '" + src + "'!");
        }
        return document;
    }

    /**
     * Retrieves the URI from the grammar node by either returning the src
     * attribute or by evaluating the srcexpr attribute.
     * 
     * @param grammar
     *            the current grammar node
     * @param context
     *            the VoiceXML interpreter context
     * @return grammar URI, <code>null</code> if there is no value defined
     * @throws URISyntaxException
     *             error creating an URI from the attribute
     * @throws SemanticError
     *             error evaluating the srcexpr attribute
     * @throws BadFetchError
     *             both, src and srcexpr were specified
     * @since 0.7.4
     */
    private URI getExternalUriSrc(final Grammar grammar, final VoiceXmlInterpreterContext context)
            throws URISyntaxException, SemanticError, BadFetchError {
        final URI src = grammar.getSrcUri();
        if (src != null) {
            return src;
        }
        final String srcexpr = grammar.getSrcexpr();
        if (srcexpr == null) {
            LOGGER.warn("unable to resolve the external URI: " + "neither a src nor a srcexpr found");
            return null;
        }
        final String unescapedSrcexpr = StringEscapeUtils.unescapeXml(srcexpr);
        final DataModel model = context.getDataModel();
        final String value = model.evaluateExpression(unescapedSrcexpr, String.class);
        if ((value == null) || (value == model.getUndefinedValue())) {
            LOGGER.warn("srcexpr does not describe a valid uri");
            return null;
        }
        return new URI(value);
    }

    /**
     * Extracts the fetch attributes from the grammar and overrides the settings
     * of the document default fetch attributes.
     * 
     * @param docAttributes
     *            fetch attributes for the document.
     * @param grammar
     *            the current grammar.
     * @return attributes governing the fetch.
     */
    private FetchAttributes adaptFetchAttributes(final FetchAttributes docAttributes, final Grammar grammar) {
        final FetchAttributes attributes;
        if (docAttributes == null) {
            attributes = new FetchAttributes();
        } else {
            attributes = new FetchAttributes(docAttributes);
        }

        final String fetchHint = grammar.getFetchhint();
        if (fetchHint != null) {
            attributes.setFetchHint(fetchHint);
        }
        final long fetchTimeout = grammar.getFetchTimeoutAsMsec();
        if (fetchTimeout > 0) {
            attributes.setFetchTimeout(fetchTimeout);
        }
        final long maxAge = grammar.getMaxageAsMsec();
        if (maxAge > 0) {
            attributes.setMaxage(maxAge);
        }
        final long maxStale = grammar.getMaxageAsMsec();
        if (maxStale > 0) {
            attributes.setMaxstale(maxStale);
        }

        return attributes;
    }
}