From 40ed19976c496bd32d6fa6cdda321942a437a19c Mon Sep 17 00:00:00 2001 From: Romman Sabbir Date: Sun, 15 May 2022 17:55:31 +0600 Subject: [PATCH 1/9] Fixed app cache dir changes issue (#1158) ParsePlugins :: - `getCacheDir()`, `getFilesDir()` APIs now has support for backward compatibility before migration to v3.0.0 --- .../src/main/java/com/parse/ParsePlugins.java | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/parse/src/main/java/com/parse/ParsePlugins.java b/parse/src/main/java/com/parse/ParsePlugins.java index df8c1ebe6..c204673a1 100644 --- a/parse/src/main/java/com/parse/ParsePlugins.java +++ b/parse/src/main/java/com/parse/ParsePlugins.java @@ -178,7 +178,17 @@ InstallationId installationId() { File getCacheDir() { synchronized (lock) { if (cacheDir == null) { - cacheDir = new File(applicationContext.getCacheDir(), "com.parse"); + /* + Check for old reference file before migration to v3.0.0. + If old reference found, copy the ref to new directory and delete the ref. + */ + File oldRef = applicationContext.getDir("Parse", Context.MODE_PRIVATE); + if (oldRef.exists()) { + cacheDir = new File(oldRef, "com.parse"); + oldRef.deleteOnExit(); + } else { + cacheDir = new File(applicationContext.getCacheDir(), "com.parse"); + } } return createFileDir(cacheDir); } @@ -187,7 +197,17 @@ File getCacheDir() { File getFilesDir() { synchronized (lock) { if (filesDir == null) { - filesDir = new File(applicationContext.getFilesDir(), "com.parse"); + /* + Check for old reference file before migration to v3.0.0. + If old reference found, copy the ref to new directory and delete the ref. + */ + File oldRef = applicationContext.getDir("Parse", Context.MODE_PRIVATE); + if (oldRef.exists()) { + filesDir = new File(oldRef, "com.parse"); + oldRef.deleteOnExit(); + } else { + filesDir = new File(applicationContext.getFilesDir(), "com.parse"); + } } return createFileDir(filesDir); } From 1e44f6c307ad8d246fb4e5963acddd6b9cb7381a Mon Sep 17 00:00:00 2001 From: Romman Sabbir Date: Fri, 20 May 2022 15:40:30 +0600 Subject: [PATCH 2/9] ParseFileUtils :: - Introduced new static API `getAllNestedFiles(directoryName,files)` to return all files including sub-dirs. --- .../main/java/com/parse/ParseFileUtils.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/parse/src/main/java/com/parse/ParseFileUtils.java b/parse/src/main/java/com/parse/ParseFileUtils.java index 070baa111..50af66982 100644 --- a/parse/src/main/java/com/parse/ParseFileUtils.java +++ b/parse/src/main/java/com/parse/ParseFileUtils.java @@ -16,6 +16,7 @@ */ package com.parse; +import androidx.annotation.NonNull; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -25,6 +26,7 @@ import java.io.OutputStream; import java.nio.channels.FileChannel; import java.nio.charset.Charset; +import java.util.List; import org.json.JSONException; import org.json.JSONObject; @@ -347,6 +349,24 @@ private static void doCopyFile( } } + /** + * Get all files path from an given directory (including sub-directory). + * + * @param directoryName given directory name. + * @param files where all the files will be stored. + */ + public static void getAllNestedFiles(@NonNull String directoryName, @NonNull List files) { + File[] directoryItems = new File(directoryName).listFiles(); + if (directoryItems != null) + for (File item : directoryItems) { + if (item.isFile()) { + files.add(item); + } else if (item.isDirectory()) { + getAllNestedFiles(item.getAbsolutePath(), files); + } + } + } + // ----------------------------------------------------------------------- /** From a7c2a93283d0c2ee19402d86b791e2974d79810a Mon Sep 17 00:00:00 2001 From: Romman Sabbir Date: Fri, 20 May 2022 15:47:44 +0600 Subject: [PATCH 3/9] ParsePlugins :: - Introduced parse old (`app_Parse`) dir migration API `runSilentMigration()` - Added new APIs (Method Overloading) `getCacheDir(true)` and `getFilesDir(true)` to run silent migration before returning the File Object. --- .../src/main/java/com/parse/ParsePlugins.java | 272 +++++++++++++----- 1 file changed, 201 insertions(+), 71 deletions(-) diff --git a/parse/src/main/java/com/parse/ParsePlugins.java b/parse/src/main/java/com/parse/ParsePlugins.java index c204673a1..1d2974f00 100644 --- a/parse/src/main/java/com/parse/ParsePlugins.java +++ b/parse/src/main/java/com/parse/ParsePlugins.java @@ -10,12 +10,19 @@ import android.content.Context; import android.os.Build; +import android.util.Log; + import java.io.File; +import java.io.IOException; +import java.util.ArrayList; + import okhttp3.Headers; import okhttp3.OkHttpClient; import okhttp3.Request; -/** Public for LiveQuery. You probably don't need access */ +/** + * Public for LiveQuery. You probably don't need access + */ public class ParsePlugins { private static final String INSTALLATION_ID_LOCATION = "installationId"; @@ -111,50 +118,50 @@ ParseHttpClient restClient() { } // add it as the first interceptor clientBuilder - .interceptors() - .add( - 0, - chain -> { - Request request = chain.request(); - Headers.Builder headersBuilder = - request.headers() - .newBuilder() - .set( - ParseRESTCommand.HEADER_APPLICATION_ID, - configuration.applicationId) - .set( - ParseRESTCommand - .HEADER_APP_BUILD_VERSION, - String.valueOf( - ManifestInfo.getVersionCode())) - .set( - ParseRESTCommand - .HEADER_APP_DISPLAY_VERSION, - ManifestInfo.getVersionName()) - .set( - ParseRESTCommand.HEADER_OS_VERSION, - Build.VERSION.RELEASE) - .set(ParseRESTCommand.USER_AGENT, userAgent()); - if (request.header(ParseRESTCommand.HEADER_INSTALLATION_ID) - == null) { - // We can do this synchronously since the caller is already - // on a background thread - headersBuilder.set( - ParseRESTCommand.HEADER_INSTALLATION_ID, - installationId().get()); - } - // client key can be null with self-hosted Parse Server - if (configuration.clientKey != null) { - headersBuilder.set( - ParseRESTCommand.HEADER_CLIENT_KEY, - configuration.clientKey); - } - request = - request.newBuilder() - .headers(headersBuilder.build()) - .build(); - return chain.proceed(request); - }); + .interceptors() + .add( + 0, + chain -> { + Request request = chain.request(); + Headers.Builder headersBuilder = + request.headers() + .newBuilder() + .set( + ParseRESTCommand.HEADER_APPLICATION_ID, + configuration.applicationId) + .set( + ParseRESTCommand + .HEADER_APP_BUILD_VERSION, + String.valueOf( + ManifestInfo.getVersionCode())) + .set( + ParseRESTCommand + .HEADER_APP_DISPLAY_VERSION, + ManifestInfo.getVersionName()) + .set( + ParseRESTCommand.HEADER_OS_VERSION, + Build.VERSION.RELEASE) + .set(ParseRESTCommand.USER_AGENT, userAgent()); + if (request.header(ParseRESTCommand.HEADER_INSTALLATION_ID) + == null) { + // We can do this synchronously since the caller is already + // on a background thread + headersBuilder.set( + ParseRESTCommand.HEADER_INSTALLATION_ID, + installationId().get()); + } + // client key can be null with self-hosted Parse Server + if (configuration.clientKey != null) { + headersBuilder.set( + ParseRESTCommand.HEADER_CLIENT_KEY, + configuration.clientKey); + } + request = + request.newBuilder() + .headers(headersBuilder.build()) + .build(); + return chain.proceed(request); + }); restClient = ParseHttpClient.createClient(clientBuilder); } return restClient; @@ -169,7 +176,7 @@ InstallationId installationId() { synchronized (lock) { if (installationId == null) { installationId = - new InstallationId(new File(getFilesDir(), INSTALLATION_ID_LOCATION)); + new InstallationId(new File(getFilesDir(), INSTALLATION_ID_LOCATION)); } return installationId; } @@ -177,39 +184,162 @@ InstallationId installationId() { File getCacheDir() { synchronized (lock) { - if (cacheDir == null) { - /* - Check for old reference file before migration to v3.0.0. - If old reference found, copy the ref to new directory and delete the ref. - */ - File oldRef = applicationContext.getDir("Parse", Context.MODE_PRIVATE); - if (oldRef.exists()) { - cacheDir = new File(oldRef, "com.parse"); - oldRef.deleteOnExit(); - } else { - cacheDir = new File(applicationContext.getCacheDir(), "com.parse"); - } - } - return createFileDir(cacheDir); + return _getCacheDir(); } } File getFilesDir() { synchronized (lock) { - if (filesDir == null) { - /* - Check for old reference file before migration to v3.0.0. - If old reference found, copy the ref to new directory and delete the ref. - */ - File oldRef = applicationContext.getDir("Parse", Context.MODE_PRIVATE); - if (oldRef.exists()) { - filesDir = new File(oldRef, "com.parse"); - oldRef.deleteOnExit(); + return _getFilesDir(); + } + } + + private File _getFilesDir() { + if (filesDir == null) { + filesDir = new File(applicationContext.getFilesDir(), "com.parse"); + } + return createFileDir(filesDir); + } + + private File _getCacheDir() { + if (cacheDir == null) { + cacheDir = new File(applicationContext.getCacheDir(), "com.parse"); + } + return createFileDir(cacheDir); + } + + /*Migration [START]*/ + + /** + * Get cache, file object for Parse. + * + * @param useMigration to migrate old data to new locations before returning cache {@link File} object. + */ + File getCacheDir(Boolean useMigration) { + synchronized (lock) { + if (useMigration) { + runSilentMigration(); + } + return _getCacheDir(); + } + } + + /** + * Get files, file object for Parse. + * + * @param useMigration to migrate old data to new locations before returning cache {@link File} object. + */ + File getFilesDir(Boolean useMigration) { + synchronized (lock) { + if (useMigration) { + runSilentMigration(); + } + return _getFilesDir(); + } + } + + /** + * Start old data migrations to new respective locations ({@link #getFilesDir()}, {@link #getCacheDir()}). + */ + public void runSilentMigration() { + ArrayList filesToBeMigrated = new ArrayList<>(); + ParseFileUtils.getAllNestedFiles( + getOldParseDir().getAbsolutePath(), + filesToBeMigrated + ); + runParseDirFilesMigrationToCacheDir(filesToBeMigrated); + } + + public static String replaceLast(String text, String regex, String replacement) { + return text.replaceFirst("(?s)" + regex + "(?!.*?" + regex + ")", replacement); + } + + /** + * Since there is two new different APIs {@link #getFilesDir()}, {@link #getCacheDir()} for caching. + *

+ * - Config related files, that manages by SDK itself should be migrated to {@link #getFilesDir()}`. + *

+ * - Others files, that exists in the {@link #getOldParseDir()} should be migrated to {@link #getCacheDir()}. + *

+ * To identify the config files from {@link #getOldParseDir()}, + * we are using a hard coded list which defines the SDK config files names. + * + * @param allFiles Files that needed to be migrated into new location. + */ + private void runParseDirFilesMigrationToCacheDir(ArrayList allFiles) { + if (allFiles.isEmpty()) { + return; + } + boolean useFilesDir = false; + //Hard coded config file names list. + ArrayList configFilesToMigrateToFilesDir = new ArrayList<>(); + configFilesToMigrateToFilesDir.add("installationId"); + configFilesToMigrateToFilesDir.add("currentUser"); + configFilesToMigrateToFilesDir.add("currentConfig"); + configFilesToMigrateToFilesDir.add("currentInstallation"); + configFilesToMigrateToFilesDir.add("LocalId"); + configFilesToMigrateToFilesDir.add("pushState"); + //Start migration for each files in `allFiles`. + for (File itemToMove : allFiles) { + try { + for (String configName : configFilesToMigrateToFilesDir) { + if (itemToMove.getAbsolutePath().contains(configName)) { + useFilesDir = true; + break; + } else { + useFilesDir = false; + } + } + //Parse the old sub directory name where the file should be moved (new location) by following the old sub directory name. + String oldSubDir = replaceLast(itemToMove.getAbsolutePath().replace(getOldParseDir().getAbsolutePath(), "").replace("/" + itemToMove.getName(), ""), itemToMove.getName(), ""); + File fileToSave = new File( + (useFilesDir ? applicationContext.getFilesDir() : applicationContext.getCacheDir()) + + "/com.parse/" + + oldSubDir, + itemToMove.getName()); + //Perform copy operation if file doesn't exist in the new directory. + if (!fileToSave.exists()) { + ParseFileUtils.copyFile(itemToMove, fileToSave); } else { - filesDir = new File(applicationContext.getFilesDir(), "com.parse"); + Log.d("ParsePlugins", "runParseDirFilesMigrationToCacheDir: itemToMove (File) already exist in the location. So just deleting it."); } + ParseFileUtils.deleteQuietly(itemToMove); + } catch (Exception e) { + e.printStackTrace(); } - return createFileDir(filesDir); } + //Check again, if all files has been resolved or not. If yes, delete the old dir "app_Parse". + deleteOldDirAfterMigration(); } + + private void deleteOldDirAfterMigration() { + File oldFileRef = getOldParseDir(); + ArrayList allFiles = new ArrayList<>(); + ParseFileUtils.getAllNestedFiles(oldFileRef.getAbsolutePath(), allFiles); + if (allFiles.isEmpty()) { + try { + ParseFileUtils.deleteDirectory(oldFileRef); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + /* Deprecated API has been introduced newly for the migration purpose only. [START] */ + @Deprecated + File getOldParseDir() { + return applicationContext.getDir("Parse", Context.MODE_PRIVATE); + } + + @Deprecated + public void deleteOldParseDirSilently() { + try { + ParseFileUtils.deleteDirectory(getOldParseDir()); + } catch (IOException e) { + e.printStackTrace(); + } + } + /* Deprecated API has been introduced newly for the migration purpose only. [END] */ + + /*Migration [END]*/ } From 0dfad46756078d1128ee6ee8d428a16b2788b764 Mon Sep 17 00:00:00 2001 From: Romman Sabbir Date: Fri, 20 May 2022 15:54:34 +0600 Subject: [PATCH 4/9] ParseCacheDirMigrationTest :: - `@Test`: Manually run Parse Old Dir migrations process and check for migration result. - `@Test`: Auto migration before access Cache File (`*/cache/com.parse/*`) - `@Test`: Auto migration before accessing Files File (`*/files/com.parse/*`) - `@Test`: Auto migration by creating files conflicts between migration migrations item and latest item (File) before access Cache File (`*/cache/com.parse/*`) or Files File (`*/files/com.parse/*`) --- .../com/parse/ParseCacheDirMigrationTest.java | 167 ++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 parse/src/test/java/com/parse/ParseCacheDirMigrationTest.java diff --git a/parse/src/test/java/com/parse/ParseCacheDirMigrationTest.java b/parse/src/test/java/com/parse/ParseCacheDirMigrationTest.java new file mode 100644 index 000000000..dda4ff618 --- /dev/null +++ b/parse/src/test/java/com/parse/ParseCacheDirMigrationTest.java @@ -0,0 +1,167 @@ +package com.parse; + +import android.content.Context; +import androidx.test.platform.app.InstrumentationRegistry; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import java.io.File; +import java.util.ArrayList; + +@RunWith(RobolectricTestRunner.class) +public class ParseCacheDirMigrationTest { + ArrayList writtenFiles = new ArrayList<>(); + + @Before + public void setUp() throws Exception { + Context context = InstrumentationRegistry.getInstrumentation().getContext(); + ParsePlugins.reset(); + Parse.Configuration configuration = + new Parse.Configuration.Builder(context).applicationId("1234").build(); + ParsePlugins.initialize(context, configuration); + writtenFiles.clear(); + } + + @After + public void tearDown() throws Exception { + ParsePlugins.reset(); + writtenFiles.clear(); + } + + @Test + public void manualMigrationBeforeAccessNewCacheAPIs() { + prepareForMockFilesWriting(); + writtenFiles.addAll(writeSomeMockFiles(false)); + + //Run migration manually. + ParsePlugins.get().runSilentMigration(); + + //Check for cache file after migration. + File cacheDir = ParsePlugins.get().getCacheDir(); + ArrayList migratedCaches = new ArrayList<>(); + ParseFileUtils.getAllNestedFiles(cacheDir.getAbsolutePath(), migratedCaches); + + //Check for files file after migration. + File filesDir = ParsePlugins.get().getFilesDir(); + ArrayList migratedFiles = new ArrayList<>(); + ParseFileUtils.getAllNestedFiles(filesDir.getAbsolutePath(), migratedFiles); + + //To check migrations result + int sizeAfterMigration = (migratedCaches.size() + migratedFiles.size()); + int sizeBeforeMigrations = writtenFiles.size(); + + assert (cacheDir.exists() && !migratedCaches.isEmpty()); + assert (filesDir.exists() && !migratedFiles.isEmpty()); + assert sizeBeforeMigrations == sizeAfterMigration; + } + + @Test + public void autoMigrationBeforeAccessFilesDir() { + prepareForMockFilesWriting(); + writtenFiles.addAll(writeSomeMockFiles(false)); + ArrayList migratedFiles = new ArrayList<>(); + //Auto migration + File filesDir = ParsePlugins.get().getFilesDir(true); + ParseFileUtils.getAllNestedFiles(filesDir.getAbsolutePath(), migratedFiles); + assert !migratedFiles.isEmpty(); + } + + @Test + public void autoMigrationBeforeAccessCacheDir() { + prepareForMockFilesWriting(); + writtenFiles.addAll(writeSomeMockFiles(false)); + ArrayList migratedCaches = new ArrayList<>(); + //Auto migration + File cacheDir = ParsePlugins.get().getCacheDir(true); + ParseFileUtils.getAllNestedFiles(cacheDir.getAbsolutePath(), migratedCaches); + assert !migratedCaches.isEmpty(); + } + + @Test + public void autoMigrationBeforeAccessCacheOrFilesDirBySolvingFileConflicts() { + prepareForMockFilesWriting(); + //Set some existing files in new location so that there could be file conflict. + writtenFiles.addAll(writeSomeMockFiles(true)); + + //Auto migration for files + ArrayList migratedFiles = new ArrayList<>(); + File filesDir = ParsePlugins.get().getFilesDir(true); + ParseFileUtils.getAllNestedFiles(filesDir.getAbsolutePath(), migratedFiles); + + /* + Auto migration for caches. + Although migration already completed when accessed `ParsePlugins.get().getFilesDir(true)` or `ParsePlugins.get().getCacheDir(true)` API. + */ + ArrayList migratedCaches = new ArrayList<>(); + File cacheDir = ParsePlugins.get().getCacheDir(true); + ParseFileUtils.getAllNestedFiles(cacheDir.getAbsolutePath(), migratedCaches); + + assert !migratedFiles.isEmpty(); + assert !migratedCaches.isEmpty(); + } + + private void prepareForMockFilesWriting() { + //Delete `"app_Parse"` dir including nested dir and files. + ParsePlugins.get().deleteOldParseDirSilently(); + writtenFiles.clear(); + //Create new `"app_Parse"` dir to write some files. + createFileDir(ParsePlugins.get().getCacheDir()); + } + + private ArrayList writeSomeMockFiles(Boolean checkForExistingFile) { + ArrayList fileToReturn = new ArrayList<>(); + File oldRef = ParsePlugins.get().getOldParseDir(); + + //Writing some config & random files for migration process. + File config = new File(oldRef + "/config/", "config"); + fileToReturn.add(config); + File installationId = new File(oldRef + "/CommandCache/", "installationId"); + fileToReturn.add(installationId); + File currentConfig = new File(oldRef + "/", "currentConfig"); + fileToReturn.add(currentConfig); + File currentInstallation = new File(oldRef + "/", "currentInstallation"); + fileToReturn.add(currentInstallation); + File pushState = new File(oldRef + "/push/", "pushState"); + fileToReturn.add(pushState); + File localId = new File(oldRef + "/LocalId/", "LocalId"); + fileToReturn.add(localId); + File cache = new File(oldRef + "/testcache/", "cache"); + fileToReturn.add(cache); + File cache1 = new File(oldRef + "/testcache/", "cache1"); + fileToReturn.add(cache1); + File cache2 = new File(oldRef + "/testcache/another/", "cache4"); + fileToReturn.add(cache2); + File user = new File(oldRef + "/user/", "user_config"); + fileToReturn.add(user); + + //Write all listed files to the app cache ("app_Parse") directory. + for (File item : fileToReturn) { + try { + ParseFileUtils.writeStringToFile(item, "gger", "UTF-8"); + } catch (Exception e) { + e.printStackTrace(); + } + } + //To create a file conflict scenario during migration by creating an existing file to the new files dir ("*/files/com.parse/*"). + if (checkForExistingFile) { + try { + ParseFileUtils.writeStringToFile(new File(ParsePlugins.get().getFilesDir() + "/CommandCache/", "installationId"), "gger", "UTF-8"); + } catch (Exception e) { + e.printStackTrace(); + } + } + return fileToReturn; + } + + private File createFileDir(File file) { + if (!file.exists()) { + if (!file.mkdirs()) { + return file; + } + } + return file; + } + +} From 78ecd666f20a913ca772cafebd4291f1a4979ab5 Mon Sep 17 00:00:00 2001 From: Romman Sabbir Date: Fri, 20 May 2022 16:14:26 +0600 Subject: [PATCH 5/9] ParseFileUtilsTest :: - `@Test`: To get all files from a given path using `ParseFileUtils.getAllNestedFiles(path, files)` API. --- .../java/com/parse/ParseFileUtilsTest.java | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/parse/src/test/java/com/parse/ParseFileUtilsTest.java b/parse/src/test/java/com/parse/ParseFileUtilsTest.java index 4a1465dae..fe72d2e7a 100644 --- a/parse/src/test/java/com/parse/ParseFileUtilsTest.java +++ b/parse/src/test/java/com/parse/ParseFileUtilsTest.java @@ -17,6 +17,8 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; +import java.util.ArrayList; + import org.json.JSONObject; import org.junit.Rule; import org.junit.Test; @@ -101,4 +103,38 @@ public void testWriteJSONObjectToFile() throws Exception { assertNotNull(json); assertEquals("bar", json.getString("foo")); } + + @Test + public void testGetAllFilesFromAGivenPath(){ + ArrayList filesListToSave = new ArrayList<>(); + File oldRef = new File(temporaryFolder.getRoot()+"/ParseFileUtilsTest/"); + + //Writing some files to the `*/ParseFileUtilsTest/*` dir. + File config = new File(oldRef + "/config/", "config"); + filesListToSave.add(config); + File installationId = new File(oldRef + "/CommandCache/", "installationId"); + filesListToSave.add(installationId); + File currentConfig = new File(oldRef + "/", "currentConfig"); + filesListToSave.add(currentConfig); + File currentInstallation = new File(oldRef + "/", "currentInstallation"); + filesListToSave.add(currentInstallation); + File pushState = new File(oldRef + "/push/", "pushState"); + filesListToSave.add(pushState); + + //Write all listed files to the temp (oldRef) directory. + for (File item : filesListToSave) { + try { + ParseFileUtils.writeStringToFile(item, "gger", "UTF-8"); + } catch (Exception e) { + e.printStackTrace(); + } + } + + //Get all the written files under `*/ParseFileUtilsTest/*`. + ArrayList allWrittenFiles = new ArrayList<>(); + ParseFileUtils.getAllNestedFiles(oldRef.getAbsolutePath(), allWrittenFiles); + + //Check if they both matches or not. + assertEquals(filesListToSave.size(), allWrittenFiles.size()); + } } From a4c11c97126d85b3cce7299d95aa2eede6bfcb85 Mon Sep 17 00:00:00 2001 From: Romman Sabbir Date: Sat, 21 May 2022 13:51:37 +0600 Subject: [PATCH 6/9] ParsePlugins:: - Revert to old code (3.x) --- .../src/main/java/com/parse/ParsePlugins.java | 166 +----------------- 1 file changed, 8 insertions(+), 158 deletions(-) diff --git a/parse/src/main/java/com/parse/ParsePlugins.java b/parse/src/main/java/com/parse/ParsePlugins.java index 1d2974f00..27d73f63f 100644 --- a/parse/src/main/java/com/parse/ParsePlugins.java +++ b/parse/src/main/java/com/parse/ParsePlugins.java @@ -10,19 +10,12 @@ import android.content.Context; import android.os.Build; -import android.util.Log; - import java.io.File; -import java.io.IOException; -import java.util.ArrayList; - import okhttp3.Headers; import okhttp3.OkHttpClient; import okhttp3.Request; -/** - * Public for LiveQuery. You probably don't need access - */ +/** Public for LiveQuery. You probably don't need access */ public class ParsePlugins { private static final String INSTALLATION_ID_LOCATION = "installationId"; @@ -184,162 +177,19 @@ InstallationId installationId() { File getCacheDir() { synchronized (lock) { - return _getCacheDir(); - } - } - - File getFilesDir() { - synchronized (lock) { - return _getFilesDir(); - } - } - - private File _getFilesDir() { - if (filesDir == null) { - filesDir = new File(applicationContext.getFilesDir(), "com.parse"); - } - return createFileDir(filesDir); - } - - private File _getCacheDir() { - if (cacheDir == null) { - cacheDir = new File(applicationContext.getCacheDir(), "com.parse"); - } - return createFileDir(cacheDir); - } - - /*Migration [START]*/ - - /** - * Get cache, file object for Parse. - * - * @param useMigration to migrate old data to new locations before returning cache {@link File} object. - */ - File getCacheDir(Boolean useMigration) { - synchronized (lock) { - if (useMigration) { - runSilentMigration(); + if (cacheDir == null) { + cacheDir = new File(applicationContext.getCacheDir(), "com.parse"); } - return _getCacheDir(); + return createFileDir(cacheDir); } } - /** - * Get files, file object for Parse. - * - * @param useMigration to migrate old data to new locations before returning cache {@link File} object. - */ - File getFilesDir(Boolean useMigration) { + File getFilesDir() { synchronized (lock) { - if (useMigration) { - runSilentMigration(); + if (filesDir == null) { + filesDir = new File(applicationContext.getFilesDir(), "com.parse"); } - return _getFilesDir(); + return createFileDir(filesDir); } } - - /** - * Start old data migrations to new respective locations ({@link #getFilesDir()}, {@link #getCacheDir()}). - */ - public void runSilentMigration() { - ArrayList filesToBeMigrated = new ArrayList<>(); - ParseFileUtils.getAllNestedFiles( - getOldParseDir().getAbsolutePath(), - filesToBeMigrated - ); - runParseDirFilesMigrationToCacheDir(filesToBeMigrated); - } - - public static String replaceLast(String text, String regex, String replacement) { - return text.replaceFirst("(?s)" + regex + "(?!.*?" + regex + ")", replacement); - } - - /** - * Since there is two new different APIs {@link #getFilesDir()}, {@link #getCacheDir()} for caching. - *

- * - Config related files, that manages by SDK itself should be migrated to {@link #getFilesDir()}`. - *

- * - Others files, that exists in the {@link #getOldParseDir()} should be migrated to {@link #getCacheDir()}. - *

- * To identify the config files from {@link #getOldParseDir()}, - * we are using a hard coded list which defines the SDK config files names. - * - * @param allFiles Files that needed to be migrated into new location. - */ - private void runParseDirFilesMigrationToCacheDir(ArrayList allFiles) { - if (allFiles.isEmpty()) { - return; - } - boolean useFilesDir = false; - //Hard coded config file names list. - ArrayList configFilesToMigrateToFilesDir = new ArrayList<>(); - configFilesToMigrateToFilesDir.add("installationId"); - configFilesToMigrateToFilesDir.add("currentUser"); - configFilesToMigrateToFilesDir.add("currentConfig"); - configFilesToMigrateToFilesDir.add("currentInstallation"); - configFilesToMigrateToFilesDir.add("LocalId"); - configFilesToMigrateToFilesDir.add("pushState"); - //Start migration for each files in `allFiles`. - for (File itemToMove : allFiles) { - try { - for (String configName : configFilesToMigrateToFilesDir) { - if (itemToMove.getAbsolutePath().contains(configName)) { - useFilesDir = true; - break; - } else { - useFilesDir = false; - } - } - //Parse the old sub directory name where the file should be moved (new location) by following the old sub directory name. - String oldSubDir = replaceLast(itemToMove.getAbsolutePath().replace(getOldParseDir().getAbsolutePath(), "").replace("/" + itemToMove.getName(), ""), itemToMove.getName(), ""); - File fileToSave = new File( - (useFilesDir ? applicationContext.getFilesDir() : applicationContext.getCacheDir()) - + "/com.parse/" + - oldSubDir, - itemToMove.getName()); - //Perform copy operation if file doesn't exist in the new directory. - if (!fileToSave.exists()) { - ParseFileUtils.copyFile(itemToMove, fileToSave); - } else { - Log.d("ParsePlugins", "runParseDirFilesMigrationToCacheDir: itemToMove (File) already exist in the location. So just deleting it."); - } - ParseFileUtils.deleteQuietly(itemToMove); - } catch (Exception e) { - e.printStackTrace(); - } - } - //Check again, if all files has been resolved or not. If yes, delete the old dir "app_Parse". - deleteOldDirAfterMigration(); - } - - private void deleteOldDirAfterMigration() { - File oldFileRef = getOldParseDir(); - ArrayList allFiles = new ArrayList<>(); - ParseFileUtils.getAllNestedFiles(oldFileRef.getAbsolutePath(), allFiles); - if (allFiles.isEmpty()) { - try { - ParseFileUtils.deleteDirectory(oldFileRef); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - - /* Deprecated API has been introduced newly for the migration purpose only. [START] */ - @Deprecated - File getOldParseDir() { - return applicationContext.getDir("Parse", Context.MODE_PRIVATE); - } - - @Deprecated - public void deleteOldParseDirSilently() { - try { - ParseFileUtils.deleteDirectory(getOldParseDir()); - } catch (IOException e) { - e.printStackTrace(); - } - } - /* Deprecated API has been introduced newly for the migration purpose only. [END] */ - - /*Migration [END]*/ } From 4d3640bee3a7619134cbe80102e1faf921069a28 Mon Sep 17 00:00:00 2001 From: Romman Sabbir Date: Sat, 21 May 2022 13:58:18 +0600 Subject: [PATCH 7/9] ParseCacheDirMigrationUtils:: - To perform Parse SDK Cache Dir migration operation. ParseCacheDirMigrationUtilsTest:: - Added test to check migration manually without SDK initialization - Added test to run migration routine only once on SDK initialization --- .../parse/ParseCacheDirMigrationUtils.java | 106 ++++++++++++++++++ ...a => ParseCacheDirMigrationUtilsTest.java} | 95 ++++++---------- 2 files changed, 139 insertions(+), 62 deletions(-) create mode 100644 parse/src/main/java/com/parse/ParseCacheDirMigrationUtils.java rename parse/src/test/java/com/parse/{ParseCacheDirMigrationTest.java => ParseCacheDirMigrationUtilsTest.java} (58%) diff --git a/parse/src/main/java/com/parse/ParseCacheDirMigrationUtils.java b/parse/src/main/java/com/parse/ParseCacheDirMigrationUtils.java new file mode 100644 index 000000000..ad002d834 --- /dev/null +++ b/parse/src/main/java/com/parse/ParseCacheDirMigrationUtils.java @@ -0,0 +1,106 @@ +package com.parse; + +import android.content.Context; + +import java.io.File; +import java.util.ArrayList; + +/** + * The {@code ParseMigrationUtils} class perform caching dir migration operation for {@code Parse} SDK. + */ +public class ParseCacheDirMigrationUtils { + private final String TAG = this.getClass().getName(); + private final Object lock = new Object(); + private final Context context; + + protected ParseCacheDirMigrationUtils(Context context) { + this.context = context; + } + + /*Start old data migrations to new respective locations ("/files/com.parse/", "/cache/com.parse/")*/ + protected void runMigrations() { + synchronized (lock) { + runSilentMigration(context); + } + } + + private void runSilentMigration(Context context) { + ArrayList filesToBeMigrated = new ArrayList<>(); + ParseFileUtils.getAllNestedFiles( + getOldParseDir(context).getAbsolutePath(), + filesToBeMigrated + ); + if (filesToBeMigrated.isEmpty()) { + return; + } + boolean useFilesDir = false; + //Hard coded config file names list. + String[] configNamesList = {"installationId", "currentUser", "currentConfig", "currentInstallation", "LocalId", "pushState"}; + //Start migration for each files in `allFiles`. + for (File itemToMove : filesToBeMigrated) { + try { + for (String configName : configNamesList) { + if (itemToMove.getAbsolutePath().contains(configName)) { + useFilesDir = true; + break; + } else { + useFilesDir = false; + } + } + File fileToSave = new File( + (useFilesDir ? context.getFilesDir() : context.getCacheDir()) + + "/com.parse/" + + getFileOldDir(context, itemToMove), + itemToMove.getName()); + //Perform copy operation if file doesn't exist in the new directory. + if (!fileToSave.exists()) { + ParseFileUtils.copyFile(itemToMove, fileToSave); + logMigrationStatus(itemToMove.getName(), itemToMove.getPath(), fileToSave.getAbsolutePath(), "Successful."); + } else { + logMigrationStatus(itemToMove.getName(), itemToMove.getPath(), fileToSave.getAbsolutePath(), "Already exist in new location."); + } + ParseFileUtils.deleteQuietly(itemToMove); + PLog.v(TAG, "File deleted: " + "{" + itemToMove.getName() + "}" + " successfully"); + } catch (Exception e) { + e.printStackTrace(); + } + } + //Check again, if all files has been resolved or not. If yes, delete the old dir "app_Parse". + filesToBeMigrated.clear(); + ParseFileUtils.getAllNestedFiles(getOldParseDir(context).getAbsolutePath(), filesToBeMigrated); + if (filesToBeMigrated.isEmpty()) { + try { + ParseFileUtils.deleteDirectory(getOldParseDir(context)); + } catch (Exception e) { + e.printStackTrace(); + } + } + PLog.v(TAG, "Migration completed."); + } + + private String getFileOldDir(Context context, File file) { + //Parse the old sub directory name where the file should be moved (new location) by following the old sub directory name. + String temp = file + .getAbsolutePath() + .replace( + getOldParseDir(context).getAbsolutePath(), "") + .replace("/" + file.getName(), ""); + //Before returning the path, replace file name from the last, eg. dir name & file name could be same, as we want to get only dir name. + return replaceLast(temp, file.getName()); + } + + private void logMigrationStatus(String fileName, String oldPath, String newPath, String status) { + PLog.v(TAG, "Migration for file: " + "{" + fileName + "}" + " from {" + oldPath + "} to {" + newPath + "}, Status: " + status); + } + + /*Replace a given string from the last*/ + private String replaceLast(String text, String regex) { + return text.replaceFirst("(?s)" + regex + "(?!.*?" + regex + ")", ""); + } + + private File getOldParseDir(Context context) { + return context.getDir("Parse", Context.MODE_PRIVATE); + } + + +} diff --git a/parse/src/test/java/com/parse/ParseCacheDirMigrationTest.java b/parse/src/test/java/com/parse/ParseCacheDirMigrationUtilsTest.java similarity index 58% rename from parse/src/test/java/com/parse/ParseCacheDirMigrationTest.java rename to parse/src/test/java/com/parse/ParseCacheDirMigrationUtilsTest.java index dda4ff618..1eb8dabec 100644 --- a/parse/src/test/java/com/parse/ParseCacheDirMigrationTest.java +++ b/parse/src/test/java/com/parse/ParseCacheDirMigrationUtilsTest.java @@ -1,50 +1,62 @@ package com.parse; import android.content.Context; + import androidx.test.platform.app.InstrumentationRegistry; + import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; + import java.io.File; import java.util.ArrayList; @RunWith(RobolectricTestRunner.class) -public class ParseCacheDirMigrationTest { +public class ParseCacheDirMigrationUtilsTest { ArrayList writtenFiles = new ArrayList<>(); + private ParseCacheDirMigrationUtils utils; @Before public void setUp() throws Exception { - Context context = InstrumentationRegistry.getInstrumentation().getContext(); - ParsePlugins.reset(); - Parse.Configuration configuration = - new Parse.Configuration.Builder(context).applicationId("1234").build(); - ParsePlugins.initialize(context, configuration); + utils = new ParseCacheDirMigrationUtils(InstrumentationRegistry.getInstrumentation().getContext()); writtenFiles.clear(); } @After public void tearDown() throws Exception { - ParsePlugins.reset(); writtenFiles.clear(); } @Test - public void manualMigrationBeforeAccessNewCacheAPIs() { + public void testMigrationOnParseSDKInitialization() { + prepareForMockFilesWriting(); + writtenFiles.addAll(writeSomeMockFiles(true)); + Parse.Configuration configuration = + new Parse.Configuration.Builder(InstrumentationRegistry.getInstrumentation().getContext()) + .applicationId(BuildConfig.LIBRARY_PACKAGE_NAME) + .server("https://api.parse.com/1") + .enableLocalDataStore() + .build(); + Parse.initialize(configuration); + } + + @Test + public void testMockMigration() { prepareForMockFilesWriting(); - writtenFiles.addAll(writeSomeMockFiles(false)); + writtenFiles.addAll(writeSomeMockFiles(true)); - //Run migration manually. - ParsePlugins.get().runSilentMigration(); + //Run migration. + utils.runMigrations(); //Check for cache file after migration. - File cacheDir = ParsePlugins.get().getCacheDir(); + File cacheDir = InstrumentationRegistry.getInstrumentation().getContext().getCacheDir(); ArrayList migratedCaches = new ArrayList<>(); ParseFileUtils.getAllNestedFiles(cacheDir.getAbsolutePath(), migratedCaches); //Check for files file after migration. - File filesDir = ParsePlugins.get().getFilesDir(); + File filesDir = InstrumentationRegistry.getInstrumentation().getContext().getFilesDir(); ArrayList migratedFiles = new ArrayList<>(); ParseFileUtils.getAllNestedFiles(filesDir.getAbsolutePath(), migratedFiles); @@ -57,62 +69,21 @@ public void manualMigrationBeforeAccessNewCacheAPIs() { assert sizeBeforeMigrations == sizeAfterMigration; } - @Test - public void autoMigrationBeforeAccessFilesDir() { - prepareForMockFilesWriting(); - writtenFiles.addAll(writeSomeMockFiles(false)); - ArrayList migratedFiles = new ArrayList<>(); - //Auto migration - File filesDir = ParsePlugins.get().getFilesDir(true); - ParseFileUtils.getAllNestedFiles(filesDir.getAbsolutePath(), migratedFiles); - assert !migratedFiles.isEmpty(); - } - - @Test - public void autoMigrationBeforeAccessCacheDir() { - prepareForMockFilesWriting(); - writtenFiles.addAll(writeSomeMockFiles(false)); - ArrayList migratedCaches = new ArrayList<>(); - //Auto migration - File cacheDir = ParsePlugins.get().getCacheDir(true); - ParseFileUtils.getAllNestedFiles(cacheDir.getAbsolutePath(), migratedCaches); - assert !migratedCaches.isEmpty(); - } - - @Test - public void autoMigrationBeforeAccessCacheOrFilesDirBySolvingFileConflicts() { - prepareForMockFilesWriting(); - //Set some existing files in new location so that there could be file conflict. - writtenFiles.addAll(writeSomeMockFiles(true)); - - //Auto migration for files - ArrayList migratedFiles = new ArrayList<>(); - File filesDir = ParsePlugins.get().getFilesDir(true); - ParseFileUtils.getAllNestedFiles(filesDir.getAbsolutePath(), migratedFiles); - - /* - Auto migration for caches. - Although migration already completed when accessed `ParsePlugins.get().getFilesDir(true)` or `ParsePlugins.get().getCacheDir(true)` API. - */ - ArrayList migratedCaches = new ArrayList<>(); - File cacheDir = ParsePlugins.get().getCacheDir(true); - ParseFileUtils.getAllNestedFiles(cacheDir.getAbsolutePath(), migratedCaches); - - assert !migratedFiles.isEmpty(); - assert !migratedCaches.isEmpty(); - } - private void prepareForMockFilesWriting() { //Delete `"app_Parse"` dir including nested dir and files. - ParsePlugins.get().deleteOldParseDirSilently(); + try { + ParseFileUtils.deleteDirectory(InstrumentationRegistry.getInstrumentation().getContext().getDir("Parse", Context.MODE_PRIVATE)); + } catch (Exception e) { + e.printStackTrace(); + } writtenFiles.clear(); //Create new `"app_Parse"` dir to write some files. - createFileDir(ParsePlugins.get().getCacheDir()); + createFileDir(InstrumentationRegistry.getInstrumentation().getContext().getCacheDir()); } private ArrayList writeSomeMockFiles(Boolean checkForExistingFile) { ArrayList fileToReturn = new ArrayList<>(); - File oldRef = ParsePlugins.get().getOldParseDir(); + File oldRef = InstrumentationRegistry.getInstrumentation().getContext().getDir("Parse", Context.MODE_PRIVATE); //Writing some config & random files for migration process. File config = new File(oldRef + "/config/", "config"); @@ -147,7 +118,7 @@ private ArrayList writeSomeMockFiles(Boolean checkForExistingFile) { //To create a file conflict scenario during migration by creating an existing file to the new files dir ("*/files/com.parse/*"). if (checkForExistingFile) { try { - ParseFileUtils.writeStringToFile(new File(ParsePlugins.get().getFilesDir() + "/CommandCache/", "installationId"), "gger", "UTF-8"); + ParseFileUtils.writeStringToFile(new File(InstrumentationRegistry.getInstrumentation().getContext().getFilesDir() + "/com.parse/CommandCache/", "installationId"), "gger", "UTF-8"); } catch (Exception e) { e.printStackTrace(); } From a03b49e50444f9e582f358db1e85c048aa1c578e Mon Sep 17 00:00:00 2001 From: Romman Sabbir Date: Sat, 21 May 2022 14:01:05 +0600 Subject: [PATCH 8/9] fix: parse cache dir migration routine on SDK initialization (only once) (#1168) --- parse/src/main/java/com/parse/Parse.java | 127 +++++++++++++---------- 1 file changed, 74 insertions(+), 53 deletions(-) diff --git a/parse/src/main/java/com/parse/Parse.java b/parse/src/main/java/com/parse/Parse.java index 39cdc2545..fff046b5f 100644 --- a/parse/src/main/java/com/parse/Parse.java +++ b/parse/src/main/java/com/parse/Parse.java @@ -12,10 +12,13 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.util.Log; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; + import com.parse.boltsinternal.Continuation; import com.parse.boltsinternal.Task; + import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -26,6 +29,7 @@ import java.util.List; import java.util.Set; import java.util.concurrent.Callable; + import okhttp3.OkHttpClient; /** @@ -75,7 +79,7 @@ private Parse() { * } * } * - * + *

* See https://github.com/parse-community/Parse-SDK-Android/issues/279 * for a discussion on performance of local datastore, and if it is right for your project. @@ -85,8 +89,8 @@ private Parse() { public static void enableLocalDatastore(Context context) { if (isInitialized()) { throw new IllegalStateException( - "`Parse#enableLocalDatastore(Context)` must be invoked " - + "before `Parse#initialize(Context)`"); + "`Parse#enableLocalDatastore(Context)` must be invoked " + + "before `Parse#initialize(Context)`"); } isLocalDatastoreEnabled = true; } @@ -113,7 +117,7 @@ public static boolean isLocalDatastoreEnabled() { /** * @return {@code True} if {@link Configuration.Builder#allowCustomObjectId()} has been called, - * otherwise {@code false}. + * otherwise {@code false}. */ public static boolean isAllowCustomObjectId() { return allowCustomObjectId; @@ -145,6 +149,9 @@ static void initialize(Configuration configuration, ParsePlugins parsePlugins) { PLog.w(TAG, "Parse is already initialized"); return; } + // Perform old dir migration on initialize. + new ParseCacheDirMigrationUtils(configuration.context).runMigrations(); + // NOTE (richardross): We will need this here, as ParsePlugins uses the return value of // isLocalDataStoreEnabled() to perform additional behavior. isLocalDatastoreEnabled = configuration.localDataStoreEnabled; @@ -176,32 +183,32 @@ static void initialize(Configuration configuration, ParsePlugins parsePlugins) { checkCacheApplicationId(); final Context context = configuration.context; Task.callInBackground( - (Callable) - () -> { - getEventuallyQueue(context); - return null; - }); + (Callable) + () -> { + getEventuallyQueue(context); + return null; + }); ParseFieldOperations.registerDefaultDecoders(); if (!allParsePushIntentReceiversInternal()) { throw new SecurityException( - "To prevent external tampering to your app's notifications, " - + "all receivers registered to handle the following actions must have " - + "their exported attributes set to false: com.parse.push.intent.RECEIVE, " - + "com.parse.push.intent.OPEN, com.parse.push.intent.DELETE"); + "To prevent external tampering to your app's notifications, " + + "all receivers registered to handle the following actions must have " + + "their exported attributes set to false: com.parse.push.intent.RECEIVE, " + + "com.parse.push.intent.OPEN, com.parse.push.intent.DELETE"); } ParseUser.getCurrentUserAsync() - .makeVoid() - .continueWith( - (Continuation) - task -> { - // Prime config in the background - ParseConfig.getCurrentConfig(); - return null; - }, - Task.BACKGROUND_EXECUTOR); + .makeVoid() + .continueWith( + (Continuation) + task -> { + // Prime config in the background + ParseConfig.getCurrentConfig(); + return null; + }, + Task.BACKGROUND_EXECUTOR); dispatchOnParseInitialized(); @@ -213,8 +220,11 @@ static void initialize(Configuration configuration, ParsePlugins parsePlugins) { // region Server URL - /** Returns the current server URL. */ - public static @Nullable String getServer() { + /** + * Returns the current server URL. + */ + public static @Nullable + String getServer() { URL server = ParseRESTCommand.server; return server == null ? null : server.toString(); } @@ -248,7 +258,8 @@ public static void setServer(@NonNull String server) { * @param server The server URL to validate. * @return The validated server URL. */ - private static @Nullable String validateServerUrl(@Nullable String server) { + private static @Nullable + String validateServerUrl(@Nullable String server) { // Add an extra trailing slash so that Parse REST commands include // the path as part of the server URL (i.e. http://api.myhost.com/parse) @@ -285,7 +296,9 @@ public static void destroy() { allowCustomObjectId = false; } - /** @return {@code True} if {@link #initialize} has been called, otherwise {@code false}. */ + /** + * @return {@code True} if {@link #initialize} has been called, otherwise {@code false}. + */ static boolean isInitialized() { return ParsePlugins.get() != null; } @@ -308,10 +321,10 @@ public static Context getApplicationContext() { */ private static boolean allParsePushIntentReceiversInternal() { List intentReceivers = - ManifestInfo.getIntentReceivers( - ParsePushBroadcastReceiver.ACTION_PUSH_RECEIVE, - ParsePushBroadcastReceiver.ACTION_PUSH_DELETE, - ParsePushBroadcastReceiver.ACTION_PUSH_OPEN); + ManifestInfo.getIntentReceivers( + ParsePushBroadcastReceiver.ACTION_PUSH_RECEIVE, + ParsePushBroadcastReceiver.ACTION_PUSH_DELETE, + ParsePushBroadcastReceiver.ACTION_PUSH_OPEN); for (ResolveInfo resolveInfo : intentReceivers) { if (resolveInfo.activityInfo.exported) { @@ -414,15 +427,15 @@ private static ParseEventuallyQueue getEventuallyQueue(Context context) { synchronized (MUTEX) { boolean isLocalDatastoreEnabled = Parse.isLocalDatastoreEnabled(); if (eventuallyQueue == null - || (isLocalDatastoreEnabled && eventuallyQueue instanceof ParseCommandCache) - || (!isLocalDatastoreEnabled - && eventuallyQueue instanceof ParsePinningEventuallyQueue)) { + || (isLocalDatastoreEnabled && eventuallyQueue instanceof ParseCommandCache) + || (!isLocalDatastoreEnabled + && eventuallyQueue instanceof ParsePinningEventuallyQueue)) { checkContext(); ParseHttpClient httpClient = ParsePlugins.get().restClient(); eventuallyQueue = - isLocalDatastoreEnabled - ? new ParsePinningEventuallyQueue(context, httpClient) - : new ParseCommandCache(context, httpClient); + isLocalDatastoreEnabled + ? new ParsePinningEventuallyQueue(context, httpClient) + : new ParseCommandCache(context, httpClient); // We still need to clear out the old command cache even if we're using Pinning in // case @@ -436,33 +449,35 @@ private static ParseEventuallyQueue getEventuallyQueue(Context context) { } } - /** Used by Parse LiveQuery */ + /** + * Used by Parse LiveQuery + */ public static void checkInit() { if (ParsePlugins.get() == null) { throw new RuntimeException( - "You must call Parse.initialize(Context)" + " before using the Parse library."); + "You must call Parse.initialize(Context)" + " before using the Parse library."); } if (ParsePlugins.get().applicationId() == null) { throw new RuntimeException( - "applicationId is null. " - + "You must call Parse.initialize(Context)" - + " before using the Parse library."); + "applicationId is null. " + + "You must call Parse.initialize(Context)" + + " before using the Parse library."); } } static void checkContext() { if (ParsePlugins.get().applicationContext() == null) { throw new RuntimeException( - "applicationContext is null. " - + "You must call Parse.initialize(Context)" - + " before using the Parse library."); + "applicationContext is null. " + + "You must call Parse.initialize(Context)" + + " before using the Parse library."); } } static boolean hasPermission(String permission) { return (getApplicationContext().checkCallingOrSelfPermission(permission) - == PackageManager.PERMISSION_GRANTED); + == PackageManager.PERMISSION_GRANTED); } // endregion @@ -472,10 +487,10 @@ static boolean hasPermission(String permission) { static void requirePermission(String permission) { if (!hasPermission(permission)) { throw new IllegalStateException( - "To use this functionality, add this to your AndroidManifest.xml:\n" - + ""); + "To use this functionality, add this to your AndroidManifest.xml:\n" + + ""); } } @@ -489,7 +504,7 @@ static void requirePermission(String permission) { static void registerParseCallbacks(ParseCallbacks listener) { if (isInitialized()) { throw new IllegalStateException( - "You must register callbacks before Parse.initialize(Context)"); + "You must register callbacks before Parse.initialize(Context)"); } synchronized (MUTEX_CALLBACKS) { @@ -537,7 +552,9 @@ private static ParseCallbacks[] collectParseCallbacks() { return callbacks; } - /** Returns the level of logging that will be displayed. */ + /** + * Returns the level of logging that will be displayed. + */ public static int getLogLevel() { return PLog.getLogLevel(); } @@ -569,7 +586,9 @@ interface ParseCallbacks { void onParseInitialized(); } - /** Represents an opaque configuration for the {@code Parse} SDK configuration. */ + /** + * Represents an opaque configuration for the {@code Parse} SDK configuration. + */ public static final class Configuration { final Context context; final String applicationId; @@ -591,7 +610,9 @@ private Configuration(Builder builder) { this.maxRetries = builder.maxRetries; } - /** Allows for simple constructing of a {@code Configuration} object. */ + /** + * Allows for simple constructing of a {@code Configuration} object. + */ public static final class Builder { private final Context context; private String applicationId; From 4e2c22c551a6fa9ada67787a90e2a8950c1d52a7 Mon Sep 17 00:00:00 2001 From: Romman Sabbir Date: Sat, 21 May 2022 16:13:56 +0600 Subject: [PATCH 9/9] fix: SpotlessJavaCheck Violations (#1168) --- parse/src/main/java/com/parse/Parse.java | 126 ++++++++---------- .../parse/ParseCacheDirMigrationUtils.java | 85 ++++++++---- .../src/main/java/com/parse/ParsePlugins.java | 90 ++++++------- .../ParseCacheDirMigrationUtilsTest.java | 62 +++++---- .../java/com/parse/ParseFileUtilsTest.java | 13 +- 5 files changed, 199 insertions(+), 177 deletions(-) diff --git a/parse/src/main/java/com/parse/Parse.java b/parse/src/main/java/com/parse/Parse.java index fff046b5f..c3ad5c1ee 100644 --- a/parse/src/main/java/com/parse/Parse.java +++ b/parse/src/main/java/com/parse/Parse.java @@ -12,13 +12,10 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.util.Log; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; - import com.parse.boltsinternal.Continuation; import com.parse.boltsinternal.Task; - import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -29,7 +26,6 @@ import java.util.List; import java.util.Set; import java.util.concurrent.Callable; - import okhttp3.OkHttpClient; /** @@ -79,8 +75,8 @@ private Parse() { * } * } * - *

- * See See https://github.com/parse-community/Parse-SDK-Android/issues/279 * for a discussion on performance of local datastore, and if it is right for your project. * @@ -89,8 +85,8 @@ private Parse() { public static void enableLocalDatastore(Context context) { if (isInitialized()) { throw new IllegalStateException( - "`Parse#enableLocalDatastore(Context)` must be invoked " - + "before `Parse#initialize(Context)`"); + "`Parse#enableLocalDatastore(Context)` must be invoked " + + "before `Parse#initialize(Context)`"); } isLocalDatastoreEnabled = true; } @@ -117,7 +113,7 @@ public static boolean isLocalDatastoreEnabled() { /** * @return {@code True} if {@link Configuration.Builder#allowCustomObjectId()} has been called, - * otherwise {@code false}. + * otherwise {@code false}. */ public static boolean isAllowCustomObjectId() { return allowCustomObjectId; @@ -183,32 +179,32 @@ static void initialize(Configuration configuration, ParsePlugins parsePlugins) { checkCacheApplicationId(); final Context context = configuration.context; Task.callInBackground( - (Callable) - () -> { - getEventuallyQueue(context); - return null; - }); + (Callable) + () -> { + getEventuallyQueue(context); + return null; + }); ParseFieldOperations.registerDefaultDecoders(); if (!allParsePushIntentReceiversInternal()) { throw new SecurityException( - "To prevent external tampering to your app's notifications, " - + "all receivers registered to handle the following actions must have " - + "their exported attributes set to false: com.parse.push.intent.RECEIVE, " - + "com.parse.push.intent.OPEN, com.parse.push.intent.DELETE"); + "To prevent external tampering to your app's notifications, " + + "all receivers registered to handle the following actions must have " + + "their exported attributes set to false: com.parse.push.intent.RECEIVE, " + + "com.parse.push.intent.OPEN, com.parse.push.intent.DELETE"); } ParseUser.getCurrentUserAsync() - .makeVoid() - .continueWith( - (Continuation) - task -> { - // Prime config in the background - ParseConfig.getCurrentConfig(); - return null; - }, - Task.BACKGROUND_EXECUTOR); + .makeVoid() + .continueWith( + (Continuation) + task -> { + // Prime config in the background + ParseConfig.getCurrentConfig(); + return null; + }, + Task.BACKGROUND_EXECUTOR); dispatchOnParseInitialized(); @@ -220,11 +216,8 @@ static void initialize(Configuration configuration, ParsePlugins parsePlugins) { // region Server URL - /** - * Returns the current server URL. - */ - public static @Nullable - String getServer() { + /** Returns the current server URL. */ + public static @Nullable String getServer() { URL server = ParseRESTCommand.server; return server == null ? null : server.toString(); } @@ -258,8 +251,7 @@ public static void setServer(@NonNull String server) { * @param server The server URL to validate. * @return The validated server URL. */ - private static @Nullable - String validateServerUrl(@Nullable String server) { + private static @Nullable String validateServerUrl(@Nullable String server) { // Add an extra trailing slash so that Parse REST commands include // the path as part of the server URL (i.e. http://api.myhost.com/parse) @@ -296,9 +288,7 @@ public static void destroy() { allowCustomObjectId = false; } - /** - * @return {@code True} if {@link #initialize} has been called, otherwise {@code false}. - */ + /** @return {@code True} if {@link #initialize} has been called, otherwise {@code false}. */ static boolean isInitialized() { return ParsePlugins.get() != null; } @@ -321,10 +311,10 @@ public static Context getApplicationContext() { */ private static boolean allParsePushIntentReceiversInternal() { List intentReceivers = - ManifestInfo.getIntentReceivers( - ParsePushBroadcastReceiver.ACTION_PUSH_RECEIVE, - ParsePushBroadcastReceiver.ACTION_PUSH_DELETE, - ParsePushBroadcastReceiver.ACTION_PUSH_OPEN); + ManifestInfo.getIntentReceivers( + ParsePushBroadcastReceiver.ACTION_PUSH_RECEIVE, + ParsePushBroadcastReceiver.ACTION_PUSH_DELETE, + ParsePushBroadcastReceiver.ACTION_PUSH_OPEN); for (ResolveInfo resolveInfo : intentReceivers) { if (resolveInfo.activityInfo.exported) { @@ -427,15 +417,15 @@ private static ParseEventuallyQueue getEventuallyQueue(Context context) { synchronized (MUTEX) { boolean isLocalDatastoreEnabled = Parse.isLocalDatastoreEnabled(); if (eventuallyQueue == null - || (isLocalDatastoreEnabled && eventuallyQueue instanceof ParseCommandCache) - || (!isLocalDatastoreEnabled - && eventuallyQueue instanceof ParsePinningEventuallyQueue)) { + || (isLocalDatastoreEnabled && eventuallyQueue instanceof ParseCommandCache) + || (!isLocalDatastoreEnabled + && eventuallyQueue instanceof ParsePinningEventuallyQueue)) { checkContext(); ParseHttpClient httpClient = ParsePlugins.get().restClient(); eventuallyQueue = - isLocalDatastoreEnabled - ? new ParsePinningEventuallyQueue(context, httpClient) - : new ParseCommandCache(context, httpClient); + isLocalDatastoreEnabled + ? new ParsePinningEventuallyQueue(context, httpClient) + : new ParseCommandCache(context, httpClient); // We still need to clear out the old command cache even if we're using Pinning in // case @@ -449,35 +439,33 @@ private static ParseEventuallyQueue getEventuallyQueue(Context context) { } } - /** - * Used by Parse LiveQuery - */ + /** Used by Parse LiveQuery */ public static void checkInit() { if (ParsePlugins.get() == null) { throw new RuntimeException( - "You must call Parse.initialize(Context)" + " before using the Parse library."); + "You must call Parse.initialize(Context)" + " before using the Parse library."); } if (ParsePlugins.get().applicationId() == null) { throw new RuntimeException( - "applicationId is null. " - + "You must call Parse.initialize(Context)" - + " before using the Parse library."); + "applicationId is null. " + + "You must call Parse.initialize(Context)" + + " before using the Parse library."); } } static void checkContext() { if (ParsePlugins.get().applicationContext() == null) { throw new RuntimeException( - "applicationContext is null. " - + "You must call Parse.initialize(Context)" - + " before using the Parse library."); + "applicationContext is null. " + + "You must call Parse.initialize(Context)" + + " before using the Parse library."); } } static boolean hasPermission(String permission) { return (getApplicationContext().checkCallingOrSelfPermission(permission) - == PackageManager.PERMISSION_GRANTED); + == PackageManager.PERMISSION_GRANTED); } // endregion @@ -487,10 +475,10 @@ static boolean hasPermission(String permission) { static void requirePermission(String permission) { if (!hasPermission(permission)) { throw new IllegalStateException( - "To use this functionality, add this to your AndroidManifest.xml:\n" - + ""); + "To use this functionality, add this to your AndroidManifest.xml:\n" + + ""); } } @@ -504,7 +492,7 @@ static void requirePermission(String permission) { static void registerParseCallbacks(ParseCallbacks listener) { if (isInitialized()) { throw new IllegalStateException( - "You must register callbacks before Parse.initialize(Context)"); + "You must register callbacks before Parse.initialize(Context)"); } synchronized (MUTEX_CALLBACKS) { @@ -552,9 +540,7 @@ private static ParseCallbacks[] collectParseCallbacks() { return callbacks; } - /** - * Returns the level of logging that will be displayed. - */ + /** Returns the level of logging that will be displayed. */ public static int getLogLevel() { return PLog.getLogLevel(); } @@ -586,9 +572,7 @@ interface ParseCallbacks { void onParseInitialized(); } - /** - * Represents an opaque configuration for the {@code Parse} SDK configuration. - */ + /** Represents an opaque configuration for the {@code Parse} SDK configuration. */ public static final class Configuration { final Context context; final String applicationId; @@ -610,9 +594,7 @@ private Configuration(Builder builder) { this.maxRetries = builder.maxRetries; } - /** - * Allows for simple constructing of a {@code Configuration} object. - */ + /** Allows for simple constructing of a {@code Configuration} object. */ public static final class Builder { private final Context context; private String applicationId; diff --git a/parse/src/main/java/com/parse/ParseCacheDirMigrationUtils.java b/parse/src/main/java/com/parse/ParseCacheDirMigrationUtils.java index ad002d834..9b7b2725a 100644 --- a/parse/src/main/java/com/parse/ParseCacheDirMigrationUtils.java +++ b/parse/src/main/java/com/parse/ParseCacheDirMigrationUtils.java @@ -1,12 +1,12 @@ package com.parse; import android.content.Context; - import java.io.File; import java.util.ArrayList; /** - * The {@code ParseMigrationUtils} class perform caching dir migration operation for {@code Parse} SDK. + * The {@code ParseMigrationUtils} class perform caching dir migration operation for {@code Parse} + * SDK. */ public class ParseCacheDirMigrationUtils { private final String TAG = this.getClass().getName(); @@ -27,16 +27,21 @@ protected void runMigrations() { private void runSilentMigration(Context context) { ArrayList filesToBeMigrated = new ArrayList<>(); ParseFileUtils.getAllNestedFiles( - getOldParseDir(context).getAbsolutePath(), - filesToBeMigrated - ); + getOldParseDir(context).getAbsolutePath(), filesToBeMigrated); if (filesToBeMigrated.isEmpty()) { return; } boolean useFilesDir = false; - //Hard coded config file names list. - String[] configNamesList = {"installationId", "currentUser", "currentConfig", "currentInstallation", "LocalId", "pushState"}; - //Start migration for each files in `allFiles`. + // Hard coded config file names list. + String[] configNamesList = { + "installationId", + "currentUser", + "currentConfig", + "currentInstallation", + "LocalId", + "pushState" + }; + // Start migration for each files in `allFiles`. for (File itemToMove : filesToBeMigrated) { try { for (String configName : configNamesList) { @@ -47,17 +52,26 @@ private void runSilentMigration(Context context) { useFilesDir = false; } } - File fileToSave = new File( - (useFilesDir ? context.getFilesDir() : context.getCacheDir()) - + "/com.parse/" + - getFileOldDir(context, itemToMove), - itemToMove.getName()); - //Perform copy operation if file doesn't exist in the new directory. + File fileToSave = + new File( + (useFilesDir ? context.getFilesDir() : context.getCacheDir()) + + "/com.parse/" + + getFileOldDir(context, itemToMove), + itemToMove.getName()); + // Perform copy operation if file doesn't exist in the new directory. if (!fileToSave.exists()) { ParseFileUtils.copyFile(itemToMove, fileToSave); - logMigrationStatus(itemToMove.getName(), itemToMove.getPath(), fileToSave.getAbsolutePath(), "Successful."); + logMigrationStatus( + itemToMove.getName(), + itemToMove.getPath(), + fileToSave.getAbsolutePath(), + "Successful."); } else { - logMigrationStatus(itemToMove.getName(), itemToMove.getPath(), fileToSave.getAbsolutePath(), "Already exist in new location."); + logMigrationStatus( + itemToMove.getName(), + itemToMove.getPath(), + fileToSave.getAbsolutePath(), + "Already exist in new location."); } ParseFileUtils.deleteQuietly(itemToMove); PLog.v(TAG, "File deleted: " + "{" + itemToMove.getName() + "}" + " successfully"); @@ -65,9 +79,11 @@ private void runSilentMigration(Context context) { e.printStackTrace(); } } - //Check again, if all files has been resolved or not. If yes, delete the old dir "app_Parse". + // Check again, if all files has been resolved or not. If yes, delete the old dir + // "app_Parse". filesToBeMigrated.clear(); - ParseFileUtils.getAllNestedFiles(getOldParseDir(context).getAbsolutePath(), filesToBeMigrated); + ParseFileUtils.getAllNestedFiles( + getOldParseDir(context).getAbsolutePath(), filesToBeMigrated); if (filesToBeMigrated.isEmpty()) { try { ParseFileUtils.deleteDirectory(getOldParseDir(context)); @@ -79,18 +95,31 @@ private void runSilentMigration(Context context) { } private String getFileOldDir(Context context, File file) { - //Parse the old sub directory name where the file should be moved (new location) by following the old sub directory name. - String temp = file - .getAbsolutePath() - .replace( - getOldParseDir(context).getAbsolutePath(), "") - .replace("/" + file.getName(), ""); - //Before returning the path, replace file name from the last, eg. dir name & file name could be same, as we want to get only dir name. + // Parse the old sub directory name where the file should be moved (new location) by + // following the old sub directory name. + String temp = + file.getAbsolutePath() + .replace(getOldParseDir(context).getAbsolutePath(), "") + .replace("/" + file.getName(), ""); + // Before returning the path, replace file name from the last, eg. dir name & file name + // could be same, as we want to get only dir name. return replaceLast(temp, file.getName()); } - private void logMigrationStatus(String fileName, String oldPath, String newPath, String status) { - PLog.v(TAG, "Migration for file: " + "{" + fileName + "}" + " from {" + oldPath + "} to {" + newPath + "}, Status: " + status); + private void logMigrationStatus( + String fileName, String oldPath, String newPath, String status) { + PLog.v( + TAG, + "Migration for file: " + + "{" + + fileName + + "}" + + " from {" + + oldPath + + "} to {" + + newPath + + "}, Status: " + + status); } /*Replace a given string from the last*/ @@ -101,6 +130,4 @@ private String replaceLast(String text, String regex) { private File getOldParseDir(Context context) { return context.getDir("Parse", Context.MODE_PRIVATE); } - - } diff --git a/parse/src/main/java/com/parse/ParsePlugins.java b/parse/src/main/java/com/parse/ParsePlugins.java index 27d73f63f..df8c1ebe6 100644 --- a/parse/src/main/java/com/parse/ParsePlugins.java +++ b/parse/src/main/java/com/parse/ParsePlugins.java @@ -111,50 +111,50 @@ ParseHttpClient restClient() { } // add it as the first interceptor clientBuilder - .interceptors() - .add( - 0, - chain -> { - Request request = chain.request(); - Headers.Builder headersBuilder = - request.headers() - .newBuilder() - .set( - ParseRESTCommand.HEADER_APPLICATION_ID, - configuration.applicationId) - .set( - ParseRESTCommand - .HEADER_APP_BUILD_VERSION, - String.valueOf( - ManifestInfo.getVersionCode())) - .set( - ParseRESTCommand - .HEADER_APP_DISPLAY_VERSION, - ManifestInfo.getVersionName()) - .set( - ParseRESTCommand.HEADER_OS_VERSION, - Build.VERSION.RELEASE) - .set(ParseRESTCommand.USER_AGENT, userAgent()); - if (request.header(ParseRESTCommand.HEADER_INSTALLATION_ID) - == null) { - // We can do this synchronously since the caller is already - // on a background thread - headersBuilder.set( - ParseRESTCommand.HEADER_INSTALLATION_ID, - installationId().get()); - } - // client key can be null with self-hosted Parse Server - if (configuration.clientKey != null) { - headersBuilder.set( - ParseRESTCommand.HEADER_CLIENT_KEY, - configuration.clientKey); - } - request = - request.newBuilder() - .headers(headersBuilder.build()) - .build(); - return chain.proceed(request); - }); + .interceptors() + .add( + 0, + chain -> { + Request request = chain.request(); + Headers.Builder headersBuilder = + request.headers() + .newBuilder() + .set( + ParseRESTCommand.HEADER_APPLICATION_ID, + configuration.applicationId) + .set( + ParseRESTCommand + .HEADER_APP_BUILD_VERSION, + String.valueOf( + ManifestInfo.getVersionCode())) + .set( + ParseRESTCommand + .HEADER_APP_DISPLAY_VERSION, + ManifestInfo.getVersionName()) + .set( + ParseRESTCommand.HEADER_OS_VERSION, + Build.VERSION.RELEASE) + .set(ParseRESTCommand.USER_AGENT, userAgent()); + if (request.header(ParseRESTCommand.HEADER_INSTALLATION_ID) + == null) { + // We can do this synchronously since the caller is already + // on a background thread + headersBuilder.set( + ParseRESTCommand.HEADER_INSTALLATION_ID, + installationId().get()); + } + // client key can be null with self-hosted Parse Server + if (configuration.clientKey != null) { + headersBuilder.set( + ParseRESTCommand.HEADER_CLIENT_KEY, + configuration.clientKey); + } + request = + request.newBuilder() + .headers(headersBuilder.build()) + .build(); + return chain.proceed(request); + }); restClient = ParseHttpClient.createClient(clientBuilder); } return restClient; @@ -169,7 +169,7 @@ InstallationId installationId() { synchronized (lock) { if (installationId == null) { installationId = - new InstallationId(new File(getFilesDir(), INSTALLATION_ID_LOCATION)); + new InstallationId(new File(getFilesDir(), INSTALLATION_ID_LOCATION)); } return installationId; } diff --git a/parse/src/test/java/com/parse/ParseCacheDirMigrationUtilsTest.java b/parse/src/test/java/com/parse/ParseCacheDirMigrationUtilsTest.java index 1eb8dabec..16869e9b7 100644 --- a/parse/src/test/java/com/parse/ParseCacheDirMigrationUtilsTest.java +++ b/parse/src/test/java/com/parse/ParseCacheDirMigrationUtilsTest.java @@ -1,18 +1,15 @@ package com.parse; import android.content.Context; - import androidx.test.platform.app.InstrumentationRegistry; - +import java.io.File; +import java.util.ArrayList; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import java.io.File; -import java.util.ArrayList; - @RunWith(RobolectricTestRunner.class) public class ParseCacheDirMigrationUtilsTest { ArrayList writtenFiles = new ArrayList<>(); @@ -20,7 +17,9 @@ public class ParseCacheDirMigrationUtilsTest { @Before public void setUp() throws Exception { - utils = new ParseCacheDirMigrationUtils(InstrumentationRegistry.getInstrumentation().getContext()); + utils = + new ParseCacheDirMigrationUtils( + InstrumentationRegistry.getInstrumentation().getContext()); writtenFiles.clear(); } @@ -34,11 +33,12 @@ public void testMigrationOnParseSDKInitialization() { prepareForMockFilesWriting(); writtenFiles.addAll(writeSomeMockFiles(true)); Parse.Configuration configuration = - new Parse.Configuration.Builder(InstrumentationRegistry.getInstrumentation().getContext()) - .applicationId(BuildConfig.LIBRARY_PACKAGE_NAME) - .server("https://api.parse.com/1") - .enableLocalDataStore() - .build(); + new Parse.Configuration.Builder( + InstrumentationRegistry.getInstrumentation().getContext()) + .applicationId(BuildConfig.LIBRARY_PACKAGE_NAME) + .server("https://api.parse.com/1") + .enableLocalDataStore() + .build(); Parse.initialize(configuration); } @@ -47,20 +47,20 @@ public void testMockMigration() { prepareForMockFilesWriting(); writtenFiles.addAll(writeSomeMockFiles(true)); - //Run migration. + // Run migration. utils.runMigrations(); - //Check for cache file after migration. + // Check for cache file after migration. File cacheDir = InstrumentationRegistry.getInstrumentation().getContext().getCacheDir(); ArrayList migratedCaches = new ArrayList<>(); ParseFileUtils.getAllNestedFiles(cacheDir.getAbsolutePath(), migratedCaches); - //Check for files file after migration. + // Check for files file after migration. File filesDir = InstrumentationRegistry.getInstrumentation().getContext().getFilesDir(); ArrayList migratedFiles = new ArrayList<>(); ParseFileUtils.getAllNestedFiles(filesDir.getAbsolutePath(), migratedFiles); - //To check migrations result + // To check migrations result int sizeAfterMigration = (migratedCaches.size() + migratedFiles.size()); int sizeBeforeMigrations = writtenFiles.size(); @@ -70,22 +70,28 @@ public void testMockMigration() { } private void prepareForMockFilesWriting() { - //Delete `"app_Parse"` dir including nested dir and files. + // Delete `"app_Parse"` dir including nested dir and files. try { - ParseFileUtils.deleteDirectory(InstrumentationRegistry.getInstrumentation().getContext().getDir("Parse", Context.MODE_PRIVATE)); + ParseFileUtils.deleteDirectory( + InstrumentationRegistry.getInstrumentation() + .getContext() + .getDir("Parse", Context.MODE_PRIVATE)); } catch (Exception e) { e.printStackTrace(); } writtenFiles.clear(); - //Create new `"app_Parse"` dir to write some files. + // Create new `"app_Parse"` dir to write some files. createFileDir(InstrumentationRegistry.getInstrumentation().getContext().getCacheDir()); } private ArrayList writeSomeMockFiles(Boolean checkForExistingFile) { ArrayList fileToReturn = new ArrayList<>(); - File oldRef = InstrumentationRegistry.getInstrumentation().getContext().getDir("Parse", Context.MODE_PRIVATE); + File oldRef = + InstrumentationRegistry.getInstrumentation() + .getContext() + .getDir("Parse", Context.MODE_PRIVATE); - //Writing some config & random files for migration process. + // Writing some config & random files for migration process. File config = new File(oldRef + "/config/", "config"); fileToReturn.add(config); File installationId = new File(oldRef + "/CommandCache/", "installationId"); @@ -107,7 +113,7 @@ private ArrayList writeSomeMockFiles(Boolean checkForExistingFile) { File user = new File(oldRef + "/user/", "user_config"); fileToReturn.add(user); - //Write all listed files to the app cache ("app_Parse") directory. + // Write all listed files to the app cache ("app_Parse") directory. for (File item : fileToReturn) { try { ParseFileUtils.writeStringToFile(item, "gger", "UTF-8"); @@ -115,10 +121,19 @@ private ArrayList writeSomeMockFiles(Boolean checkForExistingFile) { e.printStackTrace(); } } - //To create a file conflict scenario during migration by creating an existing file to the new files dir ("*/files/com.parse/*"). + // To create a file conflict scenario during migration by creating an existing file to the + // new files dir ("*/files/com.parse/*"). if (checkForExistingFile) { try { - ParseFileUtils.writeStringToFile(new File(InstrumentationRegistry.getInstrumentation().getContext().getFilesDir() + "/com.parse/CommandCache/", "installationId"), "gger", "UTF-8"); + ParseFileUtils.writeStringToFile( + new File( + InstrumentationRegistry.getInstrumentation() + .getContext() + .getFilesDir() + + "/com.parse/CommandCache/", + "installationId"), + "gger", + "UTF-8"); } catch (Exception e) { e.printStackTrace(); } @@ -134,5 +149,4 @@ private File createFileDir(File file) { } return file; } - } diff --git a/parse/src/test/java/com/parse/ParseFileUtilsTest.java b/parse/src/test/java/com/parse/ParseFileUtilsTest.java index fe72d2e7a..11485d7bd 100644 --- a/parse/src/test/java/com/parse/ParseFileUtilsTest.java +++ b/parse/src/test/java/com/parse/ParseFileUtilsTest.java @@ -18,7 +18,6 @@ import java.io.FileOutputStream; import java.io.InputStream; import java.util.ArrayList; - import org.json.JSONObject; import org.junit.Rule; import org.junit.Test; @@ -105,11 +104,11 @@ public void testWriteJSONObjectToFile() throws Exception { } @Test - public void testGetAllFilesFromAGivenPath(){ + public void testGetAllFilesFromAGivenPath() { ArrayList filesListToSave = new ArrayList<>(); - File oldRef = new File(temporaryFolder.getRoot()+"/ParseFileUtilsTest/"); + File oldRef = new File(temporaryFolder.getRoot() + "/ParseFileUtilsTest/"); - //Writing some files to the `*/ParseFileUtilsTest/*` dir. + // Writing some files to the `*/ParseFileUtilsTest/*` dir. File config = new File(oldRef + "/config/", "config"); filesListToSave.add(config); File installationId = new File(oldRef + "/CommandCache/", "installationId"); @@ -121,7 +120,7 @@ public void testGetAllFilesFromAGivenPath(){ File pushState = new File(oldRef + "/push/", "pushState"); filesListToSave.add(pushState); - //Write all listed files to the temp (oldRef) directory. + // Write all listed files to the temp (oldRef) directory. for (File item : filesListToSave) { try { ParseFileUtils.writeStringToFile(item, "gger", "UTF-8"); @@ -130,11 +129,11 @@ public void testGetAllFilesFromAGivenPath(){ } } - //Get all the written files under `*/ParseFileUtilsTest/*`. + // Get all the written files under `*/ParseFileUtilsTest/*`. ArrayList allWrittenFiles = new ArrayList<>(); ParseFileUtils.getAllNestedFiles(oldRef.getAbsolutePath(), allWrittenFiles); - //Check if they both matches or not. + // Check if they both matches or not. assertEquals(filesListToSave.size(), allWrittenFiles.size()); } }