/* * GeoServer-Manager - Simple Manager Library for GeoServer * * Copyright (C) 2007,2011 GeoSolutions S.A.S. * http://www.geo-solutions.it * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package it.geosolutions.geoserver.rest; import it.geosolutions.geoserver.rest.decoder.RESTCoverageList; import it.geosolutions.geoserver.rest.decoder.RESTCoverageStore; import it.geosolutions.geoserver.rest.decoder.utils.NameLinkElem; import it.geosolutions.geoserver.rest.encoder.GSLayerEncoder; import it.geosolutions.geoserver.rest.encoder.GSPostGISDatastoreEncoder; import it.geosolutions.geoserver.rest.encoder.GSResourceEncoder.ProjectionPolicy; import it.geosolutions.geoserver.rest.encoder.GSWorkspaceEncoder; import it.geosolutions.geoserver.rest.encoder.coverage.GSCoverageEncoder; import it.geosolutions.geoserver.rest.encoder.feature.GSFeatureTypeEncoder; import java.io.File; import java.io.FileNotFoundException; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; import java.net.URLEncoder; import java.util.Iterator; import org.apache.commons.httpclient.NameValuePair; import org.apache.commons.io.FilenameUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Connect to a GeoServer instance to publish or modify data. *
* There are no modifiable instance fields, so all the calls are thread-safe. * * @author ETj (etj at geo-solutions.it) */ public class GeoServerRESTPublisher { private static final Logger LOGGER = LoggerFactory.getLogger(GeoServerRESTPublisher.class); private final String restURL; private final String gsuser; private final String gspass; /** * Creates a GeoServerRESTPublisher for a given GeoServer instance * with the given auth credentials. * * @param restURL * the base GeoServer URL (e.g.: * http://localhost:8080/geoserver) * @param username * username auth credential * @param password * password auth credential */ public GeoServerRESTPublisher(String restURL, String username, String password) { this.restURL = HTTPUtils.decurtSlash(restURL); this.gsuser = username; this.gspass = password; } // ========================================================================== // === WORKSPACES // ========================================================================== /** * Create a new Workspace * * @param workspace * The name of the new workspace. * *
* This is the equivalent call with cUrl: * *
* {@code curl -u admin:geoserver -XPOST \
* -H 'Content-type: text/xml' \
* -d "$WORKSPACE " \
* http://$GSIP:$GSPORT/$SERVLET/rest/workspaces
* }
*
*/
public boolean createWorkspace(final String workspace) {
final String sUrl = restURL + "/rest/workspaces";
final GSWorkspaceEncoder wsenc = new GSWorkspaceEncoder(workspace);
final String wsxml = wsenc.toString();
final String result = HTTPUtils.postXml(sUrl, wsxml, gsuser, gspass);
return result != null;
}
// ==========================================================================
// === STYLES
// ==========================================================================
/**
* Store and publish an SLD.
* * This is the equivalent call with cUrl: * *
* {@code curl -u admin:geoserver -XPOST \
* -H 'Content-type: application/vnd.ogc.sld+xml' \
* -d @$FULLSLD \
* http://$GSIP:$GSPORT/$SERVLET/rest/styles}
*
*
* @param sldBody
* the SLD document as an XML String.
*
* @return true if the operation completed successfully.
*/
public boolean publishStyle(String sldBody) {
try {
return publishStyle(sldBody, null);
} catch (IllegalArgumentException e) {
if (LOGGER.isErrorEnabled()) {
LOGGER.error(e.getLocalizedMessage(), e);
}
}
return false;
}
/**
* Store and publish an SLD.
* * This is the equivalent call with cUrl: * *
* {@code curl -u admin:geoserver -XPOST \
* -H 'Content-type: application/vnd.ogc.sld+xml' \
* -d @$FULLSLD \
* http://$GSIP:$GSPORT/$SERVLET/rest/styles?name=name}
*
*
* @param sldBody
* the SLD document as an XML String.
* @param name
* the Style name (can be null).
*
* @return true if the operation completed successfully.
* @throws IllegalArgumentException
* if the style body is null or empty
*/
public boolean publishStyle(final String sldBody, final String name)
throws IllegalArgumentException {
if (sldBody == null || sldBody.isEmpty()) {
throw new IllegalArgumentException(
"The style body may not be null or empty");
}
StringBuilder sUrl = new StringBuilder(restURL);
sUrl.append("/rest/styles");
if (name != null && !name.isEmpty()) {
sUrl.append("?name=").append(name);
}
final String result = HTTPUtils.post(sUrl.toString(), sldBody,
"application/vnd.ogc.sld+xml", gsuser, gspass);
return result != null;
}
/**
* Store and publish an SLD.
*
* @param sldFile
* the File containing the SLD document.
*
* @return true if the operation completed successfully.
*/
public boolean publishStyle(File sldFile) {
return publishStyle(sldFile, null);
}
/**
* Store and publish an SLD, assigning it a name.
*
* @param sldFile
* the File containing the SLD document.
* @param name
* the Style name.
*
* @return true if the operation completed successfully.
*/
public boolean publishStyle(File sldFile, String name) {
String sUrl = restURL + "/rest/styles";
if (name != null && !name.isEmpty()) {
sUrl += "?name=" + encode(name);
}
LOGGER.debug("POSTing new style " + name + " to " + sUrl);
String result = HTTPUtils.post(sUrl, sldFile,
"application/vnd.ogc.sld+xml", gsuser, gspass);
return result != null;
}
/**
* Update SLD called as 'name'.
* * This is the equivalent call with cUrl: * *
* {@code curl -u admin:geoserver -XPUT \
* -H 'Content-type: application/vnd.ogc.sld+xml' \
* -d @$FULLSLD \
* http://$GSIP:$GSPORT/$SERVLET/rest/styles/$NAME}
*
*
* @param sldBody
* the SLD document as an XML String.
* @param name
* the Style name to modify.
*
* @return true if the operation completed successfully.
*
* @throws IllegalArgumentException
* if the style body or name are null or empty
*
*/
public boolean updateStyle(final String sldBody, final String name)
throws IllegalArgumentException {
if (sldBody == null || sldBody.isEmpty()) {
throw new IllegalArgumentException(
"The style body may not be null or empty");
} else if (name == null || name.isEmpty()) {
throw new IllegalArgumentException(
"The style name may not be null or empty");
}
final StringBuilder sUrl = new StringBuilder(restURL);
sUrl.append("/rest/styles/").append(encode(name));
final String result = HTTPUtils.put(sUrl.toString(), sldBody,
"application/vnd.ogc.sld+xml", gsuser, gspass);
return result != null;
}
/**
* Update an SLD called 'name'.
*
* @param sldFile
* the File containing the SLD document.
* @param name
* the Style name.
*
* @return true if the operation completed successfully.
*
* @throws IllegalArgumentException
* if the sldFile file or name are null or name is empty
*
*/
public boolean updateStyle(final File sldFile, final String name)
throws IllegalArgumentException {
if (sldFile == null) {
throw new IllegalArgumentException(
"Unable to updateStyle using a null parameter file");
} else if (name == null || name.isEmpty()) {
throw new IllegalArgumentException(
"The style name may not be null or empty");
}
final StringBuilder sUrl = new StringBuilder(restURL);
sUrl.append("/rest/styles/").append(encode(name));
final String result = HTTPUtils.put(sUrl.toString(), sldFile,
"application/vnd.ogc.sld+xml", gsuser, gspass);
return result != null;
}
/**
* Remove a Style.
* The Style will be unpublished and the related SLD file will be removed.
*
* @param styleName
* the name of the Style to remove.
*
* @return true if the operation completed successfully.
*/
public boolean removeStyle(String styleName) {
try {
return removeStyle(styleName, true);
} catch (IllegalArgumentException e) {
if (LOGGER.isErrorEnabled()) {
LOGGER.error(e.getLocalizedMessage(), e);
}
}
return false;
}
private boolean createDataStore(String workspace, String storeName,
UploadMethod method, DataStoreExtension extension, String mimeType, URI uri,
ParameterConfigure configure, NameValuePair... params)
throws FileNotFoundException, IllegalArgumentException {
return createStore(workspace, DataStoreType.datastores, storeName, method, extension, mimeType, uri, configure, params);
}
private boolean createCoverageStore(String workspace, String storeName,
UploadMethod method, CoverageStoreExtension extension, String mimeType, URI uri,
ParameterConfigure configure, NameValuePair... params)
throws FileNotFoundException, IllegalArgumentException {
return createStore(workspace, DataStoreType.coveragestores, storeName, method, extension, mimeType, uri, configure, params);
}
/**
*
* @param workspace
* @param dsType
* @param storeName
* @param method
* @param extension
* @param mimeType
* @param uri
* @param configure
* @param params
* @return
* @throws FileNotFoundException
* @throws IllegalArgumentException
*/
private boolean createStore(String workspace, DataStoreType dsType, String storeName, UploadMethod method, Enum extension,
String mimeType, URI uri, ParameterConfigure configure, NameValuePair... params)
throws FileNotFoundException, IllegalArgumentException {
if (workspace==null||dsType==null||storeName==null||method==null|extension==null||mimeType==null||uri==null){
throw new IllegalArgumentException("Null argument");
}
StringBuilder sbUrl = new StringBuilder(restURL)
.append("/rest/workspaces/").append(workspace)
.append("/").append(dsType).append("/").append(storeName)
.append("/").append(method).append(".").append(extension);
if (configure != null) {
sbUrl.append("?configure=").append(configure);
if (params != (NameValuePair[]) null
&& !configure.equals(ParameterConfigure.NONE)) {
final String paramString = appendParameters(params);
if (!paramString.isEmpty()) {
sbUrl.append("&").append(paramString);
}
}
}
String sentResult =null;
if (method.equals(UploadMethod.file)){
final File file=new File(uri);
if (!file.exists())
throw new FileNotFoundException("unable to locate file: "+file);
sentResult = HTTPUtils.put(sbUrl.toString(), file, mimeType, gsuser, gspass);
} else if (method.equals(UploadMethod.external)){
sentResult = HTTPUtils.put(sbUrl.toString(), uri.toString(), mimeType, gsuser, gspass);
} else if (method.equals(UploadMethod.url)){
// TODO check
sentResult = HTTPUtils.put(sbUrl.toString(), uri.toString(), mimeType, gsuser, gspass);
}
if (sentResult != null) {
if (LOGGER.isInfoEnabled())
LOGGER.info("Store successfully created using ( " + uri + " )");
return true;
} else {
if (LOGGER.isErrorEnabled())
LOGGER.error("Error in creating store using: " + uri);
return false;
}
}
/**
* A data store is a source of spatial data that is vector based. It can be
* a file in the case of a Shapefile, a database in the case of PostGIS, or
* a server in the case of a remote Web Feature Service.
*
* A coverage store is a source of spatial data that is raster based.
*
* @author Carlo Cancellieri - carlo.cancellieri@geo-solutions.it
*
*/
public enum DataStoreType{
coveragestores,
datastores
}
/**
* The file, url, and external endpoints are used to specify the method that
* is used to upload the file.
*
* The file method is used to directly upload a file from a local source.
* The body of the request is the file itself.
*
* The url method is used to indirectly upload a file from an remote source.
* The body of the request is a url pointing to the file to upload. This url
* must be visible from the server.
*
* The external method is used to forgo upload and use an existing file on
* the server. The body of the request is the absolute path to the existing
* file.
*
* @author Carlo Cancellieri - carlo.cancellieri@geo-solutions.it
*
*/
public enum UploadMethod {
file,
url,
external
}
// ==========================================================================
// === DATASTORE
// ==========================================================================
/**
* Create a PostGIS datastore.
*
* @param workspace
* Name of the workspace to contain the database. This will also
* be the prefix of any layer names created from tables in the
* database.
* @param datastoreEncoder
* the set of parameters to be set to the datastore (including
* connection params)
*
* @return true if the PostGIS datastore has been successfully
* created, false otherwise
*/
public boolean createPostGISDatastore(String workspace,
GSPostGISDatastoreEncoder datastoreEncoder) {
String sUrl = restURL + "/rest/workspaces/" + workspace
+ "/datastores/";
String xml = datastoreEncoder.toString();
String result = HTTPUtils.postXml(sUrl, xml, gsuser, gspass);
return result != null;
}
// ==========================================================================
// === SHAPEFILES
// ==========================================================================
/**
* Publish a zipped shapefile.
* The CRS will be forced to EPSG:4326.
*
* @param workspace
* @param storename
* @param layername
* @param zipFile
* @return true if the operation completed successfully.
* @throws FileNotFoundException
*/
public boolean publishShp(String workspace, String storename,
String layername, File zipFile) throws FileNotFoundException {
return publishShp(workspace, storename, layername, zipFile, "EPSG:4326");
}
/**
* Publish a zipped shapefile.
*
* @param workspace
* @param storename
* @param layerName
* @param nativeCrs
* @param defaultStyle
* may be null
* @return true if the operation completed successfully.
* @throws FileNotFoundException
*/
public boolean publishShp(String workspace, String storename,
String layerName, File zipFile, String nativeCrs,
String defaultStyle) throws FileNotFoundException {
boolean sent = publishShp(workspace, storename, layerName, zipFile,
nativeCrs);
if (sent) {
try {
GSLayerEncoder layerEncoder = new GSLayerEncoder();
layerEncoder.setDefaultStyle(defaultStyle);
configureLayer(workspace, layerName, layerEncoder);
} catch (Exception e) {
LOGGER.warn("Error in publishing shapefile " + e.getMessage(),
e);
sent = false;
}
}
return sent;
}
/**
* Publish a zipped shapefile.
*
*
* These are the equivalent calls with cUrl: * *
* {@code
* curl -u admin:geoserver -XPUT -H 'Content-type: application/zip' \
* --data-binary @$ZIPFILE \
* http://$GSIP:$GSPORT/$SERVLET/rest/workspaces/$WORKSPACE/datastores/$STORENAME/file.shp
*
* curl -u admin:geoserver -XPOST -H 'Content-type: text/xml' \
* -d "$BARE EPSG:4326 true " \
* http://$GSIP:$GSPORT/$SERVLET/rest/workspaces/$WORKSPACE/datastores/$STORENAME/featuretypes/$LAYERNAME
* }
*
*
* {@link #publishShp(String, String, String, File, String, NameValuePair...)}
*
* @return true if the operation completed successfully.
*/
public boolean publishShp(String workspace, String storename,
String layername, File zipFile, String srs)
throws FileNotFoundException {
return publishShp(workspace, storename, layername, zipFile, srs,
new NameValuePair[0]);
}
/**
*
* Publish a zipped shapefile.* This is the equivalent call with cUrl: * *
* {@code curl -u admin:geoserver -XPOST -H 'Content-type: text/xml' \
* -d "easia_gaul_1_aggr EPSG:4326 true " \
* http://localhost:8080/geoserver/rest/workspaces/it.geosolutions/datastores/pg_kids/featuretypes
* }
*
*
* and a PUT to * This is an example with cUrl: * *
* {@code
* curl -u admin:geoserver -XPUT -H 'Content-type: application/zip' \
*
* --data-binary @$ZIPFILE \
*
* http://$GSIP:$GSPORT/$SERVLET/rest/workspaces/$WORKSPACE/coveragestores/$COVERAGESTORE/file.worldimage
*
*
* @param workspace
* Workspace to use
* @param coveragestore
* Name of the coveragestore
* @param file
* file to upload
* @param configure
* Configure parameter. It may be null.
* @param params
* parameters to append to the url (can be null).* Here is an example call with cUrl: * *
* {@code
* curl -u admin:geoserver -XPUT -H 'Content-type: application/zip' \
*
* --data-binary @$ZIPFILE \
*
* http://$GSIP:$GSPORT/$SERVLET/rest/workspaces/$WORKSPACE/coveragestores/$COVERAGESTORE/file.worldimage
*
*
* @param workspace
* Workspace to use
* @param coveragestore
* Name of the coveragestore
* @param file
* file to upload
* @param configure
* Configure parameter. It may be null.
* @param update
* Accepted parameters are:
* * This is the equivalent call with cUrl: * *
* {@code
* curl -u admin:geoserver -XPUT -H 'Content-type: text' -d "file:$FULLPATH" \
* http://$GSIP:$GSPORT/$SERVLET/rest/workspaces/$WORKSPACE/coveragestores/$STORENAME/external.geotiff
* }
*
*
* @param workspace Workspace to use
* @param storeName Name of the coveragestore (if null the file name will be used)
* @param coverageName the name of the coverage (if null the file name will be used)
* @param geotiff file to upload
* @return true if the operation completed successfully.
* @throws FileNotFoundException if file does not exists
* @throws IllegalArgumentException if workspace or geotiff are null
*/
public boolean publishGeoTIFF(final String workspace, final String storeName, final String coverageName,
final File geotiff) throws FileNotFoundException, IllegalArgumentException {
if (workspace==null || geotiff==null)
throw new IllegalArgumentException("Unable to proceed, some arguments are null");
return publishCoverage(workspace, (storeName!=null)?storeName:FilenameUtils.getBaseName(geotiff.getAbsolutePath()), CoverageStoreExtension.geotiff,
"image/geotiff", geotiff, ParameterConfigure.FIRST,
(coverageName!=null)?new NameValuePair[]{new NameValuePair("coverageName", coverageName)}:(NameValuePair[]) null);
}
/**
*
* Publish a GeoTiff already in a filesystem readable by GeoServer.
*
* @param workspace
* an existing workspace
* @param storeName
* the coverageStore to be created
* @param geotiff
* the geoTiff to be published
* @param srs
* @param policy
* @param defaultStyle
* @return
* @throws FileNotFoundException
*/
public boolean publishExternalGeoTIFF(String workspace,
String storeName, File geotiff, String coverageName, String srs, ProjectionPolicy policy, String defaultStyle)
throws FileNotFoundException, IllegalArgumentException {
if (workspace==null || storeName==null || geotiff==null || coverageName==null || srs==null || policy==null || defaultStyle==null)
throw new IllegalArgumentException("Unable to run: null parameter");
// config coverage props (srs)
final GSCoverageEncoder coverageEncoder = new GSCoverageEncoder();
coverageEncoder.setName(coverageName);
coverageEncoder.setSRS(srs);
coverageEncoder.setProjectionPolicy(policy);
// config layer props (style, ...)
final GSLayerEncoder layerEncoder = new GSLayerEncoder();
layerEncoder.setDefaultStyle(defaultStyle);
return publishExternalGeoTIFF(workspace, storeName, geotiff, coverageEncoder, layerEncoder)!=null?true:false;
}
// /**
// *
// * @param workspace
// * @param storeName
// * @param geotiff
// * @param srs
// * @param defaultStyle
// * @return
// * @throws FileNotFoundException
// * @deprecated
// */
// public RESTCoverageStore publishExternalGeoTIFF(String workspace,
// String storeName, File geotiff, String srs, String defaultStyle)
// throws FileNotFoundException {
//
// if (publishExternalGeoTIFF(workspace, storeName, geotiff, storeName, srs,ProjectionPolicy.FORCE_DECLARED,defaultStyle)){
// GeoServerRESTReader reader=new GeoServerRESTReader(this.restURL, this.gsuser, this.gspass);
// return reader.getCoverageStore(workspace, storeName);
// }
// return null;
// }
/**
* Publish a GeoTiff already in a filesystem readable by GeoServer.
*
* @param workspace
* an existing workspace
* @param storeName
* the coverageStore to be created
* @param geotiff
* the geoTiff to be published
* @param coverageEncoder
* @param layerEncoder
* @return true if successfully configured
*
*
* @throws FileNotFoundException
* @throws IllegalArgumentException if null parameter
*/
public RESTCoverageStore publishExternalGeoTIFF(final String workspace, final String storeName, final File geotiff, final GSCoverageEncoder coverageEncoder,final GSLayerEncoder layerEncoder)
throws IllegalArgumentException, FileNotFoundException {
if (workspace==null || geotiff==null || storeName==null || layerEncoder==null || coverageEncoder==null)
throw new IllegalArgumentException("Unable to run: null parameter");
final String coverageName=coverageEncoder.getName();
if (coverageName.isEmpty()){
throw new IllegalArgumentException("Unable to run: empty coverage store name");
}
// create store
final boolean store=publishExternalCoverage(workspace, storeName, CoverageStoreExtension.geotiff, "text/plain", geotiff, ParameterConfigure.NONE, ParameterUpdate.OVERWRITE);
if (!store) {
return null;
}
// create Coverage Store
if (!createCoverage(workspace, storeName, coverageEncoder)) {
if (LOGGER.isErrorEnabled())
LOGGER.error("Unable to create a coverage for the store:"+ coverageName);
return null;
}
// create Layer
if (configureLayer(workspace, coverageName, layerEncoder)){
GeoServerRESTReader reader;
try {
reader = new GeoServerRESTReader(this.restURL, this.gsuser, this.gspass);
return reader.getCoverageStore(workspace, storeName);
} catch (MalformedURLException e) {
LOGGER.error(e.getMessage(), e);
}
}
return null;
}
// ==========================================================================
// === WORLDIMAGE
// ==========================================================================
/**
* {@link #publishWorldImage(String, String, File, ParameterConfigure, NameValuePair...)}
*/
public boolean publishWorldImage(String workspace, String coveragestore,
File zipFile) throws FileNotFoundException {
return publishWorldImage(workspace, coveragestore, zipFile,
ParameterConfigure.FIRST, (NameValuePair) null);
}
/**
*
* Publish a zipped worldimage file. It is assumed that the the zip-file
* contain the *.prj to set the srs.
* * This is equivalent call with cUrl: * *
* {@code
* curl -u admin:geoserver -XPUT -H 'Content-type: application/zip' \
*
* --data-binary @$ZIPFILE \
*
* http://$GSIP:$GSPORT/$SERVLET/rest/workspaces/$WORKSPACE/coveragestores/$COVERAGESTORE/file.worldimage
*
*
* @param workspace
* Workspace to use
* @param coveragestore
* Name of the coveragestore
* @param zipFile
* zip file to upload
* @param configure
* Configure parameter. It may be null.
* @param params
* parameters to append to the url (can be null).
* Sample cUrl usage:
* <>
* curl -u admin:geoserver -XPUT -H 'Content-type: text' -d "file:$ABSPORTDIR"
* http://$GSIP:$GSPORT/$SERVLET/rest/workspaces/$WORKSPACE/coveragestores/$BAREDIR/external.imagemosaic
*
* @param workspace
* an existing workspace
* @param storeName
* the name of the coverageStore to be created
* @param mosaicDir
* the directory where the raster images are located
* @param configure
* a specify if a coverage should be configured
* @return true if the operation completed successfully.
* @throws FileNotFoundException
*/
public RESTCoverageStore createExternaMosaicDatastore(String workspace,
String storeName, File mosaicDir, ParameterConfigure configure,
ParameterUpdate update) throws FileNotFoundException {
/*
* Carlo (23 Nov 2011): commented out since this directory should be
* readable by target GeoServer not the calling client!
*/
if (!mosaicDir.isDirectory()) {
if (LOGGER.isWarnEnabled())
LOGGER.warn("Directory '"
+ mosaicDir
+ "' not exists locally. Continue: please check existance on the remote server.");
}
String sUrl = restURL + "/rest/workspaces/" + workspace
+ "/coveragestores/" + storeName
+ "/external.imagemosaic?configure=" + configure.toString()
+ "&update=" + update.toString();
String sendResult = HTTPUtils.put(sUrl, mosaicDir.toURI().toString(),
"text/plain", gsuser, gspass);
return RESTCoverageStore.build(sendResult);
}
/**
* @deprecated provided for backward compatibility use {@link
* createExternaMosaicDatastore(String workspace, String
* storeName, File mosaicDir, CoverageConfigure configure)}
* @param workspace
* @param storeName
* @param mosaicDir
* @return
* @throws FileNotFoundException
*/
// public RESTCoverageStore configureExternaMosaicDatastore(String workspace,
// String storeName, File mosaicDir) throws FileNotFoundException {
// return createExternaMosaicDatastore(workspace, storeName, mosaicDir,
// ParameterConfigure.FIRST, ParameterUpdate.APPEND);
// }
/**
* Publish a Mosaic already in a filesystem readable by GeoServer.
*
*
* Sample cUrl usage:
* curl -u admin:geoserver -XPUT -H 'Content-type: text' -d "file:$ABSPORTDIR"
* http://$GSIP:$GSPORT/$SERVLET/rest/workspaces/$WORKSPACE/coveragestores/$BAREDIR/external.imagemosaic
*
* @param workspace
* an existing workspace
* @param storeName
* the name of the coverageStore to be created
* @param mosaicDir
* the directory where the raster images are located
* @param srs
* the coverage declared SRS
* @param defaultStyle
* may be null
*
* @return true if the operation completed successfully.
*
* @throws FileNotFoundException
*/
public boolean publishExternalMosaic(String workspace,
String storeName, File mosaicDir, String srs, String defaultStyle)
throws FileNotFoundException {
final GSCoverageEncoder coverageEncoder = new GSCoverageEncoder();
coverageEncoder.setSRS(srs);
final String name=FilenameUtils.getBaseName(mosaicDir.getName());
coverageEncoder.setName(name);
final GSLayerEncoder layerEncoder = new GSLayerEncoder();
layerEncoder.setDefaultStyle(defaultStyle);
return publishExternalMosaic(workspace, storeName, mosaicDir, coverageEncoder, layerEncoder);
}
/**
* @deprecated use {@link #publishExternalMosaic(String workspace, final String storeName, File mosaicDir, GSCoverageEncoder coverageEncoder,
GSLayerEncoder layerEncoder)}
* @param workspace
* @param storeName
* @param mosaicDir
* @param coverageEncoder
* @param layerEncoder
* @return
* @throws FileNotFoundException
*/
public boolean createExternalMosaic(String workspace, String storeName,
File mosaicDir, GSCoverageEncoder coverageEncoder,
GSLayerEncoder layerEncoder) throws FileNotFoundException {
return publishExternalMosaic(workspace, storeName, mosaicDir, coverageEncoder, layerEncoder);
}
/**
* Publish a Mosaic already in a filesystem readable by GeoServer.
*
*
* Sample cUrl usage:
* curl -u admin:geoserver -XPUT -H 'Content-type: text' -d "file:$ABSPORTDIR"
* http://$GSIP:$GSPORT/$SERVLET/rest/workspaces/$WORKSPACE/coveragestores/$BAREDIR/external.imagemosaic
*
* @param workspace
* an existing workspace
* @param storeName
* the name of the coverageStore to be created
* @param mosaicDir
* the directory where the raster images are located
* @param coverageEncoder
* the set of parameters to be set to the coverage (bbox, srs,
* ...)
* @param layerEncoder
* the set of parameters to be set to the layer (defaultstyle,
* wmspath, ...)
* @return true if the operation completed successfully.
*
* @throws FileNotFoundException
*/
public boolean publishExternalMosaic(String workspace, final String storeName, File mosaicDir, GSCoverageEncoder coverageEncoder,
GSLayerEncoder layerEncoder) throws FileNotFoundException,IllegalArgumentException {
if (coverageEncoder == null) {
throw new IllegalArgumentException("no coverageEncoder provided for mosaic " + mosaicDir);
}
// override name to match the FIRST configured coverage
String coverageName=coverageEncoder.getName();
if (layerEncoder == null) {
throw new IllegalArgumentException("no layerEncoder provided for " + workspace + ":"
+ coverageName);
}
RESTCoverageStore store = createExternaMosaicDatastore(workspace, storeName, mosaicDir, ParameterConfigure.NONE,
ParameterUpdate.OVERWRITE);
if (store == null) {
return false;
}
if (!createCoverage(workspace, storeName, coverageEncoder)) {
if (LOGGER.isErrorEnabled())
LOGGER.error("Unable to create a coverage for the store:" + coverageName);
return false;
}
if (!configureLayer(workspace, coverageName, layerEncoder)) {
if (LOGGER.isErrorEnabled())
LOGGER.error("Unable to configure the Layer for the coverage:" + coverageName);
return false;
}
return true;
}
// ==========================================================================
// === COVERAGES
// ==========================================================================
/**
* Remove the Coverage configuration from GeoServer.
* First, the associated layer is removed, then the Coverage configuration
* itself.
*
* CHECKME Maybe the coveragestore has to be removed as well. * *
* REST URL:
* http://localhost:8080/geoserver/rest/workspaces/it.geosolutions/coveragestores/gbRESTtestStore/coverages/resttestdem.xml
*
* @return true if the operation completed successfully.
*/
public boolean unpublishCoverage(String workspace, String storename,
String layerName) {
try {
final String fqLayerName;
// this null check is here only for backward compatibility.
// workspace
// shall be mandatory.
if (workspace == null) {
fqLayerName = layerName;
if (LOGGER.isWarnEnabled()) {
LOGGER.warn("Null workspace while configuring layer : "
+ layerName + " -- This behavior is deprecated.");
}
} else {
fqLayerName = workspace + ":" + layerName;
}
// delete related layer
URL deleteLayerUrl = new URL(restURL + "/rest/layers/"
+ fqLayerName);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Going to delete " + "/rest/layers/" + fqLayerName);
}
boolean layerDeleted = HTTPUtils.delete(
deleteLayerUrl.toExternalForm(), gsuser, gspass);
if (!layerDeleted) {
LOGGER.warn("Could not delete layer '" + fqLayerName + "'");
return false;
}
// delete the coverage
URL deleteCovUrl = new URL(restURL + "/rest/workspaces/"
+ workspace + "/coveragestores/" + storename
+ "/coverages/" + layerName);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Going to delete " + "/rest/workspaces/"
+ workspace + "/coveragestores/" + storename
+ "/coverages/" + layerName);
}
boolean covDeleted = HTTPUtils.delete(
deleteCovUrl.toExternalForm(), gsuser, gspass);
if (!covDeleted) {
LOGGER.warn("Could not delete coverage " + workspace + ":"
+ storename + "/" + layerName
+ ", but layer was deleted.");
} else {
LOGGER.info("Coverage successfully deleted " + workspace + ":"
+ storename + "/" + layerName);
}
return covDeleted;
// the covstore is still there: should we delete it?
} catch (MalformedURLException ex) {
if (LOGGER.isErrorEnabled())
LOGGER.error(ex.getLocalizedMessage(),ex);
return false;
}
}
// ==========================================================================
// === FEATURETYPES
// ==========================================================================
/**
* Removes the featuretype and the associated layer.
* NAME_0=VALUE_0&NAME_1=VALUE_1&....&NAME_n-1=VALUE_n-1
*
* You may also want to {@link #removeDatastore(String, String) remove the
* datastore}.
*
* @return true if the operation completed successfully.
*/
public boolean unpublishFeatureType(String workspace, String storename,
String layerName) {
try {
final String fqLayerName;
// this null check is here only for backward compatibility.
// workspace
// shall be mandatory.
if (workspace == null) {
fqLayerName = layerName;
if (LOGGER.isWarnEnabled()) {
LOGGER.warn("Null workspace while configuring layer : "
+ layerName + " -- This behavior is deprecated.");
}
} else {
fqLayerName = workspace + ":" + layerName;
}
// delete related layer
URL deleteLayerUrl = new URL(restURL + "/rest/layers/"
+ fqLayerName);
boolean layerDeleted = HTTPUtils.delete(
deleteLayerUrl.toExternalForm(), gsuser, gspass);
if (!layerDeleted) {
LOGGER.warn("Could not delete layer '" + fqLayerName + "'");
return false;
}
// delete the coverage
URL deleteFtUrl = new URL(restURL + "/rest/workspaces/" + workspace
+ "/datastores/" + storename + "/featuretypes/" + layerName);
boolean ftDeleted = HTTPUtils.delete(deleteFtUrl.toExternalForm(),
gsuser, gspass);
if (!ftDeleted) {
LOGGER.warn("Could not delete featuretype " + workspace + ":"
+ storename + "/" + layerName
+ ", but layer was deleted.");
} else {
LOGGER.info("FeatureType successfully deleted " + workspace
+ ":" + storename + "/" + layerName);
}
return ftDeleted;
// the store is still there: should we delete it?
} catch (MalformedURLException ex) {
if (LOGGER.isErrorEnabled())
LOGGER.error(ex.getLocalizedMessage(),ex);
return false;
}
}
/**
* Remove recursively a given Datastore in a given Workspace.
*
* @param workspace
* The name of the workspace
* @param storename
* The name of the Datastore to remove.
* @return true if the datastore was successfully removed.
*
* @deprecated will be removed in next release use
* {@link GeoServerRESTPublisher#removeDatastore(String, String, boolean)}
*/
public boolean removeDatastore(String workspace, String storename) {
try {
return removeDatastore(workspace, storename, true);
} catch (IllegalArgumentException e) {
if (LOGGER.isErrorEnabled())
LOGGER.error("Arguments may not be null or empty!", e);
}
return false;
}
/**
* Remove a given Datastore in a given Workspace.
*
* @param workspace
* The name of the workspace
* @param storename
* The name of the Datastore to remove.
* @param recurse
* if remove should be performed recursively
* @throws IllegalArgumentException
* if workspace or storename are null or empty
* @return true if the datastore was successfully removed.
*/
public boolean removeDatastore(String workspace, String storename,
final boolean recurse) throws IllegalArgumentException {
try {
if (workspace == null || storename == null)
throw new IllegalArgumentException("Arguments may not be null!");
if (workspace.isEmpty() || storename.isEmpty())
throw new IllegalArgumentException(
"Arguments may not be empty!");
final StringBuilder url = new StringBuilder(restURL);
url.append("/rest/workspaces/").append(workspace)
.append("/datastores/").append(storename);
if (recurse)
url.append("?recurse=true");
final URL deleteStore = new URL(url.toString());
boolean deleted = HTTPUtils.delete(deleteStore.toExternalForm(),
gsuser, gspass);
if (!deleted) {
LOGGER.warn("Could not delete datastore " + workspace + ":"
+ storename);
} else {
LOGGER.info("Datastore successfully deleted " + workspace + ":"
+ storename);
}
return deleted;
} catch (MalformedURLException ex) {
if (LOGGER.isErrorEnabled())
LOGGER.error(ex.getLocalizedMessage(),ex);
return false;
}
}
/**
* Remove recursively a given CoverageStore in a given Workspace.
*
* @param workspace
* The name of the workspace
* @param storename
* The name of the CoverageStore to remove.
* @return true if the CoverageStore was successfully removed.
* @deprecated use {@link #removeCoverageStore(String, String, boolean)}
*/
public boolean removeCoverageStore(String workspace, String storename) {
try {
return removeCoverageStore(workspace, storename, true);
} catch (IllegalArgumentException e) {
if (LOGGER.isErrorEnabled())
LOGGER.error("Arguments may not be null or empty!", e);
}
return false;
}
/**
* Remove a given CoverageStore in a given Workspace.
*
* @param workspace
* The name of the workspace
* @param storename
* The name of the CoverageStore to remove.
* @param recurse
* if remove should be performed recursively
* @return true if the CoverageStore was successfully removed.
*/
public boolean removeCoverageStore(final String workspace,
final String storename, final boolean recurse)
throws IllegalArgumentException {
try {
if (workspace == null || storename == null)
throw new IllegalArgumentException("Arguments may not be null!");
if (workspace.isEmpty() || storename.isEmpty())
throw new IllegalArgumentException(
"Arguments may not be empty!");
final StringBuilder url = new StringBuilder(restURL);
url.append("/rest/workspaces/").append(workspace)
.append("/coveragestores/").append(storename);
if (recurse)
url.append("?recurse=true");
final URL deleteStore = new URL(url.toString());
boolean deleted = HTTPUtils.delete(deleteStore.toExternalForm(),
gsuser, gspass);
if (!deleted) {
LOGGER.warn("Could not delete CoverageStore " + workspace + ":"
+ storename);
} else {
LOGGER.info("CoverageStore successfully deleted " + workspace
+ ":" + storename);
}
return deleted;
} catch (MalformedURLException ex) {
if (LOGGER.isErrorEnabled())
LOGGER.error(ex.getLocalizedMessage(),ex);
return false;
}
}
/**
* Remove the workspace given Workspace using default parameters
*
* @see {@link GeoServerRESTPublisher#removeWorkspace(String, boolean)}
* @param workspace
* the workspace to remove
* @return true if success, false otherwise
* @deprecated {@link #removeWorkspace(String, boolean)}
*/
public boolean removeWorkspace(String workspace) {
try {
return removeWorkspace(workspace, false);
} catch (IllegalArgumentException e) {
if (LOGGER.isErrorEnabled())
LOGGER.error("Arguments may not be null or empty!", e);
}
return false;
}
/**
* Remove a given Workspace.
*
* @param workspace
* The name of the workspace
* @param recurse
* The recurse parameter is used to recursively delete all
* resources contained by the specified workspace. This includes
* data stores, coverage stores, feature types, etc... Allowable
* values for this parameter are true or false. The
* default value is false.
* @return true if the WorkSpace was successfully removed.
*/
public boolean removeWorkspace(String workspace, boolean recurse)
throws IllegalArgumentException {
workspace = sanitize(workspace);
try {
if (workspace == null)
throw new IllegalArgumentException("Arguments may not be null!");
if (workspace.isEmpty())
throw new IllegalArgumentException(
"Arguments may not be empty!");
StringBuffer url = new StringBuffer(restURL).append(
"/rest/workspaces/").append(workspace);
if (recurse)
url.append("?recurse=true");
final URL deleteUrl = new URL(url.toString());
boolean deleted = HTTPUtils.delete(deleteUrl.toExternalForm(),
gsuser, gspass);
if (!deleted) {
LOGGER.warn("Could not delete Workspace " + workspace);
} else {
LOGGER.info("Workspace successfully deleted " + workspace);
}
return deleted;
} catch (MalformedURLException ex) {
if (LOGGER.isErrorEnabled())
LOGGER.error(ex.getLocalizedMessage(),ex);
return false;
}
}
/**
* reload the target geoserver configuration
*
* @return true if success
*
* @see http
* ://docs.geoserver.org/stable/en/user/restconfig/rest-config-api.html
*/
public boolean reload() {
String sUrl = restURL + "/rest/reload";
String result = HTTPUtils.post(sUrl, "", "text/plain", gsuser, gspass);
return result != null;
}
/**
* reset the target geoserver configuration
*
* @return true if success
*
* @see http
* ://docs.geoserver.org/stable/en/user/restconfig/rest-config-api.html
*/
public boolean reset() {
String sUrl = restURL + "/rest/reset";
String result = HTTPUtils.post(sUrl, "", "text/plain", gsuser, gspass);
return result != null;
}
public boolean removeLayerGroup(String name) {
try {
URL deleteUrl = new URL(restURL + "/rest/layergroups/" + name);
boolean deleted = HTTPUtils.delete(deleteUrl.toExternalForm(),
gsuser, gspass);
if (!deleted) {
if (LOGGER.isWarnEnabled())
LOGGER.warn("Could not delete layergroup " + name);
} else {
if (LOGGER.isInfoEnabled())
LOGGER.info("Layergroup successfully deleted: " + name);
}
return deleted;
} catch (MalformedURLException ex) {
if (LOGGER.isErrorEnabled())
LOGGER.error(ex.getLocalizedMessage(),ex);
return false;
}
}
// ==========================================================================
// ===
// ==========================================================================
/**
* remove a generic given layer from a given workspace
*
* @param workspace
* @param layerName
* @return true if success
*/
public boolean removeLayer(final String workspace, final String layerName) {
final String fqLayerName;
// this null check is here only for backward compatibility. workspace
// shall be mandatory.
if (workspace == null) {
fqLayerName = layerName;
if (LOGGER.isWarnEnabled()) {
LOGGER.warn("Null workspace while removing layer : "
+ layerName + " -- This behavior is deprecated.");
}
} else {
fqLayerName = workspace + ":" + layerName;
}
if (layerName == null) {
if (LOGGER.isErrorEnabled()) {
LOGGER.error("Null layerName : " + layerName);
}
return false;
}
final String url = restURL + "/rest/layers/" + fqLayerName;
boolean result = HTTPUtils.delete(url, gsuser, gspass);
if (result) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Layer successfully removed: " + fqLayerName);
}
} else {
if (LOGGER.isWarnEnabled())
LOGGER.warn("Error removing layer " + fqLayerName);
}
return result;
}
/**
* Allows to configure some layer attributes such and DefaultStyle
*
* @param workspace
* @param resourceName the name of the resource to use (featureStore or coverageStore name)
* @param layer the layer encoder used to configure the layer
* @return true if success
* @throws IllegalArgumentException if some arguments are null or empty
*
* @TODO WmsPath
*/
public boolean configureLayer(final String workspace,
final String resourceName, final GSLayerEncoder layer) throws IllegalArgumentException {
if (workspace == null || resourceName == null || layer == null) {
throw new IllegalArgumentException("Null argument");
}
// TODO: check this usecase, layer should always be defined
if (workspace.isEmpty() || resourceName.isEmpty() || layer.isEmpty()) {
throw new IllegalArgumentException("Empty argument");
}
final String fqLayerName = workspace + ":" + resourceName;
final String url = restURL + "/rest/layers/" + fqLayerName;
String layerXml = layer.toString();
String sendResult = HTTPUtils.putXml(url, layerXml, gsuser, gspass);
if (sendResult != null) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Layer successfully configured: " + fqLayerName);
}
} else {
if (LOGGER.isWarnEnabled())
LOGGER.warn("Error configuring layer " + fqLayerName + " (" + sendResult + ")");
}
return sendResult != null;
}
/**
* Configure an existent coverage in a given workspace and coverage store
*
* @param ce
* contains the coverage name to configure and the configuration
* to apply
* @param wsname
* the workspace to search for existent coverage
* @param csname
* the coverage store to search for existent coverage
* @return true if success
*/
public boolean configureCoverage(final GSCoverageEncoder ce,
final String wsname, final String csname) {
final String cname = ce.getName();
if (cname == null) {
if (LOGGER.isErrorEnabled())
LOGGER.error("Unable to configure a coverage with no name try using GSCoverageEncoder.setName(String)");
return false;
}
// retrieve coverage name
GeoServerRESTReader reader;
try {
reader = new GeoServerRESTReader(restURL, gsuser, gspass);
} catch (MalformedURLException e) {
if (LOGGER.isErrorEnabled())
LOGGER.error(e.getLocalizedMessage(),e);
return false;
}
final RESTCoverageList covList = reader.getCoverages(wsname, csname);
if (covList.isEmpty()) {
if (LOGGER.isErrorEnabled())
LOGGER.error("No coverages found in new coveragestore "
+ csname);
return false;
}
final Iterator
*