Configure File Access
Overview
There are two styles of file access that Liquibase supports:
- File references within changelog files which must remain constant across environments are handled by the "ResourceAccessor" (also known as the "Search Path")
- File references outside changelog files that use environment-specific paths are handled by the "PathHandler"
The reason changelog files are handled differently is that the changelog file must be used unchanged across different environments and run through various integrations.
Search Path
The ResourceAccessor API provides the abstraction around how changelog-related files are looked up and read which allows the file references encoded into changelog files to be usable across a wide range of environments without changes.
The final, overall ResourceAccessor is exposed to end-users as the "Search Path"
Each integration needs to configure the ResourceAccessor
and set it in the liquibase.Scope
sequenceDiagram
participant Integration
participant CommandScope
participant Liquibase Logic
participant ResourceAccessor
Integration->>ResourceAccessor: Create and configure
Integration->>CommandScope: execute()
CommandScope->>Liquibase Logic: Runs Business Logic
Liquibase Logic->>ResourceAccessor: openStream()
ResourceAccessor-->>Liquibase Logic: file stream
SearchPathResourceAccessor
While the overall ResourceAccessor can be created in whatever way works best, you should generally create an instance of SearchPathResourceAccessor passing along their specified search path and any other ResourceAccessors that should be searched as well.
This provides consistent behavior compared to other integrations.
CompositeResourceAccessor
If your integration can't use SearchPathResourceAccessor, use CompositeResourceAccessor to combine multiple ResourceAccessors into an overall "search path" ResourceAccessor.
Liquibase ships with some standard/common ResourceAccessor implementations including:
liquibase.resource.DirectoryResourceAccessor
for reading files from the filesystemliquibase.resource.ClassLoaderResourceAccessor
for reading files from the Java classpathliquibase.resource.ZipResourceAccessor
for reading files from a zip or jar file
Custom ResourceAccessors and PathHandlers
If your integration needs to define its own providers, see Add a ResourceAccessor or Add a PathHandler
API Documentation
The following pages give a complete description of the APIs, including what methods must be implemented:
Example Code
SearchPathResourceAccessor
//set up ConfigurationValueProviders
Scope.child(Scope.Attr.resourceAccessor, new SearchPathResourceAccessor(), () -> {
//Code in this lambda will use the new ResourceAccessor
});
The above code will automatically create ResourceAccessors for each element in the liquibase.searchPath
configuration setting at the point the new SearchPathResourceAccessor()
constructor was called.
For information on how to set up ConfigurationValueProviders, see configure configuration system.
If there are additional ResourceAccessors you would like included regardless of the configured liquibase.searchPath
, you can pass them along in the constructor like this:
ResourceAccessor resourceAccessor = new SearchPathResourceAccessor(
new DirectoryResourceAccessor(projectHome),
new ZipResourceAccessor(Paths.get("/tmp/optional.zip"))
);
Scope.child(Scope.Attr.resourceAccessor, resourceAccessor, () -> {
//Code in this lambda will use the new ResourceAccessor
});
CompositeResourceAccessor
If you need complete control over the search path and do not want to expose the liquibase.searchPath
setting to end-users, you can create a CompositeResourceAccessor
directly:
ResourceAccessor resourceAccessor = new CompositeResourceAccessor(
new DirectoryResourceAccessor(projectHome),
new ZipResourceAccessor(Paths.get("/tmp/optional.zip"))
);
Scope.child(Scope.Attr.resourceAccessor, resourceAccessor, () -> {
//Code in this lambda will use the new ResourceAccessor
});