org.geoserver.importer.web.ImportDataPage.java Source code

Java tutorial

Introduction

Here is the source code for org.geoserver.importer.web.ImportDataPage.java

Source

/* (c) 2014 Open Source Geospatial Foundation - all rights reserved
 * (c) 2001 - 2013 OpenPlans
 * This code is licensed under the GPL 2.0 license, available at the root
 * application directory.
 */
package org.geoserver.importer.web;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.wicket.Application;
import org.apache.wicket.AttributeModifier;
import org.apache.wicket.Component;
import org.apache.wicket.PageParameters;
import org.apache.wicket.ResourceReference;
import org.apache.wicket.SharedResources;
import org.apache.wicket.ajax.AbstractAjaxTimerBehavior;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink;
import org.apache.wicket.behavior.SimpleAttributeModifier;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.RadioGroup;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.image.Image;
import org.apache.wicket.markup.html.link.ExternalLink;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.util.time.Duration;
import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.NamespaceInfo;
import org.geoserver.catalog.StoreInfo;
import org.geoserver.catalog.WorkspaceInfo;
import org.geoserver.web.GeoServerApplication;
import org.geoserver.web.GeoServerSecuredPage;
import org.geoserver.web.data.store.StoreChoiceRenderer;
import org.geoserver.web.data.store.StoreModel;
import org.geoserver.web.data.workspace.WorkspaceChoiceRenderer;
import org.geoserver.web.data.workspace.WorkspaceDetachableModel;
import org.geoserver.web.data.workspace.WorkspacesModel;
import org.geoserver.web.wicket.GeoServerDialog;
import org.geoserver.web.wicket.GeoServerDialog.DialogDelegate;
import org.geoserver.web.wicket.ParamResourceModel;
import org.geotools.data.DataStoreFactorySpi;
import org.geotools.util.logging.Logging;
import org.geoserver.importer.ImportContext;
import org.geoserver.importer.ImportData;
import org.geoserver.importer.Importer;
import org.geoserver.importer.job.ProgressMonitor;
import org.geoserver.importer.job.Task;

/**
 * First page of the import wizard.
 * 
 * @author Andrea Aime - OpenGeo
 * @author Justin Deoliveira, OpenGeo
 */
@SuppressWarnings("serial")
public class ImportDataPage extends GeoServerSecuredPage {

    static Logger LOGGER = Logging.getLogger(ImportDataPage.class);

    AjaxRadioPanel<Source> sourceList;
    WebMarkupContainer sourcePanel;

    WorkspaceDetachableModel workspace;
    DropDownChoice workspaceChoice;
    TextField workspaceNameTextField;
    Component statusLabel;

    StoreModel store;
    DropDownChoice storeChoice;

    String storeName;

    ImportContextTable importTable;
    AjaxLink removeImportLink;

    GeoServerDialog dialog;

    public ImportDataPage(PageParameters params) {
        Form form = new Form("form");
        add(form);

        sourceList = new AjaxRadioPanel<Source>("sources", Arrays.asList(Source.values()), Source.SPATIAL_FILES) {
            @Override
            protected void onRadioSelect(AjaxRequestTarget target, Source newSelection) {
                updateSourcePanel(newSelection, target);
            }

            @Override
            protected AjaxRadio<Source> newRadioCell(RadioGroup<Source> group, ListItem<Source> item) {
                AjaxRadio<Source> radio = super.newRadioCell(group, item);
                if (!item.getModelObject().isAvailable()) {
                    radio.setEnabled(false);
                }
                return radio;
            }

            @Override
            protected Component createLabel(String id, ListItem<Source> item) {
                return new SourceLabelPanel(id, item.getModelObject());
            }
        };

        form.add(sourceList);

        sourcePanel = new WebMarkupContainer("panel");
        sourcePanel.setOutputMarkupId(true);
        form.add(sourcePanel);

        Catalog catalog = GeoServerApplication.get().getCatalog();

        // workspace chooser
        workspace = new WorkspaceDetachableModel(catalog.getDefaultWorkspace());
        workspaceChoice = new DropDownChoice("workspace", workspace, new WorkspacesModel(),
                new WorkspaceChoiceRenderer());
        workspaceChoice.setOutputMarkupId(true);
        workspaceChoice.add(new AjaxFormComponentUpdatingBehavior("onchange") {
            @Override
            protected void onUpdate(AjaxRequestTarget target) {
                updateTargetStore(target);
            }
        });
        workspaceChoice.setNullValid(true);
        form.add(workspaceChoice);

        WebMarkupContainer workspaceNameContainer = new WebMarkupContainer("workspaceNameContainer");
        workspaceNameContainer.setOutputMarkupId(true);
        form.add(workspaceNameContainer);

        workspaceNameTextField = new TextField("workspaceName", new Model());
        workspaceNameTextField.setOutputMarkupId(true);
        boolean defaultWorkspace = catalog.getDefaultWorkspace() != null;
        workspaceNameTextField.setVisible(!defaultWorkspace);
        workspaceNameTextField.setRequired(!defaultWorkspace);
        workspaceNameContainer.add(workspaceNameTextField);

        //store chooser
        WorkspaceInfo ws = (WorkspaceInfo) workspace.getObject();
        store = new StoreModel(ws != null ? catalog.getDefaultDataStore(ws) : null);
        storeChoice = new DropDownChoice("store", store, new EnabledStoresModel(workspace),
                new StoreChoiceRenderer()) {
            protected String getNullValidKey() {
                return ImportDataPage.class.getSimpleName() + "." + super.getNullValidKey();
            };
        };
        storeChoice.setOutputMarkupId(true);

        storeChoice.setNullValid(true);
        form.add(storeChoice);

        form.add(statusLabel = new Label("status", new Model()).setOutputMarkupId(true));
        form.add(new AjaxSubmitLink("next", form) {
            @Override
            protected void disableLink(ComponentTag tag) {
                super.disableLink(tag);
                tag.setName("a");
                tag.addBehavior(new SimpleAttributeModifier("class", "disabled"));
            }

            protected void onError(AjaxRequestTarget target, Form<?> form) {
                target.addComponent(feedbackPanel);
            }

            protected void onSubmit(AjaxRequestTarget target, final Form<?> form) {

                //update status to indicate we are working
                statusLabel.add(new SimpleAttributeModifier("class", "working-link"));
                statusLabel.setDefaultModelObject("Working");
                target.addComponent(statusLabel);

                //enable cancel and disable this
                Component cancel = form.get("cancel");
                cancel.setEnabled(true);
                target.addComponent(cancel);

                setEnabled(false);
                target.addComponent(this);

                final AjaxSubmitLink self = this;

                final Long jobid;
                try {
                    jobid = createContext();
                } catch (Exception e) {
                    error(e);
                    LOGGER.log(Level.WARNING, "Error creating import", e);
                    resetButtons(form, target);
                    return;
                }

                cancel.setDefaultModelObject(jobid);
                this.add(new AbstractAjaxTimerBehavior(Duration.seconds(3)) {
                    protected void onTimer(AjaxRequestTarget target) {
                        Importer importer = ImporterWebUtils.importer();
                        Task<ImportContext> t = importer.getTask(jobid);

                        if (t.isDone()) {
                            try {
                                if (t.getError() != null) {
                                    error(t.getError());
                                } else if (t.isCancelled()) {
                                    //do nothing
                                } else {
                                    ImportContext imp = t.get();

                                    //check the import for actual things to do
                                    boolean proceed = !imp.getTasks().isEmpty();

                                    if (proceed) {
                                        imp.setArchive(false);
                                        importer.changed(imp);

                                        PageParameters pp = new PageParameters();
                                        pp.put("id", imp.getId());

                                        setResponsePage(ImportPage.class, pp);
                                    } else {
                                        info("No data to import was found");
                                        importer.delete(imp);
                                    }
                                }
                            } catch (Exception e) {
                                error(e);
                                LOGGER.log(Level.WARNING, "", e);
                            } finally {
                                stop();

                                //update the button back to original state
                                resetButtons(form, target);

                                target.addComponent(feedbackPanel);
                            }
                            return;
                        }

                        ProgressMonitor m = t.getMonitor();
                        String msg = m.getTask() != null ? m.getTask().toString() : "Working";

                        statusLabel.setDefaultModelObject(msg);
                        target.addComponent(statusLabel);
                    };
                });
            }
        });

        form.add(new AjaxLink<Long>("cancel", new Model<Long>()) {
            protected void disableLink(ComponentTag tag) {
                super.disableLink(tag);
                ImporterWebUtils.disableLink(tag);
            };

            @Override
            public void onClick(AjaxRequestTarget target) {
                Importer importer = ImporterWebUtils.importer();
                Long jobid = getModelObject();
                Task<ImportContext> task = importer.getTask(jobid);
                if (task != null && !task.isDone() && !task.isCancelled()) {
                    task.getMonitor().setCanceled(true);
                    task.cancel(false);
                    try {
                        task.get();
                    } catch (Exception e) {
                    }
                }

                setEnabled(false);

                Component next = getParent().get("next");
                next.setEnabled(true);

                target.addComponent(this);
                target.addComponent(next);
            }
        }.setOutputMarkupId(true).setEnabled(false));

        importTable = new ImportContextTable("imports", new ImportContextProvider(true) {
            @Override
            protected List<org.geoserver.web.wicket.GeoServerDataProvider.Property<ImportContext>> getProperties() {
                return Arrays.asList(ID, STATE, UPDATED);
            }
        }, true) {
            protected void onSelectionUpdate(AjaxRequestTarget target) {
                removeImportLink.setEnabled(!getSelection().isEmpty());
                target.addComponent(removeImportLink);
            };
        };
        importTable.setOutputMarkupId(true);
        importTable.setFilterable(false);
        importTable.setSortable(false);
        form.add(importTable);

        form.add(removeImportLink = new AjaxLink("remove") {
            @Override
            public void onClick(AjaxRequestTarget target) {
                Importer importer = ImporterWebUtils.importer();
                for (ImportContext c : importTable.getSelection()) {
                    try {
                        importer.delete(c);
                    } catch (IOException e) {
                        LOGGER.log(Level.WARNING, "Error deleting context", c);
                    }
                }
                importTable.clearSelection();
                target.addComponent(importTable);
            }
        });
        removeImportLink.setOutputMarkupId(true).setEnabled(false);

        AjaxLink jobLink = new AjaxLink("jobs") {
            @Override
            public void onClick(AjaxRequestTarget target) {
                dialog.showOkCancel(target, new DialogDelegate() {
                    @Override
                    protected boolean onSubmit(AjaxRequestTarget target, Component contents) {
                        return true;
                    }

                    @Override
                    protected Component getContents(String id) {
                        return new JobQueuePanel(id);
                    }
                });
            }
        };
        jobLink.setVisible(ImporterWebUtils.isDevMode());
        form.add(jobLink);

        add(dialog = new GeoServerDialog("dialog"));
        dialog.setInitialWidth(600);
        dialog.setInitialHeight(400);
        dialog.setMinimalHeight(150);

        updateSourcePanel(Source.SPATIAL_FILES, null);
        updateTargetStore(null);
    }

    Long createContext() throws Exception {
        ImportSourcePanel panel = (ImportSourcePanel) sourcePanel.get("content");
        ImportData source = panel.createImportSource();

        WorkspaceInfo targetWorkspace = (WorkspaceInfo) workspace.getObject();
        if (targetWorkspace == null) {
            Catalog cat = getCatalog();

            String wsName = workspaceNameTextField.getDefaultModelObjectAsString();
            targetWorkspace = cat.getWorkspaceByName(wsName);
            if (targetWorkspace == null) {
                targetWorkspace = cat.getFactory().createWorkspace();
                targetWorkspace.setName(wsName);

                NamespaceInfo ns = cat.getFactory().createNamespace();
                ns.setPrefix(wsName);
                try {
                    ns.setURI("http://opengeo.org/#" + URLEncoder.encode(wsName, "ASCII"));
                } catch (UnsupportedEncodingException e) {
                    throw new RuntimeException(e);
                }

                cat.add(targetWorkspace);
                cat.add(ns);
            }
        }

        StoreInfo targetStore = (StoreInfo) (store.getObject() != null ? store.getObject() : null);

        Importer importer = ImporterWebUtils.importer();
        return importer.createContextAsync(source, targetWorkspace, targetStore);

    }

    void updateTargetStore(AjaxRequestTarget target) {
        WorkspaceInfo ws = (WorkspaceInfo) workspace.getObject();
        store.setObject(ws != null ? GeoServerApplication.get().getCatalog().getDefaultDataStore(ws) : null);

        workspaceNameTextField.setVisible(ws == null);
        workspaceNameTextField.setRequired(ws == null);

        if (target != null) {
            target.addComponent(storeChoice);
            target.addComponent(workspaceNameTextField.getParent());
        }
    }

    void updateSourcePanel(Source source, AjaxRequestTarget target) {
        Panel old = (Panel) sourcePanel.get(0);
        if (old != null) {
            sourcePanel.remove(old);
        }

        Panel p = source.createPanel("content");
        sourcePanel.add(p);

        if (target != null) {
            target.addComponent(sourcePanel);
        }
    }

    void resetButtons(Form form, AjaxRequestTarget target) {
        form.get("next").setEnabled(true);
        form.get("cancel").setEnabled(false);
        statusLabel.setDefaultModelObject("");
        statusLabel.add(new SimpleAttributeModifier("class", ""));

        target.addComponent(form.get("next"));
        target.addComponent(form.get("cancel"));
        target.addComponent(form.get("status"));
    }

    class SourceLabelPanel extends Panel {

        public SourceLabelPanel(String id, Source source) {
            super(id);

            add(new Label("name", source.getName(ImportDataPage.this)));
            add(new Label("description", source.getDescription(ImportDataPage.this)));

            Image icon = new Image("icon", source.getIcon());
            icon.add(new AttributeModifier("alt", true, source.getDescription(ImportDataPage.this)));
            add(icon);

            WebMarkupContainer extra = new WebMarkupContainer("extra");
            add(extra);
            extra.add(new ExternalLink("link", source.getHelpLink(ImportDataPage.this)));

            if (!source.isAvailable()) {
                get("name").add(new SimpleAttributeModifier("style", "font-style: italic;"));
                add(new SimpleAttributeModifier("title",
                        "Data source not available. Please " + "install required plugin and drivers."));
            } else {
                extra.setVisible(false);
            }
        }
    }

    /**
     * A type data source.
     */
    enum Source {
        SPATIAL_FILES(DataIcon.FOLDER) {
            @Override
            ImportSourcePanel createPanel(String panelId) {
                return new SpatialFilePanel(panelId);
            }
        },
        MOSAIC(DataIcon.RASTER) {
            @Override
            ImportSourcePanel createPanel(String panelId) {
                return new MosaicPanel(panelId);
            }
        },
        POSTGIS(DataIcon.POSTGIS) {
            @Override
            ImportSourcePanel createPanel(String panelId) {
                return new PostGISPanel(panelId);
            }
        },
        ORACLE(DataIcon.DATABASE) {
            @Override
            ImportSourcePanel createPanel(String panelId) {
                return new OraclePanel(panelId);
            }

            @Override
            boolean isAvailable() {
                return isDataStoreFactoryAvaiable("org.geotools.data.oracle.OracleNGDataStoreFactory");
            }
        },
        SQLSERVER(DataIcon.DATABASE) {
            @Override
            ImportSourcePanel createPanel(String panelId) {
                return new SQLServerPanel(panelId);
            }

            @Override
            boolean isAvailable() {
                return isDataStoreFactoryAvaiable("org.geotools.data.sqlserver.SQLServerDataStoreFactory");
            }
        };

        //        directory(new ResourceReference(GeoServerApplication.class, "img/icons/silk/folder.png"),
        //                DirectoryPage.class, "org.geotools.data.shapefile.ShapefileDataStoreFactory"), // 
        //        postgis(new ResourceReference(GeoServerApplication.class,
        //                "img/icons/geosilk/database_vector.png"), PostGISPage.class,
        //                "org.geotools.data.postgis.PostgisNGDataStoreFactory"), //
        //        oracle(new ResourceReference(GeoServerApplication.class,
        //                "img/icons/geosilk/database_vector.png"), OraclePage.class,
        //                "org.geotools.data.oracle.OracleNGDataStoreFactory"), //
        //        sqlserver(new ResourceReference(GeoServerApplication.class,
        //                "img/icons/geosilk/database_vector.png"), SQLServerPage.class,
        //                "org.geotools.data.sqlserver.SQLServerDataStoreFactory"), //
        //        arcsde(new ResourceReference(GeoServerApplication.class,
        //                "img/icons/geosilk/database_vector.png"), ArcSDEPage.class,
        //                "org.geotools.arcsde.ArcSDEDataStoreFactory");

        DataIcon icon;

        Source(DataIcon icon) {
            this.icon = icon;
        }

        IModel getName(Component component) {
            return new ParamResourceModel(this.name().toLowerCase() + "_name", component);
        }

        IModel getDescription(Component component) {
            return new ParamResourceModel(this.name().toLowerCase() + "_description", component);
        }

        IModel getHelpLink(Component component) {
            return new ParamResourceModel(this.name().toLowerCase() + "_helpLink", component);
        }

        ResourceReference getIcon() {
            return icon.getIcon();
        }

        boolean isAvailable() {
            return true;
        }

        boolean isDataStoreFactoryAvaiable(String className) {
            Class<DataStoreFactorySpi> clazz = null;
            try {
                clazz = (Class<DataStoreFactorySpi>) Class.forName(className);
            } catch (Exception e) {
                if (LOGGER.isLoggable(Level.FINE)) {
                    LOGGER.log(Level.FINE, "DataStore class not available: " + className, e);
                }
            }
            if (clazz == null) {
                return false;
            }

            DataStoreFactorySpi factory = null;
            try {
                factory = clazz.newInstance();
            } catch (Exception e) {
                if (LOGGER.isLoggable(Level.FINE)) {
                    LOGGER.log(Level.FINE, "Error creating DataStore factory: " + className, e);
                }
            }

            if (factory == null) {
                return false;
            }

            return factory.isAvailable();
        }

        abstract ImportSourcePanel createPanel(String panelId);
    }
}