Skip to content

Commit dabf1dd

Browse files
committed
Add things
1 parent 0d6cb36 commit dabf1dd

23 files changed

+1429
-60
lines changed

pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
<grpc.version>1.69.0</grpc.version>
1818
<protobuf.version>3.25.5</protobuf.version>
1919
<protocCommand>protoc</protocCommand>
20-
<dapr.proto.baseurl>https://raw.githubusercontent.com/dapr/dapr/v1.14.4/dapr/proto</dapr.proto.baseurl>
20+
<dapr.proto.baseurl>https://raw.githubusercontent.com/dapr/dapr/v1.15.2/dapr/proto</dapr.proto.baseurl>
2121
<dapr.sdk.version>1.15.0-SNAPSHOT</dapr.sdk.version>
2222
<dapr.sdk.alpha.version>0.15.0-SNAPSHOT</dapr.sdk.alpha.version>
2323
<os-maven-plugin.version>1.7.1</os-maven-plugin.version>

sdk-jobs/pom.xml

+25-4
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
<artifactId>dapr-sdk-jobs</artifactId>
1414
<packaging>jar</packaging>
15-
<version>0.15.0-SNAPSHOT</version>
15+
<version>1.15.0-SNAPSHOT</version>
1616
<name>dapr-sdk-jobs</name>
1717
<description>SDK for Jobs on Dapr</description>
1818

@@ -24,12 +24,12 @@
2424
<dependency>
2525
<groupId>io.dapr</groupId>
2626
<artifactId>dapr-sdk</artifactId>
27-
<version>${project.parent.version}</version>
27+
<version>${project.version}</version>
2828
</dependency>
2929
<dependency>
3030
<groupId>io.dapr</groupId>
3131
<artifactId>dapr-sdk-autogen</artifactId>
32-
<version>1.15.0-SNAPSHOT</version>
32+
<version>${project.version}</version>
3333
</dependency>
3434
<dependency>
3535
<groupId>org.mockito</groupId>
@@ -50,13 +50,34 @@
5050
<dependency>
5151
<groupId>org.junit.vintage</groupId>
5252
<artifactId>junit-vintage-engine</artifactId>
53-
<version>5.7.0</version>
53+
<version>5.7.2</version>
5454
<scope>test</scope>
5555
</dependency>
56+
<dependency>
57+
<groupId>org.testng</groupId>
58+
<artifactId>testng</artifactId>
59+
<version>RELEASE</version>
60+
<scope>compile</scope>
61+
</dependency>
62+
<dependency>
63+
<groupId>org.junit.platform</groupId>
64+
<artifactId>junit-platform-console-standalone</artifactId>
65+
<version>1.11.4</version>
66+
<scope>compile</scope>
67+
</dependency>
68+
<dependency>
69+
<groupId>org.mockito</groupId>
70+
<artifactId>mockito-core</artifactId>
71+
<scope>compile</scope>
72+
</dependency>
5673
</dependencies>
5774

5875
<build>
5976
<plugins>
77+
<plugin>
78+
<groupId>org.sonatype.plugins</groupId>
79+
<artifactId>nexus-staging-maven-plugin</artifactId>
80+
</plugin>
6081
<plugin>
6182
<groupId>org.apache.maven.plugins</groupId>
6283
<artifactId>maven-source-plugin</artifactId>

sdk-jobs/src/main/java/io/dapr/jobs/client/CronExpressionBuilder.java

+6-7
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
* A builder class for constructing cron expressions. This class provides an easy way to construct cron expressions
99
* by adding individual values or ranges for each of the cron fields: seconds, minutes, hours, day of month,
1010
* day of week, and month of year. It supports adding steps and ranges for fields where appropriate.
11-
* <p>
1211
* Example usage:
1312
* <pre>
1413
* CronExpressionBuilder builder = new CronExpressionBuilder();
@@ -182,12 +181,12 @@ public String build() {
182181
this.dayOfMonth.add("*");
183182
}
184183

185-
return String.join(",", this.seconds) + " " +
186-
String.join(",", this.minutes) + " " +
187-
String.join(",", this.hours) + " " +
188-
String.join(",", this.dayOfMonth) + " " +
189-
String.join(",", this.monthOfYear) + " " +
190-
String.join(",", this.dayOfWeek);
184+
return String.join(",", this.seconds) + " "
185+
+ String.join(",", this.minutes) + " "
186+
+ String.join(",", this.hours) + " "
187+
+ String.join(",", this.dayOfMonth) + " "
188+
+ String.join(",", this.monthOfYear) + " "
189+
+ String.join(",", this.dayOfWeek);
191190
}
192191

193192
/**

sdk-jobs/src/main/java/io/dapr/jobs/client/CronPeriod.java

-2
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@
33
/**
44
* Represents the different fields of a cron expression that can be modified
55
* using the {@link CronExpressionBuilder}.
6-
* <p>
76
* Each enum value corresponds to a specific component of a cron schedule.
8-
* <p>
97
* Example usage:
108
* <pre>
119
* CronPeriod period = CronPeriod.MINUTES;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
package io.dapr.jobs.client;
2+
3+
import com.google.protobuf.Any;
4+
import com.google.protobuf.ByteString;
5+
import io.dapr.client.resiliency.ResiliencyOptions;
6+
import io.dapr.config.Properties;
7+
import io.dapr.exceptions.DaprException;
8+
import io.dapr.internal.exceptions.DaprHttpException;
9+
import io.dapr.internal.grpc.interceptors.DaprTimeoutInterceptor;
10+
import io.dapr.internal.grpc.interceptors.DaprTracingInterceptor;
11+
import io.dapr.internal.resiliency.RetryPolicy;
12+
import io.dapr.internal.resiliency.TimeoutPolicy;
13+
import io.dapr.utils.NetworkUtils;
14+
import io.dapr.v1.DaprGrpc;
15+
import io.dapr.v1.DaprProtos;
16+
import io.grpc.ManagedChannel;
17+
import io.grpc.stub.StreamObserver;
18+
import reactor.core.publisher.Mono;
19+
import reactor.core.publisher.MonoSink;
20+
import reactor.util.context.ContextView;
21+
22+
import java.time.OffsetDateTime;
23+
import java.util.function.Consumer;
24+
25+
public class DaprJobsClient implements AutoCloseable {
26+
27+
/**
28+
* Stub that has the method to call the conversation apis.
29+
*/
30+
private final DaprGrpc.DaprStub asyncStub;
31+
32+
/**
33+
* The retry policy.
34+
*/
35+
private final RetryPolicy retryPolicy;
36+
37+
/**
38+
* The timeout policy.
39+
*/
40+
private final TimeoutPolicy timeoutPolicy;
41+
42+
/**
43+
* Constructor to create conversation client.
44+
*/
45+
public DaprJobsClient() {
46+
this(DaprGrpc.newStub(NetworkUtils.buildGrpcManagedChannel(new Properties())), null);
47+
}
48+
49+
/**
50+
* Constructor.
51+
*
52+
* @param properties with client configuration options.
53+
* @param resiliencyOptions retry options.
54+
*/
55+
public DaprJobsClient(
56+
Properties properties,
57+
ResiliencyOptions resiliencyOptions) {
58+
this(DaprGrpc.newStub(NetworkUtils.buildGrpcManagedChannel(properties)), resiliencyOptions);
59+
}
60+
61+
/**
62+
* ConversationClient constructor.
63+
*
64+
* @param resiliencyOptions timeout and retry policies.
65+
*/
66+
protected DaprJobsClient(
67+
DaprGrpc.DaprStub asyncStub,
68+
ResiliencyOptions resiliencyOptions) {
69+
this.asyncStub = asyncStub;
70+
this.retryPolicy = new RetryPolicy(resiliencyOptions == null ? null : resiliencyOptions.getMaxRetries());
71+
this.timeoutPolicy = new TimeoutPolicy(resiliencyOptions == null ? null : resiliencyOptions.getTimeout());
72+
}
73+
74+
/**
75+
* Schedules a job using the provided job request details.
76+
*
77+
* @param createJobRequest The request containing the details of the job to schedule.
78+
* Must include a name and optional schedule, data, and other related properties.
79+
* @return A {@link Mono} that completes when the job scheduling operation is successful or raises an error.
80+
* @throws IllegalArgumentException If the request or its required fields like name are null or empty.
81+
*/
82+
public Mono<Void> scheduleJob(ScheduleJobRequest createJobRequest) {
83+
try {
84+
if (createJobRequest == null) {
85+
throw new IllegalArgumentException("scheduleJobRequest cannot be null");
86+
}
87+
88+
if (createJobRequest.getName() == null || createJobRequest.getName().isEmpty()) {
89+
throw new IllegalArgumentException("Name in the request cannot be null or empty");
90+
}
91+
92+
if (createJobRequest.getSchedule() == null && createJobRequest.getDueTime() == null) {
93+
throw new IllegalArgumentException("At least one of schedule or dueTime must be provided");
94+
}
95+
96+
DaprProtos.Job.Builder scheduleJobRequestBuilder = DaprProtos.Job.newBuilder();
97+
scheduleJobRequestBuilder.setName(createJobRequest.getName());
98+
99+
if (createJobRequest.getData() != null) {
100+
scheduleJobRequestBuilder.setData(Any.newBuilder()
101+
.setValue(ByteString.copyFrom(createJobRequest.getData())).build());
102+
}
103+
104+
if (createJobRequest.getSchedule() != null) {
105+
scheduleJobRequestBuilder.setSchedule(createJobRequest.getSchedule().getExpression());
106+
}
107+
108+
if (createJobRequest.getTtl() != null) {
109+
scheduleJobRequestBuilder.setTtl(createJobRequest.getTtl().toString());
110+
}
111+
112+
if (createJobRequest.getRepeats() != null) {
113+
scheduleJobRequestBuilder.setRepeats(createJobRequest.getRepeats());
114+
}
115+
116+
if (createJobRequest.getDueTime() != null) {
117+
scheduleJobRequestBuilder.setDueTime(createJobRequest.getDueTime().toString());
118+
}
119+
120+
DaprProtos.ScheduleJobRequest scheduleJobRequest = DaprProtos.ScheduleJobRequest.newBuilder()
121+
.setJob(scheduleJobRequestBuilder.build()).build();
122+
123+
Mono<DaprProtos.ScheduleJobResponse> scheduleJobResponseMono =
124+
Mono.deferContextual(context -> this.createMono(
125+
it -> intercept(context, asyncStub)
126+
.scheduleJobAlpha1(scheduleJobRequest, it)
127+
)
128+
);
129+
130+
return scheduleJobResponseMono.then();
131+
} catch (Exception ex) {
132+
return DaprException.wrapMono(ex);
133+
}
134+
}
135+
136+
/**
137+
* Retrieves details of a specific job.
138+
*
139+
* @param getJobRequest The request containing the job name for which the details are to be fetched.
140+
* The name property is mandatory.
141+
* @return A {@link Mono} that emits the {@link GetJobResponse} containing job details or raises an
142+
* error if the job is not found.
143+
* @throws IllegalArgumentException If the request or its required fields like name are null or empty.
144+
*/
145+
146+
public Mono<GetJobResponse> getJob(GetJobRequest getJobRequest) {
147+
try {
148+
if (getJobRequest == null) {
149+
throw new IllegalArgumentException("getJobRequest cannot be null");
150+
}
151+
152+
if (getJobRequest.getName() == null || getJobRequest.getName().isEmpty()) {
153+
throw new IllegalArgumentException("Name in the request cannot be null or empty");
154+
}
155+
156+
Mono<DaprProtos.GetJobResponse> getJobResponseMono =
157+
Mono.deferContextual(context -> this.createMono(
158+
it -> intercept(context, asyncStub)
159+
.getJobAlpha1(DaprProtos.GetJobRequest.newBuilder()
160+
.setName(getJobRequest.getName()).build(), it)
161+
)
162+
);
163+
164+
return getJobResponseMono.map(getJobResponse -> {
165+
DaprProtos.Job job = getJobResponse.getJob();
166+
return GetJobResponse.builder()
167+
.setName(job.getName())
168+
.setTtl(job.hasTtl() ? OffsetDateTime.parse(job.getTtl()) : null)
169+
.setData(job.hasData() ? job.getData().getValue().toByteArray() : null)
170+
.setRepeat(job.hasRepeats() ? job.getRepeats() : null)
171+
.setSchedule(job.hasSchedule() ? JobSchedule.fromString(job.getSchedule()) : null)
172+
.setDueTime(job.hasDueTime() ? OffsetDateTime.parse(job.getDueTime()) : null)
173+
.build();
174+
});
175+
} catch (Exception ex) {
176+
return DaprException.wrapMono(ex);
177+
}
178+
}
179+
180+
/**
181+
* Deletes a job based on the given request.
182+
*
183+
* @param deleteJobRequest The request containing the job name to be deleted.
184+
* The name property is mandatory.
185+
* @return A {@link Mono} that completes when the job is successfully deleted or raises an error.
186+
* @throws IllegalArgumentException If the request or its required fields like name are null or empty.
187+
*/
188+
public Mono<Void> deleteJob(DeleteJobRequest deleteJobRequest) {
189+
try {
190+
if (deleteJobRequest == null) {
191+
throw new IllegalArgumentException("deleteJobRequest cannot be null");
192+
}
193+
194+
if (deleteJobRequest.getName() == null || deleteJobRequest.getName().isEmpty()) {
195+
throw new IllegalArgumentException("Name in the request cannot be null or empty");
196+
}
197+
198+
Mono<DaprProtos.DeleteJobResponse> deleteJobResponseMono =
199+
Mono.deferContextual(context -> this.createMono(
200+
it -> intercept(context, asyncStub)
201+
.deleteJobAlpha1(DaprProtos.DeleteJobRequest.newBuilder()
202+
.setName(deleteJobRequest.getName()).build(), it)
203+
)
204+
);
205+
206+
return deleteJobResponseMono.then();
207+
} catch (Exception ex) {
208+
return DaprException.wrapMono(ex);
209+
}
210+
}
211+
212+
@Override
213+
public void close() throws Exception {
214+
ManagedChannel channel = (ManagedChannel) this.asyncStub.getChannel();
215+
216+
DaprException.wrap(() -> {
217+
if (channel != null && !channel.isShutdown()) {
218+
channel.shutdown();
219+
}
220+
221+
return true;
222+
}).call();
223+
}
224+
225+
private DaprGrpc.DaprStub intercept(
226+
ContextView context, DaprGrpc.DaprStub client) {
227+
return client.withInterceptors(new DaprTimeoutInterceptor(this.timeoutPolicy), new DaprTracingInterceptor(context));
228+
}
229+
230+
private <T> Mono<T> createMono(Consumer<StreamObserver<T>> consumer) {
231+
return retryPolicy.apply(
232+
Mono.create(sink -> DaprException.wrap(() -> consumer.accept(
233+
createStreamObserver(sink))).run()));
234+
}
235+
236+
private <T> StreamObserver<T> createStreamObserver(MonoSink<T> sink) {
237+
return new StreamObserver<T>() {
238+
@Override
239+
public void onNext(T value) {
240+
sink.success(value);
241+
}
242+
243+
@Override
244+
public void onError(Throwable t) {
245+
sink.error(DaprException.propagate(DaprHttpException.fromGrpcExecutionException(null, t)));
246+
}
247+
248+
@Override
249+
public void onCompleted() {
250+
sink.success();
251+
}
252+
};
253+
}
254+
}

sdk-jobs/src/main/java/io/dapr/jobs/client/DayOfWeek.java

-4
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,9 @@
22

33
/**
44
* Represents the days of the week in a cron expression.
5-
* <p>
65
* This enum maps each day of the week to its corresponding integer value
76
* as used in cron expressions (0 for Sunday through 6 for Saturday).
8-
* <p>
97
* Implements {@link OrdinalEnum} to provide an ordinal ranking for each day.
10-
* <p>
118
* Example usage:
129
* <pre>
1310
* DayOfWeek day = DayOfWeek.MON;
@@ -16,7 +13,6 @@
1613
*/
1714
public enum DayOfWeek implements OrdinalEnum {
1815

19-
2016
SUN(0),
2117
MON(1),
2218
TUE(2),

0 commit comments

Comments
 (0)