1
1
package io .temporal .internal .common ;
2
2
3
- import static io .temporal .internal .common .ProtoEnumNameUtils .EVENT_TYPE_PREFIX ;
4
- import static io .temporal .internal .common .ProtoEnumNameUtils .simplifiedToUniqueName ;
3
+ import static io .temporal .internal .common .ProtoEnumNameUtils .*;
5
4
6
5
import io .temporal .api .common .v1 .Link ;
7
6
import io .temporal .api .enums .v1 .EventType ;
7
+ import java .io .UnsupportedEncodingException ;
8
8
import java .net .URI ;
9
9
import java .net .URLDecoder ;
10
10
import java .net .URLEncoder ;
11
11
import java .nio .charset .StandardCharsets ;
12
- import java .util .StringTokenizer ;
12
+ import java .util .*;
13
+ import java .util .AbstractMap .SimpleImmutableEntry ;
14
+ import java .util .stream .Collectors ;
13
15
import org .slf4j .Logger ;
14
16
import org .slf4j .LoggerFactory ;
15
17
@@ -18,6 +20,15 @@ public class LinkConverter {
18
20
private static final Logger log = LoggerFactory .getLogger (LinkConverter .class );
19
21
20
22
private static final String linkPathFormat = "temporal:///namespaces/%s/workflows/%s/%s/history" ;
23
+ private static final String linkReferenceTypeKey = "referenceType" ;
24
+ private static final String linkEventIDKey = "eventID" ;
25
+ private static final String linkEventTypeKey = "eventType" ;
26
+ private static final String linkRequestIDKey = "requestID" ;
27
+
28
+ private static final String eventReferenceType =
29
+ Link .WorkflowEvent .EventReference .getDescriptor ().getName ();
30
+ private static final String requestIDReferenceType =
31
+ Link .WorkflowEvent .RequestIdReference .getDescriptor ().getName ();
21
32
22
33
public static io .temporal .api .nexus .v1 .Link workflowEventToNexusLink (Link .WorkflowEvent we ) {
23
34
try {
@@ -28,19 +39,36 @@ public static io.temporal.api.nexus.v1.Link workflowEventToNexusLink(Link.Workfl
28
39
URLEncoder .encode (we .getWorkflowId (), StandardCharsets .UTF_8 .toString ()),
29
40
URLEncoder .encode (we .getRunId (), StandardCharsets .UTF_8 .toString ()));
30
41
42
+ List <Map .Entry <String , String >> queryParams = new ArrayList <>();
31
43
if (we .hasEventRef ()) {
32
- url += "?" ;
33
- if (we .getEventRef ().getEventId () > 0 ) {
34
- url += "eventID=" + we .getEventRef ().getEventId () + "&" ;
44
+ queryParams .add (new SimpleImmutableEntry <>(linkReferenceTypeKey , eventReferenceType ));
45
+ Link .WorkflowEvent .EventReference eventRef = we .getEventRef ();
46
+ if (eventRef .getEventId () > 0 ) {
47
+ queryParams .add (
48
+ new SimpleImmutableEntry <>(linkEventIDKey , String .valueOf (eventRef .getEventId ())));
35
49
}
36
- url +=
37
- "eventType="
38
- + URLEncoder .encode (
39
- we .getEventRef ().getEventType ().name (), StandardCharsets .UTF_8 .toString ())
40
- + "&" ;
41
- url += "referenceType=EventReference" ;
50
+ final String eventType =
51
+ URLEncoder .encode (
52
+ encodeEventType (eventRef .getEventType ()), StandardCharsets .UTF_8 .toString ());
53
+ queryParams .add (new SimpleImmutableEntry <>(linkEventTypeKey , eventType ));
54
+ } else if (we .hasRequestIdRef ()) {
55
+ queryParams .add (new SimpleImmutableEntry <>(linkReferenceTypeKey , requestIDReferenceType ));
56
+ Link .WorkflowEvent .RequestIdReference requestIDRef = we .getRequestIdRef ();
57
+ final String requestID =
58
+ URLEncoder .encode (requestIDRef .getRequestId (), StandardCharsets .UTF_8 .toString ());
59
+ queryParams .add (new SimpleImmutableEntry <>(linkRequestIDKey , requestID ));
60
+ final String eventType =
61
+ URLEncoder .encode (
62
+ encodeEventType (requestIDRef .getEventType ()), StandardCharsets .UTF_8 .toString ());
63
+ queryParams .add (new SimpleImmutableEntry <>(linkEventTypeKey , eventType ));
42
64
}
43
65
66
+ url +=
67
+ "?"
68
+ + queryParams .stream ()
69
+ .map ((item ) -> item .getKey () + "=" + item .getValue ())
70
+ .collect (Collectors .joining ("&" ));
71
+
44
72
return io .temporal .api .nexus .v1 .Link .newBuilder ()
45
73
.setUrl (url )
46
74
.setType (we .getDescriptorForType ().getFullName ())
@@ -84,36 +112,74 @@ public static Link nexusLinkToWorkflowEvent(io.temporal.api.nexus.v1.Link nexusL
84
112
.setWorkflowId (workflowID )
85
113
.setRunId (runID );
86
114
87
- if (uri .getQuery () != null ) {
115
+ Map <String , String > queryParams = parseQueryParams (uri );
116
+ String referenceType = queryParams .get (linkReferenceTypeKey );
117
+ if (referenceType .equals (eventReferenceType )) {
88
118
Link .WorkflowEvent .EventReference .Builder eventRef =
89
119
Link .WorkflowEvent .EventReference .newBuilder ();
90
- String query = URLDecoder .decode (uri .getQuery (), StandardCharsets .UTF_8 .toString ());
91
- st = new StringTokenizer (query , "&" );
92
- while (st .hasMoreTokens ()) {
93
- String [] param = st .nextToken ().split ("=" );
94
- switch (param [0 ]) {
95
- case "eventID" :
96
- eventRef .setEventId (Long .parseLong (param [1 ]));
97
- continue ;
98
- case "eventType" :
99
- // Have to handle the SCREAMING_CASE enum or the traditional temporal PascalCase enum
100
- // to EventType
101
- if (param [1 ].startsWith (EVENT_TYPE_PREFIX )) {
102
- eventRef .setEventType (EventType .valueOf (param [1 ]));
103
- } else {
104
- eventRef .setEventType (
105
- EventType .valueOf (simplifiedToUniqueName (param [1 ], EVENT_TYPE_PREFIX )));
106
- }
107
- }
120
+ String eventID = queryParams .get (linkEventIDKey );
121
+ if (eventID != null && !eventID .isEmpty ()) {
122
+ eventRef .setEventId (Long .parseLong (eventID ));
123
+ }
124
+ String eventType = queryParams .get (linkEventTypeKey );
125
+ if (eventType != null && !eventType .isEmpty ()) {
126
+ eventRef .setEventType (decodeEventType (eventType ));
108
127
}
109
128
we .setEventRef (eventRef );
110
- link .setWorkflowEvent (we );
129
+ } else if (referenceType .equals (requestIDReferenceType )) {
130
+ Link .WorkflowEvent .RequestIdReference .Builder requestIDRef =
131
+ Link .WorkflowEvent .RequestIdReference .newBuilder ();
132
+ String requestID = queryParams .get (linkRequestIDKey );
133
+ if (requestID != null && !requestID .isEmpty ()) {
134
+ requestIDRef .setRequestId (requestID );
135
+ }
136
+ String eventType = queryParams .get (linkEventTypeKey );
137
+ if (eventType != null && !eventType .isEmpty ()) {
138
+ requestIDRef .setEventType (decodeEventType (eventType ));
139
+ }
140
+ we .setRequestIdRef (requestIDRef );
141
+ } else {
142
+ log .error ("Failed to parse Nexus link URL: invalid reference type: {}" , referenceType );
143
+ return null ;
111
144
}
145
+
146
+ link .setWorkflowEvent (we );
112
147
} catch (Exception e ) {
113
148
// Swallow un-parsable links since they are not critical to processing
114
149
log .error ("Failed to parse Nexus link URL" , e );
115
150
return null ;
116
151
}
117
152
return link .build ();
118
153
}
154
+
155
+ private static Map <String , String > parseQueryParams (URI uri ) throws UnsupportedEncodingException {
156
+ final String query = uri .getQuery ();
157
+ if (query == null || query .isEmpty ()) {
158
+ return Collections .emptyMap ();
159
+ }
160
+ Map <String , String > queryParams = new HashMap <>();
161
+ for (String pair : query .split ("&" )) {
162
+ final String [] kv = pair .split ("=" , 2 );
163
+ final String key = URLDecoder .decode (kv [0 ], StandardCharsets .UTF_8 .toString ());
164
+ final String value =
165
+ kv .length == 2 && !kv [1 ].isEmpty ()
166
+ ? URLDecoder .decode (kv [1 ], StandardCharsets .UTF_8 .toString ())
167
+ : null ;
168
+ queryParams .put (key , value );
169
+ }
170
+ return queryParams ;
171
+ }
172
+
173
+ private static String encodeEventType (EventType eventType ) {
174
+ return uniqueToSimplifiedName (eventType .name (), EVENT_TYPE_PREFIX );
175
+ }
176
+
177
+ private static EventType decodeEventType (String eventType ) {
178
+ // Have to handle the SCREAMING_CASE enum or the traditional temporal PascalCase enum to
179
+ // EventType
180
+ if (eventType .startsWith (EVENT_TYPE_PREFIX )) {
181
+ return EventType .valueOf (eventType );
182
+ }
183
+ return EventType .valueOf (simplifiedToUniqueName (eventType , EVENT_TYPE_PREFIX ));
184
+ }
119
185
}
0 commit comments