From de75a98093bcc2d8f6c5ef602ba619f52942bb0e Mon Sep 17 00:00:00 2001 From: Moxie Marlinspike Date: Fri, 28 Nov 2014 10:10:47 -0800 Subject: [PATCH] Move JobManager to external project and dependency. // FREEBIE --- build.gradle | 4 +- gradle/wrapper/gradle-wrapper.properties | 4 +- jobqueue/.gitignore | 1 - jobqueue/README.md | 238 ---------------- jobqueue/build.gradle | 19 -- .../jobqueue/JobManagerTest.java | 225 ---------------- .../jobqueue/jobs/PersistentTestJob.java | 39 --- .../jobs/RequirementDeferringTestJob.java | 51 ---- .../jobqueue/jobs/RequirementTestJob.java | 12 - .../whispersystems/jobqueue/jobs/TestJob.java | 81 ------ .../jobqueue/util/MockRequirement.java | 23 -- .../util/MockRequirementProvider.java | 23 -- .../util/PersistentMockRequirement.java | 10 - .../jobqueue/util/PersistentRequirement.java | 22 -- .../jobqueue/util/PersistentResult.java | 73 ----- .../jobqueue/util/RunnableThrowable.java | 8 - jobqueue/src/main/AndroidManifest.xml | 6 - .../jobqueue/EncryptionKeys.java | 30 --- .../java/org/whispersystems/jobqueue/Job.java | 116 -------- .../whispersystems/jobqueue/JobConsumer.java | 90 ------- .../whispersystems/jobqueue/JobManager.java | 253 ------------------ .../jobqueue/JobParameters.java | 149 ----------- .../org/whispersystems/jobqueue/JobQueue.java | 95 ------- .../dependencies/ContextDependent.java | 27 -- .../dependencies/DependencyInjector.java | 24 -- .../persistence/JavaJobSerializer.java | 58 ---- .../jobqueue/persistence/JobSerializer.java | 47 ---- .../persistence/PersistentStorage.java | 152 ----------- .../requirements/NetworkRequirement.java | 50 ---- .../NetworkRequirementProvider.java | 59 ---- .../jobqueue/requirements/Requirement.java | 29 -- .../requirements/RequirementListener.java | 21 -- .../requirements/RequirementProvider.java | 37 --- jobqueue/src/main/res/values/strings.xml | 2 - settings.gradle | 2 +- 35 files changed, 6 insertions(+), 2074 deletions(-) delete mode 100644 jobqueue/.gitignore delete mode 100644 jobqueue/README.md delete mode 100644 jobqueue/build.gradle delete mode 100644 jobqueue/src/androidTest/java/org/whispersystems/jobqueue/JobManagerTest.java delete mode 100644 jobqueue/src/androidTest/java/org/whispersystems/jobqueue/jobs/PersistentTestJob.java delete mode 100644 jobqueue/src/androidTest/java/org/whispersystems/jobqueue/jobs/RequirementDeferringTestJob.java delete mode 100644 jobqueue/src/androidTest/java/org/whispersystems/jobqueue/jobs/RequirementTestJob.java delete mode 100644 jobqueue/src/androidTest/java/org/whispersystems/jobqueue/jobs/TestJob.java delete mode 100644 jobqueue/src/androidTest/java/org/whispersystems/jobqueue/util/MockRequirement.java delete mode 100644 jobqueue/src/androidTest/java/org/whispersystems/jobqueue/util/MockRequirementProvider.java delete mode 100644 jobqueue/src/androidTest/java/org/whispersystems/jobqueue/util/PersistentMockRequirement.java delete mode 100644 jobqueue/src/androidTest/java/org/whispersystems/jobqueue/util/PersistentRequirement.java delete mode 100644 jobqueue/src/androidTest/java/org/whispersystems/jobqueue/util/PersistentResult.java delete mode 100644 jobqueue/src/androidTest/java/org/whispersystems/jobqueue/util/RunnableThrowable.java delete mode 100644 jobqueue/src/main/AndroidManifest.xml delete mode 100644 jobqueue/src/main/java/org/whispersystems/jobqueue/EncryptionKeys.java delete mode 100644 jobqueue/src/main/java/org/whispersystems/jobqueue/Job.java delete mode 100644 jobqueue/src/main/java/org/whispersystems/jobqueue/JobConsumer.java delete mode 100644 jobqueue/src/main/java/org/whispersystems/jobqueue/JobManager.java delete mode 100644 jobqueue/src/main/java/org/whispersystems/jobqueue/JobParameters.java delete mode 100644 jobqueue/src/main/java/org/whispersystems/jobqueue/JobQueue.java delete mode 100644 jobqueue/src/main/java/org/whispersystems/jobqueue/dependencies/ContextDependent.java delete mode 100644 jobqueue/src/main/java/org/whispersystems/jobqueue/dependencies/DependencyInjector.java delete mode 100644 jobqueue/src/main/java/org/whispersystems/jobqueue/persistence/JavaJobSerializer.java delete mode 100644 jobqueue/src/main/java/org/whispersystems/jobqueue/persistence/JobSerializer.java delete mode 100644 jobqueue/src/main/java/org/whispersystems/jobqueue/persistence/PersistentStorage.java delete mode 100644 jobqueue/src/main/java/org/whispersystems/jobqueue/requirements/NetworkRequirement.java delete mode 100644 jobqueue/src/main/java/org/whispersystems/jobqueue/requirements/NetworkRequirementProvider.java delete mode 100644 jobqueue/src/main/java/org/whispersystems/jobqueue/requirements/Requirement.java delete mode 100644 jobqueue/src/main/java/org/whispersystems/jobqueue/requirements/RequirementListener.java delete mode 100644 jobqueue/src/main/java/org/whispersystems/jobqueue/requirements/RequirementProvider.java delete mode 100644 jobqueue/src/main/res/values/strings.xml diff --git a/build.gradle b/build.gradle index b6cbf4abb..96680fb5c 100644 --- a/build.gradle +++ b/build.gradle @@ -45,12 +45,13 @@ dependencies { compile 'com.squareup.dagger:dagger:1.2.2' provided 'com.squareup.dagger:dagger-compiler:1.2.2' + compile 'org.whispersystems:jobmanager:0.9.0' + androidTestCompile 'com.squareup:fest-android:1.0.8' androidTestCompile 'com.google.dexmaker:dexmaker:1.1' androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.1' compile project(':libtextsecure') - compile project(':jobqueue') } dependencyVerification { @@ -72,6 +73,7 @@ dependencyVerification { 'com.google.protobuf:protobuf-java:e0c1c64575c005601725e7c6a02cebf9e1285e888f756b2a1d73ffa8d725cc74', 'com.googlecode.libphonenumber:libphonenumber:eba17eae81dd622ea89a00a3a8c025b2f25d342e0d9644c5b62e16f15687c3ab', 'org.whispersystems:gson:08f4f7498455d1539c9233e5aac18e9b1805815ef29221572996508eb512fe51', + 'org.whispersystems:jobmanager:adb4329b69035053a7b6a48e22a3280235ac405b225ed8679b994612a8e6f5b6', 'com.android.support:support-annotations:1aa96ef0cc4a445bfc2f93ccf762305bc57fa107b12afe9d11f3863ae8a11036', ] } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 7130a39d5..22cc9acdf 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Fri Nov 14 10:44:11 MSK 2014 +#Fri Nov 28 10:03:17 PST 2014 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip diff --git a/jobqueue/.gitignore b/jobqueue/.gitignore deleted file mode 100644 index 796b96d1c..000000000 --- a/jobqueue/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build diff --git a/jobqueue/README.md b/jobqueue/README.md deleted file mode 100644 index d56b67569..000000000 --- a/jobqueue/README.md +++ /dev/null @@ -1,238 +0,0 @@ -# JobManager - -An Android library that facilitates scheduling persistent jobs which are executed when their -prerequisites have been met. Similar to Path's android-priority-queue. - -## The JobManager Way - -Android apps often need to perform blocking operations. A messaging app might need to make REST -API calls over a network, send SMS messages, download attachments, and interact with a database. - -The standard Android way to do these things are with Services, AsyncTasks, or a dedicated Thread. -However, some of an app's operations might need to wait until certain dependencies are available -(such as a network connection), and some of the operations might need to be durable (complete even if the -app restarts before they have a chance to run). The standard Android way can result in -a lot of retry logic, timers for monitoring dependencies, and one-off code for making operations -durable. - -By contrast, the JobManager way allows operations to be broken up into Jobs. A Job represents a -unit of work to be done, the prerequisites that need to be met (such as network access) before the -work can execute, and the characteristics of the job (such as durable persistence). - -Applications construct a `JobManager` at initialization time: - -``` -public class ApplicationContext extends Application { - - private JobManager jobManager; - - @Override - public void onCreate() { - initializeJobManager(); - } - - private void initializeJobManager() { - this.jobManager = JobManager.newBuilder(this) - .withName("SampleJobManager") - .withConsumerThreads(5) - .build(); - } - - ... - -} -``` - -This constructs a new `JobManager` with 5 consumer threads dedicated to executing Jobs. A -Job looks like this: - -``` -public class SampleJob extends Job { - - public SampleJob() { - super(JobParameters.newBuilder().create()); - } - - @Override - public onAdded() { - // Called after the Job has been added to the queue. - } - - @Override - public void onRun() { - // Here's where we execute our work. - Log.w("SampleJob", "Hello, world!"); - } - - @Override - public void onCanceled() { - // This would be called if the job had failed. - } - - @Override - public boolean onShouldRetry(Exception exception) { - // Called if onRun() had thrown an exception to determine whether - // onRun() should be called again. - return false; - } -} -``` - -A Job is scheduled simply by adding it to the JobManager: - -``` - this.jobManager.add(new SampleJob()); -``` - -## Persistence - -To create durable Jobs, the JobManager needs to be given an interface responsible for serializing -and deserializing Job objects. A `JavaJobSerializer` is included with JobManager that uses Java -Serialization, but you can specify your own serializer if you wish: - -``` -public class ApplicationContext extends Application { - - private JobManager jobManager; - - @Override - public void onCreate() { - initializeJobManager(); - } - - private void initializeJobManager() { - this.jobManager = JobManager.newBuilder(this) - .withName("SampleJobManager") - .withConsumerThreads(5) - .withJobSerializer(new JavaJobSerializer()) - .build(); - } - - ... - -} - -``` - -The Job simply needs to declare itself as durable when constructed: - -``` -public class SampleJob extends Job { - - public SampleJob() { - super(JobParameters.newBuilder() - .withPersistence() - .create()); - } - - ... - -``` - -Persistent jobs that are enqueued will be serialized to disk to ensure that they run even if -the App restarts first. A Job's onAdded() method is called after the commit to disk is complete. - -## Requirements - -A Job might have certain requirements that need to be met before it can run. A requirement is -represented by the `Requirement` interface. Each `Requirement` must also have a corresponding -`RequirementProvider` that is registered with the JobManager. - -A `Requirement` tells you whether it is present when queried, while a `RequirementProvider` -broadcasts to a listener when a Requirement's status might have changed. `Requirement` is attached -to Job, while `RequirementProvider` is attached to JobManager. - - -One common `Requirement` a `Job` might depend on is the presence of network connectivity. -A `NetworkRequirement` is bundled with JobManager: - -``` -public class ApplicationContext extends Application { - - private JobManager jobManager; - - @Override - public void onCreate() { - initializeJobManager(); - } - - private void initializeJobManager() { - this.jobManager = JobManager.newBuilder(this) - .withName("SampleJobManager") - .withConsumerThreads(5) - .withJobSerializer(new JavaJobSerializer()) - .withRequirementProviders(new NetworkRequirementProvider(this)) - .build(); - } - - ... - -} -``` - -The Job declares itself as having a `Requirement` when constructed: - -``` -public class SampleJob extends Job { - - public SampleJob(Context context) { - super(JobParameters.newBuilder() - .withPersistence() - .withRequirement(new NetworkRequirement(context)) - .create()); - } - - ... - -``` - -## Dependency Injection - -It is possible that Jobs (and Requirements) might require dependency injection. A simple example -is `Context`, which many Jobs might require, but can't be persisted to disk for durable Jobs. Or -maybe Jobs require more complex DI through libraries such as Dagger. - -JobManager has an extremely primitive DI mechanism strictly for injecting `Context` objects into -Jobs and Requirements after they're deserialized, and includes support for plugging in more complex -DI systems such as Dagger. - -The JobManager `Context` injection works by having your `Job` and/or `Requirement` implement the -`ContextDependent` interface. `Job`s and `Requirement`s implementing that interface will get a -`setContext(Context context)` call immediately after the persistent `Job` or `Requirement` is -deserialized. - -To plugin a more complex DI mechanism, simply pass an instance of the `DependencyInjector` interface - to the `JobManager`: - -``` -public class ApplicationContext extends Application implements DependencyInjector { - - private JobManager jobManager; - - @Override - public void onCreate() { - initializeJobManager(); - } - - private void initializeJobManager() { - this.jobManager = JobManager.newBuilder(this) - .withName("SampleJobManager") - .withConsumerThreads(5) - .withJobSerializer(new JavaJobSerializer()) - .withRequirementProviders(new NetworkRequirementProvider(this)) - .withDependencyInjector(this) - .build(); - } - - @Override - public void injectDependencies(Object object) { - // And here we do our DI magic. - } - - ... - -} -``` - -`injectDependencies(Object object)` will be called for a `Job` before the job's `onAdded()` method -is called, or after a persistent job is deserialized. \ No newline at end of file diff --git a/jobqueue/build.gradle b/jobqueue/build.gradle deleted file mode 100644 index 19a141129..000000000 --- a/jobqueue/build.gradle +++ /dev/null @@ -1,19 +0,0 @@ -apply plugin: 'com.android.library' - -android { - compileSdkVersion 21 - buildToolsVersion '21.1.1' - - defaultConfig { - applicationId "org.whispersystems.jobqueue" - minSdkVersion 9 - targetSdkVersion 19 - versionCode 1 - versionName "1.0" - } - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_7 - targetCompatibility JavaVersion.VERSION_1_7 - } -} \ No newline at end of file diff --git a/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/JobManagerTest.java b/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/JobManagerTest.java deleted file mode 100644 index 62030f284..000000000 --- a/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/JobManagerTest.java +++ /dev/null @@ -1,225 +0,0 @@ -package org.whispersystems.jobqueue; - -import android.test.AndroidTestCase; - -import org.whispersystems.jobqueue.jobs.PersistentTestJob; -import org.whispersystems.jobqueue.jobs.RequirementDeferringTestJob; -import org.whispersystems.jobqueue.jobs.RequirementTestJob; -import org.whispersystems.jobqueue.jobs.TestJob; -import org.whispersystems.jobqueue.persistence.JavaJobSerializer; -import org.whispersystems.jobqueue.requirements.RequirementProvider; -import org.whispersystems.jobqueue.util.MockRequirement; -import org.whispersystems.jobqueue.util.MockRequirementProvider; -import org.whispersystems.jobqueue.util.PersistentMockRequirement; -import org.whispersystems.jobqueue.util.PersistentRequirement; -import org.whispersystems.jobqueue.util.PersistentResult; -import org.whispersystems.jobqueue.util.RunnableThrowable; - -import java.io.IOException; -import java.util.LinkedList; -import java.util.List; - -public class JobManagerTest extends AndroidTestCase { - - public void testTransientJobExecution() throws InterruptedException { - TestJob testJob = new TestJob(); - JobManager jobManager = JobManager.newBuilder(getContext()) - .withName("transient-test") - .withConsumerThreads(1) - .build(); - - jobManager.add(testJob); - - assertTrue(testJob.isAdded()); - assertTrue(testJob.isRan()); - } - - public void testTransientRequirementJobExecution() throws InterruptedException { - MockRequirementProvider provider = new MockRequirementProvider(); - MockRequirement requirement = new MockRequirement(false); - TestJob testJob = new RequirementTestJob(requirement); - - JobManager jobManager = JobManager.newBuilder(getContext()) - .withName("transient-requirement-test") - .withRequirementProviders(provider) - .withConsumerThreads(1) - .build(); - - jobManager.add(testJob); - - assertTrue(testJob.isAdded()); - assertTrue(!testJob.isRan()); - - requirement.setPresent(true); - provider.fireChange(); - - assertTrue(testJob.isRan()); - } - - public void testTransientRequirementDeferringJobExecution() throws InterruptedException { - final Object lock = new Object(); - - RunnableThrowable waitRunnable = new RunnableThrowable() { - public Boolean shouldThrow = false; - - @Override - public void run() throws Exception { - try { - synchronized (lock) { - lock.wait(); - - if (shouldThrow) { - throw new Exception(); - } - } - } catch (InterruptedException e) { - throw new AssertionError(e); - } - } - @Override - public void shouldThrow(Boolean value) { - shouldThrow = value; - } - }; - - MockRequirementProvider provider = new MockRequirementProvider(); - MockRequirement requirement = new MockRequirement(false); - RequirementDeferringTestJob testJob = new RequirementDeferringTestJob(requirement, 5, waitRunnable); - - JobManager jobManager = JobManager.newBuilder(getContext()) - .withName("transient-requirement-test") - .withRequirementProviders(provider) - .withConsumerThreads(1) - .build(); - - jobManager.add(testJob); - - waitRunnable.shouldThrow(true); - requirement.setPresent(true); - provider.fireChange(); - - assertTrue(testJob.isRan()); - assertTrue(!testJob.isFinished()); - synchronized (lock) { lock.notifyAll(); } - assertTrue(!testJob.isFinished()); - - requirement.setPresent(false); - provider.fireChange(); - assertTrue(!testJob.isFinished()); - synchronized (lock) { lock.notifyAll(); } - assertTrue(!testJob.isFinished()); - - waitRunnable.shouldThrow(false); - requirement.setPresent(true); - provider.fireChange(); - assertTrue(!testJob.isFinished()); - synchronized (lock) { lock.notifyAll(); } - assertTrue(testJob.isFinished()); - } - - public void testPersistentJobExecuton() throws InterruptedException { - PersistentMockRequirement requirement = new PersistentMockRequirement(); - PersistentTestJob testJob = new PersistentTestJob(requirement); - JobManager jobManager = JobManager.newBuilder(getContext()) - .withName("persistent-requirement-test3") - .withJobSerializer(new JavaJobSerializer()) - .withConsumerThreads(1) - .build(); - - PersistentResult.getInstance().reset(); - PersistentRequirement.getInstance().setPresent(false); - - jobManager.add(testJob); - - assertTrue(PersistentResult.getInstance().isAdded()); - assertTrue(!PersistentResult.getInstance().isRan()); - - PersistentRequirement.getInstance().setPresent(true); - - jobManager = JobManager.newBuilder(getContext()) - .withName("persistent-requirement-test3") - .withJobSerializer(new JavaJobSerializer()) - .withConsumerThreads(1) - .build(); - - assertTrue(PersistentResult.getInstance().isRan()); - } - - public void testEncryptedJobExecuton() throws InterruptedException { - EncryptionKeys keys = new EncryptionKeys(new byte[30]); - PersistentMockRequirement requirement = new PersistentMockRequirement(); - PersistentTestJob testJob = new PersistentTestJob(requirement, keys); - JobManager jobManager = JobManager.newBuilder(getContext()) - .withName("persistent-requirement-test4") - .withJobSerializer(new JavaJobSerializer()) - .withConsumerThreads(1) - .build(); - - jobManager.setEncryptionKeys(keys); - - PersistentResult.getInstance().reset(); - PersistentRequirement.getInstance().setPresent(false); - - jobManager.add(testJob); - - assertTrue(PersistentResult.getInstance().isAdded()); - assertTrue(!PersistentResult.getInstance().isRan()); - - PersistentRequirement.getInstance().setPresent(true); - jobManager = JobManager.newBuilder(getContext()) - .withName("persistent-requirement-test4") - .withJobSerializer(new JavaJobSerializer()) - .withConsumerThreads(1) - .build(); - - assertTrue(!PersistentResult.getInstance().isRan()); - - jobManager.setEncryptionKeys(keys); - - assertTrue(PersistentResult.getInstance().isRan()); - } - - public void testGroupIdExecution() throws InterruptedException { - final Object lock = new Object(); - - Runnable waitRunnable = new Runnable() { - @Override - public void run() { - try { - synchronized (lock) { - lock.wait(); - } - } catch (InterruptedException e) { - throw new AssertionError(e); - } - } - }; - - TestJob testJobOne = new TestJob(JobParameters.newBuilder().withGroupId("foo").create(), waitRunnable); - TestJob testJobTwo = new TestJob(JobParameters.newBuilder().withGroupId("foo").create()); - TestJob testJobThree = new TestJob(JobParameters.newBuilder().withGroupId("bar").create()); - JobManager jobManager = JobManager.newBuilder(getContext()) - .withName("transient-test") - .withConsumerThreads(3) - .build(); - - jobManager.add(testJobOne); - jobManager.add(testJobTwo); - jobManager.add(testJobThree); - - assertTrue(testJobOne.isAdded()); - assertTrue(testJobTwo.isAdded()); - assertTrue(testJobThree.isAdded()); - - assertTrue(testJobOne.isRan()); - assertTrue(!testJobTwo.isRan()); - assertTrue(testJobThree.isRan()); - - synchronized (lock) { - lock.notifyAll(); - } - - assertTrue(testJobTwo.isRan()); - } - -} diff --git a/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/jobs/PersistentTestJob.java b/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/jobs/PersistentTestJob.java deleted file mode 100644 index 0d9a561f4..000000000 --- a/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/jobs/PersistentTestJob.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.whispersystems.jobqueue.jobs; - -import org.whispersystems.jobqueue.EncryptionKeys; -import org.whispersystems.jobqueue.Job; -import org.whispersystems.jobqueue.JobParameters; -import org.whispersystems.jobqueue.requirements.Requirement; -import org.whispersystems.jobqueue.util.PersistentResult; - -public class PersistentTestJob extends Job { - - public PersistentTestJob(Requirement requirement) { - super(JobParameters.newBuilder().withRequirement(requirement).withPersistence().create()); - } - - public PersistentTestJob(Requirement requirement, EncryptionKeys keys) { - super(JobParameters.newBuilder().withRequirement(requirement).withPersistence().withEncryption(keys).create()); - } - - - @Override - public void onAdded() { - PersistentResult.getInstance().onAdded(); - } - - @Override - public void onRun() throws Exception { - PersistentResult.getInstance().onRun(); - } - - @Override - public void onCanceled() { - PersistentResult.getInstance().onCanceled(); - } - - @Override - public boolean onShouldRetry(Exception exception) { - return false; - } -} diff --git a/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/jobs/RequirementDeferringTestJob.java b/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/jobs/RequirementDeferringTestJob.java deleted file mode 100644 index 5306d3931..000000000 --- a/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/jobs/RequirementDeferringTestJob.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.whispersystems.jobqueue.jobs; - - import org.whispersystems.jobqueue.JobParameters; - import org.whispersystems.jobqueue.requirements.Requirement; - import org.whispersystems.jobqueue.util.RunnableThrowable; - - import java.io.IOException; - -public class RequirementDeferringTestJob extends TestJob { - - private final Object FINISHED_LOCK = new Object(); - - private boolean finished = false; - - private RunnableThrowable runnable; - - public RequirementDeferringTestJob(Requirement requirement, int retryCount, RunnableThrowable runnable) { - super(JobParameters.newBuilder().withRequirement(requirement).withRetryCount(retryCount).create()); - this.runnable = runnable; - } - - @Override - public void onRun() throws Exception { - synchronized (RAN_LOCK) { - this.ran = true; - } - - if (runnable != null) - runnable.run(); - - synchronized (FINISHED_LOCK) { - this.finished = true; - } - } - - @Override - public boolean onShouldRetry(Exception exception) { - if (exception instanceof Exception) { - return true; - } - return false; - } - - public boolean isFinished() throws InterruptedException { - synchronized (FINISHED_LOCK) { - if (!finished) FINISHED_LOCK.wait(1000); - return finished; - } - } - -} \ No newline at end of file diff --git a/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/jobs/RequirementTestJob.java b/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/jobs/RequirementTestJob.java deleted file mode 100644 index 8dac14c60..000000000 --- a/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/jobs/RequirementTestJob.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.whispersystems.jobqueue.jobs; - -import org.whispersystems.jobqueue.JobParameters; -import org.whispersystems.jobqueue.requirements.Requirement; - -public class RequirementTestJob extends TestJob { - - public RequirementTestJob(Requirement requirement) { - super(JobParameters.newBuilder().withRequirement(requirement).create()); - } - -} diff --git a/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/jobs/TestJob.java b/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/jobs/TestJob.java deleted file mode 100644 index 5e3a866b8..000000000 --- a/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/jobs/TestJob.java +++ /dev/null @@ -1,81 +0,0 @@ -package org.whispersystems.jobqueue.jobs; - -import org.whispersystems.jobqueue.Job; -import org.whispersystems.jobqueue.JobParameters; - -public class TestJob extends Job { - - private final Object ADDED_LOCK = new Object(); - protected final Object RAN_LOCK = new Object(); - private final Object CANCELED_LOCK = new Object(); - - private boolean added = false; - protected boolean ran = false; - private boolean canceled = false; - - private Runnable runnable; - - public TestJob() { - this(JobParameters.newBuilder().create()); - } - - public TestJob(JobParameters parameters) { - super(parameters); - } - - public TestJob(JobParameters parameters, Runnable runnable) { - super(parameters); - this.runnable = runnable; - } - - @Override - public void onAdded() { - synchronized (ADDED_LOCK) { - this.added = true; - this.ADDED_LOCK.notifyAll(); - } - } - - @Override - public void onRun() throws Exception { - synchronized (RAN_LOCK) { - this.ran = true; - } - - if (runnable != null) - runnable.run(); - } - - @Override - public void onCanceled() { - synchronized (CANCELED_LOCK) { - this.canceled = true; - } - } - - @Override - public boolean onShouldRetry(Exception exception) { - return false; - } - - public boolean isAdded() throws InterruptedException { - synchronized (ADDED_LOCK) { - if (!added) ADDED_LOCK.wait(1000); - return added; - } - } - - public boolean isRan() throws InterruptedException { - synchronized (RAN_LOCK) { - if (!ran) RAN_LOCK.wait(1000); - return ran; - } - } - - public boolean isCanceled() throws InterruptedException { - synchronized (CANCELED_LOCK) { - if (!canceled) CANCELED_LOCK.wait(1000); - return canceled; - } - } -} diff --git a/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/util/MockRequirement.java b/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/util/MockRequirement.java deleted file mode 100644 index 779d07747..000000000 --- a/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/util/MockRequirement.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.whispersystems.jobqueue.util; - -import org.whispersystems.jobqueue.requirements.Requirement; - -import java.util.concurrent.atomic.AtomicBoolean; - -public class MockRequirement implements Requirement { - - private AtomicBoolean present; - - public MockRequirement(boolean present) { - this.present = new AtomicBoolean(present); - } - - public void setPresent(boolean present) { - this.present.set(present); - } - - @Override - public boolean isPresent() { - return present.get(); - } -} diff --git a/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/util/MockRequirementProvider.java b/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/util/MockRequirementProvider.java deleted file mode 100644 index ba2e27a18..000000000 --- a/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/util/MockRequirementProvider.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.whispersystems.jobqueue.util; - -import org.whispersystems.jobqueue.requirements.RequirementListener; -import org.whispersystems.jobqueue.requirements.RequirementProvider; - -public class MockRequirementProvider implements RequirementProvider { - - private RequirementListener listener; - - public void fireChange() { - listener.onRequirementStatusChanged(); - } - - @Override - public void setListener(RequirementListener listener) { - this.listener = listener; - } - - @Override - public String getName() { - return "mock-requirement-provider"; - } -} diff --git a/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/util/PersistentMockRequirement.java b/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/util/PersistentMockRequirement.java deleted file mode 100644 index f39eb491a..000000000 --- a/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/util/PersistentMockRequirement.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.whispersystems.jobqueue.util; - -import org.whispersystems.jobqueue.requirements.Requirement; - -public class PersistentMockRequirement implements Requirement { - @Override - public boolean isPresent() { - return PersistentRequirement.getInstance().isPresent(); - } -} diff --git a/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/util/PersistentRequirement.java b/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/util/PersistentRequirement.java deleted file mode 100644 index 917574805..000000000 --- a/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/util/PersistentRequirement.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.whispersystems.jobqueue.util; - -import java.util.concurrent.atomic.AtomicBoolean; - -public class PersistentRequirement { - - private AtomicBoolean present = new AtomicBoolean(false); - - private static final PersistentRequirement instance = new PersistentRequirement(); - - public static PersistentRequirement getInstance() { - return instance; - } - - public void setPresent(boolean present) { - this.present.set(present); - } - - public boolean isPresent() { - return present.get(); - } -} diff --git a/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/util/PersistentResult.java b/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/util/PersistentResult.java deleted file mode 100644 index 7bdff69cc..000000000 --- a/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/util/PersistentResult.java +++ /dev/null @@ -1,73 +0,0 @@ -package org.whispersystems.jobqueue.util; - -public class PersistentResult { - - private final Object ADDED_LOCK = new Object(); - private final Object RAN_LOCK = new Object(); - private final Object CANCELED_LOCK = new Object(); - - private boolean added = false; - private boolean ran = false; - private boolean canceled = false; - - private static final PersistentResult instance = new PersistentResult(); - - public static PersistentResult getInstance() { - return instance; - } - - public void onAdded() { - synchronized (ADDED_LOCK) { - this.added = true; - this.ADDED_LOCK.notifyAll(); - } - } - - public void onRun() throws Exception { - synchronized (RAN_LOCK) { - this.ran = true; - } - } - - public void onCanceled() { - synchronized (CANCELED_LOCK) { - this.canceled = true; - } - } - - public boolean isAdded() throws InterruptedException { - synchronized (ADDED_LOCK) { - if (!added) ADDED_LOCK.wait(1000); - return added; - } - } - - public boolean isRan() throws InterruptedException { - synchronized (RAN_LOCK) { - if (!ran) RAN_LOCK.wait(1000); - return ran; - } - } - - public boolean isCanceled() throws InterruptedException { - synchronized (CANCELED_LOCK) { - if (!canceled) CANCELED_LOCK.wait(1000); - return canceled; - } - } - - public void reset() { - synchronized (ADDED_LOCK) { - this.added = false; - } - - synchronized (RAN_LOCK) { - this.ran = false; - } - - synchronized (CANCELED_LOCK) { - this.canceled = false; - } - } - -} diff --git a/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/util/RunnableThrowable.java b/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/util/RunnableThrowable.java deleted file mode 100644 index 470d66e20..000000000 --- a/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/util/RunnableThrowable.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.whispersystems.jobqueue.util; - -public interface RunnableThrowable { - - public void run() throws Exception; - - public void shouldThrow(Boolean value); -} diff --git a/jobqueue/src/main/AndroidManifest.xml b/jobqueue/src/main/AndroidManifest.xml deleted file mode 100644 index 4265f4c4f..000000000 --- a/jobqueue/src/main/AndroidManifest.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/jobqueue/src/main/java/org/whispersystems/jobqueue/EncryptionKeys.java b/jobqueue/src/main/java/org/whispersystems/jobqueue/EncryptionKeys.java deleted file mode 100644 index a67356799..000000000 --- a/jobqueue/src/main/java/org/whispersystems/jobqueue/EncryptionKeys.java +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright (C) 2014 Open Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.whispersystems.jobqueue; - -public class EncryptionKeys { - - private transient final byte[] encoded; - - public EncryptionKeys(byte[] encoded) { - this.encoded = encoded; - } - - public byte[] getEncoded() { - return encoded; - } -} diff --git a/jobqueue/src/main/java/org/whispersystems/jobqueue/Job.java b/jobqueue/src/main/java/org/whispersystems/jobqueue/Job.java deleted file mode 100644 index b1d525d84..000000000 --- a/jobqueue/src/main/java/org/whispersystems/jobqueue/Job.java +++ /dev/null @@ -1,116 +0,0 @@ -/** - * Copyright (C) 2014 Open Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.whispersystems.jobqueue; - -import org.whispersystems.jobqueue.requirements.Requirement; - -import java.io.Serializable; -import java.util.List; - -/** - * An abstract class representing a unit of work that can be scheduled with - * the JobManager. This should be extended to implement tasks. - */ -public abstract class Job implements Serializable { - - private final JobParameters parameters; - - private transient long persistentId; - private transient int runIteration; - - public Job(JobParameters parameters) { - this.parameters = parameters; - } - - public List getRequirements() { - return parameters.getRequirements(); - } - - public boolean isRequirementsMet() { - for (Requirement requirement : parameters.getRequirements()) { - if (!requirement.isPresent()) return false; - } - - return true; - } - - public String getGroupId() { - return parameters.getGroupId(); - } - - public boolean isPersistent() { - return parameters.isPersistent(); - } - - public EncryptionKeys getEncryptionKeys() { - return parameters.getEncryptionKeys(); - } - - public void setEncryptionKeys(EncryptionKeys keys) { - parameters.setEncryptionKeys(keys); - } - - public int getRetryCount() { - return parameters.getRetryCount(); - } - - public void setPersistentId(long persistentId) { - this.persistentId = persistentId; - } - - public long getPersistentId() { - return persistentId; - } - - public int getRunIteration() { - return runIteration; - } - - public void setRunIteration(int runIteration) { - this.runIteration = runIteration; - } - - /** - * Called after a job has been added to the JobManager queue. If it's a persistent job, - * the state has been persisted to disk before this method is called. - */ - public abstract void onAdded(); - - /** - * Called to actually execute the job. - * @throws Exception - */ - public abstract void onRun() throws Exception; - - /** - * If onRun() throws an exception, this method will be called to determine whether the - * job should be retried. - * - * @param exception The exception onRun() threw. - * @return true if onRun() should be called again, false otherwise. - */ - public abstract boolean onShouldRetry(Exception exception); - - /** - * Called if a job fails to run (onShouldRetry returned false, or the number of retries exceeded - * the job's configured retry count. - */ - public abstract void onCanceled(); - - - -} diff --git a/jobqueue/src/main/java/org/whispersystems/jobqueue/JobConsumer.java b/jobqueue/src/main/java/org/whispersystems/jobqueue/JobConsumer.java deleted file mode 100644 index 194b866fc..000000000 --- a/jobqueue/src/main/java/org/whispersystems/jobqueue/JobConsumer.java +++ /dev/null @@ -1,90 +0,0 @@ -/** - * Copyright (C) 2014 Open Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.whispersystems.jobqueue; - -import android.util.Log; - -import org.whispersystems.jobqueue.persistence.PersistentStorage; - -class JobConsumer extends Thread { - - private static final String TAG = JobConsumer.class.getSimpleName(); - - enum JobResult { - SUCCESS, - FAILURE, - DEFERRED - } - - private final JobQueue jobQueue; - private final PersistentStorage persistentStorage; - - public JobConsumer(String name, JobQueue jobQueue, PersistentStorage persistentStorage) { - super(name); - this.jobQueue = jobQueue; - this.persistentStorage = persistentStorage; - } - - @Override - public void run() { - while (true) { - Job job = jobQueue.getNext(); - JobResult result = runJob(job); - - if (result == JobResult.DEFERRED) { - jobQueue.push(job); - } else { - if (result == JobResult.FAILURE) { - job.onCanceled(); - } - - if (job.isPersistent()) { - persistentStorage.remove(job.getPersistentId()); - } - } - - if (job.getGroupId() != null) { - jobQueue.setGroupIdAvailable(job.getGroupId()); - } - } - } - - private JobResult runJob(Job job) { - int retryCount = job.getRetryCount(); - int runIteration = job.getRunIteration(); - - for (;runIteration. - */ -package org.whispersystems.jobqueue; - -import android.content.Context; -import android.util.Log; - -import org.whispersystems.jobqueue.dependencies.DependencyInjector; -import org.whispersystems.jobqueue.persistence.JobSerializer; -import org.whispersystems.jobqueue.persistence.PersistentStorage; -import org.whispersystems.jobqueue.requirements.RequirementListener; -import org.whispersystems.jobqueue.requirements.RequirementProvider; - -import java.io.IOException; -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; -import java.util.concurrent.atomic.AtomicBoolean; - -/** - * A JobManager allows you to enqueue {@link org.whispersystems.jobqueue.Job} tasks - * that are executed once a Job's {@link org.whispersystems.jobqueue.requirements.Requirement}s - * are met. - */ -public class JobManager implements RequirementListener { - - private final JobQueue jobQueue = new JobQueue(); - private final Executor eventExecutor = Executors.newSingleThreadExecutor(); - private final AtomicBoolean hasLoadedEncrypted = new AtomicBoolean(false); - - private final PersistentStorage persistentStorage; - private final List requirementProviders; - private final DependencyInjector dependencyInjector; - - private JobManager(Context context, String name, - List requirementProviders, - DependencyInjector dependencyInjector, - JobSerializer jobSerializer, int consumers) - { - this.persistentStorage = new PersistentStorage(context, name, jobSerializer, dependencyInjector); - this.requirementProviders = requirementProviders; - this.dependencyInjector = dependencyInjector; - - eventExecutor.execute(new LoadTask(null)); - - if (requirementProviders != null && !requirementProviders.isEmpty()) { - for (RequirementProvider provider : requirementProviders) { - provider.setListener(this); - } - } - - for (int i=0;i pendingJobs; - - if (keys == null) pendingJobs = persistentStorage.getAllUnencrypted(); - else pendingJobs = persistentStorage.getAllEncrypted(keys); - - jobQueue.addAll(pendingJobs); - } - } - - public static class Builder { - private final Context context; - private String name; - private List requirementProviders; - private DependencyInjector dependencyInjector; - private JobSerializer jobSerializer; - private int consumerThreads; - - Builder(Context context) { - this.context = context; - this.consumerThreads = 5; - } - - /** - * A name for the {@link org.whispersystems.jobqueue.JobManager}. This is a required parameter, - * and is linked to the durable queue used by persistent jobs. - * - * @param name The name for the JobManager to build. - * @return The builder. - */ - public Builder withName(String name) { - this.name = name; - return this; - } - - /** - * The {@link org.whispersystems.jobqueue.requirements.RequirementProvider}s to register with this - * JobManager. Optional. Each {@link org.whispersystems.jobqueue.requirements.Requirement} an - * enqueued Job depends on should have a matching RequirementProvider registered here. - * - * @param requirementProviders The RequirementProviders - * @return The builder. - */ - public Builder withRequirementProviders(RequirementProvider... requirementProviders) { - this.requirementProviders = Arrays.asList(requirementProviders); - return this; - } - - /** - * The {@link org.whispersystems.jobqueue.dependencies.DependencyInjector} to use for injecting - * dependencies into {@link Job}s. Optional. Injection occurs just before a Job's onAdded() callback, or - * after deserializing a persistent job. - * - * @param dependencyInjector The injector to use. - * @return The builder. - */ - public Builder withDependencyInjector(DependencyInjector dependencyInjector) { - this.dependencyInjector = dependencyInjector; - return this; - } - - /** - * The {@link org.whispersystems.jobqueue.persistence.JobSerializer} to use for persistent Jobs. - * Required if persistent Jobs are used. - * - * @param jobSerializer The serializer to use. - * @return The builder. - */ - public Builder withJobSerializer(JobSerializer jobSerializer) { - this.jobSerializer = jobSerializer; - return this; - } - - /** - * Set the number of threads dedicated to consuming Jobs from the queue and executing them. - * - * @param consumerThreads The number of threads. - * @return The builder. - */ - public Builder withConsumerThreads(int consumerThreads) { - this.consumerThreads = consumerThreads; - return this; - } - - /** - * @return A constructed JobManager. - */ - public JobManager build() { - if (name == null) { - throw new IllegalArgumentException("You must specify a name!"); - } - - if (requirementProviders == null) { - requirementProviders = new LinkedList<>(); - } - - return new JobManager(context, name, requirementProviders, - dependencyInjector, jobSerializer, - consumerThreads); - } - } - -} diff --git a/jobqueue/src/main/java/org/whispersystems/jobqueue/JobParameters.java b/jobqueue/src/main/java/org/whispersystems/jobqueue/JobParameters.java deleted file mode 100644 index ff6951779..000000000 --- a/jobqueue/src/main/java/org/whispersystems/jobqueue/JobParameters.java +++ /dev/null @@ -1,149 +0,0 @@ -/** - * Copyright (C) 2014 Open Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.whispersystems.jobqueue; - -import org.whispersystems.jobqueue.requirements.Requirement; - -import java.io.Serializable; -import java.util.LinkedList; -import java.util.List; - -/** - * The set of parameters that describe a {@link org.whispersystems.jobqueue.Job}. - */ -public class JobParameters implements Serializable { - - private transient EncryptionKeys encryptionKeys; - - private final List requirements; - private final boolean isPersistent; - private final int retryCount; - private final String groupId; - - private JobParameters(List requirements, - boolean isPersistent, String groupId, - EncryptionKeys encryptionKeys, - int retryCount) - { - this.requirements = requirements; - this.isPersistent = isPersistent; - this.groupId = groupId; - this.encryptionKeys = encryptionKeys; - this.retryCount = retryCount; - } - - public List getRequirements() { - return requirements; - } - - public boolean isPersistent() { - return isPersistent; - } - - public EncryptionKeys getEncryptionKeys() { - return encryptionKeys; - } - - public void setEncryptionKeys(EncryptionKeys encryptionKeys) { - this.encryptionKeys = encryptionKeys; - } - - public int getRetryCount() { - return retryCount; - } - - /** - * @return a builder used to construct JobParameters. - */ - public static Builder newBuilder() { - return new Builder(); - } - - public String getGroupId() { - return groupId; - } - - public static class Builder { - private List requirements = new LinkedList<>(); - private boolean isPersistent = false; - private EncryptionKeys encryptionKeys = null; - private int retryCount = 100; - private String groupId = null; - - /** - * Specify a {@link org.whispersystems.jobqueue.requirements.Requirement }that must be met - * before the Job is executed. May be called multiple times to register multiple requirements. - * @param requirement The Requirement that must be met. - * @return the builder. - */ - public Builder withRequirement(Requirement requirement) { - this.requirements.add(requirement); - return this; - } - - /** - * Specify that the Job should be durably persisted to disk, so that it remains in the queue - * across application restarts. - * @return The builder. - */ - public Builder withPersistence() { - this.isPersistent = true; - return this; - } - - /** - * Specify that the job should use encryption when durably persisted to disk. - * @param encryptionKeys The keys to encrypt the serialized job with before persisting. - * @return the builder. - */ - public Builder withEncryption(EncryptionKeys encryptionKeys) { - this.encryptionKeys = encryptionKeys; - return this; - } - - /** - * Specify how many times the job should be retried if execution fails but onShouldRetry() returns - * true. - * - * @param retryCount The number of times the job should be retried. - * @return the builder. - */ - public Builder withRetryCount(int retryCount) { - this.retryCount = retryCount; - return this; - } - - /** - * Specify a groupId the job should belong to. Jobs with the same groupId are guaranteed to be - * executed serially. - * - * @param groupId The job's groupId. - * @return the builder. - */ - public Builder withGroupId(String groupId) { - this.groupId = groupId; - return this; - } - - /** - * @return the JobParameters instance that describes a Job. - */ - public JobParameters create() { - return new JobParameters(requirements, isPersistent, groupId, encryptionKeys, retryCount); - } - } -} diff --git a/jobqueue/src/main/java/org/whispersystems/jobqueue/JobQueue.java b/jobqueue/src/main/java/org/whispersystems/jobqueue/JobQueue.java deleted file mode 100644 index 7d098c0c4..000000000 --- a/jobqueue/src/main/java/org/whispersystems/jobqueue/JobQueue.java +++ /dev/null @@ -1,95 +0,0 @@ -/** - * Copyright (C) 2014 Open Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.whispersystems.jobqueue; - -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.ListIterator; -import java.util.Set; - -class JobQueue { - - private final Set activeGroupIds = new HashSet<>(); - private final LinkedList jobQueue = new LinkedList<>(); - - synchronized void onRequirementStatusChanged() { - notifyAll(); - } - - synchronized void add(Job job) { - jobQueue.add(job); - notifyAll(); - } - - synchronized void addAll(List jobs) { - jobQueue.addAll(jobs); - notifyAll(); - } - - synchronized void push(Job job) { - jobQueue.push(job); - } - - synchronized Job getNext() { - try { - Job nextAvailableJob; - - while ((nextAvailableJob = getNextAvailableJob()) == null) { - wait(); - } - - return nextAvailableJob; - } catch (InterruptedException e) { - throw new AssertionError(e); - } - } - - synchronized void setGroupIdAvailable(String groupId) { - if (groupId != null) { - activeGroupIds.remove(groupId); - notifyAll(); - } - } - - private Job getNextAvailableJob() { - if (jobQueue.isEmpty()) return null; - - ListIterator iterator = jobQueue.listIterator(); - while (iterator.hasNext()) { - Job job = iterator.next(); - - if (job.isRequirementsMet() && isGroupIdAvailable(job.getGroupId())) { - iterator.remove(); - setGroupIdUnavailable(job.getGroupId()); - return job; - } - } - - return null; - } - - private boolean isGroupIdAvailable(String groupId) { - return groupId == null || !activeGroupIds.contains(groupId); - } - - private void setGroupIdUnavailable(String groupId) { - if (groupId != null) { - activeGroupIds.add(groupId); - } - } -} diff --git a/jobqueue/src/main/java/org/whispersystems/jobqueue/dependencies/ContextDependent.java b/jobqueue/src/main/java/org/whispersystems/jobqueue/dependencies/ContextDependent.java deleted file mode 100644 index 1cdaadc64..000000000 --- a/jobqueue/src/main/java/org/whispersystems/jobqueue/dependencies/ContextDependent.java +++ /dev/null @@ -1,27 +0,0 @@ -/** -* Copyright (C) 2014 Open Whisper Systems -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ -package org.whispersystems.jobqueue.dependencies; - -import android.content.Context; - -/** - * Any Job or Requirement that depends on {@link android.content.Context} can implement this - * interface to receive a Context after being deserialized. - */ -public interface ContextDependent { - public void setContext(Context context); -} diff --git a/jobqueue/src/main/java/org/whispersystems/jobqueue/dependencies/DependencyInjector.java b/jobqueue/src/main/java/org/whispersystems/jobqueue/dependencies/DependencyInjector.java deleted file mode 100644 index cb396bed1..000000000 --- a/jobqueue/src/main/java/org/whispersystems/jobqueue/dependencies/DependencyInjector.java +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Copyright (C) 2014 Open Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.whispersystems.jobqueue.dependencies; - -/** - * Interface responsible for injecting dependencies into Jobs. - */ -public interface DependencyInjector { - public void injectDependencies(Object object); -} diff --git a/jobqueue/src/main/java/org/whispersystems/jobqueue/persistence/JavaJobSerializer.java b/jobqueue/src/main/java/org/whispersystems/jobqueue/persistence/JavaJobSerializer.java deleted file mode 100644 index ebb088644..000000000 --- a/jobqueue/src/main/java/org/whispersystems/jobqueue/persistence/JavaJobSerializer.java +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Copyright (C) 2014 Open Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.whispersystems.jobqueue.persistence; - -import android.util.Base64; - -import org.whispersystems.jobqueue.EncryptionKeys; -import org.whispersystems.jobqueue.Job; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; - -/** - * An implementation of {@link org.whispersystems.jobqueue.persistence.JobSerializer} that uses - * Java Serialization. - */ -public class JavaJobSerializer implements JobSerializer { - - public JavaJobSerializer() {} - - @Override - public String serialize(Job job) throws IOException { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream oos = new ObjectOutputStream(baos); - oos.writeObject(job); - - return Base64.encodeToString(baos.toByteArray(), Base64.NO_WRAP); - } - - @Override - public Job deserialize(EncryptionKeys keys, boolean encrypted, String serialized) throws IOException { - try { - ByteArrayInputStream bais = new ByteArrayInputStream(Base64.decode(serialized, Base64.NO_WRAP)); - ObjectInputStream ois = new ObjectInputStream(bais); - - return (Job)ois.readObject(); - } catch (ClassNotFoundException e) { - throw new IOException(e); - } - } -} diff --git a/jobqueue/src/main/java/org/whispersystems/jobqueue/persistence/JobSerializer.java b/jobqueue/src/main/java/org/whispersystems/jobqueue/persistence/JobSerializer.java deleted file mode 100644 index 6c0384e65..000000000 --- a/jobqueue/src/main/java/org/whispersystems/jobqueue/persistence/JobSerializer.java +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright (C) 2014 Open Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.whispersystems.jobqueue.persistence; - -import org.whispersystems.jobqueue.EncryptionKeys; -import org.whispersystems.jobqueue.Job; - -import java.io.IOException; - -/** - * A JobSerializer is responsible for serializing and deserializing persistent jobs. - */ -public interface JobSerializer { - - /** - * Serialize a job object into a string. - * @param job The Job to serialize. - * @return The serialized Job. - * @throws IOException if serialization fails. - */ - public String serialize(Job job) throws IOException; - - /** - * Deserialize a String into a Job. - * @param keys Optional encryption keys that could have been used. - * @param encrypted True if the job was encrypted using the encryption keys. - * @param serialized The serialized Job. - * @return The deserialized Job. - * @throws IOException If the Job deserialization fails. - */ - public Job deserialize(EncryptionKeys keys, boolean encrypted, String serialized) throws IOException; - -} diff --git a/jobqueue/src/main/java/org/whispersystems/jobqueue/persistence/PersistentStorage.java b/jobqueue/src/main/java/org/whispersystems/jobqueue/persistence/PersistentStorage.java deleted file mode 100644 index dda9c985e..000000000 --- a/jobqueue/src/main/java/org/whispersystems/jobqueue/persistence/PersistentStorage.java +++ /dev/null @@ -1,152 +0,0 @@ -/** - * Copyright (C) 2014 Open Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.whispersystems.jobqueue.persistence; - -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteOpenHelper; -import android.util.Log; - -import org.whispersystems.jobqueue.EncryptionKeys; -import org.whispersystems.jobqueue.Job; -import org.whispersystems.jobqueue.dependencies.ContextDependent; -import org.whispersystems.jobqueue.dependencies.DependencyInjector; -import org.whispersystems.jobqueue.requirements.Requirement; - -import java.io.IOException; -import java.util.LinkedList; -import java.util.List; - -public class PersistentStorage { - - private static final int DATABASE_VERSION = 1; - - private static final String TABLE_NAME = "queue"; - private static final String ID = "_id"; - private static final String ITEM = "item"; - private static final String ENCRYPTED = "encrypted"; - - private static final String DATABASE_CREATE = String.format("CREATE TABLE %s (%s INTEGER PRIMARY KEY, %s TEXT NOT NULL, %s INTEGER DEFAULT 0);", - TABLE_NAME, ID, ITEM, ENCRYPTED); - - private final Context context; - private final DatabaseHelper databaseHelper; - private final JobSerializer jobSerializer; - private final DependencyInjector dependencyInjector; - - public PersistentStorage(Context context, String name, - JobSerializer serializer, - DependencyInjector dependencyInjector) - { - this.databaseHelper = new DatabaseHelper(context, "_jobqueue-" + name); - this.context = context; - this.jobSerializer = serializer; - this.dependencyInjector = dependencyInjector; - } - - public void store(Job job) throws IOException { - ContentValues contentValues = new ContentValues(); - contentValues.put(ITEM, jobSerializer.serialize(job)); - contentValues.put(ENCRYPTED, job.getEncryptionKeys() != null); - - long id = databaseHelper.getWritableDatabase().insert(TABLE_NAME, null, contentValues); - job.setPersistentId(id); - } - - public List getAllUnencrypted() { - return getJobs(null, ENCRYPTED + " = 0"); - } - - public List getAllEncrypted(EncryptionKeys keys) { - return getJobs(keys, ENCRYPTED + " = 1"); - } - - private List getJobs(EncryptionKeys keys, String where) { - List results = new LinkedList<>(); - SQLiteDatabase database = databaseHelper.getReadableDatabase(); - Cursor cursor = null; - - try { - cursor = database.query(TABLE_NAME, null, where, null, null, null, ID + " ASC", null); - - while (cursor.moveToNext()) { - long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID)); - String item = cursor.getString(cursor.getColumnIndexOrThrow(ITEM)); - boolean encrypted = cursor.getInt(cursor.getColumnIndexOrThrow(ENCRYPTED)) == 1; - - try{ - Job job = jobSerializer.deserialize(keys, encrypted, item); - - job.setPersistentId(id); - job.setEncryptionKeys(keys); - injectDependencies(job); - - results.add(job); - } catch (IOException e) { - Log.w("PersistentStore", e); - remove(id); - } - } - } finally { - if (cursor != null) - cursor.close(); - } - - return results; - } - - public void remove(long id) { - databaseHelper.getWritableDatabase() - .delete(TABLE_NAME, ID + " = ?", new String[] {String.valueOf(id)}); - } - - private void injectDependencies(Job job) { - if (job instanceof ContextDependent) { - ((ContextDependent)job).setContext(context); - } - - for (Requirement requirement : job.getRequirements()) { - if (requirement instanceof ContextDependent) { - ((ContextDependent)requirement).setContext(context); - } - } - - if (dependencyInjector != null) { - dependencyInjector.injectDependencies(job); - } - } - - private static class DatabaseHelper extends SQLiteOpenHelper { - - public DatabaseHelper(Context context, String name) { - super(context, name, null, DATABASE_VERSION); - } - - @Override - public void onCreate(SQLiteDatabase db) { - db.execSQL(DATABASE_CREATE); - } - - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - - } - } - -} diff --git a/jobqueue/src/main/java/org/whispersystems/jobqueue/requirements/NetworkRequirement.java b/jobqueue/src/main/java/org/whispersystems/jobqueue/requirements/NetworkRequirement.java deleted file mode 100644 index 315a6c678..000000000 --- a/jobqueue/src/main/java/org/whispersystems/jobqueue/requirements/NetworkRequirement.java +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright (C) 2014 Open Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.whispersystems.jobqueue.requirements; - -import android.content.Context; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; - -import org.whispersystems.jobqueue.dependencies.ContextDependent; - -/** - * A requirement that is satisfied when a network connection is present. - */ -public class NetworkRequirement implements Requirement, ContextDependent { - - private transient Context context; - - public NetworkRequirement(Context context) { - this.context = context; - } - - public NetworkRequirement() {} - - @Override - public boolean isPresent() { - ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkInfo netInfo = cm.getActiveNetworkInfo(); - - return netInfo != null && netInfo.isConnectedOrConnecting(); - } - - @Override - public void setContext(Context context) { - this.context = context; - } -} diff --git a/jobqueue/src/main/java/org/whispersystems/jobqueue/requirements/NetworkRequirementProvider.java b/jobqueue/src/main/java/org/whispersystems/jobqueue/requirements/NetworkRequirementProvider.java deleted file mode 100644 index a15c58cd7..000000000 --- a/jobqueue/src/main/java/org/whispersystems/jobqueue/requirements/NetworkRequirementProvider.java +++ /dev/null @@ -1,59 +0,0 @@ -/** - * Copyright (C) 2014 Open Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.whispersystems.jobqueue.requirements; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; - -public class NetworkRequirementProvider implements RequirementProvider { - - private RequirementListener listener; - - private final NetworkRequirement requirement; - - public NetworkRequirementProvider(Context context) { - this.requirement = new NetworkRequirement(context); - - context.getApplicationContext().registerReceiver(new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (listener == null) { - return; - } - - if (requirement.isPresent()) { - listener.onRequirementStatusChanged(); - } - } - }, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)); - } - - @Override - public String getName() { - return "network"; - } - - @Override - public void setListener(RequirementListener listener) { - this.listener = listener; - } - -} diff --git a/jobqueue/src/main/java/org/whispersystems/jobqueue/requirements/Requirement.java b/jobqueue/src/main/java/org/whispersystems/jobqueue/requirements/Requirement.java deleted file mode 100644 index 27a9aa493..000000000 --- a/jobqueue/src/main/java/org/whispersystems/jobqueue/requirements/Requirement.java +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Copyright (C) 2014 Open Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.whispersystems.jobqueue.requirements; - -import java.io.Serializable; - -/** - * A Requirement that must be satisfied before a Job can run. - */ -public interface Requirement extends Serializable { - /** - * @return true if the requirement is satisfied, false otherwise. - */ - public boolean isPresent(); -} diff --git a/jobqueue/src/main/java/org/whispersystems/jobqueue/requirements/RequirementListener.java b/jobqueue/src/main/java/org/whispersystems/jobqueue/requirements/RequirementListener.java deleted file mode 100644 index 2b2cb1b64..000000000 --- a/jobqueue/src/main/java/org/whispersystems/jobqueue/requirements/RequirementListener.java +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Copyright (C) 2014 Open Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.whispersystems.jobqueue.requirements; - -public interface RequirementListener { - public void onRequirementStatusChanged(); -} diff --git a/jobqueue/src/main/java/org/whispersystems/jobqueue/requirements/RequirementProvider.java b/jobqueue/src/main/java/org/whispersystems/jobqueue/requirements/RequirementProvider.java deleted file mode 100644 index 5091ec16d..000000000 --- a/jobqueue/src/main/java/org/whispersystems/jobqueue/requirements/RequirementProvider.java +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright (C) 2014 Open Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.whispersystems.jobqueue.requirements; - -/** - * Notifies listeners when a {@link org.whispersystems.jobqueue.requirements.Requirement}'s - * state is likely to have changed. - */ -public interface RequirementProvider { - /** - * @return The name of the provider. - */ - public String getName(); - - /** - * The {@link org.whispersystems.jobqueue.requirements.RequirementListener} to call when - * a {@link org.whispersystems.jobqueue.requirements.Requirement}'s status is likely to - * have changed. - * - * @param listener The listener to call. - */ - public void setListener(RequirementListener listener); -} diff --git a/jobqueue/src/main/res/values/strings.xml b/jobqueue/src/main/res/values/strings.xml deleted file mode 100644 index 854200555..000000000 --- a/jobqueue/src/main/res/values/strings.xml +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/settings.gradle b/settings.gradle index 73a41872d..7bb255bf2 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include ':libtextsecure', ':libaxolotl', ':jobqueue' +include ':libtextsecure', ':libaxolotl'