/* (c) 2014 - 2016 Open Source Geospatial Foundation - all rights reserved
* (c) 2014 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.web.data.layer;
import java.awt.image.SampleModel;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.media.jai.ImageLayout;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.SubmitLink;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.model.CompoundPropertyModel;
import org.apache.wicket.model.PropertyModel;
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.CoverageInfo;
import org.geoserver.catalog.CoverageStoreInfo;
import org.geoserver.catalog.CoverageView;
import org.geoserver.catalog.CoverageView.CoverageBand;
import org.geoserver.web.ComponentAuthorizer;
import org.geoserver.web.GeoServerSecuredPage;
import org.geotools.coverage.grid.io.GridCoverage2DReader;
/**
* Base page for {@link CoverageView} creation/editing
*
* @author Daniele Romagnoli, GeoSolutions SAS
*/
@SuppressWarnings("serial")
public abstract class CoverageViewAbstractPage extends GeoServerSecuredPage {
public static final String COVERAGESTORE = "storeName";
public static final String WORKSPACE = "wsName";
static final String COVERAGE_VIEW_NAME = "COVERAGEVIEW_NAME";
String storeId;
String coverageInfoId;
String definition;
String name;
boolean newCoverage;
CoverageInfo coverageViewInfo;
List<String> availableCoverages;
List<String> selectedCoverages;
List<CoverageBand> outputBands;
CoverageViewEditor coverageEditor;
public CoverageViewAbstractPage(PageParameters params) throws IOException {
this(params.get(WORKSPACE).toOptionalString(), params.get(COVERAGESTORE).toString(), null, null);
}
public CoverageViewAbstractPage(String workspaceName, String storeName, String coverageName,
CoverageInfo coverageInfo) throws IOException {
storeId = getCatalog().getStoreByName(workspaceName, storeName, CoverageStoreInfo.class)
.getId();
Catalog catalog = getCatalog();
CoverageStoreInfo store = catalog.getStore(storeId, CoverageStoreInfo.class);
GridCoverage2DReader reader = (GridCoverage2DReader) catalog.getResourcePool()
.getGridCoverageReader(store, null);
String[] coverageNames = reader.getGridCoverageNames();
if (availableCoverages == null) {
availableCoverages = new ArrayList<String>();
}
for (String coverage : coverageNames) {
ImageLayout layout = reader.getImageLayout(coverage);
SampleModel sampleModel = layout.getSampleModel(null);
final int numBands = sampleModel.getNumBands();
if(numBands == 1) {
// simple syntax for simple case
availableCoverages.add(coverage);
} else {
for (int i = 0; i < numBands; i++) {
availableCoverages.add(coverage + CoverageView.BAND_SEPARATOR + i);
}
}
}
Collections.sort(availableCoverages);
name = COVERAGE_VIEW_NAME;
if (coverageName != null) {
newCoverage = false;
// grab the coverage view
coverageViewInfo = coverageInfo != null ? coverageInfo : catalog.getResourceByStore(
store, coverageName, CoverageInfo.class);
CoverageView coverageView = coverageViewInfo.getMetadata().get(
CoverageView.COVERAGE_VIEW, CoverageView.class);
// the type can be still not saved
if (coverageViewInfo != null) {
coverageInfoId = coverageViewInfo.getId();
}
if (coverageView == null) {
throw new IllegalArgumentException(
"The specified coverage does not have a coverage view attached to it");
}
outputBands = new ArrayList<CoverageBand>(coverageView.getCoverageBands());
name = coverageView.getName();
} else {
outputBands = new ArrayList<CoverageBand>();
newCoverage = true;
coverageViewInfo = null;
}
selectedCoverages = new ArrayList<String>(availableCoverages);
// build the form and the text area
Form<CoverageViewAbstractPage> form = new Form<>("form", new CompoundPropertyModel<>(this));
add(form);
final TextField<String> nameField = new TextField<>("name");
nameField.setRequired(true);
nameField.add(new CoverageViewNameValidator());
form.add(nameField);
coverageEditor = new CoverageViewEditor("coverages",
new PropertyModel<>(this,"selectedCoverages"),
new PropertyModel<>(this, "outputBands"),
availableCoverages);
form.add(coverageEditor);
// save and cancel at the bottom of the page
form.add(new SubmitLink("save") {
@Override
public void onSubmit() {
onSave();
}
});
form.add(new Link<Void>("cancel") {
@Override
public void onClick() {
onCancel();
}
});
}
protected CoverageView buildCoverageView() throws IOException {
return new CoverageView(name, coverageEditor.currentOutputBands);
}
/**
* Data stores tend to return IOExceptions with no explanation, and the actual error coming from the db is in the cause. This method extracts the
* first not null message in the cause chain
*
* @param t
*
*/
protected String getFirstErrorMessage(Throwable t) {
Throwable original = t;
while (!(t instanceof SQLException)) {
t = t.getCause();
if (t == null) {
break;
}
}
if (t == null) {
return original.getMessage();
} else {
return t.getMessage();
}
}
protected abstract void onSave();
protected abstract void onCancel();
/**
* Checks the {@link CoverageView} name is unique
*/
class CoverageViewNameValidator implements IValidator<String> {
@Override
public void validate(IValidatable<String> validatable) {
String vcName = validatable.getValue();
final CoverageStoreInfo store = getCatalog().getStore(storeId, CoverageStoreInfo.class);
List<CoverageInfo> coverages = getCatalog().getCoveragesByCoverageStore(store);
for (CoverageInfo curr : coverages) {
CoverageView currvc = curr.getMetadata().get(CoverageView.COVERAGE_VIEW, CoverageView.class);
if (currvc != null) {
if (coverageInfoId == null || !coverageInfoId.equals(curr.getId())) {
if (currvc.getName().equals(vcName) && newCoverage) {
Map<String, Object> map = new HashMap<>();
map.put("name", vcName);
map.put("coverageName", curr.getName());
IValidationError err = new ValidationError("duplicateCoverageViewName")
.addKey("duplicateCoverageViewName").setVariables(map);
validatable.error(err);
return;
}
}
}
}
}
}
@Override
protected ComponentAuthorizer getPageAuthorizer() {
return ComponentAuthorizer.WORKSPACE_ADMIN;
}
public List<String> getSelectedCoverages() {
return selectedCoverages;
}
public void setSelectedCoverages(List<String> selectedCoverages) {
this.selectedCoverages = selectedCoverages;
}
}