diff --git a/biz.aQute.api/bnd.bnd b/biz.aQute.api/bnd.bnd index 841b3793..f6893200 100644 --- a/biz.aQute.api/bnd.bnd +++ b/biz.aQute.api/bnd.bnd @@ -10,6 +10,7 @@ org.osgi.dto,\ org.apache.felix.http.servlet-api,\ org.osgi.service.component.annotations,\ - org.osgi.namespace.extender + org.osgi.namespace.extender,\ + org.osgi.service.metatype.annotations -sub: *.bnd \ No newline at end of file diff --git a/biz.aQute.api/src/main/java/biz/aQute/scheduler/api/Constants.java b/biz.aQute.api/src/main/java/biz/aQute/scheduler/api/Constants.java new file mode 100644 index 00000000..966b3807 --- /dev/null +++ b/biz.aQute.api/src/main/java/biz/aQute/scheduler/api/Constants.java @@ -0,0 +1,83 @@ +package biz.aQute.scheduler.api; + +public final class Constants { + + private Constants() { + // Constants + } + + /** + * Specification Name + */ + public static final String SPECIFICATION_NAME = "aqute.scheduler"; + + /** + * Specification Version + */ + public static final String SPECIFICATION_VERSION = "1.1.0"; + + /** + * The service property Prefix for cronjobs + */ + public static final String SERVICE_PROPERTY_CRONJOB_PREFIX = "cronjob"; + + /** + * The service property that specifies the cron schedule. The type is String+. + */ + public static final String SERVICE_PROPERTY_CRONJOB_CRON = SERVICE_PROPERTY_CRONJOB_PREFIX+".cron"; + + /** + * The service property that specifies the name of the cron job. The type is + * String. + */ + public static final String SERVICE_PROPERTY_CRONJOB_NAME = SERVICE_PROPERTY_CRONJOB_PREFIX+".name"; + + /** + * Default name of the cron job. + */ + public static final String CRONJOB_NAME_DEFAULT = "unknown"; + + /** + * the named cron expression for annually execution. + */ + public static final String CRON_EXPRESSION_ANNUALLY = "@annually"; + + /** + * the named cron expression for yearly execution. + */ + public static final String CRON_EXPRESSION_YEARLY = "@yearly"; + + /** + * the named cron expression for monthly execution. + */ + public static final String CRON_EXPRESSION_MONTHLY = "@monthly"; + /** + * the named cron expression for weekly execution. + */ + public static final String CRON_EXPRESSION_WEEKLY = "@weekly"; + + /** + * the named cron expression for daily execution. + */ + public static final String CRON_EXPRESSION_DAYLY = "@daily"; + + /** + * the named cron expression for hourly execution. + */ + public static final String CRON_EXPRESSION_HOURLY = "@hourly"; + + /** + * the named cron expression for minutely execution. + */ + public static final String CRON_EXPRESSION_MINUTLY = "@minutely"; + + /** + * the named cron expression for secondly execution. + */ + public static final String CRON_EXPRESSION_SECUNDLY = "@secondly"; + + /** + * the named cron expression for execution onreboot. + */ + public static final String CRON_EXPRESSION_REBOOT = "@reboot"; +} diff --git a/biz.aQute.api/src/main/java/biz/aQute/scheduler/api/CronExpression.java b/biz.aQute.api/src/main/java/biz/aQute/scheduler/api/CronExpression.java index e6ce78b7..0baa3b5e 100644 --- a/biz.aQute.api/src/main/java/biz/aQute/scheduler/api/CronExpression.java +++ b/biz.aQute.api/src/main/java/biz/aQute/scheduler/api/CronExpression.java @@ -1,18 +1,32 @@ package biz.aQute.scheduler.api; import org.osgi.service.component.annotations.ComponentPropertyType; +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; /** * An annotation to simplify using a CronJob */ @ComponentPropertyType +@ObjectClassDefinition +@RequireSchedulerImplementation public @interface CronExpression { + public static final String PREFIX_ = Constants.SERVICE_PROPERTY_CRONJOB_PREFIX; /** - * The 'cron.expression' service property + * The 'cronjob.cron' service property as defines in {@link Constants#SERVICE_PROPERTY_CRONJOB_CRON} * @return */ - String cron(); + @AttributeDefinition(name="cronJobCronExpression", description = "Cron Expression according the Cron Spec. see http://en.wikipedia.org/wiki/Cron") + String[] cron(); + + /** + * The 'cronjob.name' service property as defines in {@link Constants#SERVIC_PROPERTY_CRON_NAME()()} + * @return + */ + @AttributeDefinition(name="cronJobName", description = "Human readable name of the cronjob") + String name() default Constants.CRONJOB_NAME_DEFAULT; + } diff --git a/biz.aQute.api/src/main/java/biz/aQute/scheduler/api/CronJob.java b/biz.aQute.api/src/main/java/biz/aQute/scheduler/api/CronJob.java index 8f5ca276..5ba6d7b1 100644 --- a/biz.aQute.api/src/main/java/biz/aQute/scheduler/api/CronJob.java +++ b/biz.aQute.api/src/main/java/biz/aQute/scheduler/api/CronJob.java @@ -11,7 +11,7 @@ * chronos. *
* The Unix Cron defines a syntax that is used by the Cron service. A user - * should register a Cron service with the {@value CronJob#CRON} property. The + * should register a Cron service with the {@value Constants#SERVICE_PROPERTY_CRONJOB_CRON} property. The * value is according to the {link http://en.wikipedia.org/wiki/Cron}. *
*
@@ -77,8 +77,15 @@ public interface CronJob {
/**
* The service property that specifies the cron schedule. The type is
* String+.
+ * @deprecated use {@link Constants#SERVICE_PROPERTY_CRONJOB_CRON} "cron.expression";
*/
+ @Deprecated
String CRON = "cron";
+
+ /**
+ * @deprecated use {@link Constants#SERVICE_PROPERTY_CRONJOB_NAME} "cron.name";
+ */
+ @Deprecated
String NAME = "name";
/**
diff --git a/biz.aQute.api/src/main/java/biz/aQute/scheduler/api/RequireSchedulerImplementation.java b/biz.aQute.api/src/main/java/biz/aQute/scheduler/api/RequireSchedulerImplementation.java
new file mode 100644
index 00000000..8503200e
--- /dev/null
+++ b/biz.aQute.api/src/main/java/biz/aQute/scheduler/api/RequireSchedulerImplementation.java
@@ -0,0 +1,17 @@
+package biz.aQute.scheduler.api;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import org.osgi.annotation.bundle.Requirement;
+import org.osgi.namespace.implementation.ImplementationNamespace;
+
+/**
+ * Require an implementation for the this specification
+ */
+@Requirement(namespace = ImplementationNamespace.IMPLEMENTATION_NAMESPACE, filter = "(&("
+ + ImplementationNamespace.IMPLEMENTATION_NAMESPACE + "="
+ + Constants.SPECIFICATION_NAME + ")${frange;${version;==;"
+ + Constants.SPECIFICATION_VERSION + "}})")
+@Retention(RetentionPolicy.CLASS)
+public @interface RequireSchedulerImplementation {}
\ No newline at end of file
diff --git a/biz.aQute.api/src/main/java/biz/aQute/scheduler/api/Scheduler.java b/biz.aQute.api/src/main/java/biz/aQute/scheduler/api/Scheduler.java
index 444b3e12..49f476da 100644
--- a/biz.aQute.api/src/main/java/biz/aQute/scheduler/api/Scheduler.java
+++ b/biz.aQute.api/src/main/java/biz/aQute/scheduler/api/Scheduler.java
@@ -1,5 +1,6 @@
package biz.aQute.scheduler.api;
+import java.time.Duration;
import java.time.temporal.TemporalAdjuster;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
@@ -21,12 +22,41 @@ interface RunnableWithException {
* Schedule a runnable to run periodically at a fixed rate. The schedule can
* be canceled by the returned task.
*
+ * @param runnable
+ * the task to run
+ * @param name
+ * The name of the task
+ * @param fixedRateInMs
+ * The fixed rate in milliseconds.
+ *
+ */
+ Task periodic(Runnable runnable, long fixedRateInMs, String name);
+
+ /**
+ * Schedule a runnable to run periodically at a fixed rate. The schedule can
+ * be canceled by the returned task.
+ *
+ * @param runnable
+ * the task to run
+ * @param name
+ * The name of the task
+ * @param fixedRate
+ * The fixed rate in milliseconds.
+ *
+ */
+ Task periodic(Runnable runnable, Duration fixedRate, String name);
+ /**
+ * Schedule a runnable to run after a certain time. The schedule can be
+ * canceled by the returned task if it was not yet canceled.
+ *
* @param name
* The name of the task
* @param runnable
* the task to run
+ * @param afterMs
+ * time in ms after the run is scheduled.
*/
- Task periodic(Runnable runnable, long ms, String name);
+ Task after(Runnable runnable, long afterMs, String name);
/**
* Schedule a runnable to run after a certain time. The schedule can be
@@ -36,8 +66,10 @@ interface RunnableWithException {
* The name of the task
* @param runnable
* the task to run
+ * @param after
+ * duration after the run is scheduled.
*/
- Task after(Runnable runnable, long ms, String name);
+ Task after(Runnable runnable, Duration after, String name);
/**
* Executes a task in the background, intended for short term tasks
@@ -69,7 +101,7 @@ interface RunnableWithException {
/**
* Schedule a runnable to be executed for the give cron expression (See
- * {@link CronJob}). Every time when the cronExpression matches the current
+ * {@link CronExpression#expression()}). Every time when the cronExpression matches the current
* time, the runnable will be run. The method returns a closeable that can
* be used to stop scheduling. This variation does not take an environment
* object.
@@ -96,7 +128,7 @@ interface RunnableWithException {
* ZonedDateTime next = now.with(cron);
*
*
- * @param cronExpression a Cron expression as specified in {@link CronJob}
+ * @param cronExpression a Cron expression as specified in {@link CronExpression#expression()}
* @return a Temporal Adjuster based on a cron expression
*/
TemporalAdjuster getCronAdjuster(String cronExpression);
diff --git a/biz.aQute.api/src/main/java/biz/aQute/scheduler/api/package-info.java b/biz.aQute.api/src/main/java/biz/aQute/scheduler/api/package-info.java
index 84b7d5b2..46074a40 100644
--- a/biz.aQute.api/src/main/java/biz/aQute/scheduler/api/package-info.java
+++ b/biz.aQute.api/src/main/java/biz/aQute/scheduler/api/package-info.java
@@ -1,5 +1,5 @@
@org.osgi.annotation.bundle.Export
-@Version("1.0.0")
+@Version(biz.aQute.scheduler.api.Constants.SPECIFICATION_VERSION)
package biz.aQute.scheduler.api;
import org.osgi.annotation.versioning.Version;
diff --git a/biz.aQute.scheduler.basic.provider/bnd.bnd b/biz.aQute.scheduler.basic.provider/bnd.bnd
index 33649075..814d01ec 100644
--- a/biz.aQute.scheduler.basic.provider/bnd.bnd
+++ b/biz.aQute.scheduler.basic.provider/bnd.bnd
@@ -8,8 +8,9 @@
slf4j.api,\
biz.aQute.api.scheduler,\
org.osgi.util.promise,\
- aQute.libg,\
- org.osgi.service.metatype.annotations
+ org.osgi.service.metatype.annotations,\
+ org.osgi.util.converter,\
+ org.osgi.namespace.implementation
-testpath: \
@@ -18,8 +19,8 @@
org.assertj.core,\
org.awaitility,\
biz.aQute.launchpad,\
+ aQute.libg,\
osgi.core, \
- slf4j.api, \
+ org.osgi.util.function,\
+ slf4j.api,\
slf4j.simple
-
--conditionalpackage: aQute.lib*
\ No newline at end of file
diff --git a/biz.aQute.scheduler.basic.provider/src/main/java/biz/aQute/scheduler/basic/config/SchedulerConfig.java b/biz.aQute.scheduler.basic.provider/src/main/java/biz/aQute/scheduler/basic/config/SchedulerConfig.java
index 16ffad44..710f5bd6 100644
--- a/biz.aQute.scheduler.basic.provider/src/main/java/biz/aQute/scheduler/basic/config/SchedulerConfig.java
+++ b/biz.aQute.scheduler.basic.provider/src/main/java/biz/aQute/scheduler/basic/config/SchedulerConfig.java
@@ -1,20 +1,27 @@
package biz.aQute.scheduler.basic.config;
+import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;
-/**
- * Configuration for the scheduler. The scheduler is a singleton
- */
-
-@ObjectClassDefinition
+@ObjectClassDefinition( description = "Configuration for the scheduler. The scheduler is a singleton")
public @interface SchedulerConfig {
String PID = "biz.aQute.scheduler.basic";
String SYSTEM_DEFAULT_TIMEZONE = "system.default.timezone";
+ String DESCRIPTION = "Set the time zone. The default is the system default time zone. "
+ + "If the time zone does not exist, an error is logged and the system default time zone is used.";
+ int COREPOOLSIZE_DEFAUL = 50;
+ int SHUTDOWNTIMEOUT_SOFT_DEFAUL = 500;
+ int SHUTDOWNTIMEOUT_HARD_DEFAUL = 5000;
- /**
- * Set the time zone. The default is the system default time zone. If the
- * time zone does not exist, an error is logged and the system default time zone is
- * used.
- */
+ @AttributeDefinition(description = DESCRIPTION)
String timeZone() default SYSTEM_DEFAULT_TIMEZONE;
+
+ @AttributeDefinition(description = "corePoolSize of ScheduledThreadPoolExecutor")
+ int corePoolSize() default COREPOOLSIZE_DEFAUL;
+
+ @AttributeDefinition(description = "Expected shutdownTimeout of ScheduledThreadPoolExecutor")
+ int shutdownTimeoutSoft() default SHUTDOWNTIMEOUT_SOFT_DEFAUL;
+
+ @AttributeDefinition(description = "Expected shutdownTimeout after the shutdownTimeoutSoft befor the shutdown of ScheduledThreadPoolExecutor is forced")
+ int shutdownTimeoutHard() default SHUTDOWNTIMEOUT_HARD_DEFAUL;
}
\ No newline at end of file
diff --git a/biz.aQute.scheduler.basic.provider/src/main/java/biz/aQute/scheduler/basic/config/package-info.java b/biz.aQute.scheduler.basic.provider/src/main/java/biz/aQute/scheduler/basic/config/package-info.java
index 5b3b7cff..b92d316c 100644
--- a/biz.aQute.scheduler.basic.provider/src/main/java/biz/aQute/scheduler/basic/config/package-info.java
+++ b/biz.aQute.scheduler.basic.provider/src/main/java/biz/aQute/scheduler/basic/config/package-info.java
@@ -1,5 +1,5 @@
@org.osgi.annotation.bundle.Export
-@Version("1.0.0")
+@Version("1.1.0")
package biz.aQute.scheduler.basic.config;
import org.osgi.annotation.versioning.Version;
diff --git a/biz.aQute.scheduler.basic.provider/src/main/java/biz/aQute/scheduler/basic/provider/CentralScheduler.java b/biz.aQute.scheduler.basic.provider/src/main/java/biz/aQute/scheduler/basic/provider/CentralScheduler.java
index 326b4bf9..8051c2a5 100644
--- a/biz.aQute.scheduler.basic.provider/src/main/java/biz/aQute/scheduler/basic/provider/CentralScheduler.java
+++ b/biz.aQute.scheduler.basic.provider/src/main/java/biz/aQute/scheduler/basic/provider/CentralScheduler.java
@@ -15,6 +15,8 @@
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
+import org.osgi.annotation.bundle.Capability;
+import org.osgi.namespace.implementation.ImplementationNamespace;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.ConfigurationPolicy;
@@ -25,12 +27,14 @@
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.component.annotations.ServiceScope;
import org.osgi.service.metatype.annotations.Designate;
+import org.osgi.util.converter.Converter;
+import org.osgi.util.converter.Converters;
import org.osgi.util.promise.Promise;
import org.osgi.util.promise.PromiseFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import aQute.lib.converter.Converter;
+import biz.aQute.scheduler.api.Constants;
import biz.aQute.scheduler.api.CronJob;
import biz.aQute.scheduler.api.Task;
import biz.aQute.scheduler.basic.config.SchedulerConfig;
@@ -48,19 +52,31 @@
configurationPolicy = ConfigurationPolicy.OPTIONAL,
name = SchedulerConfig.PID
)
+@Capability(
+ namespace = ImplementationNamespace.IMPLEMENTATION_NAMESPACE,
+ name = Constants.SPECIFICATION_NAME,
+ version = Constants.SPECIFICATION_VERSION
+)
//@formatter:on
public class CentralScheduler {
- final List