/* Copyright (c) 2001 - 2008 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.importer;
import java.io.File;
import java.io.Serializable;
import java.net.URI;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import org.apache.wicket.Component;
import org.apache.wicket.PageParameters;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink;
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.model.CompoundPropertyModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.validation.IValidatable;
import org.apache.wicket.validation.validator.AbstractValidator;
import org.apache.wicket.validation.validator.PatternValidator;
import org.apache.wicket.validation.validator.StringValidator;
import org.geoserver.catalog.CatalogBuilder;
import org.geoserver.catalog.DataStoreInfo;
import org.geoserver.catalog.NamespaceInfo;
import org.geoserver.catalog.StoreInfo;
import org.geoserver.catalog.WorkspaceInfo;
import org.geoserver.importer.FeatureTypeImporter;
import org.geoserver.importer.ImporterThreadManager;
import org.geoserver.web.GeoServerSecuredPage;
import org.geoserver.web.wicket.GeoServerDialog;
import org.geoserver.web.wicket.ParamResourceModel;
import org.geoserver.web.wicket.browser.ExtensionFileFilter;
import org.geoserver.web.wicket.browser.GeoServerFileChooser;
import org.geotools.data.DataStore;
import org.geotools.data.DataStoreFinder;
import org.geotools.data.directory.DirectoryDataStoreFactory;
/**
* Sets up the import process and starts it up delegating the progress to {@link ImportProgressPage}
*/
@SuppressWarnings("serial")
public class ImportPage extends GeoServerSecuredPage {
String directory = "";
String project = "";
GeoServerDialog dialog;
private TextField dirField;
public ImportPage(PageParameters params) {
if("TRUE".equalsIgnoreCase((String) params.getString("afterCleanup")))
info(new ParamResourceModel("rollbackSuccessful", this).getString());
add(dialog = new GeoServerDialog("dialog"));
Form form = new Form("form", new CompoundPropertyModel(this));
add(form);
dirField = new TextField("directory");
dirField.add(new DirectoryValidator());
dirField.setRequired(true);
dirField.setOutputMarkupId(true);
// dirField.setEnabled(false);
form.add(dirField);
form.add(chooserButton(form));
TextField projectField = new TextField("project");
projectField.setRequired(true);
projectField.add(new ProjectValidator());
projectField.add(new PatternValidator("\\w+"));
projectField.add(new StringValidator.MaximumLengthValidator(6));
form.add(projectField);
SubmitLink submitLink = submitLink();
form.add(submitLink);
form.setDefaultButton(submitLink);
}
private Component chooserButton(Form form) {
AjaxSubmitLink link = new AjaxSubmitLink("chooser") {
@Override
protected void onSubmit(AjaxRequestTarget target, Form form) {
dialog.setTitle(new ParamResourceModel("chooseDirectory", this));
dialog.showOkCancel(target, new GeoServerDialog.DialogDelegate() {
@Override
protected Component getContents(String id) {
// use what the user currently typed
File file = null;
if(!dirField.getInput().trim().equals("")) {
file = new File(dirField.getInput());
if(!file.exists())
file = null;
}
GeoServerFileChooser chooser = new GeoServerFileChooser(id, new Model(file));
chooser.setFilter(new Model(new ExtensionFileFilter(".shp")));
return chooser;
}
@Override
protected boolean onSubmit(AjaxRequestTarget target, Component contents) {
GeoServerFileChooser chooser = (GeoServerFileChooser) contents;
directory = ((File) chooser.getModelObject()).getAbsolutePath();
// clear the raw input of the field won't show the new model value
dirField.clearInput();
target.addComponent(dirField);
return true;
}
@Override
public void onClose(AjaxRequestTarget target) {
// update the field with the user chosen value
target.addComponent(dirField);
}
});
}
};
// otherwise the link won't trigger when the form contents are not valid
link.setDefaultFormProcessing(false);
return link;
}
SubmitLink submitLink() {
return new SubmitLink("import") {
@Override
public void onSubmit() {
try {
// build the datastore namespace URI
String ns = buildDatastoreNamespace();
// build the workspace
WorkspaceInfo ws = getCatalog().getWorkspaceByName(project);
boolean workspaceNew = false;
if (ws == null) {
workspaceNew = true;
ws = getCatalog().getFactory().createWorkspace();
ws.setName(project);
NamespaceInfo nsi = getCatalog().getFactory().createNamespace();
nsi.setPrefix(project);
nsi.setURI(ns);
getCatalog().add(ws);
getCatalog().add(nsi);
}
// build/reuse the store
String storeType = new DirectoryDataStoreFactory().getDisplayName();
Map<String, Serializable> params = new HashMap<String, Serializable>();
params.put(DirectoryDataStoreFactory.URLP.key, new File(directory).toURI().toURL().toString());
params.put(DirectoryDataStoreFactory.NAMESPACE.key, new URI(ns).toString());
DataStoreInfo si;
StoreInfo preExisting = getCatalog().getStoreByName(ws, project, StoreInfo.class);
boolean storeNew = false;
if(preExisting != null) {
if(!(preExisting instanceof DataStoreInfo)) {
error(new ParamResourceModel("storeExistsNotVector", this, project));
return;
}
si = (DataStoreInfo) preExisting;
if(!si.getType().equals(storeType) || !si.getConnectionParameters().equals(params)) {
error(new ParamResourceModel("storeExistsNotSame", this, project));
return;
}
// make sure it's enabled, we just verified the directory exists
si.setEnabled(true);
} else {
storeNew = true;
CatalogBuilder builder = new CatalogBuilder(getCatalog());
builder.setWorkspace(ws);
si = builder.buildDataStore(project);
si.getConnectionParameters().putAll(params);
si.setEnabled(true);
si.setType(storeType);
getCatalog().add(si);
}
// build and run the importer
FeatureTypeImporter importer = new FeatureTypeImporter(si, null, getCatalog(), workspaceNew, storeNew);
ImporterThreadManager manager = (ImporterThreadManager) getGeoServerApplication().getBean("importerPool");
String importerKey = manager.startImporter(importer);
setResponsePage(new ImportProgressPage(importerKey));
} catch (Exception e) {
LOGGER.log(Level.SEVERE, "Error while setting up mass import", e);
}
}
};
}
String buildDatastoreNamespace() {
return "http://www.geoserver.org/" + project;
}
static class DirectoryValidator extends AbstractValidator {
@Override
protected void onValidate(IValidatable validatable) {
String directory = (String) validatable.getValue();
DataStore store = null;
Map<String, Serializable> params = new HashMap<String, Serializable>();
try {
// check the store can be built (we need to provide the namespace as well
params.put(DirectoryDataStoreFactory.URLP.key, new File(directory).toURI().toURL());
params.put(DirectoryDataStoreFactory.NAMESPACE.key, new URI("http://www.geoserver.org"));
store = DataStoreFinder.getDataStore(params);
if (store == null) {
error(validatable, "ImportPage.invalidPath");
} else if (store.getTypeNames().length == 0) {
error(validatable, "ImportPage.noData");
}
} catch(Exception e) {
error(validatable, "ImportPage.noData");
}
}
}
class ProjectValidator extends AbstractValidator {
@Override
protected void onValidate(IValidatable validatable) {
String project = (String) validatable.getValue();
// new workspace? if so, good
WorkspaceInfo ws = getCatalog().getWorkspaceByName(project);
if(ws == null)
return;
// new store too?
StoreInfo store = getCatalog().getStoreByName(ws, project, StoreInfo.class);
if(store != null)
error(validatable, "ImportPage.duplicateStore",
Collections.singletonMap("project", project));
}
}
}