Skip to content

Commit

Permalink
Converted to 9.18 for Mendix 10 compat.
Browse files Browse the repository at this point in the history
  • Loading branch information
ArjenLammers committed Apr 17, 2023
1 parent 0672d55 commit 0c582cf
Show file tree
Hide file tree
Showing 144 changed files with 7,252 additions and 1,062 deletions.
74 changes: 74 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
Connect your Mendix app to Apache Kafka.

# Usage
This module allows you to:

- Produce data in Kafka topic
- Consume data from Kafka topics
- Stream data between Kafka topics
- Produce data
- Kafka Produce allows you to write data to a topic.

To produce data, you need to configure a Producer. Within your microflow logic you can choose to publish data in a synchronous manner (blocks until delivery is guaranteed) and asynchronous manner (continue and trust the library to take care of it; which has no guarantee).

# Consume data
Kafka Consume allows you to read data from a topic.

To consume data, configure a consumer and a on-receive microflow.

The microflow takes the following parameters:

Offset (Long): The position of this record in the corresponding Kafka partition.
Key (String): The key (or null if no key is specified)
Value (String): The value
… : any parameters
An example microflow has been created for reference, see Example_OnReceiveMicroflow.

The consumer calls the microflow for each message in the topic. If you only want to start the microflow for certain messages, you can use a filtered processor.

To start the consumer, it is adviced to include this in the after startup microflow. An example has been created in Example_AfterStartupConsumer.

# Stream data
Kafka Streams allows you to read data from one topic, and write data to another.

To stream data between two topics, you need to start a processor. All configuration options are available. However, the only configuration information it needs is the Kafka server to connect to, the topic to read from, and a microflow.

The microflow takes the following parameters:

Offset (Long): The position of this record in the corresponding Kafka partition.
Key (String): The key (or null if no key is specified)
Value (String): The value
It may return one of the following:

List of KeyValuePair: All these messages will be sent to the output topic.
KeyValuePair: This message will be sent to the output topic.
String: A message with that value (and no key) will be sent to the output topic
Nothing: No messages will be sent to the output topic.
If you start a processor without an output topic, it behaves like a consumer in the sense that it only reads and does not write.

The consumer calls the microflow for each message in the input topic.

# Filtering
You can filter the messages that cause the microflow to execute by starting a filtered processor. This works for JSON messages only, and only when you want to filter on a specific part of the JSON message, such as a property value.

# Shut down
Make sure you call the 'Stop all Kafka connections' action before the app stops, for instance during the 'Before shutdown' microflow.

# Features and limitations
Features:
- Easy to setup Kafka consumers and producers.
- Full SSL support (using keystore and truststores).
- Explorer (discover topics and read messages).
- Support for headers (as consumer and producer).
- Logging from the Kafka library redirected to Mendix (so you can actually see errors and connectivity issues).
- Producing messages using asynchronous and synchronous mode.
- Publish messages through UI.
- Consumer commit control (to force at-least-once processing).

# Limitations

To apply configuration changes it is strongly adviced to restart the application. This because there's no (platform) way of informing all instances about changes of configuration.
In order for the logging to work, SLF4j logging has been redirected through log4j. If any other SLF4j outputs are present, this will probably fail.

# Dependencies
Library Logging module
Binary file modified src/KafkaModule.mpr
Binary file not shown.
28 changes: 17 additions & 11 deletions src/javasource/administration/proxies/Account.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public enum MemberNames
Password("Password"),
LastLogin("LastLogin"),
Blocked("Blocked"),
BlockedSince("BlockedSince"),
Active("Active"),
FailedLogins("FailedLogins"),
WebServiceUser("WebServiceUser"),
Expand All @@ -31,7 +32,7 @@ public enum MemberNames
User_Language("System.User_Language"),
User_TimeZone("System.User_TimeZone");

private java.lang.String metaName;
private final java.lang.String metaName;

MemberNames(java.lang.String s)
{
Expand All @@ -47,14 +48,15 @@ public java.lang.String toString()

public Account(com.mendix.systemwideinterfaces.core.IContext context)
{
this(context, com.mendix.core.Core.instantiate(context, "Administration.Account"));
this(context, com.mendix.core.Core.instantiate(context, entityName));
}

protected Account(com.mendix.systemwideinterfaces.core.IContext context, com.mendix.systemwideinterfaces.core.IMendixObject accountMendixObject)
{
super(context, accountMendixObject);
if (!com.mendix.core.Core.isSubClassOf("Administration.Account", accountMendixObject.getType()))
throw new java.lang.IllegalArgumentException("The given object is not a Administration.Account");
if (!com.mendix.core.Core.isSubClassOf(entityName, accountMendixObject.getType())) {
throw new java.lang.IllegalArgumentException(String.format("The given object is not a %s", entityName));
}
}

/**
Expand All @@ -69,6 +71,9 @@ public static administration.proxies.Account initialize(com.mendix.systemwideint
/**
* Initialize a proxy using context (recommended). This context will be used for security checking when the get- and set-methods without context parameters are called.
* The get- and set-methods with context parameter should be used when for instance sudo access is necessary (IContext.createSudoClone() can be used to obtain sudo access).
* @param context The context to be used
* @param mendixObject The Mendix object for the new instance
* @return a new instance of this proxy class
*/
public static administration.proxies.Account initialize(com.mendix.systemwideinterfaces.core.IContext context, com.mendix.systemwideinterfaces.core.IMendixObject mendixObject)
{
Expand All @@ -83,10 +88,11 @@ public static administration.proxies.Account load(com.mendix.systemwideinterface

public static java.util.List<administration.proxies.Account> load(com.mendix.systemwideinterfaces.core.IContext context, java.lang.String xpathConstraint) throws com.mendix.core.CoreException
{
java.util.List<administration.proxies.Account> result = new java.util.ArrayList<administration.proxies.Account>();
for (com.mendix.systemwideinterfaces.core.IMendixObject obj : com.mendix.core.Core.retrieveXPathQuery(context, "//Administration.Account" + xpathConstraint))
result.add(administration.proxies.Account.initialize(context, obj));
return result;
return com.mendix.core.Core.createXPathQuery(String.format("//%1$s%2$s", entityName, xpathConstraint))
.execute(context)
.stream()
.map(obj -> administration.proxies.Account.initialize(context, obj))
.collect(java.util.stream.Collectors.toList());
}

/**
Expand Down Expand Up @@ -200,9 +206,9 @@ public final void setIsLocalUser(com.mendix.systemwideinterfaces.core.IContext c
@java.lang.Override
public boolean equals(Object obj)
{
if (obj == this)
if (obj == this) {
return true;

}
if (obj != null && getClass().equals(obj.getClass()))
{
final administration.proxies.Account that = (administration.proxies.Account) obj;
Expand All @@ -222,7 +228,7 @@ public int hashCode()
*/
public static java.lang.String getType()
{
return "Administration.Account";
return entityName;
}

/**
Expand Down
33 changes: 22 additions & 11 deletions src/javasource/administration/proxies/AccountPasswordData.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public enum MemberNames
ConfirmPassword("ConfirmPassword"),
AccountPasswordData_Account("Administration.AccountPasswordData_Account");

private java.lang.String metaName;
private final java.lang.String metaName;

MemberNames(java.lang.String s)
{
Expand All @@ -41,15 +41,17 @@ public java.lang.String toString()

public AccountPasswordData(com.mendix.systemwideinterfaces.core.IContext context)
{
this(context, com.mendix.core.Core.instantiate(context, "Administration.AccountPasswordData"));
this(context, com.mendix.core.Core.instantiate(context, entityName));
}

protected AccountPasswordData(com.mendix.systemwideinterfaces.core.IContext context, com.mendix.systemwideinterfaces.core.IMendixObject accountPasswordDataMendixObject)
{
if (accountPasswordDataMendixObject == null)
if (accountPasswordDataMendixObject == null) {
throw new java.lang.IllegalArgumentException("The given object cannot be null.");
if (!com.mendix.core.Core.isSubClassOf("Administration.AccountPasswordData", accountPasswordDataMendixObject.getType()))
throw new java.lang.IllegalArgumentException("The given object is not a Administration.AccountPasswordData");
}
if (!com.mendix.core.Core.isSubClassOf(entityName, accountPasswordDataMendixObject.getType())) {
throw new java.lang.IllegalArgumentException(String.format("The given object is not a %s", entityName));
}

this.accountPasswordDataMendixObject = accountPasswordDataMendixObject;
this.context = context;
Expand All @@ -67,6 +69,9 @@ public static administration.proxies.AccountPasswordData initialize(com.mendix.s
/**
* Initialize a proxy using context (recommended). This context will be used for security checking when the get- and set-methods without context parameters are called.
* The get- and set-methods with context parameter should be used when for instance sudo access is necessary (IContext.createSudoClone() can be used to obtain sudo access).
* @param context The context to be used
* @param mendixObject The Mendix object for the new instance
* @return a new instance of this proxy class
*/
public static administration.proxies.AccountPasswordData initialize(com.mendix.systemwideinterfaces.core.IContext context, com.mendix.systemwideinterfaces.core.IMendixObject mendixObject)
{
Expand All @@ -81,6 +86,7 @@ public static administration.proxies.AccountPasswordData load(com.mendix.systemw

/**
* Commit the changes made on this proxy object.
* @throws com.mendix.core.CoreException
*/
public final void commit() throws com.mendix.core.CoreException
{
Expand All @@ -89,6 +95,7 @@ public final void commit() throws com.mendix.core.CoreException

/**
* Commit the changes made on this proxy object using the specified context.
* @throws com.mendix.core.CoreException
*/
public final void commit(com.mendix.systemwideinterfaces.core.IContext context) throws com.mendix.core.CoreException
{
Expand Down Expand Up @@ -219,6 +226,7 @@ public final void setConfirmPassword(com.mendix.systemwideinterfaces.core.IConte
}

/**
* @throws com.mendix.core.CoreException
* @return value of AccountPasswordData_Account
*/
public final administration.proxies.Account getAccountPasswordData_Account() throws com.mendix.core.CoreException
Expand All @@ -229,13 +237,15 @@ public final administration.proxies.Account getAccountPasswordData_Account() thr
/**
* @param context
* @return value of AccountPasswordData_Account
* @throws com.mendix.core.CoreException
*/
public final administration.proxies.Account getAccountPasswordData_Account(com.mendix.systemwideinterfaces.core.IContext context) throws com.mendix.core.CoreException
{
administration.proxies.Account result = null;
com.mendix.systemwideinterfaces.core.IMendixIdentifier identifier = getMendixObject().getValue(context, MemberNames.AccountPasswordData_Account.toString());
if (identifier != null)
if (identifier != null) {
result = administration.proxies.Account.load(context, identifier);
}
return result;
}

Expand All @@ -255,10 +265,11 @@ public final void setAccountPasswordData_Account(administration.proxies.Account
*/
public final void setAccountPasswordData_Account(com.mendix.systemwideinterfaces.core.IContext context, administration.proxies.Account accountpassworddata_account)
{
if (accountpassworddata_account == null)
if (accountpassworddata_account == null) {
getMendixObject().setValue(context, MemberNames.AccountPasswordData_Account.toString(), null);
else
} else {
getMendixObject().setValue(context, MemberNames.AccountPasswordData_Account.toString(), accountpassworddata_account.getMendixObject().getId());
}
}

/**
Expand All @@ -280,9 +291,9 @@ public final com.mendix.systemwideinterfaces.core.IContext getContext()
@java.lang.Override
public boolean equals(Object obj)
{
if (obj == this)
if (obj == this) {
return true;

}
if (obj != null && getClass().equals(obj.getClass()))
{
final administration.proxies.AccountPasswordData that = (administration.proxies.AccountPasswordData) obj;
Expand All @@ -302,7 +313,7 @@ public int hashCode()
*/
public static java.lang.String getType()
{
return "Administration.AccountPasswordData";
return entityName;
}

/**
Expand Down
25 changes: 15 additions & 10 deletions src/javasource/administration/proxies/microflows/Microflows.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,19 @@
import java.util.HashMap;
import java.util.Map;
import com.mendix.core.Core;
import com.mendix.core.CoreException;
import com.mendix.systemwideinterfaces.MendixRuntimeException;
import com.mendix.systemwideinterfaces.core.IContext;
import com.mendix.systemwideinterfaces.core.IMendixObject;

public class Microflows
{
/**
* @deprecated
* The default constructor of the Microflows class should not be used.
* Use the static microflow invocation methods instead.
*/
@java.lang.Deprecated(since = "9.12", forRemoval = true)
public Microflows() {}

// These are the microflows for the Administration module
public static void changeMyPassword(IContext context, administration.proxies.AccountPasswordData _accountPasswordData)
{
Expand Down Expand Up @@ -50,14 +56,13 @@ public static java.util.List<system.proxies.TimeZone> retrieveTimeZones(IContext
{
Map<java.lang.String, Object> params = new HashMap<>();
java.util.List<IMendixObject> objs = Core.microflowCall("Administration.RetrieveTimeZones").withParams(params).execute(context);
java.util.List<system.proxies.TimeZone> result = null;
if (objs != null)
{
result = new java.util.ArrayList<>();
for (IMendixObject obj : objs)
result.add(system.proxies.TimeZone.initialize(context, obj));
if (objs == null) {
return null;
} else {
return objs.stream()
.map(obj -> system.proxies.TimeZone.initialize(context, obj))
.collect(java.util.stream.Collectors.toList());
}
return result;
}
public static void saveNewAccount(IContext context, administration.proxies.AccountPasswordData _accountPasswordData)
{
Expand All @@ -77,4 +82,4 @@ public static void showPasswordForm(IContext context, administration.proxies.Acc
params.put("Account", _account == null ? null : _account.getMendixObject());
Core.microflowCall("Administration.ShowPasswordForm").withParams(params).execute(context);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@

public class Constants
{
/**
* @deprecated
* The default constructor of the Constants class should not be used.
* Use the static get methods instead.
*/
@java.lang.Deprecated(since = "9.12", forRemoval = true)
public Constants() {}

// These are the constants for the Atlas_UI_Resources module

public static java.lang.String getAtlas_UI_Resources_Version()
Expand Down
Loading

0 comments on commit 0c582cf

Please sign in to comment.