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