/* (c) 2014 - 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.geoserver.solr;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.wicket.Component;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.form.AjaxButton;
import org.apache.wicket.ajax.markup.html.form.AjaxCheckBox;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.CheckBox;
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.TextField;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.markup.html.panel.Fragment;
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.apache.wicket.model.PropertyModel;
import org.geoserver.catalog.DataStoreInfo;
import org.geoserver.catalog.FeatureTypeInfo;
import org.geoserver.catalog.ResourceInfo;
import org.geoserver.web.wicket.GeoServerDataProvider.Property;
import org.geoserver.web.wicket.GeoServerTablePanel;
import org.geoserver.web.wicket.ParamResourceModel;
import org.geotools.data.solr.SolrAttribute;
import org.geotools.data.solr.SolrDataStore;
import org.geotools.data.solr.SolrLayerConfiguration;
import org.geotools.util.NullProgressListener;
import org.geotools.util.logging.Logging;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryCollection;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.MultiLineString;
import com.vividsolutions.jts.geom.MultiPoint;
import com.vividsolutions.jts.geom.MultiPolygon;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;
/**
* Class to render and manage the SOLR modal dialog This dialog allow the user to choice which SOLR
* attributes include in layers, selects attributes to use as PK, as GEOMETRY, and set native SRID
*/
public abstract class SolrConfigurationPage extends Panel {
private static final long serialVersionUID = 5615867383881988931L;
private static final Logger LOGGER = Logging.getLogger(SolrConfigurationPage.class);
private String solrurl;
private FeedbackPanel feedbackPanel;
private static final List<Class<?>> GEOMETRY_TYPES = Arrays.asList(Geometry.class,
GeometryCollection.class, Point.class, MultiPoint.class, LineString.class,
MultiLineString.class, Polygon.class, MultiPolygon.class);
/**
* Constructs the dialog to set SOLR attributes with the follow components: <li>The checkbox to
* hide/show the empty attributes <li>The table with SOLR attributes and configuration options
*
* @see {@link SolrAttributeProvider}
* @see {@link SolrAttribute}
*
*/
public SolrConfigurationPage(String panelId,
final IModel<?> model) {
super(panelId, model);
ResourceInfo ri = (ResourceInfo) model.getObject();
DataStoreInfo store = (DataStoreInfo) ri.getStore();
Map<String, Serializable> connectionparameters = store.getConnectionParameters();
solrurl = (String) connectionparameters.get("solr_url");
final Form<SolrConfigurationPage> solr_form = new Form<SolrConfigurationPage>("solr_form", new CompoundPropertyModel<SolrConfigurationPage>(this));
add(solr_form);
List<SolrAttribute> attributes = fillSolrAttributes((ResourceInfo) model.getObject())
.getAttributes();
final SolrAttributeProvider attProvider = new SolrAttributeProvider(attributes);
final GeoServerTablePanel<SolrAttribute> solrAttributePanel = getSolrAttributePanel(attProvider);
solr_form.add(solrAttributePanel);
AjaxCheckBox checkBox = new AjaxCheckBox("hideEmpty", Model.of(Boolean.TRUE)) {
/**
*
*/
private static final long serialVersionUID = 8715377219204904531L;
@Override
protected void onUpdate(AjaxRequestTarget target) {
attProvider.reload((Boolean) this.getDefaultModelObject());
target.add(solrAttributePanel);
}
};
checkBox.setOutputMarkupId(true);
solr_form.add(checkBox);
solr_form.add(new AjaxButton("solr_save") {
/**
*
*/
private static final long serialVersionUID = 819555072210390051L;
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
onSave(target);
}
});
feedbackPanel = new FeedbackPanel("solr_feedback");
feedbackPanel.setOutputMarkupId(true);
solr_form.add(feedbackPanel);
}
/**
* Do nothing
*/
protected void onCancel(AjaxRequestTarget target) {
done(target, null);
}
/**
* Validates SOLR attributes configuration and stores the SOLR layer configuration into feature
* type metadata as {@link SolrLayerConfiguration#KEY} <br>
* Validation include the follow rules <li>One attribute must be a PK <li>One attribute must be
* a GEOMETRY <li>GEOMETRY attribute must have a SRID
*
* @see {@link SolrLayerConfiguration}
* @see {@link FeatureTypeInfo#getMetadata}
*/
protected void onSave(AjaxRequestTarget target) {
try {
ResourceInfo ri = (ResourceInfo) getDefaultModel().getObject();
SolrLayerConfiguration layerConfiguration = fillSolrAttributes(ri);
Boolean pkSet = false;
Boolean geomSet = false;
Boolean sridSet = false;
// Validate configuration
for (SolrAttribute att : layerConfiguration.getAttributes()) {
if (att.isPk() && att.isUse()) {
pkSet = true;
}
if (Geometry.class.isAssignableFrom(att.getType()) && att.isUse()) {
geomSet = true;
if (att.getSrid() != null) {
sridSet = true;
}
}
}
if (!pkSet) {
error(new ParamResourceModel("pkEmptyFailure", SolrConfigurationPage.this)
.getString());
}
if (!geomSet) {
error(new ParamResourceModel("geomEmptyFailure", SolrConfigurationPage.this)
.getString());
} else if (!sridSet) {
error(new ParamResourceModel("sridEmptyFailure", SolrConfigurationPage.this)
.getString());
}
if (!pkSet || !geomSet || !sridSet) {
target.add(feedbackPanel);
return;
}
ri.getMetadata().put(SolrLayerConfiguration.KEY, layerConfiguration);
done(target, ri);
} catch (Exception e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
error(new ParamResourceModel("creationFailure", this, e).getString());
}
}
/*
* Load SolrLayerConfiguration configuration before shows on table Reloads SOLR attributes from
* datastore and merge it with user attributes configurations
*/
private SolrLayerConfiguration fillSolrAttributes(ResourceInfo ri) {
SolrLayerConfiguration solrLayerConfiguration = (SolrLayerConfiguration) ri.getMetadata()
.get(SolrLayerConfiguration.KEY);
try {
ArrayList<SolrAttribute> result = new ArrayList<SolrAttribute>();
Map<String, SolrAttribute> tempMap = new HashMap<String, SolrAttribute>();
if (solrLayerConfiguration != null) {
for (SolrAttribute att : solrLayerConfiguration.getAttributes()) {
tempMap.put(att.getName(), att);
}
} else {
tempMap.clear();
solrLayerConfiguration = new SolrLayerConfiguration(new ArrayList<SolrAttribute>());
solrLayerConfiguration.setLayerName(ri.getName());
ri.getMetadata().put(SolrLayerConfiguration.KEY, solrLayerConfiguration);
}
SolrDataStore dataStore = (SolrDataStore) ((DataStoreInfo) ri.getStore())
.getDataStore(new NullProgressListener());
ArrayList<SolrAttribute> attributes = dataStore
.getSolrAttributes(solrLayerConfiguration.getLayerName());
for (SolrAttribute at : attributes) {
if (tempMap.containsKey(at.getName())) {
SolrAttribute prev = tempMap.get(at.getName());
prev.setEmpty(at.getEmpty());
at = prev;
}
result.add(at);
}
solrLayerConfiguration.getAttributes().clear();
solrLayerConfiguration.getAttributes().addAll(result);
} catch (Exception e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
}
return solrLayerConfiguration;
}
/*
* Builds attribute table
*/
private GeoServerTablePanel<SolrAttribute> getSolrAttributePanel(
SolrAttributeProvider attProvider) {
GeoServerTablePanel<SolrAttribute> atts = new GeoServerTablePanel<SolrAttribute>(
"solrAttributes", attProvider) {
/**
*
*/
private static final long serialVersionUID = 7306412054935816724L;
@Override
protected Component getComponentForProperty(String id, IModel<SolrAttribute> itemModel,
Property<SolrAttribute> property) {
SolrAttribute att = (SolrAttribute) itemModel.getObject();
boolean isGeometry = att.getType() != null
&& Geometry.class.isAssignableFrom(att.getType());
boolean isPK = att.isPk();
if (property == SolrAttributeProvider.PK) {
if (isPK) {
Fragment f = new Fragment(id, "checkboxPk", SolrConfigurationPage.this);
f.add(new CheckBox("pk", new PropertyModel<Boolean>(itemModel, "pk")));
return f;
} else {
Fragment f = new Fragment(id, "empty", SolrConfigurationPage.this);
return f;
}
} else if (property == SolrAttributeProvider.NAME && (isGeometry || isPK)) {
Fragment f = new Fragment(id, "label", SolrConfigurationPage.this);
f.add(new Label("label", ((SolrAttribute) itemModel.getObject()).getName()
+ "*"));
return f;
} else if (property == SolrAttributeProvider.TYPE && isGeometry) {
Fragment f = new Fragment(id, "geometry", SolrConfigurationPage.this);
f.add(new DropDownChoice("geometry",
new PropertyModel(itemModel, "type"),
GEOMETRY_TYPES, new GeometryTypeRenderer()));
return f;
} else if (property == SolrAttributeProvider.USE) {
Fragment f = new Fragment(id, "checkboxUse", SolrConfigurationPage.this);
f.add(new CheckBox("use", new PropertyModel<Boolean>(itemModel, "use")));
return f;
} else if (property == SolrAttributeProvider.EMPTY) {
Fragment f = new Fragment(id, "checkboxEmpty", SolrConfigurationPage.this);
f.add(new CheckBox("isEmpty", new PropertyModel<Boolean>(itemModel, "empty")));
return f;
} else if (property == SolrAttributeProvider.SRID) {
if (isGeometry) {
Fragment f = new Fragment(id, "text", SolrConfigurationPage.this);
f.add(new TextField<Integer>("text", new PropertyModel<Integer>(itemModel,
"srid")));
return f;
} else {
Fragment f = new Fragment(id, "empty", SolrConfigurationPage.this);
return f;
}
} else if (property == SolrAttributeProvider.DEFAULT_GEOMETRY) {
if (isGeometry) {
Fragment f = new Fragment(id, "checkboxDefaultGeometry",
SolrConfigurationPage.this);
f.add(new CheckBox("defaultGeometry", new PropertyModel<Boolean>(itemModel,
"defaultGeometry")));
return f;
} else {
Fragment f = new Fragment(id, "empty", SolrConfigurationPage.this);
return f;
}
}
return null;
}
};
atts.setOutputMarkupId(true);
atts.setFilterVisible(false);
atts.setSortable(false);
atts.setPageable(false);
atts.setOutputMarkupId(true);
return atts;
}
/*
* Render geometry type select
*/
private static class GeometryTypeRenderer extends ChoiceRenderer<Class<?>> {
private static final long serialVersionUID = -6371918467884222834L;
public Object getDisplayValue(Class<?> object) {
return ((Class<?>) object).getSimpleName();
}
public String getIdValue(Class<?> object, int index) {
return (String) getDisplayValue(object);
}
}
/**
* Abstract method to implements in panel that opens the dialog to close the dialog itself <br>
* This method is called after modal executes its operation
*
* @param target ajax response target
* @param layerInfo contains attribute configuration
* @param isNew used to communicate to parent if the attributes configuration if for new or for
* existing layer
*
* @see {@link #onSave}
* @see {@link #onCancel}
*
*/
abstract void done(AjaxRequestTarget target, ResourceInfo layerInfo);
}