Jangle Java: Synchronization
This tutorial is a continutation of the 'Jangle Java: Upload & Load' tutorial. Make sure to follow the steps of this tutorial first before doing this one.
This tutorial shows the synchronization capabilities of the appjangle Java client. In particular, the well known producer-consumer scenario is applied on the simple pizza parlor data defined in the upload & load tutorial.
You can find the source code of the completed tutorial on github: V_JangleJavaShort_Synchronize.java.
Step 1: Define the Producer
The producer in this simple scenario adds nodes with the value "Pizza!"
to the ./servings
node defined for the pizza parlor.
For this, define a new Java class Producer
as shown below. Please replace the pizza parlor node path with the path to the pizza parlor data created in the upload & load tutoria and replace the access secret as well.
static class Producer implements Runnable {
final CoreDsl dsl = OneJre.init();
final OneClient client = dsl.createClient();
@Override
public void run() {
try {
Thread.sleep(600);
} catch (final InterruptedException e) {
e.printStackTrace();
}
System.out.println("Making pizza ...");
dsl.load(
"[your node]/servings")
.withSecret("[your secret]").in(client)
.and(new WhenLoaded() {
@Override
public void thenDo(final WithLoadResult<Object> sr) {
dsl.append(new String("Pizza!"))
.to(sr.loadedNode()).in(client);
dsl.commit(client).and(WhenCommitted.DO_NOTHING);
System.out.println("... pizza made!");
run();
}
});
}
}
Calling the run()
method of this class will start a recursive loop in which nodes with the value "Pizza!" will be appended to pizzaParlor/servings
. The resulting changes to the local client data will be uploaded to the server via the commit
operation.
Step 2: Defining the Consumer
The consumer in this scenario will 'monitor' the pizza parlor's servings
node for any changes. If a change occurs, the consumer will replace all "Pizza!" values with outcries of yummy!
Define a new class Consumer as follows (again replace address and access secret!):
class Consumer implements Runnable {
private volatile int eaten = 0;
@Override
public void run() {
final CoreDsl dsl = OneJre.init();
final OneClient client = dsl.createClient();
dsl.monitor(
dsl.reference("[your node]/servings"))
.inInterval(Interval.FAST).withSecret("[your secret]")
.in(client).and(new WhenNodeChanged() {
@Override
public void thenDo(final WithNodeChangedContext context) {
checkForPizza(dsl, client, context);
}
});
}
This class so far will install a monitor on the ./servings
node and call a checkForPizza
method every time a change has been made to the servings node.
The checkForPizza
method can be defined as follows:
private void checkForPizza(final CoreDsl dsl, final OneClient client,
final WithNodeChangedContext context) {
dsl.selectFrom(context.changedNode()).theChildren()
.ofType(String.class).in(client)
.and(new WhenChildrenSelected<OneTypedReference<String>>() {
@Override
public void thenDo(
final WithChildrenSelectedResult<OneTypedReference<String>> csr) {
for (final OneTypedReference<String> pizza : csr
.children()) {
if (!dsl.dereference(pizza).in(client)
.equals("Pizza!")) {
continue;
}
dsl.replace(pizza)
.with("Yummy (" + eaten + ")!")
.in(client);
eaten++;
System.out.println("Ate " + eaten
+ " Pizza(s)!");
}
dsl.commit(client).and(WhenCommitted.DO_NOTHING);
if (eaten > 10) {
System.out.println("Had enough pizza.");
context.monitor().stop(WhenShutdown.DO_NOTHING);
System.exit(0);
}
}
});
}
This method does the following:
- All child nodes, which have the class
String.class
are selected from thepizzaParlor/servings
node through calling the methodselectFrom(...)
. - All children of the class String are checked whether their value equals "Pizza!".
- If so, the respective value is replaces with the value "Yummy (x)!".
- Lastly, all changes made to the servings node are committed to the appjangle cloud.
Producer and consumer can be assembled in an application such as given here. Running this application should result in an output such as the following:
Making pizza ...
Ate 1 Pizza(s)!
... pizza made!
Making pizza ...
... pizza made!
Making pizza ...
... pizza made!
Ate 2 Pizza(s)!
Ate 3 Pizza(s)!
Making pizza ...
... pizza made!
Making pizza ...
Ate 4 Pizza(s)!
... pizza made!
Making pizza ...
While such a producer/consumer example is easily accomplished using threads and shared resources, the producer and consumer in the given example need not be part of one application. Indeed, producer and consumer can run on seperate Java-compatible devices as long as these are connected to the Internet.
The work of producer and consumer can further be traced through the various REST interfaces as seen for instance on the following page:
http://u1.linnk.it/lnzvwp/sd1/2/h/sd/pizzaParlor/servings.node.html
What's more?
To learn more about the capabilities of appjangle and onedb, you can check:
- the extensive onedb tutorial
- other articles on the onedb documentation page.
- subscribe to this blog!
- example apps on github