/* Copyright (c) 2001 - 2007 TOPP - www.openplans.org. All rights reserved.
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.web.data.layer;
import java.io.IOException;
import java.util.Arrays;
import java.util.logging.Level;
import org.apache.wicket.Component;
import org.apache.wicket.PageParameters;
import org.apache.wicket.ResourceReference;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.markup.html.basic.Label;
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.markup.html.panel.Fragment;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.PropertyModel;
import org.geoserver.catalog.CatalogBuilder;
import org.geoserver.catalog.DataStoreInfo;
import org.geoserver.catalog.FeatureTypeInfo;
import org.geoserver.catalog.LayerInfo;
import org.geoserver.web.GeoServerSecuredPage;
import org.geoserver.web.data.resource.ResourceConfigurationPage;
import org.geoserver.web.wicket.GeoServerAjaxFormLink;
import org.geoserver.web.wicket.GeoServerTablePanel;
import org.geoserver.web.wicket.ImageAjaxLink;
import org.geoserver.web.wicket.ParamResourceModel;
import org.geoserver.web.wicket.GeoServerDataProvider.Property;
import org.geotools.data.DataStore;
import org.geotools.data.FeatureSource;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.referencing.CRS;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import com.vividsolutions.jts.geom.Geometry;
/**
* Builds a new feature type by having the user specify the attributes
* @author aaime
*/
@SuppressWarnings("serial")
public class NewFeatureTypePage extends GeoServerSecuredPage {
public static final String DATASTORE = "storeName";
public static final String WORKSPACE = "wsName";
String name;
Form form;
AttributesProvider attributesProvider;
GeoServerTablePanel<AttributeDescription> attributeTable;
String storeId;
public NewFeatureTypePage(PageParameters params) {
this(params.getString(WORKSPACE), params.getString(DATASTORE));
}
public NewFeatureTypePage(String workspaceName, String storeName) {
DataStoreInfo di = getCatalog().getDataStoreByName(workspaceName, storeName);
if (di == null) {
throw new IllegalArgumentException("Could not find a " + storeName + " store in the "
+ workspaceName + " workspace");
}
this.storeId = di.getId();
form = new Form("form");
form.setOutputMarkupId(true);
add(form);
form.add(new TextField("name", new PropertyModel(this, "name")).setRequired(true));
attributesProvider = new AttributesProvider();
attributeTable = new GeoServerTablePanel<AttributeDescription>("attributes",
attributesProvider, true) {
@Override
protected Component getComponentForProperty(String id, IModel itemModel,
Property<AttributeDescription> property) {
AttributeDescription att = (AttributeDescription) itemModel.getObject();
if (property == AttributesProvider.NAME) {
Fragment f = new Fragment(id, "nameFragment", NewFeatureTypePage.this);
f.add(editAttributeLink(itemModel));
return f;
} else if (property == AttributesProvider.BINDING) {
return new Label(id, AttributeDescription.getLocalizedName(att.getBinding()));
} else if (property == AttributesProvider.CRS) {
if (att.getBinding() != null
&& Geometry.class.isAssignableFrom(att.getBinding())) {
try {
Integer epsgCode = CRS.lookupEpsgCode(att.getCrs(), false);
return new Label(id, "EPSG:" + epsgCode);
} catch (Exception e) {
throw new RuntimeException(e);
}
} else {
return new Label(id, "");
}
} else if (property == AttributesProvider.SIZE) {
if (att.getBinding() != null && String.class.equals(att.getBinding())) {
return new Label(id, String.valueOf(att.getSize()));
} else {
return new Label(id, "");
}
} else if (property == AttributesProvider.UPDOWN) {
return upDownFragment(id, att);
}
return null;
}
};
attributeTable.setSortable(false);
attributeTable.setFilterable(false);
attributeTable.getBottomPager().setVisible(false);
form.add(attributeTable);
SubmitLink saveLink = saveLink();
form.add(saveLink);
form.setDefaultButton(saveLink);
form.add(cancelLink());
setHeaderPanel(headerPanel());
}
private SubmitLink saveLink() {
return new SubmitLink("save") {
@Override
public void onSubmit() {
DataStore ds = null;
DataStoreInfo dsInfo = null;
try {
// basic checks
dsInfo = getCatalog().getDataStore(storeId);
ds = (DataStore) dsInfo.getDataStore(null);
if (Arrays.asList(ds.getTypeNames()).contains(name)) {
error(new ParamResourceModel("duplicateTypeName", this, dsInfo.getName(),
name).getString());
return;
}
} catch (Exception e) {
throw new RuntimeException(e);
}
if (attributesProvider.getAttributes().size() == 0) {
error(new ParamResourceModel("noAttributes", this).getString());
return;
}
try {
SimpleFeatureType featureType = buildFeatureType();
ds.createSchema(featureType);
CatalogBuilder builder = new CatalogBuilder(getCatalog());
builder.setStore(dsInfo);
FeatureTypeInfo fti = builder.buildFeatureType(getFeatureSource(ds));
LayerInfo layerInfo = builder.buildLayer(fti);
setResponsePage(new ResourceConfigurationPage(layerInfo, true));
} catch (Exception e) {
LOGGER.log(Level.SEVERE, "Failed to create feature type", e);
error(new ParamResourceModel("creationFailure", this, e.getMessage())
.getString());
}
}
};
}
FeatureSource<SimpleFeatureType, SimpleFeature> getFeatureSource(DataStore ds)
throws IOException {
try {
return ds.getFeatureSource(name);
} catch(IOException e) {
// maybe it's Oracle?
try {
return ds.getFeatureSource(name.toUpperCase());
} catch(Exception ora) {
// nope, the reason was another one
throw e;
}
}
}
SimpleFeatureType buildFeatureType() {
SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
for (AttributeDescription att : attributesProvider.getAttributes()) {
if (att.getSize() > 0) {
builder.length(att.getSize());
}
if (Geometry.class.isAssignableFrom(att.getBinding())) {
builder.add(att.getName(), att.getBinding(), att.getCrs());
} else {
builder.add(att.getName(), att.getBinding());
}
}
builder.setName(name);
return builder.buildFeatureType();
}
private Link cancelLink() {
return new Link("cancel") {
@Override
public void onClick() {
setResponsePage(NewLayerPage.class);
}
};
}
Component editAttributeLink(final IModel itemModel) {
GeoServerAjaxFormLink link = new GeoServerAjaxFormLink("link") {
@Override
protected void onClick(AjaxRequestTarget target, Form form) {
AttributeDescription attribute = (AttributeDescription) itemModel.getObject();
setResponsePage(new AttributeEditPage(attribute, NewFeatureTypePage.this));
}
};
link.add(new Label("name", new PropertyModel(itemModel, "name")));
return link;
}
protected Component headerPanel() {
Fragment header = new Fragment(HEADER_PANEL, "header", this);
// the add button
header.add(new GeoServerAjaxFormLink("addNew", form) {
@Override
public void onClick(AjaxRequestTarget target, Form form) {
AttributeDescription attribute = new AttributeDescription();
setResponsePage(new AttributeNewPage(attribute, NewFeatureTypePage.this));
}
});
header.add(new GeoServerAjaxFormLink("removeSelected", form) {
@Override
public void onClick(AjaxRequestTarget target, Form form) {
attributesProvider.removeAll(attributeTable.getSelection());
attributeTable.clearSelection();
target.addComponent(form);
}
});
return header;
}
protected Component upDownFragment(String id, final AttributeDescription attribute) {
Fragment upDown = new Fragment(id, "upDown", this);
if (attributesProvider.isFirst(attribute)) {
upDown.add(new PlaceholderLink("up"));
} else {
ImageAjaxLink upLink = new ImageAjaxLink("up", new ResourceReference(getClass(),
"../../img/icons/silk/arrow_up.png")) {
@Override
protected void onClick(AjaxRequestTarget target) {
attributesProvider.moveUp(attribute);
target.addComponent(form);
}
};
upDown.add(upLink);
}
if (attributesProvider.isLast(attribute)) {
upDown.add(new PlaceholderLink("down"));
} else {
ImageAjaxLink downLink = new ImageAjaxLink("down", new ResourceReference(getClass(),
"../../img/icons/silk/arrow_down.png")) {
@Override
protected void onClick(AjaxRequestTarget target) {
attributesProvider.moveDown(attribute);
target.addComponent(form);
}
};
upDown.add(downLink);
}
return upDown;
}
/**
* An empty link, put there just so that it will consume the same space as an ImageAjaxLink
*
* @author Andrea Aime
*/
class PlaceholderLink extends ImageAjaxLink {
public PlaceholderLink(String id) {
super(id, new ResourceReference(NewFeatureTypePage.class, "../../img/icons/blank.png"));
setEnabled(false);
}
@Override
protected void onClick(AjaxRequestTarget target) {
// nothing to do
}
}
}