You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by sb...@apache.org on 2014/12/19 09:00:12 UTC

incubator-ignite git commit: # IGNITE-32 WIP: parse db metadata and generating XML configs.

Repository: incubator-ignite
Updated Branches:
  refs/heads/ignite-32 [created] ac306c5e0


# IGNITE-32 WIP: parse db metadata and generating XML configs.


Project: http://git-wip-us.apache.org/repos/asf/incubator-ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ignite/commit/ac306c5e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ignite/tree/ac306c5e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ignite/diff/ac306c5e

Branch: refs/heads/ignite-32
Commit: ac306c5e02dad55ac0284b173ab67588b60e4477
Parents: 3032bee
Author: AKuznetsov <ak...@gridgain.com>
Authored: Fri Dec 19 14:59:48 2014 +0700
Committer: AKuznetsov <ak...@gridgain.com>
Committed: Fri Dec 19 14:59:48 2014 +0700

----------------------------------------------------------------------
 .../cache/query/GridCacheQueryTypeMetadata.java |  14 +-
 modules/schema-load/pom.xml                     |  54 ++++
 .../apache/ignite/schema/db/DbConnection.java   | 102 +++++++
 .../ignite/schema/db/DbMetadataParser.java      | 184 ++++++++++++
 .../apache/ignite/schema/util/SchemaUtils.java  |  67 +++++
 .../ignite/schema/xml/XmlTransformer.java       | 278 +++++++++++++++++++
 pom.xml                                         |   1 +
 7 files changed, 695 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/ac306c5e/modules/core/src/main/java/org/gridgain/grid/cache/query/GridCacheQueryTypeMetadata.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/gridgain/grid/cache/query/GridCacheQueryTypeMetadata.java b/modules/core/src/main/java/org/gridgain/grid/cache/query/GridCacheQueryTypeMetadata.java
index 946ad19..b213a18 100644
--- a/modules/core/src/main/java/org/gridgain/grid/cache/query/GridCacheQueryTypeMetadata.java
+++ b/modules/core/src/main/java/org/gridgain/grid/cache/query/GridCacheQueryTypeMetadata.java
@@ -25,19 +25,19 @@ public class GridCacheQueryTypeMetadata {
 
     /** Fields to be queried, in addition to indexed fields. */
     @GridToStringInclude
-    private Map<String, Class<?>> qryFlds = new HashMap<>();
+    private Map<String, Class<?>> qryFlds;
 
     /** Fields to index in ascending order. */
     @GridToStringInclude
-    private Map<String, Class<?>> ascFlds = new HashMap<>();
+    private Map<String, Class<?>> ascFlds;
 
     /** Fields to index in descending order. */
     @GridToStringInclude
-    private Map<String, Class<?>> descFlds = new HashMap<>();
+    private Map<String, Class<?>> descFlds;
 
     /** Fields to index as text. */
     @GridToStringInclude
-    private Collection<String> txtFlds = new LinkedHashSet<>();
+    private Collection<String> txtFlds;
 
     /** Fields to create group indexes for. */
     @GridToStringInclude
@@ -47,7 +47,11 @@ public class GridCacheQueryTypeMetadata {
      * Default constructor.
      */
     public GridCacheQueryTypeMetadata() {
-        // No-op.
+        qryFlds = new LinkedHashMap<>();
+        ascFlds = new LinkedHashMap<>();
+        descFlds = new LinkedHashMap<>();
+        txtFlds = new LinkedHashSet<>();
+        grps = new LinkedHashMap<>();
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/ac306c5e/modules/schema-load/pom.xml
----------------------------------------------------------------------
diff --git a/modules/schema-load/pom.xml b/modules/schema-load/pom.xml
new file mode 100644
index 0000000..bca95b9
--- /dev/null
+++ b/modules/schema-load/pom.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+    _________        _____ __________________        _____
+    __  ____/___________(_)______  /__  ____/______ ____(_)_______
+    _  / __  __  ___/__  / _  __  / _  / __  _  __ `/__  / __  __ \
+    / /_/ /  _  /    _  /  / /_/ /  / /_/ /  / /_/ / _  /  _  / / /
+    \____/   /_/     /_/   \_,__/   \____/   \__,_/  /_/   /_/ /_/
+
+    Copyright (C) GridGain Systems. All Rights Reserved.
+-->
+<!--
+    POM file.
+-->
+<project
+    xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.ignite</groupId>
+        <artifactId>ignite</artifactId>
+        <version>${ignite.version}</version>
+        <relativePath>../..</relativePath>
+    </parent>
+
+    <artifactId>ignite-schema-load</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.ignite</groupId>
+            <artifactId>ignite-core</artifactId>
+            <version>${ignite.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.h2database</groupId>
+            <artifactId>h2</artifactId>
+            <version>1.3.175</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <resources>
+            <resource>
+                <directory>src/main/java</directory>
+                <excludes>
+                    <exclude>**/*.java</exclude>
+                </excludes>
+            </resource>
+        </resources>
+    </build>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/ac306c5e/modules/schema-load/src/main/java/org/apache/ignite/schema/db/DbConnection.java
----------------------------------------------------------------------
diff --git a/modules/schema-load/src/main/java/org/apache/ignite/schema/db/DbConnection.java b/modules/schema-load/src/main/java/org/apache/ignite/schema/db/DbConnection.java
new file mode 100644
index 0000000..d6bce39
--- /dev/null
+++ b/modules/schema-load/src/main/java/org/apache/ignite/schema/db/DbConnection.java
@@ -0,0 +1,102 @@
+/* @java.file.header */
+
+/*  _________        _____ __________________        _____
+ *  __  ____/___________(_)______  /__  ____/______ ____(_)_______
+ *  _  / __  __  ___/__  / _  __  / _  / __  _  __ `/__  / __  __ \
+ *  / /_/ /  _  /    _  /  / /_/ /  / /_/ /  / /_/ / _  /  _  / / /
+ *  \____/   /_/     /_/   \_,__/   \____/   \__,_/  /_/   /_/ /_/
+ */
+
+package org.apache.ignite.schema.db;
+
+import org.apache.ignite.schema.xml.*;
+import org.gridgain.grid.cache.query.*;
+
+import javax.xml.transform.*;
+import javax.xml.transform.stream.*;
+import java.io.*;
+import java.sql.*;
+import java.util.*;
+
+/**
+ * TODO: Add class description.
+ */
+public class DbConnection {
+    /**
+     * TODO Temporary test.
+     *
+     * @param args App args...
+     */
+    public static void main(String[] args) {
+        try {
+            Class.forName("org.h2.Driver");
+            Connection conn = DriverManager.getConnection("jdbc:h2:mem:test", "sa", "");
+
+            Statement stmt = conn.createStatement();
+
+            stmt.executeUpdate("CREATE TABLE Organization (id integer, name varchar(50), city varchar(50))");
+            stmt.executeUpdate("CREATE TABLE Person (id integer, org_id integer, name varchar(50))");
+
+            stmt.executeUpdate("CREATE INDEX Org_Name_IDX On Organization (name)");
+            stmt.executeUpdate("CREATE INDEX Org_Name_City_IDX On Organization (name, city)");
+            stmt.executeUpdate("CREATE INDEX Person_Name_IDX1 On Person (name)");
+            stmt.executeUpdate("CREATE INDEX Person_Name_IDX2 On Person (name desc)");
+
+            conn.commit();
+
+            stmt.executeUpdate("INSERT INTO Organization(id, name) VALUES (1, 'GridGain')" );
+            stmt.executeUpdate("INSERT INTO Organization(id, name) VALUES (2, 'Apache')" );
+
+            stmt.executeUpdate("INSERT INTO Person(id, org_id, name) VALUES (1, 1, 'Kuznetsov')");
+            stmt.executeUpdate("INSERT INTO Person(id, org_id, name) VALUES (2, 2, 'Boudnik')");
+
+            DbMetadataParser parser = new DbMetadataParser(conn);
+
+            ResultSet schemas = parser.schemas();
+
+            Collection<GridCacheQueryTypeMetadata> all = new ArrayList<>(30);
+
+            while(schemas.next()) {
+                String schema = schemas.getString(1);
+
+                if (!"PUBLIC".equalsIgnoreCase(schema))
+                    continue;
+
+                String cat = schemas.getString(2);
+
+                System.out.println("Schema:" + schema + " Catalog: " + cat);
+
+                ResultSet tbls = parser.tables(cat, schema);
+
+                while(tbls.next()) {
+                    String tbl = tbls.getString(3);
+
+                    System.out.println("   Table:" + tbl);
+
+                    GridCacheQueryTypeMetadata meta = parser.parse(cat, schema, tbl);
+
+                    all.add(meta);
+
+                    XmlTransformer transformer = new XmlTransformer(4);
+
+                    Result res = new StreamResult(new File("C:/temp/ignite/" + tbl + ".xml"));
+
+                    transformer.transform(meta, res);
+                }
+
+                XmlTransformer transformer = new XmlTransformer(4);
+
+                Result res = new StreamResult(new File("C:/temp/ignite/all.xml"));
+
+                transformer.transform(all, res);
+            }
+
+            conn.close();
+
+           System.out.println("Done!");
+        }
+        catch(Throwable ex) {
+            ex.printStackTrace();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/ac306c5e/modules/schema-load/src/main/java/org/apache/ignite/schema/db/DbMetadataParser.java
----------------------------------------------------------------------
diff --git a/modules/schema-load/src/main/java/org/apache/ignite/schema/db/DbMetadataParser.java b/modules/schema-load/src/main/java/org/apache/ignite/schema/db/DbMetadataParser.java
new file mode 100644
index 0000000..e7e2cb9
--- /dev/null
+++ b/modules/schema-load/src/main/java/org/apache/ignite/schema/db/DbMetadataParser.java
@@ -0,0 +1,184 @@
+/* @java.file.header */
+
+/*  _________        _____ __________________        _____
+ *  __  ____/___________(_)______  /__  ____/______ ____(_)_______
+ *  _  / __  __  ___/__  / _  __  / _  / __  _  __ `/__  / __  __ \
+ *  / /_/ /  _  /    _  /  / /_/ /  / /_/ /  / /_/ / _  /  _  / / /
+ *  \____/   /_/     /_/   \_,__/   \____/   \__,_/  /_/   /_/ /_/
+ */
+
+package org.apache.ignite.schema.db;
+
+import org.apache.ignite.lang.*;
+import org.gridgain.grid.cache.query.*;
+
+import java.math.*;
+import java.net.*;
+import java.sql.*;
+import java.sql.Date;
+import java.util.*;
+
+import static java.sql.Types.*;
+import static org.apache.ignite.schema.util.SchemaUtils.*;
+
+/**
+ * Database metadata parser.
+ */
+public class DbMetadataParser {
+    /** */
+    private final DatabaseMetaData meta;
+
+    /**
+     * @param conn Database connection.
+     * @throws SQLException If a database access error occurs.
+     */
+    public DbMetadataParser(Connection conn) throws SQLException {
+        meta = conn.getMetaData();
+    }
+
+    /**
+     * @return Schemas description.
+     * @throws SQLException If a database access error occurs.
+     */
+    public ResultSet schemas() throws SQLException {
+        return meta.getSchemas();
+    }
+
+    /**
+     * @return Tables description.
+     * @throws SQLException If a database access error occurs.
+     */
+    public ResultSet tables(String catalog, String schema) throws SQLException {
+        return meta.getTables(catalog, schema, "%", null);
+    }
+
+    /**
+     * @param type SQL data type.
+     * @return Java data type.
+     */
+    private Class<?> dataType(int type) {
+        switch (type) {
+            case BIT:
+            case BOOLEAN:
+                return Boolean.class;
+
+            case TINYINT:
+                return Byte.class;
+
+            case SMALLINT:
+                return Short.class;
+
+            case INTEGER:
+                return Integer.class;
+
+            case BIGINT:
+                return Long.class;
+
+            case REAL:
+                return Float.class;
+
+            case FLOAT:
+            case DOUBLE:
+                return Double.class;
+
+            case NUMERIC:
+            case DECIMAL:
+                return BigDecimal.class;
+
+            case CHAR:
+            case VARCHAR:
+            case LONGVARCHAR:
+            case NCHAR:
+            case NVARCHAR:
+            case LONGNVARCHAR:
+                return String.class;
+
+            case DATE:
+                return Date.class;
+
+            case TIME:
+                return Time.class;
+
+            case TIMESTAMP:
+                return Timestamp.class;
+
+            case BINARY:
+            case VARBINARY:
+            case LONGVARBINARY:
+            case ARRAY:
+            case BLOB:
+            case CLOB:
+            case NCLOB:
+                return Array.class;
+
+            case NULL:
+                return Void.class;
+
+            case DATALINK:
+                return URL.class;
+
+            // OTHER, JAVA_OBJECT, DISTINCT, STRUCT, REF, ROWID, SQLXML
+            default:
+                return Object.class;
+        }
+    }
+
+    /**
+     * Parse database metadata.
+     *
+     * @param catalog Catalog name.
+     * @param schema Schema name.
+     * @param tbl Table name.
+     * @return New initialized instance of {@code GridCacheQueryTypeMetadata}.
+     * @throws SQLException If parsing failed.
+     */
+    public GridCacheQueryTypeMetadata parse(String catalog, String schema, String tbl) throws SQLException {
+        GridCacheQueryTypeMetadata res = new GridCacheQueryTypeMetadata();
+
+        Map<String, Class<?>> qryFields = res.getQueryFields();
+        Map<String, Class<?>> ascFields = res.getAscendingFields();
+        Map<String, Class<?>> descFields = res.getDescendingFields();
+        Map<String, LinkedHashMap<String, IgniteBiTuple<Class<?>, Boolean>>> groups = res.getGroups();
+
+        res.setType(toJavaClassName(tbl));
+
+        ResultSet flds = meta.getColumns(catalog, schema, tbl, null);
+
+        while (flds.next()) {
+            String col = toJavaFieldName(flds.getString(4));
+
+            qryFields.put(col, dataType(flds.getInt(5)));
+        }
+
+        ResultSet idxs = meta.getIndexInfo(catalog, schema, tbl, false, true);
+
+        while (idxs.next()) {
+            String idx = toJavaFieldName(idxs.getString(6));
+            String col = toJavaFieldName(idxs.getString(9));
+            String askOrDesc = idxs.getString(10);
+
+            LinkedHashMap<String, IgniteBiTuple<Class<?>, Boolean>> idxCols = groups.get(idx);
+
+            if (idxCols == null) {
+                idxCols = new LinkedHashMap<>();
+
+                groups.put(idx, idxCols);
+            }
+
+            Class<?> dataType = qryFields.get(col);
+
+            Boolean desc = askOrDesc != null ? "D".equals(askOrDesc) : null;
+
+            if (desc != null) {
+                if (desc)
+                    descFields.put(col, dataType);
+                else
+                    ascFields.put(col, dataType);
+            }
+
+            idxCols.put(col, new IgniteBiTuple<Class<?>, Boolean>(dataType, desc));
+        }
+
+        return res;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/ac306c5e/modules/schema-load/src/main/java/org/apache/ignite/schema/util/SchemaUtils.java
----------------------------------------------------------------------
diff --git a/modules/schema-load/src/main/java/org/apache/ignite/schema/util/SchemaUtils.java b/modules/schema-load/src/main/java/org/apache/ignite/schema/util/SchemaUtils.java
new file mode 100644
index 0000000..6e0e9f1
--- /dev/null
+++ b/modules/schema-load/src/main/java/org/apache/ignite/schema/util/SchemaUtils.java
@@ -0,0 +1,67 @@
+/* @java.file.header */
+
+/*  _________        _____ __________________        _____
+ *  __  ____/___________(_)______  /__  ____/______ ____(_)_______
+ *  _  / __  __  ___/__  / _  __  / _  / __  _  __ `/__  / __  __ \
+ *  / /_/ /  _  /    _  /  / /_/ /  / /_/ /  / /_/ / _  /  _  / / /
+ *  \____/   /_/     /_/   \_,__/   \____/   \__,_/  /_/   /_/ /_/
+ */
+
+package org.apache.ignite.schema.util;
+
+/**
+ * TODO: Add class description.
+ */
+public class SchemaUtils {
+    /**
+     * @param str Source string.
+     * @return String with each word first letters capitalized.
+     */
+    public static String capitalize(String str) {
+        int len = str.length();
+
+        StringBuilder buf = new StringBuilder(len);
+
+        boolean capitalizeNext = true;
+
+        for (int i = 0; i < len; i++) {
+            char ch = str.charAt(i);
+
+            if (Character.isWhitespace(ch))
+                capitalizeNext = true;
+            else if (capitalizeNext) {
+                buf.append(Character.toUpperCase(ch));
+
+                capitalizeNext = false;
+            }
+            else
+                buf.append(Character.toLowerCase(ch));
+        }
+
+        return buf.toString();
+    }
+
+    /**
+     * @param str Source string.
+     * @return String with first letters in lower case.
+     */
+    public static String uncapitalize(String str) {
+        return Character.toLowerCase(str.charAt(0)) + str.substring(1);
+    }
+
+    /**
+     * @param name Source name.
+     * @return String converted to java class name notation.
+     */
+    public static String toJavaClassName(String name) {
+        return capitalize(name.replace("_", " ")).replace(" ", "");
+    }
+
+    /**
+     * @param name Source name.
+     * @return String converted to java field name notation.
+     */
+    public static String toJavaFieldName(String name) {
+        return uncapitalize(toJavaClassName(name));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/ac306c5e/modules/schema-load/src/main/java/org/apache/ignite/schema/xml/XmlTransformer.java
----------------------------------------------------------------------
diff --git a/modules/schema-load/src/main/java/org/apache/ignite/schema/xml/XmlTransformer.java b/modules/schema-load/src/main/java/org/apache/ignite/schema/xml/XmlTransformer.java
new file mode 100644
index 0000000..6a51604
--- /dev/null
+++ b/modules/schema-load/src/main/java/org/apache/ignite/schema/xml/XmlTransformer.java
@@ -0,0 +1,278 @@
+/* @java.file.header */
+
+/*  _________        _____ __________________        _____
+ *  __  ____/___________(_)______  /__  ____/______ ____(_)_______
+ *  _  / __  __  ___/__  / _  __  / _  / __  _  __ `/__  / __  __ \
+ *  / /_/ /  _  /    _  /  / /_/ /  / /_/ /  / /_/ / _  /  _  / / /
+ *  \____/   /_/     /_/   \_,__/   \____/   \__,_/  /_/   /_/ /_/
+ */
+
+package org.apache.ignite.schema.xml;
+
+import org.apache.ignite.lang.*;
+import org.gridgain.grid.cache.query.*;
+import org.gridgain.grid.util.typedef.*;
+import org.w3c.dom.*;
+
+import javax.xml.parsers.*;
+import javax.xml.transform.*;
+import javax.xml.transform.dom.*;
+import java.util.*;
+
+/**
+ * Transformer that will take cache query metadata and write it to xml.
+ */
+public class XmlTransformer {
+    /**  */
+    private final Document doc;
+
+    /**  */
+    private final Element beans;
+
+    /** */
+    private final Transformer transformer;
+
+    /**
+     * Create transformer.
+     *
+     * @param indent Number of additional whitespace when outputting the result tree.
+     * @throws IllegalStateException If failed to create instance of {@code CacheQueryTypeMetadataXmlTransformer}.
+     */
+    public XmlTransformer(int indent) throws IllegalStateException {
+        try {
+            DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
+
+            DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
+
+            doc = docBuilder.newDocument();
+            doc.setXmlStandalone(true);
+
+            beans = addElement(doc, "beans");
+            beans.setAttribute("xmlns", "http://www.springframework.org/schema/beans");
+            beans.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
+            beans.setAttribute("xmlns:util", "http://www.springframework.org/schema/util");
+            beans.setAttribute("xsi:schemaLocation",
+                "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" +
+                "http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd");
+
+            TransformerFactory transformerFactory = TransformerFactory.newInstance();
+
+            transformer = transformerFactory.newTransformer();
+
+            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+            transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", String.valueOf(indent));
+
+        }
+        catch(ParserConfigurationException | TransformerConfigurationException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+    /**
+     * @param parent Parent XML node.
+     * @param clazz Bean class.
+     */
+    private Element addBean(Node parent, Class<?> clazz) {
+        Element elem = doc.createElement("bean");
+
+        elem.setAttribute("class", clazz.getName());
+
+        parent.appendChild(elem);
+
+        return elem;
+    }
+
+
+    /**
+     * @param parent Parent XML node.
+     * @param tagName XML tag name.
+     * @param name Value for &quot;name&quot; attribute.
+     * @param val Value for &quot;value&quot; attribute.
+     */
+    private Element addElement(Node parent, String tagName, String name, String val) {
+        Element elem = doc.createElement(tagName);
+
+        if (name != null)
+            elem.setAttribute("name", name);
+
+        if (val != null)
+            elem.setAttribute("value", val);
+
+        parent.appendChild(elem);
+
+        return elem;
+    }
+
+    /**
+     * @param parent Parent XML node.
+     * @param tagName XML tag name.
+     */
+    private Element addElement(Node parent, String tagName) {
+        return addElement(parent, tagName, null, null);
+    }
+
+    /**
+     * Add to xml document:
+     * <pre name="code" class="xml">
+     *     &lt;property name=&quot;name&quot; value=&quot;value&quot;/&gt;
+     * </pre>
+     *
+     * @param parent Parent element.
+     * @param name Property name.
+     * @param val Property value.
+     */
+    private Element addProperty(Node parent, String name, String val) {
+        return addElement(parent, "property", name, val);
+    }
+
+    /**
+     * Add to xml document:
+     * <pre name="code" class="xml">
+     *     &lt;property name=&quot;name&quot;/&gt;
+     * </pre>
+     *
+     * @param parent Parent XML node.
+     * @param name Property name.
+     */
+    private Element addProperty(Node parent, String name) {
+        return addProperty(parent, name, null);
+    }
+
+    /**
+     * Add fields to xml document:
+     * <pre name="code" class="xml">
+     *     &lt;property name=&quot;name&quot;&gt;
+     *         &lt;map&gt;
+     *             &lt;property entry=&quot;name&quot; value=&quot;value&quot;/&gt;
+     *         &lt;/map&gt;
+     *     &lt;/property&gt;
+     * </pre>
+     *
+     * @param parent Parent XML node.
+     * @param name Property name.
+     * @param fields Map with fields.
+     */
+    private void addFields(Node parent, String name, Map<String, Class<?>> fields) {
+        if (!fields.isEmpty()) {
+            Element prop = addProperty(parent, name);
+
+            Element map = addElement(prop, "map");
+
+            for(Map.Entry<String, Class<?>> item : fields.entrySet())
+                addElement(map, "entry", item.getKey(), item.getValue().getName());
+        }
+    }
+
+    /**
+     * Add text fields to xml document:
+     * <pre name="code" class="xml">
+     *     &lt;property name=&quot;textFields&quot;&gt;
+     *         &lt;list&gt;
+     *             &lt;value&gt;field&lt;/value&gt;
+     *         &lt;/list&gt;
+     *     &lt;/property&gt;
+     * </pre>
+     *
+     * @param textFields Collection with text fields.
+     */
+    private void addTextFields(Node parent, Collection<String> textFields) {
+        if (!textFields.isEmpty()) {
+            Element prop = addProperty(parent, "textFields");
+
+            Element list = addElement(prop, "list");
+
+            for(String textField : textFields)
+                addElement(list, "value").setNodeValue(textField);
+        }
+    }
+
+    /**
+     * Add indexes to xml document.
+     *
+     * @param groups Map with indexes.
+     */
+    private void addGroups(Node parent, Map<String, LinkedHashMap<String, IgniteBiTuple<Class<?>, Boolean>>> groups) {
+        if (!F.isEmpty(groups)) {
+            Element prop = addProperty(parent, "groups");
+
+            Element map = addElement(prop, "map");
+
+            for (Map.Entry<String, LinkedHashMap<String, IgniteBiTuple<Class<?>, Boolean>>> group : groups.entrySet()) {
+                Element entry1 = addElement(map, "entry", group.getKey(), null);
+
+                Element val1 = addElement(entry1, "map");
+
+                LinkedHashMap<String, IgniteBiTuple<Class<?>, Boolean>> fields = group.getValue();
+
+                for(Map.Entry<String, IgniteBiTuple<Class<?>, Boolean>> field : fields.entrySet()) {
+                    Element entry2 = addElement(val1, "entry", field.getKey(), null);
+
+                    Element val2 = addBean(entry2, IgniteBiTuple.class);
+
+                    Class<?> clazz = field.getValue().get1();
+
+                    assert clazz != null;
+
+                    addProperty(val2, "key", field.getValue().get1().getCanonicalName());
+                    addProperty(val2, "value", String.valueOf(field.getValue().get2()));
+                }
+            }
+        }
+    }
+
+    /**
+     * Add element with cache query type metadata to XML document.
+     *
+     * @param parent Parent XML node.
+     * @param meta Meta.
+     */
+    private void addCacheQueryTypeMetadata(Node parent, GridCacheQueryTypeMetadata meta) {
+        Element bean = addBean(parent, GridCacheQueryTypeMetadata.class);
+
+        addProperty(bean, "type", meta.getType());
+
+        addFields(bean, "queryFields", meta.getQueryFields());
+
+        addFields(bean, "ascendingFields", meta.getAscendingFields());
+
+        addFields(bean, "descendingFields", meta.getDescendingFields());
+
+        addTextFields(bean, meta.getTextFields());
+
+        addGroups(bean, meta.getGroups());
+    }
+
+    /**
+     * @param out Output result.
+     * @throws TransformerException If an unrecoverable error occurs during the course of the transformation.
+     */
+    private void transform(Result out) throws TransformerException {
+        transformer.transform(new DOMSource(doc), out);
+    }
+
+    /**
+     * Transform metadata into xml.
+     *
+     * @param meta Metadata to transform.
+     * @param out Output result.
+     * @throws TransformerException If an unrecoverable error occurs during the course of the transformation.
+     */
+    public void transform(GridCacheQueryTypeMetadata meta, Result out) throws TransformerException {
+        addCacheQueryTypeMetadata(beans, meta);
+
+        transform(out);
+    }
+
+    /**
+     * Transform metadata into xml.
+     *
+     * @param meta Metadata to transform.
+     * @param out Output result.
+     * @throws TransformerException If an unrecoverable error occurs during the course of the transformation.
+     */
+    public void transform(Collection<GridCacheQueryTypeMetadata> meta, Result out) throws TransformerException {
+        for(GridCacheQueryTypeMetadata item : meta)
+            addCacheQueryTypeMetadata(beans, item);
+
+        transform(out);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/ac306c5e/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index e35788f..cb7a73d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -85,6 +85,7 @@
         <module>modules/log4j</module>
         <module>modules/slf4j</module>
         <module>modules/jcl</module>
+        <module>modules/schema-load</module>
     </modules>
 
     <dependencyManagement>