Skip to content

Commit 96c0277

Browse files
committed
add event handler
1 parent 4a3ea81 commit 96c0277

File tree

2 files changed

+63
-0
lines changed

2 files changed

+63
-0
lines changed

src/main/java/com/stripe/StripeClient.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1333,4 +1333,8 @@ public StripeResponse rawRequest(
13331333
public StripeObject deserialize(String rawJson, ApiMode apiMode) throws StripeException {
13341334
return StripeObject.deserializeStripeObject(rawJson, this.getResponseGetter(), apiMode);
13351335
}
1336+
1337+
public StripeEventHandler handler(String webhookSecret) {
1338+
return new StripeEventHandler(webhookSecret, this);
1339+
}
13361340
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package com.stripe;
2+
3+
import com.stripe.exception.SignatureVerificationException;
4+
import com.stripe.model.v2.core.EventNotification;
5+
import java.util.HashMap;
6+
7+
public class StripeEventHandler {
8+
/** Functional interface for event handlers that can throw StripeException. */
9+
@FunctionalInterface
10+
public interface EventHandler<T extends EventNotification> {
11+
// this is an internal-facing method name that dictates how we call the stored method
12+
void process(T event, StripeClient client);
13+
}
14+
15+
private final String webhookSecret;
16+
private final StripeClient stripeClient;
17+
private final HashMap<String, EventHandler<? extends EventNotification>> registeredHandlers =
18+
new HashMap<>();
19+
20+
public StripeEventHandler(String webhookSecret, StripeClient stripeClient) {
21+
this.webhookSecret = webhookSecret;
22+
this.stripeClient = stripeClient;
23+
}
24+
25+
public <T extends EventNotification> StripeEventHandler register(
26+
Class<T> eventClass, EventHandler<T> handler) {
27+
this.registeredHandlers.put(eventClass.getName(), handler);
28+
return this;
29+
}
30+
31+
/**
32+
* Handle an incoming webhook event notification.
33+
*
34+
* @param webhookBody the incoming webhook body
35+
* @param sigHeader the incoming webhook signature header
36+
* @throws SignatureVerificationException if the validation of the webhook signature fails
37+
* @throws IllegalArgumentException if no handler is registered for the event type
38+
* @throws Exception any other exception that the registered handler might throw
39+
*/
40+
@SuppressWarnings("unchecked")
41+
public void handle(String webhookBody, String sigHeader) throws SignatureVerificationException {
42+
EventNotification eventNotification =
43+
this.stripeClient.parseEventNotification(webhookBody, sigHeader, this.webhookSecret);
44+
45+
EventHandler<? extends EventNotification> handler =
46+
// I don't _love_ getName as a matcher but lets us bucket all the unknown events in a way
47+
// that checking .type doesn't.
48+
registeredHandlers.get(eventNotification.getClass().getName());
49+
50+
if (handler == null) {
51+
throw new IllegalArgumentException(
52+
"No handler registered for event type: " + eventNotification.getType());
53+
}
54+
55+
// TODO: re-bind client context
56+
// this is technically unsafe but we control the registration API so should be ok
57+
((EventHandler<EventNotification>) handler).process(eventNotification, this.stripeClient);
58+
}
59+
}

0 commit comments

Comments
 (0)