/* (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;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.wicket.AttributeModifier;
import org.apache.wicket.Page;
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.image.Image;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.ResourceModel;
import org.apache.wicket.request.resource.PackageResourceReference;
import org.geoserver.web.CatalogIconFactory;
import org.geoserver.web.ComponentAuthorizer;
import org.geoserver.web.GeoServerApplication;
import org.geoserver.web.GeoServerSecuredPage;
import org.geoserver.web.wicket.ParamResourceModel;
import org.geotools.coverage.grid.io.GridFormatFinder;
import org.geotools.data.DataAccessFactory;
import org.h2.store.DataPage;
import org.opengis.coverage.grid.Format;
import org.vfny.geoserver.util.DataStoreUtils;
/**
* Page that presents a list of vector and raster store types available in the classpath in order to
* choose what kind of data source to create, as well as which workspace to create the store in.
* <p>
* Meant to be called by {@link DataPage} when about to add a new datastore or coverage.
* </p>
*
* @author Gabriel Roldan
*/
@SuppressWarnings("serial")
public class NewDataPage extends GeoServerSecuredPage {
// do not access directly, it is transient and the instance can be the de-serialized version
private transient Map<String, DataAccessFactory> dataStores = getAvailableDataStores();
// do not access directly, it is transient and the instance can be the de-serialized version
private transient Map<String, Format> coverages = getAvailableCoverageStores();
/**
* Creates the page components to present the list of available vector and raster data source
* types
*
* @param workspaceId
* the id of the workspace to attach the new resource store to.
*/
public NewDataPage() {
final boolean thereAreWorkspaces = !getCatalog().getWorkspaces().isEmpty();
if (!thereAreWorkspaces) {
super.error((String) new ResourceModel("NewDataPage.noWorkspacesErrorMessage")
.getObject());
}
final Form storeForm = new Form("storeForm");
add(storeForm);
final ArrayList<String> sortedDsNames = new ArrayList<String>(getAvailableDataStores()
.keySet());
Collections.sort(sortedDsNames);
final CatalogIconFactory icons = CatalogIconFactory.get();
final ListView dataStoreLinks = new ListView("vectorResources", sortedDsNames) {
@Override
protected void populateItem(ListItem item) {
final String dataStoreFactoryName = item.getDefaultModelObjectAsString();
final DataAccessFactory factory = getAvailableDataStores()
.get(dataStoreFactoryName);
final String description = factory.getDescription();
SubmitLink link;
link = new SubmitLink("resourcelink") {
@Override
public void onSubmit() {
setResponsePage(new DataAccessNewPage(dataStoreFactoryName));
}
};
link.setEnabled(thereAreWorkspaces);
link.add(new Label("resourcelabel", dataStoreFactoryName));
item.add(link);
item.add(new Label("resourceDescription", description));
Image icon = new Image("storeIcon", icons.getStoreIcon(factory.getClass()));
// TODO: icons could provide a description too to be used in alt=...
icon.add(new AttributeModifier("alt", new Model("")));
item.add(icon);
}
};
final List<String> sortedCoverageNames = new ArrayList<String>();
sortedCoverageNames.addAll(getAvailableCoverageStores().keySet());
Collections.sort(sortedCoverageNames);
final ListView coverageLinks = new ListView("rasterResources", sortedCoverageNames) {
@Override
protected void populateItem(ListItem item) {
final String coverageFactoryName = item.getDefaultModelObjectAsString();
final Map<String, Format> coverages = getAvailableCoverageStores();
Format format = coverages.get(coverageFactoryName);
final String description = format.getDescription();
SubmitLink link;
link = new SubmitLink("resourcelink") {
@Override
public void onSubmit() {
setResponsePage(new CoverageStoreNewPage(coverageFactoryName));
}
};
link.setEnabled(thereAreWorkspaces);
link.add(new Label("resourcelabel", coverageFactoryName));
item.add(link);
item.add(new Label("resourceDescription", description));
Image icon = new Image("storeIcon", icons.getStoreIcon(format.getClass()));
// TODO: icons could provide a description too to be used in alt=...
icon.add(new AttributeModifier("alt", new Model("")));
item.add(icon);
}
};
final List<OtherStoreDescription> otherStores = getOtherStores();
final ListView otherStoresLinks = new ListView("otherStores", otherStores) {
@Override
protected void populateItem(ListItem item) {
final OtherStoreDescription store = (OtherStoreDescription) item.getModelObject();
SubmitLink link;
link = new SubmitLink("resourcelink") {
@Override
public void onSubmit() {
setResponsePage(store.configurationPage);
}
};
link.setEnabled(thereAreWorkspaces);
link.add(new Label("resourcelabel", new ParamResourceModel("other." + store.key, NewDataPage.this)));
item.add(link);
item.add(new Label("resourceDescription", new ParamResourceModel("other." + store.key + ".description", NewDataPage.this)));
Image icon = new Image("storeIcon", store.icon);
// TODO: icons could provide a description too to be used in alt=...
icon.add(new AttributeModifier("alt", new Model("")));
item.add(icon);
}
};
storeForm.add(dataStoreLinks);
storeForm.add(coverageLinks);
storeForm.add(otherStoresLinks);
}
/**
* @return the name/description set of available datastore factories
*/
private Map<String, DataAccessFactory> getAvailableDataStores() {
// dataStores is transient, a back button may get us to the serialized version so check for
// it
if (dataStores == null) {
final Iterator<DataAccessFactory> availableDataStores;
availableDataStores = DataStoreUtils.getAvailableDataStoreFactories().iterator();
Map<String, DataAccessFactory> storeNames = new HashMap<String, DataAccessFactory>();
while (availableDataStores.hasNext()) {
DataAccessFactory factory = availableDataStores.next();
if(factory.getDisplayName() != null) {
storeNames.put(factory.getDisplayName(), factory);
}
}
dataStores = storeNames;
}
return dataStores;
}
/**
* @return the name/description set of available raster formats
*/
private Map<String, Format> getAvailableCoverageStores() {
if (coverages == null) {
Format[] availableFormats = GridFormatFinder.getFormatArray();
Map<String, Format> formatNames = new HashMap<String, Format>();
for (Format format : availableFormats) {
formatNames.put(format.getName(), format);
}
coverages = formatNames;
}
return coverages;
}
private List<OtherStoreDescription> getOtherStores() {
List<OtherStoreDescription> stores = new ArrayList<OtherStoreDescription>();
PackageResourceReference wmsIcon = new PackageResourceReference(GeoServerApplication.class, "img/icons/geosilk/server_map.png");
stores.add(new OtherStoreDescription("wms", wmsIcon, WMSStoreNewPage.class));
return stores;
}
@Override
protected ComponentAuthorizer getPageAuthorizer() {
return ComponentAuthorizer.WORKSPACE_ADMIN;
}
/**
* Provides a description for a store that is not a vector nor a raster data source
*/
static class OtherStoreDescription implements Serializable {
String key;
PackageResourceReference icon;
Class<? extends Page> configurationPage;
public OtherStoreDescription(String key, PackageResourceReference icon, Class<? extends Page> configurationPage) {
super();
this.key = key;
this.icon = icon;
this.configurationPage = configurationPage;
}
}
}