/* Copyright (c) 2001 - 2009 TOPP - www.openplans.org. All rights reserved.
* This code is licensed under the GPL 2.0 license, availible at the root
* application directory.
*/
package org.geoserver.catalog.rest;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.Map;
import java.util.logging.Level;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.apache.commons.io.IOUtils;
import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.CatalogBuilder;
import org.geoserver.catalog.DataStoreInfo;
import org.geoserver.catalog.FeatureTypeInfo;
import org.geoserver.catalog.NamespaceInfo;
import org.geoserver.rest.RestletException;
import org.geoserver.rest.format.StreamDataFormat;
import org.geotools.data.DataStore;
import org.geotools.data.DataStoreFactorySpi;
import org.geotools.data.FeatureSource;
import org.geotools.data.DataAccessFactory.Param;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.restlet.data.Form;
import org.restlet.data.MediaType;
import org.restlet.data.Request;
import org.restlet.data.Response;
import org.restlet.data.Status;
public class DataStoreFileResource extends StoreFileResource {
DataStoreFactorySpi factory;
public DataStoreFileResource( Request request, Response response, DataStoreFactorySpi factory, Catalog catalog ) {
super( request, response, catalog );
this.factory = factory;
}
@Override
public void handleGet() {
String workspace = (String)getRequest().getAttributes().get("workspace");
String datastore = (String)getRequest().getAttributes().get("datastore");
String format = (String)getRequest().getAttributes().get("format");
//find the directory containig the files
File directory;
try {
directory = catalog.getResourceLoader().find( "data/" + datastore );
}
catch (IOException e) {
throw new RestletException( e.getMessage(), Status.SERVER_ERROR_INTERNAL, e );
}
if ( directory == null || !directory.exists() || !directory.isDirectory() ) {
throw new RestletException( "No files for datastore " + datastore, Status.CLIENT_ERROR_NOT_FOUND );
}
//zip up all the files in the directory
StreamDataFormat fmt = new StreamDataFormat(MediaType.APPLICATION_ZIP) {
@Override
protected Object read(InputStream in) throws IOException {
return null;
}
@Override
protected void write(Object object, OutputStream out)
throws IOException {
ZipOutputStream zout = new ZipOutputStream( out );
File directory = (File) object;
for ( File f : directory.listFiles() ) {
ZipEntry entry = new ZipEntry( f.getName() );
zout.putNextEntry(entry);
IOUtils.copy( new FileInputStream( f ), zout );
zout.closeEntry();
}
zout.flush();
zout.close();
}
};
getResponse().setEntity( fmt.toRepresentation( directory ) );
}
@Override
public void handlePut() {
String workspace = (String)getRequest().getAttributes().get("workspace");
String datastore = (String)getRequest().getAttributes().get("datastore");
String format = (String)getRequest().getAttributes().get("format");
getResponse().setStatus(Status.SUCCESS_ACCEPTED);
Form form = getRequest().getResourceRef().getQueryAsForm();
//get the directory to put the file into
//TODO: add a method createDirectory(String...) so as not to specify the file seperator
File directory;
try {
directory = catalog.getResourceLoader().createDirectory( "data/" + datastore );
}
catch (IOException e) {
throw new RestletException( e.getMessage(), Status.SERVER_ERROR_INTERNAL, e );
}
File uploadedFile = handleFileUpload(datastore, format, directory);
//create a builder to help build catalog objects
CatalogBuilder builder = new CatalogBuilder(catalog);
builder.setWorkspace( catalog.getWorkspaceByName( workspace ) );
//check if the datastore already exists, if not auto configure one
DataStoreInfo info = catalog.getDataStoreByName( datastore );
boolean add = false;
if ( info == null ) {
LOGGER.info("Auto-configuring datastore: " + datastore);
info = builder.buildDataStore( datastore );
add = true;
}
else {
LOGGER.info("Using existing datastore: " + datastore);
}
builder.setStore(info);
//update the connection parameters to point to the new file
Map connectionParameters = info.getConnectionParameters();
for ( Param p : factory.getParametersInfo() ) {
//the nasty url / file hack
if ( File.class == p.type || URL.class == p.type ) {
File f = uploadedFile;
if ( "directory".equals( p.key ) ) {
//set the value to be the directory
f = directory;
}
//convert to the required type
//TODO: use geotools converter
Object converted = null;
if ( URI.class.equals( p.type ) ) {
converted = f.toURI();
}
else if ( URL.class.equals( p.type ) ) {
try {
converted = f.toURL();
}
catch (MalformedURLException e) {
}
}
//Converters.convert( f.getAbsolutePath(), p.type );
if ( converted != null ) {
connectionParameters.put( p.key, converted );
}
else {
connectionParameters.put( p.key, f );
}
continue;
}
if ( p.required ) {
try {
p.lookUp( connectionParameters );
}
catch( Exception e ) {
//set the sample value
connectionParameters.put( p.key, p.sample );
}
}
}
// set the namespace uri
NamespaceInfo namespace = catalog.getNamespaceByPrefix( info.getWorkspace().getName() );
connectionParameters.put( "namespace", namespace.getURI() );
// ensure the parameters are valid
if ( !factory.canProcess( connectionParameters ) ) {
//TODO: log the parameters at the debug level
throw new RestletException( "Unable to configure datastore, bad parameters.", Status.SERVER_ERROR_INTERNAL );
}
//add or update the datastore info
if ( add ) {
catalog.add( info );
}
else {
catalog.save( info );
}
//check configure parameter, if set to none to not try to configure
// data feature types
String configure = form.getFirstValue( "configure" );
if ( "none".equalsIgnoreCase( configure ) ) {
getResponse().setStatus( Status.SUCCESS_CREATED );
return;
}
//load the datastore
try {
DataStore ds = (DataStore) info.getDataStore(null);
String[] featureTypeNames = ds.getTypeNames();
for ( int i = 0; i < featureTypeNames.length; i++ ) {
//unless configure specified "all", only configure the first feature type
if ( !"all".equalsIgnoreCase( configure ) && i > 0 ) {
break;
}
FeatureSource fs = ds.getFeatureSource(featureTypeNames[i]);
FeatureTypeInfo ftinfo = null;
if ( add ) {
//auto configure the feature type as well
ftinfo = builder.buildFeatureType(fs);
builder.lookupSRS(ftinfo, true);
builder.setupBounds(ftinfo);
}
else {
ftinfo = catalog.getFeatureTypeByName( namespace.getPrefix(), featureTypeNames[i] );
}
//update the bounds
ReferencedEnvelope bounds = fs.getBounds();
ftinfo.setNativeBoundingBox( bounds );
//TODO: set lat lon bounding box
if ( add ) {
catalog.add( ftinfo );
//add a layer for the feature type as well
catalog.add(builder.buildLayer(ftinfo));
}
else {
catalog.save( ftinfo );
}
getResponse().setStatus( Status.SUCCESS_CREATED );
}
}
catch (Exception e) {
//TODO: report a proper error code
throw new RuntimeException ( e );
}
}
}