/* (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.store; import java.io.IOException; import java.io.Serializable; import java.util.List; import java.util.logging.Level; import org.apache.wicket.Component; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.request.mapper.parameter.PageParameters; import org.geoserver.catalog.Catalog; import org.geoserver.catalog.DataStoreInfo; import org.geoserver.catalog.FeatureTypeInfo; import org.geoserver.catalog.NamespaceInfo; import org.geoserver.catalog.ResourcePool; import org.geoserver.web.wicket.GeoServerDialog; import org.geoserver.web.wicket.ParamResourceModel; import org.geotools.data.DataAccess; import org.opengis.feature.Feature; import org.opengis.feature.type.FeatureType; /** * Provides a form to edit a geotools {@link DataAccess} that already exists in the {@link Catalog} * * @author Gabriel Roldan */ public class DataAccessEditPage extends AbstractDataAccessPage implements Serializable { public static final String STORE_NAME = "storeName"; public static final String WS_NAME = "wsName"; /** * Dialog to ask for save confirmation in case the store can't be reached */ private GeoServerDialog dialog; /** * Uses a "name" parameter to locate the datastore * @param parameters */ public DataAccessEditPage(PageParameters parameters) { String wsName = parameters.get(WS_NAME).toOptionalString(); String storeName = parameters.get(STORE_NAME).toString(); DataStoreInfo dsi = getCatalog().getDataStoreByName(wsName, storeName); if(dsi == null) { getSession().error( new ParamResourceModel("DataAccessEditPage.notFound", this, wsName, storeName).getString() ); doReturn(StorePage.class); return; } try { initUI(dsi); } catch (IllegalArgumentException e) { error(e.getMessage()); doReturn(StorePage.class); return; } } /** * Creates a new datastore configuration page to edit the properties of the given data store * * @param dataStoreInfoId * the datastore id to modify, as per {@link DataStoreInfo#getId()} */ public DataAccessEditPage(final String dataStoreInfoId) throws IllegalArgumentException { final Catalog catalog = getCatalog(); final DataStoreInfo dataStoreInfo = catalog.getDataStore(dataStoreInfoId); if (null == dataStoreInfo) { throw new IllegalArgumentException("DataStore " + dataStoreInfoId + " not found"); } initUI(dataStoreInfo); } /** * Creates a new edit page directly from a store object. */ public DataAccessEditPage(DataStoreInfo store) { initUI(store); } protected void initUI(final DataStoreInfo dataStoreInfo) { // the confirm dialog dialog = new GeoServerDialog("dialog"); add(dialog); super.initUI(dataStoreInfo); if (dataStoreInfo.getId() != null) { //null id means detached from catalog, don't bother with uniqueness check final String wsId = dataStoreInfo.getWorkspace().getId(); workspacePanel.getFormComponent().add( new CheckExistingResourcesInWorkspaceValidator(dataStoreInfo.getId(), wsId)); } } /** * Callback method called when the submit button have been hit and the parameters validation has * succeed. * * @param paramsForm * the form to report any error to * @see AbstractDataAccessPage#onSaveDataStore(Form) */ protected final void onSaveDataStore(final DataStoreInfo info, final AjaxRequestTarget requestTarget) { if(!storeEditPanel.onSave()) { return; } final Catalog catalog = getCatalog(); final ResourcePool resourcePool = catalog.getResourcePool(); resourcePool.clear(info); if (info.isEnabled()) { // store's enabled, check availability DataAccess<? extends FeatureType, ? extends Feature> dataStore; try { dataStore = catalog.getResourcePool().getDataStore(info); LOGGER.finer("connection parameters verified for store " + info.getName() + ". Got a " + dataStore.getClass().getName()); doSaveStore(info); doReturn(StorePage.class); } catch (IOException e) { LOGGER.log(Level.WARNING, "Error obtaining datastore with the modified values", e); confirmSaveOnConnectionFailure(info, requestTarget, e); } catch (RuntimeException e) { LOGGER.log(Level.WARNING, "Error obtaining datastore with the modified values", e); confirmSaveOnConnectionFailure(info, requestTarget, e); } } else { // store's disabled, no need to check the connection parameters doSaveStore(info); doReturn(StorePage.class); } } @SuppressWarnings("serial") private void confirmSaveOnConnectionFailure(final DataStoreInfo info, final AjaxRequestTarget requestTarget, final Exception error) { getCatalog().getResourcePool().clear(info); final String exceptionMessage; { String message = error.getMessage(); if (message == null && error.getCause() != null) { message = error.getCause().getMessage(); } exceptionMessage = message; } dialog.showOkCancel(requestTarget, new GeoServerDialog.DialogDelegate() { boolean accepted = false; @Override protected Component getContents(String id) { return new StoreConnectionFailedInformationPanel(id, info.getName(), exceptionMessage); } @Override protected boolean onSubmit(AjaxRequestTarget target, Component contents) { doSaveStore(info); accepted = true; return true; } @Override protected boolean onCancel(AjaxRequestTarget target) { return true; } @Override public void onClose(AjaxRequestTarget target) { if (accepted) { doReturn(StorePage.class); } } }); } /** * Performs the save of the store. * <p> * This method may be subclasses to provide custom save functionality. * </p> */ protected void doSaveStore(final DataStoreInfo info) { try { final Catalog catalog = getCatalog(); // The namespace may have changed, in which case we need to update the store resources NamespaceInfo namespace = catalog.getNamespaceByPrefix(info.getWorkspace().getName()); List<FeatureTypeInfo> configuredResources = catalog.getResourcesByStore(info, FeatureTypeInfo.class); for (FeatureTypeInfo alreadyConfigured : configuredResources) { alreadyConfigured.setNamespace(namespace); } ResourcePool resourcePool = catalog.getResourcePool(); resourcePool.clear(info); DataStoreInfo expandedStore = catalog.getResourcePool().clone(info, true); // Cloning into "expandedStore" through the super class "clone" method catalog.validate(expandedStore, false).throwIfInvalid(); catalog.save(info); // save the resources after saving the store for (FeatureTypeInfo alreadyConfigured : configuredResources) { catalog.save(alreadyConfigured); } LOGGER.finer("Saved store " + info.getName()); } catch (Exception e) { LOGGER.log(Level.WARNING, "Error saving data store to catalog", e); throw new IllegalArgumentException("Error saving data store:" + e.getMessage()); } } }