Package org.geoserver.web.data.resource

Source Code of org.geoserver.web.data.resource.ResourceConfigurationPage

/* (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.web.data.resource;

import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map.Entry;
import java.util.logging.Level;

import org.apache.wicket.Component;
import org.apache.wicket.PageParameters;
import org.apache.wicket.WicketRuntimeException;
import org.apache.wicket.extensions.markup.html.tabs.AbstractTab;
import org.apache.wicket.extensions.markup.html.tabs.ITab;
import org.apache.wicket.extensions.markup.html.tabs.TabbedPanel;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.SubmitLink;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.CompoundPropertyModel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.CoverageInfo;
import org.geoserver.catalog.LayerInfo;
import org.geoserver.catalog.NamespaceInfo;
import org.geoserver.catalog.ProjectionPolicy;
import org.geoserver.catalog.ResourceInfo;
import org.geoserver.web.ComponentAuthorizer;
import org.geoserver.web.GeoServerApplication;
import org.geoserver.web.GeoServerSecuredPage;
import org.geoserver.web.data.layer.LayerPage;
import org.geoserver.web.publish.LayerConfigurationPanel;
import org.geoserver.web.publish.LayerConfigurationPanelInfo;
import org.geoserver.web.wicket.ParamResourceModel;
import org.geotools.coverage.grid.GridGeometry2D;
import org.geotools.coverage.grid.io.GridCoverage2DReader;
import org.geotools.factory.GeoTools;
import org.geotools.feature.NameImpl;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.opengis.coverage.grid.GridGeometry;

/**
* Page allowing to configure a layer and its resource.
* <p>
* The page is completely pluggable, the UI will be made up by scanning the Spring context for
* implementations of {@link ResourceConfigurationPanel} and {@link LayerConfigurationPanel}.
* <p>
* WARNING: one crucial aspect of this page is its ability to not loose edits when one switches from
* one tab to the other. I did not find any effective way to unit test this, so _please_, if you do
* modify anything in this class (especially the models), manually retest that the edits are not
* lost on tab switch.
*/
@SuppressWarnings({"serial", "rawtypes", "unchecked" })
public class ResourceConfigurationPage extends GeoServerSecuredPage {

    private static final long serialVersionUID = 7870938096047218989L;

    public static final String NAME = "name";

    public static final String WORKSPACE = "wsName";

    private IModel myResourceModel;

    private IModel myLayerModel;

    private boolean isNew;

    private TabbedPanel tabbedPanel;

    /**
     * {@link LayerEditTabPanel} contributions may need to edit something different than the
     * LayerInfo and ResourceInfo this page holds models to. In such cases
     * {@link LayerEditTabPanelInfo#createOwnModel} will return a non null model and well pass it
     * back to the concrete LayerEditTabPanel constructor. This is so because LayerEditTabPanel are
     * re-created everytime the user switches tabs.
     */
    private LinkedHashMap<Class<? extends LayerEditTabPanel>, IModel<?>> tabPanelCustomModels;

    public ResourceConfigurationPage(PageParameters parameters) {
        this(parameters.getString(WORKSPACE), parameters.getString(NAME));
    }

    public ResourceConfigurationPage(String workspaceName, String layerName) {
        LayerInfo layer;
        if (workspaceName != null) {
            NamespaceInfo ns = getCatalog().getNamespaceByPrefix(workspaceName);
            if (ns == null) {
                // unlikely to happen, requires someone making modifications on the workspaces
                // with a layer page open in another tab/window
                throw new RuntimeException("Could not find workspace " + workspaceName);
            }
            String nsURI = ns.getURI();
            layer = getCatalog().getLayerByName(new NameImpl(nsURI, layerName));
        } else {
            layer = getCatalog().getLayerByName(layerName);
        }

        if (layer == null) {
            error(new ParamResourceModel("ResourceConfigurationPage.notFound", this, layerName)
                    .getString());
            setResponsePage(returnPage);
            return;
        }

        setup(getCatalog().getResource(layer.getResource().getId(), ResourceInfo.class), layer);
        this.isNew = false;
        initComponents();
    }

    public ResourceConfigurationPage(ResourceInfo info, boolean isNew) {
        setup(info, getCatalog().getLayers(info).get(0));
        this.isNew = isNew;
        initComponents();
    }

    public ResourceConfigurationPage(LayerInfo info, boolean isNew) {
        setup(info.getResource(), info);
        this.isNew = isNew;
        initComponents();
    }

    private void setup(ResourceInfo resource, LayerInfo layer) {
        layer.setResource(resource);
        myResourceModel = new CompoundPropertyModel(new ResourceModel(resource));
        myLayerModel = new CompoundPropertyModel(new LayerModel(layer));
    }

    /**
     *
     */
    private void initComponents() {
        this.returnPageClass = LayerPage.class;
        this.tabPanelCustomModels = new LinkedHashMap<Class<? extends LayerEditTabPanel>, IModel<?>>();

        add(new Label("resourcename", getResourceInfo().getPrefixedName()));
        Form theForm = new Form("resource", myResourceModel);
        add(theForm);

        List<ITab> tabs = new ArrayList<ITab>();

        // add the "well known" tabs
        tabs.add(new AbstractTab(new org.apache.wicket.model.ResourceModel(
                "ResourceConfigurationPage.Data")) {

            public Panel getPanel(String panelID) {
                return new DataLayerEditTabPanel(panelID, myLayerModel);
            }
        });
        tabPanelCustomModels.put(DataLayerEditTabPanel.class, null);
       
        tabs.add(new AbstractTab(new org.apache.wicket.model.ResourceModel(
                "ResourceConfigurationPage.Publishing")) {

            public Panel getPanel(String panelID) {
                return new PublishingLayerEditTabPanel(panelID, myLayerModel);
            }
        });
        tabPanelCustomModels.put(PublishingLayerEditTabPanel.class, null);

        // add the tabs contributed via extension point
        List<LayerEditTabPanelInfo> tabPanels = getGeoServerApplication().getBeansOfType(
                LayerEditTabPanelInfo.class);

        // sort the tabs based on order
        Collections.sort(tabPanels, new Comparator<LayerEditTabPanelInfo>() {
            public int compare(LayerEditTabPanelInfo o1, LayerEditTabPanelInfo o2) {
                Integer order1 = o1.getOrder() >= 0 ? o1.getOrder() : Integer.MAX_VALUE;
                Integer order2 = o2.getOrder() >= 0 ? o2.getOrder() : Integer.MAX_VALUE;

                return order1.compareTo(order2);
            }
        });

        for (LayerEditTabPanelInfo tabPanelInfo : tabPanels) {
            String titleKey = tabPanelInfo.getTitleKey();
            IModel titleModel = null;
            if (titleKey != null) {
                titleModel = new org.apache.wicket.model.ResourceModel(titleKey);
            } else {
                titleModel = new Model(tabPanelInfo.getComponentClass().getSimpleName());
            }
           
            final Class<LayerEditTabPanel> panelClass = tabPanelInfo.getComponentClass();
            IModel<?> panelCustomModel = tabPanelInfo.createOwnModel(myResourceModel, myLayerModel, isNew);
            tabPanelCustomModels.put(panelClass, panelCustomModel);
           
            tabs.add(new AbstractTab(titleModel) {
                private final Class<LayerEditTabPanel> panelType = panelClass;
                @Override
                public Panel getPanel(String panelId) {
                    LayerEditTabPanel tabPanel;
                    final IModel<?> panelCustomModel = tabPanelCustomModels.get(panelType);
                    try {
                        // if this tab needs a custom model instead of just our layer model, then
                        // let it create it once
                        if (panelCustomModel == null) {
                            tabPanel = panelClass.getConstructor(String.class, IModel.class)
                                    .newInstance(panelId, myLayerModel);
                        } else {
                            tabPanel = panelClass.getConstructor(String.class, IModel.class,
                                    IModel.class).newInstance(panelId, myLayerModel,
                                    panelCustomModel);
                        }
                    } catch (Exception e) {
                        throw new WicketRuntimeException(e);
                        // LOGGER.log(Level.WARNING, "Error creating resource panel", e);
                    }
                    return tabPanel;
                }
            });
        }

        // we need to override with submit links so that the various form
        // element
        // will validate and write down into their
        tabbedPanel = new TabbedPanel("tabs", tabs) {
            @Override
            protected WebMarkupContainer newLink(String linkId, final int index) {
                return new SubmitLink(linkId) {
                    @Override
                    public void onSubmit() {
                        setSelectedTab(index);
                    }
                };
            }
        };
        theForm.add(tabbedPanel);
        theForm.add(saveLink());
        theForm.add(cancelLink());
    }

    public void setSelectedTab(Class<? extends LayerEditTabPanel> selectedTabClass) {
        int selectedTabIndex;
        //relying on LinkedHashMap here
        selectedTabIndex = new ArrayList<Class<? extends LayerEditTabPanel>>(
                tabPanelCustomModels.keySet()).indexOf(selectedTabClass);
        if (selectedTabIndex > -1) {
            tabbedPanel.setSelectedTab(selectedTabIndex);
        }
    }

    private SubmitLink saveLink() {
        return new SubmitLink("save") {
            @Override
            public void onSubmit() {
                doSave();
            }
        };
    }

    /**
     * Performs the necessary operation on save.
     * <p>
     * This implementation adds the necessary objects to the catalog, respecting the isNew flag, and
     * calls {@link #onSuccessfulSave()} upon success.
     * </p>
     */
    protected void doSave() {
        try {
            Catalog catalog = getCatalog();
            ResourceInfo resourceInfo = getResourceInfo();
            if (isNew) {
                // updating grid if is a coverage
                if (resourceInfo instanceof CoverageInfo) {
                    // the coverage bounds computation path is a bit more linear, the
                    // readers always return the bounds and in the proper CRS (afaik)
                    CoverageInfo cinfo = (CoverageInfo) resourceInfo;
                    GridCoverage2DReader reader = (GridCoverage2DReader) cinfo
                            .getGridCoverageReader(null, GeoTools.getDefaultHints());

                    // get bounds
                    final ReferencedEnvelope bounds = new ReferencedEnvelope(
                            reader.getOriginalEnvelope());
                    // apply the bounds, taking into account the reprojection policy if need be
                    final ProjectionPolicy projectionPolicy = resourceInfo.getProjectionPolicy();
                    if (projectionPolicy != ProjectionPolicy.NONE && bounds != null) {
                        // we need to fix the registered grid for this coverage
                        final GridGeometry grid = cinfo.getGrid();
                        cinfo.setGrid(new GridGeometry2D(grid.getGridRange(), grid.getGridToCRS(),
                                resourceInfo.getCRS()));
                    }
                }

                catalog.validate(resourceInfo, true).throwIfInvalid();
                catalog.add(resourceInfo);
                try {
                    catalog.add(getLayerInfo());
                } catch (IllegalArgumentException e) {
                    catalog.remove(resourceInfo);
                    throw e;
                }
            } else {
                ResourceInfo oldState = catalog.getResource(resourceInfo.getId(),
                        ResourceInfo.class);
               
                catalog.validate(resourceInfo, true).throwIfInvalid();
                catalog.save(resourceInfo);
                try {
                    LayerInfo layer = getLayerInfo();
                    layer.setResource(resourceInfo);
                    catalog.save(layer);
                } catch (IllegalArgumentException e) {
                    catalog.save(oldState);
                    throw e;
                }
            }
           
            for(Entry<Class<? extends LayerEditTabPanel>, IModel<?>> e : tabPanelCustomModels.entrySet()){
                Class<? extends LayerEditTabPanel> panelClass = e.getKey();
                IModel<?> customModel = e.getValue();
                if(customModel == null){
                    continue;
                }
                LayerEditTabPanel tabPanel = panelClass.getConstructor(String.class, IModel.class,
                        IModel.class).newInstance("temp", myLayerModel, customModel);
                tabPanel.save();
            }
           
            onSuccessfulSave();
        } catch (Exception e) {
            LOGGER.log(Level.INFO, "Error saving layer", e);
            error(e.getMessage());
        }
    }

    private Link cancelLink() {
        return new Link("cancel") {

            @Override
            public void onClick() {
                onCancel();
            }
        };
    }

    private List<ResourceConfigurationPanelInfo> filterResourcePanels(
            List<ResourceConfigurationPanelInfo> list) {
        for (int i = 0; i < list.size(); i++) {
            if (!list.get(i).canHandle(getResourceInfo())) {
                list.remove(i);
                i--;
            }
        }
        return list;
    }

    private List<LayerConfigurationPanelInfo> filterLayerPanels(
            List<LayerConfigurationPanelInfo> list) {
        for (int i = 0; i < list.size(); i++) {
            if (!list.get(i).canHandle(getLayerInfo())) {
                list.remove(i);
                i--;
            }
        }
        return list;
    }

    private abstract class ListLayerEditTabPanel extends LayerEditTabPanel {

        public ListLayerEditTabPanel(String id, IModel model) {
            super(id, model);

            ListView list = createList("theList");

            // do this or die on validation (the form element contents will
            // reset, the edit will be lost)
            list.setReuseItems(true);
            add(list);
        }

        protected abstract ListView createList(String id);

    }

    private class DataLayerEditTabPanel extends ListLayerEditTabPanel {

        public DataLayerEditTabPanel(String id, IModel model) {
            super(id, model);
        }

        protected ListView createList(String id) {
            List dataPanels = filterResourcePanels(((GeoServerApplication) getGeoServerApplication())
                    .getBeansOfType(ResourceConfigurationPanelInfo.class));
            ListView dataPanelList = new ListView(id, dataPanels) {
                @Override
                protected void populateItem(ListItem item) {
                    ResourceConfigurationPanelInfo panelInfo = (ResourceConfigurationPanelInfo) item
                            .getModelObject();
                    try {
                        final Class<ResourceConfigurationPanel> componentClass = panelInfo
                                .getComponentClass();
                        final Constructor<ResourceConfigurationPanel> constructor;
                        constructor = componentClass.getConstructor(String.class, IModel.class);
                        ResourceConfigurationPanel panel = constructor.newInstance("content",
                                myResourceModel);
                        item.add((Component) panel);
                    } catch (Exception e) {
                        throw new WicketRuntimeException(
                                "Failed to add pluggable resource configuration panels", e);
                    }
                }
            };
            return dataPanelList;
        }

    }

    private class PublishingLayerEditTabPanel extends ListLayerEditTabPanel {
        private static final long serialVersionUID = -6575960326680386479L;

        public PublishingLayerEditTabPanel(String id, IModel model) {
            super(id, model);
        }

        @Override
        public ListView createList(String id) {
            List pubPanels = filterLayerPanels(((GeoServerApplication) getGeoServerApplication())
                    .getBeansOfType(LayerConfigurationPanelInfo.class));
            ListView pubPanelList = new ListView(id, pubPanels) {
                @Override
                protected void populateItem(ListItem item) {
                    LayerConfigurationPanelInfo panelInfo = (LayerConfigurationPanelInfo) item
                            .getModelObject();
                    try {
                        LayerConfigurationPanel panel = panelInfo.getComponentClass()
                                .getConstructor(String.class, IModel.class)
                                .newInstance("content", myLayerModel);
                        item.add((Component) panel);
                    } catch (Exception e) {
                        throw new WicketRuntimeException(
                                "Failed to add pluggable layer configuration panels", e);
                    }
                }
            };
            return pubPanelList;
        }

    }

    /**
     * Returns the {@link ResourceInfo} contained in this page
     *
     * @return
     */
    public ResourceInfo getResourceInfo() {
        return (ResourceInfo) myResourceModel.getObject();
    }

    /**
     * Returns the {@link LayerInfo} contained in this page
     *
     * @return
     */
    public LayerInfo getLayerInfo() {
        return (LayerInfo) myLayerModel.getObject();
    }

    /**
     * By default brings back the user to LayerPage, subclasses can override this behavior
     */
    protected void onSuccessfulSave() {
        doReturn();
    }

    /**
     * By default brings back the user to LayerPage, subclasses can override this behavior
     */
    protected void onCancel() {
        doReturn();
    }

    /**
     * Allows collaborating pages to update the resource info object
     *
     * @param info
     */
    public void updateResource(ResourceInfo info) {
        myResourceModel.setObject(info);
    }

    /**
     * Allows collaborating pages to update the layer info object
     *
     * @param info
     */
    public void updateLayer(LayerInfo info) {
        myLayerModel.setObject(info);
    }

    @Override
    protected ComponentAuthorizer getPageAuthorizer() {
        return ComponentAuthorizer.WORKSPACE_ADMIN;
    }
}
TOP

Related Classes of org.geoserver.web.data.resource.ResourceConfigurationPage

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.