ignite-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From sboi...@apache.org
Subject [3/3] incubator-ignite git commit: # IGNITE-32 WIP: Reworked classes packages and added support for type selection from UI.
Date Tue, 20 Jan 2015 10:14:23 GMT
# IGNITE-32 WIP: Reworked classes packages and added support for type selection from UI.


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

Branch: refs/heads/ignite-32
Commit: cebc464fc086e3ca4ff87a9b2c5bc82184c16095
Parents: 53742d1
Author: AKuznetsov <akuznetsov@gridgain.com>
Authored: Tue Jan 20 17:14:49 2015 +0700
Committer: AKuznetsov <akuznetsov@gridgain.com>
Committed: Tue Jan 20 17:14:49 2015 +0700

----------------------------------------------------------------------
 .../ignite/schema/db/DbMetadataParser.java      | 236 ------
 .../ignite/schema/generator/PojoGenerator.java  | 316 ++++++++
 .../ignite/schema/generator/XmlGenerator.java   | 320 ++++++++
 .../ignite/schema/pojo/PojoCodeGenerator.java   | 309 --------
 .../apache/ignite/schema/ui/PojoDescriptor.java | 149 ----
 .../org/apache/ignite/schema/ui/PojoField.java  | 319 --------
 .../apache/ignite/schema/ui/SchemaLoadApp.java  | 749 ++++++++++++++++++-
 .../apache/ignite/schema/util/SchemaUtils.java  |  84 ---
 .../ignite/schema/xml/XmlTransformer.java       | 320 --------
 9 files changed, 1346 insertions(+), 1456 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/cebc464f/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
deleted file mode 100644
index ec63d7b..0000000
--- a/modules/schema-load/src/main/java/org/apache/ignite/schema/db/DbMetadataParser.java
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ignite.schema.db;
-
-import org.apache.ignite.lang.*;
-import org.apache.ignite.schema.ui.*;
-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 {
-    /**
-     * Convert JDBC data type to java type.
-     *
-     * @param type JDBC SQL data type.
-     * @return Java data type.
-     */
-    private static 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 meta 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.
-     */
-    private static GridCacheQueryTypeMetadata parse(DatabaseMetaData meta, String catalog, String schema, String tbl)
-        throws SQLException {
-        GridCacheQueryTypeMetadata res = new GridCacheQueryTypeMetadata();
-
-        res.setSchema(schema);
-        res.setTableName(tbl);
-
-        res.setType(toJavaClassName(tbl));
-        res.setKeyType(res.getType() + "Key");
-
-        Collection<GridCacheQueryTypeDescriptor> keyDescs = res.getKeyDescriptors();
-        Collection<GridCacheQueryTypeDescriptor> valDescs = res.getValueDescriptors();
-
-        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();
-
-        Set<String> pkFlds = new LinkedHashSet<>();
-
-        try (ResultSet pk = meta.getPrimaryKeys(catalog, schema, tbl)) {
-            while (pk.next())
-                pkFlds.add(pk.getString(4));
-        }
-
-        try (ResultSet flds = meta.getColumns(catalog, schema, tbl, null)) {
-            while (flds.next()) {
-                String dbName = flds.getString(4);
-                int dbType = flds.getInt(5);
-
-                String javaName = toJavaFieldName(dbName);
-                Class<?> javaType = dataType(dbType);
-
-                GridCacheQueryTypeDescriptor desc = new GridCacheQueryTypeDescriptor(javaName, javaType, dbName, dbType);
-
-                if (pkFlds.contains(dbName))
-                    keyDescs.add(desc);
-                else
-                    valDescs.add(desc);
-
-                qryFields.put(javaName, javaType);
-            }
-        }
-
-        try (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;
-    }
-
-    /**
-     * Parse database metadata.
-     *
-     * @param conn Connection to database.
-     * @return Map with schemes and tables metadata.
-     * @throws SQLException If parsing failed.
-     */
-    public static Map<String, Map<String, PojoDescriptor>> parse(Connection conn)
-        throws SQLException {
-        DatabaseMetaData meta = conn.getMetaData();
-
-        Map<String, Map<String, PojoDescriptor>> res = new TreeMap<>();
-
-        try (ResultSet schemas = meta.getSchemas()) {
-            while (schemas.next()) {
-                String schema = schemas.getString(1);
-
-                // Skip system tables from INFORMATION_SCHEMA.
-                if ("INFORMATION_SCHEMA".equalsIgnoreCase(schema))
-                    continue;
-
-                String catalog = schemas.getString(2);
-
-                Map<String, PojoDescriptor> items = new TreeMap<>();
-
-                try (ResultSet tbls = meta.getTables(catalog, schema, "%", null)) {
-                    while (tbls.next()) {
-                        String tbl = tbls.getString(3);
-
-                        items.put(tbl, new PojoDescriptor(parse(meta, catalog, schema, tbl)));
-                    }
-                }
-
-                if (!items.isEmpty())
-                    res.put(schema, items);
-            }
-        }
-
-        return res;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/cebc464f/modules/schema-load/src/main/java/org/apache/ignite/schema/generator/PojoGenerator.java
----------------------------------------------------------------------
diff --git a/modules/schema-load/src/main/java/org/apache/ignite/schema/generator/PojoGenerator.java b/modules/schema-load/src/main/java/org/apache/ignite/schema/generator/PojoGenerator.java
new file mode 100644
index 0000000..fadb3a3
--- /dev/null
+++ b/modules/schema-load/src/main/java/org/apache/ignite/schema/generator/PojoGenerator.java
@@ -0,0 +1,316 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.schema.generator;
+
+import org.apache.ignite.schema.ui.*;
+import org.gridgain.grid.cache.query.*;
+
+import java.io.*;
+import java.util.*;
+
+import static org.apache.ignite.schema.ui.MessageBox.Result.*;
+
+/**
+ * POJO generator for key and value classes.
+ */
+public class PojoGenerator {
+    /** */
+    private static final String TAB = "    ";
+    /** */
+    private static final String TAB2 = TAB + TAB;
+    /** */
+    private static final String TAB3 = TAB + TAB + TAB;
+
+    /**
+     * Add line to source code without indent.
+     *
+     * @param src Source code.
+     * @param line Code line.
+     */
+    private static void add0(Collection<String> src, String line) {
+        src.add(line);
+    }
+
+    /**
+     * Add line to source code with one indent.
+     *
+     * @param src Source code.
+     * @param line Code line.
+     */
+    private static void add1(Collection<String> src, String line) {
+        src.add(TAB + line);
+    }
+
+    /**
+     * Add line to source code with two indents.
+     *
+     * @param src Source code.
+     * @param line Code line.
+     */
+    private static void add2(Collection<String> src, String line) {
+        src.add(TAB2 + line);
+    }
+
+    /**
+     * Add line to source code with three indents.
+     *
+     * @param src Source code.
+     * @param line Code line.
+     */
+    private static void add3(Collection<String> src, String line) {
+        src.add(TAB3 + line);
+    }
+
+    /**
+     * @param str Source string.
+     * @return String with first letters in upper case.
+     */
+    private static String capitalizeFirst(String str) {
+        return Character.toUpperCase(str.charAt(0)) + str.substring(1);
+    }
+
+    /**
+     * Generate java class code.
+     *
+     * @param pkg Package name.
+     * @param type Type name.
+     * @param descs Type descriptors.
+     * @param constructor If {@code true} then generate empty and full constructors.
+     * @param askOverwrite Callback to ask user to confirm file overwrite.
+     * @throws IOException If failed to write generated code into file.
+     */
+    private static void generateCode(String pkg, String type, Collection<GridCacheQueryTypeDescriptor> descs,
+        File pkgFolder, boolean constructor, ConfirmCallable askOverwrite) throws IOException {
+        File out = new File(pkgFolder, type + ".java");
+
+        if (out.exists()) {
+            MessageBox.Result choice = askOverwrite.confirm(out.getName());
+
+            if (CANCEL == choice)
+                throw new IllegalStateException("POJO generation was canceled!");
+
+            if (NO == choice || NO_TO_ALL == choice)
+                return;
+        }
+
+        Collection<String> src = new ArrayList<>(256);
+
+        add0(src, "/*");
+        add0(src, " * Licensed to the Apache Software Foundation (ASF) under one or more");
+        add0(src, " * contributor license agreements.  See the NOTICE file distributed with");
+        add0(src, " * this work for additional information regarding copyright ownership.");
+        add0(src, " * The ASF licenses this file to You under the Apache License, Version 2.0");
+        add0(src, " * (the \"License\"); you may not use this file except in compliance with");
+        add0(src, " * the License.  You may obtain a copy of the License at");
+        add0(src, " *");
+        add0(src, " *      http://www.apache.org/licenses/LICENSE-2.0");
+        add0(src, " *");
+        add0(src, " * Unless required by applicable law or agreed to in writing, software");
+        add0(src, " * distributed under the License is distributed on an \"AS IS\" BASIS,");
+        add0(src, " * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.");
+        add0(src, " * See the License for the specific language governing permissions and");
+        add0(src, " * limitations under the License.");
+        add0(src, " */");
+
+        add0(src, "");
+
+        add0(src, "package " + pkg + ";");
+
+        add0(src, "");
+
+        add0(src, "import java.io.*;");
+
+        add0(src, "");
+
+        add0(src, "/**");
+        add0(src, " * " + type + " definition.");
+        add0(src, " *");
+        add0(src, " * Code generated by Apache Ignite Schema Load utility.");
+        add0(src, " */");
+        add0(src, "public class " + type + " implements Serializable {");
+
+        add1(src, "/** */");
+        add1(src, "private static final long serialVersionUID = 0L;");
+
+        add0(src, "");
+
+        // Fields.
+        for (GridCacheQueryTypeDescriptor desc : descs) {
+            String fldName = desc.getJavaName();
+
+            add1(src, "/** Value for " + fldName + ". */");
+            add1(src, "private " + desc.getJavaType().getSimpleName() + " " + fldName + ";");
+            add0(src, "");
+        }
+
+        // Constructors.
+        if (constructor) {
+            add1(src, "/**");
+            add1(src, " * Empty constructor.");
+            add1(src, " */");
+            add1(src, "public " + type + "() {");
+            add2(src, "// No-op.");
+            add1(src, "}");
+
+            add0(src, "");
+
+            add1(src, "/**");
+            add1(src, " * Full constructor.");
+            add1(src, " */");
+            add1(src, "public " + type + "(");
+
+            Iterator<GridCacheQueryTypeDescriptor> it = descs.iterator();
+
+            while (it.hasNext()) {
+                GridCacheQueryTypeDescriptor desc = it.next();
+
+                add2(src, desc.getJavaType().getSimpleName() + " " + desc.getJavaName() + (it.hasNext() ? "," : ""));
+            }
+            add1(src, ") {");
+
+            for (GridCacheQueryTypeDescriptor desc : descs)
+                add2(src, String.format("this.%1$s = %1$s;", desc.getJavaName()));
+
+            add1(src, "}");
+
+            add0(src, "");
+        }
+
+        // Methods.
+        for (GridCacheQueryTypeDescriptor desc : descs) {
+            String fldName = desc.getJavaName();
+
+            String fldType = desc.getJavaType().getSimpleName();
+
+            String mtdName = capitalizeFirst(fldName);
+
+            add1(src, "/**");
+            add1(src, " * Gets " + fldName + ".");
+            add1(src, " *");
+            add1(src, " * @return Value for " + fldName + ".");
+            add1(src, " */");
+            add1(src, "public " + fldType + " get" + mtdName + "() {");
+            add2(src, "return " + fldName + ";");
+            add1(src, "}");
+
+            add0(src, "");
+
+            add1(src, "/**");
+            add1(src, " * Sets " + fldName + ".");
+            add1(src, " *");
+            add1(src, " * @param " + fldName + " New value for " + fldName + ".");
+            add1(src, " */");
+            add1(src, "public void set" + mtdName + "(" + fldType + " " + fldName + ") {");
+            add2(src, "this." + fldName + " = " + fldName + ";");
+            add1(src, "}");
+
+            add0(src, "");
+        }
+
+        add1(src, "/** {@inheritDoc} */");
+        add1(src, "@Override public boolean equals(Object o) {");
+        add2(src, "if (this == o)");
+        add3(src, "return true;");
+
+        add0(src, "");
+
+        add2(src, "if (!(o instanceof " + type + "))");
+        add3(src, "return false;");
+
+        add0(src, "");
+
+        add2(src, String.format("%1$s that = (%1$s)o;", type));
+
+        for (GridCacheQueryTypeDescriptor desc : descs) {
+            add0(src, "");
+            add2(src, String.format("if (%1$s != null ? !%1$s.equals(that.%1$s) : that.%1$s != null)",
+                desc.getJavaName()));
+            add3(src, "return false;");
+        }
+
+        add0(src, "");
+        add2(src, "return true;");
+        add1(src, "}");
+
+        add0(src, "");
+
+        add1(src, "/** {@inheritDoc} */");
+        add1(src, "@Override public int hashCode() {");
+
+        Iterator<GridCacheQueryTypeDescriptor> it = descs.iterator();
+
+        add2(src, String.format("int res = %1$s != null ? %1$s.hashCode() : 0;", it.next().getJavaName()));
+
+        if (it.hasNext()) {
+            add0(src, "");
+
+            while (it.hasNext())
+                add2(src, String.format("res = 31 * res + (%1$s != null ? %1$s.hashCode() : 0);",
+                    it.next().getJavaName()));
+        }
+
+        add0(src, "");
+        add2(src, "return res;");
+        add1(src, "}");
+
+        add0(src, "");
+
+        add1(src, "/** {@inheritDoc} */");
+        add1(src, "@Override public String toString() {");
+
+        it = descs.iterator();
+
+        add2(src, String.format("return \"%1$s [%2$s=\" + %2$s +", type, it.next().getJavaName()));
+
+        while (it.hasNext())
+            add3(src, String.format("\", %1$s=\" + %1$s +", it.next().getJavaName()));
+
+        add3(src, "\"]\";");
+        add1(src, "}");
+
+        add0(src, "}");
+
+        try (Writer writer = new BufferedWriter(new FileWriter(out))) {
+            for (String line : src)
+                writer.write(line + '\n');
+        }
+    }
+
+    /**
+     * Generate source code for type by its metadata.
+     *
+     * @param meta Type metadata.
+     * @param outFolder Output folder.
+     * @param pkg Types package.
+     * @param constructor If {@code true} then generate empty and full constructors.
+     * @param askOverwrite Callback to ask user to confirm file overwrite.
+     * @throws IOException If failed to write generated code into file.
+     */
+    public static void generate(GridCacheQueryTypeMetadata meta, String outFolder, String pkg, boolean constructor,
+        ConfirmCallable askOverwrite)
+        throws IOException {
+        File pkgFolder = new File(outFolder, pkg.replace('.', File.separatorChar));
+
+        if (!pkgFolder.exists() && !pkgFolder.mkdirs())
+            throw new IOException("Failed to create folders for package: " + pkg);
+
+        generateCode(pkg, meta.getKeyType(), meta.getKeyDescriptors(), pkgFolder, constructor, askOverwrite);
+
+        generateCode(pkg, meta.getType(), meta.getValueDescriptors(), pkgFolder, constructor, askOverwrite);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/cebc464f/modules/schema-load/src/main/java/org/apache/ignite/schema/generator/XmlGenerator.java
----------------------------------------------------------------------
diff --git a/modules/schema-load/src/main/java/org/apache/ignite/schema/generator/XmlGenerator.java b/modules/schema-load/src/main/java/org/apache/ignite/schema/generator/XmlGenerator.java
new file mode 100644
index 0000000..a038bd9
--- /dev/null
+++ b/modules/schema-load/src/main/java/org/apache/ignite/schema/generator/XmlGenerator.java
@@ -0,0 +1,320 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.schema.generator;
+
+import org.apache.ignite.lang.*;
+import org.apache.ignite.schema.ui.*;
+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 javax.xml.transform.stream.*;
+import java.io.*;
+import java.util.*;
+
+import static org.apache.ignite.schema.ui.MessageBox.Result.*;
+
+/**
+ * Generator of XML files for type metadata.
+ */
+public class XmlGenerator {
+    /**
+     * Add bean to XML document.
+     *
+     * @param doc XML document.
+     * @param parent Parent XML node.
+     * @param clazz Bean class.
+     */
+    private static Element addBean(Document doc, Node parent, Class<?> clazz) {
+        Element elem = doc.createElement("bean");
+
+        elem.setAttribute("class", clazz.getName());
+
+        parent.appendChild(elem);
+
+        return elem;
+    }
+
+    /**
+     * Add element to XML document.
+     *
+     * @param doc XML document.
+     * @param parent Parent XML node.
+     * @param tagName XML tag name.
+     * @param attr1 Name for first attr.
+     * @param val1 Value for first attribute.
+     * @param attr2 Name for second attr.
+     * @param val2 Value for second attribute.
+     */
+    private static Element addElement(Document doc, Node parent, String tagName,
+        String attr1, String val1, String attr2, String val2) {
+        Element elem = doc.createElement(tagName);
+
+        if (attr1 != null)
+            elem.setAttribute(attr1, val1);
+
+        if (attr2 != null)
+            elem.setAttribute(attr2, val2);
+
+        parent.appendChild(elem);
+
+        return elem;
+    }
+
+    /**
+     * Add element to XML document.
+     *
+     * @param doc XML document.
+     * @param parent Parent XML node.
+     * @param tagName XML tag name.
+     */
+    private static Element addElement(Document doc, Node parent, String tagName) {
+        return addElement(doc, parent, tagName, null, null, null, null);
+    }
+
+    /**
+     * Add element to XML document.
+     *
+     * @param doc XML document.
+     * @param parent Parent XML node.
+     * @param tagName XML tag name.
+     */
+    private static Element addElement(Document doc, Node parent, String tagName, String attrName, String attrVal) {
+        return addElement(doc, parent, tagName, attrName, attrVal, null, null);
+    }
+
+    /**
+     * Add &quot;property&quot; element to XML document.
+     *
+     * @param doc XML document.
+     * @param parent Parent XML node.
+     * @param name Value for &quot;name&quot; attribute
+     * @param val Value for &quot;value&quot; attribute
+     */
+    private static Element addProperty(Document doc, Node parent, String name, String val) {
+        String valAttr = val != null ? "value" : null;
+
+        return addElement(doc, parent, "property", "name", name, valAttr, val);
+    }
+
+    /**
+     * Add fields to xml document.
+     *
+     * @param doc XML document.
+     * @param parent Parent XML node.
+     * @param name Property name.
+     * @param fields Map with fields.
+     */
+    private static void addFields(Document doc, Node parent, String name, Map<String, Class<?>> fields) {
+        if (!fields.isEmpty()) {
+            Element prop = addProperty(doc, parent, name, null);
+
+            Element map = addElement(doc, prop, "map");
+
+            for (Map.Entry<String, Class<?>> item : fields.entrySet())
+                addElement(doc, map, "entry", "key", item.getKey(), "value", item.getValue().getName());
+        }
+    }
+
+    /**
+     * Add type descriptors to XML document.
+     *
+     * @param doc XML document.
+     * @param parent Parent XML node.
+     * @param name Property name.
+     * @param descs Map with type descriptors.
+     */
+    private static void addTypeDescriptors(Document doc, Node parent, String name,
+        Collection<GridCacheQueryTypeDescriptor> descs) {
+        if (!descs.isEmpty()) {
+            Element prop = addProperty(doc, parent, name, null);
+
+            Element list = addElement(doc, prop, "list");
+
+            for (GridCacheQueryTypeDescriptor desc : descs) {
+                Element item = addBean(doc, list, GridCacheQueryTypeDescriptor.class);
+
+                addProperty(doc, item, "javaName", desc.getJavaName());
+                addProperty(doc, item, "javaType", desc.getJavaType().getName());
+                addProperty(doc, item, "dbName", desc.getDbName());
+                addProperty(doc, item, "dbType", String.valueOf(desc.getDbType()));
+            }
+        }
+    }
+
+    /**
+     * Add text fields to xml document.
+     *
+     * @param doc XML document.
+     * @param parent Parent XML node.
+     * @param textFields Collection with text fields.
+     */
+    private static void addTextFields(Document doc, Node parent, Collection<String> textFields) {
+        if (!textFields.isEmpty()) {
+            Element prop = addProperty(doc, parent, "textFields", null);
+
+            Element list = addElement(doc, prop, "list");
+
+            for (String textField : textFields)
+                addElement(doc, list, "value").setNodeValue(textField);
+        }
+    }
+
+    /**
+     * Add indexes to xml document.
+     *
+     * @param doc XML document.
+     * @param parent Parent XML node.
+     * @param groups Map with indexes.
+     */
+    private static void addGroups(Document doc, Node parent,
+        Map<String, LinkedHashMap<String, IgniteBiTuple<Class<?>, Boolean>>> groups) {
+        if (!F.isEmpty(groups)) {
+            Element prop = addProperty(doc, parent, "groups", null);
+
+            Element map = addElement(doc, prop, "map");
+
+            for (Map.Entry<String, LinkedHashMap<String, IgniteBiTuple<Class<?>, Boolean>>> group : groups.entrySet()) {
+                Element entry1 = addElement(doc, map, "entry", "key", group.getKey());
+
+                Element val1 = addElement(doc, entry1, "map");
+
+                LinkedHashMap<String, IgniteBiTuple<Class<?>, Boolean>> fields = group.getValue();
+
+                for (Map.Entry<String, IgniteBiTuple<Class<?>, Boolean>> field : fields.entrySet()) {
+                    Element entry2 = addElement(doc, val1, "entry", "key", field.getKey());
+
+                    Element val2 = addBean(doc, entry2, IgniteBiTuple.class);
+
+                    IgniteBiTuple<Class<?>, Boolean> tuple = field.getValue();
+
+                    Class<?> clazz = tuple.get1();
+
+                    assert clazz != null;
+
+                    addElement(doc, val2, "constructor-arg", null, null, "value", clazz.getName());
+                    addElement(doc, val2, "constructor-arg", null, null, "value", String.valueOf(tuple.get2()));
+                }
+            }
+        }
+    }
+
+    /**
+     * Add element with type metadata to XML document.
+     *
+     * @param doc XML document.
+     * @param parent Parent XML node.
+     * @param pkg Package fo types.
+     * @param meta Meta.
+     */
+    private static void addTypeMetadata(Document doc, Node parent, String pkg, GridCacheQueryTypeMetadata meta) {
+        Element bean = addBean(doc, parent, GridCacheQueryTypeMetadata.class);
+
+        addProperty(doc, bean, "type", pkg + "." + meta.getType());
+
+        addProperty(doc, bean, "keyType", pkg + "." + meta.getKeyType());
+
+        addProperty(doc, bean, "schema", meta.getSchema());
+
+        addProperty(doc, bean, "tableName", meta.getTableName());
+
+        addTypeDescriptors(doc, bean, "keyDescriptors", meta.getKeyDescriptors());
+
+        addTypeDescriptors(doc, bean, "valueDescriptors", meta.getValueDescriptors());
+
+        addFields(doc, bean, "queryFields", meta.getQueryFields());
+
+        addFields(doc, bean, "ascendingFields", meta.getAscendingFields());
+
+        addFields(doc, bean, "descendingFields", meta.getDescendingFields());
+
+        addTextFields(doc, bean, meta.getTextFields());
+
+        addGroups(doc, bean, meta.getGroups());
+    }
+
+    /**
+     * Transform metadata into xml.
+     *
+     * @param pkg Package fo types.
+     * @param meta Metadata to transform.
+     * @param out File to output result.
+     * @param askOverwrite Callback to ask user to confirm file overwrite.
+     */
+    public static void transform(String pkg, GridCacheQueryTypeMetadata meta, File out, ConfirmCallable askOverwrite) {
+        transform(pkg, Collections.singleton(meta), out, askOverwrite);
+    }
+
+    /**
+     * Transform metadata into xml.
+     *
+     * @param pkg Package fo types.
+     * @param meta Metadata to transform.
+     * @param out File to output result.
+     * @param askOverwrite Callback to ask user to confirm file overwrite.
+     */
+    public static void transform(String pkg, Collection<GridCacheQueryTypeMetadata> meta, File out,
+        ConfirmCallable askOverwrite) {
+        try {
+            if (out.exists()) {
+                MessageBox.Result choice = askOverwrite.confirm(out.getName());
+
+                if (CANCEL == choice)
+                    throw new IllegalStateException("XML generation was canceled!");
+
+                if (NO == choice || NO_TO_ALL == choice)
+                    return;
+            }
+
+            DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
+
+            DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
+
+            Document doc = docBuilder.newDocument();
+            doc.setXmlStandalone(true);
+
+            Element beans = addElement(doc, 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");
+
+            for (GridCacheQueryTypeMetadata item : meta)
+                addTypeMetadata(doc, beans, pkg, item);
+
+            TransformerFactory transformerFactory = TransformerFactory.newInstance();
+
+            Transformer transformer = transformerFactory.newTransformer();
+
+            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+            transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
+
+            transformer.transform(new DOMSource(doc), new StreamResult(out));
+        }
+        catch (ParserConfigurationException | TransformerException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/cebc464f/modules/schema-load/src/main/java/org/apache/ignite/schema/pojo/PojoCodeGenerator.java
----------------------------------------------------------------------
diff --git a/modules/schema-load/src/main/java/org/apache/ignite/schema/pojo/PojoCodeGenerator.java b/modules/schema-load/src/main/java/org/apache/ignite/schema/pojo/PojoCodeGenerator.java
deleted file mode 100644
index 76755b6..0000000
--- a/modules/schema-load/src/main/java/org/apache/ignite/schema/pojo/PojoCodeGenerator.java
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ignite.schema.pojo;
-
-import org.apache.ignite.schema.ui.*;
-import org.gridgain.grid.cache.query.*;
-
-import java.io.*;
-import java.util.*;
-
-import static org.apache.ignite.schema.ui.MessageBox.Result.*;
-import static org.apache.ignite.schema.util.SchemaUtils.*;
-
-/**
- * POJO generator for key and value classes.
- */
-public class PojoCodeGenerator {
-    /** */
-    private static final String TAB = "    ";
-    /** */
-    private static final String TAB2 = TAB + TAB;
-    /** */
-    private static final String TAB3 = TAB + TAB + TAB;
-
-    /**
-     * Add line to source code without indent.
-     *
-     * @param src Source code.
-     * @param line Code line.
-     */
-    private static void add0(Collection<String> src, String line) {
-        src.add(line);
-    }
-
-    /**
-     * Add line to source code with one indent.
-     *
-     * @param src Source code.
-     * @param line Code line.
-     */
-    private static void add1(Collection<String> src, String line) {
-        src.add(TAB + line);
-    }
-
-    /**
-     * Add line to source code with two indents.
-     *
-     * @param src Source code.
-     * @param line Code line.
-     */
-    private static void add2(Collection<String> src, String line) {
-        src.add(TAB2 + line);
-    }
-
-    /**
-     * Add line to source code with three indents.
-     *
-     * @param src Source code.
-     * @param line Code line.
-     */
-    private static void add3(Collection<String> src, String line) {
-        src.add(TAB3 + line);
-    }
-
-    /**
-     * Generate java class code.
-     *
-     * @param pkg Package name.
-     * @param type Type name.
-     * @param descs Type descriptors.
-     * @param constructor If {@code true} then generate empty and full constructors.
-     * @param askOverwrite Callback to ask user to confirm file overwrite.
-     * @throws IOException If failed to write generated code into file.
-     */
-    private static void generateCode(String pkg, String type, Collection<GridCacheQueryTypeDescriptor> descs,
-        File pkgFolder, boolean constructor, ConfirmCallable askOverwrite) throws IOException {
-        File out = new File(pkgFolder, type + ".java");
-
-        if (out.exists()) {
-            MessageBox.Result choice = askOverwrite.confirm(out.getName());
-
-            if (CANCEL == choice)
-                throw new IllegalStateException("POJO generation was canceled!");
-
-            if (NO == choice || NO_TO_ALL == choice)
-                return;
-        }
-
-        Collection<String> src = new ArrayList<>(256);
-
-        add0(src, "/*");
-        add0(src, " * Licensed to the Apache Software Foundation (ASF) under one or more");
-        add0(src, " * contributor license agreements.  See the NOTICE file distributed with");
-        add0(src, " * this work for additional information regarding copyright ownership.");
-        add0(src, " * The ASF licenses this file to You under the Apache License, Version 2.0");
-        add0(src, " * (the \"License\"); you may not use this file except in compliance with");
-        add0(src, " * the License.  You may obtain a copy of the License at");
-        add0(src, " *");
-        add0(src, " *      http://www.apache.org/licenses/LICENSE-2.0");
-        add0(src, " *");
-        add0(src, " * Unless required by applicable law or agreed to in writing, software");
-        add0(src, " * distributed under the License is distributed on an \"AS IS\" BASIS,");
-        add0(src, " * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.");
-        add0(src, " * See the License for the specific language governing permissions and");
-        add0(src, " * limitations under the License.");
-        add0(src, " */");
-
-        add0(src, "");
-
-        add0(src, "package " + pkg + ";");
-
-        add0(src, "");
-
-        add0(src, "import java.io.*;");
-
-        add0(src, "");
-
-        add0(src, "/**");
-        add0(src, " * " + type + " definition.");
-        add0(src, " *");
-        add0(src, " * Code generated by Apache Ignite Schema Load utility.");
-        add0(src, " */");
-        add0(src, "public class " + type + " implements Serializable {");
-
-        add1(src, "/** */");
-        add1(src, "private static final long serialVersionUID = 0L;");
-
-        add0(src, "");
-
-        // Fields.
-        for (GridCacheQueryTypeDescriptor desc : descs) {
-            String fldName = desc.getJavaName();
-
-            add1(src, "/** Value for " + fldName + ". */");
-            add1(src, "private " + desc.getJavaType().getSimpleName() + " " + fldName + ";");
-            add0(src, "");
-        }
-
-        // Constructors.
-        if (constructor) {
-            add1(src, "/**");
-            add1(src, " * Empty constructor.");
-            add1(src, " */");
-            add1(src, "public " + type + "() {");
-            add2(src, "// No-op.");
-            add1(src, "}");
-
-            add0(src, "");
-
-            add1(src, "/**");
-            add1(src, " * Full constructor.");
-            add1(src, " */");
-            add1(src, "public " + type + "(");
-
-            Iterator<GridCacheQueryTypeDescriptor> it = descs.iterator();
-
-            while (it.hasNext()) {
-                GridCacheQueryTypeDescriptor desc = it.next();
-
-                add2(src, desc.getJavaType().getSimpleName() + " " + desc.getJavaName() + (it.hasNext() ? "," : ""));
-            }
-            add1(src, ") {");
-
-            for (GridCacheQueryTypeDescriptor desc : descs)
-                add2(src, String.format("this.%1$s = %1$s;", desc.getJavaName()));
-
-            add1(src, "}");
-
-            add0(src, "");
-        }
-
-        // Methods.
-        for (GridCacheQueryTypeDescriptor desc : descs) {
-            String fldName = desc.getJavaName();
-
-            String fldType = desc.getJavaType().getSimpleName();
-
-            String mtdName = capitalizeFirst(fldName);
-
-            add1(src, "/**");
-            add1(src, " * Gets " + fldName + ".");
-            add1(src, " *");
-            add1(src, " * @return Value for " + fldName + ".");
-            add1(src, " */");
-            add1(src, "public " + fldType + " get" + mtdName + "() {");
-            add2(src, "return " + fldName + ";");
-            add1(src, "}");
-
-            add0(src, "");
-
-            add1(src, "/**");
-            add1(src, " * Sets " + fldName + ".");
-            add1(src, " *");
-            add1(src, " * @param " + fldName + " New value for " + fldName + ".");
-            add1(src, " */");
-            add1(src, "public void set" + mtdName + "(" + fldType + " " + fldName + ") {");
-            add2(src, "this." + fldName + " = " + fldName + ";");
-            add1(src, "}");
-
-            add0(src, "");
-        }
-
-        add1(src, "/** {@inheritDoc} */");
-        add1(src, "@Override public boolean equals(Object o) {");
-        add2(src, "if (this == o)");
-        add3(src, "return true;");
-
-        add0(src, "");
-
-        add2(src, "if (!(o instanceof " + type + "))");
-        add3(src, "return false;");
-
-        add0(src, "");
-
-        add2(src, String.format("%1$s that = (%1$s)o;", type));
-
-        for (GridCacheQueryTypeDescriptor desc : descs) {
-            add0(src, "");
-            add2(src, String.format("if (%1$s != null ? !%1$s.equals(that.%1$s) : that.%1$s != null)",
-                desc.getJavaName()));
-            add3(src, "return false;");
-        }
-
-        add0(src, "");
-        add2(src, "return true;");
-        add1(src, "}");
-
-        add0(src, "");
-
-        add1(src, "/** {@inheritDoc} */");
-        add1(src, "@Override public int hashCode() {");
-
-        Iterator<GridCacheQueryTypeDescriptor> it = descs.iterator();
-
-        add2(src, String.format("int res = %1$s != null ? %1$s.hashCode() : 0;", it.next().getJavaName()));
-
-        if (it.hasNext()) {
-            add0(src, "");
-
-            while (it.hasNext())
-                add2(src, String.format("res = 31 * res + (%1$s != null ? %1$s.hashCode() : 0);",
-                    it.next().getJavaName()));
-        }
-
-        add0(src, "");
-        add2(src, "return res;");
-        add1(src, "}");
-
-        add0(src, "");
-
-        add1(src, "/** {@inheritDoc} */");
-        add1(src, "@Override public String toString() {");
-
-        it = descs.iterator();
-
-        add2(src, String.format("return \"%1$s [%2$s=\" + %2$s +", type, it.next().getJavaName()));
-
-        while (it.hasNext())
-            add3(src, String.format("\", %1$s=\" + %1$s +", it.next().getJavaName()));
-
-        add3(src, "\"]\";");
-        add1(src, "}");
-
-        add0(src, "}");
-
-        try (Writer writer = new BufferedWriter(new FileWriter(out))) {
-            for (String line : src)
-                writer.write(line + '\n');
-        }
-    }
-
-    /**
-     * Generate source code for type by its metadata.
-     *
-     * @param meta Type metadata.
-     * @param outFolder Output folder.
-     * @param pkg Types package.
-     * @param constructor If {@code true} then generate empty and full constructors.
-     * @param askOverwrite Callback to ask user to confirm file overwrite.
-     * @throws IOException If failed to write generated code into file.
-     */
-    public static void generate(GridCacheQueryTypeMetadata meta, String outFolder, String pkg, boolean constructor,
-        ConfirmCallable askOverwrite)
-        throws IOException {
-        File pkgFolder = new File(outFolder, pkg.replace('.', File.separatorChar));
-
-        if (!pkgFolder.exists() && !pkgFolder.mkdirs())
-            throw new IOException("Failed to create folders for package: " + pkg);
-
-        generateCode(pkg, meta.getKeyType(), meta.getKeyDescriptors(), pkgFolder, constructor, askOverwrite);
-
-        generateCode(pkg, meta.getType(), meta.getValueDescriptors(), pkgFolder, constructor, askOverwrite);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/cebc464f/modules/schema-load/src/main/java/org/apache/ignite/schema/ui/PojoDescriptor.java
----------------------------------------------------------------------
diff --git a/modules/schema-load/src/main/java/org/apache/ignite/schema/ui/PojoDescriptor.java b/modules/schema-load/src/main/java/org/apache/ignite/schema/ui/PojoDescriptor.java
deleted file mode 100644
index 76c29d4..0000000
--- a/modules/schema-load/src/main/java/org/apache/ignite/schema/ui/PojoDescriptor.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ignite.schema.ui;
-
-import javafx.collections.*;
-import org.gridgain.grid.cache.query.*;
-
-import java.util.*;
-
-/**
- * Descriptor for java type.
- */
-public class PojoDescriptor {
-    /** Previous name for key class. */
-    private final String keyClsNamePrev;
-
-    /** Previous name for value class. */
-    private final String valClsNamePrev;
-
-    /** Java class fields. */
-    private final ObservableList<PojoField> fields;
-
-    /** Java class fields. */
-    private final List<PojoField> fieldsPrev;
-
-    /** Type metadata. */
-    private final GridCacheQueryTypeMetadata meta;
-
-    /**
-     * Type descriptor.
-     *
-     * @param meta Type metadata.
-     */
-    public PojoDescriptor(GridCacheQueryTypeMetadata meta) {
-        this.meta = meta;
-
-        keyClsNamePrev = meta.getKeyType();
-
-        valClsNamePrev = meta.getType();
-
-        Collection<GridCacheQueryTypeDescriptor> keys = meta.getKeyDescriptors();
-
-        Collection<GridCacheQueryTypeDescriptor> vals = meta.getValueDescriptors();
-
-        int sz = keys.size() + vals.size();
-
-        List<PojoField> flds = new ArrayList<>(sz);
-        fieldsPrev = new ArrayList<>(sz);
-
-        for (GridCacheQueryTypeDescriptor key : keys) {
-            flds.add(new PojoField(true, key));
-            fieldsPrev.add(new PojoField(true, key));
-        }
-
-        for (GridCacheQueryTypeDescriptor val : vals) {
-            flds.add(new PojoField(false, val));
-            fieldsPrev.add(new PojoField(false, val));
-        }
-
-        fields = FXCollections.observableList(flds);
-    }
-
-    /**
-     * @return {@code true} if descriptor was changed by user via GUI.
-     */
-    public boolean changed() {
-        boolean diff = !meta.getKeyType().equals(keyClsNamePrev) || !meta.getType().equals(valClsNamePrev);
-
-        if (!diff)
-            for (int i = 0; i < fields.size(); i++) {
-                PojoField cur = fields.get(i);
-                PojoField prev = fieldsPrev.get(i);
-
-                // User can change via GUI only key and java name properties.
-                if (cur.key() != prev.key() || !cur.javaName().equals(prev.javaName())) {
-                    diff = true;
-
-                    break;
-                }
-            }
-
-        return diff;
-    }
-
-    /**
-     * Revert changes to java names made by user.
-     */
-    public void revertJavaNames() {
-        for (int i = 0; i < fields.size(); i++)
-            fields.get(i).javaName(fieldsPrev.get(i).javaName());
-    }
-
-    /**
-     * @return Name for key class.
-     */
-    public String keyClassName() {
-        return meta.getKeyType();
-    }
-
-    /**
-     * @param name Name for key class.
-     */
-    public void keyClassName(String name) {
-        meta.setKeyType(name);
-    }
-
-    /**
-     * @return Name for value class.
-     */
-    public String valueClassName() {
-        return meta.getType();
-    }
-
-    /**
-     * @param name Name for value class.
-     */
-    public void valueClassName(String name) {
-        meta.setType(name);
-    }
-
-    /**
-     * @return Java class fields.
-     */
-    public ObservableList<PojoField> fields() {
-        return fields;
-    }
-
-    /**
-     * @return Type metadata.
-     */
-    public GridCacheQueryTypeMetadata metadata() {
-        return meta;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/cebc464f/modules/schema-load/src/main/java/org/apache/ignite/schema/ui/PojoField.java
----------------------------------------------------------------------
diff --git a/modules/schema-load/src/main/java/org/apache/ignite/schema/ui/PojoField.java b/modules/schema-load/src/main/java/org/apache/ignite/schema/ui/PojoField.java
deleted file mode 100644
index 711d95d..0000000
--- a/modules/schema-load/src/main/java/org/apache/ignite/schema/ui/PojoField.java
+++ /dev/null
@@ -1,319 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ignite.schema.ui;
-
-import javafx.beans.property.*;
-import javafx.collections.*;
-import org.gridgain.grid.cache.query.*;
-import org.gridgain.grid.util.typedef.internal.*;
-
-import java.util.*;
-
-import static java.sql.Types.*;
-
-/**
- * Field descriptor with properties for JavaFX GUI bindings.
- */
-public class PojoField {
-    /** If this field belongs to primary key. */
-    private final BooleanProperty key;
-
-    /** Field name for POJO. */
-    private final StringProperty javaName;
-
-    /** Field type for POJO. */
-    private final StringProperty javaTypeName;
-
-    /** Field name in database. */
-    private final StringProperty dbName;
-
-    /** Field type in database. */
-    private final StringProperty dbTypeName;
-
-    /** Field type descriptor. */
-    private final GridCacheQueryTypeDescriptor desc;
-
-    /** List of possible java type conversions. */
-    private final ObservableList<String> conversions;
-
-    /**
-     * @param key {@code true} if this field belongs to primary key.
-     * @param desc Field type descriptor.
-     */
-    public PojoField(boolean key, GridCacheQueryTypeDescriptor desc) {
-        this.desc = desc;
-        this.key = new SimpleBooleanProperty(key);
-        javaName = new SimpleStringProperty(desc.getJavaName());
-        javaTypeName = new SimpleStringProperty(desc.getJavaType().getName());
-        dbName = new SimpleStringProperty(desc.getDbName());
-        dbTypeName = new SimpleStringProperty(jdbcTypeName(desc.getDbType()));
-
-        ObservableList<String> c = conversionsMap.get(desc.getDbType());
-
-        if (c != null)
-            conversions = c;
-        else
-            conversions = FXCollections.singletonObservableList(javaTypeName());
-    }
-
-    /**
-     * @param jdbcType String name for JDBC type.
-     */
-    private static String jdbcTypeName(int jdbcType) {
-        switch (jdbcType) {
-            case BIT:
-                return "BIT";
-            case TINYINT:
-                return "TINYINT";
-            case SMALLINT:
-                return "SMALLINT";
-            case INTEGER:
-                return "INTEGER";
-            case BIGINT:
-                return "BIGINT";
-            case FLOAT:
-                return "FLOAT";
-            case REAL:
-                return "REAL";
-            case DOUBLE:
-                return "DOUBLE";
-            case NUMERIC:
-                return "NUMERIC";
-            case DECIMAL:
-                return "DECIMAL";
-            case CHAR:
-                return "CHAR";
-            case VARCHAR:
-                return "VARCHAR";
-            case LONGVARCHAR:
-                return "LONGVARCHAR";
-            case DATE:
-                return "DATE";
-            case TIME:
-                return "TIME";
-            case TIMESTAMP:
-                return "TIMESTAMP";
-            case BINARY:
-                return "BINARY";
-            case VARBINARY:
-                return "VARBINARY";
-            case LONGVARBINARY:
-                return "LONGVARBINARY";
-            case NULL:
-                return "NULL";
-            case OTHER:
-                return "OTHER";
-            case JAVA_OBJECT:
-                return "JAVA_OBJECT";
-            case DISTINCT:
-                return "DISTINCT";
-            case STRUCT:
-                return "STRUCT";
-            case ARRAY:
-                return "ARRAY";
-            case BLOB:
-                return "BLOB";
-            case CLOB:
-                return "CLOB";
-            case REF:
-                return "REF";
-            case DATALINK:
-                return "DATALINK";
-            case BOOLEAN:
-                return "BOOLEAN";
-            case ROWID:
-                return "ROWID";
-            case NCHAR:
-                return "NCHAR";
-            case NVARCHAR:
-                return "NVARCHAR";
-            case LONGNVARCHAR:
-                return "LONGNVARCHAR";
-            case NCLOB:
-                return "NCLOB";
-            case SQLXML:
-                return "SQLXML";
-            default:
-                return "Unknown";
-        }
-    }
-
-    /**
-     * @return {@code true} if this field belongs to primary key.
-     */
-    public boolean key() {
-        return key.get();
-    }
-
-    /**
-     * @param pk {@code true} if this field belongs to primary key.
-     */
-    public void key(boolean pk) {
-        key.set(pk);
-    }
-
-    /**
-     * @return POJO field java name.
-     */
-    public String javaName() {
-        return javaName.get();
-    }
-
-    /**
-     * @param name POJO field java name.
-     */
-    public void javaName(String name) {
-        javaName.set(name);
-    }
-
-    /**
-     * @return POJO field java type name.
-     */
-    public String javaTypeName() {
-        return javaTypeName.get();
-    }
-
-    /**
-     * @return Type descriptor.
-     */
-    public GridCacheQueryTypeDescriptor descriptor() {
-        desc.setJavaName(javaName.get());
-
-        return desc;
-    }
-
-    /**
-     * @return POJO field JDBC type in database.
-     */
-    public int dbType() {
-        return desc.getDbType();
-    }
-
-    /**
-     * @return Boolean property support for {@code key} property.
-     */
-    public BooleanProperty keyProperty() {
-        return key;
-    }
-
-    /**
-     * @return String property support for {@code javaName} property.
-     */
-    public StringProperty javaNameProperty() {
-        return javaName;
-    }
-
-    /**
-     * @return String property support for {@code javaTypeName} property.
-     */
-    public StringProperty javaTypeNameProperty() {
-        return javaTypeName;
-    }
-
-    /**
-     * @return String property support for {@code dbName} property.
-     */
-    public StringProperty dbNameProperty() {
-        return dbName;
-    }
-
-    /**
-     * @return String property support for {@code dbName} property.
-     */
-    public StringProperty dbTypeNameProperty() {
-        return dbTypeName;
-    }
-
-
-    /** */
-    private static final String BOOL_P = "boolean";
-
-    /** */
-    private static final String BOOL_O = "java.lang.Boolean";
-
-    /** */
-    private static final String BYTE_P = "byte";
-
-    /** */
-    private static final String BYTE_O = "java.lang.Byte";
-
-    /** */
-    private static final String SHORT_P = "short";
-
-    /** */
-    private static final String SHORT_O = "java.lang.Short";
-
-    /** */
-    private static final String INT_P = "int";
-
-    /** */
-    private static final String INT_O = "java.lang.Integer";
-
-    /** */
-    private static final String LONG_P = "long";
-
-    /** */
-    private static final String LONG_O = "java.lang.Long";
-
-    /** */
-    private static final String FLOAT_P = "float";
-
-    /** */
-    private static final String FLOAT_O = "java.lang.Float";
-
-    /** */
-    private static final String DOUBLE_P = "double";
-
-    /** */
-    private static final String DOUBLE_O = "java.lang.Double";
-
-    /** */
-    private static final String BIG_DECIMAL_O = "java.math.BigDecimal";
-
-    /** */
-    private static final Map<Integer, ObservableList<String>> conversionsMap = U.newHashMap(10);
-
-    static {
-        conversionsMap.put(TINYINT, FXCollections.observableArrayList(BOOL_P, BYTE_P, SHORT_P, INT_P, LONG_P, FLOAT_P,
-                DOUBLE_P, BOOL_O, BYTE_O, SHORT_O, INT_O, LONG_O, FLOAT_O, DOUBLE_O, BIG_DECIMAL_O));
-
-        conversionsMap.put(SMALLINT, FXCollections.observableArrayList(BOOL_P, SHORT_P, INT_P, LONG_P, FLOAT_P, DOUBLE_P,
-                BOOL_O, SHORT_O, INT_O, LONG_O, FLOAT_O, DOUBLE_O, BIG_DECIMAL_O));
-
-        conversionsMap.put(INTEGER, FXCollections.observableArrayList(BOOL_P, INT_P, LONG_P, FLOAT_P, DOUBLE_P,
-                BOOL_O, INT_O, LONG_O, FLOAT_O, DOUBLE_O, BIG_DECIMAL_O));
-
-        conversionsMap.put(BIGINT, FXCollections.observableArrayList(BOOL_P, LONG_P, FLOAT_P, DOUBLE_P, BOOL_O, LONG_O,
-            FLOAT_O, DOUBLE_O, BIG_DECIMAL_O));
-
-        conversionsMap.put(REAL, FXCollections.observableArrayList(BOOL_P, FLOAT_P, DOUBLE_P, BOOL_O, FLOAT_O, DOUBLE_O,
-            BIG_DECIMAL_O));
-
-        conversionsMap.put(FLOAT, FXCollections.observableArrayList(BOOL_P, FLOAT_P, DOUBLE_P, BOOL_O, FLOAT_O, DOUBLE_O,
-            BIG_DECIMAL_O));
-
-        conversionsMap.put(DOUBLE, conversionsMap.get(FLOAT));
-    }
-
-    /**
-     * @return List of possible java type conversions.
-     */
-    public ObservableList<String> conversions() {
-        return conversions;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/cebc464f/modules/schema-load/src/main/java/org/apache/ignite/schema/ui/SchemaLoadApp.java
----------------------------------------------------------------------
diff --git a/modules/schema-load/src/main/java/org/apache/ignite/schema/ui/SchemaLoadApp.java b/modules/schema-load/src/main/java/org/apache/ignite/schema/ui/SchemaLoadApp.java
index 9a6175c..ce5c188 100644
--- a/modules/schema-load/src/main/java/org/apache/ignite/schema/ui/SchemaLoadApp.java
+++ b/modules/schema-load/src/main/java/org/apache/ignite/schema/ui/SchemaLoadApp.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.schema.ui;
 
 import javafx.application.*;
+import javafx.beans.property.*;
 import javafx.beans.value.*;
 import javafx.collections.*;
 import javafx.concurrent.*;
@@ -29,18 +30,20 @@ import javafx.scene.control.cell.*;
 import javafx.scene.layout.*;
 import javafx.stage.*;
 import javafx.util.*;
-import org.apache.ignite.schema.db.*;
-import org.apache.ignite.schema.pojo.*;
-import org.apache.ignite.schema.xml.*;
+import org.apache.ignite.lang.*;
+import org.apache.ignite.schema.generator.*;
 import org.gridgain.grid.cache.query.*;
 
 import java.io.*;
+import java.math.*;
 import java.net.*;
 import java.sql.*;
+import java.sql.Date;
 import java.util.*;
 import java.util.concurrent.*;
 import java.util.prefs.*;
 
+import static java.sql.Types.*;
 import static javafx.embed.swing.SwingFXUtils.*;
 import static org.apache.ignite.schema.ui.Controls.*;
 
@@ -140,10 +143,10 @@ public class SchemaLoadApp extends Application {
     private PojoDescriptor curPojo;
 
     /** */
-    private static final ObservableList<PojoField> NO_DATA = FXCollections.emptyObservableList();
+    private final Map<String, Driver> drivers = new HashMap<>();
 
     /** */
-    private final Map<String, Driver> drivers = new HashMap<>();
+    private final ObservableList<PojoField> NO_DATA = FXCollections.emptyObservableList();
 
     /** */
     private final ExecutorService exec = Executors.newSingleThreadExecutor(new ThreadFactory() {
@@ -212,7 +215,7 @@ public class SchemaLoadApp extends Application {
                 long started = System.currentTimeMillis();
 
                 try (Connection conn = connect()) {
-                    schemas = DbMetadataParser.parse(conn);
+                    schemas = parse(conn);
                 }
 
                 pojos = new ArrayList<>();
@@ -372,10 +375,10 @@ public class SchemaLoadApp extends Application {
                             all.add(meta);
 
                             if (!singleXml)
-                                XmlTransformer.transform(pkg, meta, new File(destFolder, meta.getType() + ".xml"),
+                                XmlGenerator.transform(pkg, meta, new File(destFolder, meta.getType() + ".xml"),
                                     askOverwrite);
 
-                            PojoCodeGenerator.generate(meta, outFolder, pkg, constructor, askOverwrite);
+                            PojoGenerator.generate(meta, outFolder, pkg, constructor, askOverwrite);
                         }
                     }
                 }
@@ -383,7 +386,7 @@ public class SchemaLoadApp extends Application {
                 if (all.isEmpty())
                     throw new IllegalStateException("Nothing selected!");
                 else if (singleXml)
-                    XmlTransformer.transform(pkg, all, new File(outFolder, "Ignite.xml"), askOverwrite);
+                    XmlGenerator.transform(pkg, all, new File(outFolder, "Ignite.xml"), askOverwrite);
 
                 perceptualDelay(started);
 
@@ -1124,6 +1127,242 @@ public class SchemaLoadApp extends Application {
     }
 
     /**
+     * @param name Source name.
+     * @return String converted to java class name notation.
+     */
+    private String toJavaClassName(String name) {
+        int len = name.length();
+
+        StringBuilder buf = new StringBuilder(len);
+
+        boolean capitalizeNext = true;
+
+        for (int i = 0; i < len; i++) {
+            char ch = name.charAt(i);
+
+            if (Character.isWhitespace(ch) || '_' == ch)
+                capitalizeNext = true;
+            else if (capitalizeNext) {
+                buf.append(Character.toUpperCase(ch));
+
+                capitalizeNext = false;
+            }
+            else
+                buf.append(Character.toLowerCase(ch));
+        }
+
+        return buf.toString();
+    }
+
+    /**
+     * @param name Source name.
+     * @return String converted to java field name notation.
+     */
+    private String toJavaFieldName(String name) {
+        String javaName = toJavaClassName(name);
+
+        return Character.toLowerCase(javaName.charAt(0)) + javaName.substring(1);
+    }
+
+    /**
+     * Convert JDBC data type to java type.
+     *
+     * @param type JDBC 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 meta 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.
+     */
+    private PojoDescriptor parse(DatabaseMetaData meta, String catalog, String schema, String tbl) throws SQLException {
+        GridCacheQueryTypeMetadata res = new GridCacheQueryTypeMetadata();
+
+        res.setSchema(schema);
+        res.setTableName(tbl);
+
+        res.setType(toJavaClassName(tbl));
+        res.setKeyType(res.getType() + "Key");
+
+        Collection<GridCacheQueryTypeDescriptor> keyDescs = res.getKeyDescriptors();
+        Collection<GridCacheQueryTypeDescriptor> valDescs = res.getValueDescriptors();
+
+        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();
+
+        Set<String> pkFlds = new LinkedHashSet<>();
+
+        try (ResultSet pk = meta.getPrimaryKeys(catalog, schema, tbl)) {
+            while (pk.next())
+                pkFlds.add(pk.getString(4));
+        }
+
+        try (ResultSet flds = meta.getColumns(catalog, schema, tbl, null)) {
+            while (flds.next()) {
+                String dbName = flds.getString(4);
+                int dbType = flds.getInt(5);
+
+                String javaName = toJavaFieldName(dbName);
+                Class<?> javaType = dataType(dbType);
+
+                GridCacheQueryTypeDescriptor desc = new GridCacheQueryTypeDescriptor(javaName, javaType, dbName, dbType);
+
+                if (pkFlds.contains(dbName))
+                    keyDescs.add(desc);
+                else
+                    valDescs.add(desc);
+
+                qryFields.put(javaName, javaType);
+            }
+        }
+
+        try (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 new PojoDescriptor(res);
+    }
+
+    /**
+     * Parse database metadata.
+     *
+     * @param conn Connection to database.
+     * @return Map with schemes and tables metadata.
+     * @throws SQLException If parsing failed.
+     */
+    private Map<String, Map<String, PojoDescriptor>> parse(Connection conn) throws SQLException {
+        DatabaseMetaData meta = conn.getMetaData();
+
+        Map<String, Map<String, PojoDescriptor>> res = new TreeMap<>();
+
+        try (ResultSet schemas = meta.getSchemas()) {
+            while (schemas.next()) {
+                String schema = schemas.getString(1);
+
+                // Skip system tables from INFORMATION_SCHEMA.
+                if ("INFORMATION_SCHEMA".equalsIgnoreCase(schema))
+                    continue;
+
+                String catalog = schemas.getString(2);
+
+                Map<String, PojoDescriptor> items = new TreeMap<>();
+
+                try (ResultSet tbls = meta.getTables(catalog, schema, "%", null)) {
+                    while (tbls.next()) {
+                        String tbl = tbls.getString(3);
+
+                        items.put(tbl, parse(meta, catalog, schema, tbl));
+                    }
+                }
+
+                if (!items.isEmpty())
+                    res.put(schema, items);
+            }
+        }
+
+        return res;
+    }
+
+    /**
      * Schema load utility launcher.
      *
      * @param args Command line arguments passed to the application.
@@ -1157,6 +1396,434 @@ public class SchemaLoadApp extends Application {
     }
 
     /**
+     * Field descriptor with properties for JavaFX GUI bindings.
+     */
+    public static class PojoField {
+        /** If this field belongs to primary key. */
+        private final BooleanProperty key;
+
+        /** Field name for POJO. */
+        private final StringProperty javaName;
+
+        /** Field type for POJO. */
+        private final StringProperty javaTypeName;
+
+        /** Field name in database. */
+        private final StringProperty dbName;
+
+        /** Field type in database. */
+        private final StringProperty dbTypeName;
+
+        /** Field type descriptor. */
+        private final GridCacheQueryTypeDescriptor desc;
+
+        /** List of possible java type conversions. */
+        private final ObservableList<String> conversions;
+
+        /** */
+        private static final Map<String, Class<?>> classesMap = new HashMap<>();
+
+        /**
+         * @param clss Class to add.
+         */
+        private static void fillClassesMap(Class<?>... clss) {
+            for (Class<?> cls : clss)
+                classesMap.put(cls.getName(), cls);
+        }
+
+        /**
+         * @param clss List of classes to get class names.
+         * @return List of classes names to show in UI for manual select.
+         */
+        private static List<String> classNames(Class<?>... clss) {
+            List<String> names = new ArrayList<>(clss.length);
+
+            for (Class<?> cls : clss)
+                names.add(cls.getName());
+
+            return names;
+        }
+
+        /** Null number conversions. */
+        private static final ObservableList<String> NULL_NUM_CONVERSIONS = FXCollections.observableArrayList();
+
+        /** Not null number conversions. */
+        private static final ObservableList<String> NOT_NULL_NUM_CONVERSIONS = FXCollections.observableArrayList();
+
+        static {
+            List<String> primitives = classNames(boolean.class, byte.class, short.class,
+                int.class, long.class, float.class, double.class);
+
+            List<String> objects = classNames(Boolean.class, Byte.class, Short.class, Integer.class,
+                Long.class, Float.class, Double.class, BigDecimal.class);
+
+            NULL_NUM_CONVERSIONS.addAll(objects);
+
+            NOT_NULL_NUM_CONVERSIONS.addAll(primitives);
+            NOT_NULL_NUM_CONVERSIONS.addAll(objects);
+
+            fillClassesMap(boolean.class, Boolean.class,
+                byte.class, Byte.class,
+                short.class, Short.class,
+                int.class, Integer.class,
+                long.class, Long.class,
+                float.class, Float.class,
+                double.class, Double.class,
+                BigDecimal.class,
+                String.class,
+                java.sql.Date.class, java.sql.Time.class, java.sql.Timestamp.class,
+                Array.class, Void.class, URL.class, Object.class);
+        }
+
+        /**
+         * @param dbType Database type.
+         * @param nullable Nullable.
+         * @param dflt Default.
+         * @return List of possible type conversions.
+         */
+        private static ObservableList<String> conversions(int dbType, boolean nullable, String dflt) {
+            switch (dbType) {
+                case TINYINT:
+                case SMALLINT:
+                case INTEGER:
+                case BIGINT:
+                case REAL:
+                case FLOAT:
+                case DOUBLE:
+                    return nullable ? NULL_NUM_CONVERSIONS : NOT_NULL_NUM_CONVERSIONS;
+
+                default:
+                    return FXCollections.singletonObservableList(dflt);
+            }
+        }
+
+        /**
+         * @param key {@code true} if this field belongs to primary key.
+         * @param desc Field type descriptor.
+         */
+        public PojoField(boolean key, GridCacheQueryTypeDescriptor desc) {
+            this.desc = desc;
+            this.key = new SimpleBooleanProperty(key);
+
+            javaName = new SimpleStringProperty(desc.getJavaName());
+
+            String typeName = desc.getJavaType().getName();
+
+            javaTypeName = new SimpleStringProperty(typeName);
+
+            dbName = new SimpleStringProperty(desc.getDbName());
+
+            dbTypeName = new SimpleStringProperty(jdbcTypeName(desc.getDbType()));
+
+            boolean nullable = true;
+
+            conversions = conversions(desc.getDbType(), nullable, typeName);
+        }
+
+        /**
+         * @param jdbcType String name for JDBC type.
+         */
+        private String jdbcTypeName(int jdbcType) {
+            switch (jdbcType) {
+                case BIT:
+                    return "BIT";
+                case TINYINT:
+                    return "TINYINT";
+                case SMALLINT:
+                    return "SMALLINT";
+                case INTEGER:
+                    return "INTEGER";
+                case BIGINT:
+                    return "BIGINT";
+                case FLOAT:
+                    return "FLOAT";
+                case REAL:
+                    return "REAL";
+                case DOUBLE:
+                    return "DOUBLE";
+                case NUMERIC:
+                    return "NUMERIC";
+                case DECIMAL:
+                    return "DECIMAL";
+                case CHAR:
+                    return "CHAR";
+                case VARCHAR:
+                    return "VARCHAR";
+                case LONGVARCHAR:
+                    return "LONGVARCHAR";
+                case DATE:
+                    return "DATE";
+                case TIME:
+                    return "TIME";
+                case TIMESTAMP:
+                    return "TIMESTAMP";
+                case BINARY:
+                    return "BINARY";
+                case VARBINARY:
+                    return "VARBINARY";
+                case LONGVARBINARY:
+                    return "LONGVARBINARY";
+                case NULL:
+                    return "NULL";
+                case OTHER:
+                    return "OTHER";
+                case JAVA_OBJECT:
+                    return "JAVA_OBJECT";
+                case DISTINCT:
+                    return "DISTINCT";
+                case STRUCT:
+                    return "STRUCT";
+                case ARRAY:
+                    return "ARRAY";
+                case BLOB:
+                    return "BLOB";
+                case CLOB:
+                    return "CLOB";
+                case REF:
+                    return "REF";
+                case DATALINK:
+                    return "DATALINK";
+                case BOOLEAN:
+                    return "BOOLEAN";
+                case ROWID:
+                    return "ROWID";
+                case NCHAR:
+                    return "NCHAR";
+                case NVARCHAR:
+                    return "NVARCHAR";
+                case LONGNVARCHAR:
+                    return "LONGNVARCHAR";
+                case NCLOB:
+                    return "NCLOB";
+                case SQLXML:
+                    return "SQLXML";
+                default:
+                    return "Unknown";
+            }
+        }
+
+        /**
+         * @return {@code true} if this field belongs to primary key.
+         */
+        public boolean key() {
+            return key.get();
+        }
+
+        /**
+         * @param pk {@code true} if this field belongs to primary key.
+         */
+        public void key(boolean pk) {
+            key.set(pk);
+        }
+
+        /**
+         * @return POJO field java name.
+         */
+        public String javaName() {
+            return javaName.get();
+        }
+
+        /**
+         * @param name POJO field java name.
+         */
+        public void javaName(String name) {
+            javaName.set(name);
+        }
+
+        /**
+         * @return POJO field java type name.
+         */
+        public String javaTypeName() {
+            return javaTypeName.get();
+        }
+
+        /**
+         * @return Type descriptor.
+         */
+        public GridCacheQueryTypeDescriptor descriptor() {
+            desc.setJavaName(javaName.get());
+            desc.setJavaType(classesMap.get(javaTypeName()));
+
+            return desc;
+        }
+
+        /**
+         * @return POJO field JDBC type in database.
+         */
+        public int dbType() {
+            return desc.getDbType();
+        }
+
+        /**
+         * @return Boolean property support for {@code key} property.
+         */
+        public BooleanProperty keyProperty() {
+            return key;
+        }
+
+        /**
+         * @return String property support for {@code javaName} property.
+         */
+        public StringProperty javaNameProperty() {
+            return javaName;
+        }
+
+        /**
+         * @return String property support for {@code javaTypeName} property.
+         */
+        public StringProperty javaTypeNameProperty() {
+            return javaTypeName;
+        }
+
+        /**
+         * @return String property support for {@code dbName} property.
+         */
+        public StringProperty dbNameProperty() {
+            return dbName;
+        }
+
+        /**
+         * @return String property support for {@code dbName} property.
+         */
+        public StringProperty dbTypeNameProperty() {
+            return dbTypeName;
+        }
+
+        /**
+         * @return List of possible java type conversions.
+         */
+        public ObservableList<String> conversions() {
+            return conversions;
+        }
+    }
+
+    /**
+     * Descriptor for java type.
+     */
+    private static class PojoDescriptor {
+        /** Previous name for key class. */
+        private final String keyClsNamePrev;
+
+        /** Previous name for value class. */
+        private final String valClsNamePrev;
+
+        /** Java class fields. */
+        private final ObservableList<PojoField> fields;
+
+        /** Java class fields. */
+        private final List<PojoField> fieldsPrev;
+
+        /** Type metadata. */
+        private final GridCacheQueryTypeMetadata meta;
+
+        /**
+         * Type descriptor.
+         *
+         * @param meta Type metadata.
+         */
+        public PojoDescriptor(GridCacheQueryTypeMetadata meta) {
+            this.meta = meta;
+
+            keyClsNamePrev = meta.getKeyType();
+
+            valClsNamePrev = meta.getType();
+
+            Collection<GridCacheQueryTypeDescriptor> keys = meta.getKeyDescriptors();
+
+            Collection<GridCacheQueryTypeDescriptor> vals = meta.getValueDescriptors();
+
+            int sz = keys.size() + vals.size();
+
+            List<PojoField> flds = new ArrayList<>(sz);
+            fieldsPrev = new ArrayList<>(sz);
+
+            for (GridCacheQueryTypeDescriptor key : keys) {
+                flds.add(new PojoField(true, key));
+                fieldsPrev.add(new PojoField(true, key));
+            }
+
+            for (GridCacheQueryTypeDescriptor val : vals) {
+                flds.add(new PojoField(false, val));
+                fieldsPrev.add(new PojoField(false, val));
+            }
+
+            fields = FXCollections.observableList(flds);
+        }
+
+        /**
+         * @return {@code true} if descriptor was changed by user via GUI.
+         */
+        public boolean changed() {
+            boolean diff = !meta.getKeyType().equals(keyClsNamePrev) || !meta.getType().equals(valClsNamePrev);
+
+            if (!diff)
+                for (int i = 0; i < fields.size(); i++) {
+                    PojoField cur = fields.get(i);
+                    PojoField prev = fieldsPrev.get(i);
+
+                    // User can change via GUI only key and java name properties.
+                    if (cur.key() != prev.key() || !cur.javaName().equals(prev.javaName())) {
+                        diff = true;
+
+                        break;
+                    }
+                }
+
+            return diff;
+        }
+
+        /**
+         * Revert changes to java names made by user.
+         */
+        public void revertJavaNames() {
+            for (int i = 0; i < fields.size(); i++)
+                fields.get(i).javaName(fieldsPrev.get(i).javaName());
+        }
+
+        /**
+         * @return Name for key class.
+         */
+        public String keyClassName() {
+            return meta.getKeyType();
+        }
+
+        /**
+         * @param name Name for key class.
+         */
+        public void keyClassName(String name) {
+            meta.setKeyType(name);
+        }
+
+        /**
+         * @return Name for value class.
+         */
+        public String valueClassName() {
+            return meta.getType();
+        }
+
+        /**
+         * @param name Name for value class.
+         */
+        public void valueClassName(String name) {
+            meta.setType(name);
+        }
+
+        /**
+         * @return Java class fields.
+         */
+        public ObservableList<PojoField> fields() {
+            return fields;
+        }
+
+        /**
+         * @return Type metadata.
+         */
+        public GridCacheQueryTypeMetadata metadata() {
+            return meta;
+        }
+    }
+
+    /**
      * Special table cell to select possible java type conversions.
      */
     private static class JavaTypeCell extends TableCell<PojoField, String> {
@@ -1167,7 +1834,7 @@ public class SchemaLoadApp extends Application {
         public static Callback<TableColumn<PojoField, String>, TableCell<PojoField, String>> forTableColumn() {
             return new Callback<TableColumn<PojoField, String>, TableCell<PojoField, String>>() {
                 public TableCell<PojoField, String> call(TableColumn<PojoField, String> col) {
-                    return new JavaTypeCell(col);
+                    return new JavaTypeCell();
                 }
             };
         }
@@ -1175,29 +1842,9 @@ public class SchemaLoadApp extends Application {
         /**
          * Default constructor.
          */
-        private JavaTypeCell(final TableColumn<PojoField, String> col) {
+        private JavaTypeCell() {
             comboBox = new ComboBox<>(FXCollections.<String>emptyObservableList());
 
-            comboBox.editableProperty().bind(col.editableProperty());
-
-            comboBox.disableProperty().bind(col.editableProperty().not());
-
-            comboBox.setOnShowing(new EventHandler<Event>() {
-                @Override public void handle(Event evt) {
-                    final TableView<PojoField> tblView = getTableView();
-                    tblView.getSelectionModel().select(getTableRow().getIndex());
-
-                    PojoField pojo = tblView.getSelectionModel().getSelectedItem();
-                    if (pojo != null) {
-                        comboBox.setItems(pojo.conversions());
-
-                        comboBox.getSelectionModel().select(pojo.javaTypeName());
-                    }
-
-                    tblView.edit(tblView.getSelectionModel().getSelectedIndex(), col);
-                }
-            });
-
             comboBox.valueProperty().addListener(new ChangeListener<String>() {
                 @Override public void changed(ObservableValue<? extends String> val, String oldVal, String newVal) {
                     if (isEditing())
@@ -1205,22 +1852,46 @@ public class SchemaLoadApp extends Application {
                 }
             });
 
-            setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
-
             getStyleClass().add("combo-box-table-cell");
         }
 
         /** {@inheritDoc} */
+        @Override public void startEdit() {
+            if (comboBox.getItems().size() > 1) {
+                comboBox.getSelectionModel().select(this.getItem());
+
+                super.startEdit();
+
+                setText(null);
+                setGraphic(comboBox);
+            }
+        }
+
+        /** {@inheritDoc} */
+        @Override public void cancelEdit() {
+            super.cancelEdit();
+
+            setText(getItem());
+
+            setGraphic(null);
+        }
+
+        /** {@inheritDoc} */
         @Override public void updateItem(String item, boolean empty) {
             super.updateItem(item, empty);
 
-            setText(null);
+            setGraphic(null);
 
-            if(empty)
-                setGraphic(null);
-            else {
-                comboBox.setValue(item);
-                setGraphic(comboBox);
+            if (!empty) {
+                setText(item);
+
+                PojoField pojo = (PojoField)getTableRow().getItem();
+
+                if (pojo != null) {
+                    comboBox.setItems(pojo.conversions());
+
+                    comboBox.getSelectionModel().select(pojo.javaTypeName());
+                }
             }
         }
     }


Mime
View raw message