Skip to content

Commit 7d45261

Browse files
Sample for dataConverter (#37)
1 parent a79d8d6 commit 7d45261

File tree

1 file changed

+212
-0
lines changed

1 file changed

+212
-0
lines changed
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
/*
2+
* Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Modifications copyright (C) 2017 Uber Technologies, Inc.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License"). You may not
7+
* use this file except in compliance with the License. A copy of the License is
8+
* located at
9+
*
10+
* http://aws.amazon.com/apache2.0
11+
*
12+
* or in the "license" file accompanying this file. This file is distributed on
13+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
14+
* express or implied. See the License for the specific language governing
15+
* permissions and limitations under the License.
16+
*/
17+
18+
package com.uber.cadence.samples.hello;
19+
20+
import static com.uber.cadence.samples.common.SampleConstants.DOMAIN;
21+
22+
import com.uber.cadence.activity.ActivityMethod;
23+
import com.uber.cadence.client.WorkflowClient;
24+
import com.uber.cadence.client.WorkflowClientOptions;
25+
import com.uber.cadence.converter.DataConverter;
26+
import com.uber.cadence.converter.DataConverterException;
27+
import com.uber.cadence.converter.JsonDataConverter;
28+
import com.uber.cadence.serviceclient.ClientOptions;
29+
import com.uber.cadence.serviceclient.WorkflowServiceTChannel;
30+
import com.uber.cadence.worker.Worker;
31+
import com.uber.cadence.worker.WorkerFactory;
32+
import com.uber.cadence.workflow.Workflow;
33+
import com.uber.cadence.workflow.WorkflowMethod;
34+
import java.lang.reflect.Type;
35+
import java.nio.charset.Charset;
36+
37+
/**
38+
* HelloDataConverter is a sample to how to implement a dataConverter to convert some objects that
39+
* you want to use a different way to serialize/deserialize
40+
*/
41+
public class HelloDataConverter {
42+
43+
/**
44+
* MyStruct is a sample class that you want to use a different to serialize/deserialize it. In
45+
* real-world you can put anything like Avro classes in it
46+
*/
47+
public static class MyStruct {
48+
public int num;
49+
public String str;
50+
51+
public MyStruct(int num, String str) {
52+
this.num = num;
53+
this.str = str;
54+
}
55+
56+
public static MyStruct fromBytes(byte[] content) {
57+
String s = new String(content, Charset.defaultCharset());
58+
String[] ss = s.split("#");
59+
int num = Integer.parseInt(ss[0]);
60+
return new MyStruct(num, ss[1]);
61+
}
62+
63+
public byte[] toBytes() {
64+
return (this.num + "#" + this.str).getBytes(Charset.defaultCharset());
65+
}
66+
67+
@Override
68+
public String toString() {
69+
return str + " and " + num;
70+
}
71+
}
72+
73+
static final String TASK_LIST = "HelloActivity";
74+
75+
/** Workflow interface has to have at least one method annotated with @WorkflowMethod. */
76+
public interface GreetingWorkflow {
77+
/** @return greeting string */
78+
@WorkflowMethod(executionStartToCloseTimeoutSeconds = 10, taskList = TASK_LIST)
79+
String getGreeting(MyStruct st);
80+
}
81+
82+
/** Activity interface is just a POJI. */
83+
public interface GreetingActivities {
84+
@ActivityMethod(scheduleToCloseTimeoutSeconds = 2)
85+
MyStruct composeGreeting(Integer num, String str);
86+
}
87+
88+
/** GreetingWorkflow implementation that calls GreetingsActivities#composeGreeting. */
89+
public static class GreetingWorkflowImpl implements GreetingWorkflow {
90+
91+
private final GreetingActivities activities =
92+
Workflow.newActivityStub(GreetingActivities.class);
93+
94+
@Override
95+
public String getGreeting(MyStruct st) {
96+
// This is a blocking call that returns only after the activity has completed.
97+
st = activities.composeGreeting(st.num, st.str);
98+
return st.toString();
99+
}
100+
}
101+
102+
public static class MyStructConverter implements DataConverter {
103+
104+
private static final DataConverter cadenceDefaultDataConverter =
105+
JsonDataConverter.getInstance();
106+
107+
/**
108+
* * toData is converting input/output parameter of workflow/activity, exception, internal
109+
* classes(local activity, heartbeat etc) into binary.
110+
*
111+
* @param values
112+
* @return
113+
* @throws DataConverterException
114+
*/
115+
@Override
116+
public byte[] toData(final Object... values) throws DataConverterException {
117+
if (values == null || values.length == 0) {
118+
return null;
119+
}
120+
121+
if (values.length == 1 && values[0] instanceof MyStruct) {
122+
// NOTE: toData can be used to converting multiple input parameter as well.
123+
// but here we assume that when passing MyStruct as input, we always use one parameter.
124+
// In your real-world case, you can change this to support multiple(values.length > 1) if
125+
// needed
126+
MyStruct st = (MyStruct) values[0];
127+
return st.toBytes();
128+
}
129+
130+
// fallback to cadenceDefaultDataConverter to keep backward compatible
131+
return cadenceDefaultDataConverter.toData(values);
132+
}
133+
134+
/**
135+
* * fromData is converting binary back to a single object. It's only being used for output of
136+
* workflow/activity, exception, internal classes(local activity, heartbeat etc)
137+
*
138+
* @param content
139+
* @param valueClass
140+
* @param valueType
141+
* @param <T>
142+
* @return
143+
* @throws DataConverterException
144+
*/
145+
@Override
146+
public <T> T fromData(final byte[] content, final Class<T> valueClass, final Type valueType)
147+
throws DataConverterException {
148+
if (valueType.getTypeName().equals(MyStruct.class.getTypeName())) {
149+
return (T) MyStruct.fromBytes(content);
150+
} else {
151+
return cadenceDefaultDataConverter.fromData(content, valueClass, valueType);
152+
}
153+
}
154+
155+
/*
156+
* Used to deserialize a byte[] into one-to-many different value types. The
157+
* primary use case for this is the deserialization of Workflow / Activity arguments for worker to execute workflow/activity
158+
*/
159+
@Override
160+
public Object[] fromDataArray(final byte[] content, final Type... valueTypes)
161+
throws DataConverterException {
162+
if ((content == null) || (content.length == 0)) {
163+
Object[] result = new Object[valueTypes.length];
164+
return result;
165+
}
166+
if (valueTypes.length == 1) {
167+
final Object result;
168+
final Type valueType = valueTypes[0];
169+
if (valueType.getTypeName().equals(MyStruct.class.getTypeName())) {
170+
result = MyStruct.fromBytes(content);
171+
return new Object[] {result};
172+
}
173+
}
174+
175+
return cadenceDefaultDataConverter.fromDataArray(content, valueTypes);
176+
}
177+
}
178+
179+
static class GreetingActivitiesImpl implements GreetingActivities {
180+
@Override
181+
public MyStruct composeGreeting(Integer num, String str) {
182+
return new MyStruct(num * 2, str + "::" + str);
183+
}
184+
}
185+
186+
public static void main(String[] args) {
187+
final MyStructConverter dc = new MyStructConverter();
188+
// Get a new client
189+
// NOTE: to set a different options, you can do like this:
190+
// ClientOptions.newBuilder().setRpcTimeout(5 * 1000).build();
191+
WorkflowClient workflowClient =
192+
WorkflowClient.newInstance(
193+
new WorkflowServiceTChannel(ClientOptions.defaultInstance()),
194+
WorkflowClientOptions.newBuilder().setDataConverter(dc).setDomain(DOMAIN).build());
195+
// Get worker to poll the task list.
196+
WorkerFactory factory = WorkerFactory.newInstance(workflowClient);
197+
Worker worker = factory.newWorker(TASK_LIST);
198+
// Workflows are stateful. So you need a type to create instances.
199+
worker.registerWorkflowImplementationTypes(GreetingWorkflowImpl.class);
200+
// Activities are stateless and thread safe. So a shared instance is used.
201+
worker.registerActivitiesImplementations(new GreetingActivitiesImpl());
202+
// Start listening to the workflow and activity task lists.
203+
factory.start();
204+
205+
// Get a workflow stub using the same task list the worker uses.
206+
GreetingWorkflow workflow = workflowClient.newWorkflowStub(GreetingWorkflow.class);
207+
// Execute a workflow waiting for it to complete.
208+
String greeting = workflow.getGreeting(new MyStruct(100, "Hello"));
209+
System.out.println(greeting);
210+
System.exit(0);
211+
}
212+
}

0 commit comments

Comments
 (0)