Skip to content

GSIP 76

Jody Garnett edited this page Jul 12, 2017 · 1 revision

GSIP 76 - Extend REST API to configure settings and OWS services

Overview

Provide the capability to configure global and workspace specific settings and OWS services.

Proposed By

Juan Marin

Assigned to Release

2.2 if possible

State

Choose one of: Under Discussion, In Progress, Completed, Rejected, Deferred

Motivation

Currently the REST API only exposes Catalog related functionality and configuration, such as workspaces, layers, layer groups, styles, etc. This enhancement would allow it to also include REST endpoints to configure general purpose settings (i.e. contact info) and OWS services (WMS, WFS, WCS), both at the global and workspace specific level (virtual services)

Proposal

This proposal intends to extend the REST API to cover other configuration aspects of GeoServer, besides the Catalog related objects. The only modification needed in existent objects is adding a reference to the GeoServer interface in CatalogResourceBase, so that subclasses have access to other parts of GeoServer configuration besides the Catalog. Complete patch with unit tests and documentation has been submitted as a JIRA ticket at https://jira.codehaus.org/browse/GEOS-5122

public abstract class CatalogResourceBase extends ReflectiveResource {

 protected GeoServer geoServer;

 ...

 public CatalogResourceBase(Context context,Request request, Response response,
                            Class clazz, Catalog catalog) {
        super( context, request, response );
        this.clazz = clazz;
        this.catalog = catalog;
        this.xpf = GeoServerExtensions.bean(XStreamPersisterFactory.class);
        this.geoServer = GeoServerExtensions.bean(GeoServer.class);
    }

....

}

All the new endpoints have been implemented following the same conventions and structure present in the Catalog REST API, by creating an AbstractGeoServerFinder that is extended by each implementation to provide the Restlet Finder, and its corresponding Resource to describe the REST endpoint.

public class AbstractGeoServerFinder extends AbstractCatalogFinder {

    protected GeoServer geoServer;

    protected AbstractGeoServerFinder(GeoServer geoServer) {
        super(geoServer.getCatalog());
        this.geoServer = geoServer;
    }

}

The proposal includes implementation of REST endpoints for the following (example URL endpoints assume locally deployed GeoServer running on port 8080):

1. Global settings

The endpoint is at http://localhost:8080/geoserver/rest/settings

It allows GET and PUT operations, and supports HTML (default), XML and JSON

Classes created: GlobalSettingsFinder, GlobalSettingsResource (package org.geoserver.rest, please see patch for details)

2. Global contact

This endpoint can be accessed at http://localhost:8080/geoserver/rest/settings/contact

It allows GET and PUT operations, and supports HTML (default), XML and JSON

Classes created: GlobalContactFinder, GlobalContactResource (package org.geoserver.rest, please see patch for details) *3. Workspace specific settings (GET, POST, PUT, DELETE)*

This endpoint can be accessed at http://localhost:8080/geoserver/rest/workspaces/LocalWorkspace/settings

It allows GET, POST, PUT and DELETE operations, and supports HTML (default), XML and JSON

Classes created: LocalSettingsFinder, LocalSettingsResource (package org.geoserver.rest, please see patch for details)

4. OWS Services configuration

Both global and local settings for OWS services have been implemented by providing a parent class that deals with ServiceInfo objects. Subclasses provide specifics for each OWS service by using the appropriate instance (WMSInfo, WFSInfo, WCSInfo)

The service settings parent class is as follows:

public class ServiceSettingsResource extends AbstractCatalogResource {

    protected GeoServer geoServer;

    private Class clazz;

    public ServiceSettingsResource(Context context, Request request, Response response,
            Class clazz, GeoServer geoServer) {
        super(context, request, response, clazz, geoServer.getCatalog());
        this.clazz = clazz;
        this.geoServer = geoServer;
    }

    @Override
    public boolean allowPost() {
        return allowNew();
    }

    @Override
    public boolean allowPut() {
        return allowExisting();
    }

    @Override
    public boolean allowDelete() {
        String workspace = getAttribute("workspace");
        if (workspace != null) {
            WorkspaceInfo ws = geoServer.getCatalog().getWorkspaceByName(workspace);
            return geoServer.getService(ws, clazz) != null;
        }
        return false;
    }

    private boolean allowNew() {
        String workspace = getAttribute("workspace");
        WorkspaceInfo ws = geoServer.getCatalog().getWorkspaceByName(workspace);
        assert (ws != null);
        return geoServer.getService(ws, clazz) == null;
    }

    private boolean allowExisting() {
        String workspace = getAttribute("workspace");
        if (workspace != null) {
            WorkspaceInfo ws = geoServer.getCatalog().getWorkspaceByName(workspace);
            return geoServer.getService(ws, clazz) != null;
        }
        return geoServer.getService(clazz) != null;
    }

    @Override
    protected Object handleObjectGet() throws Exception {
        String workspace = getAttribute("workspace");
        if (workspace != null) {
            WorkspaceInfo ws = geoServer.getCatalog().getWorkspaceByName(workspace);
            if (geoServer.getService(ws, clazz) == null) {
                throw new RestletException("Service for workspace " + workspace + " does not exist",
                        Status.CLIENT_ERROR_NOT_FOUND);
            }
            return geoServer.getService(ws, clazz);
        }
        if (geoServer.getService(clazz) == null) {
            throw new RestletException("Service for workspace " + workspace + " does not exist",
                    Status.CLIENT_ERROR_NOT_FOUND);
        }
        return (ServiceInfo) geoServer.getService(clazz);
    }

    @Override
    protected String handleObjectPost(Object object) throws Exception {
        String name = "";
        ServiceInfo serviceInfo = handlePost(object);
        name = serviceInfo.getName();
        if (name == null) {
            throw new RestletException("Service name cannot be null",
                    Status.CLIENT_ERROR_BAD_REQUEST);
        }
        geoServer.add(serviceInfo);
        return name;
    }

    protected ServiceInfo handlePost(Object object) {
        String workspace = getAttribute("workspace");
        if (workspace != null) {
            WorkspaceInfo ws = geoServer.getCatalog().getWorkspaceByName(workspace);
            if (ws == null) {
                throw new RestletException("Workspace does not exist",
                        Status.CLIENT_ERROR_BAD_REQUEST);
            }
            if (geoServer.getService(ws, clazz) != null) {
                throw new RestletException(
                        "Service information already exists, creation of a new object is not allowed",
                        Status.CLIENT_ERROR_FORBIDDEN);
            }
            ServiceInfo serviceInfo = (ServiceInfo) object;
            serviceInfo.setWorkspace(ws);
            return serviceInfo;
        }
        return null;
    }

    @Override
    protected void handleObjectPut(Object object) throws Exception {
        String workspace = getAttribute("workspace");
        ServiceInfo original = null;
        if (workspace != null) {
            WorkspaceInfo ws = geoServer.getCatalog().getWorkspaceByName(workspace);
            original = geoServer.getService(ws, clazz);
            OwsUtils.copy(object, original, clazz);
            original.setWorkspace(ws);
        } else {
            original = geoServer.getService(clazz);
        }
        OwsUtils.copy(object, original, clazz);
        geoServer.save(original);
    }

    @Override
    protected void handleObjectDelete() throws Exception {
        String workspace = getAttribute("workspace");
        if (workspace != null) {
            WorkspaceInfo ws = geoServer.getCatalog().getWorkspaceByName(workspace);
            ServiceInfo serviceInfo = geoServer.getService(ws, clazz);
            if (serviceInfo != null) {
                geoServer.remove(serviceInfo);
            }
        }
    }
}

Classes created: ServiceSettingsResource, WCSSettingsFinder, WCSSettingsResource,WFSSettingsFinder, WFSSettingsResource, WMSSettingsFinder, WMSSettingsResource (package org.geoserver.service.rest, please see patch for details)

4.1 Global OWS Service settings

These endpoints can be accessed at the following URLs:

http://localhost:8080/geoserver/rest/services/wcs/settings http://localhost:8080/geoserver/rest/services/wfs/settings http://localhost:8080/geoserver/rest/services/wms/settings

They allow GET and PUT operations, and support HTML (default), XML and JSON

4.2 Workspace specific OWS Service settings

These endpoints can be accessed at the following URLs:

http://localhost:8080/geoserver/rest/services/wcs//settings http://localhost:8080/geoserver/rest/services/wfs//settings http://localhost:8080/geoserver/rest/services/wms//settings

They allow GET, POST, PUT and DELETE operations, and support HTML (default), XML and JSON

Feedback

This section should contain feedback provided by PSC members who may have a problem with the proposal.

Backwards Compatibility

No backwards compatibility issues.

Voting

Andrea Aime: Alessio Fabiani: Ben Caradoc Davies: Gabriel Roldan: Justin Deoliveira: Jody Garnett: Mark Leslie: Rob Atkinson: Simone Giannecchini:

Links

JIRA Task Email Discussion Wiki Page

Clone this wiki locally