partially fix issue #8 and #7.

This commit is contained in:
ccancellieri 2012-03-27 17:59:39 +02:00
parent 0b9f6eda5d
commit 270f3450fb
7 changed files with 593 additions and 351 deletions

View File

@ -37,6 +37,7 @@ import it.geosolutions.geoserver.rest.encoder.feature.GSFeatureTypeEncoder;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL; import java.net.URL;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.util.Iterator; import java.util.Iterator;
@ -344,6 +345,122 @@ public class GeoServerRESTPublisher {
return false; 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.isEnabledFor(Level.ERROR))
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.<br>
*
* A coverage store is a source of spatial data that is raster based.<br>
*
* @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 // === DATASTORE
// ========================================================================== // ==========================================================================
@ -510,9 +627,9 @@ public class GeoServerRESTPublisher {
.append("/featuretypes/").append(layername); .append("/featuretypes/").append(layername);
GSFeatureTypeEncoder fte = new GSFeatureTypeEncoder(); GSFeatureTypeEncoder fte = new GSFeatureTypeEncoder();
fte.addName(layername); fte.setName(layername);
fte.addSRS(srs); fte.setSRS(srs);
fte.addProjectionPolicy(ProjectionPolicy.REPROJECT_TO_DECLARED); fte.setProjectionPolicy(ProjectionPolicy.FORCE_DECLARED);
String configuredResult = HTTPUtils.putXml(postUrl.toString(), String configuredResult = HTTPUtils.putXml(postUrl.toString(),
fte.toString(), this.gsuser, this.gspass); fte.toString(), this.gsuser, this.gspass);
@ -552,10 +669,10 @@ public class GeoServerRESTPublisher {
fte.setProjectionPolicy(ProjectionPolicy.REPROJECT_TO_DECLARED); fte.setProjectionPolicy(ProjectionPolicy.REPROJECT_TO_DECLARED);
fte.addKeyword("KEYWORD"); fte.addKeyword("KEYWORD");
fte.addName(layername); fte.setName(layername);
fte.addSRS(srs); // srs=null?"EPSG:4326":srs); fte.setSRS(srs); // srs=null?"EPSG:4326":srs);
final GSLayerEncoder layerEncoder = new GSLayerEncoder(); final GSLayerEncoder layerEncoder = new GSLayerEncoder();
layerEncoder.addDefaultStyle(defaultStyle); layerEncoder.setDefaultStyle(defaultStyle);
return publishDBLayer(workspace, storename, fte, layerEncoder); return publishDBLayer(workspace, storename, fte, layerEncoder);
} }
@ -633,12 +750,13 @@ public class GeoServerRESTPublisher {
/** /**
* The configure parameter is used to control how the data store is * The configure parameter is used to control how the data store is
* configured upon file upload. It can take one of the three values first, * configured upon file upload. It can take one of the three values <i>first</i>,
* <i>none</i>, or <i>all</i>. <br> * <i>none</i>, or <i>all</i>.
* first - Only setup the first feature type available in the data store. * <ul>
* This is the default. <br> * <li><b>first</b> - This is the default.</li>
* none - Do not configure any feature types.<br> * <li><b>none</b> - Do not configure any feature types.</li>
* all - Configure all feature types. * <li><b>all</b> - Configure all feature types.</li>
* </ul>
*/ */
public static enum ParameterConfigure { public static enum ParameterConfigure {
FIRST, NONE, ALL; FIRST, NONE, ALL;
@ -681,10 +799,9 @@ public class GeoServerRESTPublisher {
/** /**
* *
* Publish a zipped worldimage file. It is assumed that the the zip-file * Publish a file.
* contain the *.prj to set the srs.
* <P> * <P>
* This is equivalent call with cUrl: * This is an example with cUrl:
* *
* <PRE> * <PRE>
* {@code * {@code
@ -715,37 +832,144 @@ public class GeoServerRESTPublisher {
* @return true if the operation completed successfully. * @return true if the operation completed successfully.
*/ */
private boolean publishCoverage(String workspace, String coveragestore, private boolean publishCoverage(String workspace, String coveragestore,
String format, String mimeType, File file, CoverageStoreExtension extension, String mimeType, File file,
ParameterConfigure configure, NameValuePair... params) ParameterConfigure configure, NameValuePair... params)
throws FileNotFoundException { throws FileNotFoundException {
// build full URL return createCoverageStore(workspace, coveragestore, UploadMethod.file, extension, mimeType, file.toURI(), configure, params);
StringBuilder sbUrl = new StringBuilder(restURL) // // build full URL
.append("/rest/workspaces/").append(workspace) // StringBuilder sbUrl = new StringBuilder(restURL)
.append("/coveragestores/").append(coveragestore) // .append("/rest/workspaces/").append(workspace)
.append("/file.").append(format); // .append("/coveragestores/").append(coveragestore)
// .append("/file.").append(format);
//
// 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 = HTTPUtils.put(sbUrl.toString(), file, mimeType,
// gsuser, gspass);
// boolean fileSent = sentResult != null;
//
// if (fileSent) {
// if (LOGGER.isInfoEnabled())
// LOGGER.info("File successfully uploaded ( " + file + ")");
// } else {
// if (LOGGER.isEnabledFor(Level.WARN))
// LOGGER.warn("Error in sending file " + file);
// }
// return fileSent;
}
if (configure != null) { /**
sbUrl.append("?configure=").append(configure); *
if (params != (NameValuePair[]) null * The extension parameter specifies the type of data being uploaded. The
&& !configure.equals(ParameterConfigure.NONE)) { * following extensions are supported:
final String paramString = appendParameters(params); * <ul>
if (!paramString.isEmpty()) { * <li>Extension:<b>geotiff</b> Datastore:<b>GeoTiff coverage</b></li>
sbUrl.append("&").append(paramString); * <li>Extension:<b>imagemosaic</b> Datastore:<b>ImageMosaic</b></li>
* <li>Extension:<b>worldimage</b> Datastore:<b>Geo referenced image (JPEG,PNG,TIF)</b></li>
* </ul>
*
* @author Carlo Cancellieri - carlo.cancellieri@geo-solutions.it
*
*/
public enum CoverageStoreExtension {
geotiff,
imagemosaic,
worldimage
} }
}
}
String sentResult = HTTPUtils.put(sbUrl.toString(), file, mimeType,
gsuser, gspass);
boolean fileSent = sentResult != null;
if (fileSent) { /**
if (LOGGER.isInfoEnabled()) *
LOGGER.info("File successfully uploaded ( " + file + ")"); * The extension parameter specifies the type of data being uploaded. The
} else { * following extensions are supported:
if (LOGGER.isEnabledFor(Level.WARN)) * <ul>
LOGGER.warn("Error in sending file " + file); * <li>Extension:<b>shp</b> Datastore:<b>Shapefile</b></li>
* <li>Extension:<b>properties</b> Datastore:<b>Property file</b></li>
* <li>Extension:<b>h2</b> Datastore:<b>H2 Database</b></li>
* <li>Extension:<b>spatialite</b> Datastore:<b>SpatiaLite Database</b></li>
* </ul>
*
* @author Carlo Cancellieri - carlo.cancellieri@geo-solutions.it
*
*/
public enum DataStoreExtension {
shp,
properties,
h2,
spatialite
} }
return fileSent;
/**
*
* Publish a file sending it to the GeoServer.
*
* <P>
* Here is an example call with cUrl:
*
* <PRE>
* {@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
* </PRE>
*
* @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:
* <ul>
* <li> See <b>{@link #ParameterUpdate}</b> </li>
* </ul>
* @see #{@link ParameterConfigure}
* @return true if the operation completed successfully.
* @throws IllegalArgumentException
* @throws FileNotFoundException
*/
private boolean publishExternalCoverage(String workspace, String coveragestore,
CoverageStoreExtension extension, String mimeType, File file,
ParameterConfigure configure, ParameterUpdate update) throws FileNotFoundException, IllegalArgumentException {
return createCoverageStore(workspace, coveragestore, UploadMethod.external, extension, mimeType, file.toURI(), configure, (update!=null)?new NameValuePair[]{new NameValuePair("update",update.toString())}:(NameValuePair[])null);
// // build full URL
// StringBuilder sbUrl = new StringBuilder(restURL)
// .append("/rest/workspaces/").append(workspace)
// .append("/coveragestores/").append(coveragestore)
// .append("/external.").append(format);
//
// if (configure!=null){
// sbUrl.append("?configure=").append(configure);
// if (update!=null){
// sbUrl.append("&update=").append(update.toString());
// }
// } else if (update!=null){
// sbUrl.append("?update=").append(update.toString());
// }
//
// final String sentResult = HTTPUtils.put(sbUrl.toString(), file.getAbsoluteFile().toURI().toString(), mimeType, gsuser, gspass);
//
// if (sentResult != null) {
// if (LOGGER.isInfoEnabled())
// LOGGER.info("Store successfully created using ( " + file + " )");
// return true;
// } else {
// if (LOGGER.isEnabledFor(Level.ERROR))
// LOGGER.error("Error in creating store using file " + file);
// return false;
// }
} }
// ========================================================================== // ==========================================================================
@ -757,14 +981,14 @@ public class GeoServerRESTPublisher {
*/ */
public boolean publishGeoTIFF(String workspace, String storeName, public boolean publishGeoTIFF(String workspace, String storeName,
File geotiff) throws FileNotFoundException { File geotiff) throws FileNotFoundException {
return publishCoverage(workspace, storeName, "geotiff", return publishCoverage(workspace, storeName, CoverageStoreExtension.geotiff,
"image/geotiff", geotiff, ParameterConfigure.FIRST, "image/geotiff", geotiff, ParameterConfigure.FIRST,
(NameValuePair[]) null); (NameValuePair[]) null);
} }
/** /**
* Publish a GeoTiff. * Publish a GeoTiff.
* Simple wrapper for {@link #publishCoverage(String, String, String, String, File, ParameterConfigure, NameValuePair...)} * Simple wrapper for {@link #publishCoverage(String, String, CoverageStoreExtension, String, File, ParameterConfigure, NameValuePair...)}
* <P> * <P>
* This is the equivalent call with cUrl: * This is the equivalent call with cUrl:
* *
@ -777,22 +1001,79 @@ public class GeoServerRESTPublisher {
* *
* @param workspace Workspace to use * @param workspace Workspace to use
* @param storeName Name of the coveragestore (if null the file name will be used) * @param storeName Name of the coveragestore (if null the file name will be used)
* @param layerName the name of the coverage (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 * @param geotiff file to upload
* @return true if the operation completed successfully. * @return true if the operation completed successfully.
* @throws FileNotFoundException if file does not exists * @throws FileNotFoundException if file does not exists
* @throws IllegalArgumentException if workspace or geotiff are null * @throws IllegalArgumentException if workspace or geotiff are null
*/ */
public boolean publishGeoTIFF(final String workspace, final String storeName, final String layerName, public boolean publishGeoTIFF(final String workspace, final String storeName, final String coverageName,
final File geotiff) throws FileNotFoundException, IllegalArgumentException { final File geotiff) throws FileNotFoundException, IllegalArgumentException {
if (workspace==null || geotiff==null) if (workspace==null || geotiff==null)
throw new IllegalArgumentException("Unable to proceed, some arguments are null"); throw new IllegalArgumentException("Unable to proceed, some arguments are null");
return publishCoverage(workspace, (storeName!=null)?storeName:FilenameUtils.getBaseName(geotiff.getAbsolutePath()), "geotiff", return publishCoverage(workspace, (storeName!=null)?storeName:FilenameUtils.getBaseName(geotiff.getAbsolutePath()), CoverageStoreExtension.geotiff,
"image/geotiff", geotiff, ParameterConfigure.FIRST, "image/geotiff", geotiff, ParameterConfigure.FIRST,
(layerName!=null)?new NameValuePair[]{new NameValuePair("coverageName", layerName)}:(NameValuePair[]) null); (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. * Publish a GeoTiff already in a filesystem readable by GeoServer.
* *
@ -802,57 +1083,49 @@ public class GeoServerRESTPublisher {
* the coverageStore to be created * the coverageStore to be created
* @param geotiff * @param geotiff
* the geoTiff to be published * the geoTiff to be published
* @param coverageEncoder
* @param layerEncoder
* @return true if successfully configured
*
* *
* @return a PublishedCoverage, or null on errors
* @throws FileNotFoundException * @throws FileNotFoundException
* @throws IllegalArgumentException if null parameter
*/ */
public RESTCoverageStore publishExternalGeoTIFF(String workspace, public RESTCoverageStore publishExternalGeoTIFF(final String workspace, final String storeName, final File geotiff, final GSCoverageEncoder coverageEncoder,final GSLayerEncoder layerEncoder)
String storeName, File geotiff, String srs, String defaultStyle) throws IllegalArgumentException, FileNotFoundException {
throws FileNotFoundException {
// create store
String sUrl = restURL + "/rest/workspaces/" + workspace
+ "/coveragestores/" + storeName + "/external.geotiff";
String sendResult = HTTPUtils.put(sUrl, geotiff.toURI().toString(),
"text/plain", gsuser, gspass);
RESTCoverageStore store = RESTCoverageStore.build(sendResult);
if (store != null) { if (workspace==null || geotiff==null || storeName==null || layerEncoder==null || coverageEncoder==null)
try { throw new IllegalArgumentException("Unable to run: null parameter");
// retrieve coverage name
GeoServerRESTReader reader = new GeoServerRESTReader(restURL, final String coverageName=coverageEncoder.getName();
gsuser, gspass); if (coverageName.isEmpty()){
RESTCoverageList covList = reader.getCoverages(workspace, throw new IllegalArgumentException("Unable to run: empty coverage store name");
storeName); }
if (covList.isEmpty()) {
LOGGER.error("No coverages found in new coveragestore " // create store
+ storeName); final boolean store=publishExternalCoverage(workspace, storeName, CoverageStoreExtension.geotiff, "text/plain", geotiff, ParameterConfigure.NONE, ParameterUpdate.OVERWRITE);
if (!store) {
return null; return null;
} }
final String coverageName = covList.get(0).getName();
// config coverage props (srs) // create Coverage Store
GSCoverageEncoder coverageEncoder = new GSCoverageEncoder(); if (!createCoverage(workspace, storeName, coverageEncoder)) {
coverageEncoder.addName(FilenameUtils.getBaseName(geotiff if (LOGGER.isEnabledFor(Level.ERROR))
.getName())); LOGGER.error("Unable to create a coverage for the store:"+ coverageName);
coverageEncoder.addSRS(srs); return null;
coverageEncoder
.addProjectionPolicy(ProjectionPolicy.REPROJECT_TO_DECLARED);
configureCoverage(coverageEncoder, workspace, storeName,
coverageName);
// config layer props (style, ...)
GSLayerEncoder layerEncoder = new GSLayerEncoder();
layerEncoder.addDefaultStyle(defaultStyle);
configureLayer(workspace, coverageName, layerEncoder);
} catch (Exception e) {
LOGGER.warn(
"Could not configure external GEOTiff:" + storeName, e);
store = null; // TODO: should we remove the configured pc?
}
} }
return store; // 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.log(Level.ERROR, e.getMessage(), e);
}
}
return null;
} }
// ========================================================================== // ==========================================================================
@ -906,7 +1179,7 @@ public class GeoServerRESTPublisher {
public boolean publishWorldImage(String workspace, String coveragestore, public boolean publishWorldImage(String workspace, String coveragestore,
File zipFile, ParameterConfigure configure, NameValuePair... params) File zipFile, ParameterConfigure configure, NameValuePair... params)
throws FileNotFoundException { throws FileNotFoundException {
return publishCoverage(workspace, coveragestore, "worldimage", return publishCoverage(workspace, coveragestore, CoverageStoreExtension.worldimage,
"application/zip", zipFile, configure, params); "application/zip", zipFile, configure, params);
} }
@ -921,7 +1194,7 @@ public class GeoServerRESTPublisher {
*/ */
public boolean publishImageMosaic(String workspace, String storeName, public boolean publishImageMosaic(String workspace, String storeName,
File zipFile) throws FileNotFoundException { File zipFile) throws FileNotFoundException {
return publishCoverage(workspace, storeName, "imagemosaic", return publishCoverage(workspace, storeName, CoverageStoreExtension.imagemosaic,
"application/zip", zipFile, ParameterConfigure.FIRST, "application/zip", zipFile, ParameterConfigure.FIRST,
(NameValuePair[]) null); (NameValuePair[]) null);
} }
@ -934,7 +1207,7 @@ public class GeoServerRESTPublisher {
public boolean publishImageMosaic(String workspace, String storeName, public boolean publishImageMosaic(String workspace, String storeName,
File zipFile, ParameterConfigure configure, NameValuePair... params) File zipFile, ParameterConfigure configure, NameValuePair... params)
throws FileNotFoundException { throws FileNotFoundException {
return publishCoverage(workspace, storeName, "imagemosaic", return publishCoverage(workspace, storeName, CoverageStoreExtension.imagemosaic,
"application/zip", zipFile, configure, params); "application/zip", zipFile, configure, params);
} }
@ -992,11 +1265,11 @@ public class GeoServerRESTPublisher {
* @return * @return
* @throws FileNotFoundException * @throws FileNotFoundException
*/ */
public RESTCoverageStore configureExternaMosaicDatastore(String workspace, // public RESTCoverageStore configureExternaMosaicDatastore(String workspace,
String storeName, File mosaicDir) throws FileNotFoundException { // String storeName, File mosaicDir) throws FileNotFoundException {
return createExternaMosaicDatastore(workspace, storeName, mosaicDir, // return createExternaMosaicDatastore(workspace, storeName, mosaicDir,
ParameterConfigure.FIRST, ParameterUpdate.APPEND); // ParameterConfigure.FIRST, ParameterUpdate.APPEND);
} // }
/** /**
* Publish a Mosaic already in a filesystem readable by GeoServer. * Publish a Mosaic already in a filesystem readable by GeoServer.
@ -1021,160 +1294,95 @@ public class GeoServerRESTPublisher {
* *
* @throws FileNotFoundException * @throws FileNotFoundException
*/ */
public RESTCoverageStore publishExternalMosaic(String workspace, public boolean publishExternalMosaic(String workspace,
String storeName, File mosaicDir, String srs, String defaultStyle) String storeName, File mosaicDir, String srs, String defaultStyle)
throws FileNotFoundException { throws FileNotFoundException {
final GSCoverageEncoder coverageEncoder = new GSCoverageEncoder(); final GSCoverageEncoder coverageEncoder = new GSCoverageEncoder();
coverageEncoder.addSRS(srs); coverageEncoder.setSRS(srs);
coverageEncoder.addName(FilenameUtils.getBaseName(mosaicDir.getName())); final String name=FilenameUtils.getBaseName(mosaicDir.getName());
coverageEncoder.setName(name);
final GSLayerEncoder layerEncoder = new GSLayerEncoder(); final GSLayerEncoder layerEncoder = new GSLayerEncoder();
layerEncoder.addDefaultStyle(defaultStyle); layerEncoder.setDefaultStyle(defaultStyle);
return publishExternalMosaic(workspace, storeName, mosaicDir, return publishExternalMosaic(workspace, storeName, mosaicDir, coverageEncoder, layerEncoder);
coverageEncoder, layerEncoder);
} }
/** /**
* Publish a Mosaic already in a filesystem readable by GeoServer. * @deprecated use {@link #publishExternalMosaic(String workspace, final String storeName, File mosaicDir, GSCoverageEncoder coverageEncoder,
* GSLayerEncoder layerEncoder)}
* <P>
* Sample cUrl usage:<BR>
* <TT>curl -u admin:geoserver -XPUT -H 'Content-type: text' -d "file:$ABSPORTDIR"
* http://$GSIP:$GSPORT/$SERVLET/rest/workspaces/$WORKSPACE/coveragestores/$BAREDIR/external.imagemosaic </TT>
*
* @param workspace * @param workspace
* an existing workspace
* @param storeName * @param storeName
* the name of the coverageStore to be created
* @param mosaicDir * @param mosaicDir
* the directory where the raster images are located
* @param coverageEncoder * @param coverageEncoder
* the set of parameters to be set to the coverage (bbox, srs,
* ...)
* @param layerEncoder * @param layerEncoder
* the set of parameters to be set to the layer (defaultstyle, * @return
* wmspath, ...)
*
* @return the created RESTCoverageStore
* @deprecated this is keep only for backward compatibility use
* createExternalMosaic and getCoverageStore separately
*
* @throws FileNotFoundException
*/
public RESTCoverageStore publishExternalMosaic(String workspace,
String storeName, File mosaicDir,
GSCoverageEncoder coverageEncoder, GSLayerEncoder layerEncoder)
throws FileNotFoundException {
if (!createExternalMosaic(workspace, storeName, mosaicDir,
coverageEncoder, layerEncoder)) {
return null;
}
GeoServerRESTReader reader;
try {
reader = new GeoServerRESTReader(restURL, gsuser, gspass);
} catch (MalformedURLException e1) {
LOGGER.warn("Could not configure external Mosaic:" + storeName, e1);
return null;
}
final RESTCoverageStore store = reader.getCoverageStore(workspace,
storeName);
if (store == null) {
LOGGER.warn("Unable to get the store" + workspace + ":" + storeName
+ " from the target geoserver.");
return null;
}
return store;
}
/**
* Publish a Mosaic already in a filesystem readable by GeoServer.
*
* <P>
* Sample cUrl usage:<BR>
* <TT>curl -u admin:geoserver -XPUT -H 'Content-type: text' -d "file:$ABSPORTDIR"
* http://$GSIP:$GSPORT/$SERVLET/rest/workspaces/$WORKSPACE/coveragestores/$BAREDIR/external.imagemosaic </TT>
*
* @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 * @throws FileNotFoundException
*/ */
public boolean createExternalMosaic(String workspace, String storeName, public boolean createExternalMosaic(String workspace, String storeName,
File mosaicDir, GSCoverageEncoder coverageEncoder, File mosaicDir, GSCoverageEncoder coverageEncoder,
GSLayerEncoder layerEncoder) throws FileNotFoundException { GSLayerEncoder layerEncoder) throws FileNotFoundException {
return publishExternalMosaic(workspace, storeName, mosaicDir, coverageEncoder, layerEncoder);
}
RESTCoverageStore store = createExternaMosaicDatastore(workspace, /**
storeName, mosaicDir, ParameterConfigure.NONE, * Publish a Mosaic already in a filesystem readable by GeoServer.
ParameterUpdate.OVERWRITE); *
* <P>
// override name to match the FIRST configured coverage * Sample cUrl usage:<BR>
final String coverageStoreName = FilenameUtils.getBaseName(mosaicDir * <TT>curl -u admin:geoserver -XPUT -H 'Content-type: text' -d "file:$ABSPORTDIR"
.getName()); * http://$GSIP:$GSPORT/$SERVLET/rest/workspaces/$WORKSPACE/coveragestores/$BAREDIR/external.imagemosaic </TT>
*
* @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) { if (coverageEncoder == null) {
if (LOGGER.isDebugEnabled()) { throw new IllegalArgumentException("no coverageEncoder provided for mosaic " + mosaicDir);
LOGGER.debug("no coverageEncoder provided for " + workspace
+ ":" + storeName);
}
coverageEncoder = new GSCoverageEncoder();
coverageEncoder.setName(coverageStoreName);
} }
// override name to match the FIRST configured coverage
String coverageName=coverageEncoder.getName();
if (layerEncoder == null) { if (layerEncoder == null) {
if (LOGGER.isDebugEnabled()) { throw new IllegalArgumentException("no layerEncoder provided for " + workspace + ":"
LOGGER.debug("no layerEncoder provided for " + workspace + ":" + coverageName);
+ storeName);
}
layerEncoder = new GSLayerEncoder();
} }
if (store != null) { RESTCoverageStore store = createExternaMosaicDatastore(workspace, storeName, mosaicDir, ParameterConfigure.NONE,
try { ParameterUpdate.OVERWRITE);
// override name
coverageEncoder.setName(coverageStoreName);
if (!createCoverage(coverageEncoder, workspace, storeName)) { if (store == null) {
if (LOGGER.isEnabledFor(Level.ERROR))
LOGGER.error("Unable to create a coverage for the store:"
+ storeName);
return false; return false;
} }
if (!configureLayer(workspace, coverageStoreName, layerEncoder)) { if (!createCoverage(workspace, storeName, coverageEncoder)) {
if (LOGGER.isEnabledFor(Level.ERROR)) if (LOGGER.isEnabledFor(Level.ERROR))
LOGGER.error("Unable to configure the Layer for the coverage:" LOGGER.error("Unable to create a coverage for the store:" + coverageName);
+ coverageStoreName);
return false; return false;
} }
if (!configureLayer(workspace, coverageName, layerEncoder)) {
} catch (Exception e) { if (LOGGER.isEnabledFor(Level.ERROR))
if (LOGGER.isEnabledFor(Level.WARN)) LOGGER.error("Unable to configure the Layer for the coverage:" + coverageName);
LOGGER.warn("Could not configure external mosaic:"
+ storeName, e);
store = null; // TODO: should we remove the configured store?
return false; return false;
} }
return true; return true;
} }
return false;
}
// ========================================================================== // ==========================================================================
// === COVERAGES // === COVERAGES
@ -1569,15 +1777,6 @@ public class GeoServerRESTPublisher {
// === // ===
// ========================================================================== // ==========================================================================
/**
* @deprecated please use {@link configureLayer(String workspace, String
* layerName, GSLayerEncoder layer) }
*/
public boolean configureLayer(final GSLayerEncoder layer,
final String layerName) {
return configureLayer(null, layerName, layer);
}
/** /**
* remove a generic given layer from a given workspace * remove a generic given layer from a given workspace
* *
@ -1627,33 +1826,26 @@ public class GeoServerRESTPublisher {
/** /**
* Allows to configure some layer attributes such and DefaultStyle * 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 * @TODO WmsPath
*/ */
public boolean configureLayer(final String workspace, public boolean configureLayer(final String workspace,
final String layerName, final GSLayerEncoder layer) { 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 // TODO: check this usecase, layer should always be defined
if (layer.isEmpty()) { if (workspace.isEmpty() || resourceName.isEmpty() || layer.isEmpty()) {
if (LOGGER.isEnabledFor(Level.WARN)) throw new IllegalArgumentException("Empty argument");
LOGGER.warn("Null layer name while configuring layer -- This behavior is suspicious.");
return true;
} }
final String fqLayerName; final String fqLayerName = workspace + ":" + resourceName;
// this null check is here only for backward compatibility. workspace
// shall be mandatory.
if (workspace == null) {
fqLayerName = layerName;
if (LOGGER.isEnabledFor(Level.WARN)) {
LOGGER.warn("Null workspace while configuring layer : "
+ layerName + " -- This behavior is deprecated.");
}
} else {
fqLayerName = workspace + ":" + layerName;
}
final String url = restURL + "/rest/layers/" + fqLayerName; final String url = restURL + "/rest/layers/" + fqLayerName;
@ -1665,8 +1857,7 @@ public class GeoServerRESTPublisher {
} }
} else { } else {
if (LOGGER.isEnabledFor(Level.WARN)) if (LOGGER.isEnabledFor(Level.WARN))
LOGGER.warn("Error configuring layer " + fqLayerName + " (" LOGGER.warn("Error configuring layer " + fqLayerName + " (" + sendResult + ")");
+ sendResult + ")");
} }
return sendResult != null; return sendResult != null;
@ -1692,7 +1883,6 @@ public class GeoServerRESTPublisher {
LOGGER.error("Unable to configure a coverage with no name try using GSCoverageEncoder.setName(String)"); LOGGER.error("Unable to configure a coverage with no name try using GSCoverageEncoder.setName(String)");
return false; return false;
} }
// retrieve coverage name // retrieve coverage name
GeoServerRESTReader reader; GeoServerRESTReader reader;
try { try {
@ -1748,72 +1938,57 @@ public class GeoServerRESTPublisher {
} }
/** /**
* Create a new coverage in a given workspace and coverage store * @deprecated use {@link #createCoverage(String, String, GSCoverageEncoder)}
*
* @param ce * @param ce
* contains the coverage name to create and the configuration to
* apply
* @param wsname * @param wsname
* the workspace to search for existent coverage
* @param csname * @param csname
* the coverage store to search for existent coverage
* @return * @return
*/ */
public boolean createCoverage(final GSCoverageEncoder ce, public boolean createCoverage(final GSCoverageEncoder ce, final String wsname, final String csname) {
final String wsname, final String csname) { return createCoverage(wsname, csname, ce);
final String cname = ce.getName();
if (cname == null) {
if (LOGGER.isEnabledFor(Level.ERROR))
LOGGER.error("Unable to configure a coverage with no name try using GSCoverageEncoder.setName(String)");
return false;
}
// configure the selected coverage
final String url = restURL + "/rest/workspaces/" + wsname
+ "/coveragestores/" + csname + "/coverages.xml";
final String xmlBody = ce.toString();
final String sendResult = HTTPUtils.postXml(url, xmlBody, gsuser,
gspass);
if (sendResult != null) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Coverage successfully created " + wsname + ":"
+ csname + ":" + cname);
}
} else {
if (LOGGER.isEnabledFor(Level.WARN))
LOGGER.warn("Error creating coverage " + wsname + ":" + csname
+ ":" + cname + " (" + sendResult + ")");
}
return sendResult != null;
} }
/** /**
* Allows to configure some coverage's attributes * Create a new coverage in a given workspace and coverage store
*
* @param ce
* Coverage encoder
* @param wsname * @param wsname
* workspace name * the workspace to search for existent coverage
* @param csname * @param storeName
* coveragestore name * an existent store name to use as data source
* @param cname * @param ce
* coverage name (if != null will override the CoverageEncoder * contains the coverage name to create and the configuration to
* name) * apply
* @return true if success * @return true if success
* @deprecated use * @throws IllegalArgumentException if arguments are null or empty
* {@link GeoServerRESTPublisher#configureCoverage(GSCoverageEncoder, String, String)}
*/ */
protected boolean configureCoverage(final GSCoverageEncoder ce, public boolean createCoverage(final String wsname, final String storeName, final GSCoverageEncoder ce)
final String wsname, final String csname, String cname) { throws IllegalArgumentException {
if (cname != null) if (wsname.isEmpty() || wsname==null || ce == null || ce.isEmpty()) {
ce.setName(cname); throw new IllegalArgumentException(
else "Unable to configure a coverage with null or empty arguments");
cname = ce.getName(); }
return configureCoverage(ce, wsname, csname); final String coverageName = ce.getName();
if (coverageName == null) {
throw new IllegalArgumentException("Unable to configure a coverage with unnamed coverage encoder");
}
// configure the selected coverage
final String url = restURL + "/rest/workspaces/" + wsname + "/coveragestores/" + storeName
+ "/coverages.xml";
final String xmlBody = ce.toString();
final String sendResult = HTTPUtils.postXml(url, xmlBody, gsuser, gspass);
if (sendResult != null) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Coverage successfully created " + wsname + ":" + storeName + ":" + coverageName);
}
} else {
if (LOGGER.isEnabledFor(Level.WARN))
LOGGER.warn("Error creating coverage " + wsname + ":" + storeName + ":" + coverageName + " ("
+ sendResult + ")");
}
return sendResult != null;
} }
/** /**

View File

@ -25,6 +25,8 @@
package it.geosolutions.geoserver.rest.encoder; package it.geosolutions.geoserver.rest.encoder;
import org.jdom.Element;
import it.geosolutions.geoserver.rest.encoder.utils.PropertyXMLEncoder; import it.geosolutions.geoserver.rest.encoder.utils.PropertyXMLEncoder;
/** /**
@ -42,6 +44,9 @@ public class GSLayerEncoder extends PropertyXMLEncoder {
addEnabled(); addEnabled();
} }
/**
* enabled the layer
*/
protected void addEnabled(){ protected void addEnabled(){
add("enabled","true"); add("enabled","true");
} }
@ -56,17 +61,71 @@ public class GSLayerEncoder extends PropertyXMLEncoder {
set("enabled","false"); set("enabled","false");
} }
// /**
// * @param name the name of the layer
// */
// protected void addName(final String name){
// add("name",name);
// }
//
// /**
// * @return name the name of the layer or null
// */
// public String getName() {
// final Element nameNode = get("name");
// if (nameNode != null)
// return nameNode.getText();
// else
// return null;
// }
//
// /**
// * @param name the name of the layer
// * @throws IllegalArgumentException
// */
// public void setName(final String name) throws IllegalArgumentException {
// if (name==null || name.isEmpty())
// throw new IllegalArgumentException("Unable to set an empty or null parameter");
// set("name",name);
// }
/** /**
* @see {@link GSLayerEncoder#setWmsPath(String)}
* *
* @param defaultStyle * @param path the wms path to set
* @deprecated will be set to protected in the next release, please use setDefaultStyle
*
*/ */
public void addDefaultStyle(String defaultStyle) { protected void addWmsPath(final String path) {
add("path", path);
}
/**
* Default WMS Path The GeoServer WMS path is, by default, /geoserver/wms.
* However you can change it to /geoserver/anythingyouwant
*
* @param path the wms path to set
* @throws IllegalArgumentException if path is null or empty
*/
public void setWmsPath(final String path) throws IllegalArgumentException {
if (path==null || path.isEmpty())
throw new IllegalArgumentException("Unable to set an empty or null parameter");
set("path",path);
}
/**
* @see {@link GSLayerEncoder#setDefaultStyle(String)}
* @param defaultStyle
*/
protected void addDefaultStyle(String defaultStyle) {
add("defaultStyle", defaultStyle); add("defaultStyle", defaultStyle);
} }
public void setDefaultStyle(String defaultStyle) { /**
* @param defaultStyle The style that will be applied if no style is specified.
* @throws IllegalArgumentException if defaultStyle is null or empty
*/
public void setDefaultStyle(final String defaultStyle) throws IllegalArgumentException {
if (defaultStyle==null || defaultStyle.isEmpty())
throw new IllegalArgumentException("Unable to set an empty or null parameter");
set("defaultStyle", defaultStyle); set("defaultStyle", defaultStyle);
} }
} }

View File

@ -27,6 +27,9 @@ package it.geosolutions.geoserver.rest;
import it.geosolutions.geoserver.rest.decoder.RESTCoverageStore; import it.geosolutions.geoserver.rest.decoder.RESTCoverageStore;
import it.geosolutions.geoserver.rest.encoder.GSLayerEncoder;
import it.geosolutions.geoserver.rest.encoder.GSResourceEncoder.ProjectionPolicy;
import it.geosolutions.geoserver.rest.encoder.coverage.GSCoverageEncoder;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
@ -90,19 +93,18 @@ public class ConfigTest extends GeoserverRESTTest {
String layerName = "resttestdem"; String layerName = "resttestdem";
File geotiff = new ClassPathResource("testdata/resttestdem.tif").getFile(); File geotiff = new ClassPathResource("testdata/resttestdem.tif").getFile();
RESTCoverageStore pc = publisher.publishExternalGeoTIFF(DEFAULT_WS, storeName, geotiff, null, null); boolean pc = publisher.publishExternalGeoTIFF(DEFAULT_WS, storeName, geotiff, layerName,"EPSG:4326",ProjectionPolicy.FORCE_DECLARED,"raster");
assertNotNull(pc); assertTrue(pc);
} }
public void insertExternalShape() throws FileNotFoundException, IOException { public void insertExternalShape() throws FileNotFoundException, IOException {
File zipFile = new ClassPathResource("testdata/resttestshp.zip").getFile(); File zipFile = new ClassPathResource("testdata/resttestshp.zip").getFile();
boolean published = publisher.publishShp(DEFAULT_WS, "anyname", "cities", zipFile, "EPSG:4326", "default_point"); boolean published = publisher.publishShp(DEFAULT_WS, "anyname", "cities", zipFile, "EPSG:41001", "default_point");
assertTrue("publish() failed", published); assertTrue("publish() failed", published);
//test delete //test delete
boolean ok = publisher.unpublishFeatureType(DEFAULT_WS, "anyname", "cities"); boolean ok = publisher.unpublishFeatureType(DEFAULT_WS, "anyname", "cities");
assertTrue("Unpublish() failed", ok); assertTrue("Unpublish() failed", ok);

View File

@ -27,6 +27,9 @@ package it.geosolutions.geoserver.rest.publisher;
import it.geosolutions.geoserver.rest.GeoserverRESTTest; import it.geosolutions.geoserver.rest.GeoserverRESTTest;
import it.geosolutions.geoserver.rest.decoder.RESTCoverageStore; import it.geosolutions.geoserver.rest.decoder.RESTCoverageStore;
import it.geosolutions.geoserver.rest.encoder.GSLayerEncoder;
import it.geosolutions.geoserver.rest.encoder.GSResourceEncoder.ProjectionPolicy;
import it.geosolutions.geoserver.rest.encoder.coverage.GSCoverageEncoder;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
@ -66,14 +69,14 @@ public class GeoserverRESTGeoTiffTest extends GeoserverRESTTest {
assertFalse("Cleanup failed", existsLayer(layerName)); assertFalse("Cleanup failed", existsLayer(layerName));
// test insert // test insert
RESTCoverageStore pc = publisher.publishExternalGeoTIFF(DEFAULT_WS, storeName, geotiff, null, null); boolean pc = publisher.publishExternalGeoTIFF(DEFAULT_WS, storeName, geotiff, layerName,"EPSG:4326",ProjectionPolicy.FORCE_DECLARED,"raster");
assertNotNull("publish() failed", pc); assertTrue("publish() failed", pc);
assertTrue(existsLayer(layerName)); assertTrue(existsLayer(layerName));
LOGGER.info(pc); LOGGER.info(pc);
RESTCoverageStore reloadedCS = reader.getCoverageStore(DEFAULT_WS, storeName); RESTCoverageStore reloadedCS = reader.getCoverageStore(DEFAULT_WS, storeName);
assertEquals(pc.getName(), reloadedCS.getName()); assertEquals(storeName, reloadedCS.getName());
assertEquals(pc.getWorkspaceName(), reloadedCS.getWorkspaceName()); assertEquals(DEFAULT_WS, reloadedCS.getWorkspaceName());
//test delete //test delete
assertTrue("Unpublish() failed", publisher.unpublishCoverage(DEFAULT_WS, storeName, layerName)); assertTrue("Unpublish() failed", publisher.unpublishCoverage(DEFAULT_WS, storeName, layerName));

View File

@ -139,7 +139,7 @@ public class GeoserverRESTImageMosaicTest extends GeoserverRESTTest {
try { try {
final File mosaicFile = new ClassPathResource("testdata/time_geotiff/").getFile(); final File mosaicFile = new ClassPathResource("testdata/time_geotiff/").getFile();
if (!publisher.createExternalMosaic(wsName,coverageStoreName,mosaicFile,coverageEncoder,layerEncoder)){ if (!publisher.publishExternalMosaic(wsName,coverageStoreName,mosaicFile,coverageEncoder,layerEncoder)){
fail(); fail();
} }
coverageStore = reader.getCoverageStore(wsName,coverageStoreName); coverageStore = reader.getCoverageStore(wsName,coverageStoreName);

View File

@ -27,6 +27,9 @@ package it.geosolutions.geoserver.rest.publisher;
import it.geosolutions.geoserver.rest.GeoserverRESTTest; import it.geosolutions.geoserver.rest.GeoserverRESTTest;
import it.geosolutions.geoserver.rest.decoder.RESTCoverageStore; import it.geosolutions.geoserver.rest.decoder.RESTCoverageStore;
import it.geosolutions.geoserver.rest.encoder.GSLayerEncoder;
import it.geosolutions.geoserver.rest.encoder.GSResourceEncoder.ProjectionPolicy;
import it.geosolutions.geoserver.rest.encoder.coverage.GSCoverageEncoder;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -84,7 +87,7 @@ public class GeoserverRESTWorkspaceTest extends GeoserverRESTTest {
assertFalse("Cleanup failed", existsLayer(layerName)); assertFalse("Cleanup failed", existsLayer(layerName));
// test insert // test insert
RESTCoverageStore pc = publisher.publishExternalGeoTIFF(DEFAULT_WS, storeName, geotiff, null, null); boolean pc = publisher.publishExternalGeoTIFF(DEFAULT_WS, storeName, geotiff, layerName, "EPSG:4326",ProjectionPolicy.REPROJECT_TO_DECLARED,"raster");
// remove workspace and all of its contents // remove workspace and all of its contents
assertTrue(publisher.removeWorkspace(DEFAULT_WS,true)); assertTrue(publisher.removeWorkspace(DEFAULT_WS,true));