public interface RepoTransport extends AutoCloseable
The naming in this interface assumes a local client talking to a remote repository. But the repository accessed via this transport does not need to be remote - it might be in the local file system!
More precisely:
"Remote repository" references the repository which is accessed via this transport layer. The word "remote" thus indicates that there might be some distance between here and wherever this repository is located.
"Client" should primarily be understood as API client, i.e. the code using the methods of this
interface. The "client repository" is the repository for which some client code accesses this
RepoTransport
, therefore the "client repository" is used for repo-to-repo-authentication. Some
methods in this interface can be used without authentication (i.e. anonymously) - therefore a "client
repository" is optional.
The synchronisation logic accesses all repositories through this abstraction layer. Therefore, the synchronisation logic does not need to know any details about how to communicate with a repository.
There are currently two implementations:
An instance of an implementation of RepoTransport
is obtained via the
RepoTransportFactory
.
Important: Implementors should not directly implement this interface, but instead sub-class
AbstractRepoTransport
!
Modifier and Type | Method and Description |
---|---|
void |
beginPutFile(String path)
Begins a file transfer to this
RepoTransport (more precisely the remote repository behind it). |
void |
close() |
void |
copy(String fromPath,
String toPath) |
void |
delete(String path)
Deletes the file (or directory) specified by
path . |
void |
endPutFile(String path,
Date lastModified,
long length,
String sha1)
Ends a file transfer to this
RepoTransport (more precisely the remote repository behind it). |
void |
endSyncFromRepository()
Marks the end of a synchronisation from the remote repository behind this
RepoTransport . |
void |
endSyncToRepository(long fromLocalRevision)
Marks the end of a synchronisation to the remote repository behind this
RepoTransport . |
ChangeSetDto |
getChangeSetDto(boolean localSync,
Long lastSyncToRemoteRepoLocalRepositoryRevisionSynced)
Gets the change-set from the remote repository.
|
RepositoryDto |
getClientRepositoryDto() |
UUID |
getClientRepositoryId()
Gets the client repository's unique identifier.
|
byte[] |
getFileData(String path,
long offset,
int length)
Get the binary file data at the given
offset and with the given length . |
String |
getPathPrefix()
Prefix for every path (as used in
delete(String) for example). |
byte[] |
getPublicKey()
Gets the remote repository's public key.
|
URL |
getRemoteRoot()
Gets the remote repository's root URL, maybe including a path-prefix.
|
URL |
getRemoteRootWithoutPathPrefix()
Gets the remote repository's root URL without the path-prefix.
|
RepoFileDto |
getRepoFileDto(String path)
|
RepositoryDto |
getRepositoryDto()
Gets the remote repository's repository-descriptor.
|
UUID |
getRepositoryId()
Get the remote repository's unique identifier.
|
RepoTransportFactory |
getRepoTransportFactory()
Gets the factory which created this instance.
|
VersionInfoDto |
getVersionInfoDto() |
void |
makeDirectory(String path,
Date lastModified)
Creates the specified directory (including all parent-directories as needed).
|
void |
makeSymlink(String path,
String target,
Date lastModified) |
void |
move(String fromPath,
String toPath) |
String |
prefixPath(String path)
Prepend the
pathPrefix to the given path . |
void |
prepareForChangeSetDto(ChangeSetDto changeSetDto)
Notifies the destination repository that this change-set is about to be synced into it.
|
void |
putFileData(String path,
long offset,
byte[] fileData)
Write a block of binary data into the file.
|
void |
putParentConfigPropSetDto(ConfigPropSetDto parentConfigPropSetDto) |
void |
requestRepoConnection(byte[] publicKey)
Request to connect the client repository with
the remote repository.
|
void |
setClientRepositoryId(UUID clientRepositoryId)
Sets the client's repository identifier.
|
void |
setRemoteRoot(URL remoteRoot)
Sets the remote repository's root URL.
|
void |
setRepoTransportFactory(RepoTransportFactory repoTransportFactory)
Sets the factory which created this instance.
|
String |
unprefixPath(String path)
Cut the
pathPrefix from the given path . |
RepoTransportFactory getRepoTransportFactory()
null
, if properly initialised.setRepoTransportFactory(RepoTransportFactory)
void setRepoTransportFactory(RepoTransportFactory repoTransportFactory)
repoTransportFactory
- the factory which created this instance. Must not be null
.getRepoTransportFactory()
URL getRemoteRoot()
This is thus the remote repository's root URL as used to synchronise a certain local repository. The word "remote" should not be misunderstood as actually on another computer. It just means behind this transport abstraction.
In contrast to the remoteRootWithoutPathPrefix
, this is
the connection point for the synchronisation, which might be a sub-directory, i.e. not the native
root of the connected repository.
null
, if properly initialised.setRemoteRoot(URL)
void setRemoteRoot(URL remoteRoot)
This URL is the point where the client-repository is connected
to the repository managed by this RepoTransport
.
You should never directly invoke this method! It is automatically called when creating a
RepoTransport
instance via the RepoTransportFactory
.
Invoking this method twice with different remoteRoot
values is not allowed. The remoteRoot
cannot be changed after it was once set.
remoteRoot
- the remote repository's root URL. It may be null
, but this
RepoTransport
is only usable, after this method was invoked with a non-null
value.getRemoteRoot()
UUID getClientRepositoryId()
The word "client" does not necessarily mean a remote JVM. It merely means the API client accessing
this RepoTransport
API.
This property might be null
. If it is not set, only operations which do not require
repo-to-repo-authentication can be used.
null
.setClientRepositoryId(UUID)
void setClientRepositoryId(UUID clientRepositoryId)
clientRepositoryId
- the client's repository identifier. May be null
.getClientRepositoryId()
URL getRemoteRootWithoutPathPrefix()
In other words, this is the repository's native root, even if the connection is established to a sub-directory.
null
, if properly initialised.String getPathPrefix()
delete(String)
for example).
It is possible to connect to a repository at a sub-directory, i.e. not the repo's root. If this
RepoTransport
is connected to the repo's root, this pathPrefix
is an empty string.
But if this RepoTransport
is connected to a sub-directory, this sub-directory will be the
pathPrefix
.
For example, if the remoteRoot
is
"https://some.host/some/repo/Private+pictures/Wedding+%26+honeymoon"
and the
remoteRootWithoutPathPrefix
is
"https://some.host/some/repo"
,
then this pathPrefix
will be "/Private pictures/Wedding & honeymoon"
.
As shown in this example, the pathPrefix
is - just like every other path - not encoded
in any way! The separator for the path-segments inside this prefix is "/" on all operating systems.
The RepoTransport
implementations use this prefix to calculate back and forth between the
path relative to the connected remoteRoot
and the complete path used in the repository.
String prefixPath(String path)
pathPrefix
to the given path
.path
- the path to be prepended. Must not be null
.pathPrefix
and the given
path
. Never null
.unprefixPath(String)
,
getPathPrefix()
String unprefixPath(String path)
pathPrefix
from the given path
.path
- the path to be shortened. Must not be null
. Of course, this path
must start with pathPrefix
.pathPrefix
. Never
null
.prefixPath(String)
,
getPathPrefix()
RepositoryDto getRepositoryDto()
This operation does not require authentication! It can (and is regularly) invoked anonymously.
null
.UUID getRepositoryId()
byte[] getPublicKey()
null
.void requestRepoConnection(byte[] publicKey)
publicKey
- the public key of the client repository which requests the connection. Must not be
null
.ChangeSetDto getChangeSetDto(boolean localSync, Long lastSyncToRemoteRepoLocalRepositoryRevisionSynced)
The invocation of this method marks the beginning of a synchronisation. After the synchronisation is
complete, the endSyncFromRepository()
method must be invoked to notify the remote repository
that all changes contained in the change set have been successfully and completely written to the
client repository.
The change-set is dependent on the client repository: Every client repository gets its own individual
change-set. The remote repository tracks which changes need to be sent to the client. In normal
operation, the same change is transferred only once. Under certain circumstances, however, the same
change might be transferred multiple times and the client must cope with this! Such duplicate
transfers happen, if the transfer is interrupted - i.e. the endSyncFromRepository()
was not
invoked.
Please note that the DTOs in this ChangeSetDto
do not need to be completely resolved. They
might be incomplete in order to reduce the size of the ChangeSetDto
. For example,
NormalFileDto.fileChunkDtos
is not populated. These details
are separately requested, later - e.g. by getRepoFileDto(String)
.
localSync
- true
indicates that the remote repository should perform a local sync
before calculating the change set. false
indicates that the remote repository should
abstain from a local sync. This flag is a hint and the remote repository does not need to adhere it.lastSyncToRemoteRepoLocalRepositoryRevisionSynced
- the last revision that was synced.
May be null
. If it is not null
, the property
co.codewizards.cloudstore.local.persistence.LastSyncToRemoteRepo.localRepositoryRevisionSynced
is overwritten by this value, before querying the changes. This causes all data modified in greater
(not equal) revisions to be included.null
.void prepareForChangeSetDto(ChangeSetDto changeSetDto)
changeSetDto
- the change-set from the other RepoTransport (the source of the sync). Never null
.void makeDirectory(String path, Date lastModified)
If the directory already exists, this is a noop.
If there is any obstruction in the way of this path (e.g. a normal file), it is moved away (renamed or simply deleted depending on the conflict resolution strategy).
path
- the path of the directory. Must not be null
. No matter which operating system is used,
the separation-character is always '/'. This path may start with a "/", but there is no difference, if it does:
It is always relative to the repository's root directory.lastModified
- the last-modified-timestamp the newly created
directory will be set to.
May be null
(in which case the lastModified
property is not touched). This applies only to the
actual directory and not to the parent-directories! The parent-directories' lastModified
properties are never
touched - even if the parent-directories are newly created.void makeSymlink(String path, String target, Date lastModified)
void delete(String path)
path
.
If there is no such file (or directory), this method is a noop.
If path
denotes a directory, all its children (if there are) are deleted recursively.
path
- the path of the file (or directory) to be deleted. Must not be null
. No matter which
operating system is used, the separation-character is always '/'. This path may start with a "/", but there is no
difference, if it does: It is always relative to the repository's root directory.RepoFileDto getRepoFileDto(String path)
path
- the path to the file.path
. Never null
.byte[] getFileData(String path, long offset, int length)
offset
and with the given length
.
If the file was modified/deleted, this method should not fail, but simply return null
or a result being shorter than the length
specified.
path
- the path of the file. Must not be null
. No matter which operating system is used,
the separation-character is always '/'. This path may start with a "/", but there is no difference, if it does:
It is always relative to the repository's root directory.offset
- the offset of the first byte to be read (0-based).length
- the length of the data to be read. -1 to read from offset
to the end of the file.void beginPutFile(String path)
RepoTransport
(more precisely the remote repository behind it).
Usually, this method creates the specified file in the file system (if necessary with parent-directories)
and in the database. But this operation may be deferred until endPutFile(String, Date, long, String)
.
If the file is immediately created, it should not be synchronised to any other repository, yet! It should
be ignored, until endPutFile(String, Date, long, String)
was called for it.
In normal operation, zero or more invocations of putFileData(String, long, byte[])
and
finally one invocation of endPutFile(String, Date, long, String)
follow this method. However, this is not
guaranteed and the file transfer may be interrupted. If it is resumed, later this method is called again,
without endPutFile(String, Date, long, String)
ever having been called in between.
path
- the path of the file. Must not be null
. No matter which operating system is used,
the separation-character is always '/'. This path may start with a "/", but there is no difference, if it does:
It is always relative to the repository's root directory.putFileData(String, long, byte[])
,
endPutFile(String, Date, long, String)
void putFileData(String path, long offset, byte[] fileData)
This method may only be called after beginPutFile(String)
and before endPutFile(String, Date, long, String)
.
offset
- the 0-based position in the file at which the block should be written.beginPutFile(String)
,
endPutFile(String, Date, long, String)
void endPutFile(String path, Date lastModified, long length, String sha1)
RepoTransport
(more precisely the remote repository behind it).path
- the path of the file. Must not be null
. No matter which operating system is used,
the separation-character is always '/'. This path may start with a "/", but there is no difference, if it does:
It is always relative to the repository's root directory.lastModified
- when was the file's last modification. Must not be null
.length
- the length of the file in bytes. If the file already existed and was longer, it is
truncated to this length.sha1
- the SHA1 hash of the file. May be null
. If it is given, the repository may
log a warning, if the current file is different. It should not throw an exception, because it
is a valid state that a file is modified (by another process) while it is transferred.void endSyncFromRepository()
RepoTransport
.
This method should be invoked after all changes indicated by #getChangeSetDto(boolean, long)
have
been completely written into the client repository.
After this method was invoked, #getChangeSetDto(boolean, long)
will return the new changes only.
New changes means all those changes that were accumulated after its last invocation - not after the
invocation of this method! This method might be called some time after getChangeSetDto(...)
and it must be guaranteed that changes done between getChangeSetDto(...)
and
endSyncFromRepository()
are contained in the next invocation of getChangeSetDto(...)
.
This method must not be invoked, if an error was encountered during the synchronisation! It must thus
not be used in a finally block! More invocations of getChangeSetDto(...)
than of
endSyncFromRepository()
are totally fine.
void endSyncToRepository(long fromLocalRevision)
RepoTransport
.
This method should be invoked after all changes in the client repository have been completely written
into the remote repository behind this RepoTransport
.
fromLocalRevision
- the localRevision
of the source-repository to which the destination
repository is now synchronous.void close()
close
in interface AutoCloseable
void putParentConfigPropSetDto(ConfigPropSetDto parentConfigPropSetDto)
VersionInfoDto getVersionInfoDto()
RepositoryDto getClientRepositoryDto()
Copyright © 2013–2018. All rights reserved.