/* (c) 2014 - 2016 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.layergroup; import java.util.List; import java.util.logging.Level; import org.apache.wicket.WicketRuntimeException; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.form.OnChangeAjaxBehavior; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.form.CheckBox; import org.apache.wicket.markup.html.form.DropDownChoice; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.form.TextArea; import org.apache.wicket.markup.html.form.TextField; import org.apache.wicket.model.Model; import org.apache.wicket.model.StringResourceModel; import org.apache.wicket.request.mapper.parameter.PageParameters; import org.apache.wicket.validation.IValidatable; import org.apache.wicket.validation.IValidationError; import org.apache.wicket.validation.IValidator; import org.apache.wicket.validation.ValidationError; import org.geoserver.catalog.Catalog; import org.geoserver.catalog.CatalogBuilder; import org.geoserver.catalog.LayerGroupInfo; import org.geoserver.catalog.WorkspaceInfo; import org.geoserver.web.data.resource.MetadataLinkEditor; import org.geoserver.web.data.workspace.WorkspaceChoiceRenderer; import org.geoserver.web.data.workspace.WorkspacesModel; import org.geoserver.web.publish.PublishedConfigurationPage; import org.geoserver.web.publish.PublishedEditTabPanel; import org.geoserver.web.wicket.EnvelopePanel; import org.geoserver.web.wicket.GeoServerAjaxFormLink; import org.geoserver.web.wicket.ParamResourceModel; import org.opengis.referencing.crs.CoordinateReferenceSystem; /** * Handles layer group */ public class LayerGroupEditPage extends PublishedConfigurationPage<LayerGroupInfo> { private static final long serialVersionUID = 5659874305843575438L; public static final String GROUP = "group"; public static final String WORKSPACE = "workspace"; LayerGroupEntryPanel lgEntryPanel; private CheckBox queryableCheckBox; protected LayerGroupEditPage(boolean isNew) { super(isNew); this.returnPageClass = LayerGroupPage.class; } public LayerGroupEditPage() { this(true); setupPublished(getCatalog().getFactory().createLayerGroup()); postInit(); } public LayerGroupEditPage(PageParameters parameters) { this(false); String groupName = parameters.get(GROUP).toString(); String wsName = parameters.get(WORKSPACE).toOptionalString(); LayerGroupInfo lg = wsName != null ? getCatalog().getLayerGroupByName(wsName, groupName) : getCatalog().getLayerGroupByName(groupName); if(lg == null) { error(new ParamResourceModel("LayerGroupEditPage.notFound", this, groupName).getString()); doReturn(LayerGroupPage.class); return; } setupPublished(lg); postInit(); } private void postInit() { if (!isAuthenticatedAsAdmin() && !isNew) { // global layer groups only editable by full admin if (getPublishedInfo().getWorkspace() == null) { // disable all form components but cancel setInputEnabled(false); info(new StringResourceModel("globalLayerGroupReadOnly", this, null).getString()); } } } public class LayerGroupTab extends PublishedEditTabPanel<LayerGroupInfo> { private static final long serialVersionUID = 2192005814142588155L; public LayerGroupTab(String id) { super(id, myModel); initUI(); } private EnvelopePanel envelopePanel; protected RootLayerEntryPanel rootLayerPanel; @SuppressWarnings("serial") private void initUI() { final WebMarkupContainer rootLayerPanelContainer = new WebMarkupContainer("rootLayerContainer"); rootLayerPanelContainer.setOutputMarkupId(true); add(rootLayerPanelContainer); rootLayerPanel = new RootLayerEntryPanel("rootLayer", getPublishedInfo().getWorkspace(), myModel); rootLayerPanelContainer.add(rootLayerPanel); updateRootLayerPanel(getPublishedInfo().getMode()); TextField<String> name = new TextField<String>("name"); name.setRequired(true); //JD: don't need this, this is validated at the catalog level //name.add(new GroupNameValidator()); add(name); final DropDownChoice<LayerGroupInfo.Mode> modeChoice = new DropDownChoice<LayerGroupInfo.Mode>("mode", new LayerGroupModeModel(), new LayerGroupModeChoiceRenderer()); modeChoice.setNullValid(false); modeChoice.setRequired(true); modeChoice.add(new OnChangeAjaxBehavior() { private static final long serialVersionUID = 8819356789334465887L; @Override protected void onUpdate(AjaxRequestTarget target) { LayerGroupInfo.Mode mode = modeChoice.getModelObject(); updateRootLayerPanel(mode); target.add(rootLayerPanelContainer); } }); add(modeChoice); queryableCheckBox = new CheckBox("queryable", new Model<Boolean>(!getPublishedInfo().isQueryDisabled())); add(queryableCheckBox); add(new TextField<String>("title")); add(new TextArea<String>("abstract")); DropDownChoice<WorkspaceInfo> wsChoice = new DropDownChoice<WorkspaceInfo>("workspace", new WorkspacesModel(), new WorkspaceChoiceRenderer()); wsChoice.setNullValid(true); wsChoice.add(new OnChangeAjaxBehavior() { @Override protected void onUpdate(AjaxRequestTarget target) { // nothing to do really, just wanted to get the state back on the server side // for the chooser dialogs to use } }); if (!isAuthenticatedAsAdmin()) { wsChoice.setNullValid(false); wsChoice.setRequired(true); } add(wsChoice); //bounding box add(envelopePanel = new EnvelopePanel( "bounds" )/*.setReadOnly(true)*/); envelopePanel.setRequired(true); envelopePanel.setCRSFieldVisible(true); envelopePanel.setCrsRequired(true); envelopePanel.setOutputMarkupId( true ); add(new GeoServerAjaxFormLink( "generateBounds") { private static final long serialVersionUID = -5290731459036222837L; @Override public void onClick(AjaxRequestTarget target, Form<?> form) { // build a layer group with the current contents of the group LayerGroupInfo lg = getCatalog().getFactory().createLayerGroup(); for ( LayerGroupEntry entry : lgEntryPanel.getEntries() ) { lg.getLayers().add(entry.getLayer()); lg.getStyles().add(entry.getStyle()); } try { // grab the eventually manually inserted CoordinateReferenceSystem crs = envelopePanel.getCoordinateReferenceSystem(); if ( crs != null ) { //ensure the bounds calculated in terms of the user specified crs new CatalogBuilder( getCatalog() ).calculateLayerGroupBounds( lg, crs ); } else { //calculate from scratch new CatalogBuilder( getCatalog() ).calculateLayerGroupBounds( lg ); } envelopePanel.setModelObject( lg.getBounds() ); target.add( envelopePanel ); } catch (Exception e) { throw new WicketRuntimeException( e ); } } }); add(new GeoServerAjaxFormLink("generateBoundsFromCRS") { private static final long serialVersionUID = -7907583302556368270L; @Override protected void onClick(AjaxRequestTarget target, Form<?> form) { LOGGER.log(Level.FINE, "Computing bounds for LG based off CRS"); LayerGroupInfo lg = getPublishedInfo(); CoordinateReferenceSystem crs = envelopePanel.getCoordinateReferenceSystem(); new CatalogBuilder(getCatalog()).calculateLayerGroupBoundsFromCRS(lg, crs); envelopePanel.modelChanged(); target.add(envelopePanel); } }); add(lgEntryPanel = new LayerGroupEntryPanel( "layers", getPublishedInfo(), wsChoice.getModel())); add(new MetadataLinkEditor("metadataLinks", myModel)); if (!isAuthenticatedAsAdmin()) { if (isNew) { //default to first available workspace List<WorkspaceInfo> ws = getCatalog().getWorkspaces(); if (!ws.isEmpty()) { wsChoice.setModelObject(ws.get(0)); } } else { //always disable the workspace toggle wsChoice.setEnabled(false); } } } private void updateRootLayerPanel(LayerGroupInfo.Mode mode) { rootLayerPanel.setEnabled(LayerGroupInfo.Mode.EO.equals(mode)); rootLayerPanel.setVisible(LayerGroupInfo.Mode.EO.equals(mode)); } class GroupNameValidator implements IValidator<String> { private static final long serialVersionUID = -6621372846640620132L; @Override public void validate(IValidatable<String> validatable) { String name = validatable.getValue(); LayerGroupInfo other = getCatalog().getLayerGroupByName(name); if(other != null && (isNew || !other.getId().equals(getPublishedInfo().getId()))) { IValidationError err = new ValidationError("duplicateGroupNameError") .addKey("duplicateGroupNameError").setVariable("name", name); validatable.error(err); } } } } @Override protected PublishedEditTabPanel<LayerGroupInfo> createMainTab(String panelID) { return new LayerGroupTab(panelID); } @Override protected void doSaveInternal() { // validation if(lgEntryPanel.getEntries().size() == 0) { error((String) new ParamResourceModel("oneLayerMinimum", getPage()).getObject()); return; } LayerGroupInfo lg = getPublishedInfo(); if (!LayerGroupInfo.Mode.EO.equals(lg.getMode())) { lg.setRootLayer(null); lg.setRootLayerStyle(null); } else { if (lg.getRootLayerStyle() == null && lg.getRootLayer() != null) { lg.setRootLayerStyle(lg.getRootLayer().getDefaultStyle()); } } // update the layer group entries lg.getLayers().clear(); lg.getStyles().clear(); for ( LayerGroupEntry entry : lgEntryPanel.getEntries() ) { lg.getLayers().add(entry.getLayer()); lg.getStyles().add(entry.getStyle()); } // update not queryable flag Boolean queryable = queryableCheckBox.getModelObject(); lg.setQueryDisabled(!queryable); try { Catalog catalog = getCatalog(); if (isNew) { catalog.add(lg); } else { catalog.save( lg ); } } catch(Exception e) { error(e); LOGGER.log(Level.WARNING, "Error adding/modifying layer group.", e); } } }