Building a multi-platform Ignite cluster: Java+.NET
An Ignite cluster can consist of nodes launched on any platform it supports, including Java, .NET, and C++. This article will show you how to run a .NET/Java cluster with NuGet and Maven. As an example, this article will create a cross-platform peer-to-peer chat system.
Preconditions
This article is intended for .NET developers unfamiliar with Java and vice versa, so it will be described in more detail. This article will use the following software:
- Visual Studio 2015 (including NuGet; free community edition);
- IntelliJ IDEA (including Maven; free community edition).
The full source code for this article is on GitHub, github.com/ptupitsyn/ignite-multi-platform-demo . For brevity, the code below is not very complete (public fields, no namespaces, etc.).
Target
- Connect Java and .NET nodes;
- Use Java and .NET classes to access shared data in the Ignite cache with the same names and fields;
- Run continuous queries and watch real-time data updates from another platform.
Java project settings
- Start IntelliJ IDEA and click "Create New Project":
- Select Maven and click "Next":
- Enter the Maven information, click "Next" and then "Finish":
- Once done, you will see the files opened for the new project
pom.xml
: project
Add Ignite dependency to fragment:
<dependencies>
<dependency>
<groupId>org.apache.ignite</groupId>
<artifactId>ignite-core</artifactId>
<version>1.7.0</version>
</dependency>
</dependencies>
- IDEA may ask whether to import project changes, click on any link:
- Add the class to src\main\java with the
Demo
following code:
import org.apache.ignite.Ignition;
public class Demo {
public static void main(String[] args) {
Ignition.start();
}
}
- Confirm that the node is up by
Shift+F10
running and then on IDEA's console:
- Terminate the program with the
Ctrl+F2
or stop button.
.NET Project Settings
- Start Visual Studio and click File -> New -> Project:
- Select Visual C# -> Windows -> Console Application:
- Make sure .NET Framework version 4 and above is selected above:
- Click "OK", then an empty console project will be generated;
- Open the NuGet console: Menu -> Tools -> NuGet Package Manager -> Package Manager Console;
- Enter
Install-Package Apache.Ignite
:
- Hit enter and
Successfully installed 'Apache.Ignite 1.7.0' to IgniteMultiPlatform
this message will be output. - Change the
Program.cs
content to the following:
using System;
using Apache.Ignite.Core;
class Program
{
static void Main(string[] args)
{
Ignition.Start();
Console.ReadKey();
}
}
- Confirm in the console that the Ignite node is up by
Ctrl-F5
starting the program:
Adjust the configuration of Java nodes to discover .NET nodes
Now, you can start the Java node in IDEA and the .NET node in Visual Studio at the same time, and you will find the following error in one of them:
IgniteSpiException: Local node's binary configuration is not equal to remote node's binary configuration [locBinaryCfg={globSerializer=null, compactFooter=true, globIdMapper=org.apache.ignite.binary.BinaryBasicIdMapper}, rmtBinaryCfg=null]
The error is saying that .NET node BinaryConfiguration
only supports BinaryBasicIdMapper
and in Java and BinaryBasicNameMapper
needs to be set explicitly in Java, change the Ignition.start();
line to the following code:
BinaryConfiguration binCfg = new BinaryConfiguration();
binCfg.setIdMapper(new BinaryBasicIdMapper());
binCfg.setNameMapper(new BinaryBasicNameMapper());
IgniteConfiguration cfg = new IgniteConfiguration().setBinaryConfiguration(binCfg);
Ignition.start(cfg);
Now start the Java and .NET nodes at the same time and verify that they can discover each other:
[15:04:17] Topology snapshot [ver=2, servers=2, clients=0, CPUs=8, heap=7.1GB]
Data exchange via Ignite cache
Now that each node is connected, a simple chat program will be written on each platform to demonstrate data exchange. The code is very simple because the API is the same and the language syntax is similar. First, define a class with the exact same name and members.
Java Message类
Right-click the src\main\java project folder and select New -> Java Class, enter the Message
name, and the code is as follows:
public class Message {
public Message(String author, String text) {
this.author = author;
this.text = text;
}
final String author;
final String text;
}
.NET Message class
Right-click the project node of the Solution Explorer, then select Add -> Class..., enter the Message
name, and the code is as follows:
class Message
{
public Message(string author, string text)
{
Author = author;
Text = text;
}
public string Author { get; }
public string Text { get; }
}
Basic
The mapper is case-sensitive and ignores namespaces (packages), so the two classes are mappable to each other, injecting a Message instance into the cache in one platform and fetching it in the other. Now to write the chat program itself, the logic is relatively simple: the user enters a chat message, then injects it into the cache, and the continuous query will receive all cache update notifications and display them.
Java chat program
main
Change the code of the method to the following:
// Retrieve user name
System.out.print("Hi, enter your name: ");
Scanner consoleScanner = new Scanner(System.in);
String name = consoleScanner.nextLine();
// Get or create cache
IgniteCache<Long, Message> cache = ignite.getOrCreateCache("chat");
// Initialize unique ID sequence
IgniteAtomicSequence messageId = ignite.atomicSequence("chatId", 0, true);
// Set up continuous query
ContinuousQuery<Long, Message> qry = new ContinuousQuery<>();
qry.setLocalListener(iterable -> {
// This will be invoked immediately on each cache update
for (CacheEntryEvent<? extends Long, ? extends Message> evt : iterable)
System.out.println(evt.getValue().author + ": " + evt.getValue().text);
});
cache.query(qry);
// Run the chat loop
while (true) {
System.out.print("> ");
String msgText = consoleScanner.nextLine();
Long msgId = messageId.incrementAndGet();
cache.put(msgId, new Message(name, msgText));
}
.NET chat program
There are two differences in Ignite.NET (these features are expected to be implemented in the next version):
- Need to register a type for caching in BinaryConfiguration (Java will do this automatically);
- Lambda expressions are not yet supported in the API, and
ICacheEntryEventListener<K, V>
interfaces need to be implemented separately.
So create a separate class with the following code:
using System;
using System.Collections.Generic;
using Apache.Ignite.Core.Cache.Event;
class CacheListener : ICacheEntryEventListener<long, Message>
{
public void OnEvent(IEnumerable<ICacheEntryEvent<long, Message>> evts)
{
foreach (var evt in evts)
Console.WriteLine($"{evt.Value.Author}: {evt.Value.Text}");
}
}
Then update the Main
method:
// Retrieve user name
Console.Write("Hi, enter your name: ");
var name = Console.ReadLine();
// Register Message type
var cfg = new IgniteConfiguration
{
BinaryConfiguration = new BinaryConfiguration(typeof(Message))
};
// Start Ignite and retrieve cache
var ignite = Ignition.Start(cfg);
var cache = ignite.GetOrCreateCache<long, Message>("chat");
// Initialize unique ID sequence
var messageId = ignite.GetAtomicSequence("chatId", 0, true);
// Set up continuous query
cache.QueryContinuous(new ContinuousQuery<long, Message>(new CacheListener()));
// Run the chat loop
while (true)
{
Console.Write("> ");
var msgText = Console.ReadLine();
var msgId = messageId.Increment();
cache[msgId] = new Message(name, msgText);
}
in conclusion
Start these two nodes, put the two windows side by side, type some messages, and you'll see them immediately appear in the other window.
Finish! A cross-platform peer-to-peer chat program has been created! There is no central server, and any number of clients can join or leave at any time. As an exercise, this can be done better:
- Change the cache mode to
Replicated
(refer to cache mode ), so that each chat node will hold the complete chat history; - Set the
ContinuousQuery.InitialQuery
property (see Initial Query ) so that each new node immediately displays the previous message.
This way, as long as one node is alive, the entire chat history will be saved, and new nodes will show them as they join.
This article is translated from Pavel Tupitsyn's blog: Building a Multi-Platform Ignite Cluster: Java + .NET