001package co.codewizards.cloudstore.core.repo.local; 002 003import java.lang.reflect.InvocationHandler; 004import java.net.URL; 005import java.util.Map; 006import java.util.UUID; 007import java.util.concurrent.locks.Lock; 008 009import co.codewizards.cloudstore.core.appid.AppIdRegistry; 010import co.codewizards.cloudstore.core.oio.File; 011import co.codewizards.cloudstore.core.progress.ProgressMonitor; 012 013public interface LocalRepoManager extends AutoCloseable { 014 String APP_ID_SIMPLE_ID = AppIdRegistry.getInstance().getAppIdOrFail().getSimpleId(); 015 016 String SYSTEM_PROPERTY_KEY_SIZE = APP_ID_SIMPLE_ID + ".repository.asymmetricKey.size"; 017 int DEFAULT_KEY_SIZE = 4096; 018 019 /** 020 * @deprecated replaced by {@link #CONFIG_KEY_CLOSE_DEFERRED_MILLIS}. 021 */ 022 @Deprecated 023 String SYSTEM_PROPERTY_CLOSE_DEFERRED_MILLIS = APP_ID_SIMPLE_ID + ".localRepoManager.closeDeferredMillis"; 024 String CONFIG_KEY_CLOSE_DEFERRED_MILLIS = "localRepoManager.closeDeferredMillis"; 025 long DEFAULT_CLOSE_DEFERRED_MILLIS = 20L * 1000L; 026 027 String META_DIR_NAME = "." + APP_ID_SIMPLE_ID + "-repo"; 028 /** 029 * Temporary directory potentially inside every directory. 030 * <p> 031 * For example: <code>${repo}/Accounting/2019/.cloudstore-tmp/</code> 032 */ 033 String TEMP_DIR_NAME = "." + APP_ID_SIMPLE_ID + "-tmp"; 034 String TEMP_NEW_FILE_PREFIX = "." + APP_ID_SIMPLE_ID + "-new_"; 035 036 /** 037 * Repository-wide global directory inside the meta-directory. 038 * <p> 039 * For example: <code>${repo}/.cloudstore-repo/tmp/</code> 040 */ 041 String REPO_TEMP_DIR_NAME = "tmp"; 042 043 String REPOSITORY_LOCK_FILE_NAME = APP_ID_SIMPLE_ID + "-repository.lock"; 044 String REPOSITORY_PROPERTIES_FILE_NAME = APP_ID_SIMPLE_ID + "-repository.properties"; 045 String PROP_REPOSITORY_ID = "repository.id"; 046 String PROP_VERSION = "repository.version"; 047 /** 048 * Aliases separated by '/' (because '/' is an illegal character for an alias). 049 * <p> 050 * To make scripting easier (e.g. using grep), the aliases start and end with a 051 * '/'. For example: "/alias1/alias2/alias3/" 052 */ 053 String PROP_REPOSITORY_ALIASES = "repository.aliases"; 054 055 String PERSISTENCE_PROPERTIES_FILE_NAME = APP_ID_SIMPLE_ID + "-persistence.properties"; 056 057 String VAR_REPOSITORY_ID = "repository.id"; 058 String VAR_LOCAL_ROOT = "repository.localRoot"; 059 String VAR_META_DIR = "repository.metaDir"; 060 061 /** 062 * Gets the repository's local root directory. 063 * <p> 064 * This file is canonical (absolute and symbolic links resolved). 065 * @return the repository's local root directory. Never <code>null</code>. 066 */ 067 File getLocalRoot(); 068 069 /** 070 * Gets the local repository's unique ID. 071 * <p> 072 * This is {@link LocalRepository#getEntityID() LocalRepository.entityID} in the local repository database. 073 * @return the local repository's unique ID. Never <code>null</code>. 074 */ 075 UUID getRepositoryId(); 076 077 /** 078 * Gets the local repository's private key. 079 * <p> 080 * This is always an RSA key - other key types are not (yet) supported. 081 * @return the local repository's private key. Never <code>null</code>. 082 */ 083 byte[] getPrivateKey(); 084 085 /** 086 * Gets the local repository's public key. 087 * <p> 088 * This is always an RSA key - other key types are not (yet) supported. 089 * @return the local repository's public key. Never <code>null</code>. 090 */ 091 byte[] getPublicKey(); 092 093 /** 094 * Gets the remote repository's public key. 095 * <p> 096 * This is always an RSA key - other key types are not (yet) supported. 097 * @param repositoryId the remote repository's unique ID. Must not be <code>null</code>. 098 * @return the remote repository's public key. Never <code>null</code>. 099 * @throws IllegalArgumentException if there is no remote-repository with the given {@code repositoryId}. 100 */ 101 byte[] getRemoteRepositoryPublicKeyOrFail(UUID repositoryId); 102 103 void addLocalRepoManagerCloseListener(LocalRepoManagerCloseListener listener); 104 105 void removeLocalRepoManagerCloseListener(LocalRepoManagerCloseListener listener); 106 107 /** 108 * Gets the <i>open</i> state. 109 * <p> 110 * If this is <code>false</code>, the {@link LocalRepoManager} instance cannot be used anymore. 111 * Due to the proxy-mechanism, this does, however, not mean that the backend is really shut down. 112 * @return the <i>open</i> state. 113 */ 114 boolean isOpen(); 115 116 /** 117 * Closes this {@link LocalRepoManager}. 118 * <p> 119 * <b>Important:</b> The {@link LocalRepoManagerFactory} always returns a proxy. It never returns 120 * the real backend-instance. Calling {@code close()} closes the proxy and thus renders it unusable. 121 * It decrements the real backend-instance's reference counter. As soon as this reaches 0, the backend 122 * is really closed - which may happen delayed (for performance reasons). 123 */ 124 @Override 125 void close(); 126 127 /** 128 * Begin a JDO transaction for read operations only in the underlying database. 129 * @return the transaction handle. Never <code>null</code>. 130 */ 131 LocalRepoTransaction beginReadTransaction(); 132 133 /** 134 * Begin a JDO transaction for read and write operations in the underlying database. 135 * @return the transaction handle. Never <code>null</code>. 136 */ 137 LocalRepoTransaction beginWriteTransaction(); 138 139 /** 140 * Synchronises the local file system with the local database. 141 * <p> 142 * Registers every directory and file in the repository's {@link #getLocalRoot() local root} and its 143 * sub-directories. 144 */ 145 void localSync(ProgressMonitor monitor); 146 147 /** 148 * Adds or relocates a remote repository. 149 * @param repositoryId the remote repository's unique ID. Must not be <code>null</code>. This is 150 * {@link LocalRepository#getEntityID() LocalRepository.entityID} in the remote database and will become 151 * {@link RemoteRepository#getEntityID() RemoteRepository.entityID} in the local database. 152 * @param remoteRoot the URL of the remote repository. May be <code>null</code> (in the server, a 153 * {@code RemoteRepository} never has a {@code remoteRoot}). 154 * @param localPathPrefix TODO 155 */ 156 void putRemoteRepository(UUID repositoryId, URL remoteRoot, byte[] publicKey, String localPathPrefix); 157 158 /** 159 * Deletes a remote repository from the local database. 160 * <p> 161 * Does nothing, if the specified repository does not exist. 162 * @param repositoryId the remote repository's unique ID. Must not be <code>null</code>. 163 */ 164 void deleteRemoteRepository(UUID repositoryId); 165 166 Map<UUID, URL> getRemoteRepositoryId2RemoteRootMap(); 167 168 /** 169 * Gets the local path-prefix (of the local repository managed by this {@code LocalRepoManager}) when syncing with 170 * the remote repository identified by the given {@code remoteRoot}. 171 * @param remoteRoot the remote repository's root-URL (not necessarily its real root, but the root URL connected 172 * to the local repository). Must not be <code>null</code>. 173 * @return the local path-prefix. Never <code>null</code>, but maybe empty. 174 * @throws IllegalArgumentException if there is no remote-repository with the given {@code remoteRoot}. 175 */ 176 String getLocalPathPrefixOrFail(URL remoteRoot); 177 178 /** 179 * Gets the local path-prefix (of the local repository managed by this {@code LocalRepoManager}) when syncing with 180 * the remote repository identified by the given {@code remoteRoot}. 181 * @param repositoryId the remote repository's unique ID. Must not be <code>null</code>. 182 * @return the local path-prefix. Never <code>null</code>, but maybe empty. 183 * @throws IllegalArgumentException if there is no remote-repository with the given {@code remoteRoot}. 184 */ 185 String getLocalPathPrefixOrFail(UUID repositoryId); 186 187 /** 188 * Gets the unique ID of the remote repository identified by the given {@code remoteRoot}. 189 * @param remoteRoot the remote repository's root-URL (not necessarily its real root, but the root URL connected 190 * to the local repository). Must not be <code>null</code>. 191 * @return the remote repository's unique ID. Never <code>null</code>. 192 * @throws IllegalArgumentException if there is no remote-repository with the given {@code remoteRoot}. 193 */ 194 UUID getRemoteRepositoryIdOrFail(URL remoteRoot); 195 196 Lock getLock(); 197 198 /** 199 * @deprecated <b>Do not invoke this method directly!</b> It is declared in this interface to make sure the 200 * proxy's {@link InvocationHandler} is invoked when the garbage-collector collects the proxy. 201 */ 202 @Deprecated 203 void finalize() throws Throwable; 204 205 void putRepositoryAlias(String repositoryAlias); 206 207 void removeRepositoryAlias(String repositoryAlias); 208 209 LocalRepoMetaData getLocalRepoMetaData(); 210}