/* (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.arcsde; import static org.geoserver.web.data.store.arcsde.RasterTableSelectionPanel.TABLE_NAME; import static org.geotools.arcsde.ArcSDEDataStoreFactory.INSTANCE_PARAM; import static org.geotools.arcsde.ArcSDEDataStoreFactory.PASSWORD_PARAM; import static org.geotools.arcsde.ArcSDEDataStoreFactory.PORT_PARAM; import static org.geotools.arcsde.ArcSDEDataStoreFactory.SERVER_PARAM; import static org.geotools.arcsde.ArcSDEDataStoreFactory.USER_PARAM; import static org.geotools.arcsde.session.ArcSDEConnectionConfig.INSTANCE_NAME_PARAM_NAME; import static org.geotools.arcsde.session.ArcSDEConnectionConfig.PASSWORD_PARAM_NAME; import static org.geotools.arcsde.session.ArcSDEConnectionConfig.PORT_NUMBER_PARAM_NAME; import static org.geotools.arcsde.session.ArcSDEConnectionConfig.SERVER_NAME_PARAM_NAME; import static org.geotools.arcsde.session.ArcSDEConnectionConfig.USER_NAME_PARAM_NAME; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.logging.Logger; import org.apache.wicket.AttributeModifier; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.form.OnChangeAjaxBehavior; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.form.ChoiceRenderer; import org.apache.wicket.markup.html.form.DropDownChoice; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.form.FormComponent; import org.apache.wicket.markup.html.form.validation.IFormValidator; import org.apache.wicket.model.IModel; import org.apache.wicket.model.LoadableDetachableModel; import org.apache.wicket.model.Model; import org.apache.wicket.model.PropertyModel; import org.apache.wicket.model.ResourceModel; import org.geoserver.catalog.Catalog; import org.geoserver.catalog.CoverageStoreInfo; import org.geoserver.catalog.DataStoreInfo; import org.geoserver.catalog.StoreInfo; import org.geoserver.web.data.store.StoreEditPanel; import org.geoserver.web.data.store.panel.PasswordParamPanel; import org.geoserver.web.data.store.panel.TextParamPanel; import org.geoserver.web.util.MapModel; import org.geotools.arcsde.ArcSDEDataStoreFactory; import org.geotools.arcsde.raster.gce.ArcSDERasterFormat; import org.geotools.arcsde.session.ArcSDEConnectionConfig; import org.geotools.data.DataAccessFactory.Param; import org.geotools.util.logging.Logging; /** * Provides the form components for the arcsde coverage edit page * * @author Gabriel Roldan * */ public final class ArcSDECoverageStoreEditPanel extends StoreEditPanel { private static final long serialVersionUID = 4149587878405421797L; private static final Logger LOGGER = Logging.getLogger("org.geoserver.web.data.store.arcsde"); private static final String RESOURCE_KEY_PREFIX = ArcSDECoverageStoreEditPanel.class .getSimpleName(); final FormComponent<String> server; final FormComponent<String> port; final FormComponent<String> instance; final FormComponent<String> user; final FormComponent<String> password; final FormComponent<String> table; public ArcSDECoverageStoreEditPanel(final String componentId, final Form<?> storeEditForm) { super(componentId, storeEditForm); final IModel<?> model = storeEditForm.getModel(); setDefaultModel(model); final CoverageStoreInfo storeInfo = (CoverageStoreInfo) storeEditForm.getModelObject(); { Map<String, String> existingParameters = parseConnectionParameters(storeInfo); Map<String, Serializable> connectionParameters = storeInfo.getConnectionParameters(); connectionParameters.putAll(existingParameters); } final IModel<Map<String, Object>> paramsModel = new PropertyModel<Map<String, Object>>(model, "connectionParameters"); addConnectionPrototypePanel(storeInfo); // server, port, instance, user, pwd server = addTextPanel(paramsModel, SERVER_PARAM); port = addTextPanel(paramsModel, PORT_PARAM); instance = addTextPanel(paramsModel, INSTANCE_PARAM); user = addTextPanel(paramsModel, USER_PARAM); password = addPasswordPanel(paramsModel); server.setOutputMarkupId(true); port.setOutputMarkupId(true); instance.setOutputMarkupId(true); user.setOutputMarkupId(true); password.setOutputMarkupId(true); table = addRasterTable(storeInfo, paramsModel); /* * Listen to form submission and update the model's URL */ storeEditForm.add(new IFormValidator() { private static final long serialVersionUID = 1L; public FormComponent<?>[] getDependentFormComponents() { return new FormComponent<?>[] { server, port, instance, user, password, table }; } public void validate(final Form<?> form) { CoverageStoreInfo storeInfo = (CoverageStoreInfo) form.getModelObject(); final String serverVal = server.getValue(); final String portVal = port.getValue(); final String instanceVal = instance.getValue(); final String userVal = user.getValue(); final String passwordVal = password.getValue(); final String tableVal = table.getValue(); StringBuilder urlb = new StringBuilder("sde://"); urlb.append(userVal).append(":").append(passwordVal).append("@"); urlb.append(serverVal).append(":").append(portVal).append("/"); if (instanceVal != null && instanceVal.trim().length() > 0) { urlb.append(instanceVal); } urlb.append("#").append(tableVal); String coverageUrl = urlb.toString(); LOGGER.info("Coverage URL: '" + coverageUrl + "'"); storeInfo.setURL(coverageUrl); } }); } private FormComponent<String> addRasterTable(final CoverageStoreInfo storeInfo, final IModel<Map<String, Object>> paramsModel) { //final String resourceKey = RESOURCE_KEY_PREFIX + "." + TABLE_NAME; boolean isNew = storeInfo.getId() == null; FormComponent<String> tableComponent = addTableNameComponent(paramsModel, isNew); return tableComponent; } /** * * @param paramsModel * @param isNew * @return a combobox set up to display the list of available raster tables if the StoreInfo is * new, or a non editable text box if we're editing an existing StoreInfo */ private FormComponent<String> addTableNameComponent(final IModel<Map<String, Object>> paramsModel, final boolean isNew) { final FormComponent<String> tableNameComponent; final String panelId = "tableNamePanel"; if (isNew) { RasterTableSelectionPanel selectionPanel; selectionPanel = new RasterTableSelectionPanel(panelId, paramsModel, storeEditForm, server, port, instance, user, password); add(selectionPanel); DropDownChoice<String> tableDropDown = selectionPanel.getFormComponent(); tableNameComponent = tableDropDown; } else { /* * We're editing an existing store. Don't allow to change the table name, it could be * catastrophic for the Catalog/ResourcePool as ability to get to the coverage is really * based on the Store's URL and the CoverageInfo is tied to it */ final IModel<String> paramValue = new MapModel<String>(paramsModel, TABLE_NAME); final String resourceKey = RESOURCE_KEY_PREFIX + "." + TABLE_NAME; final IModel<String> paramLabelModel = new ResourceModel(resourceKey, TABLE_NAME); final boolean required = true; TextParamPanel<String> tableNamePanel; tableNamePanel = new TextParamPanel<String>(panelId, paramValue, paramLabelModel, required); add(tableNamePanel); tableNameComponent = tableNamePanel.getFormComponent(); tableNameComponent.setEnabled(false); final String titleKey = resourceKey + ".title"; ResourceModel titleModel = new ResourceModel(titleKey); String title = String.valueOf(titleModel.getObject()); tableNamePanel.add(AttributeModifier.replace("title", title)); } return tableNameComponent; } private FormComponent<String> addPasswordPanel(final IModel<Map<String, Object>> paramsModel) { final String paramName = PASSWORD_PARAM.key; final String resourceKey = RESOURCE_KEY_PREFIX + "." + paramName; final PasswordParamPanel pwdPanel = new PasswordParamPanel(paramName, new MapModel<String>( paramsModel, paramName), new ResourceModel(resourceKey, paramName), true); add(pwdPanel); String defaultTitle = String.valueOf(PASSWORD_PARAM.title); ResourceModel titleModel = new ResourceModel(resourceKey + ".title", defaultTitle); String title = String.valueOf(titleModel.getObject()); pwdPanel.add(AttributeModifier.replace("title", title)); return pwdPanel.getFormComponent(); } private FormComponent<String> addTextPanel(final IModel<Map<String, Object>> paramsModel, final Param param) { final String paramName = param.key; final String resourceKey = getClass().getSimpleName() + "." + paramName; final boolean required = param.required; final TextParamPanel<String> textParamPanel = new TextParamPanel<String>(paramName, new MapModel<String>( paramsModel, paramName), new ResourceModel(resourceKey, paramName), required); textParamPanel.getFormComponent().setType(param.type); String defaultTitle = String.valueOf(param.title); ResourceModel titleModel = new ResourceModel(resourceKey + ".title", defaultTitle); String title = String.valueOf(titleModel.getObject()); textParamPanel.add(AttributeModifier.replace("title", title)); add(textParamPanel); return textParamPanel.getFormComponent(); } private void addConnectionPrototypePanel(final CoverageStoreInfo storeInfo) { final String resourceKey = RESOURCE_KEY_PREFIX + ".prototype"; Label label = new Label("prototypeLabel", new ResourceModel(resourceKey)); final String title = String.valueOf(new ResourceModel(resourceKey + ".title").getObject()); final AttributeModifier titleSetter = AttributeModifier.replace("title", title); label.add(titleSetter); add(label); final DropDownChoice<StoreInfo> existingArcSDECoverages; existingArcSDECoverages = new DropDownChoice<>("connectionPrototype", new Model<StoreInfo>(), new ArcSDEStoreListModel(), new ArcSDEStoreListChoiceRenderer()); existingArcSDECoverages.add(titleSetter); add(existingArcSDECoverages); existingArcSDECoverages.add(new OnChangeAjaxBehavior() { private static final long serialVersionUID = 1L; @SuppressWarnings("unchecked") @Override protected void onUpdate(AjaxRequestTarget target) { final String storeId = existingArcSDECoverages.getValue(); final List<StoreInfo> choices = (List<StoreInfo>) existingArcSDECoverages.getChoices(); for (StoreInfo store : choices) { if (store.getId().equals(storeId)) { Map<String, String> connParams = parseConnectionParameters(store); server.setModelObject(connParams.get(SERVER_NAME_PARAM_NAME)); port.setModelObject(connParams.get(PORT_NUMBER_PARAM_NAME)); instance.setModelObject(connParams.get(INSTANCE_NAME_PARAM_NAME)); user.setModelObject(connParams.get(USER_NAME_PARAM_NAME)); password.setModelObject(connParams.get(PASSWORD_PARAM_NAME)); target.add(server); target.add(port); target.add(instance); target.add(user); target.add(password); break; } } } }); } final class ArcSDEStoreListModel extends LoadableDetachableModel<List<StoreInfo>> { private static final long serialVersionUID = 1L; @Override protected List<StoreInfo> load() { final StoreInfo storeInfo = (StoreInfo) getDefaultModelObject(); final Catalog catalog = storeInfo.getCatalog(); List<StoreInfo> stores = catalog.getStores(StoreInfo.class); stores = new ArrayList<StoreInfo>(stores); { final String arcsdeCoverageType = ArcSDERasterFormat.getInstance().getName(); final String arcsdeVectorType = new ArcSDEDataStoreFactory().getDisplayName(); StoreInfo store; String type; for (Iterator<StoreInfo> it = stores.iterator(); it.hasNext();) { store = it.next(); type = store.getType(); if (arcsdeCoverageType.equals(type) || arcsdeVectorType.equals(type)) { continue; } else { it.remove(); } } } Collections.sort(stores, new Comparator<StoreInfo>() { public int compare(StoreInfo o1, StoreInfo o2) { if (o1.getWorkspace().equals(o2.getWorkspace())) { return String.CASE_INSENSITIVE_ORDER.compare(o1.getName(), o2.getName()); } return String.CASE_INSENSITIVE_ORDER.compare(o1.getWorkspace().getName(), o2 .getWorkspace().getName()); } }); return stores; } } static final class ArcSDEStoreListChoiceRenderer extends ChoiceRenderer<Object> { private static final long serialVersionUID = 1L; public Object getDisplayValue(final Object store) { StoreInfo info = (StoreInfo) store; return new StringBuilder(info.getWorkspace().getName()).append(':').append( info.getName()); } public String getIdValue(final Object store, final int index) { return ((StoreInfo) store).getId(); } } private Map<String, String> parseConnectionParameters(final StoreInfo storeInfo) { Map<String, String> params = new HashMap<String, String>(); if (storeInfo instanceof CoverageStoreInfo) { String url = ((CoverageStoreInfo) storeInfo).getURL(); if (null != url && url.startsWith("sde:")) { ArcSDEConnectionConfig connectionConfig; connectionConfig = ArcSDERasterFormat .sdeURLToConnectionConfig(new StringBuffer(url)); params.put(SERVER_NAME_PARAM_NAME, connectionConfig.getServerName()); params.put(PORT_NUMBER_PARAM_NAME, connectionConfig.getPortNumber().toString()); params.put(INSTANCE_NAME_PARAM_NAME, connectionConfig.getDatabaseName()); params.put(USER_NAME_PARAM_NAME, connectionConfig.getUserName()); params.put(PASSWORD_PARAM_NAME, connectionConfig.getPassword()); // parse table name int idx = url.lastIndexOf('#'); if (idx > 0) { String tableName = url.substring(idx + 1); params.put(RasterTableSelectionPanel.TABLE_NAME, tableName); } } else { params.put(PORT_NUMBER_PARAM_NAME, "5151"); } } else { Map<String, Serializable> storeParams = ((DataStoreInfo) storeInfo) .getConnectionParameters(); params.put(SERVER_NAME_PARAM_NAME, (String) storeParams.get(SERVER_NAME_PARAM_NAME)); params.put(PORT_NUMBER_PARAM_NAME, String.valueOf(storeParams .get(PORT_NUMBER_PARAM_NAME))); params .put(INSTANCE_NAME_PARAM_NAME, (String) storeParams .get(INSTANCE_NAME_PARAM_NAME)); params.put(USER_NAME_PARAM_NAME, (String) storeParams.get(USER_NAME_PARAM_NAME)); params.put(PASSWORD_PARAM_NAME, (String) storeParams.get(PASSWORD_PARAM_NAME)); } return params; } }