#' Geoserver REST API Manager
#'
#' @docType class
#' @importFrom R6 R6Class
#' @importFrom openssl base64_encode
#' @import httr
#' @import xml2
#' @import keyring
#' @import cli
#' @import magrittr
#' @importFrom readr read_csv
#' @importFrom readr write_csv
#' @export
#' @keywords geoserver rest api
#' @return Object of \code{\link{R6Class}} with methods for communication with
#' the REST API of a GeoServer instance.
#' @format \code{\link{R6Class}} object.
#'
#' @examples
#' \dontrun{
#' GSManager$new("http://localhost:8080/geoserver", "admin", "geoserver")
#' }
#'
#' @author Emmanuel Blondel <emmanuel.blondel1@@gmail.com>
GSManager <- R6Class("GSManager",
lock_objects = FALSE,
private = list(
keyring_backend = NULL,
keyring_service = NULL,
user = NA
),
public = list(
#' @field verbose.info if geosapi logs have to be printed
verbose.info = FALSE,
#' @field verbose.debug if curl logs have to be printed
verbose.debug = FALSE,
#' @field loggerType the type of logger
loggerType = NULL,
#'@description Prints a log message
#'@param type type of log, "INFO", "WARN", "ERROR"
#'@param text text
logger = function(type, text){
if(self$verbose.info){
cat(sprintf("[geosapi][%s] %s \n", type, text))
}
},
#'@description Prints an INFO log message
#'@param text text
INFO = function(text){self$logger("INFO", text)},
#'@description Prints an WARN log message
#'@param text text
WARN = function(text){self$logger("WARN", text)},
#'@description Prints an ERROR log message
#'@param text text
ERROR = function(text){self$logger("ERROR", text)},
#' @field url the Base url of GeoServer
url = NA,
#' @field version the version of Geoserver. Handled as \code{GSVersion} object
version = NULL,
#'@description This method is used to instantiate a GSManager with the \code{url} of the
#' GeoServer and credentials to authenticate (\code{user}/\code{pwd}).
#'
#' By default, the \code{logger} argument will be set to \code{NULL} (no logger).
#' This argument accepts two possible values: \code{INFO}: to print only geosapi logs,
#' \code{DEBUG}: to print geosapi and CURL logs.
#'
#' The \code{keyring_backend} can be set to use a different backend for storing
#' the Geoserver user password with \pkg{keyring} (Default value is 'env').
#'@param url url
#'@param user user
#'@param pwd pwd
#'@param logger logger
#'@param keyring_backend keyring backend. Default is 'env'
initialize = function(url, user, pwd, logger = NULL,
keyring_backend = 'env'){
if(!keyring_backend %in% names(keyring:::known_backends)){
errMsg <- sprintf("Backend '%s' is not a known keyring backend!", keyring_backend)
self$ERROR(errMsg)
stop(errMsg)
}
private$keyring_backend <- keyring:::known_backends[[keyring_backend]]$new()
private$keyring_service <- paste0("geosapi@", url)
#logger
if(!missing(logger)){
if(!is.null(logger)){
self$loggerType <- toupper(logger)
if(!(self$loggerType %in% c("INFO","DEBUG"))){
stop(sprintf("Unknown logger type '%s", logger))
}
if(self$loggerType == "INFO"){
self$verbose.info = TRUE
}else if(self$loggerType == "DEBUG"){
self$verbose.info = TRUE
self$verbose.debug = TRUE
}
}
}
#baseUrl
if(missing(url)) stop("Please provide the GeoServer base URL")
baseUrl = url
if(!grepl("/rest", baseUrl)){
if(grepl("/$", baseUrl)){
baseUrl = paste0(baseUrl, "rest")
}else{
baseUrl = paste(baseUrl, "rest", sep = "/")
}
}
self$url = baseUrl
private$user = user
private$keyring_backend$set_with_value(private$keyring_service, username = user, password = pwd)
#try to connect
if(self$getClassName() == "GSManager"){
#test connection
self$connect()
#inherit managers methods (experimenting)
list_of_classes <- ls(getNamespaceInfo("geosapi", "exports"))
supportedManagers <- list_of_classes[regexpr("GS.+Manager", list_of_classes)>0]
for(manager in supportedManagers){
class <- eval(parse(text = paste0("geosapi::", manager)))
man <- class$new(baseUrl, user, pwd, logger)
list_of_methods <- rev(names(man))
for(method in list_of_methods){
methodObj <- man[[method]]
if(!(method %in% names(self)) && is(methodObj,"function")){
self[[method]] <- methodObj
environment(self[[method]]) <- environment(self$connect)
}
}
}
}
#inherit GeoServer version
self$version <- GSVersion$new(baseUrl, user, pwd)
invisible(self)
},
#'@description Get URL
#'@return the Geoserver URL
getUrl = function(){
return(self$url)
},
#'@description Connects to geoServer
#'@return \code{TRUE} if connected, raises an error otherwise
connect = function(){
req <- GSUtils$GET(
url = self$getUrl(),
user = private$user,
pwd = private$keyring_backend$get(service = private$keyring_service, username = private$user),
path = "",
verbose = self$verbose.debug
)
if(status_code(req) == 401){
err <- "Impossible to connect to GeoServer: Wrong credentials"
cli::cli_alert_danger(err)
self$ERROR(err)
stop(err)
}
if(status_code(req) == 404){
err <- "Impossible to connect to GeoServer: Incorrect URL or GeoServer temporarily unavailable"
cli::cli_alert_danger(err)
self$ERROR(err)
stop(err)
}
if(status_code(req) != 200){
err <- sprintf("Impossible to connect to Geoserver: Unexpected error (status code %s)", status_code(req))
cli::cli_alert_danger(err)
self$ERROR(err)
stop(err)
}else{
msg = "Successfully connected to GeoServer!"
cli::cli_alert_success(msg)
self$INFO(msg)
}
return(TRUE)
},
#'@description Reloads the GeoServer catalog
#'@return \code{TRUE} if reloaded, \code{FALSE} otherwise
reload = function(){
msg = "Reloading GeoServer catalog"
cli::cli_alert_info(msg)
self$INFO(msg)
reloaded <- FALSE
req <- GSUtils$POST(self$getUrl(), private$user,
private$keyring_backend$get(service = private$keyring_service, username = private$user),
"/reload",
content = NULL, contentType = "text/plain",
self$verbose.debug)
if(status_code(req) == 200){
msg = "Successfully reloaded GeoServer catalog!"
cli::cli_alert_success(msg)
self$INFO(msg)
reloaded <- TRUE
}else{
err = "Error while reloading the GeoServer catalog"
cli::cli_alert_danger(err)
self$ERROR(err)
}
return(reloaded)
},
#'@description Get system status
#'@return an object of class \code{data.frame} given the date time and metrics value
getSystemStatus = function(){
msg = "Get system status"
cli::cli_alert_info(msg)
self$INFO(msg)
datetime <- Sys.time()
req <- GSUtils$GET(self$getUrl(), private$user,
private$keyring_backend$get(service = private$keyring_service, username = private$user),
"/about/system-status",
contentType = "application/json",
self$verbose.debug)
if(status_code(req) == 200){
msg = "Successfully fetched system status"
cli::cli_alert_success(msg)
self$INFO(msg)
}else{
err = "Error while fetching system status"
cli::cli_alert_danger(err)
self$ERROR(err)
}
content <- httr::content(req)
status <- list(
raw = do.call("rbind", lapply(content$metrics$metric, function(metric){
met <- data.frame(metric, stringsAsFactors = FALSE)
return(met)
}))
)
status$values = {
df <- cbind(time = datetime, data.frame(t(status$raw$value), stringsAsFactors = F))
colnames(df) <- c("TIME", status$raw$identifier)
df
}
return(status)
},
#'@description Monitors the Geoserver by launching a small shiny monitoring application
#'@param file file where to store monitoring results
#'@param append whether to append results to existing files
#'@param sleep sleeping interval to trigger a system status call
monitor = function(file = NULL, append = FALSE, sleep = 1){
monitor <- GSShinyMonitor$new(manager = self, file = file, append = append, sleep = sleep)
monitor$run()
},
#'@description Get class name
#'@return the self class name, as \code{character}
getClassName = function(){
return(class(self)[1])
},
#Resources GS managers
#---------------------------------------------------------------------------
#'@description Get Workspace manager
#'@return an object of class \link{GSWorkspaceManager}
getWorkspaceManager = function(){
return(GSWorkspaceManager$new(self$getUrl(), private$user,
private$keyring_backend$get(service = private$keyring_service, username = private$user),
self$loggerType))
},
#'@description Get Namespace manager
#'@return an object of class \link{GSNamespaceManager}
getNamespaceManager = function(){
return(GSNamespaceManager$new(self$getUrl(), private$user,
private$keyring_backend$get(service = private$keyring_service, username = private$user)
, self$loggerType))
},
#'@description Get Datastore manager
#'@return an object of class \link{GSDataStoreManager}
getDataStoreManager = function(){
return(GSDataStoreManager$new(self$getUrl(), private$user,
private$keyring_backend$get(service = private$keyring_service, username = private$user),
self$loggerType))
},
#'@description Get Coverage store manager
#'@return an object of class \link{GSCoverageStoreManager}
getCoverageStoreManager = function(){
return(GSCoverageStoreManager$new(self$getUrl(), private$user,
private$keyring_backend$get(service = private$keyring_service, username = private$user),
self$loggerType))
},
#'@description Get service manager
#'@return an object of class \link{GSServiceManager}
getServiceManager = function(){
return(GSServiceManager$new(self$getUrl(), private$user,
private$keyring_backend$get(service = private$keyring_service, username = private$user),
self$loggerType))
},
#'@description Get style manager
#'@return an object of class \link{GSStyleManager}
getStyleManager = function(){
return(GSStyleManager$new(self$getUrl(), private$user,
private$keyring_backend$get(service = private$keyring_service, username = private$user),
self$loggerType))
}
)
)
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.