Search in sources :

Example 1 with BooleanValue

use of org.exist.xquery.value.BooleanValue in project exist by eXist-db.

the class Jaxv method eval.

public Sequence eval(Sequence[] args, Sequence contextSequence) throws XPathException {
    // Check input parameters
    if (args.length != 2 && args.length != 3) {
        return Sequence.EMPTY_SEQUENCE;
    }
    final ValidationReport report = new ValidationReport();
    StreamSource instance = null;
    StreamSource[] grammars = null;
    String schemaLang = XMLConstants.W3C_XML_SCHEMA_NS_URI;
    try {
        report.start();
        // Get inputstream for instance document
        instance = Shared.getStreamSource(args[0].itemAt(0), context);
        // Validate using resource speciefied in second parameter
        grammars = Shared.getStreamSource(args[1], context);
        // Check input
        for (final StreamSource grammar : grammars) {
            final String grammarUrl = grammar.getSystemId();
            if (grammarUrl != null && !grammarUrl.endsWith(".xsd") && !grammarUrl.endsWith(".rng")) {
                throw new XPathException("Only XML schemas (.xsd) and RELAXNG grammars (.rng) are supported" + ", depending on the used XML parser.");
            }
        }
        // Fetch third argument if available, and override defailt value
        if (args.length == 3) {
            schemaLang = args[2].getStringValue();
        }
        // Get language specific factory
        SchemaFactory factory = null;
        try {
            factory = SchemaFactory.newInstance(schemaLang);
        } catch (final IllegalArgumentException ex) {
            final String msg = "Schema language '" + schemaLang + "' is not supported. " + ex.getMessage();
            LOG.error(msg);
            throw new XPathException(msg);
        }
        // Create grammar
        final Schema schema = factory.newSchema(grammars);
        // Setup validator
        final Validator validator = schema.newValidator();
        validator.setErrorHandler(report);
        // Perform validation
        validator.validate(instance);
    } catch (final MalformedURLException ex) {
        LOG.error(ex.getMessage());
        report.setException(ex);
    } catch (final Throwable ex) {
        LOG.error(ex);
        report.setException(ex);
    } finally {
        report.stop();
        Shared.closeStreamSource(instance);
        Shared.closeStreamSources(grammars);
    }
    // Create response
    if (isCalledAs("jaxv")) {
        final Sequence result = new ValueSequence();
        result.add(new BooleanValue(report.isValid()));
        return result;
    } else /* isCalledAs("jaxv-report") */
    {
        context.pushDocumentContext();
        try {
            final MemTreeBuilder builder = context.getDocumentBuilder();
            final NodeImpl result = Shared.writeReport(report, builder);
            return result;
        } finally {
            context.popDocumentContext();
        }
    }
}
Also used : SchemaFactory(javax.xml.validation.SchemaFactory) MalformedURLException(java.net.MalformedURLException) NodeImpl(org.exist.dom.memtree.NodeImpl) XPathException(org.exist.xquery.XPathException) StreamSource(javax.xml.transform.stream.StreamSource) Schema(javax.xml.validation.Schema) ValueSequence(org.exist.xquery.value.ValueSequence) Sequence(org.exist.xquery.value.Sequence) MemTreeBuilder(org.exist.dom.memtree.MemTreeBuilder) ValidationReport(org.exist.validation.ValidationReport) BooleanValue(org.exist.xquery.value.BooleanValue) ValueSequence(org.exist.xquery.value.ValueSequence) Validator(javax.xml.validation.Validator)

Example 2 with BooleanValue

use of org.exist.xquery.value.BooleanValue in project exist by eXist-db.

the class Jaxp method eval.

public Sequence eval(Sequence[] args, Sequence contextSequence) throws XPathException {
    XMLEntityResolver entityResolver = null;
    GrammarPool grammarPool = null;
    final ValidationReport report = new ValidationReport();
    ContentHandler contenthandler = null;
    MemTreeBuilder instanceBuilder = null;
    InputSource instance = null;
    if (isCalledAs("jaxp-parse")) {
        instanceBuilder = context.getDocumentBuilder();
        // (namespace?)
        contenthandler = new DocumentBuilderReceiver(instanceBuilder, true);
    } else {
        contenthandler = new ValidationContentHandler();
    }
    try {
        report.start();
        // Get initialized parser
        final XMLReader xmlReader = getXMLReader();
        // Setup validation reporting
        xmlReader.setContentHandler(contenthandler);
        xmlReader.setErrorHandler(report);
        // Get inputstream for instance document
        instance = Shared.getInputSource(args[0].itemAt(0), context);
        // Handle catalog
        if (args.length == 2) {
            LOG.debug("No Catalog specified");
        } else if (args[2].isEmpty()) {
            // Use system catalog
            LOG.debug("Using system catalog.");
            final Configuration config = brokerPool.getConfiguration();
            entityResolver = (eXistXMLCatalogResolver) config.getProperty(XMLReaderObjectFactory.CATALOG_RESOLVER);
            setXmlReaderEnitityResolver(xmlReader, entityResolver);
        } else {
            // Get URL for catalog
            final String[] catalogUrls = Shared.getUrls(args[2]);
            final String singleUrl = catalogUrls[0];
            if (singleUrl.endsWith("/")) {
                // Search grammar in collection specified by URL. Just one collection is used.
                LOG.debug("Search for grammar in {}", singleUrl);
                entityResolver = new SearchResourceResolver(catalogUrls[0], brokerPool);
                setXmlReaderEnitityResolver(xmlReader, entityResolver);
            } else if (singleUrl.endsWith(".xml")) {
                LOG.debug("Using catalogs {}", getStrings(catalogUrls));
                entityResolver = new eXistXMLCatalogResolver();
                ((eXistXMLCatalogResolver) entityResolver).setCatalogList(catalogUrls);
                setXmlReaderEnitityResolver(xmlReader, entityResolver);
            } else {
                LOG.error("Catalog URLs should end on / or .xml");
            }
        }
        // Use grammarpool
        final boolean useCache = ((BooleanValue) args[1].itemAt(0)).getValue();
        if (useCache) {
            LOG.debug("Grammar caching enabled.");
            final Configuration config = brokerPool.getConfiguration();
            grammarPool = (GrammarPool) config.getProperty(XMLReaderObjectFactory.GRAMMAR_POOL);
            xmlReader.setProperty(XMLReaderObjectFactory.APACHE_PROPERTIES_INTERNAL_GRAMMARPOOL, grammarPool);
        }
        // Jaxp document
        LOG.debug("Start parsing document");
        xmlReader.parse(instance);
        LOG.debug("Stopped parsing document");
        // Distill namespace from document
        if (contenthandler instanceof ValidationContentHandler) {
            report.setNamespaceUri(((ValidationContentHandler) contenthandler).getNamespaceUri());
        }
    } catch (final MalformedURLException ex) {
        LOG.error(ex.getMessage());
        report.setException(ex);
    } catch (final IOException ex) {
        LOG.error(ex.getCause());
        report.setException(ex);
    } catch (final Throwable ex) {
        LOG.error(ex);
        report.setException(ex);
    } finally {
        report.stop();
        Shared.closeInputSource(instance);
    }
    // Create response
    if (isCalledAs("jaxp")) {
        final Sequence result = new ValueSequence();
        result.add(new BooleanValue(report.isValid()));
        return result;
    } else /* isCalledAs("jaxp-report or jaxp-parse ") */
    {
        if (report.getThrowable() != null) {
            throw new XPathException(report.getThrowable().getMessage(), report.getThrowable());
        }
        if (contenthandler instanceof DocumentBuilderReceiver) {
            // DocumentBuilderReceiver dbr = (DocumentBuilderReceiver) contenthandler;
            return instanceBuilder.getDocument().getNode(0);
        } else {
            context.pushDocumentContext();
            try {
                final MemTreeBuilder builder = context.getDocumentBuilder();
                return Shared.writeReport(report, builder);
            } finally {
                context.popDocumentContext();
            }
        }
    }
}
Also used : ValidationContentHandler(org.exist.validation.ValidationContentHandler) InputSource(org.xml.sax.InputSource) SearchResourceResolver(org.exist.validation.resolver.SearchResourceResolver) MalformedURLException(java.net.MalformedURLException) org.exist.validation.resolver.eXistXMLCatalogResolver(org.exist.validation.resolver.eXistXMLCatalogResolver) Configuration(org.exist.util.Configuration) XPathException(org.exist.xquery.XPathException) XMLEntityResolver(org.apache.xerces.xni.parser.XMLEntityResolver) GrammarPool(org.exist.validation.GrammarPool) IOException(java.io.IOException) ValueSequence(org.exist.xquery.value.ValueSequence) Sequence(org.exist.xquery.value.Sequence) DocumentBuilderReceiver(org.exist.dom.memtree.DocumentBuilderReceiver) ContentHandler(org.xml.sax.ContentHandler) ValidationContentHandler(org.exist.validation.ValidationContentHandler) MemTreeBuilder(org.exist.dom.memtree.MemTreeBuilder) ValidationReport(org.exist.validation.ValidationReport) BooleanValue(org.exist.xquery.value.BooleanValue) ValueSequence(org.exist.xquery.value.ValueSequence) XMLReader(org.xml.sax.XMLReader)

Example 3 with BooleanValue

use of org.exist.xquery.value.BooleanValue in project exist by eXist-db.

the class ModuleInfo method eval.

/* (non-Javadoc)
	 * @see org.exist.xquery.BasicFunction#eval(org.exist.xquery.value.Sequence[], org.exist.xquery.value.Sequence)
	 */
@SuppressWarnings("unchecked")
public Sequence eval(Sequence[] args, Sequence contextSequence) throws XPathException {
    if ("get-module-description".equals(getSignature().getName().getLocalPart())) {
        final String uri = args[0].getStringValue();
        final Module[] modules = context.getModules(uri);
        if (isEmpty(modules)) {
            throw new XPathException(this, "No module found matching namespace URI: " + uri);
        }
        final Sequence result = new ValueSequence();
        for (final Module module : modules) {
            result.add(new StringValue(module.getDescription()));
        }
        return result;
    } else if ("is-module-registered".equals(getSignature().getName().getLocalPart())) {
        final String uri = args[0].getStringValue();
        final Module[] modules = context.getModules(uri);
        return new BooleanValue(modules != null && modules.length > 0);
    } else if ("mapped-modules".equals(getSignature().getName().getLocalPart())) {
        final ValueSequence resultSeq = new ValueSequence();
        for (final Iterator<String> i = context.getMappedModuleURIs(); i.hasNext(); ) {
            resultSeq.add(new StringValue(i.next()));
        }
        return resultSeq;
    } else if ("is-module-mapped".equals(getSignature().getName().getLocalPart())) {
        final String uri = args[0].getStringValue();
        return new BooleanValue(((Map<String, String>) context.getBroker().getConfiguration().getProperty(XQueryContext.PROPERTY_STATIC_MODULE_MAP)).get(uri) != null);
    } else if ("map-module".equals(getSignature().getName().getLocalPart())) {
        if (!context.getSubject().hasDbaRole()) {
            final XPathException xPathException = new XPathException(this, "Permission denied, calling user '" + context.getSubject().getName() + "' must be a DBA to call this function.");
            logger.error("Invalid user", xPathException);
            throw xPathException;
        }
        final String namespace = args[0].getStringValue();
        final String location = args[1].getStringValue();
        final Map<String, String> moduleMap = (Map<String, String>) context.getBroker().getConfiguration().getProperty(XQueryContext.PROPERTY_STATIC_MODULE_MAP);
        moduleMap.put(namespace, location);
        return Sequence.EMPTY_SEQUENCE;
    } else if ("unmap-module".equals(getSignature().getName().getLocalPart())) {
        if (!context.getSubject().hasDbaRole()) {
            final XPathException xPathException = new XPathException(this, "Permission denied, calling user '" + context.getSubject().getName() + "' must be a DBA to call this function.");
            logger.error("Invalid user", xPathException);
            throw xPathException;
        }
        final String namespace = args[0].getStringValue();
        final Map<String, String> moduleMap = (Map<String, String>) context.getBroker().getConfiguration().getProperty(XQueryContext.PROPERTY_STATIC_MODULE_MAP);
        moduleMap.remove(namespace);
        return Sequence.EMPTY_SEQUENCE;
    } else if ("get-module-info".equals(getSignature().getName().getLocalPart())) {
        context.pushDocumentContext();
        try {
            final MemTreeBuilder builder = context.getDocumentBuilder();
            builder.startElement(MODULES_QNAME, null);
            if (getArgumentCount() == 1) {
                final Module[] modules = context.getModules(args[0].getStringValue());
                if (modules != null) {
                    outputModules(builder, modules);
                }
            } else {
                for (final Iterator<Module> i = context.getRootModules(); i.hasNext(); ) {
                    final Module module = i.next();
                    outputModule(builder, module);
                }
            }
            return builder.getDocument().getNode(1);
        } finally {
            context.popDocumentContext();
        }
    } else {
        final ValueSequence resultSeq = new ValueSequence();
        final XQueryContext tempContext = new XQueryContext(context.getBroker().getBrokerPool());
        for (final Iterator<Module> i = tempContext.getRootModules(); i.hasNext(); ) {
            final Module module = i.next();
            resultSeq.add(new StringValue(module.getNamespaceURI()));
        }
        if (tempContext.getRepository().isPresent()) {
            for (final URI uri : tempContext.getRepository().get().getJavaModules()) {
                resultSeq.add(new StringValue(uri.toString()));
            }
        }
        return resultSeq;
    }
}
Also used : XPathException(org.exist.xquery.XPathException) XQueryContext(org.exist.xquery.XQueryContext) ValueSequence(org.exist.xquery.value.ValueSequence) Sequence(org.exist.xquery.value.Sequence) URI(java.net.URI) MemTreeBuilder(org.exist.dom.memtree.MemTreeBuilder) BooleanValue(org.exist.xquery.value.BooleanValue) ValueSequence(org.exist.xquery.value.ValueSequence) Module(org.exist.xquery.Module) ExternalModule(org.exist.xquery.ExternalModule) StringValue(org.exist.xquery.value.StringValue) Map(java.util.Map)

Example 4 with BooleanValue

use of org.exist.xquery.value.BooleanValue in project exist by eXist-db.

the class ExecuteFunction method eval.

@Override
public Sequence eval(Sequence[] args, Sequence contextSequence) throws XPathException {
    if (args.length == 5 || args.length == 6) {
        // was a connection and PL/SQL statement specified?
        if (args[0].isEmpty() || args[1].isEmpty()) {
            return (Sequence.EMPTY_SEQUENCE);
        }
        // get the Connection
        long connectionUID = ((IntegerValue) args[0].itemAt(0)).getLong();
        Connection connection = SQLModule.retrieveConnection(context, connectionUID);
        if (connection == null) {
            return (Sequence.EMPTY_SEQUENCE);
        }
        // get the PL/SQL statement
        String plSql = args[1].getStringValue();
        // get the input parameters (if any)
        Element parameters = null;
        if (!args[2].isEmpty()) {
            parameters = (Element) args[2].itemAt(0);
        }
        // was a result set position specified?
        int resultSetPos = 0;
        if (!args[3].isEmpty()) {
            resultSetPos = ((IntegerValue) args[3].itemAt(0)).getInt();
        }
        boolean haveReturnCode = false;
        // default value of 1 for success
        int plSqlSuccess = 1;
        if (args.length == 6) {
            // a return code is expected so what is the value indicating success?
            plSqlSuccess = ((IntegerValue) args[5].itemAt(0)).getInt();
            haveReturnCode = true;
        }
        CallableStatement statement = null;
        ResultSet resultSet = null;
        try {
            MemTreeBuilder builder = context.getDocumentBuilder();
            int iRow = 0;
            statement = connection.prepareCall(plSql);
            if (haveReturnCode) {
                statement.registerOutParameter(1, Types.NUMERIC);
            }
            if (resultSetPos != 0) {
                statement.registerOutParameter(resultSetPos, OracleTypes.CURSOR);
            }
            if (!args[2].isEmpty()) {
                setParametersOnPreparedStatement(statement, parameters);
            }
            statement.execute();
            if (haveReturnCode) {
                int returnCode = statement.getInt(1);
                if (returnCode != plSqlSuccess) {
                    LOG.error(plSql + " failed [" + returnCode + "]");
                    return (Sequence.EMPTY_SEQUENCE);
                }
            }
            if (resultSetPos != 0) {
                // iterate through the result set building an XML document
                builder.startDocument();
                builder.startElement(new QName("result", OracleModule.NAMESPACE_URI, OracleModule.PREFIX), null);
                builder.addAttribute(new QName("count", null, null), String.valueOf(-1));
                resultSet = (ResultSet) statement.getObject(resultSetPos);
                ResultSetMetaData rsmd = resultSet.getMetaData();
                int iColumns = rsmd.getColumnCount();
                while (resultSet.next()) {
                    builder.startElement(new QName("row", OracleModule.NAMESPACE_URI, OracleModule.PREFIX), null);
                    builder.addAttribute(new QName("index", null, null), String.valueOf(resultSet.getRow()));
                    // get each tuple in the row
                    for (int i = 0; i < iColumns; i++) {
                        String columnName = rsmd.getColumnLabel(i + 1);
                        if (columnName != null) {
                            String colValue = resultSet.getString(i + 1);
                            String colElement = "field";
                            if (((BooleanValue) args[4].itemAt(0)).effectiveBooleanValue() && columnName.length() > 0) {
                                // use column names as the XML node
                                /**
                                 * Spaces in column names are replaced with
                                 * underscore's
                                 */
                                colElement = SQLUtils.escapeXmlAttr(columnName.replace(' ', '_'));
                            }
                            builder.startElement(new QName(colElement, OracleModule.NAMESPACE_URI, OracleModule.PREFIX), null);
                            if (!((BooleanValue) args[4].itemAt(0)).effectiveBooleanValue() || columnName.length() <= 0) {
                                String name;
                                if (columnName.length() > 0) {
                                    name = SQLUtils.escapeXmlAttr(columnName);
                                } else {
                                    name = "Column: " + String.valueOf(i + 1);
                                }
                                builder.addAttribute(new QName("name", null, null), name);
                            }
                            builder.addAttribute(new QName("type", OracleModule.NAMESPACE_URI, OracleModule.PREFIX), rsmd.getColumnTypeName(i + 1));
                            builder.addAttribute(new QName("type", Namespaces.SCHEMA_NS, "xs"), Type.getTypeName(SQLUtils.sqlTypeToXMLType(rsmd.getColumnType(i + 1))));
                            if (resultSet.wasNull()) {
                                // Add a null indicator attribute if the value was SQL Null
                                builder.addAttribute(new QName("null", OracleModule.NAMESPACE_URI, OracleModule.PREFIX), "true");
                            }
                            if (colValue != null) {
                                builder.characters(SQLUtils.escapeXmlText(colValue));
                            }
                            builder.endElement();
                        }
                    }
                    builder.endElement();
                    iRow++;
                }
                builder.endElement();
                // Change the root element count attribute to have the correct value
                NodeValue node = (NodeValue) builder.getDocument().getDocumentElement();
                Node count = node.getNode().getAttributes().getNamedItem("count");
                if (count != null) {
                    count.setNodeValue(String.valueOf(iRow));
                }
                builder.endDocument();
                // return the XML result set
                return (node);
            } else {
                // there was no result set so just return an empty sequence
                return (Sequence.EMPTY_SEQUENCE);
            }
        } catch (SQLException sqle) {
            LOG.error("oracle:execute() Caught SQLException \"" + sqle.getMessage() + "\" for PL/SQL: \"" + plSql + "\"", sqle);
            // return details about the SQLException
            MemTreeBuilder builder = context.getDocumentBuilder();
            builder.startDocument();
            builder.startElement(new QName("exception", OracleModule.NAMESPACE_URI, OracleModule.PREFIX), null);
            boolean recoverable = false;
            if (sqle instanceof SQLRecoverableException) {
                recoverable = true;
            }
            builder.addAttribute(new QName("recoverable", null, null), String.valueOf(recoverable));
            builder.startElement(new QName("state", OracleModule.NAMESPACE_URI, OracleModule.PREFIX), null);
            String sqlState = sqle.getSQLState();
            if (sqlState != null) {
                builder.characters(sqle.getSQLState());
            } else {
                builder.characters("null");
            }
            builder.endElement();
            builder.startElement(new QName("message", OracleModule.NAMESPACE_URI, OracleModule.PREFIX), null);
            builder.characters(sqle.getMessage());
            builder.endElement();
            builder.startElement(new QName("stack-trace", OracleModule.NAMESPACE_URI, OracleModule.PREFIX), null);
            ByteArrayOutputStream bufStackTrace = new ByteArrayOutputStream();
            sqle.printStackTrace(new PrintStream(bufStackTrace));
            builder.characters(new String(bufStackTrace.toByteArray()));
            builder.endElement();
            builder.startElement(new QName("oracle", OracleModule.NAMESPACE_URI, OracleModule.PREFIX), null);
            builder.characters(SQLUtils.escapeXmlText(plSql));
            builder.endElement();
            int line = getLine();
            int column = getColumn();
            builder.startElement(new QName("xquery", OracleModule.NAMESPACE_URI, OracleModule.PREFIX), null);
            builder.addAttribute(new QName("line", null, null), String.valueOf(line));
            builder.addAttribute(new QName("column", null, null), String.valueOf(column));
            builder.endElement();
            builder.endElement();
            builder.endDocument();
            return (NodeValue) builder.getDocument().getDocumentElement();
        } finally {
            release(connection, statement, resultSet);
        }
    } else {
        throw new XPathException("Invalid number of arguments [" + args.length + "]");
    }
}
Also used : NodeValue(org.exist.xquery.value.NodeValue) PrintStream(java.io.PrintStream) SQLRecoverableException(java.sql.SQLRecoverableException) SQLException(java.sql.SQLException) XPathException(org.exist.xquery.XPathException) QName(org.exist.dom.QName) IntegerValue(org.exist.xquery.value.IntegerValue) Element(org.w3c.dom.Element) Node(org.w3c.dom.Node) Connection(java.sql.Connection) ByteArrayOutputStream(org.apache.commons.io.output.ByteArrayOutputStream) ResultSetMetaData(java.sql.ResultSetMetaData) MemTreeBuilder(org.exist.dom.memtree.MemTreeBuilder) CallableStatement(java.sql.CallableStatement) BooleanValue(org.exist.xquery.value.BooleanValue) ResultSet(java.sql.ResultSet)

Example 5 with BooleanValue

use of org.exist.xquery.value.BooleanValue in project exist by eXist-db.

the class MailFolderFunctions method closeMailFolder.

private Sequence closeMailFolder(Sequence[] args, Sequence contextSequence) throws XPathException {
    // was a folder handle specified?
    if (args[0].isEmpty()) {
        throw (new XPathException(this, "Folder handle not specified"));
    }
    boolean expunge = ((BooleanValue) args[1].itemAt(0)).effectiveBooleanValue();
    // get the Folder
    long folderHandle = ((IntegerValue) args[0].itemAt(0)).getLong();
    Folder folder = MailModule.retrieveFolder(context, folderHandle);
    if (folder == null) {
        throw (new XPathException(this, "Invalid Folder handle specified"));
    }
    try {
        folder.close(expunge);
    } catch (MessagingException me) {
        throw (new XPathException(this, "Failed to close mail folder", me));
    } finally {
        MailModule.removeFolder(context, folderHandle);
    }
    return (Sequence.EMPTY_SEQUENCE);
}
Also used : XPathException(org.exist.xquery.XPathException) MessagingException(jakarta.mail.MessagingException) BooleanValue(org.exist.xquery.value.BooleanValue) IntegerValue(org.exist.xquery.value.IntegerValue) Folder(jakarta.mail.Folder)

Aggregations

BooleanValue (org.exist.xquery.value.BooleanValue)15 XPathException (org.exist.xquery.XPathException)9 Sequence (org.exist.xquery.value.Sequence)9 MemTreeBuilder (org.exist.dom.memtree.MemTreeBuilder)6 ValueSequence (org.exist.xquery.value.ValueSequence)5 NodeValue (org.exist.xquery.value.NodeValue)4 MalformedURLException (java.net.MalformedURLException)3 UnsynchronizedByteArrayInputStream (org.apache.commons.io.input.UnsynchronizedByteArrayInputStream)3 ValidationReport (org.exist.validation.ValidationReport)3 Base64BinaryValueType (org.exist.xquery.value.Base64BinaryValueType)3 DoubleValue (org.exist.xquery.value.DoubleValue)3 StringValue (org.exist.xquery.value.StringValue)3 IOException (java.io.IOException)2 Date (java.util.Date)2 QName (org.exist.dom.QName)2 NodeImpl (org.exist.dom.memtree.NodeImpl)2 IntegerValue (org.exist.xquery.value.IntegerValue)2 PropertyMapBuilder (com.thaiopensource.util.PropertyMapBuilder)1 SchemaReader (com.thaiopensource.validate.SchemaReader)1 ValidationDriver (com.thaiopensource.validate.ValidationDriver)1