|
|
|
@ -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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
|