org.geogig.geoserver.web.repository.RepositoryEditFormPanel.java Source code

Java tutorial

Introduction

Here is the source code for org.geogig.geoserver.web.repository.RepositoryEditFormPanel.java

Source

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

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.annotation.Nullable;

import org.apache.wicket.Component;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.ResourceModel;
import org.geogig.geoserver.config.RepositoryInfo;
import org.geogig.geoserver.config.RepositoryManager;
import org.locationtech.geogig.plumbing.TransactionBegin;
import org.locationtech.geogig.porcelain.ConfigOp;
import org.locationtech.geogig.porcelain.ConfigOp.ConfigAction;
import org.locationtech.geogig.porcelain.ConfigOp.ConfigScope;
import org.locationtech.geogig.porcelain.RemoteAddOp;
import org.locationtech.geogig.porcelain.RemoteListOp;
import org.locationtech.geogig.porcelain.RemoteRemoveOp;
import org.locationtech.geogig.repository.Context;
import org.locationtech.geogig.repository.IndexInfo;
import org.locationtech.geogig.repository.Remote;
import org.locationtech.geogig.repository.Repository;
import org.locationtech.geogig.repository.impl.GeogigTransaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

/**
 */
public abstract class RepositoryEditFormPanel extends Panel {

    private static final long serialVersionUID = -9001389048321749075L;

    private static final Logger LOGGER = LoggerFactory.getLogger(RepositoryEditFormPanel.class);

    private RemotesListPanel remotes;

    private ConfigListPanel localConfig;

    private ConfigListPanel globalConfig;

    private IndexListPanel indexes;

    private ModalWindow popupWindow;

    private Form<RepositoryInfo> form;

    private boolean isNew = false;

    public RepositoryEditFormPanel(final String id) {
        this(id, null);
    }

    public RepositoryEditFormPanel(final String id, @Nullable IModel<RepositoryInfo> repoInfo) {
        super(id);
        isNew = repoInfo == null;
        if (isNew) {
            repoInfo = new Model<>(new RepositoryInfo());
        }
        setDefaultModel(repoInfo);

        popupWindow = new ModalWindow("popupWindow");
        add(popupWindow);

        form = new Form<>("repoForm", repoInfo);
        form.add(new RepositoryEditPanel("repo", repoInfo, isNew));

        form.add(addRemoteLink());
        List<RemoteInfo> remoteInfos = loadRemoteInfos(repoInfo.getObject());
        form.add(remotes = new RemotesListPanel("remotes", remoteInfos));

        form.add(addConfigLink(false));
        Map<String, String> localConfigMap = loadConfig(repoInfo.getObject(), false);
        form.add(localConfig = new ConfigListPanel("localConfig", localConfigMap));

        form.add(addConfigLink(true));
        Map<String, String> globalConfigMap = loadConfig(repoInfo.getObject(), true);
        form.add(globalConfig = new ConfigListPanel("globalConfig", globalConfigMap));

        List<IndexInfo> indexInfos = loadIndexes(repoInfo.getObject());
        form.add(indexes = new IndexListPanel("indexes", indexInfos));

        add(form);
        FeedbackPanel feedback = new FeedbackPanel("feedback");
        form.add(feedback);

        form.add(new AjaxLink<Void>("cancel") {
            private static final long serialVersionUID = 6220299771769708060L;

            @Override
            public void onClick(AjaxRequestTarget target) {
                cancelled(target);
            }
        });

        form.add(new AjaxSubmitLink("save", form) {
            private static final long serialVersionUID = 1L;

            @Override
            protected void onError(AjaxRequestTarget target, Form<?> form) {
                super.onError(target, form);
                target.add(form);
            }

            @Override
            protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
                try {
                    RepositoryInfo repoInfo = (RepositoryInfo) form.getModelObject();
                    onSave(repoInfo, target);
                } catch (IllegalArgumentException e) {
                    form.error(e.getMessage());
                    target.add(form);
                }
            }
        });
    }

    private List<RemoteInfo> loadRemoteInfos(RepositoryInfo repo) {
        String repoId = repo.getId();
        if (null == repoId) {
            return new ArrayList<>();
        }

        ArrayList<RemoteInfo> list = new ArrayList<>();
        Repository geogig;
        try {
            geogig = RepositoryManager.get().getRepository(repoId);
            if (geogig != null) {
                ImmutableList<Remote> geogigRemotes = geogig.command(RemoteListOp.class).call();
                list = RemoteInfo.fromList(geogigRemotes);
            }
        } catch (Exception e) {
            LOGGER.warn("Failed to load Remotes for repository", e);
        }

        return list;
    }

    private Map<String, String> loadConfig(RepositoryInfo repo, boolean global) {
        String repoId = repo.getId();
        if (null == repoId) {
            return Maps.newHashMap();
        }

        Repository geogig;
        try {
            geogig = RepositoryManager.get().getRepository(repoId);
            if (geogig != null) {
                Optional<Map<String, String>> config = geogig.command(ConfigOp.class)//
                        .setAction(ConfigAction.CONFIG_LIST)//
                        .setScope(global ? ConfigScope.GLOBAL : ConfigScope.LOCAL)//
                        .call();
                if (config.isPresent()) {
                    return config.get();
                }
            }
        } catch (Exception e) {
            LOGGER.warn("Failed to load config for repository", e);
        }

        return Maps.newHashMap();
    }

    private List<IndexInfo> loadIndexes(RepositoryInfo repo) {
        String repoId = repo.getId();
        if (null == repoId) {
            return Lists.newArrayList();
        }

        Repository geogig;
        try {
            geogig = RepositoryManager.get().getRepository(repoId);
            return geogig.indexDatabase().getIndexInfos();
        } catch (Exception e) {
            LOGGER.warn("Failed to load indexes for repository", e);
        }

        return Lists.newArrayList();
    }

    private Component addRemoteLink() {
        return new AjaxLink<Void>("addRemote") {

            private static final long serialVersionUID = 1L;

            @Override
            public void onClick(AjaxRequestTarget target) {
                RemoteInfo ri = new RemoteInfo();
                IModel<RemoteInfo> model = new Model<>(ri);
                RemotesListPanel table = RepositoryEditFormPanel.this.remotes;
                RemoteEditPanel editPanel = new RemoteEditPanel(popupWindow.getContentId(), model, popupWindow,
                        table);

                popupWindow.setContent(editPanel);
                popupWindow.setTitle(new ResourceModel("RemoteEditPanel.title"));
                popupWindow.show(target);
            }
        };
    }

    private Component addConfigLink(boolean global) {
        return new AjaxLink<Void>(global ? "addGlobalConfig" : "addLocalConfig") {

            private static final long serialVersionUID = 1L;

            @Override
            public void onClick(AjaxRequestTarget target) {
                ConfigEntry config = new ConfigEntry();
                IModel<ConfigEntry> model = new Model<>(config);
                ConfigListPanel table = global ? RepositoryEditFormPanel.this.globalConfig
                        : RepositoryEditFormPanel.this.localConfig;
                ConfigEditPanel editPanel = new ConfigEditPanel(popupWindow.getContentId(), model, popupWindow,
                        table);

                popupWindow.setContent(editPanel);
                popupWindow.setTitle(new ResourceModel("ConfigEditPanel.title"));
                popupWindow.show(target);
            }
        };
    }

    private void onSave(RepositoryInfo repoInfo, AjaxRequestTarget target) {
        RepositoryManager manager = RepositoryManager.get();
        // update remotes
        Repository geogig;
        try {
            repoInfo = manager.save(repoInfo);
            geogig = manager.getRepository(repoInfo.getId());
        } catch (Exception e) {
            form.error("Unable to connect to repository " + repoInfo.getLocation() + "\n" + e.getMessage());
            target.add(form);
            return;
        }

        Function<RemoteInfo, Integer> keyFunction = new Function<RemoteInfo, Integer>() {
            @Override
            public Integer apply(RemoteInfo r) {
                return r.getId();
            }
        };

        Map<Integer, RemoteInfo> currentRemotes = new HashMap<>(
                Maps.uniqueIndex(loadRemoteInfos(repoInfo), keyFunction));

        Set<RemoteInfo> newRemotes = Sets.newHashSet(remotes.getRemotes());
        if (!currentRemotes.isEmpty() || !newRemotes.isEmpty()) {
            GeogigTransaction tx = geogig.command(TransactionBegin.class).call();
            try {
                updateRemotes(tx, currentRemotes, newRemotes);
                tx.commit();
            } catch (Exception e) {
                try {
                    tx.abort();
                } finally {
                    form.error(e.getMessage());
                    target.add(form);
                }
                return;
            }
        }
        Map<String, String> currentLocalConfig = loadConfig(repoInfo, false);
        updateConfig(geogig.context(), currentLocalConfig, Lists.newArrayList(localConfig.getConfigs()), false);
        Map<String, String> currentGlobalConfig = loadConfig(repoInfo, true);
        updateConfig(geogig.context(), currentGlobalConfig, Lists.newArrayList(globalConfig.getConfigs()), true);
        saved(repoInfo, target);
    }

    private void updateRemotes(Context geogig, Map<Integer, RemoteInfo> currentRemotes, Set<RemoteInfo> newRemotes)
            throws Exception {

        // handle deletes first, in case a remote was deleted in the table and then a new one added
        // with the same name
        {
            Map<Integer, RemoteInfo> remaining = new HashMap<>();
            for (RemoteInfo ri : newRemotes) {
                if (ri.getId() != null) {
                    remaining.put(ri.getId(), ri);
                }
            }

            for (RemoteInfo deleted : currentRemotes.values()) {
                if (!remaining.containsKey(deleted.getId())) {
                    String name = deleted.getName();
                    try {
                        geogig.command(RemoteRemoveOp.class).setName(name).call();
                    } catch (RuntimeException e) {
                        throw new RuntimeException("Error deleting remote " + name, e);
                    }
                }
            }
        }

        for (RemoteInfo ri : newRemotes) {
            if (ri.getId() == null) {// its a new one
                RemoteAddOp cmd = geogig.command(RemoteAddOp.class);
                cmd.setName(ri.getName());
                cmd.setURL(ri.getURL());
                cmd.setUserName(ri.getUserName());
                cmd.setPassword(ri.getPassword());
                try {
                    cmd.call();
                } catch (RuntimeException e) {
                    throw new RuntimeException("Error adding remote " + ri.getName() + ": " + e.getMessage(), e);
                }
            } else {
                // handle upadtes
                RemoteInfo old = currentRemotes.remove(ri.getId());
                Preconditions.checkNotNull(old);
                if (old.equals(ri)) {
                    continue;// didn't change
                }
                try {
                    geogig.command(RemoteRemoveOp.class).setName(old.getName()).call();
                    RemoteAddOp addop = geogig.command(RemoteAddOp.class);
                    addop.setName(ri.getName()).setURL(ri.getURL()).setUserName(ri.getUserName())
                            .setPassword(ri.getPassword());
                    addop.call();
                } catch (RuntimeException e) {
                    throw new RuntimeException("Error updating remote " + ri.getName() + ": " + e.getMessage(), e);
                }

            }
        }
    }

    private void updateConfig(Context geogig, Map<String, String> currentConfig, List<ConfigEntry> newConfig,
            boolean global) {
        ConfigScope scope = global ? ConfigScope.GLOBAL : ConfigScope.LOCAL;
        for (ConfigEntry entry : newConfig) {
            if (currentConfig.containsKey(entry.getName())) {
                if (!currentConfig.get(entry.getName()).equals(entry.getValue())) {
                    // entry changed
                    geogig.command(ConfigOp.class)//
                            .setAction(ConfigAction.CONFIG_SET)//
                            .setName(entry.getName())//
                            .setValue(entry.getValue())//
                            .setScope(scope)//
                            .call();
                }
                currentConfig.remove(entry.getName());
            } else {
                // new entry
                geogig.command(ConfigOp.class)//
                        .setAction(ConfigAction.CONFIG_SET)//
                        .setName(entry.getName())//
                        .setValue(entry.getValue())//
                        .setScope(scope)//
                        .call();
            }
        }
        if (!isNew) {
            for (Entry<String, String> entry : currentConfig.entrySet()) {
                // removed entry
                geogig.command(ConfigOp.class)//
                        .setAction(ConfigAction.CONFIG_UNSET)//
                        .setName(entry.getKey())//
                        .setScope(scope)//
                        .call();
            }
        }
    }

    protected abstract void saved(RepositoryInfo info, AjaxRequestTarget target);

    protected abstract void cancelled(AjaxRequestTarget target);
}