/* 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.util.List; import java.util.Map; import java.util.logging.Level; import org.geoserver.catalog.CascadeDeleteVisitor; 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.catalog.WorkspaceInfo; import org.geoserver.config.util.XStreamPersister; import org.geoserver.rest.RestletException; import org.geoserver.rest.format.DataFormat; import org.geotools.data.DataAccessFactory; import org.restlet.Context; import org.restlet.data.Request; import org.restlet.data.Response; import org.restlet.data.Status; import org.restlet.resource.Resource; import org.vfny.geoserver.util.DataStoreUtils; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import freemarker.ext.beans.CollectionModel; import freemarker.template.Configuration; import freemarker.template.SimpleHash; public class DataStoreResource extends AbstractCatalogResource { public DataStoreResource(Context context, Request request, Response response, Catalog catalog) { super(context, request, response, DataStoreInfo.class, catalog); } @Override protected DataFormat createHTMLFormat(Request request, Response response) { return new DataStoreHTMLFormat( request, response, this, catalog ); } @Override protected Object handleObjectGet() { String ws = getAttribute( "workspace" ); String ds = getAttribute( "datastore" ); WorkspaceInfo wsInfo = catalog.getWorkspaceByName(ws); LOGGER.fine( "GET data store " + ws + "," + ds ); return catalog.getDataStoreByName( wsInfo, ds ); } @Override public boolean allowPost() { return getAttribute("datastore") == null; } @Override protected String handleObjectPost(Object object) throws Exception { String workspace = getAttribute( "workspace" ); DataStoreInfo ds = (DataStoreInfo) object; if ( ds.getWorkspace() != null ) { //ensure the specifried workspace matches the one dictated by the uri WorkspaceInfo ws = (WorkspaceInfo) ds.getWorkspace(); if ( !workspace.equals( ws.getName() ) ) { throw new RestletException( "Expected workspace " + workspace + " but client specified " + ws.getName(), Status.CLIENT_ERROR_FORBIDDEN ); } } else { ds.setWorkspace( catalog.getWorkspaceByName( workspace ) ); } ds.setEnabled(true); //if no namespace parameter set, set it //TODO: we should really move this sort of thing to be something central Map params = ds.getConnectionParameters(); if (!ds.getConnectionParameters().containsKey("namespace")) { WorkspaceInfo ws = ds.getWorkspace(); NamespaceInfo ns = catalog.getNamespaceByPrefix(ws.getName()); if (ns == null) { ns = catalog.getDefaultNamespace(); } if (ns != null) { ds.getConnectionParameters().put("namespace", ns.getURI()); } } //attempt to set the datastore type try { DataAccessFactory factory = DataStoreUtils.aquireFactory(ds.getConnectionParameters()); ds.setType(factory.getDisplayName()); } catch(Exception e) { LOGGER.warning("Unable to determine datastore type from connection parameters"); if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, "", e); } } catalog.add( (DataStoreInfo) object ); LOGGER.info( "POST data store " + ds.getName() ); return ds.getName(); } @Override public boolean allowPut() { return getAttribute( "datastore" ) != null; } @Override protected void handleObjectPut(Object object) throws Exception { String workspace = getAttribute("workspace"); String datastore = getAttribute("datastore"); DataStoreInfo ds = (DataStoreInfo) object; DataStoreInfo original = catalog.getDataStoreByName(workspace, datastore); //ensure this is not a name or workspace change if ( ds.getName() != null && !ds.getName().equals( original.getName() ) ) { throw new RestletException( "Can't change name of data store.", Status.CLIENT_ERROR_FORBIDDEN ); } if ( ds.getWorkspace() != null && !ds.getWorkspace().equals( original.getWorkspace() ) ) { throw new RestletException( "Can't change workspace of data store.", Status.CLIENT_ERROR_FORBIDDEN ); } new CatalogBuilder( catalog ).updateDataStore( original, ds ); catalog.save( original ); clear(original); LOGGER.info( "PUT data store " + workspace + "," + datastore ); } @Override public boolean allowDelete() { return getAttribute( "datastore" ) != null; } @Override protected void handleObjectDelete() throws Exception { String workspace = getAttribute("workspace"); String datastore = getAttribute("datastore"); boolean recurse = getQueryStringValue("recurse", Boolean.class, false); DataStoreInfo ds = catalog.getDataStoreByName(workspace, datastore); if (!recurse) { if ( !catalog.getFeatureTypesByDataStore(ds).isEmpty() ) { throw new RestletException( "datastore not empty", Status.CLIENT_ERROR_FORBIDDEN); } catalog.remove( ds ); } else { //recursive delete new CascadeDeleteVisitor(catalog).visit(ds); } clear(ds); LOGGER.info( "DELETE data store " + workspace + "," + datastore ); } void clear(DataStoreInfo info) { catalog.getResourcePool().clear(info); } @Override protected void configurePersister(XStreamPersister persister, DataFormat format) { persister.setCallback( new XStreamPersister.Callback() { @Override protected void postEncodeDataStore(DataStoreInfo ds, HierarchicalStreamWriter writer, MarshallingContext context) { //add a link to the feature types writer.startNode( "featureTypes"); encodeCollectionLink("featuretypes", writer); writer.endNode(); } @Override protected void postEncodeReference(Object obj, String ref, HierarchicalStreamWriter writer, MarshallingContext context) { if ( obj instanceof WorkspaceInfo ) { encodeLink("/workspaces/" + encode(ref), writer ); } } } ); } static class DataStoreHTMLFormat extends CatalogFreemarkerHTMLFormat { Catalog catalog; public DataStoreHTMLFormat(Request request, Response response, Resource resource, Catalog catalog) { super(DataStoreInfo.class, request, response, resource); this.catalog = catalog; } @Override protected Configuration createConfiguration(Object data, Class clazz) { Configuration cfg = super.createConfiguration(data, clazz); cfg.setObjectWrapper(new ObjectToMapWrapper<DataStoreInfo>(DataStoreInfo.class) { @Override protected void wrapInternal(Map properties, SimpleHash model, DataStoreInfo object) { List<FeatureTypeInfo> featureTypes = catalog.getFeatureTypesByDataStore(object); properties.put( "featureTypes", new CollectionModel( featureTypes, new ObjectToMapWrapper(FeatureTypeInfo.class) ) ); } }); return cfg; } } }