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


http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/410f9e5e/modules/schema-load/src/main/java/org/apache/ignite/schema/ui/GridPaneEx.java
----------------------------------------------------------------------
diff --git 
a/modules/schema-load/src/main/java/org/apache/ignite/schema/ui/GridPaneEx.java 
b/modules/schema-load/src/main/java/org/apache/ignite/schema/ui/GridPaneEx.java
new file mode 100644
index 0000000..be1aae9
--- /dev/null
+++ 
b/modules/schema-load/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);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/410f9e5e/modules/schema-load/src/main/java/org/apache/ignite/schema/ui/MessageBox.java
----------------------------------------------------------------------
diff --git 
a/modules/schema-load/src/main/java/org/apache/ignite/schema/ui/MessageBox.java 
b/modules/schema-load/src/main/java/org/apache/ignite/schema/ui/MessageBox.java
new file mode 100644
index 0000000..902bd91
--- /dev/null
+++ 
b/modules/schema-load/src/main/java/org/apache/ignite/schema/ui/MessageBox.java
@@ -0,0 +1,238 @@
+/*
+ * 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.event.*;
+import javafx.geometry.*;
+import javafx.scene.control.*;
+import javafx.scene.layout.*;
+import javafx.stage.*;
+
+import static org.apache.ignite.schema.ui.Controls.*;
+
+/**
+ * Message box functionality.
+ */
+public class MessageBox extends ModalDialog {
+    /** Message box type. */
+    private enum MessageType {
+        /** Information. */
+        INFO,
+        /** Warning. */
+        WARN,
+        /** Error. */
+        ERROR,
+        /** Confirm. */
+        CONFIRM,
+        /** Confirm with cancel option. */
+        CANCELLABLE_CONFIRM
+    }
+
+    /** Message box type. */
+    public enum Result {
+        /** Return value if YES is chosen. */
+        YES,
+        /** Return value if YES_TO_ALL is chosen. */
+        YES_TO_ALL,
+        /** Return value if NO is chosen. */
+        NO,
+        /** Return value if NO_TO_ALL is chosen. */
+        NO_TO_ALL,
+        /** Return value if CANCEL is chosen. */
+        CANCEL
+    }
+
+    /** Dialog result. */
+    private Result res = Result.CANCEL;
+
+    /**
+     * Create message box.
+     *
+     * @param owner Owner window.
+     * @param type Message box type.
+     * @param msg Message to show.
+     * @param rememberChoice If {@code true} then add &quot;Remember 
choice&quot; check box.
+     */
+    private MessageBox(Stage owner, MessageType type, String msg, final 
boolean rememberChoice) {
+        super(owner, 480, 180);
+
+        String title;
+        String iconFile;
+
+        switch (type) {
+            case WARN:
+                title = "Warning";
+                iconFile = "sign_warning";
+                break;
+
+            case ERROR:
+                title = "Error";
+                iconFile = "error";
+                break;
+
+            case CONFIRM:
+            case CANCELLABLE_CONFIRM:
+                title = "Confirmation";
+                iconFile = "question";
+                break;
+
+            default:
+                title = "Information";
+                iconFile = "information";
+                break;
+        }
+
+        setTitle(title);
+        initStyle(StageStyle.UTILITY);
+        initModality(Modality.APPLICATION_MODAL);
+        initOwner(owner);
+        setResizable(false);
+
+        GridPaneEx contentPnl = paneEx(10, 10, 0, 10);
+
+        contentPnl.addColumn();
+        contentPnl.addColumn(100, 100, Double.MAX_VALUE, Priority.ALWAYS);
+
+        contentPnl.add(hBox(0, true, imageView(iconFile, 48)));
+        contentPnl.add(text(msg, 350));
+
+        final CheckBox rememberChoiceCh = checkBox("Remember choice", "", 
false);
+
+        if (rememberChoice) {
+            contentPnl.skip(1);
+            contentPnl.add(rememberChoiceCh);
+        }
+
+        HBox btns = hBox(10, true);
+        btns.setAlignment(Pos.CENTER);
+
+        if (MessageType.CONFIRM == type || MessageType.CANCELLABLE_CONFIRM == 
type) {
+            res = Result.NO;
+
+            btns.getChildren().addAll(
+                button("Yes", "Approve the request", new 
EventHandler<ActionEvent>() {
+                    @Override public void handle(ActionEvent e) {
+                        if (rememberChoice && rememberChoiceCh.isSelected())
+                            res = Result.YES_TO_ALL;
+                        else
+                            res = Result.YES;
+
+                        close();
+                    }
+                }),
+                button("No", "Reject the request", new 
EventHandler<ActionEvent>() {
+                    @Override public void handle(ActionEvent e) {
+                        res = Result.NO;
+                        if (rememberChoice && rememberChoiceCh.isSelected())
+                            res = Result.NO_TO_ALL;
+                        else
+
+                            close();
+                    }
+                }));
+
+            if (MessageType.CANCELLABLE_CONFIRM == type)
+                btns.getChildren().addAll(
+                    button("Cancel", "Cancel the request", new 
EventHandler<ActionEvent>() {
+                        @Override public void handle(ActionEvent e) {
+                            res = Result.CANCEL;
+
+                            close();
+                        }
+                    }));
+        }
+        else
+            btns.getChildren().add(button("OK", "Close dialog", new 
EventHandler<ActionEvent>() {
+                @Override public void handle(ActionEvent e) {
+                    close();
+                }
+            }));
+
+        setScene(scene(borderPane(null, contentPnl, btns, null, null)));
+    }
+
+    /**
+     * Show message in modal dialog.
+     *
+     * @param owner Owner window.
+     * @param type Message box type.
+     * @param msg Message to show.
+     * @return Option selected by the user.
+     */
+    private static Result showDialog(Stage owner, MessageType type, String 
msg, boolean rememberChoice) {
+        MessageBox dlg = new MessageBox(owner, type, msg, rememberChoice);
+
+        dlg.showModal();
+
+        return dlg.res;
+    }
+
+    /**
+     * Show confirmation dialog.
+     *
+     * @param owner Owner window.
+     * @param msg Message to show.
+     * @return {@code true} If user confirm.
+     */
+    public static boolean confirmDialog(Stage owner, String msg) {
+        return showDialog(owner, MessageType.CONFIRM, msg, false) == 
Result.YES;
+    }
+
+    /**
+     * Show confirmation dialog.
+     *
+     * @param owner Owner window.
+     * @param msg Message to show.
+     * @return User confirmation result.
+     */
+    public static Result confirmRememberChoiceDialog(Stage owner, String msg) {
+        return showDialog(owner, MessageType.CANCELLABLE_CONFIRM, msg, true);
+    }
+
+    /**
+     * Show information dialog.
+     *
+     * @param owner Owner window.
+     * @param msg Message to show.
+     */
+    public static void informationDialog(Stage owner, String msg) {
+        showDialog(owner, MessageType.INFO, msg, false);
+    }
+
+    /**
+     * Show warning dialog.
+     *
+     * @param owner Owner window.
+     * @param msg Message to show.
+     */
+    public static void warningDialog(Stage owner, String msg) {
+        showDialog(owner, MessageType.WARN, msg, false);
+    }
+
+    /**
+     * Show error dialog.
+     *
+     * @param owner Owner window.
+     * @param msg Error message to show.
+     * @param e Optional exception to show.
+     */
+    public static void errorDialog(Stage owner, String msg, Throwable e) {
+        showDialog(owner, MessageType.ERROR,
+            (e != null && e.getMessage() != null) ? msg + "\n" + 
e.getMessage() : msg, false);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/410f9e5e/modules/schema-load/src/main/java/org/apache/ignite/schema/ui/ModalDialog.java
----------------------------------------------------------------------
diff --git 
a/modules/schema-load/src/main/java/org/apache/ignite/schema/ui/ModalDialog.java
 
b/modules/schema-load/src/main/java/org/apache/ignite/schema/ui/ModalDialog.java
new file mode 100644
index 0000000..6d0acb7
--- /dev/null
+++ 
b/modules/schema-load/src/main/java/org/apache/ignite/schema/ui/ModalDialog.java
@@ -0,0 +1,50 @@
+/*
+ * 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.stage.*;
+
+/**
+ * Abstract base modal dialog.
+ */
+public abstract class ModalDialog extends Stage {
+    /** Owner window. */
+    protected final Stage owner;
+
+    /**
+     * @param owner Owner window.
+     * @param width Window width.
+     * @param height Window height.
+     */
+    protected ModalDialog(Stage owner, int width, int height) {
+        this.owner = owner;
+
+        this.setWidth(width);
+        this.setHeight(height);
+    }
+
+    /**
+     * Show modal dialog.
+     */
+    protected void showModal() {
+        setX(owner.getX() + owner.getWidth() / 2 - getWidth() / 2);
+        setY(owner.getY() + owner.getHeight() / 2 - getHeight() / 2);
+
+        showAndWait();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/410f9e5e/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
new file mode 100644
index 0000000..ce5c188
--- /dev/null
+++ 
b/modules/schema-load/src/main/java/org/apache/ignite/schema/ui/SchemaLoadApp.java
@@ -0,0 +1,1898 @@
+/*
+ * 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.beans.property.*;
+import javafx.beans.value.*;
+import javafx.collections.*;
+import javafx.concurrent.*;
+import javafx.event.*;
+import javafx.geometry.*;
+import javafx.scene.*;
+import javafx.scene.control.*;
+import javafx.scene.control.cell.*;
+import javafx.scene.layout.*;
+import javafx.stage.*;
+import javafx.util.*;
+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.*;
+
+/**
+ * Schema load application.
+ */
+@SuppressWarnings("UnnecessaryFullyQualifiedName")
+public class SchemaLoadApp extends Application {
+    /** */
+    private Stage owner;
+
+    /** */
+    private BorderPane rootPane;
+
+    /** */
+    private Label titleLb;
+
+    /** */
+    private Button prevBtn;
+
+    /** */
+    private Button nextBtn;
+
+    /** */
+    private TextField jdbcDrvJarTf;
+
+    /** */
+    private TextField jdbcDrvClsTf;
+
+    /** */
+    private TextField jdbcUrlTf;
+
+    /** */
+    private TextField userTf;
+
+    /** */
+    private PasswordField pwdTf;
+
+    /** */
+    private GridPaneEx connPnl;
+
+    /** */
+    private StackPane connLayerPnl;
+
+    /** */
+    private TreeView<String> tree;
+
+    /** */
+    private CheckBoxTreeItem<String> rootItem;
+
+    /** */
+    private TextField keyClsTf;
+
+    /** */
+    private TextField valClsTf;
+
+    /** */
+    private TextField outFolderTf;
+
+    /** */
+    private TextField pkgTf;
+
+    /** */
+    private CheckBox pojoConstructorCh;
+
+    /** */
+    private CheckBox pojoIncludeKeysCh;
+
+    /** */
+    private CheckBox xmlSingleFileCh;
+
+    /** */
+    private CheckBox openFolderCh;
+
+    /** */
+    private TextField regexTf;
+
+    /** */
+    private TextField replaceTf;
+
+    /** */
+    private GridPaneEx genPnl;
+
+    /** */
+    private StackPane genLayerPnl;
+
+    /** */
+    private ProgressIndicator pi;
+
+    /** Map with schema - table - POJO descriptors. */
+    private Map<String, Map<String, PojoDescriptor>> schemas = 
Collections.emptyMap();
+
+    /** Map all POJO descriptors. */
+    private Collection<PojoDescriptor> pojos = Collections.emptyList();
+
+    /** Currently selected POJO. */
+    private PojoDescriptor curPojo;
+
+    /** */
+    private final Map<String, Driver> drivers = new HashMap<>();
+
+    /** */
+    private final ObservableList<PojoField> NO_DATA = 
FXCollections.emptyObservableList();
+
+    /** */
+    private final ExecutorService exec = Executors.newSingleThreadExecutor(new 
ThreadFactory() {
+        /** {@inheritDoc} */
+        @Override public Thread newThread(Runnable r) {
+            Thread t = new Thread(r, "schema-load-worker");
+
+            t.setDaemon(true);
+
+            return t;
+        }
+    });
+
+    /**
+     * Lock UI before start long task.
+     *
+     * @param layer Stack pane to add progress indicator.
+     * @param controls Controls to disable.
+     */
+    private void lockUI(StackPane layer, Node... controls) {
+        for (Node control : controls)
+            control.setDisable(true);
+
+        layer.getChildren().add(pi);
+    }
+
+    /**
+     * Unlock UI after long task finished.
+     *
+     * @param layer Stack pane to remove progress indicator.
+     * @param controls Controls to enable.
+     */
+    private void unlockUI(StackPane layer, Node... controls) {
+        for (Node control : controls)
+            control.setDisable(false);
+
+        layer.getChildren().remove(pi);
+    }
+
+    /**
+     * Perceptual delay to avoid UI flickering.
+     *
+     * @param started Time when background progress started.
+     */
+    private void perceptualDelay(long started) {
+        long delta = System.currentTimeMillis() - started;
+
+        if (delta < 500)
+            try {
+                Thread.sleep(500 - delta);
+            }
+            catch (InterruptedException ignored) {
+                Thread.currentThread().interrupt();
+            }
+    }
+
+    /**
+     * Fill tree with database metadata.
+     */
+    private void fill() {
+        lockUI(connLayerPnl, connPnl, nextBtn);
+
+        Runnable task = new Task<Void>() {
+            /** {@inheritDoc} */
+            @Override protected Void call() throws Exception {
+                long started = System.currentTimeMillis();
+
+                try (Connection conn = connect()) {
+                    schemas = parse(conn);
+                }
+
+                pojos = new ArrayList<>();
+
+                for (Map<String, PojoDescriptor> schema : schemas.values())
+                    for (PojoDescriptor pojo : schema.values())
+                        pojos.add(pojo);
+
+                perceptualDelay(started);
+
+                return null;
+            }
+
+            private CheckBoxTreeItem<String> 
addCheckBoxTreeItem(CheckBoxTreeItem<String> parent, String text) {
+                CheckBoxTreeItem<String> item = new CheckBoxTreeItem<>(text);
+
+                item.setSelected(true);
+                item.setExpanded(true);
+
+                parent.getChildren().add(item);
+
+                return item;
+            }
+
+            /** {@inheritDoc} */
+            @Override protected void succeeded() {
+                super.succeeded();
+
+                rootItem.getChildren().clear();
+
+                for (Map.Entry<String, Map<String, PojoDescriptor>> schema : 
schemas.entrySet()) {
+                    CheckBoxTreeItem<String> schemaItem = 
addCheckBoxTreeItem(rootItem, schema.getKey());
+
+                    for (String tbl : schema.getValue().keySet())
+                        addCheckBoxTreeItem(schemaItem, tbl);
+                }
+
+                unlockUI(connLayerPnl, connPnl, nextBtn);
+
+                titleLb.setText("Generate XML And POJOs");
+                titleLb.setGraphic(imageView("text_tree", 48));
+
+                rootPane.setCenter(genLayerPnl);
+
+                prevBtn.setDisable(false);
+                nextBtn.setText("Generate");
+                tooltip(nextBtn, "Generate XML and POJO files");
+            }
+
+            /** {@inheritDoc} */
+            @Override protected void cancelled() {
+                super.cancelled();
+
+                unlockUI(connLayerPnl, connPnl, nextBtn);
+            }
+
+            /** {@inheritDoc} */
+            @Override protected void failed() {
+                super.succeeded();
+
+                unlockUI(connLayerPnl, connPnl, nextBtn);
+
+                MessageBox.errorDialog(owner, "Failed to get tables list from 
database.", getException());
+            }
+        };
+
+        exec.submit(task);
+    }
+
+    /**
+     * Generate XML and POJOs.
+     */
+    private void generate() {
+        Collection<PojoDescriptor> selItems = selectedItems();
+
+        if (selItems.isEmpty()) {
+            MessageBox.warningDialog(owner, "Please select tables to generate 
POJOs and XML files!");
+
+            return;
+        }
+
+        lockUI(genLayerPnl, genPnl, prevBtn, nextBtn);
+
+        final String outFolder = outFolderTf.getText();
+
+        final String pkg = pkgTf.getText();
+
+        final File destFolder = new File(outFolder);
+
+        Runnable task = new Task<Void>() {
+            private void checkEmpty(Collection<GridCacheQueryTypeDescriptor> 
items,
+                final TreeItem<String> treeItem, String msg) {
+                if (items.isEmpty()) {
+                    Platform.runLater(new Runnable() {
+                        /** {@inheritDoc} */
+                        @Override public void run() {
+                            tree.getSelectionModel().select(treeItem);
+                        }
+                    });
+
+                    throw new IllegalStateException(msg);
+                }
+            }
+
+            /** {@inheritDoc} */
+            @Override protected Void call() throws Exception {
+                long started = System.currentTimeMillis();
+
+                if (!destFolder.exists() && !destFolder.mkdirs())
+                    throw new IOException("Failed to create output folder: " + 
destFolder);
+
+                Collection<GridCacheQueryTypeMetadata> all = new ArrayList<>();
+
+                boolean constructor = pojoConstructorCh.isSelected();
+                boolean include = pojoIncludeKeysCh.isSelected();
+                boolean singleXml = xmlSingleFileCh.isSelected();
+
+                ConfirmCallable askOverwrite = new ConfirmCallable(owner, 
"File already exists: %s\nOverwrite?");
+
+                // Generate POJO and XML.
+                for (TreeItem<String> schemeItem : rootItem.getChildren()) {
+                    for (TreeItem<String> tblItem : schemeItem.getChildren()) {
+                        if (((CheckBoxTreeItem)tblItem).isSelected()) {
+                            String scheme = schemeItem.getValue();
+                            String tbl = tblItem.getValue();
+
+                            PojoDescriptor pojo = schemas.get(scheme).get(tbl);
+
+                            GridCacheQueryTypeMetadata meta = pojo.metadata();
+
+                            Collection<GridCacheQueryTypeDescriptor> keys = 
new ArrayList<>();
+
+                            Collection<GridCacheQueryTypeDescriptor> vals = 
new ArrayList<>();
+
+                            // Fill list with key and value type descriptors.
+                            for (PojoField fld : pojo.fields()) {
+                                GridCacheQueryTypeDescriptor desc = 
fld.descriptor();
+
+                                if (fld.key()) {
+                                    keys.add(desc);
+
+                                    if (include)
+                                        vals.add(desc);
+                                }
+                                else
+                                    vals.add(desc);
+                            }
+
+                            checkEmpty(keys, tblItem, "No key fields specified 
for type: " + tbl);
+
+                            checkEmpty(vals, tblItem, "No value fields 
specified for type: " + tbl);
+
+                            meta.setKeyDescriptors(keys);
+
+                            meta.setValueDescriptors(vals);
+
+                            all.add(meta);
+
+                            if (!singleXml)
+                                XmlGenerator.transform(pkg, meta, new 
File(destFolder, meta.getType() + ".xml"),
+                                    askOverwrite);
+
+                            PojoGenerator.generate(meta, outFolder, pkg, 
constructor, askOverwrite);
+                        }
+                    }
+                }
+
+                if (all.isEmpty())
+                    throw new IllegalStateException("Nothing selected!");
+                else if (singleXml)
+                    XmlGenerator.transform(pkg, all, new File(outFolder, 
"Ignite.xml"), askOverwrite);
+
+                perceptualDelay(started);
+
+                return null;
+            }
+
+            /** {@inheritDoc} */
+            @Override protected void succeeded() {
+                super.succeeded();
+
+                unlockUI(genLayerPnl, genPnl, prevBtn, nextBtn);
+
+                MessageBox.informationDialog(owner, "Generation complete!");
+
+                if (openFolderCh.isSelected())
+                    try {
+                        java.awt.Desktop.getDesktop().open(destFolder);
+                    }
+                    catch (IOException e) {
+                        MessageBox.errorDialog(owner, "Failed to open folder 
with results.", e);
+                    }
+            }
+
+            /** {@inheritDoc} */
+            @Override protected void cancelled() {
+                super.cancelled();
+
+                unlockUI(genLayerPnl, genPnl, prevBtn, nextBtn);
+
+                MessageBox.warningDialog(owner, "Generation canceled.");
+            }
+
+            /** {@inheritDoc} */
+            @Override protected void failed() {
+                super.succeeded();
+
+                unlockUI(genLayerPnl, genPnl, prevBtn, nextBtn);
+
+                MessageBox.errorDialog(owner, "Generation failed.", 
getException());
+            }
+        };
+
+        exec.submit(task);
+    }
+
+    /**
+     * @return Header pane with title label.
+     */
+    private Pane createHeaderPane() {
+        titleLb = new Label("");
+        titleLb.setId("banner");
+
+        BorderPane bp = borderPane(null, hBox(10, true, titleLb), null, null, 
hBox(0, true, imageView("ignite", 48)));
+        bp.setId("banner");
+
+        return bp;
+    }
+
+    /**
+     * @return Panel with control buttons.
+     */
+    private Pane createButtonsPane() {
+        prevBtn = button("Prev", "Go to \"Database connection\" page", new 
EventHandler<ActionEvent>() {
+            @Override public void handle(ActionEvent evt) {
+                prev();
+            }
+        });
+
+        nextBtn = button("Next", "Go to \"POJO and XML generation\" page", new 
EventHandler<ActionEvent>() {
+            @Override public void handle(ActionEvent evt) {
+                next();
+            }
+        });
+
+        return buttonsPane(Pos.BOTTOM_RIGHT, true, prevBtn, nextBtn);
+    }
+
+    /**
+     * @return {@code true} if some changes were made to fields metadata.
+     */
+    private boolean changed() {
+        for (PojoDescriptor pojo : pojos)
+            if (pojo.changed())
+                return true;
+
+        return false;
+    }
+
+    /**
+     * Go to &quot;Connect To Database&quot; panel.
+     */
+    private void prev() {
+        if (changed() && !MessageBox.confirmDialog(owner, "Are you sure you 
want to return to previous page?\n" +
+            "This will discard all your changes."))
+            return;
+
+        titleLb.setText("Connect To Database");
+        titleLb.setGraphic(imageView("data_connection", 48));
+
+        rootPane.setCenter(connLayerPnl);
+
+        prevBtn.setDisable(true);
+        nextBtn.setText("Next");
+        tooltip(nextBtn, "Go to \"XML and POJO generation\" page");
+    }
+
+    /**
+     * Check that text field is non empty.
+     *
+     * @param tf Text field to check.
+     * @param trim If {@code true} then
+     * @param msg Warning message.
+     * @return {@code true} If text field is empty.
+     */
+    private boolean checkInput(TextField tf, boolean trim, String msg) {
+        String s = tf.getText();
+
+        s = trim ? s.trim() : s;
+
+        if (s.isEmpty()) {
+            tf.requestFocus();
+
+            MessageBox.warningDialog(owner, msg);
+
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Go to &quot;Generate XML And POJOs&quot; panel or generate XML and 
POJOs.
+     */
+    private void next() {
+        if (rootPane.getCenter() == connLayerPnl) {
+            if (checkInput(jdbcDrvJarTf, true, "Path to JDBC driver is not 
specified!") ||
+                checkInput(jdbcDrvClsTf, true, "JDBC driver class name is not 
specified!") ||
+                checkInput(jdbcUrlTf, true, "JDBC URL connection string is not 
specified!") ||
+                checkInput(userTf, true, "User name is not specified!"))
+                return;
+
+            fill();
+        }
+        else
+            generate();
+    }
+
+    /**
+     * Connect to database.
+     *
+     * @return Connection to database.
+     * @throws SQLException if connection failed.
+     */
+    private Connection connect() throws SQLException {
+        String drvCls = jdbcDrvClsTf.getText();
+
+        Driver drv = drivers.get(drvCls);
+
+        if (drv == null) {
+            String path = jdbcDrvJarTf.getText().trim();
+
+            if (path.isEmpty())
+                throw new IllegalStateException("Driver jar file name is not 
specified");
+
+            File drvJar = new File(jdbcDrvJarTf.getText());
+
+            if (!drvJar.exists())
+                throw new IllegalStateException("Driver jar file is not 
found");
+
+            try {
+                URL u = new URL("jar:" + drvJar.toURI() + "!/");
+
+                URLClassLoader ucl = URLClassLoader.newInstance(new URL[] {u});
+
+                drv = (Driver)Class.forName(drvCls, true, ucl).newInstance();
+
+                drivers.put(drvCls, drv);
+            }
+            catch (Throwable e) {
+                throw new IllegalStateException(e);
+            }
+        }
+
+        String user = userTf.getText().trim();
+
+        String pwd = pwdTf.getText().trim();
+
+        Properties info = new Properties();
+
+        if (!user.isEmpty())
+            info.put("user", user);
+
+        if (!pwd.isEmpty())
+            info.put("password", pwd);
+
+        return drv.connect(jdbcUrlTf.getText(), info);
+    }
+
+    /**
+     * Create connection pane with controls.
+     */
+    private Pane createConnectionPane() {
+        connPnl = paneEx(10, 10, 0, 10);
+
+        connPnl.addColumn();
+        connPnl.addColumn(100, 100, Double.MAX_VALUE, Priority.ALWAYS);
+        connPnl.addColumn(35, 35, 35, Priority.NEVER);
+
+        jdbcDrvJarTf = connPnl.addLabeled("Driver JAR:", textField("Path to 
driver jar"));
+
+        connPnl.add(button("...", "Select JDBC driver jar or zip", new 
EventHandler<ActionEvent>() {
+            /** {@inheritDoc} */
+            @Override public void handle(ActionEvent evt) {
+                FileChooser fc = new FileChooser();
+
+                fc.getExtensionFilters().addAll(
+                    new FileChooser.ExtensionFilter("JDBC Drivers (*.jar)", 
"*.jar"),
+                    new FileChooser.ExtensionFilter("ZIP archives (*.zip)", 
"*.zip"));
+
+                File drvJar = fc.showOpenDialog(owner);
+
+                if (drvJar != null)
+                    jdbcDrvJarTf.setText(drvJar.getAbsolutePath());
+            }
+        }));
+
+        jdbcDrvClsTf = connPnl.addLabeled("JDBC Driver:", textField("Class 
name for JDBC driver"), 2);
+
+        jdbcUrlTf = connPnl.addLabeled("JDBC URL:", textField("JDBC URL of the 
database connection string"), 2);
+
+        userTf = connPnl.addLabeled("User:", textField("User name"), 2);
+
+        pwdTf = connPnl.addLabeled("Password:", passwordField("User 
password"), 2);
+
+        connLayerPnl = stackPane(connPnl);
+
+        return connLayerPnl;
+    }
+
+    /**
+     * Create generate pane with controls.
+     */
+    private void createGeneratePane() {
+        genPnl = paneEx(10, 10, 0, 10);
+
+        genPnl.addColumn();
+        genPnl.addColumn(100, 100, Double.MAX_VALUE, Priority.ALWAYS);
+        genPnl.addColumn(35, 35, 35, Priority.NEVER);
+
+        genPnl.addRow(100, 100, Double.MAX_VALUE, Priority.ALWAYS);
+        genPnl.addRows(8);
+
+        TableColumn<PojoField, Boolean> keyCol = tableColumn("Key", "key",
+            "If checked then this field will be part of key object", 70, 70);
+
+        keyCol.setCellFactory(new Callback<TableColumn<PojoField, Boolean>, 
TableCell<PojoField, Boolean>>() {
+            /** {@inheritDoc} */
+            @Override public TableCell<PojoField, Boolean> 
call(TableColumn<PojoField, Boolean> col) {
+                CheckBoxTableCell<PojoField, Boolean> cell = new 
CheckBoxTableCell<>();
+
+                cell.setAlignment(Pos.CENTER);
+
+                return cell;
+            }
+        });
+
+        keyCol.setEditable(true);
+
+        TableColumn<PojoField, String> dbNameCol = tableColumn("DB Name", 
"dbName", "Field name in database", 100, 0);
+
+        TableColumn<PojoField, String> dbTypeNameCol = tableColumn("DB Type", 
"dbTypeName", "Field type in database", 100, 0);
+
+        TableColumn<PojoField, String> javaNameCol = tableColumn("Ignite 
Name", "javaName",
+            "Field name in POJO class", 100, 0);
+        
javaNameCol.setCellFactory(TextFieldTableCell.<PojoField>forTableColumn());
+        javaNameCol.setEditable(true);
+
+        TableColumn<PojoField, String> javaTypeNameCol = tableColumn("Java 
Type", "javaTypeName",
+            "Field java type in POJO class", 100, 0);
+        javaTypeNameCol.setCellFactory(JavaTypeCell.forTableColumn());
+        javaTypeNameCol.setEditable(true);
+
+        final TableView<PojoField> tbl = new TableView<>();
+
+        tbl.setMinHeight(50);
+        tbl.setPlaceholder(text("Select table to see table columns", 0));
+
+        final TableColumn[] cols = {keyCol, dbNameCol, dbTypeNameCol, 
javaNameCol, javaTypeNameCol};
+
+        //noinspection unchecked
+        tbl.getColumns().addAll(cols);
+        tbl.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
+        tbl.setEditable(true);
+
+        tbl.getColumns().addListener(new 
ListChangeListener<TableColumn<PojoField, ?>>() {
+            private boolean suspended;
+
+            /** {@inheritDoc} */
+            @Override public void onChanged(Change change) {
+                change.next();
+                if (change.wasReplaced() && !suspended) {
+                    suspended = true;
+
+                    try {
+                        //noinspection unchecked
+                        tbl.getColumns().setAll(cols);
+                    }
+                    finally {
+                        suspended = false;
+                    }
+                }
+            }
+        });
+
+        final Button upBtn = button(imageView("navigate_up", 24), "Move 
selected row up",
+            new EventHandler<ActionEvent>() {
+                @Override public void handle(ActionEvent evt) {
+                    TableView.TableViewSelectionModel<PojoField> selMdl = 
tbl.getSelectionModel();
+
+                    int selIdx = selMdl.getSelectedIndex();
+
+                    if (selIdx > 0) {
+                        ObservableList<PojoField> items = tbl.getItems();
+
+                        int newId = selIdx - 1;
+
+                        items.add(newId, items.remove(selIdx));
+
+                        if (newId == 0)
+                            tbl.requestFocus();
+
+                        selMdl.select(newId);
+                    }
+                }
+            });
+
+        upBtn.setDisable(true);
+
+        final Button downBtn = button(imageView("navigate_down", 24), "Move 
selected row down",
+            new EventHandler<ActionEvent>() {
+                @Override public void handle(ActionEvent evt) {
+                    TableView.TableViewSelectionModel<PojoField> selMdl = 
tbl.getSelectionModel();
+
+                    int selIdx = selMdl.getSelectedIndex();
+
+                    ObservableList<PojoField> items = tbl.getItems();
+
+                    int maxIdx = items.size() - 1;
+
+                    if (selIdx < maxIdx) {
+                        int newId = selIdx + 1;
+
+                        items.add(newId, items.remove(selIdx));
+
+                        if (newId == maxIdx)
+                            tbl.requestFocus();
+
+                        selMdl.select(newId);
+
+                    }
+                }
+            });
+
+        downBtn.setDisable(true);
+
+        tbl.getSelectionModel().selectedIndexProperty().addListener(new 
ChangeListener<Number>() {
+            @Override public void changed(ObservableValue<? extends Number> 
observable, Number oldVal, Number newVal) {
+                upBtn.setDisable(newVal == null || newVal.intValue() == 0);
+                downBtn.setDisable(newVal == null || newVal.intValue() == 
tbl.getItems().size() - 1);
+            }
+        });
+
+        rootItem = new CheckBoxTreeItem<>("Database");
+
+        tree = new TreeView<>(rootItem);
+
+        tree.setMinHeight(50);
+        tree.setShowRoot(false);
+        tree.setCellFactory(CheckBoxTreeCell.<String>forTreeView());
+
+        genPnl.add(splitPane(tree, borderPane(null, tbl, null, null, vBox(10, 
upBtn, downBtn)), 0.6), 3);
+
+        final GridPaneEx keyValPnl = paneEx(0, 0, 0, 0);
+        keyValPnl.addColumn(100, 100, Double.MAX_VALUE, Priority.ALWAYS);
+        keyValPnl.addColumn();
+        keyValPnl.addColumn(100, 100, Double.MAX_VALUE, Priority.ALWAYS);
+        keyValPnl.addColumn();
+
+        genPnl.add(new Label("Key class:"));
+        keyClsTf = keyValPnl.add(textField("Key class name"));
+
+        valClsTf = keyValPnl.addLabeled("  Value class:", textField("Value 
class name"));
+
+        keyValPnl.add(button("Apply", "Change key and value class names", new 
EventHandler<ActionEvent>() {
+            @Override public void handle(ActionEvent evt) {
+                if (checkInput(keyClsTf, true, "Key class name must not be 
empty!") ||
+                    checkInput(valClsTf, true, "Value class name must not be 
empty!"))
+                    return;
+
+                String keyCls = keyClsTf.getText().trim();
+
+                String valCls = valClsTf.getText().trim();
+
+                if (keyCls.equals(valCls)) {
+                    MessageBox.warningDialog(owner, "Key class name must be 
different from value class name!");
+
+                    keyClsTf.requestFocus();
+
+                    return;
+                }
+
+                for (PojoDescriptor pojo : pojos)
+                    if (pojo != curPojo) {
+                        String pojoKeyCls = pojo.keyClassName();
+
+                        String pojoValCls = pojo.valueClassName();
+
+                        if (keyCls.equals(pojoKeyCls) || 
keyCls.equals(pojoValCls)) {
+                            MessageBox.warningDialog(owner, "Key class name 
must be unique!");
+
+                            keyClsTf.requestFocus();
+
+                            return;
+                        }
+
+                        if (valCls.equals(pojoKeyCls) || 
valCls.equals(pojoValCls)) {
+                            MessageBox.warningDialog(owner, "Value class name 
must be unique!");
+
+                            valClsTf.requestFocus();
+
+                            return;
+                        }
+                    }
+
+                curPojo.keyClassName(keyCls);
+                curPojo.valueClassName(valCls);
+            }
+        }));
+
+        keyValPnl.setDisable(true);
+
+        genPnl.add(keyValPnl, 2);
+
+        pkgTf = genPnl.addLabeled("Package:", textField("Package that will be 
used for POJOs generation"), 2);
+
+        outFolderTf = genPnl.addLabeled("Output Folder:", textField("Output 
folder for POJOs and XML files"));
+
+        genPnl.add(button("...", "Select output folder", new 
EventHandler<ActionEvent>() {
+            /** {@inheritDoc} */
+            @Override public void handle(ActionEvent evt) {
+                DirectoryChooser dc = new DirectoryChooser();
+
+                File folder = dc.showDialog(owner);
+
+                if (folder != null)
+                    outFolderTf.setText(folder.getAbsolutePath());
+            }
+        }));
+
+        pojoIncludeKeysCh = genPnl.add(checkBox("Include key fields into value 
POJOs",
+            "If selected then include key fields into value object", true), 3);
+
+        pojoConstructorCh = genPnl.add(checkBox("Generate constructors for 
POJOs",
+            "If selected then generate empty and full constructors for POJOs", 
false), 3);
+
+        xmlSingleFileCh = genPnl.add(checkBox("Write all configurations to a 
single XML file",
+            "If selected then all configurations will be saved into the file 
'Ignite.xml'", true), 3);
+
+        openFolderCh = genPnl.add(checkBox("Reveal output folder",
+            "Open output folder in system file manager after generation 
complete", true), 3);
+
+        GridPaneEx regexPnl = paneEx(0, 0, 0, 0);
+        regexPnl.addColumn();
+        regexPnl.addColumn(100, 100, Double.MAX_VALUE, Priority.ALWAYS);
+        regexPnl.addColumn();
+        regexPnl.addColumn(100, 100, Double.MAX_VALUE, Priority.ALWAYS);
+
+        regexPnl.add(new Label("Replace Ignite name for selected or all 
tables:"), 4);
+        regexTf = regexPnl.addLabeled("  Regexp:", textField("Regular 
expression. For example: (\\w+)"));
+        replaceTf = regexPnl.addLabeled("  Replace with:", textField("Replace 
text. For example: $1_Suffix"));
+
+        final Button renBtn = button("Rename", "Replace Ignite names by 
provided regular expression for current table",
+            new EventHandler<ActionEvent>() {
+                /** {@inheritDoc} */
+                @Override public void handle(ActionEvent evt) {
+                    if (curPojo == null) {
+                        MessageBox.warningDialog(owner, "Please select table 
to rename Ignite names!");
+
+                        return;
+                    }
+
+                    if (checkInput(regexTf, false, "Regular expression should 
not be empty!"))
+                        return;
+
+                    String regex = regexTf.getText();
+
+                    String replace = replaceTf.getText();
+
+                    try {
+                        for (PojoField field : curPojo.fields())
+                            field.javaName(field.javaName().replaceAll(regex, 
replace));
+                    }
+                    catch (Exception e) {
+                        MessageBox.errorDialog(owner, "Failed to rename Ignite 
names!", e);
+                    }
+                }
+            });
+        renBtn.setDisable(true);
+
+        final Button revertBtn = button("Revert", "Revert changes to Ignite 
names for current table", new EventHandler<ActionEvent>() {
+            /** {@inheritDoc} */
+            @Override public void handle(ActionEvent evt) {
+                if (curPojo != null)
+                    curPojo.revertJavaNames();
+                else
+                    MessageBox.warningDialog(owner, "Please select table to 
revert changes to Ignite names!");
+            }
+        });
+        revertBtn.setDisable(true);
+
+        regexPnl.add(buttonsPane(Pos.BOTTOM_RIGHT, false,
+            renBtn,
+            button("Rename All", "Replace Ignite names by provided regular 
expression for all selected tables",
+                new EventHandler<ActionEvent>() {
+                    /** {@inheritDoc} */
+                    @Override public void handle(ActionEvent evt) {
+                        if (checkInput(regexTf, false, "Regular expression 
should not be empty!"))
+                            return;
+
+                        Collection<PojoDescriptor> selItems = selectedItems();
+
+                        if (selItems.isEmpty()) {
+                            MessageBox.warningDialog(owner, "Please select 
tables to rename Ignite names!");
+
+                            return;
+                        }
+
+                        if (!MessageBox.confirmDialog(owner,
+                            "Are you sure you want to rename Ignite names in 
all selected tables?"))
+                            return;
+
+                        String regex = regexTf.getText();
+
+                        String replace = replaceTf.getText();
+
+                        try {
+                            for (PojoDescriptor pojo : selItems)
+                                for (PojoField field : pojo.fields())
+                                    
field.javaName(field.javaName().replaceAll(regex, replace));
+                        }
+                        catch (Exception e) {
+                            MessageBox.errorDialog(owner, "Failed to rename 
Ignite names!", e);
+                        }
+                    }
+                }),
+            revertBtn,
+            button("Revert All", "Revert changes to Ignite names for all 
selected tables", new EventHandler<ActionEvent>() {
+                /** {@inheritDoc} */
+                @Override public void handle(ActionEvent evt) {
+                    Collection<PojoDescriptor> selItems = selectedItems();
+
+                    if (selItems.isEmpty()) {
+                        MessageBox.warningDialog(owner, "Please select tables 
to revert Ignite names!");
+
+                        return;
+                    }
+
+                    if (!MessageBox.confirmDialog(owner,
+                        "Are you sure you want to revert Ignite names for all 
selected tables?"))
+                        return;
+
+                    for (PojoDescriptor pojo : selItems)
+                        pojo.revertJavaNames();
+                }
+            })
+        ), 4);
+
+        tree.getSelectionModel().selectedItemProperty().addListener(new 
ChangeListener<TreeItem<String>>() {
+            /** {@inheritDoc} */
+            @Override public void changed(ObservableValue<? extends 
TreeItem<String>> val, TreeItem<String> oldItem,
+                TreeItem<String> newItem) {
+                if (newItem != null && newItem.getParent() != null && 
newItem.isLeaf()) {
+                    curPojo = 
schemas.get(newItem.getParent().getValue()).get(newItem.getValue());
+
+                    tbl.setItems(curPojo.fields());
+                    tbl.getSelectionModel().select(0);
+
+                    keyClsTf.setText(curPojo.keyClassName());
+                    valClsTf.setText(curPojo.valueClassName());
+
+                    keyValPnl.setDisable(false);
+
+                    renBtn.setDisable(false);
+                    revertBtn.setDisable(false);
+                }
+                else {
+                    curPojo = null;
+                    tbl.setItems(NO_DATA);
+
+                    keyClsTf.setText("");
+                    valClsTf.setText("");
+
+                    keyValPnl.setDisable(true);
+
+                    renBtn.setDisable(true);
+                    revertBtn.setDisable(true);
+                    upBtn.setDisable(true);
+                    downBtn.setDisable(true);
+                }
+            }
+        });
+
+        genPnl.add(regexPnl, 3);
+
+        genLayerPnl = stackPane(genPnl);
+    }
+
+    /**
+     * @return Selected tree view items.
+     */
+    private Collection<PojoDescriptor> selectedItems() {
+        Collection<PojoDescriptor> res = new ArrayList<>();
+
+        for (TreeItem<String> schemeItem : rootItem.getChildren())
+            for (TreeItem<String> tblItem : schemeItem.getChildren())
+                if (((CheckBoxTreeItem)tblItem).isSelected())
+                    
res.add(schemas.get(schemeItem.getValue()).get(tblItem.getValue()));
+
+        return res;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void start(Stage primaryStage) {
+        owner = primaryStage;
+
+        primaryStage.setTitle("Schema Load");
+
+        primaryStage.getIcons().addAll(
+            image("ignite", 16),
+            image("ignite", 24),
+            image("ignite", 32),
+            image("ignite", 48),
+            image("ignite", 64),
+            image("ignite", 128));
+
+        pi = progressIndicator(50);
+
+        createGeneratePane();
+
+        rootPane = borderPane(createHeaderPane(), createConnectionPane(), 
createButtonsPane(), null, null);
+
+        primaryStage.setScene(scene(rootPane));
+
+        primaryStage.setWidth(600);
+        primaryStage.setMinWidth(600);
+
+        primaryStage.setHeight(650);
+        primaryStage.setMinHeight(650);
+
+        prev();
+
+        Preferences userPrefs = Preferences.userNodeForPackage(getClass());
+
+        // Restore window pos and size.
+        if (userPrefs.get("window.x", null) != null) {
+            double x = userPrefs.getDouble("window.x", 100);
+            double y = userPrefs.getDouble("window.y", 100);
+            double w = userPrefs.getDouble("window.width", 650);
+            double h = userPrefs.getDouble("window.height", 650);
+
+            // Ensure that window fit any available screen.
+            if (!Screen.getScreensForRectangle(x, y, w, h).isEmpty()) {
+                if (x > 0)
+                    primaryStage.setX(x);
+
+                if (y > 0)
+                    primaryStage.setY(y);
+
+                primaryStage.setWidth(w);
+                primaryStage.setHeight(h);
+            }
+        }
+        else
+            primaryStage.centerOnScreen();
+
+        String userHome = System.getProperty("user.home").replace('\\', '/');
+
+        // Restore connection pane settings.
+        jdbcDrvJarTf.setText(userPrefs.get("jdbc.driver.jar", "h2.jar"));
+        jdbcDrvClsTf.setText(userPrefs.get("jdbc.driver.class", 
"org.h2.Driver"));
+        jdbcUrlTf.setText(userPrefs.get("jdbc.url", "jdbc:h2:" + userHome + 
"/schema-load/db"));
+        userTf.setText(userPrefs.get("jdbc.user", "sa"));
+
+        // Restore generation pane settings.
+        outFolderTf.setText(userPrefs.get("out.folder", userHome + 
"/schema-load/out"));
+        openFolderCh.setSelected(userPrefs.getBoolean("out.folder.open", 
true));
+
+        pkgTf.setText(userPrefs.get("pojo.package", "org.apache.ignite"));
+        pojoIncludeKeysCh.setSelected(userPrefs.getBoolean("pojo.include", 
true));
+        pojoConstructorCh.setSelected(userPrefs.getBoolean("pojo.constructor", 
false));
+
+        xmlSingleFileCh.setSelected(userPrefs.getBoolean("xml.single", true));
+
+        regexTf.setText(userPrefs.get("naming.pattern", ""));
+        replaceTf.setText(userPrefs.get("naming.replace", ""));
+
+        primaryStage.show();
+    }
+
+    /** {@inheritDoc} */
+    @Override public void stop() throws Exception {
+        Preferences userPrefs = Preferences.userNodeForPackage(getClass());
+
+        // Save window pos and size.
+        userPrefs.putDouble("window.x", owner.getX());
+        userPrefs.putDouble("window.y", owner.getY());
+        userPrefs.putDouble("window.width", owner.getWidth());
+        userPrefs.putDouble("window.height", owner.getHeight());
+
+        // Save connection pane settings.
+        userPrefs.put("jdbc.driver.jar", jdbcDrvJarTf.getText());
+        userPrefs.put("jdbc.driver.class", jdbcDrvClsTf.getText());
+        userPrefs.put("jdbc.url", jdbcUrlTf.getText());
+        userPrefs.put("jdbc.user", userTf.getText());
+
+        // Save generation pane settings.
+        userPrefs.put("out.folder", outFolderTf.getText());
+        userPrefs.putBoolean("out.folder.open", openFolderCh.isSelected());
+
+        userPrefs.put("pojo.package", pkgTf.getText());
+        userPrefs.putBoolean("pojo.include", pojoIncludeKeysCh.isSelected());
+        userPrefs.putBoolean("pojo.constructor", 
pojoConstructorCh.isSelected());
+
+        userPrefs.putBoolean("xml.single", xmlSingleFileCh.isSelected());
+
+        userPrefs.put("naming.pattern", regexTf.getText());
+        userPrefs.put("naming.replace", replaceTf.getText());
+    }
+
+    /**
+     * @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.
+     */
+    public static void main(String[] args) {
+        // Workaround for JavaFX ugly text AA.
+        System.setProperty("prism.lcdtext", "false");
+        System.setProperty("prism.text", "t2k");
+
+        // Workaround for AWT + JavaFX: we should initialize AWT before JavaFX.
+        java.awt.Toolkit.getDefaultToolkit();
+
+        // Workaround for JavaFX + Mac OS dock icon.
+        if (System.getProperty("os.name").toLowerCase().contains("mac os")) {
+            System.setProperty("javafx.macosx.embedded", "true");
+
+            try {
+                Class<?> appCls = Class.forName("com.apple.eawt.Application");
+
+                Object osxApp = 
appCls.getDeclaredMethod("getApplication").invoke(null);
+
+                appCls.getDeclaredMethod("setDockIconImage", 
java.awt.Image.class)
+                    .invoke(osxApp, fromFXImage(image("ignite", 128), null));
+            }
+            catch (Throwable ignore) {
+                // No-op.
+            }
+        }
+
+        launch(args);
+    }
+
+    /**
+     * 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> {
+        /** Combo box. */
+        private final ComboBox<String> comboBox;
+
+        /** Creates a ComboBox cell factory for use in TableColumn controls. */
+        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();
+                }
+            };
+        }
+
+        /**
+         * Default constructor.
+         */
+        private JavaTypeCell() {
+            comboBox = new 
ComboBox<>(FXCollections.<String>emptyObservableList());
+
+            comboBox.valueProperty().addListener(new ChangeListener<String>() {
+                @Override public void changed(ObservableValue<? extends 
String> val, String oldVal, String newVal) {
+                    if (isEditing())
+                        commitEdit(newVal);
+                }
+            });
+
+            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);
+
+            setGraphic(null);
+
+            if (!empty) {
+                setText(item);
+
+                PojoField pojo = (PojoField)getTableRow().getItem();
+
+                if (pojo != null) {
+                    comboBox.setItems(pojo.conversions());
+
+                    comboBox.getSelectionModel().select(pojo.javaTypeName());
+                }
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/410f9e5e/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 8f5676a..a1f62cc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -114,6 +114,7 @@
         <module>modules/log4j</module>
         <module>modules/slf4j</module>
         <module>modules/jcl</module>
+        <module>modules/schema-load</module>
     </modules>
 
     <dependencyManagement>

Reply via email to