/* (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.wms.web.data; import java.io.IOException; import java.util.logging.Logger; import org.apache.wicket.Component; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.markup.html.AjaxLink; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.panel.EmptyPanel; import org.apache.wicket.markup.html.panel.Fragment; import org.apache.wicket.markup.html.panel.Panel; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; import org.geoserver.catalog.FeatureTypeInfo; import org.geoserver.web.GeoServerApplication; import org.geoserver.web.wicket.GeoServerDataProvider.Property; import org.geoserver.web.wicket.GeoServerTablePanel; import org.geotools.data.FeatureSource; import org.geotools.data.Query; import org.geotools.feature.FeatureBuilder; import org.geotools.feature.FeatureCollection; import org.geotools.feature.FeatureIterator; import org.geotools.feature.simple.SimpleFeatureBuilder; import org.geotools.feature.visitor.MaxVisitor; import org.geotools.feature.visitor.MinVisitor; import org.geotools.util.Converters; import org.geotools.util.logging.Logging; import org.opengis.feature.Feature; import org.opengis.feature.type.PropertyDescriptor; import com.vividsolutions.jts.geom.Geometry; /** * Panel for listing sample attributes of a FeatureTypeInfo resource. */ public class DataPanel extends Panel { private static final long serialVersionUID = -2635691554700860434L; static final Logger LOGGER = Logging.getLogger(DataPanel.class); String featureTypeId; public DataPanel(String id, FeatureTypeInfo ft) { super(id, new Model<FeatureTypeInfo>(ft)); this.featureTypeId = ft.getId(); add(new Label("summary-message", "For reference, here is a listing of the attributes in this data set." )); // TODO: I18N final WebMarkupContainer attsContainer = new WebMarkupContainer("attributes-container"); attsContainer.setOutputMarkupId(true); add(attsContainer); Feature sample; try { sample = getSampleFeature(ft); } catch (Exception e) { attsContainer.error("Failed to load attribute list, internal error is: " + e.getMessage()); attsContainer.add(new EmptyPanel("attributes")); return; } DataAttributesProvider summaries = new DataAttributesProvider(sample); final GeoServerTablePanel<DataAttribute> attributes = new GeoServerTablePanel<DataAttribute>("attributes", summaries) { private static final long serialVersionUID = 7753093373969576568L; @Override protected Component getComponentForProperty(String id, final IModel<DataAttribute> itemModel, Property<DataAttribute> property) { if(DataAttributesProvider.COMPUTE_STATS.equals(property.getName())) { Fragment f = new Fragment(id, "computeStatsFragment", DataPanel.this); f.add(new AjaxLink<Void>("computeStats") { private static final long serialVersionUID = 1L; @Override public void onClick(AjaxRequestTarget target) { DataAttribute attribute = (DataAttribute) itemModel.getObject(); try { updateAttributeStats(attribute); } catch (IOException e) { error("Failed to compute stats for the attribute: " + e.getMessage()); } target.add(attsContainer); } }); return f; } return null; } }; attributes.setPageable(false); attributes.setFilterable(false); attributes.setSortable(false); attsContainer.add(attributes); } protected void updateAttributeStats(DataAttribute attribute) throws IOException { FeatureTypeInfo featureType = GeoServerApplication.get().getCatalog().getFeatureType(featureTypeId); FeatureSource<?, ?> fs = featureType.getFeatureSource(null, null); // check we can compute min and max PropertyDescriptor pd = fs.getSchema().getDescriptor(attribute.getName()); Class<?> binding = pd.getType().getBinding(); if(pd == null || !Comparable.class.isAssignableFrom(binding) || Geometry.class.isAssignableFrom(binding)) { return; } // grab the feature collection and run the min/max visitors (this will move the // query to the dbms in case of such data source) Query q = new Query(); q.setPropertyNames(new String[] {attribute.getName()}); FeatureCollection<?, ?> fc = fs.getFeatures(q); MinVisitor minVisitor = new MinVisitor(attribute.getName()); MaxVisitor maxVisitor = new MaxVisitor(attribute.getName()); fc.accepts(minVisitor, null); fc.accepts(maxVisitor, null); Object min = minVisitor.getResult().getValue(); attribute.setMin(Converters.convert(min, String.class)); Object max = maxVisitor.getResult().getValue(); attribute.setMax(Converters.convert(max, String.class)); } private Feature getSampleFeature(FeatureTypeInfo layerInfo) throws IOException { FeatureSource<?, ?> fs = layerInfo.getFeatureSource(null, null); Query q = new Query(); q.setMaxFeatures(1); FeatureCollection<?, ?> features = fs.getFeatures(q); FeatureIterator<?> fi = null; Feature sample = null; try { fi = features.features(); sample = fi.next(); } finally { fi.close(); } return sample; } }