Skip to content

ResourceStore Design

jodygarnett edited this page Oct 20, 2014 · 2 revisions

The ResourceStore and Resource interfaces allow stream access to GeoServer configuration. This addition allows the management of configuration files.

Design

GeoServer data directory plays host to the following kinds of files:

  • managed files - config / catalog files managed using GeoServer Catalog and Service objects.
  • config files - templates, sld files, icons and fonts, password files
  • logs - a few module specific logs exist
  • temp files - such as GWC tile cache
  • spatial data - requires file system access (i.e. not managed by GeoServer)

This design if focused on making config file use easier to code, test and manage.

ResourceStore

The ResourceStore interface used for managed files:

interface ResourceStore {
   Resource get(String path);
   boolean remove(String path);
   boolean move(String path, String destination);
}

The most common use is simply to look up a resource:

Resource resource = loader.get("logging.xml");

Anything more complicated will be handled by a utility class:

  • Paths: utility methods for resource location
  • Resources: utility methods to automate common tasks
  • Files: utility methods for file management (similar to ImageIO and security lock classes)

Resource

The Resource interface used to interact with resources at a file by file level:

interface Resource {
  String path();
  String name();

  Lock lock();
  addListener( GeoServerResourceListener listener );
  removeListener( GeoServerResourceListener listener );

  InputStream in();
  OutputStream out();

  File file();
  File dir();

  long lastmodified();

  Resource parent();
  Resource get(String path);
  Resource[] list();

  Type getType();

  enum Type {DIRECTORY,RESOURCE,UNDEFINED}
}

The interface focuses on ease of use with quick methods input and output stream access:

BufferedOutputStream out = new BufferedOutputStream( loader.get(path).out() );
SLDFormat format = new SLDFormat(true);
format.toRepresentation(style).write(out);

File access is also available:

schemaFile = catalog.getResourceLoader().get( Paths.path("workspaces",prefix,store,name,"schema.xsd") ).file();

When used with JDBCConfig the latest file will be unpacked into the data directory.


Additional examples are provided in the migration plan below.

Resources

GeoServerResourceLoader and GeoServerDataDirectory contain a lot of duplicate functionality, often following a naming convention to determine if a file existence should be checked, and if it should be created as needed.

The Resources utility class isolates this logic from the ResourceStore API:

class Resources {
  static ResourceStore EMPTY;

  static File find(Resource);
  static File directory(Resource);
  static File file(Resource);
  static File createNewDirectory(Resource);
  static File createNewFile(Resource);

  static File search(Resource, long);
}

Paths

The remaining complexity of GeoServerResourceLoader and GeoSeverDataDirectory comes from filename manipulation. There are also a fair number of examples where code assumes unix style “/” separators.

class Paths {
  static String path(String...);
  static List<String> names(String);

  static String convert(File, File);
  static String convert(File, File, String);
  static String convert(File, File, String...);
  static String convert(String);
  static String convert(String, String);

Integration Plan

GeoServerResourceLoader

GeoServerResourceLoader is responsible for isolating GeoServer modules from file access:

  • Although GeoServerResourceLoader supports a “search path” for finding contents this is rarely used
  • GeoServerResourceLoader is successfully used by the majority of the codebase for “stream access”. The file reference is immediately used with a FileInputStream to read the file.
  • GeoServerDataDirectory uses GeoServerResourceLoader for “directory access”. Once it has retrieved a Directory location it then manages files on its own
  • Finally GeoServerDataDirectory can be used for “file access”. With the resulting file being passed to an external library or converted to a URL reference.

Integration:

  • In GeoServer 2.4 resource access is handled by GeoServerResourceLoader:

    class GeoServerResourceLoader { File find(String path); File createFile(String path); File findOrCreateDirectory(String path); ... }

  • Inject ResourceStore from the application context and update GeoServerResourceLoader to delegate to ResourceStore.

    class GeoServerResourceLoader { setResourceStore(ResourceStore); ResourceStore getResourceStore();

    File find(String path);
    File createFile(String path);
    File findOrCreateDirectory(String path);
    ...
    

    }

  • Provide easy access to ResourceStore methods:

    class GeoServerResourceLoader implements ResourceStore { setResourceStore(ResourceStore); ResourceStore getResourceStore();

    Resource get(String path);
    boolean remove(String path);
    boolean move(String path, String destination);
    
    File find(String path);
    File createFile(String path);
    File findOrCreateDirectory(String path);
    ...
    

    }

  • Deprecated methods for direct file access (client code to use Resource instead).

    class GeoServerResourceLoader implements ResourceStore { setResourceStore(ResourceStore); ResourceStore getResourceStore();

    Resource get(String path);
    boolean remove(String path);
    boolean move(String path, String destination);
    
    @Deprecated File find(String path);
    @Deprecated File createFile(String path);
    @Deprecated File findOrCreateDirectory(String path);
    ...
    

    }

org.geoserver.config.GeoServerDataDirectory

The GeoServerDataDirectory is an example that just uses GeoServerResourceLoader to get a directory location, and then proceeds to manage files from there.

class GeoServerDataDirectory {
   GeoServerResourceLoader resourceLoader;
   ...
   public File findStoreFile( StoreInfo s );
   public File findOrResolveStoreFile( StoreInfo s );
   private File storeFile( boolean create, StoreInfo s );
   ...
   public File findSecurityRoot()
   public File findOrCreateSecurityRoot()
   private File securityRoot(boolean create)
   public File findSecurityDir(String...)
   public File findOrCreateSecurityDir(String...)
   private File securityDir(boolean create, String...)
   public void copyToSecurityDir(File)
   public void copyToSecurityDir(InputStream, String)
}

Much of the code here is designed to make GeoResourceLoader easier to use:

    public File findOrCreateWorkspaceDir(WorkspaceInfo ws) throws IOException {
        return workspaceDir( true, ws );
    }
    File workspaceDir( boolean create, WorkspaceInfo ws ) throws IOException {
        File workspaces = create ? resourceLoader.findOrCreateDirectory( "workspaces" ) 
           : resourceLoader.find( "workspaces" );
        if ( workspaces != null ) {
            return dir(new File( workspaces, ws.getName() ), create);
        }
        return null;
    }

Updated to use Resource:

    public File findOrCreateWorkspaceDir(WorkspaceInfo ws) throws IOException {
        Resource directory = get(path(ws));
        return directory.dir();
    }
    private String path(WorkspaceInfo workspace) {
        return Paths.path("workspaces", workspace.getName());
    }
    @Deprecated
    private File workspaceDir(boolean create, WorkspaceInfo ws) throws IOException {
        if (create) {
            Resource directory = get(path(ws));
            return directory.dir();
        } else {
            Resource directory = get(path(ws));
            return Resources.directory(directory);
        }
    }

Update this interface to allow access to Resource:

class GeoServerDataDirectory {
   GeoServerResourceLoader resourceLoader;
   ...
   Resource get( StoreInfo s );
   Resource get( WorkspaceInfo w );
   Resource security();
   ...
   @deprecate public File findStoreFile( StoreInfo s );
   @deprecate public File findOrResolveStoreFile( StoreInfo s );
   @deprecate private File storeFile( boolean create, StoreInfo s );
   ...
   ...
   @deprecate public File findSecurityRoot()
   @deprecate public File findOrCreateSecurityRoot()
   @deprecate private File securityRoot(boolean create)
   @deprecate public File findSecurityDir(String...)
   @deprecate public File findOrCreateSecurityDir(String...)
   @deprecate private File securityDir(boolean create, String...)
   @deprecate public void copyToSecurityDir(File)
   @deprecate public void copyToSecurityDir(InputStream, String)
}

org.vfny.geoserver.global.GeoserverDataDirectory

This class is actually used to access GEOSERVER_HOME ((predating the split to an external GEOSERVER_DATA directory).

class GeoserverDataDirectory {
  File getGeoserverDataDirectory()
  String findFeatureTypeDirName(SimpleFeatureType)
  String findCoverageDirName(String)
  File findConfigDir(File, String)
  File findCreateConfigDir(String)
  File findDataFile(URL)
  File findStyleFile(String)
  File findStyleFile(String, boolean)
  File findDataFile(String)
  File findConfigFile(String)
}

GeoServerSecurityManager

GeoServerSecurityManager makes use of GeoServerDataDirectory to locate a working directory.

public class GeoServerSecurityManager {
    GeoServerDataDirectory dataDir;

    public File getSecurityRoot();
    public File getRoleRoot();
    public File getPasswordPolicyRoot();
    public File getUserGroupRoot();
    public File getAuthRoot();
    public File getFilterRoot();
    public File getMasterPasswordProviderRoot();

Migrate from “directory access” to use of Resource.

public class GeoServerSecurityManager {
    GeoServerDataDirectory dataDir;

    Resource security();
    Resource passwordPolicy();
    Resource userGroup();
    Resource auth();
    Resource filter();
    Resource masterPasswordProvider();

    @deprecated public File getSecurityRoot();
    @deprecated public File getRoleRoot();
    @deprecated public File getPasswordPolicyRoot();
    @deprecated public File getUserGroupRoot();
    @deprecated public File getAuthRoot();
    @deprecated public File getFilterRoot();
    @deprecated public File getMasterPasswordProviderRoot();

GeoServerSecurity Manger methods used to construct file references:

File info = new File(getSecurityRoot(),MASTER_PASSWD_INFO_FILENAME);

Can be updated to use Resource:

File info = securityRoot().get(MASTER_PASSWD_INFO_FILENAME).file();

{tip} Note it may be worth just providing static constants for the above “root” paths.

public interface Paths {
    public static String SECURITY_DIR = "security";
    public static String SECURITY_ROLE_DIR = "security/role";
    public static String SECURITY_PASSWORD_POLICY_DIR = "security/pwpolicy";
    ...    
}

{tip}

Support Files

There are a few cases where we may need to look at how GeoTools can use use Resource:

  • SLD reference to Icons and Fonts

    • reference directory styles (asking it to check and unpack all directory contents)
    • Preprocess the SLD and ensure required Resources have been extracted to a File (this is done when moving style between workspaces)
    • Or preprocess the SLD to use an “internal” base URL, and register a URLHandler to look up the resource (works for dynamically determined icon references)
  • Referencing use of grid shift files

Clone this wiki locally