http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/9cf45b43/modules/schema-import/src/main/java/org/apache/ignite/schema/model/PojoDescriptor.java
----------------------------------------------------------------------
diff --git 
a/modules/schema-import/src/main/java/org/apache/ignite/schema/model/PojoDescriptor.java
 
b/modules/schema-import/src/main/java/org/apache/ignite/schema/model/PojoDescriptor.java
new file mode 100644
index 0000000..9f3322b
--- /dev/null
+++ 
b/modules/schema-import/src/main/java/org/apache/ignite/schema/model/PojoDescriptor.java
@@ -0,0 +1,510 @@
+/*
+ * 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.model;
+
+import javafx.beans.property.*;
+import javafx.beans.value.*;
+import javafx.collections.*;
+import org.apache.ignite.lang.*;
+import org.apache.ignite.schema.parser.*;
+
+import java.math.*;
+import java.util.*;
+
+import static java.sql.Types.*;
+
+/**
+ * Descriptor for java type.
+ */
+public class PojoDescriptor {
+    /** Database table. */
+    private final DbTable tbl;
+
+    /** Selected property. */
+    private final BooleanProperty useProp;
+
+    /** Previous name for key class. */
+    private final String keyClsNamePrev;
+
+    /** Key class name to show on screen. */
+    private final StringProperty keyClsNameProp;
+
+    /** Previous name for value class. */
+    private final String valClsNamePrev;
+
+    /** Value class name to show on screen. */
+    private final StringProperty valClsNameProp;
+
+    /** Parent item (schema name). */
+    private final PojoDescriptor parent;
+
+    /** Children items (tables names). */
+    private Collection<PojoDescriptor> children = Collections.emptyList();
+
+    /** Indeterminate state of parent. */
+    private final BooleanProperty indeterminateProp = new 
SimpleBooleanProperty(false);
+
+    /** Full database name: schema + table. */
+    private final String fullDbName;
+
+    /** Java class fields. */
+    private final ObservableList<PojoField> fields;
+
+    /** Fields map for quick access. */
+    private final Map<String, PojoField> fieldsMap;
+
+    /**
+     * Constructor of POJO descriptor.
+     *
+     * @param prn Parent descriptor.
+     * @param tbl Database table Tab;e.
+     */
+    public PojoDescriptor(PojoDescriptor prn, DbTable tbl) {
+        parent = prn;
+
+        this.tbl = tbl;
+
+        fullDbName = tbl.schema() + "." + tbl.table();
+
+        valClsNamePrev = toJavaClassName(tbl.table());
+        valClsNameProp = new SimpleStringProperty(valClsNamePrev);
+
+        keyClsNamePrev = valClsNamePrev.isEmpty() ? "" : valClsNamePrev + 
"Key";
+        keyClsNameProp = new SimpleStringProperty(keyClsNamePrev);
+
+        Collection<DbColumn> cols = tbl.columns();
+
+        List<PojoField> flds = new ArrayList<>(cols.size());
+
+        fieldsMap = new HashMap<>(cols.size());
+
+        for (DbColumn col : cols) {
+            String colName = col.name();
+
+            PojoField fld = new PojoField(colName, col.type(),
+                toJavaFieldName(colName), toJavaType(col.type(), 
col.nullable()).getName(),
+                col.key(), col.nullable());
+
+            fld.owner(this);
+
+            flds.add(fld);
+
+            fieldsMap.put(colName, fld);
+        }
+
+        fields = FXCollections.observableList(flds);
+
+        boolean isTbl = parent != null;
+
+        boolean hasKeys = !isTbl || !keyFields().isEmpty();
+
+        useProp = new SimpleBooleanProperty(hasKeys);
+
+        if (isTbl && !hasKeys && !parent.indeterminateProp.get())
+            parent.indeterminateProp.set(true);
+
+        useProp.addListener(new ChangeListener<Boolean>() {
+            @Override public void changed(ObservableValue<? extends Boolean> 
val, Boolean oldVal, Boolean newVal) {
+                for (PojoDescriptor child : children)
+                    child.useProp.set(newVal);
+
+                if (parent != null && !parent.children.isEmpty()) {
+                    Iterator<PojoDescriptor> it = parent.children.iterator();
+
+                    boolean parentIndeterminate = false;
+                    boolean first = it.next().useProp.get();
+
+                    while (it.hasNext()) {
+                        if (it.next().useProp.get() != first) {
+                            parentIndeterminate = true;
+
+                            break;
+                        }
+                    }
+
+                    parent.indeterminateProp.set(parentIndeterminate);
+
+                    if (!parentIndeterminate)
+                        parent.useProp.set(first);
+                }
+            }
+        });
+    }
+
+    /**
+     * @return Parent descriptor.
+     */
+    public PojoDescriptor parent() {
+        return parent;
+    }
+
+    /**
+     * @return Full database name: schema + table.
+     */
+    public String fullDbName() {
+        return fullDbName;
+    }
+
+    /**
+     * @return {@code true} if POJO descriptor is a table descriptor and 
checked in GUI.
+     */
+    public boolean checked() {
+        return parent != null && useProp.get();
+    }
+
+    /**
+     * @return Boolean property support for {@code use} property.
+     */
+    public BooleanProperty useProperty() {
+        return useProp;
+    }
+
+    /**
+     * @return Boolean property support for parent {@code indeterminate} 
property.
+     */
+    public BooleanProperty indeterminate() {
+        return indeterminateProp;
+    }
+
+    /**
+     * @return Key class name.
+     */
+    public String keyClassName() {
+        return keyClsNameProp.get();
+    }
+
+    /**
+     * @param name New key class name.
+     */
+    public void keyClassName(String name) {
+        keyClsNameProp.set(name);
+    }
+
+    /**
+     * @return Value class name.
+     */
+    public String valueClassName() {
+        return valClsNameProp.get();
+    }
+
+    /**
+     * @param name New value class name.
+     */
+    public void valueClassName(String name) {
+        valClsNameProp.set(name);
+    }
+
+    /**
+     * @return {@code true} if at least one field checked as &quot;used&quot;.
+     */
+    public boolean hasFields() {
+        for (PojoField field : fields)
+            if (field.use())
+                return true;
+
+        return false;
+    }
+
+    /**
+     * @return {@code true} if at least one field checked as &quot;used&quot; 
and checked as &quot;key&quot;.
+     */
+    public boolean hasKeyFields() {
+        for (PojoField field : fields)
+            if (field.use() && field.key())
+                return true;
+
+        return false;
+    }
+
+    /**
+     * @param includeKeys {@code true} if key fields should be included into 
value class.
+     * @return {@code true} if at least one field checked as &quot;used&quot; 
and not checked as &quot;key&quot;.
+     */
+    public boolean hasValueFields(boolean includeKeys) {
+        if (includeKeys)
+            return hasKeyFields();
+
+        for (PojoField field : fields)
+            if (field.use() && !field.key())
+                return true;
+
+        return false;
+    }
+
+    /**
+     * @return Collection of key fields.
+     */
+    public Collection<PojoField> keyFields() {
+        Collection<PojoField> keys = new ArrayList<>();
+
+        for (PojoField field : fields)
+            if (field.use() && field.key() )
+                keys.add(field);
+
+        return keys;
+    }
+
+    /**
+     * @param includeKeys {@code true} if key fields should be included into 
value class.
+     * @return Collection of value fields.
+     */
+    public Collection<PojoField> valueFields(boolean includeKeys) {
+        Collection<PojoField> vals = new ArrayList<>();
+
+        for (PojoField field : fields)
+            if (field.use() && (includeKeys || !field.key()))
+                vals.add(field);
+
+        return vals;
+    }
+
+    /**
+     * @return Ascending fields.
+     */
+    public Collection<PojoField> ascendingFields() {
+        Collection<PojoField> res = new ArrayList<>();
+
+        Set<String> asc = tbl.ascendingColumns();
+
+        for (PojoField field : fields)
+            if (field.use() && asc.contains(field.dbName()))
+                res.add(field);
+
+        return res;
+    }
+
+    /**
+     * @return Descending fields.
+     */
+    public Collection<PojoField> descendingFields() {
+        Collection<PojoField> res = new ArrayList<>();
+
+        Set<String> desc = tbl.descendingColumns();
+
+        for (PojoField field : fields)
+            if (field.use() && desc.contains(field.dbName()))
+                res.add(field);
+
+        return res;
+    }
+
+    /**
+     * Gets indexes groups.
+     */
+    public Map<String, Map<String, IgniteBiTuple<String, Boolean>>> groups() {
+        Map<String, Map<String, Boolean>> idxs = tbl.indexes();
+
+        Map<String, Map<String, IgniteBiTuple<String, Boolean>>> groups = new 
LinkedHashMap<>(idxs.size());
+
+        for (Map.Entry<String, Map<String, Boolean>> idx : idxs.entrySet()) {
+            String idxName = idx.getKey();
+
+            Map<String, Boolean> idxCols = idx.getValue();
+
+            Map<String, IgniteBiTuple<String, Boolean>> grp = new 
LinkedHashMap<>();
+
+            groups.put(idxName, grp);
+
+            for (Map.Entry<String, Boolean> idxCol : idxCols.entrySet()) {
+                PojoField fld = fieldsMap.get(idxCol.getKey());
+
+                grp.put(fld.javaName(), new 
IgniteBiTuple<>(fld.javaTypeName(), idxCol.getValue()));
+            }
+        }
+
+        return groups;
+    }
+
+    /**
+     * @return Key class name property.
+     */
+    public StringProperty keyClassNameProperty() {
+        return keyClsNameProp;
+    }
+
+    /**
+     * @return Value class name property.
+     */
+    public StringProperty valueClassNameProperty() {
+        return valClsNameProp;
+    }
+
+    /**
+     * @return Schema name.
+     */
+    public String schema() {
+        return tbl.schema();
+    }
+
+    /**
+     * @return Table name.
+     */
+    public String table() {
+        return tbl.table();
+    }
+
+    /**
+     * Sets children items.
+     *
+     * @param children Items to set.
+     */
+    public void children(Collection<PojoDescriptor> children) {
+        this.children = children;
+    }
+
+    /**
+     * @return {@code true} if descriptor was changed by user via GUI.
+     */
+    public boolean changed() {
+        if (!keyClsNameProp.get().equals(keyClsNamePrev) || 
!valClsNameProp.get().equals(valClsNamePrev))
+            return true;
+
+        for (PojoField field : fields)
+            if (field.changed())
+                return true;
+
+        return false;
+    }
+
+    /**
+     * Revert changes to key class name made by user.
+     */
+    public void revertKeyClassName() {
+        keyClsNameProp.set(keyClsNamePrev);
+    }
+
+    /**
+     * Revert changes to value class name made by user.
+     */
+    public void revertValueClassName() {
+        valClsNameProp.set(valClsNamePrev);
+    }
+
+    /**
+     * Revert changes to java names made by user.
+     */
+    public void revertJavaNames() {
+        for (PojoField field : fields)
+            field.resetJavaName();
+    }
+
+    /**
+     * @return Java class fields.
+     */
+    public ObservableList<PojoField> fields() {
+        return fields;
+    }
+
+    /**
+     * @param name Source name.
+     * @return String converted to java class name notation.
+     */
+    private static 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 static 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.
+     * @param nullable {@code true} if {@code NULL} is allowed for this field 
in database.
+     * @return Java data type.
+     */
+    private static Class<?> toJavaType(int type, boolean nullable) {
+        switch (type) {
+            case BIT:
+            case BOOLEAN:
+                return nullable ? Boolean.class : boolean.class;
+
+            case TINYINT:
+                return nullable ? Byte.class : byte.class;
+
+            case SMALLINT:
+                return nullable ? Short.class : short.class;
+
+            case INTEGER:
+                return nullable ? Integer.class : int.class;
+
+            case BIGINT:
+                return nullable ? Long.class : long.class;
+
+            case REAL:
+                return nullable ? Float.class : float.class;
+
+            case FLOAT:
+            case DOUBLE:
+                return nullable ? Double.class : 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 java.sql.Date.class;
+
+            case TIME:
+                return java.sql.Time.class;
+
+            case TIMESTAMP:
+                return java.sql.Timestamp.class;
+
+            // BINARY, VARBINARY, LONGVARBINARY, ARRAY, BLOB, CLOB, NCLOB, 
NULL, DATALINK
+            // OTHER, JAVA_OBJECT, DISTINCT, STRUCT, REF, ROWID, SQLXML
+            default:
+                return Object.class;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/9cf45b43/modules/schema-import/src/main/java/org/apache/ignite/schema/model/PojoField.java
----------------------------------------------------------------------
diff --git 
a/modules/schema-import/src/main/java/org/apache/ignite/schema/model/PojoField.java
 
b/modules/schema-import/src/main/java/org/apache/ignite/schema/model/PojoField.java
new file mode 100644
index 0000000..10939d9
--- /dev/null
+++ 
b/modules/schema-import/src/main/java/org/apache/ignite/schema/model/PojoField.java
@@ -0,0 +1,420 @@
+/*
+ * 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.model;
+
+import javafx.beans.property.*;
+import javafx.beans.value.*;
+import javafx.collections.*;
+
+import java.math.*;
+import java.util.*;
+
+import static java.sql.Types.*;
+
+/**
+ * Field descriptor with properties for JavaFX GUI bindings.
+ */
+public class PojoField {
+    /** If this field should be used for code generation. */
+    private final BooleanProperty useProp;
+
+    /** If this field belongs to primary key. */
+    private final BooleanProperty keyProp;
+
+    /** If this field is an affinity key. */
+    private final BooleanProperty akProp;
+
+    /** If this field initially belongs to primary key. */
+    private final boolean keyPrev;
+
+    /** Field name in database. */
+    private final StringProperty dbNameProp;
+
+    /** Field type in database. */
+    private final StringProperty dbTypeNameProp;
+
+    /** Field name in POJO. */
+    private final StringProperty javaNameProp;
+
+    /** Initial field name in POJO. */
+    private final String javaNamePrev;
+
+    /** Field type in POJO. */
+    private final StringProperty javaTypeNameProp;
+
+    /** Initial field type in POJO. */
+    private final String javaTypeNamePrev;
+
+    /** Is {@code NULL} allowed for field in database. */
+    private final boolean nullable;
+
+    /** List of possible java type conversions. */
+    private final ObservableList<String> conversions;
+
+    /** Field owner. */
+    private PojoDescriptor owner;
+
+    /**
+     * @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();
+
+    /** Primitive types. */
+    private static final List<String> PRIMITIVES = classNames(boolean.class, 
byte.class, short.class,
+        int.class, long.class, float.class, double.class);
+
+    /** Object types. */
+    private static final List<String> OBJECTS = classNames(Boolean.class, 
Byte.class, Short.class, Integer.class,
+        Long.class, Float.class, Double.class, BigDecimal.class);
+
+    static {
+        NOT_NULL_NUM_CONVERSIONS.addAll(PRIMITIVES);
+        NOT_NULL_NUM_CONVERSIONS.addAll(OBJECTS);
+
+        NULL_NUM_CONVERSIONS.addAll(OBJECTS);
+    }
+
+    /**
+     * @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 dbName Field name in database.
+     * @param dbType Field JDBC type in database.
+     * @param javaName Field name in POJO.
+     * @param javaTypeName Field type in POJO.
+     * @param key {@code true} if this field belongs to primary key.
+     * @param nullable {@code true} if  {@code NULL} allowed for field in 
database.
+     */
+    public PojoField(String dbName, int dbType, String javaName, String 
javaTypeName, boolean key, boolean nullable) {
+        dbNameProp = new SimpleStringProperty(dbName);
+
+        dbTypeNameProp = new SimpleStringProperty(jdbcTypeName(dbType));
+
+        javaNamePrev = javaName;
+
+        javaNameProp = new SimpleStringProperty(javaNamePrev);
+
+        javaTypeNamePrev = javaTypeName;
+
+        javaTypeNameProp = new SimpleStringProperty(javaTypeNamePrev);
+
+        useProp = new SimpleBooleanProperty(true);
+
+        keyPrev = key;
+
+        keyProp = new SimpleBooleanProperty(keyPrev);
+
+        this.nullable = nullable;
+
+        akProp = new SimpleBooleanProperty(false);
+
+        conversions = conversions(dbType, nullable, javaNamePrev);
+
+        keyProp.addListener(new ChangeListener<Boolean>() {
+            @Override public void changed(ObservableValue<? extends Boolean> 
val, Boolean oldVal, Boolean newVal) {
+                if (newVal) {
+                    if (!use())
+                        useProp.set(true);
+                }
+                else
+                    akProp.set(false);
+            }
+        });
+
+        akProp.addListener(new ChangeListener<Boolean>() {
+            @Override public void changed(ObservableValue<? extends Boolean> 
val, Boolean oldVal, Boolean newVal) {
+                if (newVal && owner != null) {
+                    keyProperty().set(true);
+
+                    for (PojoField field : owner.fields())
+                        if (field != PojoField.this && field.affinityKey())
+                            field.akProp.set(false);
+                }
+            }
+        });
+    }
+
+    /**
+     * @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";
+        }
+    }
+
+    /**
+     * Revert changes to java names made by user.
+     */
+    public void resetJavaName() {
+        javaNameProp.set(javaNamePrev);
+    }
+
+    /**
+     * @param owner New field owner.
+     */
+    public void owner(PojoDescriptor owner) {
+        this.owner = owner;
+    }
+
+    /**
+     * @return {@code true} if filed should be used for code generation.
+     */
+    public boolean use() {
+        return useProp.get();
+    }
+
+    /**
+     * @return {@code true} if this field belongs to primary key.
+     */
+    public boolean key() {
+        return keyProp.get();
+    }
+
+    /**
+     * @param pk {@code true} if this field belongs to primary key.
+     */
+    public void key(boolean pk) {
+        keyProp.set(pk);
+    }
+
+    /**
+     * @return {@code true} if this field is an affinity key.
+     */
+    public boolean affinityKey() {
+        return akProp.get();
+    }
+
+    /**
+     * @return POJO field java name.
+     */
+    public String javaName() {
+        return javaNameProp.get();
+    }
+
+    /**
+     * @param name New POJO field java name.
+     */
+    public void javaName(String name) {
+        javaNameProp.set(name);
+    }
+
+    /**
+     * @return POJO field java type name.
+     */
+    public String javaTypeName() {
+        return javaTypeNameProp.get();
+    }
+
+    /**
+     * @return Field name in database.
+     */
+    public String dbName() {
+        return dbNameProp.get();
+    }
+
+    /**
+     * @return POJO field JDBC type name in database.
+     */
+    public String dbTypeName() {
+        return dbTypeNameProp.get();
+    }
+
+    /**
+     * @return Is NULL allowed for field in database.
+     */
+    public boolean nullable() {
+        return nullable;
+    }
+
+    /**
+     * @return List of possible java type conversions.
+     */
+    public ObservableList<String> conversions() {
+        return conversions;
+    }
+
+    /**
+     * @return {@code true} if type of field is primitive type.
+     */
+    public boolean primitive() {
+        return PRIMITIVES.contains(javaTypeName());
+    }
+
+    /**
+     * @return {@code true} if field was changed by user.
+     */
+    public boolean changed() {
+        return keyPrev != key() || !javaNamePrev.equals(javaName()) || 
!javaTypeNamePrev.equals(javaTypeName());
+    }
+
+    /**
+     * @return Boolean property support for {@code use} property.
+     */
+    public BooleanProperty useProperty() {
+        return useProp;
+    }
+
+    /**
+     * @return Boolean property support for {@code key} property.
+     */
+    public BooleanProperty keyProperty() {
+        return keyProp;
+    }
+
+    /**
+     * @return Boolean property support for {@code affinityKey} property.
+     */
+    public BooleanProperty affinityKeyProperty() {
+        return akProp;
+    }
+
+    /**
+     * @return String property support for {@code javaName} property.
+     */
+    public StringProperty javaNameProperty() {
+        return javaNameProp;
+    }
+
+    /**
+     * @return String property support for {@code javaTypeName} property.
+     */
+    public StringProperty javaTypeNameProperty() {
+        return javaTypeNameProp;
+    }
+
+    /**
+     * @return String property support for {@code dbName} property.
+     */
+    public StringProperty dbNameProperty() {
+        return dbNameProp;
+    }
+
+    /**
+     * @return String property support for {@code dbName} property.
+     */
+    public StringProperty dbTypeNameProperty() {
+        return dbTypeNameProp;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/9cf45b43/modules/schema-import/src/main/java/org/apache/ignite/schema/parser/DatabaseMetadataParser.java
----------------------------------------------------------------------
diff --git 
a/modules/schema-import/src/main/java/org/apache/ignite/schema/parser/DatabaseMetadataParser.java
 
b/modules/schema-import/src/main/java/org/apache/ignite/schema/parser/DatabaseMetadataParser.java
new file mode 100644
index 0000000..696ca62
--- /dev/null
+++ 
b/modules/schema-import/src/main/java/org/apache/ignite/schema/parser/DatabaseMetadataParser.java
@@ -0,0 +1,108 @@
+/*
+ * 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.parser;
+
+import javafx.collections.*;
+import org.apache.ignite.schema.model.*;
+import org.apache.ignite.schema.parser.dialect.*;
+
+import java.sql.*;
+import java.util.*;
+import java.util.logging.*;
+
+/**
+ * Database metadata parser.
+ */
+public class DatabaseMetadataParser {
+    /** Logger. */
+    private static final Logger log = 
Logger.getLogger(DatabaseMetadataParser.class.getName());
+
+    /**
+     * Parse database metadata.
+     *
+     * @param conn Connection to database.
+     * @param tblsOnly If {@code true} then process tables only else process 
tables and views.
+     * @return Collection of POJO descriptors.
+     * @throws SQLException If parsing failed.
+     */
+    public static ObservableList<PojoDescriptor> parse(Connection conn, 
boolean tblsOnly) throws SQLException {
+        DatabaseMetadataDialect dialect;
+
+        try {
+            String dbProductName = conn.getMetaData().getDatabaseProductName();
+
+            if ("Oracle".equals(dbProductName))
+                dialect = new OracleMetadataDialect();
+            else if (dbProductName.startsWith("DB2/"))
+                dialect = new DB2MetadataDialect();
+            else
+                dialect = new JdbcMetadataDialect();
+        }
+        catch (SQLException e) {
+            log.log(Level.SEVERE, "Failed to resolve dialect 
(JdbcMetaDataDialect will be used.", e);
+
+            dialect = new JdbcMetadataDialect();
+        }
+
+        Map<String, PojoDescriptor> parents = new HashMap<>();
+
+        Map<String, Collection<PojoDescriptor>> childrens = new HashMap<>();
+
+        for (DbTable tbl : dialect.tables(conn, tblsOnly)) {
+            String schema = tbl.schema();
+
+            PojoDescriptor parent = parents.get(schema);
+            Collection<PojoDescriptor> children = childrens.get(schema);
+
+            if (parent == null) {
+                parent = new PojoDescriptor(null, new DbTable(schema, "", 
Collections.<DbColumn>emptyList(),
+                    Collections.<String>emptySet(), 
Collections.<String>emptySet(),
+                    Collections.<String, Map<String, Boolean>>emptyMap()));
+
+                children = new ArrayList<>();
+
+                parents.put(schema, parent);
+                childrens.put(schema, children);
+            }
+
+            children.add(new PojoDescriptor(parent, tbl));
+        }
+
+        List<PojoDescriptor> res = new ArrayList<>();
+
+        for (String schema : parents.keySet()) {
+            PojoDescriptor parent = parents.get(schema);
+            Collection<PojoDescriptor> children = childrens.get(schema);
+
+            if (!children.isEmpty()) {
+                parent.children(children);
+
+                res.add(parent);
+                res.addAll(children);
+            }
+        }
+
+        Collections.sort(res, new Comparator<PojoDescriptor>() {
+            @Override public int compare(PojoDescriptor o1, PojoDescriptor o2) 
{
+                return o1.fullDbName().compareTo(o2.fullDbName());
+            }
+        });
+
+        return FXCollections.observableList(res);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/9cf45b43/modules/schema-import/src/main/java/org/apache/ignite/schema/parser/DbColumn.java
----------------------------------------------------------------------
diff --git 
a/modules/schema-import/src/main/java/org/apache/ignite/schema/parser/DbColumn.java
 
b/modules/schema-import/src/main/java/org/apache/ignite/schema/parser/DbColumn.java
new file mode 100644
index 0000000..8b0c813
--- /dev/null
+++ 
b/modules/schema-import/src/main/java/org/apache/ignite/schema/parser/DbColumn.java
@@ -0,0 +1,76 @@
+/*
+ * 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.parser;
+
+/**
+ * Database table column.
+ */
+public class DbColumn {
+    /** Column name. */
+    private final String name;
+
+    /** Column JDBC type. */
+    private final int type;
+
+    /** Is this column belongs to primary key. */
+    private final boolean key;
+
+    /** Is {@code NULL} allowed for column in database. */
+    private final boolean nullable;
+
+    /**
+     * @param name Column name.
+     * @param type Column JDBC type.
+     * @param key {@code true} if this column belongs to primary key.
+     * @param nullable {@code true} if {@code NULL } allowed for column in 
database.
+     */
+    public DbColumn(String name, int type, boolean key, boolean nullable) {
+        this.name = name;
+        this.type = type;
+        this.key = key;
+        this.nullable = nullable;
+    }
+
+    /**
+     * @return Column name.
+     */
+    public String name() {
+        return name;
+    }
+
+    /**
+     * @return Column JDBC type.
+     */
+    public int type() {
+        return type;
+    }
+
+    /**
+     * @return {@code true} if this column belongs to primary key.
+     */
+    public boolean key() {
+        return key;
+    }
+
+    /**
+     * @return nullable {@code true} if {@code NULL } allowed for column in 
database.
+     */
+    public boolean nullable() {
+        return nullable;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/9cf45b43/modules/schema-import/src/main/java/org/apache/ignite/schema/parser/DbTable.java
----------------------------------------------------------------------
diff --git 
a/modules/schema-import/src/main/java/org/apache/ignite/schema/parser/DbTable.java
 
b/modules/schema-import/src/main/java/org/apache/ignite/schema/parser/DbTable.java
new file mode 100644
index 0000000..35c7d91
--- /dev/null
+++ 
b/modules/schema-import/src/main/java/org/apache/ignite/schema/parser/DbTable.java
@@ -0,0 +1,105 @@
+/*
+ * 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.parser;
+
+import java.util.*;
+
+/**
+ * Database table.
+ */
+public class DbTable {
+    /** Schema name. */
+    private final String schema;
+
+    /** Table name. */
+    private final String tbl;
+
+    /** Columns. */
+    private final Collection<DbColumn> cols;
+
+    /** Columns in ascending order. */
+    private final Set<String> ascCols;
+
+    /** Columns in descending order. */
+    private final Set<String> descCols;
+
+    /** Indexes. */
+    private final Map<String, Map<String, Boolean>> idxs;
+
+    /**
+     * Default columns.
+     *
+     * @param schema Schema name.
+     * @param tbl Table name.
+     * @param cols Columns.
+     * @param ascCols Columns in ascending order.
+     * @param descCols Columns in descending order.
+     * @param idxs Indexes;
+     */
+    public DbTable(String schema, String tbl, Collection<DbColumn> cols, 
Set<String> ascCols, Set<String> descCols,
+        Map<String, Map<String, Boolean>> idxs) {
+        this.schema = schema;
+        this.tbl = tbl;
+        this.cols = cols;
+        this.ascCols = ascCols;
+        this.descCols = descCols;
+        this.idxs = idxs;
+    }
+
+    /**
+     * @return Schema name.
+     */
+    public String schema() {
+        return schema;
+    }
+
+    /**
+     * @return Table name.
+     */
+    public String table() {
+        return tbl;
+    }
+
+    /**
+     * @return Columns.
+     */
+    public Collection<DbColumn> columns() {
+        return cols;
+    }
+
+    /**
+     * @return Fields in ascending order
+     */
+    public Set<String> ascendingColumns() {
+        return ascCols;
+    }
+
+    /**
+     * @return Fields in descending order
+     */
+    public Set<String> descendingColumns() {
+        return descCols;
+    }
+
+    /**
+     * @return Indexes.
+     */
+    public Map<String, Map<String, Boolean>> indexes() {
+        return idxs;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/9cf45b43/modules/schema-import/src/main/java/org/apache/ignite/schema/parser/dialect/DB2MetadataDialect.java
----------------------------------------------------------------------
diff --git 
a/modules/schema-import/src/main/java/org/apache/ignite/schema/parser/dialect/DB2MetadataDialect.java
 
b/modules/schema-import/src/main/java/org/apache/ignite/schema/parser/dialect/DB2MetadataDialect.java
new file mode 100644
index 0000000..17eb8b2
--- /dev/null
+++ 
b/modules/schema-import/src/main/java/org/apache/ignite/schema/parser/dialect/DB2MetadataDialect.java
@@ -0,0 +1,30 @@
+/*
+ * 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.parser.dialect;
+
+import java.util.*;
+
+/**
+ * DB2 specific metadata dialect.
+ */
+public class DB2MetadataDialect extends JdbcMetadataDialect {
+    /** {@inheritDoc} */
+    @Override public Set<String> systemSchemas() {
+        return new HashSet<>(Arrays.asList("SYSIBM", "SYSCAT", "SYSSTAT", 
"SYSTOOLS"));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/9cf45b43/modules/schema-import/src/main/java/org/apache/ignite/schema/parser/dialect/DatabaseMetadataDialect.java
----------------------------------------------------------------------
diff --git 
a/modules/schema-import/src/main/java/org/apache/ignite/schema/parser/dialect/DatabaseMetadataDialect.java
 
b/modules/schema-import/src/main/java/org/apache/ignite/schema/parser/dialect/DatabaseMetadataDialect.java
new file mode 100644
index 0000000..0d17567
--- /dev/null
+++ 
b/modules/schema-import/src/main/java/org/apache/ignite/schema/parser/dialect/DatabaseMetadataDialect.java
@@ -0,0 +1,78 @@
+/*
+ * 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.parser.dialect;
+
+import org.apache.ignite.schema.parser.*;
+
+import java.sql.*;
+import java.util.*;
+
+/**
+ * Base class for database metadata dialect.
+ */
+public abstract class DatabaseMetadataDialect {
+    /**
+     * Gets tables from database.
+     *
+     * @param conn Database connection.
+     * @param tblsOnly If {@code true} then gets only tables otherwise gets 
tables and views.
+     * @return Collection of table descriptors.
+     * @throws SQLException If failed to get tables.
+     */
+    public abstract Collection<DbTable> tables(Connection conn, boolean 
tblsOnly) throws SQLException;
+
+    /**
+     * @return Collection of database system schemas.
+     */
+    public Set<String> systemSchemas() {
+        return Collections.singleton("INFORMATION_SCHEMA");
+    }
+
+    /**
+     * Create table descriptor.
+     *
+     * @param schema Schema name.
+     * @param tbl Table name.
+     * @param cols Table columns.
+     * @param idxs Table indexes.
+     * @return New {@code DbTable} instance.
+     */
+    protected DbTable table(String schema, String tbl, Collection<DbColumn> 
cols, Map<String, Map<String, Boolean>>idxs) {
+        Set<String> ascCols = new HashSet<>();
+
+        Set<String> descCols = new HashSet<>();
+
+        for (Map<String, Boolean> idx : idxs.values()) {
+            if (idx.size() == 1)
+                for (Map.Entry<String, Boolean> idxCol : idx.entrySet()) {
+                    String colName = idxCol.getKey();
+
+                    Boolean desc = idxCol.getValue();
+
+                    if (desc != null) {
+                        if (desc)
+                            descCols.add(colName);
+                        else
+                            ascCols.add(colName);
+                    }
+                }
+        }
+
+        return new DbTable(schema, tbl, cols, ascCols, descCols, idxs);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/9cf45b43/modules/schema-import/src/main/java/org/apache/ignite/schema/parser/dialect/JdbcMetadataDialect.java
----------------------------------------------------------------------
diff --git 
a/modules/schema-import/src/main/java/org/apache/ignite/schema/parser/dialect/JdbcMetadataDialect.java
 
b/modules/schema-import/src/main/java/org/apache/ignite/schema/parser/dialect/JdbcMetadataDialect.java
new file mode 100644
index 0000000..ab65e7a
--- /dev/null
+++ 
b/modules/schema-import/src/main/java/org/apache/ignite/schema/parser/dialect/JdbcMetadataDialect.java
@@ -0,0 +1,141 @@
+/*
+ * 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.parser.dialect;
+
+import org.apache.ignite.schema.parser.*;
+
+import java.sql.*;
+import java.util.*;
+
+/**
+ * Metadata dialect that uses standard JDBC for reading metadata.
+ */
+public class JdbcMetadataDialect extends DatabaseMetadataDialect {
+    /** */
+    private static final String[] TABLES_ONLY = {"TABLE"};
+
+    /** */
+    private static final String[] TABLES_AND_VIEWS = {"TABLE", "VIEW"};
+
+    /** Schema catalog index. */
+    private static final int TBL_CATALOG_IDX = 1;
+
+    /** Schema name index. */
+    private static final int TBL_SCHEMA_IDX = 2;
+
+    /** Table name index. */
+    private static final int TBL_NAME_IDX = 3;
+
+    /** Primary key column name index. */
+    private static final int PK_COL_NAME_IDX = 4;
+
+    /** Column name index. */
+    private static final int COL_NAME_IDX = 4;
+
+    /** Column data type index. */
+    private static final int COL_DATA_TYPE_IDX = 5;
+
+    /** Column nullable index. */
+    private static final int COL_NULLABLE_IDX = 11;
+
+    /** Index name index. */
+    private static final int IDX_NAME_IDX = 6;
+
+    /** Index column name index. */
+    private static final int IDX_COL_NAME_IDX = 9;
+
+    /** Index column descend index. */
+    private static final int IDX_ASC_OR_DESC_IDX = 10;
+
+    /** {@inheritDoc} */
+    @Override public Collection<DbTable> tables(Connection conn, boolean 
tblsOnly) throws SQLException {
+        DatabaseMetaData dbMeta = conn.getMetaData();
+
+        Set<String> sys = systemSchemas();
+
+        Collection<DbTable> tbls = new ArrayList<>();
+
+        try (ResultSet tblsRs = dbMeta.getTables(null, null, "%",
+            tblsOnly ? TABLES_ONLY : TABLES_AND_VIEWS)) {
+            while (tblsRs.next()) {
+                String tblCatalog = tblsRs.getString(TBL_CATALOG_IDX);
+                String tblSchema = tblsRs.getString(TBL_SCHEMA_IDX);
+                String tblName = tblsRs.getString(TBL_NAME_IDX);
+
+                // In case of MySql we should use catalog.
+                String schema = tblSchema != null ? tblSchema : tblCatalog;
+
+                // Skip system schemas.
+                if (sys.contains(schema))
+                    continue;
+
+                Set<String> pkCols = new HashSet<>();
+
+                try (ResultSet pkRs = dbMeta.getPrimaryKeys(tblCatalog, 
tblSchema, tblName)) {
+                    while (pkRs.next())
+                        pkCols.add(pkRs.getString(PK_COL_NAME_IDX));
+                }
+
+                List<DbColumn> cols = new ArrayList<>();
+
+                try (ResultSet colsRs = dbMeta.getColumns(tblCatalog, 
tblSchema, tblName, null)) {
+                    while (colsRs.next()) {
+                        String colName = colsRs.getString(COL_NAME_IDX);
+
+                        cols.add(new DbColumn(
+                            colName,
+                            colsRs.getInt(COL_DATA_TYPE_IDX),
+                            pkCols.contains(colName),
+                            colsRs.getInt(COL_NULLABLE_IDX) == 
DatabaseMetaData.columnNullable));
+                    }
+                }
+
+                Map<String, Map<String, Boolean>> idxs = new LinkedHashMap<>();
+
+                try (ResultSet idxRs = dbMeta.getIndexInfo(tblCatalog, 
tblSchema, tblName, false, true)) {
+                    while (idxRs.next()) {
+                        String idxName = idxRs.getString(IDX_NAME_IDX);
+
+                        String colName = idxRs.getString(IDX_COL_NAME_IDX);
+
+                        if (idxName == null || colName == null)
+                            continue;
+
+                        Map<String, Boolean> idx = idxs.get(idxName);
+
+                        if (idx == null) {
+                            idx = new LinkedHashMap<>();
+
+                            idxs.put(idxName, idx);
+                        }
+
+                        String askOrDesc = 
idxRs.getString(IDX_ASC_OR_DESC_IDX);
+
+                        Boolean desc = askOrDesc != null ? 
"D".equals(askOrDesc) : null;
+
+                        idx.put(colName, desc);
+                    }
+                }
+
+                tbls.add(table(schema, tblName, cols, idxs));
+            }
+        }
+
+        return tbls;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/9cf45b43/modules/schema-import/src/main/java/org/apache/ignite/schema/parser/dialect/OracleMetadataDialect.java
----------------------------------------------------------------------
diff --git 
a/modules/schema-import/src/main/java/org/apache/ignite/schema/parser/dialect/OracleMetadataDialect.java
 
b/modules/schema-import/src/main/java/org/apache/ignite/schema/parser/dialect/OracleMetadataDialect.java
new file mode 100644
index 0000000..6b16042
--- /dev/null
+++ 
b/modules/schema-import/src/main/java/org/apache/ignite/schema/parser/dialect/OracleMetadataDialect.java
@@ -0,0 +1,281 @@
+/*
+ * 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.parser.dialect;
+
+import org.apache.ignite.schema.parser.*;
+
+import java.sql.*;
+import java.util.*;
+
+import static java.sql.Types.*;
+
+/**
+ * Oracle specific metadata dialect.
+ */
+public class OracleMetadataDialect extends DatabaseMetadataDialect {
+    /** SQL to get columns metadata. */
+    private static final String SQL_COLUMNS = "SELECT a.owner, a.table_name, 
a.column_name, a.nullable," +
+        " a.data_type, a.data_precision, a.data_scale " +
+        "FROM all_tab_columns a %s" +
+        " WHERE a.owner = '%s'" +
+        " ORDER BY a.owner, a.table_name, a.column_id";
+
+    /** SQL to get list of PRIMARY KEYS columns. */
+    private static final String SQL_PRIMARY_KEYS = "SELECT b.column_name" +
+        " FROM all_constraints a" +
+        "  INNER JOIN all_cons_columns b ON a.owner = b.owner AND 
a.constraint_name = b.constraint_name" +
+        " WHERE a.owner = ? and a.table_name = ? AND a.constraint_type = 'P'";
+
+    /** SQL to get indexes metadata. */
+    private static final String SQL_INDEXES = "select i.index_name, 
u.column_expression, i.column_name, i.descend" +
+        " FROM all_ind_columns i" +
+        " LEFT JOIN user_ind_expressions u on u.index_name = i.index_name and 
i.table_name = u.table_name" +
+        " WHERE i.index_owner = ? and i.table_name = ?" +
+        " ORDER BY i.index_name, i.column_position";
+
+    /** Owner index. */
+    private static final int OWNER_IDX = 1;
+
+    /** Table name index. */
+    private static final int TBL_NAME_IDX = 2;
+
+    /** Column name index. */
+    private static final int COL_NAME_IDX = 3;
+
+    /** Nullable index. */
+    private static final int NULLABLE_IDX = 4;
+
+    /** Data type index. */
+    private static final int DATA_TYPE_IDX = 5;
+
+    /** Numeric precision index. */
+    private static final int DATA_PRECISION_IDX = 6;
+
+    /** Numeric scale index. */
+    private static final int DATA_SCALE_IDX = 7;
+
+    /** Index name index. */
+    private static final int IDX_NAME_IDX = 1;
+
+    /** Index name index. */
+    private static final int IDX_EXPR_IDX = 2;
+
+    /** Index column name index. */
+    private static final int IDX_COL_NAME_IDX = 3;
+
+    /** Index column sort order index. */
+    private static final int IDX_COL_DESCEND_IDX = 4;
+
+    /**
+     * @param rs Result set with column type metadata from Oracle database.
+     * @return JDBC type.
+     * @throws SQLException If failed to decode type.
+     */
+    private int decodeType(ResultSet rs) throws SQLException {
+        switch (rs.getString(DATA_TYPE_IDX)) {
+            case "CHAR":
+            case "NCHAR":
+                return CHAR;
+
+            case "VARCHAR2":
+            case "NVARCHAR2":
+                return VARCHAR;
+
+            case "LONG":
+                return LONGVARCHAR;
+
+            case "LONG RAW":
+                return LONGVARBINARY;
+
+            case "FLOAT":
+                return FLOAT;
+
+            case "NUMBER":
+                int precision = rs.getInt(DATA_PRECISION_IDX);
+                int scale = rs.getInt(DATA_SCALE_IDX);
+
+                if (scale > 0) {
+                    if (scale < 4 && precision < 19)
+                        return FLOAT;
+
+                    if (scale > 4 || precision > 19)
+                        return DOUBLE;
+
+                    return NUMERIC;
+                }
+                else {
+                    if (precision < 1)
+                        return INTEGER;
+
+                    if (precision < 2)
+                        return BOOLEAN;
+
+                    if (precision < 4)
+                        return TINYINT;
+
+                    if (precision < 6)
+                        return SMALLINT;
+
+                    if (precision < 11)
+                        return INTEGER;
+
+                    if (precision < 20)
+                        return BIGINT;
+
+                    return NUMERIC;
+                }
+
+            case "DATE":
+                return DATE;
+
+            case "TIMESTAMP":
+                return TIMESTAMP;
+
+            case "BFILE":
+            case "BLOB":
+                return BLOB;
+
+            case "CLOB":
+            case "NCLOB":
+            case "XMLTYPE":
+                return CLOB;
+        }
+
+        return OTHER;
+    }
+
+    /**
+     * Retrieve primary key columns.
+     *
+     * @param stmt Prepared SQL statement to execute.
+     * @param owner DB owner.
+     * @param tbl Table name.
+     * @return Primary key columns.
+     * @throws SQLException If failed to retrieve primary key columns.
+     */
+    private Set<String> primaryKeys(PreparedStatement stmt, String owner, 
String tbl) throws SQLException {
+        Set<String> pkCols = new HashSet<>();
+
+        stmt.setString(1, owner);
+        stmt.setString(2, tbl);
+
+        try (ResultSet pkRs = stmt.executeQuery()) {
+            while(pkRs.next())
+                pkCols.add(pkRs.getString(1));
+        }
+
+        return pkCols;
+    }
+
+    /**
+     * Retrieve index columns.
+     *
+     * @param stmt Prepared SQL statement to execute.
+     * @param owner DB owner.
+     * @param tbl Table name.
+     * @return Index columns.
+     * @throws SQLException If failed to retrieve indexe columns.
+     */
+    private Map<String, Map<String, Boolean>> indexes(PreparedStatement stmt, 
String owner, String tbl)
+        throws SQLException {
+        Map<String, Map<String, Boolean>> idxs = new LinkedHashMap<>();
+
+        stmt.setString(1, owner);
+        stmt.setString(2, tbl);
+
+        try (ResultSet idxsRs = stmt.executeQuery()) {
+            while (idxsRs.next()) {
+                String idxName = idxsRs.getString(IDX_NAME_IDX);
+
+                Map<String, Boolean> idx = idxs.get(idxName);
+
+                if (idx == null) {
+                    idx = new LinkedHashMap<>();
+
+                    idxs.put(idxName, idx);
+                }
+
+                String expr = idxsRs.getString(IDX_EXPR_IDX);
+
+                String col = expr == null ? idxsRs.getString(IDX_COL_NAME_IDX) 
: expr.replaceAll("\"", "");
+
+                idx.put(col, 
"DESC".equals(idxsRs.getString(IDX_COL_DESCEND_IDX)));
+            }
+        }
+
+        return idxs;
+    }
+
+    /** {@inheritDoc} */
+    @Override public Collection<DbTable> tables(Connection conn, boolean 
tblsOnly) throws SQLException {
+        Collection<DbTable> tbls = new ArrayList<>();
+
+        PreparedStatement pkStmt = conn.prepareStatement(SQL_PRIMARY_KEYS);
+
+        PreparedStatement idxStmt = conn.prepareStatement(SQL_INDEXES);
+
+        try (Statement colsStmt = conn.createStatement()) {
+            Collection<DbColumn> cols = new ArrayList<>();
+
+            Set<String> pkCols = Collections.emptySet();
+            Map<String, Map<String, Boolean>> idxs = Collections.emptyMap();
+
+            String user = conn.getMetaData().getUserName().toUpperCase();
+
+            String sql = String.format(SQL_COLUMNS,
+                tblsOnly ? "INNER JOIN all_tables b on a.table_name = 
b.table_name" : "", user);
+
+            try (ResultSet colsRs = colsStmt.executeQuery(sql)) {
+                String prevSchema = "";
+                String prevTbl = "";
+
+                boolean first = true;
+
+                while (colsRs.next()) {
+                    String owner = colsRs.getString(OWNER_IDX);
+                    String tbl = colsRs.getString(TBL_NAME_IDX);
+
+                    boolean changed = !owner.equals(prevSchema) || 
!tbl.equals(prevTbl);
+
+                    if (changed) {
+                        if (first)
+                            first = false;
+                        else
+                            tbls.add(table(prevSchema, prevTbl, cols, idxs));
+
+                        prevSchema = owner;
+                        prevTbl = tbl;
+                        cols = new ArrayList<>();
+                        pkCols = primaryKeys(pkStmt, owner, tbl);
+                        idxs = indexes(idxStmt, owner, tbl);
+                    }
+
+                    String colName = colsRs.getString(COL_NAME_IDX);
+
+                    cols.add(new DbColumn(colName, decodeType(colsRs), 
pkCols.contains(colName),
+                        !"N".equals(colsRs.getString(NULLABLE_IDX))));
+                }
+
+                if (!cols.isEmpty())
+                    tbls.add(table(prevSchema, prevTbl, cols, idxs));
+            }
+        }
+
+        return tbls;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/9cf45b43/modules/schema-import/src/main/java/org/apache/ignite/schema/ui/ConfirmCallable.java
----------------------------------------------------------------------
diff --git 
a/modules/schema-import/src/main/java/org/apache/ignite/schema/ui/ConfirmCallable.java
 
b/modules/schema-import/src/main/java/org/apache/ignite/schema/ui/ConfirmCallable.java
new file mode 100644
index 0000000..3990496
--- /dev/null
+++ 
b/modules/schema-import/src/main/java/org/apache/ignite/schema/ui/ConfirmCallable.java
@@ -0,0 +1,81 @@
+/*
+ * 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.application.*;
+import javafx.stage.*;
+
+import java.util.concurrent.*;
+
+import static org.apache.ignite.schema.ui.MessageBox.Result.*;
+
+/**
+ * Callable to ask user for confirmation from non EDT thread.
+ */
+public class ConfirmCallable implements Callable<MessageBox.Result> {
+    /** Owner window. */
+    private final Stage owner;
+
+    /** Message template. */
+    private final String template;
+
+    /** Message to show in confirmation dialog. */
+    private String msg;
+
+    /** User choice. */
+    private MessageBox.Result choice = NO;
+
+    /**
+     * @param owner Owner window.
+     * @param template Message template.
+     */
+    public ConfirmCallable(Stage owner, String template) {
+        this.owner = owner;
+        this.template = template;
+    }
+
+    /** {@inheritDoc} */
+    @Override public MessageBox.Result call() throws Exception {
+        choice = MessageBox.confirmRememberChoiceDialog(owner, 
String.format(template, msg));
+
+        return choice;
+    }
+
+    /**
+     * Execute confirmation in EDT thread.
+     *
+     * @return Confirm result.
+     */
+    public MessageBox.Result confirm(String msg) {
+        this.msg = msg;
+
+        if (choice == YES_TO_ALL || choice == NO_TO_ALL)
+            return choice;
+
+        FutureTask<MessageBox.Result> fut = new FutureTask<>(this);
+
+        Platform.runLater(fut);
+
+        try {
+            return fut.get();
+        }
+        catch (Exception ignored) {
+            return NO;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/9cf45b43/modules/schema-import/src/main/java/org/apache/ignite/schema/ui/Controls.java
----------------------------------------------------------------------
diff --git 
a/modules/schema-import/src/main/java/org/apache/ignite/schema/ui/Controls.java 
b/modules/schema-import/src/main/java/org/apache/ignite/schema/ui/Controls.java
new file mode 100644
index 0000000..e270edb
--- /dev/null
+++ 
b/modules/schema-import/src/main/java/org/apache/ignite/schema/ui/Controls.java
@@ -0,0 +1,661 @@
+/*
+ * 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 com.sun.javafx.scene.control.skin.*;
+import javafx.application.*;
+import javafx.beans.value.*;
+import javafx.collections.*;
+import javafx.event.*;
+import javafx.geometry.*;
+import javafx.scene.*;
+import javafx.scene.control.*;
+import javafx.scene.control.cell.*;
+import javafx.scene.image.*;
+import javafx.scene.input.*;
+import javafx.scene.layout.*;
+import javafx.scene.text.*;
+import javafx.util.*;
+
+/**
+ * Utility class to create controls.
+ */
+public class Controls {
+    /** */
+    public static final Insets DFLT_PADDING = new Insets(10, 10, 10, 10);
+
+    /**
+     * Create scene with predefined style.
+     *
+     * @param root The root node of the scene graph.
+     * @return New {@code Scene} instance.
+     */
+    public static Scene scene(Parent root) {
+        Scene scene = new Scene(root);
+
+        scene.getStylesheets().add("media/style.css");
+
+        return scene;
+    }
+
+    /**
+     * Create grid pane with default padding.
+     *
+     * @param top Top padding
+     * @param right Right padding.
+     * @param bottom Bottom padding.
+     * @param left Left padding.
+     * @return New {@code GridPaneEx} instance.
+     */
+    public static GridPaneEx paneEx(double top, double right, double bottom, 
double left) {
+        GridPaneEx paneEx = new GridPaneEx();
+
+        paneEx.setPadding(new Insets(top, right, bottom, left));
+
+        return paneEx;
+    }
+
+    /**
+     * Create new {@code HBox} with default padding.
+     *
+     * @param spacing Amount of horizontal space between each child.
+     * @param dfltPadding If {@code true} than set default padding for pane.
+     * @return New {@code HBox} instance.
+     */
+    public static HBox hBox(int spacing, boolean dfltPadding) {
+        HBox hb = new HBox(spacing);
+
+        if (dfltPadding)
+            hb.setPadding(DFLT_PADDING);
+
+        return hb;
+    }
+
+    /**
+     * Create new {@code HBox} with default padding and add controls.
+     *
+     * @param spacing Amount of horizontal space between each child.
+     * @param dfltPadding If {@code true} than set default padding for pane.
+     * @param controls Controls to add.
+     * @return New {@code HBox} instance.
+     */
+    public static HBox hBox(int spacing, boolean dfltPadding, Node... 
controls) {
+        HBox hb = hBox(spacing, dfltPadding);
+
+        hb.getChildren().addAll(controls);
+
+        return hb;
+    }
+
+    /**
+     * Create new {@code VBox} with default padding.
+     *
+     * @param spacing Amount of horizontal space between each child.
+     * @return New {@code VBox} instance.
+     */
+    public static VBox vBox(int spacing) {
+        VBox vb = new VBox(spacing);
+
+        vb.setPadding(DFLT_PADDING);
+
+        return vb;
+    }
+
+    /**
+     * Create new {@code VBox} with default padding and add controls.
+     *
+     * @param spacing Amount of horizontal space between each child.
+     * @param controls Controls to add.
+     * @return New {@code VBox} instance.
+     */
+    public static VBox vBox(int spacing, Node... controls) {
+        VBox vb = vBox(spacing);
+
+        vb.getChildren().addAll(controls);
+
+        return vb;
+    }
+
+    /**
+     * Create stack pane.
+     *
+     * @param controls Controls to add.
+     * @return New {@code StackPane} instance.
+     */
+    public static StackPane stackPane(Node... controls) {
+        StackPane sp = new StackPane();
+
+        sp.getChildren().addAll(controls);
+
+        return sp;
+    }
+
+    /**
+     * Create border pane.
+     *
+     * @param top Optional top control.
+     * @param center Optional center control.
+     * @param bottom Optional bottom control.
+     * @param left Optional left control.
+     * @param right Optional right control.
+     * @return New {@code BorderPane} instance.
+     */
+    public static BorderPane borderPane(Node top, Node center, Node bottom, 
Node left, Node right) {
+        BorderPane bp = new BorderPane();
+
+        bp.setTop(top);
+        bp.setCenter(center);
+        bp.setBottom(bottom);
+        bp.setLeft(left);
+        bp.setRight(right);
+
+        return bp;
+    }
+
+    /**
+     * Sets control tooltip if needed.
+     *
+     * @param ctrl Target control.
+     * @param tip Tooltip text.
+     * @return Control itself for method chaining.
+     */
+    public static <T extends Control> T tooltip(T ctrl, String tip) {
+        if (!tip.isEmpty())
+            ctrl.setTooltip(new Tooltip(tip));
+
+        return ctrl;
+    }
+
+    /**
+     * Create label.
+     *
+     * @param text Label text.
+     * @return New {@code Label} instance.
+     */
+    public static Label label(String text) {
+        return new Label(text);
+    }
+
+    /**
+     * Create button with text only.
+     *
+     * @param text Button text.
+     * @param tip Tooltip text.
+     * @param onAct Button action.
+     * @return New {@code Button} instance.
+     */
+    public static Button button(String text, String tip, 
EventHandler<ActionEvent> onAct) {
+        Button btn = new Button(text);
+
+        btn.setOnAction(onAct);
+
+        tooltip(btn, tip);
+
+        return btn;
+    }
+
+    /**
+     * Create button with icon only.
+     *
+     * @param icon Button icon.
+     * @param tip Tooltip text.
+     * @param onAct Button action.
+     * @return New {@code Button} instance.
+     */
+    public static Button button(ImageView icon, String tip, 
EventHandler<ActionEvent> onAct) {
+        Button btn = new Button();
+
+        btn.setGraphic(icon);
+        btn.setOnAction(onAct);
+
+        tooltip(btn, tip);
+
+        return btn;
+    }
+
+    /**
+     * Create pane with buttons.
+     *
+     * @param alignment Alignment of buttons.
+     * @param dfltPadding If {@code true} than set default padding for pane.
+     * @param btns Buttons that will be added to pane.
+     * @return New {@code HBox} instance with buttons.
+     */
+    public static Pane buttonsPane(Pos alignment, boolean dfltPadding, 
Button... btns) {
+        HBox hb = hBox(10, dfltPadding, btns);
+
+        hb.setAlignment(alignment);
+
+        return hb;
+    }
+
+    /**
+     * Create checkbox.
+     *
+     * @param text Checkbox text.
+     * @param tip Tooltip tex.
+     * @param sel Checkbox selected state.
+     * @return New {@code Checkbox} instance.
+     */
+    public static CheckBox checkBox(String text, String tip, boolean sel) {
+        CheckBox ch = new CheckBox(text);
+
+        ch.setSelected(sel);
+
+        tooltip(ch, tip);
+
+        return ch;
+    }
+
+    /**
+     * Create text field.
+     *
+     * @param tip Tooltip text.
+     * @return New {@code TextField} instance.
+     */
+    public static TextField textField(String tip) {
+        TextField tf = new TextField();
+
+        tooltip(tf, tip);
+
+        return tf;
+    }
+
+    /**
+     * Create static text.
+     *
+     * @param text Text to show.
+     * @param wrap Text wrapping width.
+     * @return New {@code Text} instance.
+     */
+    public static Text text(String text, int wrap) {
+        Text t = new Text(text);
+
+        t.setFont(new Font(14));
+
+        if (wrap > 0)
+            t.setWrappingWidth(wrap);
+
+        return t;
+    }
+
+    /**
+     * Create password field.
+     *
+     * @param tip Tooltip text.
+     * @return New {@code PasswordField} instance.
+     */
+    public static PasswordField passwordField(String tip) {
+        PasswordField pf = new PasswordField();
+
+        tooltip(pf, tip);
+
+        return pf;
+    }
+
+    /**
+     * Create combo box.
+     *
+     * @param tip Tooltip text.
+     * @param items Combo box items.
+     * @return New {@code ComboBox} instance.
+     */
+    public static <T> ComboBox<T> comboBox(String tip, T... items) {
+        ComboBox<T> cb = new 
ComboBox<>(FXCollections.observableArrayList(items));
+
+        cb.setMaxWidth(Double.MAX_VALUE);
+        cb.getSelectionModel().select(0);
+
+        tooltip(cb, tip);
+
+        return cb;
+    }
+
+    /**
+     * Create split pane for provided nodes.
+     *
+     * @param node1 First node.
+     * @param node2 Second node.
+     * @param pos Initial divider position.
+     * @return New {@code SplitPane} instance.
+     */
+    public static SplitPane splitPane(Node node1, Node node2, double pos) {
+        SplitPane sp = new SplitPane();
+
+        sp.setOrientation(Orientation.VERTICAL);
+        sp.getItems().addAll(node1, node2);
+        sp.setDividerPosition(0, pos);
+
+        return sp;
+    }
+
+    /**
+     * Create titled pane.
+     *
+     * @param title Title.
+     * @param node Node.
+     * @return New {@code TitledPane} instance.
+     */
+    public static TitledPane titledPane(String title, Node node) {
+        TitledPane tp = new TitledPane(title, node);
+
+        tp.setExpanded(false);
+
+        return tp;
+    }
+
+    /**
+     * Create table column.
+     *
+     * @param colName Column name to display.
+     * @param propName Property name column is bound to.
+     * @param tip Column tooltip text.
+     * @param minWidth The minimum width column is permitted to be resized to.
+     * @param maxWidth The maximum width column is permitted to be resized to.
+     * @param editable {@code true} if column is editable.
+     * @return New {@code TableColumn} instance.
+     */
+    private static <S, T> TableColumn<S, T> tableColumn(String colName, String 
propName, String tip,
+        int minWidth, int maxWidth, boolean editable) {
+        TableColumn<S, T> col = new TableColumn<>();
+
+        col.setGraphic(tooltip(new Label(colName), tip));
+
+        col.setSortable(false);
+
+        if (minWidth > 0)
+            col.setMinWidth(minWidth);
+
+        if (maxWidth > 0)
+            col.setMaxWidth(maxWidth);
+
+        col.setCellValueFactory(new PropertyValueFactory<S, T>(propName));
+
+        col.setEditable(editable);
+
+        return col;
+    }
+
+    /**
+     * Create table column.
+     *
+     * @param colName Column name to display.
+     * @param propName Property name column is bound to.
+     * @param tip Column tooltip text.
+     * @return New {@code TableColumn} instance.
+     */
+    public static <S, T> TableColumn<S, T> tableColumn(String colName, String 
propName, String tip) {
+        return tableColumn(colName, propName, tip, 100, 0, false);
+    }
+
+    /**
+     * Create table column.
+     *
+     * @param colName Column name to display.
+     * @param propName Property name column is bound to.
+     * @param tip Column tooltip text.
+     * @param cellFactory Custom cell factory.
+     * @return New {@code TableColumn} instance.
+     */
+    public static <S, T> TableColumn<S, T> customColumn(String colName, String 
propName, String tip,
+        Callback<TableColumn<S, T>, TableCell<S, T>> cellFactory) {
+        TableColumn<S, T> col = tableColumn(colName, propName, tip, 100, 0, 
true);
+
+        col.setCellFactory(cellFactory);
+
+        return col;
+    }
+
+    /**
+     * Create editable boolean table column.
+     *
+     * @param colName Column name to display.
+     * @param propName Property name column is bound to.
+     * @param tip Column tooltip text.
+     * @return New {@code TableColumn} instance.
+     */
+    public static <S> TableColumn<S, Boolean> booleanColumn(String colName, 
String propName, String tip) {
+        TableColumn<S, Boolean> col = tableColumn(colName, propName, tip, 50, 
50, true);
+
+        col.setCellFactory(CheckBoxTableCellEx.<S>cellFactory());
+
+        return col;
+
+    }
+
+    /**
+     * Create editable text table column.
+     *
+     * @param colName Column name to display.
+     * @param propName Property name column is bound to.
+     * @param tip Column tooltip text.
+     * @return New {@code TableColumn} instance.
+     */
+    public static <S> TableColumn<S, String> textColumn(String colName, String 
propName, String tip,
+        TextColumnValidator<S> validator) {
+        TableColumn<S, String> col = tableColumn(colName, propName, tip, 100, 
0, true);
+
+        col.setCellFactory(TextFieldTableCellEx.cellFactory(validator));
+
+        return col;
+    }
+
+    /**
+     * Create table view.
+     *
+     * @param placeholder Text to show if table model is empty.
+     * @param cols Columns to add.
+     * @return New {@code TableView} instance.
+     */
+    public static <S> TableView<S> tableView(String placeholder, 
TableColumn<S, ?>... cols) {
+        TableView<S> tbl = new TableView<>();
+
+        tbl.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
+        tbl.setEditable(true);
+        tbl.setMinHeight(70);
+        tbl.setPlaceholder(text(placeholder, 0));
+
+        tbl.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
+
+        tbl.getColumns().addAll(cols);
+
+        return tbl;
+    }
+
+    /**
+     * Create progress indicator.
+     *
+     * @param sz Indicator diameter.
+     * @return New {@code ProgressIndicator} instance.
+     */
+    public static ProgressIndicator progressIndicator(int sz) {
+        ProgressIndicator pi = new ProgressIndicator();
+
+        pi.setMaxWidth(sz);
+        pi.setMaxHeight(sz);
+
+        return pi;
+    }
+
+    /**
+     * Create image view.
+     *
+     * @param imgFileName Image filename.
+     * @return New {@code ImageView} instance.
+     */
+    public static ImageView imageView(String imgFileName, int sz) {
+        return new ImageView(image(imgFileName, sz));
+    }
+
+    /**
+     * Gets image by its filename.
+     *
+     * @param imgFileName Image filename.
+     * @return Loaded image.
+     */
+    public static Image image(String imgFileName, int sz) {
+        return new Image(Controls.class.getClassLoader()
+            .getResourceAsStream(String.format("media/%1$s_%2$dx%2$d.png", 
imgFileName, sz)));
+    }
+
+    /**
+     * Customized checkbox.
+     */
+    private static class CheckBoxTableCellEx<S> extends CheckBoxTableCell<S, 
Boolean> {
+        /** Creates a ComboBox cell factory for use in TableColumn controls. */
+        public static <S> Callback<TableColumn<S, Boolean>, TableCell<S, 
Boolean>> cellFactory() {
+            return new Callback<TableColumn<S, Boolean>, TableCell<S, 
Boolean>>() {
+                @Override public TableCell<S, Boolean> call(TableColumn<S, 
Boolean> col) {
+                    return new CheckBoxTableCellEx<>();
+                }
+            };
+        }
+
+        /**
+         * Default constructor.
+         */
+        private CheckBoxTableCellEx() {
+            setAlignment(Pos.CENTER);
+        }
+    }
+
+    /**
+     * Special table text field cell that commit its content on focus lost.
+     */
+    private static class TextFieldTableCellEx<S> extends TextFieldTableCell<S, 
String> {
+        /** */
+        private final TextColumnValidator<S> validator;
+        /** */
+        private boolean cancelling;
+        /** */
+        private boolean hardCancel;
+        /** */
+        private String curTxt = "";
+
+        /** Row value. */
+        private S rowVal;
+
+        /** Create cell factory. */
+        public static <S> Callback<TableColumn<S, String>, TableCell<S, 
String>>
+        cellFactory(final TextColumnValidator<S> validator) {
+            return new Callback<TableColumn<S, String>, TableCell<S, 
String>>() {
+                @Override public TableCell<S, String> call(TableColumn<S, 
String> col) {
+                    return new TextFieldTableCellEx<>(validator);
+                }
+            };
+        }
+
+        /**
+         * Text field cell constructor.
+         *
+         * @param validator Input text validator.
+         */
+        private TextFieldTableCellEx(TextColumnValidator<S> validator) {
+            this.validator = validator;
+        }
+
+        /** {@inheritDoc} */
+        @Override public void startEdit() {
+            String item = getItem();
+
+            if (item == null || item.isEmpty())
+                return;
+
+            super.startEdit();
+
+            rowVal = getTableView().getSelectionModel().getSelectedItem();
+
+            curTxt = "";
+
+            hardCancel = false;
+
+            Node g = getGraphic();
+
+            if (g != null) {
+                final TextField tf = (TextField)g;
+
+                tf.textProperty().addListener(new ChangeListener<String>() {
+                    @Override public void changed(ObservableValue<? extends 
String> val, String oldVal, String newVal) {
+                        curTxt = newVal;
+                    }
+                });
+
+                tf.setOnKeyPressed(new EventHandler<KeyEvent>() {
+                    @Override public void handle(KeyEvent evt) {
+                        if (KeyCode.ENTER == evt.getCode())
+                            cancelEdit();
+                        else if (KeyCode.ESCAPE == evt.getCode()) {
+                            hardCancel = true;
+
+                            cancelEdit();
+                        }
+                    }
+                });
+
+                tf.setOnKeyReleased(new EventHandler<KeyEvent>() {
+                    @Override public void handle(KeyEvent evt) {
+                        // No-op to overwrite JavaFX implementation.
+                    }
+                });
+
+                // Special hack for editable TextFieldTableCell.
+                // Cancel edit when focus lost from text field, but do not 
cancel if focus lost to VirtualFlow.
+                tf.focusedProperty().addListener(new ChangeListener<Boolean>() 
{
+                    @Override public void changed(ObservableValue<? extends 
Boolean> val, Boolean oldVal, Boolean newVal) {
+                        Node fo = getScene().getFocusOwner();
+
+                        if (!newVal) {
+                            if (fo instanceof VirtualFlow) {
+                                if (fo.getParent().getParent() != 
getTableView())
+                                    cancelEdit();
+                            }
+                            else
+                                cancelEdit();
+                        }
+                    }
+                });
+
+                Platform.runLater(new Runnable() {
+                    @Override public void run() {
+                        tf.requestFocus();
+                    }
+                });
+            }
+        }
+
+        /** {@inheritDoc} */
+        @Override public void cancelEdit() {
+            if (cancelling)
+                super.cancelEdit();
+            else
+                try {
+                    cancelling = true;
+
+                    if (hardCancel || curTxt.trim().isEmpty())
+                        super.cancelEdit();
+                    else if (validator.valid(rowVal, curTxt))
+                        commitEdit(curTxt);
+                    else
+                        super.cancelEdit();
+                }
+                finally {
+                    cancelling = false;
+                }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/9cf45b43/modules/schema-import/src/main/java/org/apache/ignite/schema/ui/GridPaneEx.java
----------------------------------------------------------------------
diff --git 
a/modules/schema-import/src/main/java/org/apache/ignite/schema/ui/GridPaneEx.java
 
b/modules/schema-import/src/main/java/org/apache/ignite/schema/ui/GridPaneEx.java
new file mode 100644
index 0000000..be1aae9
--- /dev/null
+++ 
b/modules/schema-import/src/main/java/org/apache/ignite/schema/ui/GridPaneEx.java
@@ -0,0 +1,177 @@
+/*
+ * 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.geometry.*;
+import javafx.scene.*;
+import javafx.scene.control.*;
+import javafx.scene.layout.*;
+
+/**
+ * Utility extension of {@code GridPane}.
+ */
+public class GridPaneEx extends GridPane {
+    /** Current column. */
+    private int col;
+
+    /** Current row. */
+    private int row;
+
+    /**
+     * Create pane.
+     */
+    public GridPaneEx() {
+        setAlignment(Pos.TOP_LEFT);
+        setHgap(5);
+        setVgap(10);
+    }
+
+    /**
+     * Add default column.
+     */
+    public void addColumn() {
+        getColumnConstraints().add(new ColumnConstraints());
+    }
+
+    /**
+     * Add column with constraints and horizontal grow priority for the column.
+     *
+     * @param min Column minimum size.
+     * @param pref Column preferred size.
+     * @param max Column max size.
+     * @param hgrow Column horizontal grow priority.
+     */
+    public void addColumn(double min, double pref, double max, Priority hgrow) 
{
+        ColumnConstraints cc = new ColumnConstraints(min, pref, max);
+
+        cc.setHgrow(hgrow);
+
+        getColumnConstraints().add(cc);
+    }
+
+    /**
+     * Add default row.
+     */
+    public void addRow() {
+        getRowConstraints().add(new RowConstraints());
+    }
+
+    /**
+     * Add default rows.
+     *
+     * @param n Number of rows to add.
+     */
+    public void addRows(int n) {
+        for (int i = 0; i < n; i++)
+            addRow();
+    }
+
+    /**
+     * Add row with constraints and vertical grow priority for the row.
+     *
+     * @param min Row minimum size.
+     * @param pref Row preferred size.
+     * @param max Row max size.
+     * @param vgrow Row vertical grow priority.
+     */
+    public void addRow(double min, double pref, double max, Priority vgrow) {
+        RowConstraints rc = new RowConstraints(min, pref, max);
+
+        rc.setVgrow(vgrow);
+
+        getRowConstraints().add(rc);
+    }
+
+    /**
+     * Wrap to next row.
+     */
+    public void wrap() {
+        col = 0;
+
+        row++;
+    }
+
+    /**
+     * Skip columns.
+     *
+     * @param span How many columns should be skipped.
+     */
+    public void skip(int span) {
+        add(new Label(""), span);
+    }
+
+    /**
+     * Move to next column.
+     */
+    private void nextCol(int span) {
+        col += span;
+
+        if (col >= getColumnConstraints().size())
+            wrap();
+    }
+
+    /**
+     * Add control to grid pane.
+     *
+     * @param ctrl Control to add.
+     * @param span How many columns control should take.
+     * @return Added control.
+     */
+    public <T extends Node> T add(T ctrl, int span) {
+        add(ctrl, col, row, span, 1);
+
+        nextCol(span);
+
+        return ctrl;
+    }
+
+    /**
+     * Add control to grid pane.
+     *
+     * @param ctrl Control to add.
+     * @return Added control.
+     */
+    public <T extends Node> T add(T ctrl) {
+        return add(ctrl, 1);
+    }
+
+    /**
+     * Add control with label.
+     *
+     * @param text Label text.
+     * @param ctrl Control to add.
+     * @param span How many columns control should take.
+     * @return Added control.
+     */
+    public <T extends Node> T addLabeled(String text, T ctrl, int span) {
+        add(new Label(text));
+
+        return add(ctrl, span);
+    }
+
+    /**
+     * Add control with label.
+     *
+     * @param text Label text.
+     * @param ctrl Control to add.
+     * @return Added control.
+     */
+    public <T extends Node> T addLabeled(String text, T ctrl) {
+        return addLabeled(text, ctrl, 1);
+    }
+}

Reply via email to